@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
  **/
@@ -172,7 +172,7 @@ function useContext(context, fallback) {
172
172
  const ZEUS_CONTEXT_REQUEST = "zeus:context-request";
173
173
  /**
174
174
  * Creates a transparent DOM element that acts as a context boundary.
175
- * Native custom elements inside it can use `requestDOMContext` to receive
175
+ * Native custom elements inside it can use `resolveDOMContext` to receive
176
176
  * context values via the DOM event protocol.
177
177
  */
178
178
  function createDOMContextBoundary(context, value, children) {
@@ -184,7 +184,7 @@ function createDOMContextBoundary(context, value, children) {
184
184
  }
185
185
  /**
186
186
  * Registers a context value on a DOM target so that any descendant custom
187
- * element can pick it up via `requestDOMContext`.
187
+ * element can pick it up via `resolveDOMContext`.
188
188
  */
189
189
  function provideDOMContext(target, context, value) {
190
190
  const handler = (event) => {
@@ -202,7 +202,7 @@ function provideDOMContext(target, context, value) {
202
202
  /**
203
203
  * Internal precise DOM context resolver.
204
204
  *
205
- * Unlike requestDOMContext(), this can distinguish:
205
+ * The result distinguishes:
206
206
  * - found: false, value: undefined
207
207
  * - found: true, value: undefined
208
208
  */
@@ -231,16 +231,6 @@ function resolveDOMContext(host, context) {
231
231
  value
232
232
  };
233
233
  }
234
- /**
235
- * Public compatibility API.
236
- *
237
- * Returns the resolved value if found, otherwise undefined.
238
- * If you need to distinguish "not found" from "found undefined",
239
- * use resolveDOMContext().
240
- */
241
- function requestDOMContext(host, context) {
242
- return resolveDOMContext(host, context).value;
243
- }
244
234
  function resolveValue$3(value) {
245
235
  return typeof value === "function" ? value() : value !== null && value !== void 0 ? value : null;
246
236
  }
@@ -633,6 +623,40 @@ function mountFor(parent, marker, each, key, render) {
633
623
  //#endregion
634
624
  //#region packages/core/runtime-dom/src/defineElement.ts
635
625
  const ZEUS_ELEMENT_DEFINITION = Symbol.for("zeus.element.definition");
626
+ function prop(input, options = {}) {
627
+ var _options$reflect, _options$default;
628
+ if (Array.isArray(input)) return {
629
+ type: String,
630
+ values: input,
631
+ attr: options.attr,
632
+ reflect: options.reflect,
633
+ default: options.default,
634
+ serialize: options.serialize,
635
+ deserialize: options.deserialize
636
+ };
637
+ const type = input;
638
+ return {
639
+ type,
640
+ attr: options.attr,
641
+ reflect: type === Boolean ? (_options$reflect = options.reflect) !== null && _options$reflect !== void 0 ? _options$reflect : true : options.reflect,
642
+ default: type === Boolean ? (_options$default = options.default) !== null && _options$default !== void 0 ? _options$default : false : options.default,
643
+ serialize: options.serialize,
644
+ deserialize: options.deserialize
645
+ };
646
+ }
647
+ function event(input) {
648
+ if (typeof input === "string") return {
649
+ __zeusEvent: true,
650
+ name: input
651
+ };
652
+ return {
653
+ __zeusEvent: true,
654
+ name: input === null || input === void 0 ? void 0 : input.name,
655
+ bubbles: input === null || input === void 0 ? void 0 : input.bubbles,
656
+ composed: input === null || input === void 0 ? void 0 : input.composed,
657
+ cancelable: input === null || input === void 0 ? void 0 : input.cancelable
658
+ };
659
+ }
636
660
  function createPropStore(defs) {
637
661
  const slots = /* @__PURE__ */ new Map();
638
662
  const props = {};
@@ -692,6 +716,13 @@ function defineElement(tagName, options, setup) {
692
716
  this.props = this.propStore.props;
693
717
  applyPropDefaults(this.propStore, propDefs);
694
718
  definePropAccessors(this, this.propStore, propDefs);
719
+ if (options.formAssociated) this.internals = attachElementInternals(this);
720
+ this.setupContext = {
721
+ host: this,
722
+ internals: this.internals,
723
+ emit: createEmitApi(this, options.emits),
724
+ expose: createExpose(this)
725
+ };
695
726
  }
696
727
  connectedCallback() {
697
728
  var _options$shadow, _options$consumes;
@@ -715,19 +746,10 @@ function defineElement(tagName, options, setup) {
715
746
  mode,
716
747
  lightChildren: this.lightChildren
717
748
  };
718
- const setupContext = {
719
- host: this,
720
- emit: (name, detail, eventOptions) => {
721
- return this.dispatchEvent(new CustomEvent(name, {
722
- bubbles: true,
723
- composed: true,
724
- cancelable: true,
725
- ...eventOptions,
726
- detail
727
- }));
728
- }
729
- };
730
- this.dispose = render(() => runWithOwner(owner, () => withHostContext(hostContext, () => setup(this.props, setupContext))), target, { owner });
749
+ this.dispose = render(() => runWithOwner(owner, () => withHostContext(hostContext, () => {
750
+ syncFormValue(this.props, this.setupContext, options.form);
751
+ return setup(this.props, this.setupContext);
752
+ })), target, { owner });
731
753
  mountStyles(target, options.styles);
732
754
  }
733
755
  disconnectedCallback() {
@@ -735,6 +757,22 @@ function defineElement(tagName, options, setup) {
735
757
  (_this$dispose = this.dispose) === null || _this$dispose === void 0 || _this$dispose.call(this);
736
758
  this.dispose = void 0;
737
759
  }
760
+ formAssociatedCallback(form) {
761
+ var _options$form, _options$form$associa;
762
+ (_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);
763
+ }
764
+ formDisabledCallback(disabled) {
765
+ var _options$form2, _options$form2$disabl;
766
+ (_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);
767
+ }
768
+ formResetCallback() {
769
+ var _options$form3, _options$form3$reset;
770
+ (_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);
771
+ }
772
+ formStateRestoreCallback(state, mode) {
773
+ var _options$form4, _options$form4$stateR;
774
+ (_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);
775
+ }
738
776
  attributeChangedCallback(name, oldValue, newValue) {
739
777
  if (oldValue === newValue || this.reflecting) return;
740
778
  const def = propDefs.find((item) => item.attr === name);
@@ -770,6 +808,7 @@ function defineElement(tagName, options, setup) {
770
808
  }
771
809
  }
772
810
  }
811
+ ZeusElement.formAssociated = Boolean(options.formAssociated);
773
812
  if (!customElements.get(tagName)) customElements.define(tagName, ZeusElement);
774
813
  Object.defineProperty(ZeusElement, ZEUS_ELEMENT_DEFINITION, {
775
814
  value: definition,
@@ -783,11 +822,17 @@ function getElementDefinition(ctor) {
783
822
  return definition;
784
823
  }
785
824
  function mountElementDefinition(ctor, host, initialValues = /* @__PURE__ */ new Map(), mountState = {}) {
786
- var _options$shadow2, _mountState$lightChil, _options$consumes2, _mountState$target;
825
+ var _options$shadow2, _mountState$lightChil, _options$consumes2, _mountState$target, _mountState$internals;
787
826
  const { options, setup, propDefs } = getElementDefinition(ctor);
788
827
  const propStore = createPropStore(propDefs);
789
828
  applyPropDefaults(propStore, propDefs);
790
829
  for (const def of propDefs) {
830
+ var _mountState$attribute;
831
+ if (def.attr !== false && ((_mountState$attribute = mountState.attributeProps) === null || _mountState$attribute === void 0 ? void 0 : _mountState$attribute.has(def.key))) {
832
+ propStore.set(def.key, castAttributeValue(host.getAttribute(def.attr), def));
833
+ initialValues.set(def.key, propStore.get(def.key));
834
+ continue;
835
+ }
791
836
  if (initialValues.has(def.key)) {
792
837
  propStore.set(def.key, initialValues.get(def.key));
793
838
  continue;
@@ -799,6 +844,10 @@ function mountElementDefinition(ctor, host, initialValues = /* @__PURE__ */ new
799
844
  */
800
845
  initialValues.set(def.key, propStore.get(def.key));
801
846
  }
847
+ for (const def of propDefs) {
848
+ var _mountState$attribute2;
849
+ 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);
850
+ }
802
851
  const shadow = (_options$shadow2 = options.shadow) !== null && _options$shadow2 !== void 0 ? _options$shadow2 : false;
803
852
  const mode = shadow ? "shadow" : "light";
804
853
  if (mode === "light" && !mountState.capturedLightChildren) {
@@ -820,21 +869,41 @@ function mountElementDefinition(ctor, host, initialValues = /* @__PURE__ */ new
820
869
  };
821
870
  const setupContext = {
822
871
  host,
823
- emit: (name, detail, eventOptions) => {
824
- return host.dispatchEvent(new CustomEvent(name, {
825
- bubbles: true,
826
- composed: true,
827
- cancelable: true,
828
- ...eventOptions,
829
- detail
830
- }));
831
- }
872
+ internals: (_mountState$internals = mountState.internals) !== null && _mountState$internals !== void 0 ? _mountState$internals : options.formAssociated ? attachElementInternals(host) : void 0,
873
+ emit: createEmitApi(host, options.emits),
874
+ expose: createExpose(host)
832
875
  };
833
- const dispose = render(() => runWithOwner(owner, () => withHostContext(hostContext, () => setup(propStore.props, setupContext))), target, { owner });
876
+ mountState.internals = setupContext.internals;
877
+ const dispose = render(() => runWithOwner(owner, () => withHostContext(hostContext, () => {
878
+ syncFormValue(propStore.props, setupContext, options.form);
879
+ return setup(propStore.props, setupContext);
880
+ })), target, { owner });
834
881
  mountStyles(target, options.styles);
835
882
  return {
836
883
  propertyChanged(name, _oldValue, newValue) {
837
- propStore.set(name, newValue);
884
+ var _mountState$attribute3;
885
+ const def = propDefs.find((item) => item.key === name);
886
+ 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)));
887
+ const value = fromAttribute && def ? castAttributeValue(typeof newValue === "string" ? newValue : null, def) : newValue;
888
+ propStore.set(name, value);
889
+ initialValues.set(name, value);
890
+ if ((def === null || def === void 0 ? void 0 : def.reflect) && !fromAttribute) reflectExternalProp(host, def, value, mountState.reflectingAttrs);
891
+ },
892
+ formAssociated(form) {
893
+ var _options$form5, _options$form5$associ;
894
+ (_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);
895
+ },
896
+ formDisabled(disabled) {
897
+ var _options$form6, _options$form6$disabl;
898
+ (_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);
899
+ },
900
+ formReset() {
901
+ var _options$form7, _options$form7$reset;
902
+ (_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);
903
+ },
904
+ formStateRestore(state, mode) {
905
+ var _options$form8, _options$form8$stateR;
906
+ (_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);
838
907
  },
839
908
  dispose() {
840
909
  dispose();
@@ -843,19 +912,27 @@ function mountElementDefinition(ctor, host, initialValues = /* @__PURE__ */ new
843
912
  }
844
913
  function normalizePropDefinitions(props) {
845
914
  return Object.keys(props).map((key) => {
915
+ const propKey = String(key);
846
916
  const input = props[key];
847
- if (typeof input === "function") return {
848
- key,
849
- attr: toKebabCase(key),
850
- type: input,
851
- reflect: false
852
- };
917
+ if (typeof input === "function") {
918
+ const type = input;
919
+ return {
920
+ key: propKey,
921
+ attr: isAttributeBackedConstructor(type) ? toKebabCase(propKey) : false,
922
+ type,
923
+ reflect: false
924
+ };
925
+ }
926
+ const type = input === null || input === void 0 ? void 0 : input.type;
927
+ const defaultAttr = isAttributeBackedConstructor(type) ? toKebabCase(propKey) : false;
853
928
  return {
854
- key,
855
- attr: (input === null || input === void 0 ? void 0 : input.attr) === void 0 ? toKebabCase(key) : input.attr,
856
- type: input === null || input === void 0 ? void 0 : input.type,
929
+ key: propKey,
930
+ attr: (input === null || input === void 0 ? void 0 : input.attr) === void 0 ? defaultAttr : input.attr,
931
+ type,
857
932
  reflect: Boolean(input === null || input === void 0 ? void 0 : input.reflect),
858
- default: input === null || input === void 0 ? void 0 : input.default
933
+ default: input === null || input === void 0 ? void 0 : input.default,
934
+ serialize: input === null || input === void 0 ? void 0 : input.serialize,
935
+ deserialize: input === null || input === void 0 ? void 0 : input.deserialize
859
936
  };
860
937
  });
861
938
  }
@@ -891,6 +968,7 @@ function definePropAccessors(element, store, defs) {
891
968
  }
892
969
  }
893
970
  function castAttributeValue(value, def) {
971
+ if (def.deserialize) return def.deserialize(value);
894
972
  if (def.type === Boolean) return value !== null;
895
973
  if (value === null) return;
896
974
  if (def.type === Number) return Number(value);
@@ -900,10 +978,17 @@ function castAttributeValue(value, def) {
900
978
  console.warn(`[Zeus custom-element] Failed to parse JSON attribute "${def.attr}".`);
901
979
  return def.type === Array ? [] : {};
902
980
  }
981
+ if (def.type === Function) return;
903
982
  return value;
904
983
  }
905
984
  function reflectPropToAttribute(element, def, value) {
906
985
  if (def.attr === false) return;
986
+ if (def.serialize) {
987
+ const serialized = def.serialize(value);
988
+ if (serialized == null) element.removeAttribute(def.attr);
989
+ else element.setAttribute(def.attr, serialized);
990
+ return;
991
+ }
907
992
  if (def.type === Boolean) {
908
993
  if (value) element.setAttribute(def.attr, "");
909
994
  else element.removeAttribute(def.attr);
@@ -917,8 +1002,80 @@ function reflectPropToAttribute(element, def, value) {
917
1002
  element.setAttribute(def.attr, JSON.stringify(value));
918
1003
  return;
919
1004
  }
1005
+ if (def.type === Function) return;
920
1006
  element.setAttribute(def.attr, String(value));
921
1007
  }
1008
+ function reflectExternalProp(element, def, value, reflectingAttrs) {
1009
+ if (def.attr === false) return;
1010
+ const attrName = def.attr.toLowerCase();
1011
+ reflectingAttrs === null || reflectingAttrs === void 0 || reflectingAttrs.add(attrName);
1012
+ try {
1013
+ reflectPropToAttribute(element, def, value);
1014
+ } finally {
1015
+ reflectingAttrs === null || reflectingAttrs === void 0 || reflectingAttrs.delete(attrName);
1016
+ }
1017
+ }
1018
+ function syncFormValue(props, context, form) {
1019
+ const valueResolver = form === null || form === void 0 ? void 0 : form.value;
1020
+ const stateResolver = form === null || form === void 0 ? void 0 : form.state;
1021
+ if (!context.internals || valueResolver === void 0) return;
1022
+ (0, _zeus_js_signal.effect)(() => {
1023
+ const value = resolveFormValue(props, valueResolver);
1024
+ const state = stateResolver === void 0 ? void 0 : resolveFormValue(props, stateResolver);
1025
+ context.internals.setFormValue(value, state);
1026
+ });
1027
+ }
1028
+ function resolveFormValue(props, resolver) {
1029
+ if (typeof resolver === "function") {
1030
+ var _resolver;
1031
+ return (_resolver = resolver(props)) !== null && _resolver !== void 0 ? _resolver : null;
1032
+ }
1033
+ const value = props[resolver];
1034
+ return value == null ? null : value;
1035
+ }
1036
+ function attachElementInternals(host) {
1037
+ const attachInternals = host.attachInternals;
1038
+ if (typeof attachInternals !== "function") return;
1039
+ try {
1040
+ return attachInternals.call(host);
1041
+ } catch (error) {
1042
+ console.warn("[Zeus custom-element] Failed to attach ElementInternals.", error);
1043
+ return;
1044
+ }
1045
+ }
1046
+ function createEmitApi(host, emits) {
1047
+ const emit = {};
1048
+ const dispatch = (name, detail, options) => {
1049
+ var _definition$name, _ref, _options$bubbles, _ref2, _options$composed, _ref3, _options$cancelable;
1050
+ const definition = emits === null || emits === void 0 ? void 0 : emits[name];
1051
+ 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), {
1052
+ 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,
1053
+ 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,
1054
+ 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,
1055
+ detail
1056
+ }));
1057
+ };
1058
+ if (emits) for (const key of Object.keys(emits)) Object.defineProperty(emit, key, {
1059
+ configurable: true,
1060
+ enumerable: true,
1061
+ value(detail, options) {
1062
+ return dispatch(key, detail, options);
1063
+ }
1064
+ });
1065
+ return emit;
1066
+ }
1067
+ function createExpose(host) {
1068
+ return (methods) => {
1069
+ for (const key of Object.keys(methods)) Object.defineProperty(host, key, {
1070
+ configurable: true,
1071
+ enumerable: false,
1072
+ value: methods[key]
1073
+ });
1074
+ };
1075
+ }
1076
+ function isAttributeBackedConstructor(type) {
1077
+ return type === String || type === Number || type === Boolean;
1078
+ }
922
1079
  function resolveExternalRenderTarget(host, shadow) {
923
1080
  var _host$shadowRoot;
924
1081
  if (!shadow) return host;
@@ -1083,6 +1240,7 @@ exports.createOwner = createOwner;
1083
1240
  exports.createSlot = createSlot;
1084
1241
  exports.defineElement = defineElement;
1085
1242
  exports.delegateEvents = delegateEvents;
1243
+ exports.event = event;
1086
1244
  exports.getCurrentHostContext = getCurrentHostContext;
1087
1245
  exports.getCurrentOwner = getCurrentOwner;
1088
1246
  exports.getElementDefinition = getElementDefinition;
@@ -1095,11 +1253,11 @@ exports.mountElementDefinition = mountElementDefinition;
1095
1253
  exports.mountFor = mountFor;
1096
1254
  exports.mountShow = mountShow;
1097
1255
  exports.normalizeClass = normalizeClass;
1256
+ exports.prop = prop;
1098
1257
  exports.provide = provide;
1099
1258
  exports.provideDOMContext = provideDOMContext;
1100
1259
  exports.removeNodes = removeNodes;
1101
1260
  exports.render = render;
1102
- exports.requestDOMContext = requestDOMContext;
1103
1261
  exports.resolveDOMContext = resolveDOMContext;
1104
1262
  exports.resolveValue = resolveValue;
1105
1263
  exports.runWithOwner = runWithOwner;