@zeus-js/web-c-runtime 0.1.0 → 0.2.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.
@@ -5,6 +5,8 @@ export interface ZeusPropMeta {
5
5
  type: ZeusPropType;
6
6
  reflect?: boolean;
7
7
  default?: unknown;
8
+ serialize?: boolean;
9
+ deserialize?: boolean;
8
10
  }
9
11
  export interface ZeusLazyComponentMeta {
10
12
  tagName: string;
@@ -17,22 +19,32 @@ export interface ZeusLazyComponentMeta {
17
19
  default: ZeusComponentModule;
18
20
  }>;
19
21
  props: ZeusPropMeta[];
22
+ methods?: string[];
20
23
  /**
21
24
  * Whether to render into a ShadowRoot.
22
25
  *
23
26
  * @default false
24
27
  */
25
28
  shadow?: boolean;
29
+ /**
30
+ * Whether the proxy class participates in browser form association.
31
+ *
32
+ * @default false
33
+ */
34
+ formAssociated?: boolean;
26
35
  }
27
36
  export interface HostRef {
28
37
  host: HTMLElement;
29
38
  meta: ZeusLazyComponentMeta;
39
+ internals?: ElementInternals;
30
40
  connected: boolean;
31
41
  loaded: boolean;
32
42
  loading?: Promise<void>;
33
43
  instance?: ZeusComponentInstance;
34
44
  values: Map<string, unknown>;
45
+ attributeProps: Set<string>;
35
46
  reflectingAttrs: Set<string>;
47
+ pendingFormCallbacks: ZeusFormCallback[];
36
48
  readyWaiters: Array<{
37
49
  resolve(host: HTMLElement): void;
38
50
  reject(error: unknown): void;
@@ -42,6 +54,10 @@ export interface ZeusComponentInstance {
42
54
  connected?(): void;
43
55
  disconnected?(): void;
44
56
  propertyChanged?(name: string, oldValue: unknown, newValue: unknown): void;
57
+ formAssociated?(form: HTMLFormElement | null): void;
58
+ formDisabled?(disabled: boolean): void;
59
+ formReset?(): void;
60
+ formStateRestore?(state: File | FormData | string | null, mode: 'restore' | 'autocomplete'): void;
45
61
  /**
46
62
  * Can return Node / Node[] / string.
47
63
  * If the component completes rendering itself, it can also return void.
@@ -49,6 +65,19 @@ export interface ZeusComponentInstance {
49
65
  render?(): void | string | Node | Node[];
50
66
  dispose?(): void;
51
67
  }
68
+ type ZeusFormCallback = {
69
+ type: 'associated';
70
+ form: HTMLFormElement | null;
71
+ } | {
72
+ type: 'disabled';
73
+ disabled: boolean;
74
+ } | {
75
+ type: 'reset';
76
+ } | {
77
+ type: 'stateRestore';
78
+ state: File | FormData | string | null;
79
+ mode: 'restore' | 'autocomplete';
80
+ };
52
81
  export interface ZeusComponentModule {
53
82
  createComponent(hostRef: HostRef): ZeusComponentInstance;
54
83
  }
@@ -1,8 +1,29 @@
1
1
  /**
2
- * web-c-runtime v0.1.0
2
+ * web-c-runtime v0.2.0
3
3
  * (c) 2026 baicie
4
4
  * Released under the MIT License.
5
5
  **/
6
+ //#region packages/web-c/web-c-runtime/src/form-callbacks.ts
7
+ function invokeFormCallback(hostRef, callback) {
8
+ switch (callback.type) {
9
+ case "associated":
10
+ var _hostRef$instance, _hostRef$instance$for;
11
+ (_hostRef$instance = hostRef.instance) === null || _hostRef$instance === void 0 || (_hostRef$instance$for = _hostRef$instance.formAssociated) === null || _hostRef$instance$for === void 0 || _hostRef$instance$for.call(_hostRef$instance, callback.form);
12
+ return;
13
+ case "disabled":
14
+ var _hostRef$instance2, _hostRef$instance2$fo;
15
+ (_hostRef$instance2 = hostRef.instance) === null || _hostRef$instance2 === void 0 || (_hostRef$instance2$fo = _hostRef$instance2.formDisabled) === null || _hostRef$instance2$fo === void 0 || _hostRef$instance2$fo.call(_hostRef$instance2, callback.disabled);
16
+ return;
17
+ case "reset":
18
+ var _hostRef$instance3, _hostRef$instance3$fo;
19
+ (_hostRef$instance3 = hostRef.instance) === null || _hostRef$instance3 === void 0 || (_hostRef$instance3$fo = _hostRef$instance3.formReset) === null || _hostRef$instance3$fo === void 0 || _hostRef$instance3$fo.call(_hostRef$instance3);
20
+ return;
21
+ case "stateRestore":
22
+ var _hostRef$instance4, _hostRef$instance4$fo;
23
+ (_hostRef$instance4 = hostRef.instance) === null || _hostRef$instance4 === void 0 || (_hostRef$instance4$fo = _hostRef$instance4.formStateRestore) === null || _hostRef$instance4$fo === void 0 || _hostRef$instance4$fo.call(_hostRef$instance4, callback.state, callback.mode);
24
+ }
25
+ }
26
+ //#endregion
6
27
  //#region packages/web-c/web-c-runtime/src/host-ref.ts
7
28
  const hostRefs = /* @__PURE__ */ new WeakMap();
8
29
  function registerHost(host, meta) {
@@ -11,15 +32,27 @@ function registerHost(host, meta) {
11
32
  const hostRef = {
12
33
  host,
13
34
  meta,
35
+ internals: meta.formAssociated ? attachElementInternals(host) : void 0,
14
36
  connected: false,
15
37
  loaded: false,
16
38
  values: /* @__PURE__ */ new Map(),
39
+ attributeProps: /* @__PURE__ */ new Set(),
17
40
  reflectingAttrs: /* @__PURE__ */ new Set(),
41
+ pendingFormCallbacks: [],
18
42
  readyWaiters: []
19
43
  };
20
44
  hostRefs.set(host, hostRef);
21
45
  return hostRef;
22
46
  }
47
+ function attachElementInternals(host) {
48
+ if (typeof host.attachInternals !== "function") return;
49
+ try {
50
+ return host.attachInternals();
51
+ } catch (error) {
52
+ console.warn("[zeus:web-c] Failed to attach ElementInternals.", error);
53
+ return;
54
+ }
55
+ }
23
56
  function getHostRef(host) {
24
57
  return hostRefs.get(host);
25
58
  }
@@ -53,7 +86,8 @@ function setPropValue(hostRef, prop, value) {
53
86
  const oldValue = getPropValue(hostRef, prop);
54
87
  if (Object.is(oldValue, value)) return;
55
88
  hostRef.values.set(prop.name, value);
56
- if (prop.reflect) reflectPropertyToAttribute(hostRef, prop, value);
89
+ hostRef.attributeProps.delete(prop.name);
90
+ if (prop.reflect && !prop.serialize) reflectPropertyToAttribute(hostRef, prop, value);
57
91
  if (hostRef.loaded) {
58
92
  var _hostRef$instance, _hostRef$instance$pro;
59
93
  (_hostRef$instance = hostRef.instance) === null || _hostRef$instance === void 0 || (_hostRef$instance$pro = _hostRef$instance.propertyChanged) === null || _hostRef$instance$pro === void 0 || _hostRef$instance$pro.call(_hostRef$instance, prop.name, oldValue, value);
@@ -68,6 +102,7 @@ function syncAttributeToProperty(hostRef, attrName, _oldValue, newValue) {
68
102
  const newPropValue = parseAttributeValue(prop, newValue);
69
103
  if (Object.is(oldPropValue, newPropValue)) return;
70
104
  hostRef.values.set(prop.name, newPropValue);
105
+ hostRef.attributeProps.add(prop.name);
71
106
  if (hostRef.loaded) {
72
107
  var _hostRef$instance2, _hostRef$instance2$pr;
73
108
  (_hostRef$instance2 = hostRef.instance) === null || _hostRef$instance2 === void 0 || (_hostRef$instance2$pr = _hostRef$instance2.propertyChanged) === null || _hostRef$instance2$pr === void 0 || _hostRef$instance2$pr.call(_hostRef$instance2, prop.name, oldPropValue, newPropValue);
@@ -80,6 +115,7 @@ function applyInitialValues(hostRef) {
80
115
  const attrName = getAttrName(prop);
81
116
  if (attrName && host.hasAttribute(attrName)) {
82
117
  hostRef.values.set(prop.name, parseAttributeValue(prop, host.getAttribute(attrName)));
118
+ hostRef.attributeProps.add(prop.name);
83
119
  continue;
84
120
  }
85
121
  if ("default" in prop) hostRef.values.set(prop.name, prop.default);
@@ -119,7 +155,7 @@ function findPropByAttrName(hostRef, attrName) {
119
155
  function getAttrName(prop) {
120
156
  var _prop$attrName;
121
157
  if (prop.attrName === false) return;
122
- if (!isAttributeBackedType(prop.type)) return;
158
+ if (!isAttributeBackedType(prop.type) && !prop.deserialize) return;
123
159
  return normalizeAttrName((_prop$attrName = prop.attrName) !== null && _prop$attrName !== void 0 ? _prop$attrName : toKebabCase(prop.name));
124
160
  }
125
161
  function isAttributeBackedType(type) {
@@ -129,6 +165,7 @@ function normalizeAttrName(value) {
129
165
  return value.toLowerCase();
130
166
  }
131
167
  function parseAttributeValue(prop, value) {
168
+ if (prop.deserialize) return value;
132
169
  switch (prop.type) {
133
170
  case "boolean": return value !== null;
134
171
  case "number":
@@ -206,6 +243,7 @@ function _initializeComponent() {
206
243
  if (hostRef.loaded) {
207
244
  var _hostRef$instance, _hostRef$instance$con;
208
245
  (_hostRef$instance = hostRef.instance) === null || _hostRef$instance === void 0 || (_hostRef$instance$con = _hostRef$instance.connected) === null || _hostRef$instance$con === void 0 || _hostRef$instance$con.call(_hostRef$instance);
246
+ flushPendingFormCallbacks(hostRef);
209
247
  return;
210
248
  }
211
249
  if (hostRef.loading) {
@@ -238,6 +276,7 @@ function _doInitializeComponent() {
238
276
  try {
239
277
  var _instance$connected, _instance$render;
240
278
  (_instance$connected = instance.connected) === null || _instance$connected === void 0 || _instance$connected.call(instance);
279
+ flushPendingFormCallbacks(hostRef);
241
280
  const rendered = (_instance$render = instance.render) === null || _instance$render === void 0 ? void 0 : _instance$render.call(instance);
242
281
  if (rendered !== void 0) mountRenderedOutput(hostRef, rendered);
243
282
  hostRef.loaded = true;
@@ -252,6 +291,12 @@ function _doInitializeComponent() {
252
291
  });
253
292
  return _doInitializeComponent.apply(this, arguments);
254
293
  }
294
+ function flushPendingFormCallbacks(hostRef) {
295
+ while (hostRef.pendingFormCallbacks.length > 0) {
296
+ invokeFormCallback(hostRef, hostRef.pendingFormCallbacks[0]);
297
+ hostRef.pendingFormCallbacks.shift();
298
+ }
299
+ }
255
300
  function loadComponentModule(_x3) {
256
301
  return _loadComponentModule.apply(this, arguments);
257
302
  }
@@ -331,6 +376,28 @@ function createLazyElementClass(meta) {
331
376
  if (oldValue === newValue) return;
332
377
  syncAttributeToProperty(requireHostRef(this), name, oldValue, newValue);
333
378
  }
379
+ formAssociatedCallback(form) {
380
+ dispatchFormCallback(requireHostRef(this), {
381
+ type: "associated",
382
+ form
383
+ });
384
+ }
385
+ formDisabledCallback(disabled) {
386
+ dispatchFormCallback(requireHostRef(this), {
387
+ type: "disabled",
388
+ disabled
389
+ });
390
+ }
391
+ formResetCallback() {
392
+ dispatchFormCallback(requireHostRef(this), { type: "reset" });
393
+ }
394
+ formStateRestoreCallback(state, mode) {
395
+ dispatchFormCallback(requireHostRef(this), {
396
+ type: "stateRestore",
397
+ state,
398
+ mode
399
+ });
400
+ }
334
401
  componentOnReady() {
335
402
  const hostRef = requireHostRef(this);
336
403
  if (hostRef.connected && !hostRef.loaded && !hostRef.loading) initializeComponent(hostRef).catch((error) => {
@@ -339,9 +406,37 @@ function createLazyElementClass(meta) {
339
406
  return waitForComponentReady(hostRef);
340
407
  }
341
408
  }
409
+ ZeusLazyElement.formAssociated = Boolean(meta.formAssociated);
342
410
  installPropertyAccessors(ZeusLazyElement.prototype, meta.props);
411
+ installMethodProxies(ZeusLazyElement.prototype, meta.methods);
343
412
  return ZeusLazyElement;
344
413
  }
414
+ function dispatchFormCallback(hostRef, callback) {
415
+ if (!hostRef.instance || !hostRef.connected) {
416
+ hostRef.pendingFormCallbacks.push(callback);
417
+ return;
418
+ }
419
+ invokeFormCallback(hostRef, callback);
420
+ }
421
+ function installMethodProxies(proto, methods) {
422
+ if (!methods) return;
423
+ for (const name of methods) {
424
+ if (name in proto) continue;
425
+ Object.defineProperty(proto, name, {
426
+ configurable: true,
427
+ value: function() {
428
+ const host = this;
429
+ const args = Array.prototype.slice.call(arguments);
430
+ const hostRef = requireHostRef(host);
431
+ return waitForComponentReady(hostRef).then((readyHost) => {
432
+ const method = readyHost[name];
433
+ if (typeof method !== "function") throw new Error(`[zeus:web-c] Method "${name}" is not exposed on <${hostRef.meta.tagName}>.`);
434
+ return method.apply(readyHost, args);
435
+ });
436
+ }
437
+ });
438
+ }
439
+ }
345
440
  //#endregion
346
441
  //#region packages/web-c/web-c-runtime/src/bootstrapLazy.ts
347
442
  function bootstrapLazy(components) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeus-js/web-c-runtime",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Zeus Web-C lazy-loading runtime",
5
5
  "type": "module",
6
6
  "main": "./dist/web-c-runtime.esm-bundler.js",