@zeus-js/runtime-dom 0.1.0-beta.2 → 0.1.0-beta.4

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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * runtime-dom v0.1.0-beta.2
2
+ * runtime-dom v0.1.0-beta.4
3
3
  * (c) 2026 baicie
4
4
  * Released under the MIT License.
5
5
  **/
@@ -166,7 +166,7 @@ function useContext(context, fallback) {
166
166
  const ZEUS_CONTEXT_REQUEST = "zeus:context-request";
167
167
  /**
168
168
  * Creates a transparent DOM element that acts as a context boundary.
169
- * Native custom elements inside it can use `requestDOMContext` to receive
169
+ * Native custom elements inside it can use `resolveDOMContext` to receive
170
170
  * context values via the DOM event protocol.
171
171
  */
172
172
  function createDOMContextBoundary(context, value, children) {
@@ -178,7 +178,7 @@ function createDOMContextBoundary(context, value, children) {
178
178
  }
179
179
  /**
180
180
  * Registers a context value on a DOM target so that any descendant custom
181
- * element can pick it up via `requestDOMContext`.
181
+ * element can pick it up via `resolveDOMContext`.
182
182
  */
183
183
  function provideDOMContext(target, context, value) {
184
184
  const handler = (event) => {
@@ -196,7 +196,7 @@ function provideDOMContext(target, context, value) {
196
196
  /**
197
197
  * Internal precise DOM context resolver.
198
198
  *
199
- * Unlike requestDOMContext(), this can distinguish:
199
+ * The result distinguishes:
200
200
  * - found: false, value: undefined
201
201
  * - found: true, value: undefined
202
202
  */
@@ -225,16 +225,6 @@ function resolveDOMContext(host, context) {
225
225
  value
226
226
  };
227
227
  }
228
- /**
229
- * Public compatibility API.
230
- *
231
- * Returns the resolved value if found, otherwise undefined.
232
- * If you need to distinguish "not found" from "found undefined",
233
- * use resolveDOMContext().
234
- */
235
- function requestDOMContext(host, context) {
236
- return resolveDOMContext(host, context).value;
237
- }
238
228
  function resolveValue$3(value) {
239
229
  return typeof value === "function" ? value() : value !== null && value !== void 0 ? value : null;
240
230
  }
@@ -625,6 +615,41 @@ function mountFor(parent, marker, each, key, render) {
625
615
  }
626
616
  //#endregion
627
617
  //#region packages/core/runtime-dom/src/defineElement.ts
618
+ const ZEUS_ELEMENT_DEFINITION = Symbol.for("zeus.element.definition");
619
+ function prop(input, options = {}) {
620
+ var _options$reflect, _options$default;
621
+ if (Array.isArray(input)) return {
622
+ type: String,
623
+ values: input,
624
+ attr: options.attr,
625
+ reflect: options.reflect,
626
+ default: options.default,
627
+ serialize: options.serialize,
628
+ deserialize: options.deserialize
629
+ };
630
+ const type = input;
631
+ return {
632
+ type,
633
+ attr: options.attr,
634
+ reflect: type === Boolean ? (_options$reflect = options.reflect) !== null && _options$reflect !== void 0 ? _options$reflect : true : options.reflect,
635
+ default: type === Boolean ? (_options$default = options.default) !== null && _options$default !== void 0 ? _options$default : false : options.default,
636
+ serialize: options.serialize,
637
+ deserialize: options.deserialize
638
+ };
639
+ }
640
+ function event(input) {
641
+ if (typeof input === "string") return {
642
+ __zeusEvent: true,
643
+ name: input
644
+ };
645
+ return {
646
+ __zeusEvent: true,
647
+ name: input === null || input === void 0 ? void 0 : input.name,
648
+ bubbles: input === null || input === void 0 ? void 0 : input.bubbles,
649
+ composed: input === null || input === void 0 ? void 0 : input.composed,
650
+ cancelable: input === null || input === void 0 ? void 0 : input.cancelable
651
+ };
652
+ }
628
653
  function createPropStore(defs) {
629
654
  const slots = /* @__PURE__ */ new Map();
630
655
  const props = {};
@@ -661,6 +686,12 @@ function createPropStore(defs) {
661
686
  function defineElement(tagName, options, setup) {
662
687
  var _options$props;
663
688
  const propDefs = normalizePropDefinitions((_options$props = options.props) !== null && _options$props !== void 0 ? _options$props : {});
689
+ const definition = {
690
+ tagName,
691
+ options,
692
+ setup,
693
+ propDefs
694
+ };
664
695
  const observedAttributes = propDefs.filter((def) => def.attr !== false).map((def) => def.attr);
665
696
  class ZeusElement extends HTMLElement {
666
697
  static get observedAttributes() {
@@ -675,6 +706,13 @@ function defineElement(tagName, options, setup) {
675
706
  this.props = this.propStore.props;
676
707
  applyPropDefaults(this.propStore, propDefs);
677
708
  definePropAccessors(this, this.propStore, propDefs);
709
+ if (options.formAssociated) this.internals = attachElementInternals(this);
710
+ this.setupContext = {
711
+ host: this,
712
+ internals: this.internals,
713
+ emit: createEmitApi(this, options.emits),
714
+ expose: createExpose(this)
715
+ };
678
716
  }
679
717
  connectedCallback() {
680
718
  var _options$shadow, _options$consumes;
@@ -698,19 +736,10 @@ function defineElement(tagName, options, setup) {
698
736
  mode,
699
737
  lightChildren: this.lightChildren
700
738
  };
701
- const setupContext = {
702
- host: this,
703
- emit: (name, detail, eventOptions) => {
704
- return this.dispatchEvent(new CustomEvent(name, {
705
- bubbles: true,
706
- composed: true,
707
- cancelable: true,
708
- ...eventOptions,
709
- detail
710
- }));
711
- }
712
- };
713
- this.dispose = render(() => runWithOwner(owner, () => withHostContext(hostContext, () => setup(this.props, setupContext))), target, { owner });
739
+ this.dispose = render(() => runWithOwner(owner, () => withHostContext(hostContext, () => {
740
+ syncFormValue(this.props, this.setupContext, options.form);
741
+ return setup(this.props, this.setupContext);
742
+ })), target, { owner });
714
743
  mountStyles(target, options.styles);
715
744
  }
716
745
  disconnectedCallback() {
@@ -718,6 +747,22 @@ function defineElement(tagName, options, setup) {
718
747
  (_this$dispose = this.dispose) === null || _this$dispose === void 0 || _this$dispose.call(this);
719
748
  this.dispose = void 0;
720
749
  }
750
+ formAssociatedCallback(form) {
751
+ var _options$form, _options$form$associa;
752
+ (_options$form = options.form) === null || _options$form === void 0 || (_options$form$associa = _options$form.associated) === null || _options$form$associa === void 0 || _options$form$associa.call(_options$form, form, this.props, this.setupContext);
753
+ }
754
+ formDisabledCallback(disabled) {
755
+ var _options$form2, _options$form2$disabl;
756
+ (_options$form2 = options.form) === null || _options$form2 === void 0 || (_options$form2$disabl = _options$form2.disabled) === null || _options$form2$disabl === void 0 || _options$form2$disabl.call(_options$form2, disabled, this.props, this.setupContext);
757
+ }
758
+ formResetCallback() {
759
+ var _options$form3, _options$form3$reset;
760
+ (_options$form3 = options.form) === null || _options$form3 === void 0 || (_options$form3$reset = _options$form3.reset) === null || _options$form3$reset === void 0 || _options$form3$reset.call(_options$form3, this.props, this.setupContext);
761
+ }
762
+ formStateRestoreCallback(state, mode) {
763
+ var _options$form4, _options$form4$stateR;
764
+ (_options$form4 = options.form) === null || _options$form4 === void 0 || (_options$form4$stateR = _options$form4.stateRestore) === null || _options$form4$stateR === void 0 || _options$form4$stateR.call(_options$form4, state, mode, this.props, this.setupContext);
765
+ }
721
766
  attributeChangedCallback(name, oldValue, newValue) {
722
767
  if (oldValue === newValue || this.reflecting) return;
723
768
  const def = propDefs.find((item) => item.attr === name);
@@ -753,24 +798,131 @@ function defineElement(tagName, options, setup) {
753
798
  }
754
799
  }
755
800
  }
801
+ ZeusElement.formAssociated = Boolean(options.formAssociated);
756
802
  if (!customElements.get(tagName)) customElements.define(tagName, ZeusElement);
803
+ Object.defineProperty(ZeusElement, ZEUS_ELEMENT_DEFINITION, {
804
+ value: definition,
805
+ configurable: false
806
+ });
757
807
  return ZeusElement;
758
808
  }
809
+ function getElementDefinition(ctor) {
810
+ const definition = ctor[ZEUS_ELEMENT_DEFINITION];
811
+ if (!definition) throw new Error("[zeus] Element definition metadata not found.");
812
+ return definition;
813
+ }
814
+ function mountElementDefinition(ctor, host, initialValues = /* @__PURE__ */ new Map(), mountState = {}) {
815
+ var _options$shadow2, _mountState$lightChil, _options$consumes2, _mountState$target, _mountState$internals;
816
+ const { options, setup, propDefs } = getElementDefinition(ctor);
817
+ const propStore = createPropStore(propDefs);
818
+ applyPropDefaults(propStore, propDefs);
819
+ for (const def of propDefs) {
820
+ var _mountState$attribute;
821
+ if (def.attr !== false && ((_mountState$attribute = mountState.attributeProps) === null || _mountState$attribute === void 0 ? void 0 : _mountState$attribute.has(def.key))) {
822
+ propStore.set(def.key, castAttributeValue(host.getAttribute(def.attr), def));
823
+ initialValues.set(def.key, propStore.get(def.key));
824
+ continue;
825
+ }
826
+ if (initialValues.has(def.key)) {
827
+ propStore.set(def.key, initialValues.get(def.key));
828
+ continue;
829
+ }
830
+ /**
831
+ * Sync real definition defaults (e.g. factory defaults like `default: () => []`)
832
+ * back to the lazy host value map so that `element.propName` returns the
833
+ * correct default value rather than undefined.
834
+ */
835
+ initialValues.set(def.key, propStore.get(def.key));
836
+ }
837
+ for (const def of propDefs) {
838
+ var _mountState$attribute2;
839
+ if (def.reflect && def.serialize && !((_mountState$attribute2 = mountState.attributeProps) === null || _mountState$attribute2 === void 0 ? void 0 : _mountState$attribute2.has(def.key))) reflectExternalProp(host, def, propStore.get(def.key), mountState.reflectingAttrs);
840
+ }
841
+ const shadow = (_options$shadow2 = options.shadow) !== null && _options$shadow2 !== void 0 ? _options$shadow2 : false;
842
+ const mode = shadow ? "shadow" : "light";
843
+ if (mode === "light" && !mountState.capturedLightChildren) {
844
+ mountState.lightChildren = Array.from(host.childNodes);
845
+ mountState.capturedLightChildren = true;
846
+ }
847
+ const lightChildren = (_mountState$lightChil = mountState.lightChildren) !== null && _mountState$lightChil !== void 0 ? _mountState$lightChil : [];
848
+ const owner = createOwner();
849
+ for (const context of (_options$consumes2 = options.consumes) !== null && _options$consumes2 !== void 0 ? _options$consumes2 : []) {
850
+ const resolved = resolveDOMContext(host, context);
851
+ if (resolved.found) owner.provides.set(context.id, resolved.value);
852
+ else if (context.hasDefaultValue) owner.provides.set(context.id, context.defaultValue);
853
+ }
854
+ const target = (_mountState$target = mountState.target) !== null && _mountState$target !== void 0 ? _mountState$target : mountState.target = resolveExternalRenderTarget(host, shadow);
855
+ const hostContext = {
856
+ host,
857
+ mode,
858
+ lightChildren
859
+ };
860
+ const setupContext = {
861
+ host,
862
+ internals: (_mountState$internals = mountState.internals) !== null && _mountState$internals !== void 0 ? _mountState$internals : options.formAssociated ? attachElementInternals(host) : void 0,
863
+ emit: createEmitApi(host, options.emits),
864
+ expose: createExpose(host)
865
+ };
866
+ mountState.internals = setupContext.internals;
867
+ const dispose = render(() => runWithOwner(owner, () => withHostContext(hostContext, () => {
868
+ syncFormValue(propStore.props, setupContext, options.form);
869
+ return setup(propStore.props, setupContext);
870
+ })), target, { owner });
871
+ mountStyles(target, options.styles);
872
+ return {
873
+ propertyChanged(name, _oldValue, newValue) {
874
+ var _mountState$attribute3;
875
+ const def = propDefs.find((item) => item.key === name);
876
+ const fromAttribute = Boolean((def === null || def === void 0 ? void 0 : def.attr) !== false && ((_mountState$attribute3 = mountState.attributeProps) === null || _mountState$attribute3 === void 0 ? void 0 : _mountState$attribute3.has(name)));
877
+ const value = fromAttribute && def ? castAttributeValue(typeof newValue === "string" ? newValue : null, def) : newValue;
878
+ propStore.set(name, value);
879
+ initialValues.set(name, value);
880
+ if ((def === null || def === void 0 ? void 0 : def.reflect) && !fromAttribute) reflectExternalProp(host, def, value, mountState.reflectingAttrs);
881
+ },
882
+ formAssociated(form) {
883
+ var _options$form5, _options$form5$associ;
884
+ (_options$form5 = options.form) === null || _options$form5 === void 0 || (_options$form5$associ = _options$form5.associated) === null || _options$form5$associ === void 0 || _options$form5$associ.call(_options$form5, form, propStore.props, setupContext);
885
+ },
886
+ formDisabled(disabled) {
887
+ var _options$form6, _options$form6$disabl;
888
+ (_options$form6 = options.form) === null || _options$form6 === void 0 || (_options$form6$disabl = _options$form6.disabled) === null || _options$form6$disabl === void 0 || _options$form6$disabl.call(_options$form6, disabled, propStore.props, setupContext);
889
+ },
890
+ formReset() {
891
+ var _options$form7, _options$form7$reset;
892
+ (_options$form7 = options.form) === null || _options$form7 === void 0 || (_options$form7$reset = _options$form7.reset) === null || _options$form7$reset === void 0 || _options$form7$reset.call(_options$form7, propStore.props, setupContext);
893
+ },
894
+ formStateRestore(state, mode) {
895
+ var _options$form8, _options$form8$stateR;
896
+ (_options$form8 = options.form) === null || _options$form8 === void 0 || (_options$form8$stateR = _options$form8.stateRestore) === null || _options$form8$stateR === void 0 || _options$form8$stateR.call(_options$form8, state, mode, propStore.props, setupContext);
897
+ },
898
+ dispose() {
899
+ dispose();
900
+ }
901
+ };
902
+ }
759
903
  function normalizePropDefinitions(props) {
760
904
  return Object.keys(props).map((key) => {
905
+ const propKey = String(key);
761
906
  const input = props[key];
762
- if (typeof input === "function") return {
763
- key,
764
- attr: toKebabCase(key),
765
- type: input,
766
- reflect: false
767
- };
907
+ if (typeof input === "function") {
908
+ const type = input;
909
+ return {
910
+ key: propKey,
911
+ attr: isAttributeBackedConstructor(type) ? toKebabCase(propKey) : false,
912
+ type,
913
+ reflect: false
914
+ };
915
+ }
916
+ const type = input === null || input === void 0 ? void 0 : input.type;
917
+ const defaultAttr = isAttributeBackedConstructor(type) ? toKebabCase(propKey) : false;
768
918
  return {
769
- key,
770
- attr: (input === null || input === void 0 ? void 0 : input.attr) === void 0 ? toKebabCase(key) : input.attr,
771
- type: input === null || input === void 0 ? void 0 : input.type,
919
+ key: propKey,
920
+ attr: (input === null || input === void 0 ? void 0 : input.attr) === void 0 ? defaultAttr : input.attr,
921
+ type,
772
922
  reflect: Boolean(input === null || input === void 0 ? void 0 : input.reflect),
773
- default: input === null || input === void 0 ? void 0 : input.default
923
+ default: input === null || input === void 0 ? void 0 : input.default,
924
+ serialize: input === null || input === void 0 ? void 0 : input.serialize,
925
+ deserialize: input === null || input === void 0 ? void 0 : input.deserialize
774
926
  };
775
927
  });
776
928
  }
@@ -803,6 +955,7 @@ function definePropAccessors(element, store, defs) {
803
955
  }
804
956
  }
805
957
  function castAttributeValue(value, def) {
958
+ if (def.deserialize) return def.deserialize(value);
806
959
  if (def.type === Boolean) return value !== null;
807
960
  if (value === null) return;
808
961
  if (def.type === Number) return Number(value);
@@ -811,10 +964,17 @@ function castAttributeValue(value, def) {
811
964
  } catch {
812
965
  return def.type === Array ? [] : {};
813
966
  }
967
+ if (def.type === Function) return;
814
968
  return value;
815
969
  }
816
970
  function reflectPropToAttribute(element, def, value) {
817
971
  if (def.attr === false) return;
972
+ if (def.serialize) {
973
+ const serialized = def.serialize(value);
974
+ if (serialized == null) element.removeAttribute(def.attr);
975
+ else element.setAttribute(def.attr, serialized);
976
+ return;
977
+ }
818
978
  if (def.type === Boolean) {
819
979
  if (value) element.setAttribute(def.attr, "");
820
980
  else element.removeAttribute(def.attr);
@@ -828,8 +988,84 @@ function reflectPropToAttribute(element, def, value) {
828
988
  element.setAttribute(def.attr, JSON.stringify(value));
829
989
  return;
830
990
  }
991
+ if (def.type === Function) return;
831
992
  element.setAttribute(def.attr, String(value));
832
993
  }
994
+ function reflectExternalProp(element, def, value, reflectingAttrs) {
995
+ if (def.attr === false) return;
996
+ const attrName = def.attr.toLowerCase();
997
+ reflectingAttrs === null || reflectingAttrs === void 0 || reflectingAttrs.add(attrName);
998
+ try {
999
+ reflectPropToAttribute(element, def, value);
1000
+ } finally {
1001
+ reflectingAttrs === null || reflectingAttrs === void 0 || reflectingAttrs.delete(attrName);
1002
+ }
1003
+ }
1004
+ function syncFormValue(props, context, form) {
1005
+ const valueResolver = form === null || form === void 0 ? void 0 : form.value;
1006
+ const stateResolver = form === null || form === void 0 ? void 0 : form.state;
1007
+ if (!context.internals || valueResolver === void 0) return;
1008
+ (0, _zeus_js_signal.effect)(() => {
1009
+ const value = resolveFormValue(props, valueResolver);
1010
+ const state = stateResolver === void 0 ? void 0 : resolveFormValue(props, stateResolver);
1011
+ context.internals.setFormValue(value, state);
1012
+ });
1013
+ }
1014
+ function resolveFormValue(props, resolver) {
1015
+ if (typeof resolver === "function") {
1016
+ var _resolver;
1017
+ return (_resolver = resolver(props)) !== null && _resolver !== void 0 ? _resolver : null;
1018
+ }
1019
+ const value = props[resolver];
1020
+ return value == null ? null : value;
1021
+ }
1022
+ function attachElementInternals(host) {
1023
+ const attachInternals = host.attachInternals;
1024
+ if (typeof attachInternals !== "function") return;
1025
+ try {
1026
+ return attachInternals.call(host);
1027
+ } catch (error) {
1028
+ return;
1029
+ }
1030
+ }
1031
+ function createEmitApi(host, emits) {
1032
+ const emit = {};
1033
+ const dispatch = (name, detail, options) => {
1034
+ var _definition$name, _ref, _options$bubbles, _ref2, _options$composed, _ref3, _options$cancelable;
1035
+ const definition = emits === null || emits === void 0 ? void 0 : emits[name];
1036
+ return host.dispatchEvent(new CustomEvent((_definition$name = definition === null || definition === void 0 ? void 0 : definition.name) !== null && _definition$name !== void 0 ? _definition$name : toKebabCase(name), {
1037
+ bubbles: (_ref = (_options$bubbles = options === null || options === void 0 ? void 0 : options.bubbles) !== null && _options$bubbles !== void 0 ? _options$bubbles : definition === null || definition === void 0 ? void 0 : definition.bubbles) !== null && _ref !== void 0 ? _ref : true,
1038
+ composed: (_ref2 = (_options$composed = options === null || options === void 0 ? void 0 : options.composed) !== null && _options$composed !== void 0 ? _options$composed : definition === null || definition === void 0 ? void 0 : definition.composed) !== null && _ref2 !== void 0 ? _ref2 : true,
1039
+ cancelable: (_ref3 = (_options$cancelable = options === null || options === void 0 ? void 0 : options.cancelable) !== null && _options$cancelable !== void 0 ? _options$cancelable : definition === null || definition === void 0 ? void 0 : definition.cancelable) !== null && _ref3 !== void 0 ? _ref3 : false,
1040
+ detail
1041
+ }));
1042
+ };
1043
+ if (emits) for (const key of Object.keys(emits)) Object.defineProperty(emit, key, {
1044
+ configurable: true,
1045
+ enumerable: true,
1046
+ value(detail, options) {
1047
+ return dispatch(key, detail, options);
1048
+ }
1049
+ });
1050
+ return emit;
1051
+ }
1052
+ function createExpose(host) {
1053
+ return (methods) => {
1054
+ for (const key of Object.keys(methods)) Object.defineProperty(host, key, {
1055
+ configurable: true,
1056
+ enumerable: false,
1057
+ value: methods[key]
1058
+ });
1059
+ };
1060
+ }
1061
+ function isAttributeBackedConstructor(type) {
1062
+ return type === String || type === Number || type === Boolean;
1063
+ }
1064
+ function resolveExternalRenderTarget(host, shadow) {
1065
+ var _host$shadowRoot;
1066
+ if (!shadow) return host;
1067
+ return (_host$shadowRoot = host.shadowRoot) !== null && _host$shadowRoot !== void 0 ? _host$shadowRoot : host.attachShadow(typeof shadow === "object" ? shadow : { mode: "open" });
1068
+ }
833
1069
  function mountStyles(target, styles) {
834
1070
  if (!styles) return;
835
1071
  const list = Array.isArray(styles) ? styles : [styles];
@@ -971,6 +1207,7 @@ exports.Host = Host;
971
1207
  exports.Show = Show;
972
1208
  exports.Slot = Slot;
973
1209
  exports.ZEUS_CONTEXT_REQUEST = ZEUS_CONTEXT_REQUEST;
1210
+ exports.ZEUS_ELEMENT_DEFINITION = ZEUS_ELEMENT_DEFINITION;
974
1211
  exports.bindAttr = bindAttr;
975
1212
  exports.bindClass = bindClass;
976
1213
  exports.bindEvent = bindEvent;
@@ -988,21 +1225,24 @@ exports.createOwner = createOwner;
988
1225
  exports.createSlot = createSlot;
989
1226
  exports.defineElement = defineElement;
990
1227
  exports.delegateEvents = delegateEvents;
1228
+ exports.event = event;
991
1229
  exports.getCurrentHostContext = getCurrentHostContext;
992
1230
  exports.getCurrentOwner = getCurrentOwner;
1231
+ exports.getElementDefinition = getElementDefinition;
993
1232
  exports.inject = inject;
994
1233
  exports.insert = insert;
995
1234
  exports.insertTracked = insertTracked;
996
1235
  exports.marker = marker;
997
1236
  exports.mountDynamic = mountDynamic;
1237
+ exports.mountElementDefinition = mountElementDefinition;
998
1238
  exports.mountFor = mountFor;
999
1239
  exports.mountShow = mountShow;
1000
1240
  exports.normalizeClass = normalizeClass;
1241
+ exports.prop = prop;
1001
1242
  exports.provide = provide;
1002
1243
  exports.provideDOMContext = provideDOMContext;
1003
1244
  exports.removeNodes = removeNodes;
1004
1245
  exports.render = render;
1005
- exports.requestDOMContext = requestDOMContext;
1006
1246
  exports.resolveDOMContext = resolveDOMContext;
1007
1247
  exports.resolveValue = resolveValue;
1008
1248
  exports.runWithOwner = runWithOwner;
@@ -72,31 +72,23 @@ export interface DOMContextResolution<T> {
72
72
  }
73
73
  /**
74
74
  * Creates a transparent DOM element that acts as a context boundary.
75
- * Native custom elements inside it can use `requestDOMContext` to receive
75
+ * Native custom elements inside it can use `resolveDOMContext` to receive
76
76
  * context values via the DOM event protocol.
77
77
  */
78
78
  export declare function createDOMContextBoundary<T>(context: Context<T>, value: T, children: JSXValue): Element;
79
79
  /**
80
80
  * Registers a context value on a DOM target so that any descendant custom
81
- * element can pick it up via `requestDOMContext`.
81
+ * element can pick it up via `resolveDOMContext`.
82
82
  */
83
83
  export declare function provideDOMContext<T>(target: EventTarget, context: Context<T>, value: T): void;
84
84
  /**
85
85
  * Internal precise DOM context resolver.
86
86
  *
87
- * Unlike requestDOMContext(), this can distinguish:
87
+ * The result distinguishes:
88
88
  * - found: false, value: undefined
89
89
  * - found: true, value: undefined
90
90
  */
91
91
  export declare function resolveDOMContext<T>(host: HTMLElement, context: Context<T>): DOMContextResolution<T>;
92
- /**
93
- * Public compatibility API.
94
- *
95
- * Returns the resolved value if found, otherwise undefined.
96
- * If you need to distinguish "not found" from "found undefined",
97
- * use resolveDOMContext().
98
- */
99
- export declare function requestDOMContext<T>(host: HTMLElement, context: Context<T>): T | undefined;
100
92
 
101
93
  export interface RenderOptions {
102
94
  owner?: ReturnType<typeof createOwner>;
@@ -145,15 +137,57 @@ export type ForProps<T, K = unknown> = {
145
137
  export declare function For<T, K = unknown>(props: ForProps<T, K>): JSXValue;
146
138
  export declare function mountFor<T, K = unknown>(parent: Node, marker: Node, each: () => readonly T[] | null | undefined, key: ((item: T, index: number) => K) | undefined, render: (item: T, index: number) => JSXValue): void;
147
139
 
148
- export type ElementPropConstructor = StringConstructor | NumberConstructor | BooleanConstructor | ObjectConstructor | ArrayConstructor;
149
- export type PropDefinition<T = unknown> = ElementPropConstructor | {
140
+ export type ElementPropConstructor = StringConstructor | NumberConstructor | BooleanConstructor | ObjectConstructor | ArrayConstructor | FunctionConstructor;
141
+ export type PropSerializer<T = unknown> = {
142
+ bivarianceHack(value: T | undefined): string | null | undefined;
143
+ }['bivarianceHack'];
144
+ export type PropDeserializer<T = unknown> = {
145
+ bivarianceHack(value: string | null): T | undefined;
146
+ }['bivarianceHack'];
147
+ export interface PropDefinitionOptions<T = unknown> {
150
148
  type?: ElementPropConstructor;
151
149
  attr?: string | false;
152
150
  reflect?: boolean;
153
151
  default?: T | (() => T);
152
+ values?: readonly T[];
153
+ serialize?(value: T | undefined): string | null | undefined;
154
+ deserialize?(value: string | null): T | undefined;
155
+ }
156
+ export type PropDefinition<T = unknown> = ElementPropConstructor | PropDefinitionOptions<T>;
157
+ export interface ValuePropDefinition<T = unknown> extends PropDefinitionOptions<T> {
158
+ type: StringConstructor;
159
+ values: readonly T[];
160
+ }
161
+ type ConstructorPropDefinition<T = unknown, C extends ElementPropConstructor = ElementPropConstructor> = PropDefinitionOptions<T> & {
162
+ type: C;
163
+ };
164
+ export interface EventDefinition<Detail = unknown> {
165
+ __zeusEvent: true;
166
+ name?: string;
167
+ bubbles?: boolean;
168
+ composed?: boolean;
169
+ cancelable?: boolean;
170
+ __detail?: Detail;
171
+ }
172
+ export interface EventOptions {
173
+ name?: string;
174
+ bubbles?: boolean;
175
+ composed?: boolean;
176
+ cancelable?: boolean;
177
+ }
178
+ export interface EmitsOptions {
179
+ [key: string]: EventDefinition<unknown>;
180
+ }
181
+ export type FormAssociatedValue = File | FormData | string | null;
182
+ export type FormStateRestoreMode = 'restore' | 'autocomplete';
183
+ type ExplicitPropKeys<T> = keyof {
184
+ [K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: T[K];
185
+ };
186
+ export type EmitApi<E extends EmitsOptions> = {
187
+ [K in keyof E]: E[K] extends EventDefinition<infer Detail> ? (detail: Detail, options?: CustomEventInit) => boolean : never;
154
188
  };
155
189
  export type PropOptions<P extends object> = Partial<{
156
- [K in keyof P]: PropDefinition<P[K]>;
190
+ [K in ExplicitPropKeys<P>]: PropDefinition<P[K]>;
157
191
  }>;
158
192
  export interface DefineElementMeta {
159
193
  description?: string;
@@ -169,27 +203,101 @@ export interface DefineElementMeta {
169
203
  slots?: Record<string, {
170
204
  description?: string;
171
205
  }>;
172
- cssVars?: string[];
206
+ cssVars?: Record<string, {
207
+ description?: string;
208
+ }>;
173
209
  cssParts?: string[];
174
210
  [key: string]: unknown;
175
211
  }
176
- export interface DefineElementOptions<P extends object> {
212
+ export interface DefineElementOptions<P extends object, E extends EmitsOptions = EmitsOptions> {
177
213
  shadow?: boolean | ShadowRootInit;
214
+ formAssociated?: boolean;
215
+ form?: FormAssociatedOptions<P, HTMLElement, E>;
178
216
  props?: PropOptions<P>;
217
+ emits?: E;
179
218
  styles?: string | string[];
180
219
  consumes?: Context<any>[];
220
+ models?: readonly ElementModelDefinition<P>[];
221
+ slots?: readonly string[];
222
+ parts?: readonly string[];
223
+ cssVars?: Record<string, {
224
+ description?: string;
225
+ }>;
181
226
  /**
182
227
  * Metadata only.
183
228
  * Runtime does not consume this field.
184
229
  */
185
230
  meta?: DefineElementMeta;
186
231
  }
187
- export interface DefineElementContext<E extends HTMLElement = HTMLElement> {
232
+ export interface FormAssociatedOptions<P extends object, E extends HTMLElement = HTMLElement, Emits extends EmitsOptions = EmitsOptions> {
233
+ value?: ExplicitPropKeys<P> | ((props: Readonly<P>) => FormAssociatedValue);
234
+ state?: ExplicitPropKeys<P> | ((props: Readonly<P>) => FormAssociatedValue);
235
+ associated?(form: HTMLFormElement | null, props: Readonly<P>, context: DefineElementContext<E, Emits>): void;
236
+ disabled?(disabled: boolean, props: Readonly<P>, context: DefineElementContext<E, Emits>): void;
237
+ reset?(props: Readonly<P>, context: DefineElementContext<E, Emits>): void;
238
+ stateRestore?(state: FormAssociatedValue, mode: FormStateRestoreMode, props: Readonly<P>, context: DefineElementContext<E, Emits>): void;
239
+ }
240
+ export interface ElementModelDefinition<P extends object> {
241
+ prop: ExplicitPropKeys<P>;
242
+ event: string;
243
+ eventPath?: string;
244
+ }
245
+ export interface DefineElementContext<E extends HTMLElement = HTMLElement, Emits extends EmitsOptions = EmitsOptions> {
188
246
  host: E;
189
- emit: (name: string, detail?: unknown, options?: CustomEventInit) => boolean;
247
+ internals?: ElementInternals;
248
+ emit: EmitApi<Emits>;
249
+ expose(methods: Record<string, Function>): void;
250
+ }
251
+ export type DefineElementSetup<P extends object, E extends HTMLElement = HTMLElement, Emits extends EmitsOptions = EmitsOptions> = (props: Readonly<P>, context: DefineElementContext<E, Emits>) => JSXValue;
252
+ export type NormalizedPropDefinition = {
253
+ key: string;
254
+ attr: string | false;
255
+ type?: ElementPropConstructor;
256
+ reflect: boolean;
257
+ default?: unknown;
258
+ serialize?: (value: unknown) => string | null | undefined;
259
+ deserialize?: (value: string | null) => unknown;
260
+ };
261
+ export declare const ZEUS_ELEMENT_DEFINITION: unique symbol;
262
+ export interface ZeusElementDefinition<P extends object = object, E extends HTMLElement = HTMLElement, Emits extends EmitsOptions = EmitsOptions> {
263
+ tagName: string;
264
+ options: DefineElementOptions<P, Emits>;
265
+ setup: DefineElementSetup<P, E, Emits>;
266
+ propDefs: NormalizedPropDefinition[];
267
+ }
268
+ export type ZeusElementConstructor = CustomElementConstructor & {
269
+ [ZEUS_ELEMENT_DEFINITION]?: ZeusElementDefinition;
270
+ };
271
+ export interface MountedElementDefinition {
272
+ propertyChanged(name: string, _oldValue: unknown, newValue: unknown): void;
273
+ formAssociated(form: HTMLFormElement | null): void;
274
+ formDisabled(disabled: boolean): void;
275
+ formReset(): void;
276
+ formStateRestore(state: FormAssociatedValue, mode: FormStateRestoreMode): void;
277
+ dispose(): void;
278
+ }
279
+ export declare function prop<const V extends readonly string[]>(values: V, options?: Omit<PropDefinitionOptions<V[number]>, 'type' | 'values'>): ValuePropDefinition<V[number]>;
280
+ export declare function prop(type: BooleanConstructor, options?: Omit<PropDefinitionOptions<boolean>, 'type' | 'values'>): ConstructorPropDefinition<boolean, BooleanConstructor>;
281
+ export declare function prop<T = unknown>(type: Exclude<ElementPropConstructor, BooleanConstructor>, options?: Omit<PropDefinitionOptions<T>, 'type' | 'values'>): ConstructorPropDefinition<T>;
282
+ export declare function event<Detail = unknown>(): EventDefinition<Detail>;
283
+ export declare function event<Detail = unknown>(name: string): EventDefinition<Detail>;
284
+ export declare function event<Detail = unknown>(options: EventOptions): EventDefinition<Detail>;
285
+ /**
286
+ * Persisted mount state for a lazy-loaded element.
287
+ * Used across disconnect/reconnect cycles to avoid re-capturing
288
+ * light DOM children or re-attaching shadow roots.
289
+ */
290
+ export interface ElementDefinitionMountState {
291
+ target?: Element | ShadowRoot;
292
+ lightChildren?: Node[];
293
+ capturedLightChildren?: boolean;
294
+ internals?: ElementInternals;
295
+ attributeProps?: Set<string>;
296
+ reflectingAttrs?: Set<string>;
190
297
  }
191
- export type DefineElementSetup<P extends object, E extends HTMLElement = HTMLElement> = (props: Readonly<P>, context: DefineElementContext<E>) => JSXValue;
192
- export declare function defineElement<P extends object = object, E extends HTMLElement = HTMLElement>(tagName: string, options: DefineElementOptions<P>, setup: DefineElementSetup<P, E>): CustomElementConstructor;
298
+ export declare function defineElement<P extends object = Record<string, unknown>, E extends HTMLElement = HTMLElement, Emits extends EmitsOptions = EmitsOptions>(tagName: string, options: DefineElementOptions<P, Emits>, setup: DefineElementSetup<P, E, Emits>): CustomElementConstructor;
299
+ export declare function getElementDefinition(ctor: CustomElementConstructor): ZeusElementDefinition;
300
+ export declare function mountElementDefinition(ctor: CustomElementConstructor, host: HTMLElement, initialValues?: Map<string, unknown>, mountState?: ElementDefinitionMountState): MountedElementDefinition;
193
301
 
194
302
  type HostValue<T> = T | (() => T);
195
303
  export interface HostProps extends Record<string, unknown> {