elements-kit 0.18.2 → 0.20.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.
Files changed (156) hide show
  1. package/README.md +14 -0
  2. package/dist/await.d.mts +53 -0
  3. package/dist/await.mjs +70 -0
  4. package/dist/custom-elements.d.mts +1 -1
  5. package/dist/{element-xQwq4ulc.mjs → element-D3om9yA6.mjs} +71 -4
  6. package/dist/for.d.mts +20 -26
  7. package/dist/for.mjs +29 -4
  8. package/dist/fragment-ROPRBJQd.mjs +61 -0
  9. package/dist/hydrate/index.d.mts +41 -0
  10. package/dist/hydrate/index.mjs +2 -0
  11. package/dist/hydrate-6Qx4n4Su.mjs +380 -0
  12. package/dist/integrations/astro-client.d.mts +17 -0
  13. package/dist/integrations/astro-client.mjs +23 -0
  14. package/dist/integrations/astro-server.d.mts +15 -0
  15. package/dist/integrations/astro-server.mjs +39 -0
  16. package/dist/integrations/astro-slots.d.mts +12 -0
  17. package/dist/integrations/astro-slots.mjs +30 -0
  18. package/dist/integrations/astro.d.mts +46 -0
  19. package/dist/integrations/astro.mjs +64 -0
  20. package/dist/integrations/react.d.mts +1 -1
  21. package/dist/integrations/react.mjs +2 -2
  22. package/dist/jsx-runtime/index.d.mts +1 -1
  23. package/dist/jsx-runtime/index.mjs +2 -20
  24. package/dist/{lib-Dkc7cV5F.mjs → lib-DYypKhxk.mjs} +63 -5
  25. package/dist/render.mjs +1 -1
  26. package/dist/{scope-CnEvL9Nd.mjs → scope-zbEG299F.mjs} +1 -1
  27. package/dist/server/index.d.mts +43 -0
  28. package/dist/server/index.mjs +2 -0
  29. package/dist/server-iFSng50i.mjs +385 -0
  30. package/dist/signals/index.d.mts +2 -2
  31. package/dist/signals/index.mjs +5 -3
  32. package/dist/{slot-B8y0aEoz.d.mts → slot-BFWXeFRl.d.mts} +6 -0
  33. package/dist/{slot-Cne__au7.mjs → slot-Dvf30O0B.mjs} +12 -1
  34. package/dist/slot.d.mts +1 -1
  35. package/dist/slot.mjs +1 -1
  36. package/dist/{infer-B7T5hi_D.d.mts → types-ncUK9rki.d.mts} +140 -141
  37. package/dist/ui/overlay/index.css +70 -0
  38. package/dist/ui/overlay/index.d.mts +209 -0
  39. package/dist/ui/overlay/index.mjs +1001 -0
  40. package/dist/ui/overlay/overlay.css +332 -0
  41. package/dist/utilities/_observe.mjs +1 -1
  42. package/dist/utilities/active-element.d.mts +1 -1
  43. package/dist/utilities/active-element.mjs +1 -1
  44. package/dist/utilities/async.d.mts +19 -2
  45. package/dist/utilities/async.mjs +49 -2
  46. package/dist/utilities/context.mjs +1 -1
  47. package/dist/utilities/debounced.d.mts +1 -1
  48. package/dist/utilities/debounced.mjs +1 -1
  49. package/dist/utilities/dom-lifecycle.bench.mjs +3255 -1
  50. package/dist/utilities/dom-lifecycle.mjs +1 -1
  51. package/dist/utilities/element-rect.d.mts +1 -1
  52. package/dist/utilities/element-rect.mjs +1 -1
  53. package/dist/utilities/element-scroll.d.mts +1 -1
  54. package/dist/utilities/event-driven.d.mts +1 -1
  55. package/dist/utilities/event-driven.mjs +1 -1
  56. package/dist/utilities/event-listener.d.mts +1 -1
  57. package/dist/utilities/event-listener.mjs +1 -1
  58. package/dist/utilities/focus-within.d.mts +1 -1
  59. package/dist/utilities/focus-within.mjs +1 -1
  60. package/dist/utilities/form-object.d.mts +96 -0
  61. package/dist/utilities/form-object.mjs +285 -0
  62. package/dist/utilities/hover.d.mts +1 -1
  63. package/dist/utilities/hover.mjs +1 -1
  64. package/dist/utilities/interval.d.mts +1 -1
  65. package/dist/utilities/interval.mjs +1 -1
  66. package/dist/utilities/location.d.mts +1 -1
  67. package/dist/utilities/location.mjs +1 -1
  68. package/dist/utilities/media-devices.d.mts +1 -1
  69. package/dist/utilities/media-devices.mjs +1 -1
  70. package/dist/utilities/media-player.d.mts +1 -1
  71. package/dist/utilities/media-query.d.mts +1 -1
  72. package/dist/utilities/media-query.mjs +1 -1
  73. package/dist/utilities/network.d.mts +1 -1
  74. package/dist/utilities/network.mjs +1 -1
  75. package/dist/utilities/orientation.d.mts +1 -1
  76. package/dist/utilities/orientation.mjs +1 -1
  77. package/dist/utilities/previous.d.mts +1 -1
  78. package/dist/utilities/previous.mjs +1 -1
  79. package/dist/utilities/promise.d.mts +19 -2
  80. package/dist/utilities/promise.mjs +33 -3
  81. package/dist/utilities/retry.mjs +1 -1
  82. package/dist/utilities/routing.d.mts +1 -1
  83. package/dist/utilities/routing.mjs +1 -1
  84. package/dist/utilities/search-params.d.mts +1 -1
  85. package/dist/utilities/storage.d.mts +1 -1
  86. package/dist/utilities/throttled.d.mts +1 -1
  87. package/dist/utilities/throttled.mjs +1 -1
  88. package/dist/utilities/timeout.d.mts +1 -1
  89. package/dist/utilities/timeout.mjs +1 -1
  90. package/dist/utilities/window-focus.d.mts +1 -1
  91. package/dist/utilities/window-focus.mjs +1 -1
  92. package/dist/utilities/window-size.d.mts +1 -1
  93. package/dist/utilities/window-size.mjs +1 -1
  94. package/package.json +20 -5
  95. package/dist/benchmark.CX_oY03V-CSLAXL5f.mjs +0 -5145
  96. package/dist/magic-string.es-CXefOmkB.mjs +0 -1011
  97. package/dist/test.BmQO5GaM-Ddz9cDxc.mjs +0 -8266
  98. package/dist/utilities/active-element.test.d.mts +0 -1
  99. package/dist/utilities/active-element.test.mjs +0 -25
  100. package/dist/utilities/async.test.d.mts +0 -1
  101. package/dist/utilities/async.test.mjs +0 -275
  102. package/dist/utilities/context.test.d.mts +0 -1
  103. package/dist/utilities/context.test.mjs +0 -171
  104. package/dist/utilities/debounced.test.d.mts +0 -1
  105. package/dist/utilities/debounced.test.mjs +0 -68
  106. package/dist/utilities/dom-lifecycle.test.d.mts +0 -1
  107. package/dist/utilities/dom-lifecycle.test.mjs +0 -228
  108. package/dist/utilities/element-rect.test.d.mts +0 -1
  109. package/dist/utilities/element-rect.test.mjs +0 -101
  110. package/dist/utilities/element-scroll.test.d.mts +0 -1
  111. package/dist/utilities/element-scroll.test.mjs +0 -27
  112. package/dist/utilities/event-listener.test.d.mts +0 -1
  113. package/dist/utilities/event-listener.test.mjs +0 -60
  114. package/dist/utilities/focus-within.test.d.mts +0 -1
  115. package/dist/utilities/focus-within.test.mjs +0 -51
  116. package/dist/utilities/hover.test.d.mts +0 -1
  117. package/dist/utilities/hover.test.mjs +0 -54
  118. package/dist/utilities/intersection-observer.test.d.mts +0 -1
  119. package/dist/utilities/intersection-observer.test.mjs +0 -46
  120. package/dist/utilities/interval.test.d.mts +0 -1
  121. package/dist/utilities/interval.test.mjs +0 -115
  122. package/dist/utilities/location.test.d.mts +0 -1
  123. package/dist/utilities/location.test.mjs +0 -61
  124. package/dist/utilities/long-press.test.d.mts +0 -1
  125. package/dist/utilities/long-press.test.mjs +0 -54
  126. package/dist/utilities/media-devices.test.d.mts +0 -1
  127. package/dist/utilities/media-devices.test.mjs +0 -44
  128. package/dist/utilities/media-player.test.d.mts +0 -1
  129. package/dist/utilities/media-player.test.mjs +0 -102
  130. package/dist/utilities/mutation-observer.test.d.mts +0 -1
  131. package/dist/utilities/mutation-observer.test.mjs +0 -48
  132. package/dist/utilities/network.test.d.mts +0 -1
  133. package/dist/utilities/network.test.mjs +0 -30
  134. package/dist/utilities/on-click-outside.test.d.mts +0 -1
  135. package/dist/utilities/on-click-outside.test.mjs +0 -45
  136. package/dist/utilities/previous.test.d.mts +0 -1
  137. package/dist/utilities/previous.test.mjs +0 -90
  138. package/dist/utilities/promise.test.d.mts +0 -1
  139. package/dist/utilities/promise.test.mjs +0 -158
  140. package/dist/utilities/retry.test.d.mts +0 -1
  141. package/dist/utilities/retry.test.mjs +0 -85
  142. package/dist/utilities/routing.test.d.mts +0 -1
  143. package/dist/utilities/routing.test.mjs +0 -129
  144. package/dist/utilities/search-params.test.d.mts +0 -1
  145. package/dist/utilities/search-params.test.mjs +0 -37
  146. package/dist/utilities/ssr.test.d.mts +0 -1
  147. package/dist/utilities/ssr.test.mjs +0 -65
  148. package/dist/utilities/storage.test.d.mts +0 -1
  149. package/dist/utilities/storage.test.mjs +0 -139
  150. package/dist/utilities/throttled.test.d.mts +0 -1
  151. package/dist/utilities/throttled.test.mjs +0 -58
  152. package/dist/utilities/timeout.test.d.mts +0 -1
  153. package/dist/utilities/timeout.test.mjs +0 -121
  154. package/dist/utilities/window-size.test.d.mts +0 -1
  155. package/dist/utilities/window-size.test.mjs +0 -43
  156. /package/dist/{custom-elements-D5CgfNKc.d.mts → custom-elements-DK5VUcWA.d.mts} +0 -0
