Skip to content

Commit 1109e1f

Browse files
committed
Merge branch 'main' of github.com:plusnew/webcomponent
2 parents 131a5a8 + f1439d3 commit 1109e1f

5 files changed

Lines changed: 87 additions & 62 deletions

File tree

src/babel-plugin-transform-jsx.cjs

Lines changed: 44 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,15 @@ module.exports = function (babel) {
1010
enter: (path, state) => {
1111
state.set(
1212
"id/jsx",
13-
addNamed(
14-
path,
15-
"jsx",
16-
"@plusnew/webcomponent/jsx-runtime",
17-
),
13+
addNamed(path, "jsx", "@plusnew/webcomponent/jsx-runtime"),
1814
);
1915
},
2016
},
2117
JSXFragment(path, state) {
2218
if (!state.get("id/Fragment")) {
2319
state.set(
2420
"id/Fragment",
25-
addNamed(
26-
path,
27-
"Fragment",
28-
"@plusnew/webcomponent/jsx-runtime",
29-
),
21+
addNamed(path, "Fragment", "@plusnew/webcomponent/jsx-runtime"),
3022
);
3123
}
3224

@@ -36,7 +28,7 @@ module.exports = function (babel) {
3628
t.objectExpression([]),
3729
...t.react
3830
.buildChildren(path.node)
39-
.map((child) => t.arrowFunctionExpression([], child))
31+
.map((child) => t.arrowFunctionExpression([], child)),
4032
]),
4133
);
4234
},
@@ -45,7 +37,9 @@ module.exports = function (babel) {
4537

4638
const typeValue = openingElement.node.name;
4739
const type = t.isJSXNamespacedName(typeValue)
48-
? t.stringLiteral(`${typeValue.namespace.name}:${typeValue.name.name}`)
40+
? t.stringLiteral(
41+
`${typeValue.namespace.name}:${typeValue.name.name}`,
42+
)
4943
: t.react.isCompatTag(typeValue.name)
5044
? t.stringLiteral(typeValue.name)
5145
: t.identifier(typeValue.name);
@@ -55,51 +49,50 @@ module.exports = function (babel) {
5549

5650
const properties = [];
5751
for (const attribute of openingElement.get("attributes")) {
58-
if (
59-
attribute.isJSXAttribute() &&
60-
t.isJSXIdentifier(attribute.node.name)
61-
) {
62-
const value = t.isJSXExpressionContainer(attribute.node.value)
63-
? attribute.node.value.expression
64-
: attribute.node.value;
52+
if (attribute.isJSXAttribute()) {
53+
if (t.isJSXIdentifier(attribute.node.name) || t.isJSXNamespacedName(attribute.node.name)) {
54+
const value = t.isJSXExpressionContainer(attribute.node.value)
55+
? attribute.node.value.expression
56+
: attribute.node.value;
6557

66-
if (
67-
t.isStringLiteral(value) &&
68-
!t.isJSXExpressionContainer(attribute.node.value)
69-
) {
70-
value.value = value.value.replace(/\n\s+/g, " ");
58+
if (
59+
t.isStringLiteral(value) &&
60+
!t.isJSXExpressionContainer(attribute.node.value)
61+
) {
62+
value.value = value.value.replace(/\n\s+/g, " ");
7163

72-
// "raw" JSXText should not be used from a StringLiteral because it needs to be escaped.
73-
delete value.extra?.raw;
74-
}
64+
// "raw" JSXText should not be used from a StringLiteral because it needs to be escaped.
65+
delete value.extra?.raw;
66+
}
67+
68+
if (t.isJSXNamespacedName(attribute.node.name)) {
69+
// @ts-expect-error mutating AST
70+
attribute.node.name = t.stringLiteral(
71+
`${attribute.node.name.namespace.name}:${attribute.node.name.name.name}`,
72+
);
73+
} else if (t.isValidIdentifier(attribute.node.name.name, false)) {
74+
// @ts-expect-error mutating AST
75+
attribute.node.name.type = "Identifier";
76+
} else {
77+
// @ts-expect-error mutating AST
78+
attribute.node.name = t.stringLiteral(attribute.node.name.name);
79+
}
7580

76-
if (t.isJSXNamespacedName(attribute.node.name)) {
77-
// @ts-expect-error mutating AST
78-
attribute.node.name = t.stringLiteral(
79-
`${attribute.node.name.namespace.name}:${attribute.node.name.name.name}`,
81+
properties.push(
82+
t.inherits(
83+
t.objectProperty(
84+
// @ts-expect-error The attribute.node.name is an Identifier now
85+
attribute.node.name,
86+
value,
87+
),
88+
attribute.node,
89+
),
8090
);
81-
} else if (t.isValidIdentifier(attribute.node.name.name, false)) {
82-
// @ts-expect-error mutating AST
83-
attribute.node.name.type = "Identifier";
8491
} else {
85-
// @ts-expect-error mutating AST
86-
attribute.node.name = t.stringLiteral(attribute.node.name.name);
92+
throw new Error(`Unknown attriute-node-type ${attribute.node.name.type}`);
8793
}
88-
89-
properties.push(
90-
t.inherits(
91-
t.objectProperty(
92-
// @ts-expect-error The attribute.node.name is an Identifier now
93-
attribute.node.name,
94-
value,
95-
),
96-
attribute.node,
97-
),
98-
);
99-
} else if (t.isJSXSpreadAttribute(attribute.node.name)) {
100-
throw new Error("not yet jmplemented");
10194
} else {
102-
throw new Error("Unknown type");
95+
throw new Error(`Unknown attribute-type ${attribute.type}`);
10396
}
10497
}
10598

@@ -113,4 +106,4 @@ module.exports = function (babel) {
113106
},
114107
},
115108
};
116-
}
109+
};

src/index.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,9 @@ export function createComponent<
6161
},
6262
| ReadonlyKeys<T>
6363
| ForbiddenHTMLProperties
64-
| keyof {
65-
[K in keyof T as T[K] extends Function
66-
? K extends `on${any}`
67-
? never
68-
: K
69-
: never]: K;
70-
}
64+
| "render"
65+
| "connectedCallback"
66+
| "disconnectedCallback"
7167
> & {
7268
children?: ShadowElement;
7369
onplusnewerror?: (evt: PlusnewErrorEvent) => void;

src/reconciler/fragment.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
type ShadowHostElement,
66
} from "../types";
77
import type { Reconciler } from "./index";
8-
import { arrayReconcileWithoutSorting } from "./utils";
8+
import { arrayReconcileWithoutSorting, getChildren } from "./utils";
99

