@zeus-js/runtime-dom 0.1.0-beta.3 → 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.3
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
  }
@@ -626,6 +616,40 @@ function mountFor(parent, marker, each, key, render) {
626
616
  //#endregion
627
617
  //#region packages/core/runtime-dom/src/defineElement.ts
628
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
+ }
629
653
  function createPropStore(defs) {
630
654
  const slots = /* @__PURE__ */ new Map();
631
655
  const props = {};
@@ -682,6 +706,13 @@ function defineElement(tagName, options, setup) {
682
706
  this.props = this.propStore.props;
683
707
  applyPropDefaults(this.propStore, propDefs);
684
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
+ };
685
716
  }
686
717
  connectedCallback() {
687
718
  var _options$shadow, _options$consumes;
@@ -705,19 +736,10 @@ function defineElement(tagName, options, setup) {
705
736
  mode,
706
737
  lightChildren: this.lightChildren
707
738
  };
708
- const setupContext = {
709
- host: this,
710
- emit: (name, detail, eventOptions) => {
711
- return this.dispatchEvent(new CustomEvent(name, {
712
- bubbles: true,
713
- composed: true,
714
- cancelable: true,
715
- ...eventOptions,
716
- detail
717
- }));
718
- }
719
- };
720
- 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 });
721
743
  mountStyles(target, options.styles);
722
744
  }
723
745
  disconnectedCallback() {
@@ -725,6 +747,22 @@ function defineElement(tagName, options, setup) {
725
747
  (_this$dispose = this.dispose) === null || _this$dispose === void 0 || _this$dispose.call(this);
726
748
  this.dispose = void 0;
727
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
+ }
728
766
  attributeChangedCallback(name, oldValue, newValue) {
729
767
  if (oldValue === newValue || this.reflecting) return;
730
768
  const def = propDefs.find((item) => item.attr === name);
@@ -760,6 +798,7 @@ function defineElement(tagName, options, setup) {
760
798
  }
761
799
  }
762
800
  }
801
+ ZeusElement.formAssociated = Boolean(options.formAssociated);
763
802
  if (!customElements.get(tagName)) customElements.define(tagName, ZeusElement);