@@ -1,4 +1,4 @@
1
- import { c as effectScope } from "../lib-Dkc7cV5F.mjs";
1
+ import { d as effectScope } from "../lib-DYypKhxk.mjs";
2
2
  import "../signals/index.mjs";
3
3
  import { isBrowser } from "./environment.mjs";
4
4
  //#region src/utilities/dom-lifecycle.ts
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-B7T5hi_D.mjs";
1
+ import { y as Computed } from "../types-ncUK9rki.mjs";
2
2
 
3
3
  //#region src/utilities/element-rect.d.ts
4
4
  type RectResult = {
@@ -1,4 +1,4 @@
1
- import { m as signal } from "../lib-Dkc7cV5F.mjs";
1
+ import { x as signal } from "../lib-DYypKhxk.mjs";
2
2
  import "../signals/index.mjs";
3
3
  import { createResizeObserver } from "./resize-observer.mjs";
4
4
  //#region src/utilities/element-rect.ts
@@ -1,4 +1,4 @@
1
- import { x as Signal } from "../infer-B7T5hi_D.mjs";
1
+ import { x as Signal } from "../types-ncUK9rki.mjs";
2
2
 
3
3
  //#region src/utilities/element-scroll.d.ts
4
4
  type ElementScrollResult = {
@@ -1,4 +1,4 @@
1
- import { x as Signal, y as Computed } from "../infer-B7T5hi_D.mjs";
1
+ import { x as Signal, y as Computed } from "../types-ncUK9rki.mjs";
2
2
 
3
3
  //#region src/utilities/event-driven.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { h as trigger, i as SIGNAL, m as signal, o as computed, p as onCleanup } from "../lib-Dkc7cV5F.mjs";
1
+ import { S as trigger, _ as onCleanup, l as computed, s as SIGNAL, x as signal } from "../lib-DYypKhxk.mjs";
2
2
  import "../signals/index.mjs";
3
3
  //#region src/utilities/event-driven.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-B7T5hi_D.mjs";
1
+ import { y as Computed } from "../types-ncUK9rki.mjs";
2
2
 
3
3
  //#region src/utilities/event-listener.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { p as onCleanup, s as effect } from "../lib-Dkc7cV5F.mjs";
1
+ import { _ as onCleanup, u as effect } from "../lib-DYypKhxk.mjs";
2
2
  import "../signals/index.mjs";
3
3
  //#region src/utilities/event-listener.ts
4
4
  function on(target, type, handler, options) {
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-B7T5hi_D.mjs";
1
+ import { y as Computed } from "../types-ncUK9rki.mjs";
2
2
 
3
3
  //#region src/utilities/focus-within.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { m as signal } from "../lib-Dkc7cV5F.mjs";
1
+ import { x as signal } from "../lib-DYypKhxk.mjs";
2
2
  import "../signals/index.mjs";
3
3
  import { on } from "./event-listener.mjs";
4
4
  //#region src/utilities/focus-within.ts
@@ -0,0 +1,96 @@
1
+ //#region src/utilities/form-object.d.ts
2
+ /** Leaf value a single control contributes to the extracted object. */
3
+ type FormObjectValue = string | number | boolean | File | null;
4
+ /** A nested plain object built from a form's dot-notation field names. */
5
+ type FormValues = {
6
+ [key: string]: unknown;
7
+ };
8
+ /** Named controls FormObject reads from and writes to. */
9
+ type NamedControl = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
10
+ /**
11
+ * One control's contribution, as seen by transforms before the nested object
12
+ * is assembled. `value` is the raw extracted value; `checked` is present only
13
+ * for checkbox / radio controls.
14
+ */
15
+ interface Field {
16
+ control: NamedControl;
17
+ /** Dot-notation path. Transforms may rewrite it to remap the output key. */
18
+ name: string;
19
+ /** `string | string[] | File | File[] | boolean` depending on control type. */
20
+ value: unknown;
21
+ /** Whether the control is checked — checkbox / radio only. */
22
+ checked?: boolean;
23
+ }
24
+ /**
25
+ * Per-field transform. Return the (possibly modified) field to keep it, or
26
+ * `null` to drop it from the output. Run in order during {@link FormObject.toObject}.
27
+ */
28
+ type FormFieldTransform = (field: Field) => Field | null;
29
+ interface FormObjectOptions {
30
+ /**
31
+ * Pipeline applied to each field during `toObject()`. Defaults to
32
+ * {@link defaultTransforms}. Providing this **replaces** the defaults —
33
+ * spread `...defaultTransforms` to extend them.
34
+ */
35
+ transforms?: FormFieldTransform[];
36
+ }
37
+ /** Drop disabled controls (mirrors native `FormData`). */
38
+ declare const skipDisabled: FormFieldTransform;
39
+ /** Drop submit / reset / button / image controls and `<button>` elements. */
40
+ declare const skipButtons: FormFieldTransform;
41
+ /** Drop fields whose control is an unchecked checkbox / radio. */
42
+ declare const dropUnchecked: FormFieldTransform;
43
+ /**
44
+ * Include unchecked **checkboxes** with the given `value` instead of dropping
45
+ * them. Unchecked **radios** are still dropped (only the selected radio is
46
+ * meaningful). Use this **in place of** {@link dropUnchecked}.
47
+ *
48
+ * @example transforms: [skipDisabled, skipButtons, uncheckedAs(false)]
49
+ */
50
+ declare function uncheckedAs(value: unknown): FormFieldTransform;
51
+ /** Drop fields whose value is empty: `""`, `null`, or an empty array. */
52
+ declare const skipEmpty: FormFieldTransform;
53
+ /** Default pipeline: skip disabled controls, buttons, and unchecked checkboxes/radios. */
54
+ declare const defaultTransforms: FormFieldTransform[];
55
+ /**
56
+ * Extracts an {@link HTMLFormElement} into a nested plain object (and writes one
57
+ * back) using dot-notation field names — `name="user.address.city"` nests into
58
+ * objects, numeric segments like `name="tags.0"` build arrays. A static snapshot:
59
+ * values are read/written at call time, no reactivity.
60
+ *
61
+ * Extraction runs each field through a composable {@link FormFieldTransform}
62
+ * pipeline ({@link defaultTransforms} by default), which decides inclusion and
63
+ * may rewrite names/values. Mirrors the ergonomics of the native `FormData`
64
+ * constructor.
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * import { FormObject, defaultTransforms, uncheckedAs }
69
+ * from "elements-kit/utilities/form-object";
70
+ *
71
+ * // <input name="user.name"> <input name="tags.0"> <input name="tags.1">
72
+ * const data = new FormObject(form).toObject();
73
+ * // => { user: { name: "..." }, tags: ["...", "..."] }
74
+ *
75
+ * // Replace the pipeline — include unchecked checkboxes as false
76
+ * new FormObject(form, {
77
+ * transforms: [...defaultTransforms.slice(0, 2), uncheckedAs(false)],
78
+ * }).toObject();
79
+ *
80
+ * new FormObject(form).fromObject({ user: { name: "Wael" }, tags: ["a", "b"] });
81
+ * ```
82
+ */
83
+ declare class FormObject {
84
+ #private;
85
+ constructor(form: HTMLFormElement, options?: FormObjectOptions);
86
+ /** Snapshot the form into a nested object built from dot-notation names. */
87
+ toObject(): FormValues;
88
+ /** Alias for {@link toObject} — lets `JSON.stringify(instance)` work. */
89
+ toJSON(): FormValues;
90
+ /** Write values from a nested object back onto the form's named controls. */
91
+ fromObject(data: FormValues): this;
92
+ /** Reset every named control to its empty/default state. */
93
+ clear(): this;
94
+ }
95
+ //#endregion
96
+ export { Field, FormFieldTransform, FormObject, FormObjectOptions, FormObjectValue, FormValues, NamedControl, defaultTransforms, dropUnchecked, skipButtons, skipDisabled, skipEmpty, uncheckedAs };
@@ -0,0 +1,285 @@
1
+ //#region src/utilities/form-object.ts
2
+ /** True when the control is a button / submit / reset / image. */
3
+ function isButton(control) {
4
+ if (control instanceof HTMLButtonElement) return true;
5
+ if (control instanceof HTMLInputElement) return control.type === "submit" || control.type === "reset" || control.type === "button" || control.type === "image";
6
+ return false;
7
+ }
8
+ /** Drop disabled controls (mirrors native `FormData`). */
9
+ const skipDisabled = (field) => field.control.disabled ? null : field;
10
+ /** Drop submit / reset / button / image controls and `<button>` elements. */
11
+ const skipButtons = (field) => isButton(field.control) ? null : field;
12
+ /** Drop fields whose control is an unchecked checkbox / radio. */
13
+ const dropUnchecked = (field) => field.checked === false ? null : field;
14
+ /**
15
+ * Include unchecked **checkboxes** with the given `value` instead of dropping
16
+ * them. Unchecked **radios** are still dropped (only the selected radio is
17
+ * meaningful). Use this **in place of** {@link dropUnchecked}.
18
+ *
19
+ * @example transforms: [skipDisabled, skipButtons, uncheckedAs(false)]
20
+ */
21
+ function uncheckedAs(value) {
22
+ return (field) => {
23
+ if (field.checked !== false) return field;
24
+ if (field.control instanceof HTMLInputElement && field.control.type === "radio") return null;
25
+ return {
26
+ ...field,
27
+ value,
28
+ checked: void 0
29
+ };
30
+ };
31
+ }
32
+ /** Drop fields whose value is empty: `""`, `null`, or an empty array. */
33
+ const skipEmpty = (field) => {
34
+ const v = field.value;
35
+ if (v === "" || v === null) return null;
36
+ if (Array.isArray(v) && v.length === 0) return null;
37
+ return field;
38
+ };
39
+ /** Default pipeline: skip disabled controls, buttons, and unchecked checkboxes/radios. */
40
+ const defaultTransforms = [
41
+ skipDisabled,
42
+ skipButtons,
43
+ dropUnchecked
44
+ ];
45
+ /** A non-negative integer string (e.g. "0", "12") — denotes an array index. */
46
+ function isIndex(segment) {
47
+ return /^(0|[1-9]\d*)$/.test(segment);
48
+ }
49
+ /**
50
+ * A trailing `[]` marks an auto-append array field (PHP / form-data-json
51
+ * convention) — `colors[]` appends to the `colors` array, `a.b[]` to `a.b`.
52
+ * Returns the dot-path without the suffix, or `null` when absent.
53
+ */
54
+ function arrayFieldPath(name) {
55
+ return name.endsWith("[]") ? name.slice(0, -2) : null;
56
+ }
57
+ /**
58
+ * Segments that could walk into an object's prototype. Writing through them
59
+ * enables prototype-pollution; reading them leaks internal objects. Paths
60
+ * containing any of these are ignored entirely.
61
+ */
62
+ function hasUnsafeKey(keys) {
63
+ return keys.some((k) => k === "__proto__" || k === "prototype" || k === "constructor");
64
+ }
65
+ /**
66
+ * Write `value` into `target` at the dot-notation `path`. Object segments
67
+ * create plain objects; integer segments create/extend arrays. Paths
68
+ * containing prototype-polluting segments are ignored.
69
+ *
70
+ * @example setPath(o, "user.tags.0", "a") // { user: { tags: ["a"] } }
71
+ */
72
+ function setPath(target, path, value) {
73
+ const keys = path.split(".");
74
+ if (hasUnsafeKey(keys)) return;
75
+ let node = target;
76
+ for (let i = 0; i < keys.length; i++) {
77
+ const key = keys[i];
78
+ if (i === keys.length - 1) {
79
+ node[key] = value;
80
+ return;
81
+ }
82
+ const nextKey = keys[i + 1];
83
+ const childShouldBeArray = isIndex(nextKey);
84
+ const existing = node[key];
85
+ if (existing === void 0 || typeof existing !== "object" || existing === null) node[key] = childShouldBeArray ? [] : {};
86
+ node = node[key];
87
+ }
88
+ }
89
+ /** Read the value at the dot-notation `path` from `source`, or `undefined`. */
90
+ function getPath(source, path) {
91
+ const keys = path.split(".");
92
+ if (hasUnsafeKey(keys)) return void 0;
93
+ let node = source;
94
+ for (const key of keys) {
95
+ if (node === null || typeof node !== "object") return void 0;
96
+ node = node[key];
97
+ }
98
+ return node;
99
+ }
100
+ /** Extract one raw {@link Field} from a named control, pre-transform. */
101
+ function extractField(control) {
102
+ if (control instanceof HTMLInputElement) {
103
+ const type = control.type;
104
+ if (type === "checkbox") return {
105
+ control,
106
+ name: control.name,
107
+ value: control.value || "on",
108
+ checked: control.checked
109
+ };
110
+ if (type === "radio") return {
111
+ control,
112
+ name: control.name,
113
+ value: control.value,
114
+ checked: control.checked
115
+ };
116
+ if (type === "file") {
117
+ const value = control.multiple ? Array.from(control.files ?? []) : control.files?.[0] ?? null;
118
+ return {
119
+ control,
120
+ name: control.name,
121
+ value
122
+ };
123
+ }
124
+ return {
125
+ control,
126
+ name: control.name,
127
+ value: control.value
128
+ };
129
+ }
130
+ if (control instanceof HTMLSelectElement && control.multiple) return {
131
+ control,
132
+ name: control.name,
133
+ value: Array.from(control.selectedOptions, (o) => o.value)
134
+ };
135
+ return {
136
+ control,
137
+ name: control.name,
138
+ value: control.value
139
+ };
140
+ }
141
+ /**
142
+ * Extracts an {@link HTMLFormElement} into a nested plain object (and writes one
143
+ * back) using dot-notation field names — `name="user.address.city"` nests into
144
+ * objects, numeric segments like `name="tags.0"` build arrays. A static snapshot:
145
+ * values are read/written at call time, no reactivity.
146
+ *
147
+ * Extraction runs each field through a composable {@link FormFieldTransform}
148
+ * pipeline ({@link defaultTransforms} by default), which decides inclusion and
149
+ * may rewrite names/values. Mirrors the ergonomics of the native `FormData`
150
+ * constructor.
151
+ *
152
+ * @example
153
+ * ```ts
154
+ * import { FormObject, defaultTransforms, uncheckedAs }
155
+ * from "elements-kit/utilities/form-object";
156
+ *
157
+ * // <input name="user.name"> <input name="tags.0"> <input name="tags.1">
158
+ * const data = new FormObject(form).toObject();
159
+ * // => { user: { name: "..." }, tags: ["...", "..."] }
160
+ *
161
+ * // Replace the pipeline — include unchecked checkboxes as false
162
+ * new FormObject(form, {
163
+ * transforms: [...defaultTransforms.slice(0, 2), uncheckedAs(false)],
164
+ * }).toObject();
165
+ *
166
+ * new FormObject(form).fromObject({ user: { name: "Wael" }, tags: ["a", "b"] });
167
+ * ```
168
+ */
169
+ var FormObject = class {
170
+ #form;
171
+ #transforms;
172
+ constructor(form, options = {}) {
173
+ this.#form = form;
174
+ this.#transforms = options.transforms ?? defaultTransforms;
175
+ }
176
+ /** Run a field through the transform pipeline; `null` if any transform drops it. */
177
+ #applyTransforms(field) {
178
+ let current = field;
179
+ for (const transform of this.#transforms) {
180
+ if (current === null) return null;
181
+ current = transform(current);
182
+ }
183
+ return current;
184
+ }
185
+ /**
186
+ * Place a field into `result`. Array-ness is explicit, like form-data-json:
187
+ * a name ending in `[]` appends to an array at that path (so a single
188
+ * `colors[]` still yields `["x"]` and an empty one stays `[]`), while a bare
189
+ * name is scalar — if several controls share it, the **last value wins**.
190
+ * Use explicit indices (`tags.0`, `tags.1`) or `[]` to build arrays.
191
+ */
192
+ #assign(result, field) {
193
+ const { name, value } = field;
194
+ const arrayPath = arrayFieldPath(name);
195
+ if (arrayPath !== null) {
196
+ let arr = getPath(result, arrayPath);
197
+ if (!Array.isArray(arr)) {
198
+ arr = [];
199
+ setPath(result, arrayPath, arr);
200
+ }
201
+ arr.push(value);
202
+ return;
203
+ }
204
+ setPath(result, name, value);
205
+ }
206
+ /** Snapshot the form into a nested object built from dot-notation names. */
207
+ toObject() {
208
+ const result = {};
209
+ for (const el of this.#form.elements) {
210
+ const control = el;
211
+ if (!control.name) continue;
212
+ const path = arrayFieldPath(control.name);
213
+ if (path !== null && getPath(result, path) === void 0) setPath(result, path, []);
214
+ }
215
+ for (const el of this.#form.elements) {
216
+ if (!el.name) continue;
217
+ const field = this.#applyTransforms(extractField(el));
218
+ if (field === null) continue;
219
+ this.#assign(result, field);
220
+ }
221
+ return result;
222
+ }
223
+ /** Alias for {@link toObject} — lets `JSON.stringify(instance)` work. */
224
+ toJSON() {
225
+ return this.toObject();
226
+ }
227
+ /** True when the control can be written/cleared (named and not disabled). */
228
+ #isWritable(el) {
229
+ const control = el;
230
+ return !!control.name && !control.disabled;
231
+ }
232
+ /** Write values from a nested object back onto the form's named controls. */
233
+ fromObject(data) {
234
+ for (const el of this.#form.elements) {
235
+ if (!this.#isWritable(el)) continue;
236
+ const control = el;
237
+ const value = getPath(data, arrayFieldPath(control.name) ?? control.name);
238
+ if (value === void 0) continue;
239
+ if (control instanceof HTMLInputElement) {
240
+ const type = control.type;
241
+ if (type === "checkbox") {
242
+ if (Array.isArray(value)) control.checked = value.includes(control.value);
243
+ else if (typeof value === "boolean") control.checked = value;
244
+ else control.checked = value === control.value || value === "on";
245
+ continue;
246
+ }
247
+ if (type === "radio") {
248
+ control.checked = control.value === value;
249
+ continue;
250
+ }
251
+ if (type === "file") continue;
252
+ control.value = value == null ? "" : String(value);
253
+ continue;
254
+ }
255
+ if (control instanceof HTMLSelectElement && control.multiple) {
256
+ const values = (Array.isArray(value) ? value : [value]).map(String);
257
+ for (const option of control.options) option.selected = values.includes(option.value);
258
+ continue;
259
+ }
260
+ control.value = value == null ? "" : String(value);
261
+ }
262
+ return this;
263
+ }
264
+ /** Reset every named control to its empty/default state. */
265
+ clear() {
266
+ for (const el of this.#form.elements) {
267
+ if (!this.#isWritable(el)) continue;
268
+ const control = el;
269
+ if (control instanceof HTMLInputElement) {
270
+ const type = control.type;
271
+ if (type === "checkbox" || type === "radio") control.checked = false;
272
+ else control.value = "";
273
+ continue;
274
+ }
275
+ if (control instanceof HTMLSelectElement) {
276
+ for (const option of control.options) option.selected = false;
277
+ continue;
278
+ }
279
+ control.value = "";
280
+ }
281
+ return this;
282
+ }
283
+ };
284
+ //#endregion
285
+ export { FormObject, defaultTransforms, dropUnchecked, skipButtons, skipDisabled, skipEmpty, uncheckedAs };
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-B7T5hi_D.mjs";
1
+ import { y as Computed } from "../types-ncUK9rki.mjs";
2
2
 
3
3
  //#region src/utilities/hover.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { m as signal } from "../lib-Dkc7cV5F.mjs";
1
+ import { x as signal } from "../lib-DYypKhxk.mjs";
2
2
  import "../signals/index.mjs";
3
3
  import { on } from "./event-listener.mjs";
4
4
  //#region src/utilities/hover.ts
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-B7T5hi_D.mjs";
1
+ import { y as Computed } from "../types-ncUK9rki.mjs";
2
2
 
3
3
  //#region src/utilities/interval.d.ts
4
4
  type IntervalResult = {
@@ -1,4 +1,4 @@
1
- import { m as signal, p as onCleanup } from "../lib-Dkc7cV5F.mjs";
1
+ import { _ as onCleanup, x as signal } from "../lib-DYypKhxk.mjs";
2
2
  import "../signals/index.mjs";
3
3
  //#region src/utilities/interval.ts
4
4
  function createInterval(arg1, arg2) {
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-B7T5hi_D.mjs";
1
+ import { y as Computed } from "../types-ncUK9rki.mjs";
2
2
 
3
3
  //#region src/utilities/location.d.ts
4
4
  type LocationResult = {
@@ -1,4 +1,4 @@
1
- import { h as trigger, m as signal, o as computed, p as onCleanup } from "../lib-Dkc7cV5F.mjs";
1
+ import { S as trigger, _ as onCleanup, l as computed, x as signal } from "../lib-DYypKhxk.mjs";
2
2
  import "../signals/index.mjs";
3
3
  import { fromEvent } from "./event-driven.mjs";
4
4
  import { isBrowser } from "./environment.mjs";
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-B7T5hi_D.mjs";
1
+ import { y as Computed } from "../types-ncUK9rki.mjs";
2
2
 
3
3
  //#region src/utilities/media-devices.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { m as signal } from "../lib-Dkc7cV5F.mjs";
1
+ import { x as signal } from "../lib-DYypKhxk.mjs";
2
2
  import "../signals/index.mjs";
3
3
  import { on } from "./event-listener.mjs";
4
4
  //#region src/utilities/media-devices.ts
@@ -1,4 +1,4 @@
1
- import { x as Signal, y as Computed } from "../infer-B7T5hi_D.mjs";
1
+ import { x as Signal, y as Computed } from "../types-ncUK9rki.mjs";
2
2
 
3
3
  //#region src/utilities/media-player.d.ts
4
4
  type MediaPlayerResult<T extends HTMLMediaElement> = {
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-B7T5hi_D.mjs";
1
+ import { y as Computed } from "../types-ncUK9rki.mjs";
2
2
 
3
3
  //#region src/utilities/media-query.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { m as signal } from "../lib-Dkc7cV5F.mjs";
1
+ import { x as signal } from "../lib-DYypKhxk.mjs";
2
2
  import "../signals/index.mjs";
3
3
  import { fromEvent, sync } from "./event-driven.mjs";
4
4
  import { isBrowser } from "./environment.mjs";
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-B7T5hi_D.mjs";
1
+ import { y as Computed } from "../types-ncUK9rki.mjs";
2
2
 
3
3
  //#region src/utilities/network.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { m as signal } from "../lib-Dkc7cV5F.mjs";
1
+ import { x as signal } from "../lib-DYypKhxk.mjs";
2
2
  import "../signals/index.mjs";
3
3
  import { on } from "./event-listener.mjs";
4
4
  import { isBrowser } from "./environment.mjs";
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-B7T5hi_D.mjs";
1
+ import { y as Computed } from "../types-ncUK9rki.mjs";
2
2
 
3
3
  //#region src/utilities/orientation.d.ts
4
4
  type OrientationResult = {
@@ -1,4 +1,4 @@
1
- import { o as computed } from "../lib-Dkc7cV5F.mjs";
1
+ import { l as computed } from "../lib-DYypKhxk.mjs";
2
2
  import "../signals/index.mjs";
3
3
  import { fromEvent, sync } from "./event-driven.mjs";
4
4
  import { isBrowser } from "./environment.mjs";
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-B7T5hi_D.mjs";
1
+ import { y as Computed } from "../types-ncUK9rki.mjs";
2
2
 
3
3
  //#region src/utilities/previous.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { m as signal, s as effect } from "../lib-Dkc7cV5F.mjs";
1
+ import { u as effect, x as signal } from "../lib-DYypKhxk.mjs";
2
2
  import "../signals/index.mjs";
3
3
  //#region src/utilities/previous.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-B7T5hi_D.mjs";
1
+ import { D as CLAIM, j as SEED, y as Computed } from "../types-ncUK9rki.mjs";
2
2
 
3
3
  //#region src/utilities/promise.d.ts
4
4
  /**
@@ -27,7 +27,24 @@ declare class ReactivePromise<T, E = unknown> extends Promise<T> {
27
27
  get result(): T | E | undefined;
28
28
  constructor(executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void);
29
29
  static from<T, E = unknown>(p: Promise<T>): ReactivePromise<T, E>;
30
+ /**
31
+ * @internal Hydration seeding: settle the reactive state from a serialized
32
+ * server snapshot. The underlying promise is untouched — when it actually
33
+ * resolves or rejects, its handlers overwrite the seeded state
34
+ * (stale-while-revalidate). `await` still waits for the real settlement.
35
+ */
36
+ [SEED](value: unknown): void;
37
+ /**
38
+ * @internal Hydrate claim protocol: seed from the server record while the
39
+ * underlying promise is still pending. The promise fired at construction —
40
+ * there is no run to skip here (see `Async[CLAIM]` for that).
41
+ */
42
+ [CLAIM](record: {
43
+ value: unknown;
44
+ } | undefined): void;
30
45
  }
46
+ /** @internal Cross-instance-safe `ReactivePromise` detection. */
47
+ declare function isReactivePromiseLike(value: unknown): value is ReactivePromise<unknown, unknown>;
31
48
  /**
32
49
  * A {@link ReactivePromise} that is also callable as a `Computed<T | E | undefined>`.
33
50
  *
@@ -59,4 +76,4 @@ declare function promise<T, E = unknown>(p: ReactivePromise<T>): ComputedPromise
59
76
  declare function promise<T, E = unknown>(p: Promise<T>): ComputedPromise<T, E>;
60
77
  declare function promise<T, E = unknown>(executor: Executor<T, E>): ComputedPromise<T, E>;
61
78
  //#endregion
62
- export { ComputedPromise, ReactivePromise, promise };
79
+ export { ComputedPromise, ReactivePromise, isReactivePromiseLike, promise };