@coherent.js/web-components 1.0.0-beta.5 → 1.0.0-beta.7
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/dist/index.js +110 -0
- package/dist/index.js.map +7 -0
- package/package.json +12 -3
- package/src/index.js +98 -7
- package/types/index.d.ts +247 -29
package/dist/index.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// src/index.js
|
|
2
|
+
import { render } from "@coherent.js/core";
|
|
3
|
+
function defineComponent(name, component, options = {}) {
|
|
4
|
+
if (typeof window === "undefined") {
|
|
5
|
+
return { name, component, options };
|
|
6
|
+
}
|
|
7
|
+
if (!window.customElements) {
|
|
8
|
+
throw new Error("Custom Elements API not supported");
|
|
9
|
+
}
|
|
10
|
+
const observedAttrs = options.observedAttributes || [];
|
|
11
|
+
const defaults = options.defaults || {};
|
|
12
|
+
class CoherentElement extends HTMLElement {
|
|
13
|
+
static get observedAttributes() {
|
|
14
|
+
return observedAttrs;
|
|
15
|
+
}
|
|
16
|
+
constructor() {
|
|
17
|
+
super();
|
|
18
|
+
this._props = { ...defaults };
|
|
19
|
+
this._connected = false;
|
|
20
|
+
this.component = component;
|
|
21
|
+
this.options = options;
|
|
22
|
+
}
|
|
23
|
+
connectedCallback() {
|
|
24
|
+
this._connected = true;
|
|
25
|
+
for (const attr of observedAttrs) {
|
|
26
|
+
if (this.hasAttribute(attr)) {
|
|
27
|
+
this._props[attr] = this.getAttribute(attr);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
this._render();
|
|
31
|
+
}
|
|
32
|
+
disconnectedCallback() {
|
|
33
|
+
this._connected = false;
|
|
34
|
+
if (options.shadow && this.shadowRoot) {
|
|
35
|
+
this.shadowRoot.innerHTML = "";
|
|
36
|
+
} else {
|
|
37
|
+
this.innerHTML = "";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
attributeChangedCallback(attrName, oldValue, newValue) {
|
|
41
|
+
if (oldValue === newValue) return;
|
|
42
|
+
this._props[attrName] = newValue;
|
|
43
|
+
if (this._connected) {
|
|
44
|
+
this._render();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Set a property and re-render
|
|
49
|
+
*/
|
|
50
|
+
setProperty(key, value) {
|
|
51
|
+
this._props[key] = value;
|
|
52
|
+
if (this._connected) {
|
|
53
|
+
this._render();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get current props
|
|
58
|
+
*/
|
|
59
|
+
getProperties() {
|
|
60
|
+
return { ...this._props };
|
|
61
|
+
}
|
|
62
|
+
_render() {
|
|
63
|
+
const componentDef = typeof this.component === "function" ? this.component(this._props) : this.component;
|
|
64
|
+
const html = render(componentDef);
|
|
65
|
+
if (this.options.shadow) {
|
|
66
|
+
if (!this.shadowRoot) {
|
|
67
|
+
this.attachShadow({ mode: "open" });
|
|
68
|
+
}
|
|
69
|
+
this.shadowRoot.innerHTML = html;
|
|
70
|
+
this._delegateEvents(this.shadowRoot);
|
|
71
|
+
} else {
|
|
72
|
+
this.innerHTML = html;
|
|
73
|
+
this._delegateEvents(this);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Delegate data-action events to component handlers
|
|
78
|
+
*/
|
|
79
|
+
_delegateEvents(root) {
|
|
80
|
+
const actionElements = root.querySelectorAll("[data-action]");
|
|
81
|
+
for (const el of actionElements) {
|
|
82
|
+
const action = el.dataset.action;
|
|
83
|
+
const [eventType, handlerName] = action.includes(":") ? action.split(":") : ["click", action];
|
|
84
|
+
el.addEventListener(eventType, (event) => {
|
|
85
|
+
this.dispatchEvent(new CustomEvent("coherent-action", {
|
|
86
|
+
bubbles: true,
|
|
87
|
+
detail: { action: handlerName, event, element: el }
|
|
88
|
+
}));
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
window.customElements.define(name, CoherentElement);
|
|
94
|
+
return CoherentElement;
|
|
95
|
+
}
|
|
96
|
+
function integrateWithWebComponents(_runtime) {
|
|
97
|
+
return {
|
|
98
|
+
defineComponent: (name, component, options) => defineComponent(name, component, options)
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function defineCoherentElement(name, component, options = {}) {
|
|
102
|
+
return defineComponent(name, component, options);
|
|
103
|
+
}
|
|
104
|
+
export {
|
|
105
|
+
defineComponent as default,
|
|
106
|
+
defineCoherentElement,
|
|
107
|
+
defineComponent,
|
|
108
|
+
integrateWithWebComponents
|
|
109
|
+
};
|
|
110
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/index.js"],
|
|
4
|
+
"sourcesContent": ["/**\n * Coherent.js Web Components Integration\n * Provides custom element and web component utilities\n */\n\nimport { render } from '@coherent.js/core';\n\n/**\n * Define a Coherent.js component as a custom element\n *\n * @param {string} name - Custom element tag name (must contain a hyphen)\n * @param {Function|Object} component - Coherent.js component (function or object)\n * @param {Object} [options] - Configuration options\n * @param {boolean} [options.shadow] - Use Shadow DOM for style encapsulation\n * @param {string[]} [options.observedAttributes] - Attributes to watch for changes\n * @param {Object} [options.defaults] - Default property values\n * @returns {Function|Object} The custom element class, or a server-side placeholder\n */\nexport function defineComponent(name, component, options = {}) {\n if (typeof window === 'undefined') {\n // Server-side: return a placeholder for SSR\n return { name, component, options };\n }\n\n if (!window.customElements) {\n throw new Error('Custom Elements API not supported');\n }\n\n const observedAttrs = options.observedAttributes || [];\n const defaults = options.defaults || {};\n\n class CoherentElement extends HTMLElement {\n static get observedAttributes() {\n return observedAttrs;\n }\n\n constructor() {\n super();\n this._props = { ...defaults };\n this._connected = false;\n this.component = component;\n this.options = options;\n }\n\n connectedCallback() {\n this._connected = true;\n // Copy initial attributes to props\n for (const attr of observedAttrs) {\n if (this.hasAttribute(attr)) {\n this._props[attr] = this.getAttribute(attr);\n }\n }\n this._render();\n }\n\n disconnectedCallback() {\n this._connected = false;\n // Cleanup: remove event listeners and clear content\n if (options.shadow && this.shadowRoot) {\n this.shadowRoot.innerHTML = '';\n } else {\n this.innerHTML = '';\n }\n }\n\n attributeChangedCallback(attrName, oldValue, newValue) {\n if (oldValue === newValue) return;\n this._props[attrName] = newValue;\n if (this._connected) {\n this._render();\n }\n }\n\n /**\n * Set a property and re-render\n */\n setProperty(key, value) {\n this._props[key] = value;\n if (this._connected) {\n this._render();\n }\n }\n\n /**\n * Get current props\n */\n getProperties() {\n return { ...this._props };\n }\n\n _render() {\n const componentDef = typeof this.component === 'function'\n ? this.component(this._props)\n : this.component;\n\n const html = render(componentDef);\n\n if (this.options.shadow) {\n if (!this.shadowRoot) {\n this.attachShadow({ mode: 'open' });\n }\n this.shadowRoot.innerHTML = html;\n this._delegateEvents(this.shadowRoot);\n } else {\n this.innerHTML = html;\n this._delegateEvents(this);\n }\n }\n\n /**\n * Delegate data-action events to component handlers\n */\n _delegateEvents(root) {\n const actionElements = root.querySelectorAll('[data-action]');\n for (const el of actionElements) {\n const action = el.dataset.action;\n const [eventType, handlerName] = action.includes(':')\n ? action.split(':')\n : ['click', action];\n\n el.addEventListener(eventType, (event) => {\n this.dispatchEvent(new CustomEvent('coherent-action', {\n bubbles: true,\n detail: { action: handlerName, event, element: el }\n }));\n });\n }\n }\n }\n\n window.customElements.define(name, CoherentElement);\n return CoherentElement;\n}\n\n/**\n * Integration utilities for runtime environments\n */\nexport function integrateWithWebComponents(_runtime) {\n return {\n defineComponent: (name, component, options) => defineComponent(name, component, options)\n };\n}\n\n/**\n * Alias for defineComponent\n */\nexport function defineCoherentElement(name, component, options = {}) {\n return defineComponent(name, component, options);\n}\n\nexport { defineComponent as default };\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coherent.js/web-components",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.7",
|
|
4
4
|
"description": "Web Components integration for Coherent.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
],
|
|
16
16
|
"author": "Coherent.js Team",
|
|
17
17
|
"license": "MIT",
|
|
18
|
-
"
|
|
19
|
-
"@coherent.js/core": "1.0.0-beta.
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"@coherent.js/core": "1.0.0-beta.7"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"vitest": "^3.2.4"
|
|
@@ -25,11 +25,20 @@
|
|
|
25
25
|
"type": "git",
|
|
26
26
|
"url": "git+https://github.com/Tomdrouv1/coherent.js.git"
|
|
27
27
|
},
|
|
28
|
+
"homepage": "https://github.com/Tomdrouv1/coherent.js",
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/Tomdrouv1/coherent.js/issues"
|
|
31
|
+
},
|
|
28
32
|
"publishConfig": {
|
|
29
33
|
"access": "public"
|
|
30
34
|
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=20.0.0"
|
|
37
|
+
},
|
|
31
38
|
"types": "./types/index.d.ts",
|
|
32
39
|
"files": [
|
|
40
|
+
"dist/",
|
|
41
|
+
"src/",
|
|
33
42
|
"LICENSE",
|
|
34
43
|
"README.md",
|
|
35
44
|
"types/"
|
package/src/index.js
CHANGED
|
@@ -7,10 +7,18 @@ import { render } from '@coherent.js/core';
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Define a Coherent.js component as a custom element
|
|
10
|
+
*
|
|
11
|
+
* @param {string} name - Custom element tag name (must contain a hyphen)
|
|
12
|
+
* @param {Function|Object} component - Coherent.js component (function or object)
|
|
13
|
+
* @param {Object} [options] - Configuration options
|
|
14
|
+
* @param {boolean} [options.shadow] - Use Shadow DOM for style encapsulation
|
|
15
|
+
* @param {string[]} [options.observedAttributes] - Attributes to watch for changes
|
|
16
|
+
* @param {Object} [options.defaults] - Default property values
|
|
17
|
+
* @returns {Function|Object} The custom element class, or a server-side placeholder
|
|
10
18
|
*/
|
|
11
19
|
export function defineComponent(name, component, options = {}) {
|
|
12
20
|
if (typeof window === 'undefined') {
|
|
13
|
-
// Server-side:
|
|
21
|
+
// Server-side: return a placeholder for SSR
|
|
14
22
|
return { name, component, options };
|
|
15
23
|
}
|
|
16
24
|
|
|
@@ -18,24 +26,104 @@ export function defineComponent(name, component, options = {}) {
|
|
|
18
26
|
throw new Error('Custom Elements API not supported');
|
|
19
27
|
}
|
|
20
28
|
|
|
29
|
+
const observedAttrs = options.observedAttributes || [];
|
|
30
|
+
const defaults = options.defaults || {};
|
|
31
|
+
|
|
21
32
|
class CoherentElement extends HTMLElement {
|
|
33
|
+
static get observedAttributes() {
|
|
34
|
+
return observedAttrs;
|
|
35
|
+
}
|
|
36
|
+
|
|
22
37
|
constructor() {
|
|
23
38
|
super();
|
|
39
|
+
this._props = { ...defaults };
|
|
40
|
+
this._connected = false;
|
|
24
41
|
this.component = component;
|
|
25
42
|
this.options = options;
|
|
26
43
|
}
|
|
27
44
|
|
|
28
45
|
connectedCallback() {
|
|
29
|
-
this.
|
|
46
|
+
this._connected = true;
|
|
47
|
+
// Copy initial attributes to props
|
|
48
|
+
for (const attr of observedAttrs) {
|
|
49
|
+
if (this.hasAttribute(attr)) {
|
|
50
|
+
this._props[attr] = this.getAttribute(attr);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
this._render();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
disconnectedCallback() {
|
|
57
|
+
this._connected = false;
|
|
58
|
+
// Cleanup: remove event listeners and clear content
|
|
59
|
+
if (options.shadow && this.shadowRoot) {
|
|
60
|
+
this.shadowRoot.innerHTML = '';
|
|
61
|
+
} else {
|
|
62
|
+
this.innerHTML = '';
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
attributeChangedCallback(attrName, oldValue, newValue) {
|
|
67
|
+
if (oldValue === newValue) return;
|
|
68
|
+
this._props[attrName] = newValue;
|
|
69
|
+
if (this._connected) {
|
|
70
|
+
this._render();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Set a property and re-render
|
|
76
|
+
*/
|
|
77
|
+
setProperty(key, value) {
|
|
78
|
+
this._props[key] = value;
|
|
79
|
+
if (this._connected) {
|
|
80
|
+
this._render();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Get current props
|
|
86
|
+
*/
|
|
87
|
+
getProperties() {
|
|
88
|
+
return { ...this._props };
|
|
30
89
|
}
|
|
31
90
|
|
|
32
|
-
|
|
33
|
-
const
|
|
91
|
+
_render() {
|
|
92
|
+
const componentDef = typeof this.component === 'function'
|
|
93
|
+
? this.component(this._props)
|
|
94
|
+
: this.component;
|
|
95
|
+
|
|
96
|
+
const html = render(componentDef);
|
|
97
|
+
|
|
34
98
|
if (this.options.shadow) {
|
|
35
|
-
|
|
36
|
-
|
|
99
|
+
if (!this.shadowRoot) {
|
|
100
|
+
this.attachShadow({ mode: 'open' });
|
|
101
|
+
}
|
|
102
|
+
this.shadowRoot.innerHTML = html;
|
|
103
|
+
this._delegateEvents(this.shadowRoot);
|
|
37
104
|
} else {
|
|
38
105
|
this.innerHTML = html;
|
|
106
|
+
this._delegateEvents(this);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Delegate data-action events to component handlers
|
|
112
|
+
*/
|
|
113
|
+
_delegateEvents(root) {
|
|
114
|
+
const actionElements = root.querySelectorAll('[data-action]');
|
|
115
|
+
for (const el of actionElements) {
|
|
116
|
+
const action = el.dataset.action;
|
|
117
|
+
const [eventType, handlerName] = action.includes(':')
|
|
118
|
+
? action.split(':')
|
|
119
|
+
: ['click', action];
|
|
120
|
+
|
|
121
|
+
el.addEventListener(eventType, (event) => {
|
|
122
|
+
this.dispatchEvent(new CustomEvent('coherent-action', {
|
|
123
|
+
bubbles: true,
|
|
124
|
+
detail: { action: handlerName, event, element: el }
|
|
125
|
+
}));
|
|
126
|
+
});
|
|
39
127
|
}
|
|
40
128
|
}
|
|
41
129
|
}
|
|
@@ -45,7 +133,7 @@ export function defineComponent(name, component, options = {}) {
|
|
|
45
133
|
}
|
|
46
134
|
|
|
47
135
|
/**
|
|
48
|
-
* Integration utilities
|
|
136
|
+
* Integration utilities for runtime environments
|
|
49
137
|
*/
|
|
50
138
|
export function integrateWithWebComponents(_runtime) {
|
|
51
139
|
return {
|
|
@@ -53,6 +141,9 @@ export function integrateWithWebComponents(_runtime) {
|
|
|
53
141
|
};
|
|
54
142
|
}
|
|
55
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Alias for defineComponent
|
|
146
|
+
*/
|
|
56
147
|
export function defineCoherentElement(name, component, options = {}) {
|
|
57
148
|
return defineComponent(name, component, options);
|
|
58
149
|
}
|
package/types/index.d.ts
CHANGED
|
@@ -3,19 +3,51 @@
|
|
|
3
3
|
* @module @coherent.js/web-components
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
import type { CoherentNode, CoherentComponent, ComponentState, ComponentProps } from '@coherent.js/core';
|
|
7
7
|
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// Web Component Configuration
|
|
10
|
+
// ============================================================================
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Property type constructors
|
|
14
|
+
*/
|
|
15
|
+
export type PropertyType =
|
|
16
|
+
| StringConstructor
|
|
17
|
+
| NumberConstructor
|
|
18
|
+
| BooleanConstructor
|
|
19
|
+
| ObjectConstructor
|
|
20
|
+
| ArrayConstructor;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Property definition for web components
|
|
24
|
+
*/
|
|
25
|
+
export interface PropertyDefinition {
|
|
26
|
+
/** Property type */
|
|
27
|
+
type?: PropertyType;
|
|
28
|
+
/** Default value */
|
|
29
|
+
default?: unknown;
|
|
30
|
+
/** Whether property is required */
|
|
31
|
+
required?: boolean;
|
|
32
|
+
/** Custom validator */
|
|
33
|
+
validator?: (value: unknown) => boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Component options for web component registration
|
|
38
|
+
*/
|
|
8
39
|
export interface ComponentOptions {
|
|
40
|
+
/** Use shadow DOM */
|
|
9
41
|
shadow?: boolean;
|
|
42
|
+
/** Shadow root mode */
|
|
10
43
|
mode?: 'open' | 'closed';
|
|
44
|
+
/** Delegates focus to shadow root */
|
|
11
45
|
delegatesFocus?: boolean;
|
|
46
|
+
/** Attributes to observe */
|
|
12
47
|
observedAttributes?: string[];
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
required?: boolean;
|
|
17
|
-
validator?: (value: any) => boolean;
|
|
18
|
-
}>;
|
|
48
|
+
/** Property definitions */
|
|
49
|
+
props?: Record<string, PropertyDefinition>;
|
|
50
|
+
/** Lifecycle hooks */
|
|
19
51
|
lifecycle?: {
|
|
20
52
|
connected?: () => void;
|
|
21
53
|
disconnected?: () => void;
|
|
@@ -24,19 +56,85 @@ export interface ComponentOptions {
|
|
|
24
56
|
};
|
|
25
57
|
}
|
|
26
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Web component configuration
|
|
61
|
+
*/
|
|
62
|
+
export interface WebComponentConfig {
|
|
63
|
+
/** Custom element tag name (must contain hyphen) */
|
|
64
|
+
tagName: string;
|
|
65
|
+
/** Coherent.js component */
|
|
66
|
+
component: CoherentComponent;
|
|
67
|
+
/** Attributes to observe */
|
|
68
|
+
observedAttributes?: string[];
|
|
69
|
+
/** Use shadow DOM */
|
|
70
|
+
shadow?: boolean | ShadowRootInit;
|
|
71
|
+
/** Styles to apply */
|
|
72
|
+
styles?: string | string[];
|
|
73
|
+
/** Adopted style sheets */
|
|
74
|
+
adoptedStyleSheets?: CSSStyleSheet[];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ============================================================================
|
|
78
|
+
// Coherent Web Component
|
|
79
|
+
// ============================================================================
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Coherent element constructor
|
|
83
|
+
*/
|
|
27
84
|
export interface CoherentElementConstructor {
|
|
28
85
|
new (): CoherentElement;
|
|
29
86
|
prototype: CoherentElement;
|
|
30
87
|
}
|
|
31
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Coherent web component element interface
|
|
91
|
+
*/
|
|
32
92
|
export interface CoherentElement extends HTMLElement {
|
|
33
|
-
component
|
|
93
|
+
/** The wrapped component */
|
|
94
|
+
component: CoherentComponent;
|
|
95
|
+
/** Component options */
|
|
34
96
|
options: ComponentOptions;
|
|
97
|
+
|
|
98
|
+
/** Render the component */
|
|
35
99
|
render(): void;
|
|
36
|
-
|
|
37
|
-
|
|
100
|
+
|
|
101
|
+
/** Update with new props */
|
|
102
|
+
update(props?: Record<string, unknown>): void;
|
|
103
|
+
|
|
104
|
+
/** Hydrate with server data */
|
|
105
|
+
hydrate(data?: unknown): void;
|
|
38
106
|
}
|
|
39
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Extended coherent web component interface
|
|
110
|
+
*/
|
|
111
|
+
export interface CoherentWebComponent extends HTMLElement {
|
|
112
|
+
/** Component instance reference */
|
|
113
|
+
readonly componentInstance: unknown;
|
|
114
|
+
/** Current props */
|
|
115
|
+
props: Record<string, unknown>;
|
|
116
|
+
/** Current state */
|
|
117
|
+
state: ComponentState;
|
|
118
|
+
|
|
119
|
+
/** Called when element is added to DOM */
|
|
120
|
+
connectedCallback(): void;
|
|
121
|
+
/** Called when element is removed from DOM */
|
|
122
|
+
disconnectedCallback(): void;
|
|
123
|
+
/** Called when an observed attribute changes */
|
|
124
|
+
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
|
|
125
|
+
/** Called when element is moved to a new document */
|
|
126
|
+
adoptedCallback(): void;
|
|
127
|
+
|
|
128
|
+
/** Update component state */
|
|
129
|
+
setState(updates: Partial<ComponentState>): void;
|
|
130
|
+
/** Force a re-render */
|
|
131
|
+
forceUpdate(): void;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ============================================================================
|
|
135
|
+
// Registration Functions
|
|
136
|
+
// ============================================================================
|
|
137
|
+
|
|
40
138
|
/**
|
|
41
139
|
* Define a Coherent.js component as a custom element
|
|
42
140
|
*
|
|
@@ -53,14 +151,14 @@ export interface CoherentElement extends HTMLElement {
|
|
|
53
151
|
*/
|
|
54
152
|
export function defineComponent(
|
|
55
153
|
name: string,
|
|
56
|
-
component:
|
|
154
|
+
component: CoherentComponent | CoherentNode,
|
|
57
155
|
options?: ComponentOptions
|
|
58
156
|
): CoherentElementConstructor;
|
|
59
157
|
|
|
60
158
|
/**
|
|
61
|
-
*
|
|
159
|
+
* Define a web component with full configuration
|
|
62
160
|
*/
|
|
63
|
-
export function
|
|
161
|
+
export function defineWebComponent(config: WebComponentConfig): typeof CoherentWebComponent;
|
|
64
162
|
|
|
65
163
|
/**
|
|
66
164
|
* Register multiple components at once
|
|
@@ -73,7 +171,30 @@ export function integrateWithWebComponents(runtime: any): void;
|
|
|
73
171
|
* });
|
|
74
172
|
* ```
|
|
75
173
|
*/
|
|
76
|
-
export function registerComponents(
|
|
174
|
+
export function registerComponents(
|
|
175
|
+
components: Record<string, CoherentComponent | CoherentNode>,
|
|
176
|
+
options?: ComponentOptions
|
|
177
|
+
): void;
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Register web components with full configuration
|
|
181
|
+
*/
|
|
182
|
+
export function registerWebComponents(
|
|
183
|
+
components: Record<string, WebComponentConfig>
|
|
184
|
+
): void;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Create a custom element class from a component
|
|
188
|
+
*/
|
|
189
|
+
export function createCustomElement(
|
|
190
|
+
component: CoherentComponent,
|
|
191
|
+
options?: Partial<WebComponentConfig>
|
|
192
|
+
): typeof CoherentWebComponent;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Integration utilities for web components runtime
|
|
196
|
+
*/
|
|
197
|
+
export function integrateWithWebComponents(runtime: unknown): void;
|
|
77
198
|
|
|
78
199
|
/**
|
|
79
200
|
* Check if a custom element is defined
|
|
@@ -93,19 +214,31 @@ export function upgradeElement(element: Element): void;
|
|
|
93
214
|
/**
|
|
94
215
|
* Create a Coherent.js component from a custom element
|
|
95
216
|
*/
|
|
96
|
-
export function fromCustomElement(element: HTMLElement):
|
|
217
|
+
export function fromCustomElement(element: HTMLElement): CoherentNode;
|
|
218
|
+
|
|
219
|
+
// ============================================================================
|
|
220
|
+
// Property Decorators
|
|
221
|
+
// ============================================================================
|
|
97
222
|
|
|
98
223
|
/**
|
|
99
|
-
*
|
|
224
|
+
* Property declaration for decorators
|
|
100
225
|
*/
|
|
101
226
|
export interface PropertyDeclaration {
|
|
102
|
-
|
|
227
|
+
/** Property type */
|
|
228
|
+
type?: PropertyType;
|
|
229
|
+
/** Sync with attribute */
|
|
103
230
|
attribute?: boolean | string;
|
|
231
|
+
/** Reflect to attribute */
|
|
104
232
|
reflect?: boolean;
|
|
105
|
-
converter
|
|
106
|
-
|
|
233
|
+
/** Custom converter from attribute string */
|
|
234
|
+
converter?: (value: string) => unknown;
|
|
235
|
+
/** Default value */
|
|
236
|
+
default?: unknown;
|
|
107
237
|
}
|
|
108
238
|
|
|
239
|
+
/**
|
|
240
|
+
* Create a property definition
|
|
241
|
+
*/
|
|
109
242
|
export function createProperty(declaration: PropertyDeclaration): PropertyDecorator;
|
|
110
243
|
|
|
111
244
|
/**
|
|
@@ -120,56 +253,141 @@ export function property(declaration?: PropertyDeclaration): PropertyDecorator;
|
|
|
120
253
|
*/
|
|
121
254
|
export function customElement(tagName: string): ClassDecorator;
|
|
122
255
|
|
|
123
|
-
//
|
|
256
|
+
// ============================================================================
|
|
257
|
+
// Event System
|
|
258
|
+
// ============================================================================
|
|
124
259
|
|
|
260
|
+
/**
|
|
261
|
+
* Custom event options
|
|
262
|
+
*/
|
|
125
263
|
export interface EventOptions {
|
|
264
|
+
/** Whether event bubbles */
|
|
126
265
|
bubbles?: boolean;
|
|
266
|
+
/** Whether event is composed (crosses shadow boundary) */
|
|
127
267
|
composed?: boolean;
|
|
268
|
+
/** Whether event is cancelable */
|
|
128
269
|
cancelable?: boolean;
|
|
129
|
-
detail
|
|
270
|
+
/** Event detail data */
|
|
271
|
+
detail?: unknown;
|
|
130
272
|
}
|
|
131
273
|
|
|
274
|
+
/**
|
|
275
|
+
* Create a custom event
|
|
276
|
+
*/
|
|
132
277
|
export function createEvent(type: string, options?: EventOptions): CustomEvent;
|
|
133
|
-
export function dispatchCustomEvent(element: Element, type: string, options?: EventOptions): boolean;
|
|
134
278
|
|
|
135
|
-
|
|
279
|
+
/**
|
|
280
|
+
* Dispatch a custom event on an element
|
|
281
|
+
*/
|
|
282
|
+
export function dispatchCustomEvent(
|
|
283
|
+
element: Element,
|
|
284
|
+
type: string,
|
|
285
|
+
options?: EventOptions
|
|
286
|
+
): boolean;
|
|
136
287
|
|
|
288
|
+
// ============================================================================
|
|
289
|
+
// Slot Utilities
|
|
290
|
+
// ============================================================================
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Slot change event interface
|
|
294
|
+
*/
|
|
137
295
|
export interface SlotChangeEvent extends Event {
|
|
138
296
|
target: HTMLSlotElement;
|
|
139
297
|
}
|
|
140
298
|
|
|
299
|
+
/**
|
|
300
|
+
* Get slotted content
|
|
301
|
+
*/
|
|
141
302
|
export function getSlotContent(element: Element, slotName?: string): Node[];
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Check if slot has content
|
|
306
|
+
*/
|
|
142
307
|
export function hasSlotContent(element: Element, slotName?: string): boolean;
|
|
143
|
-
export function onSlotChange(element: Element, callback: (event: SlotChangeEvent) => void, slotName?: string): () => void;
|
|
144
308
|
|
|
145
|
-
|
|
309
|
+
/**
|
|
310
|
+
* Listen for slot changes
|
|
311
|
+
*/
|
|
312
|
+
export function onSlotChange(
|
|
313
|
+
element: Element,
|
|
314
|
+
callback: (event: SlotChangeEvent) => void,
|
|
315
|
+
slotName?: string
|
|
316
|
+
): () => void;
|
|
146
317
|
|
|
318
|
+
// ============================================================================
|
|
319
|
+
// Shadow DOM Utilities
|
|
320
|
+
// ============================================================================
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Shadow root initialization options
|
|
324
|
+
*/
|
|
147
325
|
export interface ShadowRootInit {
|
|
326
|
+
/** Shadow mode */
|
|
148
327
|
mode: 'open' | 'closed';
|
|
328
|
+
/** Delegates focus */
|
|
149
329
|
delegatesFocus?: boolean;
|
|
330
|
+
/** Slot assignment mode */
|
|
150
331
|
slotAssignment?: 'manual' | 'named';
|
|
151
332
|
}
|
|
152
333
|
|
|
334
|
+
/**
|
|
335
|
+
* Create a shadow root
|
|
336
|
+
*/
|
|
153
337
|
export function createShadowRoot(element: Element, init: ShadowRootInit): ShadowRoot;
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Adopt styles into a shadow root
|
|
341
|
+
*/
|
|
154
342
|
export function adoptStyles(shadowRoot: ShadowRoot, styles: string | CSSStyleSheet[]): void;
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Get an element's shadow root
|
|
346
|
+
*/
|
|
155
347
|
export function getShadowRoot(element: Element): ShadowRoot | null;
|
|
156
348
|
|
|
157
|
-
//
|
|
349
|
+
// ============================================================================
|
|
350
|
+
// Template Utilities
|
|
351
|
+
// ============================================================================
|
|
158
352
|
|
|
353
|
+
/**
|
|
354
|
+
* Create a template element from HTML
|
|
355
|
+
*/
|
|
159
356
|
export function createTemplate(html: string): HTMLTemplateElement;
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Clone a template's content
|
|
360
|
+
*/
|
|
160
361
|
export function cloneTemplate(template: HTMLTemplateElement): DocumentFragment;
|
|
161
|
-
export function renderToTemplate(component: any): HTMLTemplateElement;
|
|
162
362
|
|
|
163
|
-
|
|
363
|
+
/**
|
|
364
|
+
* Render a component to a template
|
|
365
|
+
*/
|
|
366
|
+
export function renderToTemplate(component: CoherentNode): HTMLTemplateElement;
|
|
367
|
+
|
|
368
|
+
// ============================================================================
|
|
369
|
+
// Lifecycle Hooks
|
|
370
|
+
// ============================================================================
|
|
164
371
|
|
|
372
|
+
/**
|
|
373
|
+
* Lifecycle hook definitions
|
|
374
|
+
*/
|
|
165
375
|
export interface LifecycleHooks {
|
|
376
|
+
/** Called when element is added to DOM */
|
|
166
377
|
onConnected?: () => void;
|
|
378
|
+
/** Called when element is removed from DOM */
|
|
167
379
|
onDisconnected?: () => void;
|
|
380
|
+
/** Called when element is moved to new document */
|
|
168
381
|
onAdopted?: () => void;
|
|
382
|
+
/** Called when observed attribute changes */
|
|
169
383
|
onAttributeChanged?: (name: string, oldValue: string | null, newValue: string | null) => void;
|
|
170
|
-
|
|
384
|
+
/** Called when a property changes */
|
|
385
|
+
onPropertyChanged?: (name: string, oldValue: unknown, newValue: unknown) => void;
|
|
171
386
|
}
|
|
172
387
|
|
|
388
|
+
/**
|
|
389
|
+
* Create a lifecycle manager
|
|
390
|
+
*/
|
|
173
391
|
export function createLifecycleManager(hooks: LifecycleHooks): {
|
|
174
392
|
connected(): void;
|
|
175
393
|
disconnected(): void;
|