764
803
  Object.defineProperty(ZeusElement, ZEUS_ELEMENT_DEFINITION, {
765
804
  value: definition,
@@ -773,11 +812,17 @@ function getElementDefinition(ctor) {
773
812
  return definition;
774
813
  }
775
814
  function mountElementDefinition(ctor, host, initialValues = /* @__PURE__ */ new Map(), mountState = {}) {
776
- var _options$shadow2, _mountState$lightChil, _options$consumes2, _mountState$target;
815
+ var _options$shadow2, _mountState$lightChil, _options$consumes2, _mountState$target, _mountState$internals;
777
816
  const { options, setup, propDefs } = getElementDefinition(ctor);
778
817
  const propStore = createPropStore(propDefs);
779
818
  applyPropDefaults(propStore, propDefs);
780
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
+ }
781
826
  if (initialValues.has(def.key)) {
782
827
  propStore.set(def.key, initialValues.get(def.key));
783
828
  continue;
@@ -789,6 +834,10 @@ function mountElementDefinition(ctor, host, initialValues = /* @__PURE__ */ new
789
834
  */
790
835
  initialValues.set(def.key, propStore.get(def.key));
791
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
+ }
792
841
  const shadow = (_options$shadow2 = options.shadow) !== null && _options$shadow2 !== void 0 ? _options$shadow2 : false;
793
842
  const mode = shadow ? "shadow" : "light";
794
843
  if (mode === "light" && !mountState.capturedLightChildren) {
@@ -810,21 +859,41 @@ function mountElementDefinition(ctor, host, initialValues = /* @__PURE__ */ new
810
859
  };
811
860
  const setupContext = {
812
861
  host,
813
- emit: (name, detail, eventOptions) => {
814
- return host.dispatchEvent(new CustomEvent(name, {
815
- bubbles: true,
816
- composed: true,
817
- cancelable: true,
818
- ...eventOptions,
819
- detail
820
- }));
821
- }
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)
822
865
  };
823
- const dispose = render(() => runWithOwner(owner, () => withHostContext(hostContext, () => setup(propStore.props, setupContext))), target, { owner });
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 });
824
871
  mountStyles(target, options.styles);
825
872
  return {
826
873
  propertyChanged(name, _oldValue, newValue) {
827
- propStore.set(name, 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);
828
897
  },
829
898
  dispose() {
830
899
  dispose();
@@ -833,19 +902,27 @@ function mountElementDefinition(ctor, host, initialValues = /* @__PURE__ */ new
833
902
  }
834
903
  function normalizePropDefinitions(props) {
835
904
  return Object.keys(props).map((key) => {
905
+ const propKey = String(key);
836
906
  const input = props[key];
837
- if (typeof input === "function") return {
838
- key,
839
- attr: toKebabCase(key),
840
- type: input,
841
- reflect: false
842
- };
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;
843
918
  return {
844
- key,
845
- attr: (input === null || input === void 0 ? void 0 : input.attr) === void 0 ? toKebabCase(key) : input.attr,
846
- 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,
847
922
  reflect: Boolean(input === null || input === void 0 ? void 0 : input.reflect),
848
- 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
849
926
  };
850
927
  });
851
928
  }
@@ -878,6 +955,7 @@ function definePropAccessors(element, store, defs) {
878
955
  }
879
956
  }
880
957
  function castAttributeValue(value, def) {
958
+ if (def.deserialize) return def.deserialize(value);
881
959
  if (def.type === Boolean) return value !== null;
882
960
  if (value === null) return;
883
961
  if (def.type === Number) return Number(value);
@@ -886,10 +964,17 @@ function castAttributeValue(value, def) {
886
964
  } catch {
887
965
  return def.type === Array ? [] : {};
888
966
  }
967
+ if (def.type === Function) return;
889
968
  return value;
890
969
  }
891
970
  function reflectPropToAttribute(element, def, value) {
892
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
+ }
893
978
  if (def.type === Boolean) {
894
979
  if (value) element.setAttribute(def.attr, "");
895
980
  else element.removeAttribute(def.attr);
@@ -903,8 +988,79 @@ function reflectPropToAttribute(element, def, value) {
903
988
  element.setAttribute(def.attr, JSON.stringify(value));
904
989
  return;
905
990
  }
991
+ if (def.type === Function) return;
906
992
  element.setAttribute(def.attr, String(value));
907
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
+ }
908
1064
  function resolveExternalRenderTarget(host, shadow) {
909
1065
  var _host$shadowRoot;
910
1066
  if (!shadow) return host;
@@ -1069,6 +1225,7 @@ exports.createOwner = createOwner;
1069
1225
  exports.createSlot = createSlot;
1070
1226
  exports.defineElement = defineElement;
1071
1227
  exports.delegateEvents = delegateEvents;
1228
+ exports.event = event;
1072
1229
  exports.getCurrentHostContext = getCurrentHostContext;
1073
1230
  exports.getCurrentOwner = getCurrentOwner;
1074
1231
  exports.getElementDefinition = getElementDefinition;
@@ -1081,11 +1238,11 @@ exports.mountElementDefinition = mountElementDefinition;
1081
1238
  exports.mountFor = mountFor;
1082
1239
  exports.mountShow = mountShow;
1083
1240
  exports.normalizeClass = normalizeClass;
1241
+ exports.prop = prop;
1084
1242
  exports.provide = provide;
1085
1243
  exports.provideDOMContext = provideDOMContext;
1086
1244
  exports.removeNodes = removeNodes;
1087
1245
  exports.render = render;
1088
- exports.requestDOMContext = requestDOMContext;
1089
1246
  exports.resolveDOMContext = resolveDOMContext;
1090
1247
  exports.resolveValue = resolveValue;
1091
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,38 +203,66 @@ 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;
190
250
  }
191
- export type DefineElementSetup<P extends object, E extends HTMLElement = HTMLElement> = (props: Readonly<P>, context: DefineElementContext<E>) => JSXValue;
251
+ export type DefineElementSetup<P extends object, E extends HTMLElement = HTMLElement, Emits extends EmitsOptions = EmitsOptions> = (props: Readonly<P>, context: DefineElementContext<E, Emits>) => JSXValue;
192
252
  export type NormalizedPropDefinition = {
193
253
  key: string;
194
254
  attr: string | false;
195
255
  type?: ElementPropConstructor;
196
256
  reflect: boolean;
197
257
  default?: unknown;
258
+ serialize?: (value: unknown) => string | null | undefined;
259
+ deserialize?: (value: string | null) => unknown;
198
260
  };
199
261
  export declare const ZEUS_ELEMENT_DEFINITION: unique symbol;
200
- export interface ZeusElementDefinition<P extends object = object, E extends HTMLElement = HTMLElement> {
262
+ export interface ZeusElementDefinition<P extends object = object, E extends HTMLElement = HTMLElement, Emits extends EmitsOptions = EmitsOptions> {
201
263
  tagName: string;
202
- options: DefineElementOptions<P>;
203
- setup: DefineElementSetup<P, E>;
264
+ options: DefineElementOptions<P, Emits>;
265
+ setup: DefineElementSetup<P, E, Emits>;
204
266
  propDefs: NormalizedPropDefinition[];
205
267
  }
206
268
  export type ZeusElementConstructor = CustomElementConstructor & {
@@ -208,8 +270,18 @@ export type ZeusElementConstructor = CustomElementConstructor & {
208
270
  };
209
271
  export interface MountedElementDefinition {
210
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;
211
277
  dispose(): void;
212
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>;
213
285
  /**
214
286
  * Persisted mount state for a lazy-loaded element.
215
287
  * Used across disconnect/reconnect cycles to avoid re-capturing
@@ -219,8 +291,11 @@ export interface ElementDefinitionMountState {
219
291
  target?: Element | ShadowRoot;
220
292
  lightChildren?: Node[];
221
293
  capturedLightChildren?: boolean;
294
+ internals?: ElementInternals;
295
+ attributeProps?: Set<string>;
296
+ reflectingAttrs?: Set<string>;
222
297
  }
223
- 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;
224
299
  export declare function getElementDefinition(ctor: CustomElementConstructor): ZeusElementDefinition;
225
300
  export declare function mountElementDefinition(ctor: CustomElementConstructor, host: HTMLElement, initialValues?: Map<string, unknown>, mountState?: ElementDefinitionMountState): MountedElementDefinition;
226
301