1010
export function isFragmentElement(
1111
shadowElement: ShadowElement,
@@ -33,11 +33,18 @@ export const fragmentReconcile: Reconciler = (opt) => {
3333
};
3434
}
3535

36+
const children = getChildren(
37+
opt.parentElement instanceof ShadowRoot
38+
? opt.parentElement.host
39+
: (opt.parentElement as Element),
40+
opt.shadowElement.children,
41+
);
42+
3643
return arrayReconcileWithoutSorting({
3744
parentElement: opt.parentElement,
3845
previousSibling: opt.previousSibling,
3946
shadowCache: opt.shadowCache,
40-
shadowElement: opt.shadowElement.children.map((child) => child()),
47+
shadowElement: children,
4148
getParentOverwrite: opt.getParentOverwrite,
4249
});
4350
} else {

src/reconciler/utils.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import type { ShadowElement } from "../types";
22
import { reconcile } from "./index";
3+
import { active } from "../index";
4+
import { dispatchError } from "../utils";
35

46
export class ShadowCache {
57
value: ShadowElement;
@@ -39,6 +41,27 @@ export class ShadowCache {
3941
}
4042
}
4143

44+
export function getChildren(
45+
parent: Element,
46+
childrenCallbacks: (() => ShadowElement)[],
47+
) {
48+
const previousActiveElement = active.parentElement;
49+
active.parentElement = parent;
50+
51+
const children: ShadowElement[] = [];
52+
for (const childCallback of childrenCallbacks) {
53+
try {
54+
children.push(childCallback());
55+
} catch (error) {
56+
children.push(false);
57+
dispatchError(parent, error);
58+
}
59+
}
60+
active.parentElement = previousActiveElement;
61+
62+
return children;
63+
}
64+
4265
export const arrayReconcileWithoutSorting = (opt: {
4366
parentElement: ParentNode;
4467
previousSibling: Node | null;

src/utils.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,16 @@ export const parentsCacheSymbol = Symbol("parentsCache");
3737

3838
export function connectedCallback(
3939
this: HTMLElement & { render: () => ShadowElement },
40-
) {
40+
opt?: { shadowRootInit?: Partial<ShadowRootInit> },
41+
): ShadowRoot {
42+
let shadowRoot: null | ShadowRoot = null;
4143
if (this.shadowRoot === null) {
42-
this.attachShadow({ mode: "open" });
44+
shadowRoot = this.attachShadow({ mode: "open", ...opt?.shadowRootInit });
4345

4446
(this as any)[parentsCacheSymbol] = new Map();
4547
(this as any)[shadowCache] = new ShadowCache(false);
48+
} else {
49+
shadowRoot = this.shadowRoot;
4650
}
4751

4852
(this as any)[disconnect] = effect(() => {
@@ -69,6 +73,8 @@ export function connectedCallback(
6973
});
7074
});
7175
});
76+
77+
return shadowRoot;
7278
}
7379

7480
export function disconnectedCallback(

0 commit comments

Comments
 (0)