@context-action/lit-ui 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/LICENSE +201 -0
- package/README.md +110 -2
- package/dist/hydrate.cjs +139 -0
- package/dist/hydrate.cjs.map +1 -0
- package/dist/hydrate.d.cts +18 -0
- package/dist/hydrate.d.cts.map +1 -0
- package/dist/hydrate.d.ts +18 -0
- package/dist/hydrate.d.ts.map +1 -0
- package/dist/hydrate.js +127 -0
- package/dist/hydrate.js.map +1 -0
- package/dist/index.cjs +1636 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +644 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +644 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1571 -0
- package/dist/index.js.map +1 -0
- package/dist/ssr.cjs +116 -0
- package/dist/ssr.cjs.map +1 -0
- package/dist/ssr.d.cts +53 -0
- package/dist/ssr.d.cts.map +1 -0
- package/dist/ssr.d.ts +53 -0
- package/dist/ssr.d.ts.map +1 -0
- package/dist/ssr.js +111 -0
- package/dist/ssr.js.map +1 -0
- package/docs/01-dom-ownership.md +133 -0
- package/docs/02-reactive-controller-vs-hooks.md +246 -0
- package/docs/03-form-associated-elements.md +585 -0
- package/docs/04-micro-frontend-communication.md +682 -0
- package/docs/05-interface-and-state-management-standards.md +210 -0
- package/docs/06-ssr-hydration.md +134 -0
- package/docs/07-release-and-verification.md +150 -0
- package/package.json +105 -4
package/dist/hydrate.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { LitElement } from "lit";
|
|
2
|
+
import "@lit-labs/ssr-client/lit-element-hydrate-support.js";
|
|
3
|
+
import { hydrate } from "@lit-labs/ssr-client";
|
|
4
|
+
// src/hydrate.ts
|
|
5
|
+
const COMMENT_NODE = 8;
|
|
6
|
+
const DOCUMENT_FRAGMENT_NODE = 11;
|
|
7
|
+
function hasLitPartMarker(root) {
|
|
8
|
+
for (let node = root.firstChild; node; node = node.nextSibling) if (node.nodeType === COMMENT_NODE && node.data.startsWith("lit-part")) return true;
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
function findServerHost(root, element) {
|
|
12
|
+
const tagName = element.localName;
|
|
13
|
+
if (!tagName) return null;
|
|
14
|
+
if (root.nodeType === DOCUMENT_FRAGMENT_NODE && "host" in root && root.host === element) return null;
|
|
15
|
+
if (root.nodeType === 1 && root.localName === tagName) return root;
|
|
16
|
+
return root.querySelector?.(tagName) ?? null;
|
|
17
|
+
}
|
|
18
|
+
function isHydrationSupportInstalled() {
|
|
19
|
+
const shadow = {};
|
|
20
|
+
const probe = { shadowRoot: shadow };
|
|
21
|
+
const createRenderRoot = LitElement.prototype.createRenderRoot;
|
|
22
|
+
try {
|
|
23
|
+
return createRenderRoot.call(probe) === shadow;
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function hydrateHost(host) {
|
|
29
|
+
const shadow = host.shadowRoot;
|
|
30
|
+
if (!shadow) {
|
|
31
|
+
host.requestUpdate();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const hydrationSupportInstalled = isHydrationSupportInstalled();
|
|
35
|
+
if (!hydrationSupportInstalled) Object.defineProperty(host, "createRenderRoot", {
|
|
36
|
+
configurable: true,
|
|
37
|
+
value: () => shadow
|
|
38
|
+
});
|
|
39
|
+
if (shadow._$litPart$ !== void 0) {
|
|
40
|
+
host.requestUpdate();
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (!hasLitPartMarker(shadow)) {
|
|
44
|
+
shadow.replaceChildren();
|
|
45
|
+
host.requestUpdate();
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (hydrationSupportInstalled) {
|
|
49
|
+
host.requestUpdate();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const rendered = host.render();
|
|
53
|
+
hydrate(rendered, shadow);
|
|
54
|
+
host.requestUpdate();
|
|
55
|
+
}
|
|
56
|
+
function upgradeServerHost(host, element) {
|
|
57
|
+
const tagName = element.localName;
|
|
58
|
+
const registry = globalThis.customElements;
|
|
59
|
+
if (!registry) throw new Error("hydrateLit() requires a DOM environment with customElements.");
|
|
60
|
+
if (!registry.get(tagName)) registry.define(tagName, element.constructor);
|
|
61
|
+
const existingShadow = host.shadowRoot;
|
|
62
|
+
if (existingShadow && !isHydrationSupportInstalled()) Object.defineProperty(host, "createRenderRoot", {
|
|
63
|
+
configurable: true,
|
|
64
|
+
value: () => existingShadow
|
|
65
|
+
});
|
|
66
|
+
const elementConstructor = element.constructor;
|
|
67
|
+
if (host instanceof elementConstructor) {
|
|
68
|
+
hydrateHost(host);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
registry.upgrade(host);
|
|
72
|
+
if (host instanceof elementConstructor) hydrateHost(host);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Hydrates server-produced markup on the client.
|
|
76
|
+
*
|
|
77
|
+
* Supported modes:
|
|
78
|
+
* 1. `root` is an element's own shadow root (or contains the Lit template
|
|
79
|
+
* markers produced by `renderLitTemplate`): the element's current template is
|
|
80
|
+
* hydrated into that root, preserving existing DOM and attaching event parts.
|
|
81
|
+
* 2. `root` contains a server-rendered custom element host for the same tag:
|
|
82
|
+
* the host is upgraded so its controllers and attributes connect.
|
|
83
|
+
* 3. `root` is empty: the element is mounted and rendered normally.
|
|
84
|
+
*
|
|
85
|
+
* The function never reads a global `document`; it operates only on the supplied
|
|
86
|
+
* root and element.
|
|
87
|
+
*/
|
|
88
|
+
function hydrateLit(root, element) {
|
|
89
|
+
if (!root || typeof root !== "object") throw new TypeError("hydrateLit() requires an Element or ShadowRoot.");
|
|
90
|
+
if (!element || typeof element !== "object") throw new TypeError("hydrateLit() requires a LitElement instance.");
|
|
91
|
+
const serverHost = findServerHost(root, element);
|
|
92
|
+
if (serverHost && serverHost !== element) {
|
|
93
|
+
upgradeServerHost(serverHost, element);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (root.nodeType === DOCUMENT_FRAGMENT_NODE && "host" in root && root.host === element) {
|
|
97
|
+
const shadow = root;
|
|
98
|
+
if (shadow._$litPart$ === void 0) {
|
|
99
|
+
Object.defineProperty(element, "createRenderRoot", {
|
|
100
|
+
configurable: true,
|
|
101
|
+
value: () => shadow
|
|
102
|
+
});
|
|
103
|
+
if (hasLitPartMarker(shadow)) {
|
|
104
|
+
const rendered = element.render();
|
|
105
|
+
hydrate(rendered, shadow);
|
|
106
|
+
} else shadow.replaceChildren();
|
|
107
|
+
}
|
|
108
|
+
element._$needsHydration = false;
|
|
109
|
+
element._$AG = false;
|
|
110
|
+
element.requestUpdate();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (hasLitPartMarker(root)) {
|
|
114
|
+
if (root._$litPart$ !== void 0) {
|
|
115
|
+
element.requestUpdate();
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const rendered = element.render();
|
|
119
|
+
hydrate(rendered, root);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (root !== element && !element.isConnected) root.append(element);
|
|
123
|
+
element.requestUpdate();
|
|
124
|
+
}
|
|
125
|
+
export { hydrateLit };
|
|
126
|
+
|
|
127
|
+
//# sourceMappingURL=hydrate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hydrate.js","names":[],"sources":["../src/hydrate.ts"],"sourcesContent":["/**\n * @fileoverview Client-only hydration entry (`@context-action/lit-ui/hydrate`).\n *\n * This module intentionally imports only `@lit-labs/ssr-client` and the Lit\n * runtime, never the server renderer. Client bundles that only need\n * `hydrateLit()` can avoid pulling `@lit-labs/ssr` into the browser graph.\n *\n * @implements view-layer\n * @implements web-component-primitive\n * @memberof core-concepts\n */\n\nimport '@lit-labs/ssr-client/lit-element-hydrate-support.js';\nimport { LitElement } from 'lit';\nimport { hydrate } from '@lit-labs/ssr-client';\n\nconst COMMENT_NODE = 8;\nconst DOCUMENT_FRAGMENT_NODE = 11;\n\nfunction hasLitPartMarker(root: Element | ShadowRoot): boolean {\n for (let node = root.firstChild; node; node = node.nextSibling) {\n if (\n node.nodeType === COMMENT_NODE &&\n (node as Comment).data.startsWith('lit-part')\n ) {\n return true;\n }\n }\n return false;\n}\n\nfunction findServerHost(\n root: Element | ShadowRoot,\n element: LitElement,\n): Element | null {\n const tagName = element.localName;\n if (!tagName) return null;\n\n // A ShadowRoot owned by the element is a render target, not a host container.\n if (\n root.nodeType === DOCUMENT_FRAGMENT_NODE &&\n 'host' in root &&\n root.host === element\n ) {\n return null;\n }\n\n if (root.nodeType === 1 && (root as Element).localName === tagName) {\n return root as Element;\n }\n\n return root.querySelector?.(tagName) ?? null;\n}\n\nfunction isHydrationSupportInstalled(): boolean {\n const shadow = {};\n const probe = { shadowRoot: shadow } as unknown as LitElement;\n const createRenderRoot = (\n LitElement.prototype as unknown as {\n createRenderRoot(this: LitElement): unknown;\n }\n ).createRenderRoot;\n try {\n return createRenderRoot.call(probe) === shadow;\n } catch {\n return false;\n }\n}\n\nfunction hydrateHost(host: LitElement): void {\n const shadow = host.shadowRoot;\n if (!shadow) {\n host.requestUpdate();\n return;\n }\n\n const hydrationSupportInstalled = isHydrationSupportInstalled();\n if (!hydrationSupportInstalled) {\n Object.defineProperty(host, 'createRenderRoot', {\n configurable: true,\n value: () => shadow,\n });\n }\n\n const livePart = (shadow as ShadowRoot & { _$litPart$?: unknown })._$litPart$;\n if (livePart !== undefined) {\n host.requestUpdate();\n return;\n }\n\n if (!hasLitPartMarker(shadow)) {\n // Server markup without lit-html markers cannot be hydrated. Clear it and\n // force the first client render into this shadow root without asking Lit's\n // hydration support to adopt a non-lit tree.\n shadow.replaceChildren();\n host.requestUpdate();\n return;\n }\n\n // Lit's official hydration support patches createRenderRoot/update and\n // adopts the declarative shadow root on the first update. Running hydrate()\n // ourselves would make support hydrate the same container twice.\n if (hydrationSupportInstalled) {\n host.requestUpdate();\n return;\n }\n\n const rendered = (host as unknown as { render(): unknown }).render();\n hydrate(rendered, shadow);\n host.requestUpdate();\n}\n\nfunction upgradeServerHost(host: Element, element: LitElement): void {\n const tagName = element.localName;\n const registry = globalThis.customElements;\n if (!registry) {\n throw new Error('hydrateLit() requires a DOM environment with customElements.');\n }\n\n if (!registry.get(tagName)) {\n registry.define(tagName, element.constructor as CustomElementConstructor);\n }\n\n // A declarative shadow root already contains the server template. When Lit's\n // hydration support is not installed, prevent the first update from calling\n // attachShadow() on the same host. When support is installed, its patched\n // createRenderRoot already does this and must remain in control.\n const existingShadow = host.shadowRoot;\n if (existingShadow && !isHydrationSupportInstalled()) {\n Object.defineProperty(host, 'createRenderRoot', {\n configurable: true,\n value: () => existingShadow,\n });\n }\n\n const elementConstructor = element.constructor as unknown as { new (): LitElement };\n if (host instanceof elementConstructor) {\n hydrateHost(host);\n return;\n }\n\n registry.upgrade(host);\n if (host instanceof elementConstructor) {\n hydrateHost(host);\n }\n}\n\n/**\n * Hydrates server-produced markup on the client.\n *\n * Supported modes:\n * 1. `root` is an element's own shadow root (or contains the Lit template\n * markers produced by `renderLitTemplate`): the element's current template is\n * hydrated into that root, preserving existing DOM and attaching event parts.\n * 2. `root` contains a server-rendered custom element host for the same tag:\n * the host is upgraded so its controllers and attributes connect.\n * 3. `root` is empty: the element is mounted and rendered normally.\n *\n * The function never reads a global `document`; it operates only on the supplied\n * root and element.\n */\nexport function hydrateLit(root: Element | ShadowRoot, element: LitElement): void {\n if (!root || typeof root !== 'object') {\n throw new TypeError('hydrateLit() requires an Element or ShadowRoot.');\n }\n if (!element || typeof element !== 'object') {\n throw new TypeError('hydrateLit() requires a LitElement instance.');\n }\n\n const serverHost = findServerHost(root, element);\n if (serverHost && serverHost !== element) {\n upgradeServerHost(serverHost, element);\n return;\n }\n\n // The element's own shadow root is managed by its Lit update lifecycle.\n // Hydrate it explicitly and bypass the support flag so the first update does\n // not adopt the same container a second time.\n if (\n root.nodeType === DOCUMENT_FRAGMENT_NODE &&\n 'host' in root &&\n root.host === element\n ) {\n const shadow = root as ShadowRoot;\n const livePart = (shadow as ShadowRoot & { _$litPart$?: unknown })._$litPart$;\n if (livePart === undefined) {\n Object.defineProperty(element, 'createRenderRoot', {\n configurable: true,\n value: () => shadow,\n });\n if (hasLitPartMarker(shadow)) {\n const rendered = (element as unknown as { render(): unknown }).render();\n hydrate(rendered, shadow);\n } else {\n shadow.replaceChildren();\n }\n }\n // Support uses `_$needsHydration` in development and a minified field in\n // production. Clearing both is harmless when support is absent.\n (element as unknown as { _$needsHydration?: boolean })._$needsHydration = false;\n (element as unknown as { _$AG?: boolean })._$AG = false;\n element.requestUpdate();\n return;\n }\n\n if (hasLitPartMarker(root)) {\n const livePart = (root as ShadowRoot & { _$litPart$?: unknown })._$litPart$;\n if (livePart !== undefined) {\n element.requestUpdate();\n return;\n }\n const rendered = (element as unknown as { render(): unknown }).render();\n hydrate(rendered, root);\n return;\n }\n\n if (root !== element && !element.isConnected) {\n root.append(element);\n }\n element.requestUpdate();\n}\n"],"mappings":"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"}
|