elements-kit 0.3.2 → 0.3.3

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 (42) hide show
  1. package/dist/{element-BjpyY6qv.mjs → element-DvqBlRly.mjs} +195 -47
  2. package/dist/for.d.mts +1 -1
  3. package/dist/for.mjs +1 -1
  4. package/dist/{infer-LDn1TquI.d.mts → infer-K2Te9gn1.d.mts} +5 -5
  5. package/dist/integrations/react.d.mts +1 -1
  6. package/dist/jsx-runtime/index.d.mts +1 -1
  7. package/dist/jsx-runtime/index.mjs +1 -1
  8. package/dist/signals/index.d.mts +1 -1
  9. package/dist/signals/index.mjs +5 -3
  10. package/dist/slot-B8y0aEoz.d.mts +71 -0
  11. package/dist/slot-DLjSL6t1.mjs +124 -0
  12. package/dist/slot.d.mts +2 -2
  13. package/dist/slot.mjs +2 -2
  14. package/dist/utilities/active-element.d.mts +1 -1
  15. package/dist/utilities/async.d.mts +1 -1
  16. package/dist/utilities/debounced.d.mts +1 -1
  17. package/dist/utilities/dom-lifecycle.test.mjs +1 -0
  18. package/dist/utilities/element-rect.d.mts +1 -1
  19. package/dist/utilities/element-scroll.d.mts +1 -1
  20. package/dist/utilities/event-driven.d.mts +1 -1
  21. package/dist/utilities/event-listener.d.mts +1 -1
  22. package/dist/utilities/focus-within.d.mts +1 -1
  23. package/dist/utilities/hover.d.mts +1 -1
  24. package/dist/utilities/interval.d.mts +1 -1
  25. package/dist/utilities/location.d.mts +1 -1
  26. package/dist/utilities/media-devices.d.mts +1 -1
  27. package/dist/utilities/media-player.d.mts +1 -1
  28. package/dist/utilities/media-query.d.mts +1 -1
  29. package/dist/utilities/network.d.mts +1 -1
  30. package/dist/utilities/orientation.d.mts +1 -1
  31. package/dist/utilities/previous.d.mts +1 -1
  32. package/dist/utilities/promise.d.mts +1 -1
  33. package/dist/utilities/routing.d.mts +1 -1
  34. package/dist/utilities/search-params.d.mts +1 -1
  35. package/dist/utilities/storage.d.mts +1 -1
  36. package/dist/utilities/throttled.d.mts +1 -1
  37. package/dist/utilities/timeout.d.mts +1 -1
  38. package/dist/utilities/window-focus.d.mts +1 -1
  39. package/dist/utilities/window-size.d.mts +1 -1
  40. package/package.json +1 -1
  41. package/dist/slot-BnzxFBfO.mjs +0 -198
  42. package/dist/slot-CfafCBOW.d.mts +0 -121
@@ -2,19 +2,96 @@ import { c as effectScope, g as untracked, p as onCleanup, s as effect } from ".
2
2
  import "./polyfill-CdZVCxdo.mjs";
3
3
  import { isReactive, resolveProps } from "./signals/index.mjs";
4
4
  import { on } from "./utilities/event-listener.mjs";
5
- import { i as resolveNode$1, n as Slot, r as Slots, t as SLOTS } from "./slot-BnzxFBfO.mjs";
6
- import { ChildProperties, Properties, SVGNamespace } from "dom-expressions/src/constants.js";
5
+ import { n as Slot, r as resolveNode$1, t as SLOTS } from "./slot-DLjSL6t1.mjs";
7
6
  //#region src/jsx-runtime/constants.ts
8
7
  /**
9
8
  * IDL properties that take precedence over the default `setAttribute` path.
10
9
  *
11
- * Extends dom-expressions' base set with `defaultValue` without it, JSX
12
- * `<input defaultValue="x" />` falls through to `setAttribute("defaultValue",
13
- * "x")` and creates a useless `defaultvalue` HTML attribute (native
14
- * `HTMLInputElement` has no such content attribute; its `defaultValue` IDL
15
- * property reflects the `value` content attribute instead).
10
+ * Includes camelCase boolean aliases (`readOnly`, `noValidate`, …) plus
11
+ * lowercase boolean attributes that should be set as properties for correct
12
+ * reflection. `defaultValue` is added on top without it, `<input
13
+ * defaultValue="x" />` falls through to `setAttribute("defaultValue", "x")`
14
+ * which creates a useless `defaultvalue` content attribute (native
15
+ * `HTMLInputElement` has no such attribute; the IDL property reflects `value`).
16
16
  */
17
- const Properties$1 = new Set([...Properties, "defaultValue"]);
17
+ const Properties = new Set([
18
+ "className",
19
+ "value",
20
+ "readOnly",
21
+ "noValidate",
22
+ "formNoValidate",
23
+ "isMap",
24
+ "noModule",
25
+ "playsInline",
26
+ "adAuctionHeaders",
27
+ "allowFullscreen",
28
+ "browsingTopics",
29
+ "defaultChecked",
30
+ "defaultMuted",
31
+ "defaultSelected",
32
+ "disablePictureInPicture",
33
+ "disableRemotePlayback",
34
+ "preservesPitch",
35
+ "shadowRootClonable",
36
+ "shadowRootCustomElementRegistry",
37
+ "shadowRootDelegatesFocus",
38
+ "shadowRootSerializable",
39
+ "sharedStorageWritable",
40
+ "allowfullscreen",
41
+ "async",
42
+ "alpha",
43
+ "autofocus",
44
+ "autoplay",
45
+ "checked",
46
+ "controls",
47
+ "default",
48
+ "disabled",
49
+ "formnovalidate",
50
+ "hidden",
51
+ "indeterminate",
52
+ "inert",
53
+ "ismap",
54
+ "loop",
55
+ "multiple",
56
+ "muted",
57
+ "nomodule",
58
+ "novalidate",
59
+ "open",
60
+ "playsinline",
61
+ "readonly",
62
+ "required",
63
+ "reversed",
64
+ "seamless",
65
+ "selected",
66
+ "adauctionheaders",
67
+ "browsingtopics",
68
+ "credentialless",
69
+ "defaultchecked",
70
+ "defaultmuted",
71
+ "defaultselected",
72
+ "defer",
73
+ "disablepictureinpicture",
74
+ "disableremoteplayback",
75
+ "preservespitch",
76
+ "shadowrootclonable",
77
+ "shadowrootcustomelementregistry",
78
+ "shadowrootdelegatesfocus",
79
+ "shadowrootserializable",
80
+ "sharedstoragewritable",
81
+ "defaultValue"
82
+ ]);
83
+ /** Properties whose assignment replaces the element's children. */
84
+ const ChildProperties = new Set([
85
+ "innerHTML",
86
+ "textContent",
87
+ "innerText",
88
+ "children"
89
+ ]);
90
+ /** XML namespaces for SVG-namespaced attributes (`xlink:href`, `xml:lang`). */
91
+ const SVGNamespace = {
92
+ xlink: "http://www.w3.org/1999/xlink",
93
+ xml: "http://www.w3.org/XML/1998/namespace"
94
+ };
18
95
  const ReservedNameSpaces = new Set([
19
96
  "class",
20
97
  "on",
@@ -29,15 +106,14 @@ function hasSlots(node) {
29
106
  function isChildrenProperty(node, key) {
30
107
  if (key === "children" && (node instanceof Element || node instanceof DocumentFragment)) return true;
31
108
  if (hasSlots(node)) {
32
- const slotName = key.replace(/^slot:/, "");
33
- if (Slots.has(node[SLOTS], slotName)) return true;
109
+ if (key.replace(/^slot:/, "") in node[SLOTS]) return true;
34
110
  }
35
111
  return key in node && node[key] instanceof Slot;
36
112
  }
37
113
  function applyChildren(node, key, value) {
38
114
  if (hasSlots(node)) {
39
115
  const slotName = key.replace(/^slot:/, "");
40
- if (Slots.has(node[SLOTS], slotName)) {
116
+ if (slotName in node[SLOTS]) {
41
117
  applySlot(node[SLOTS][slotName], value);
42
118
  return;
43
119
  }
@@ -67,8 +143,72 @@ function applySlot(slot, value) {
67
143
  });
68
144
  });
69
145
  }
146
+ const FRAGMENT_POOL_MAX = 4;
147
+ const fragmentPool = [];
148
+ function acquireFragment() {
149
+ return fragmentPool.pop() ?? document.createDocumentFragment();
150
+ }
151
+ function releaseFragment(frag) {
152
+ if (fragmentPool.length < FRAGMENT_POOL_MAX) fragmentPool.push(frag);
153
+ }
70
154
  function mountChildren(el, value) {
71
- for (const child of ensureFlatArray(value)) mountChild(el, child);
155
+ const list = ensureFlatArray(value);
156
+ if (list.length === 0) return;
157
+ if (list.length === 1) {
158
+ mountChild(el, list[0]);
159
+ return;
160
+ }
161
+ const kind = classifyStatic(list);
162
+ if (kind !== 0) {
163
+ mountStatic(el, list, kind);
164
+ return;
165
+ }
166
+ const buffer = acquireFragment();
167
+ for (const child of list) mountChild(buffer, child);
168
+ el.appendChild(buffer);
169
+ releaseFragment(buffer);
170
+ }
171
+ function classifyStatic(list) {
172
+ let kind = 3;
173
+ for (const c of list) {
174
+ if (c == null || c === false || c === true) continue;
175
+ if (typeof c === "function") return 0;
176
+ if (c instanceof Node) kind &= 1;
177
+ else if (typeof c === "string" || typeof c === "number") kind &= 2;
178
+ else return 0;
179
+ if (kind === 0) return 3;
180
+ }
181
+ return kind === 3 ? 2 : kind;
182
+ }
183
+ function mountStatic(el, list, kind) {
184
+ const buffer = acquireFragment();
185
+ let disposers = null;
186
+ if (kind === 1) for (const c of list) {
187
+ const node = c;
188
+ const dispose = node[Symbol.dispose];
189
+ if (dispose) (disposers ??= []).push(dispose);
190
+ buffer.appendChild(node);
191
+ }
192
+ else if (kind === 2) for (const c of list) {
193
+ if (c == null || c === false || c === true) continue;
194
+ buffer.appendChild(document.createTextNode(String(c)));
195
+ }
196
+ else for (const c of list) {
197
+ if (c == null || c === false || c === true) continue;
198
+ if (c instanceof Node) {
199
+ const dispose = c[Symbol.dispose];
200
+ if (dispose) (disposers ??= []).push(dispose);
201
+ buffer.appendChild(c);
202
+ } else buffer.appendChild(document.createTextNode(String(c)));
203
+ }
204
+ el.appendChild(buffer);
205
+ releaseFragment(buffer);
206
+ if (disposers && disposers.length > 0) {
207
+ const ds = disposers;
208
+ effectScope(() => {
209
+ onCleanup(() => ds.forEach((d) => d()));
210
+ });
211
+ }
72
212
  }
73
213
  /**
74
214
  * Mounts a single child into `el`. Reactive functions become live slots; other
@@ -82,8 +222,8 @@ function mountChildren(el, value) {
82
222
  */
83
223
  function mountChild(el, child) {
84
224
  if (typeof child === "function") {
85
- const slot = Slot.new();
86
- el.appendChild(slot());
225
+ const slot = new Slot();
226
+ el.appendChild(slot.render());
87
227
  effectScope(() => {
88
228
  effect(() => slot.set(resolveChild(child())));
89
229
  onCleanup(() => slot.clear());
@@ -113,23 +253,24 @@ function ensureFlatArray(raw) {
113
253
  //#endregion
114
254
  //#region src/jsx-runtime/properties.ts
115
255
  function applyProps(node, props) {
116
- for (const [key, value] of Object.entries(props)) {
256
+ const entries = Object.entries(props);
257
+ if (entries.length === 0) return;
258
+ for (const [key, value] of entries) {
117
259
  if (isChildrenProperty(node, key)) {
118
260
  applyChildren(node, key, value);
119
261
  continue;
120
262
  }
121
- if (isReactive(value)) {
122
- if (isEventKey(key)) {
123
- effect(() => {
124
- on(node, eventName(key), value());
125
- });
126
- continue;
127
- }
128
- effect(() => setProp(node, key, value()));
263
+ const colonIdx = key.indexOf(":");
264
+ if ((colonIdx > 0 ? key.slice(0, colonIdx) : "") === "on") {
265
+ const evName = key.slice(colonIdx + 1);
266
+ if (isReactive(value)) effect(() => {
267
+ on(node, evName, value());
268
+ });
269
+ else on(node, evName, value);
129
270
  continue;
130
271
  }
131
- if (isEventKey(key)) {
132
- on(node, eventName(key), value);
272
+ if (isReactive(value)) {
273
+ effect(() => setProp(node, key, value()));
133
274
  continue;
134
275
  }
135
276
  setProp(node, key, value);
@@ -174,7 +315,7 @@ function setProp(node, key, value) {
174
315
  node[key] = value ?? "";
175
316
  return;
176
317
  }
177
- if (!(node instanceof SVGElement) && Properties$1.has(key)) {
318
+ if (!(node instanceof SVGElement) && Properties.has(key)) {
178
319
  node[key] = value;
179
320
  return;
180
321
  }
@@ -199,14 +340,35 @@ function applyStyle(el, value) {
199
340
  else if (value && typeof value === "object") Object.assign(s, value);
200
341
  }
201
342
  function setAttribute(el, key, value) {
202
- if (value == null || value === false) el.removeAttribute(key);
203
- else el.setAttribute(key, value === true ? "" : String(value));
204
- }
205
- function isEventKey(key) {
206
- return key.startsWith("on:");
343
+ if (value == null || value === false) {
344
+ if (el.hasAttribute(key)) el.removeAttribute(key);
345
+ return;
346
+ }
347
+ const next = value === true ? "" : String(value);
348
+ if (el.getAttribute(key) === next) return;
349
+ el.setAttribute(key, next);
207
350
  }
208
- function eventName(key) {
209
- return key.slice(3);
351
+ //#endregion
352
+ //#region src/jsx-runtime/dispose.ts
353
+ const DISPOSABLES = /* @__PURE__ */ new WeakMap();
354
+ const sharedDispose = function() {
355
+ const set = DISPOSABLES.get(this);
356
+ if (!set) return;
357
+ DISPOSABLES.delete(this);
358
+ set.forEach((fn) => fn());
359
+ set.clear();
360
+ };
361
+ function attachDisposables(target, disposers) {
362
+ const existing = DISPOSABLES.get(target);
363
+ if (existing) {
364
+ disposers.forEach((d) => existing.add(d));
365
+ return;
366
+ }
367
+ DISPOSABLES.set(target, disposers);
368
+ Object.defineProperty(target, Symbol.dispose, {
369
+ value: sharedDispose.bind(target),
370
+ configurable: true
371
+ });
210
372
  }
211
373
  //#endregion
212
374
  //#region src/jsx-runtime/element.ts
@@ -259,19 +421,5 @@ function renderNode(node) {
259
421
  if (!node || typeof node.render !== "function") return null;
260
422
  return renderNode(node.render());
261
423
  }
262
- function hasOwnDisposable(el) {
263
- return Object.hasOwn(el, Symbol.dispose);
264
- }
265
- function attachDisposables(el, disposables) {
266
- const existingDispose = hasOwnDisposable(el) ? el[Symbol.dispose].bind(el) : null;
267
- Object.defineProperty(el, Symbol.dispose, {
268
- value() {
269
- existingDispose?.();
270
- disposables.forEach((fn) => fn());
271
- disposables.clear();
272
- },
273
- configurable: true
274
- });
275
- }
276
424
  //#endregion
277
425
  export { disposeElement as n, mountChild as r, createElement as t };
package/dist/for.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { i as Props, s as Require } from "./infer-LDn1TquI.mjs";
1
+ import { i as Props, s as Require } from "./infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/for.d.ts
4
4
  type KeyFn<T> = (item: T, index: number) => string | number;
package/dist/for.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { c as effectScope, g as untracked, h as trigger, m as signal, p as onCleanup, s as effect } from "./lib-CVfOddra.mjs";
2
2
  import "./signals/index.mjs";
3
- import { n as disposeElement } from "./element-BjpyY6qv.mjs";
3
+ import { n as disposeElement } from "./element-DvqBlRly.mjs";
4
4
  //#region src/for.ts
5
5
  /**
6
6
  * Keyed list renderer. See {@link ForProps} for prop details.
@@ -1,6 +1,6 @@
1
1
  import { n as AttrChangeHandler, t as ATTRIBUTES } from "./attributes-3r7Diua4.mjs";
2
2
  import { t as CustomElementRegistry } from "./custom-elements-D5CgfNKc.mjs";
3
- import { a as PrimitiveNodeType, i as Slots, n as Slot, t as SLOTS } from "./slot-CfafCBOW.mjs";
3
+ import { n as Slot, r as PrimitiveNodeType, t as SLOTS } from "./slot-B8y0aEoz.mjs";
4
4
  import { JSX } from "dom-expressions/src/jsx-h";
5
5
 
6
6
  //#region src/jsx-runtime/element.d.ts
@@ -553,8 +553,8 @@ type EventMapOf<C> = C extends {
553
553
  type Capitalize1<S extends string> = S extends `${infer H}${infer R}` ? `${Uppercase<H>}${R}` : S;
554
554
  type EventsOf<C> = EventMapOf<C> extends infer E ? E extends Record<string, Event> ? { [K in keyof E & string as `on:${K}`]?: (ev: E[K]) => void } & { [K in keyof E & string as `on${Capitalize1<K>}`]?: (ev: E[K]) => void } : {} : {};
555
555
  type SlotKeys<I> = I extends {
556
- [SLOTS]: Slots<infer K>;
557
- } ? K : never;
556
+ [SLOTS]: infer S;
557
+ } ? Extract<keyof S, string> : never;
558
558
  type InstanceOf<C> = C extends (abstract new (...args: any[]) => infer I) ? I : C;
559
559
  type SlotsOf<C> = SlotKeys<InstanceOf<C>> extends infer K ? [K] extends [string] ? { [P in K as `slot:${P}`]?: Child } : {} : {};
560
560
  type ChildrenOf<C> = C extends {
@@ -573,7 +573,7 @@ type BaseDOMAttrs = JSX.DOMAttributes<HTMLElement>;
573
573
  * - **`prop:*`** — explicit property assignment for every field.
574
574
  * - **Events** — keys from `declare static events: { ... }` produce both
575
575
  * `on:${K}` and `on${Capitalize<K>}` typed handlers.
576
- * - **Slots** — keys from `[SLOTS] = Slots.new([...] as const)` produce `slot:${K}`.
576
+ * - **Slots** — keys from `[SLOTS] = { ... } as const` produce `slot:${K}`.
577
577
  * - **Children** — `children?: Child` unless `static children: never`.
578
578
  * - **DOM attrs** — the standard dom-expressions surface (`class`, `style`, `ref`, …).
579
579
  *
@@ -585,7 +585,7 @@ type BaseDOMAttrs = JSX.DOMAttributes<HTMLElement>;
585
585
  * class XRange extends HTMLElement {
586
586
  * static [ATTRIBUTES]: Attributes<XRange> = { min(v) { this.min = +v! } };
587
587
  * declare static events: { commit: CustomEvent<number> };
588
- * [SLOTS] = Slots.new(["label"] as const);
588
+ * [SLOTS] = { label: new Slot() } as const;
589
589
  * \@reactive() min = 0;
590
590
  * }
591
591
  *
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-LDn1TquI.mjs";
1
+ import { y as Computed } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/integrations/react.d.ts
4
4
  /**
@@ -1,2 +1,2 @@
1
- import { U as createElement, _ as SlotProps, a as RawProps, b as MaybeReactive, c as ResolveProps, d as ComponentClass, f as ComponentFn, g as JSX, h as Attrs, i as Props, l as Child, m as PropsTarget, n as ElementProps, o as ReactiveProps, p as ComponentInstance, r as MaybeReactiveProps, s as Require, t as ComponentProps, u as Component, v as Fragment } from "../infer-LDn1TquI.mjs";
1
+ import { U as createElement, _ as SlotProps, a as RawProps, b as MaybeReactive, c as ResolveProps, d as ComponentClass, f as ComponentFn, g as JSX, h as Attrs, i as Props, l as Child, m as PropsTarget, n as ElementProps, o as ReactiveProps, p as ComponentInstance, r as MaybeReactiveProps, s as Require, t as ComponentProps, u as Component, v as Fragment } from "../infer-K2Te9gn1.mjs";
2
2
  export { Attrs, Child, Component, ComponentClass, ComponentFn, ComponentInstance, ComponentProps, ElementProps, Fragment, JSX, MaybeReactive, MaybeReactiveProps, Props, PropsTarget, RawProps, ReactiveProps, Require, ResolveProps, SlotProps, createElement as h, createElement as jsx, createElement as jsxDEV, createElement as jsxs };
@@ -1,4 +1,4 @@
1
- import { r as mountChild, t as createElement } from "../element-BjpyY6qv.mjs";
1
+ import { r as mountChild, t as createElement } from "../element-DvqBlRly.mjs";
2
2
  //#region src/jsx-runtime/fragment.ts
3
3
  /**
4
4
  * Used by the JSX transform for `<>...</>` fragments.
@@ -1,2 +1,2 @@
1
- import { A as SIGNAL, B as signal, C as isReactive, D as COMPUTED, E as resolveProps, F as isComputed, H as untracked, I as isEffect, L as isEffectScope, M as computed, N as effect, O as EFFECT, P as effectScope, R as isSignal, S as Updater, T as resolve, V as trigger, b as MaybeReactive, j as batch, k as EFFECT_SCOPE, w as reactive, x as Signal, y as Computed, z as onCleanup } from "../infer-LDn1TquI.mjs";
1
+ import { A as SIGNAL, B as signal, C as isReactive, D as COMPUTED, E as resolveProps, F as isComputed, H as untracked, I as isEffect, L as isEffectScope, M as computed, N as effect, O as EFFECT, P as effectScope, R as isSignal, S as Updater, T as resolve, V as trigger, b as MaybeReactive, j as batch, k as EFFECT_SCOPE, w as reactive, x as Signal, y as Computed, z as onCleanup } from "../infer-K2Te9gn1.mjs";
2
2
  export { COMPUTED, Computed, EFFECT, EFFECT_SCOPE, MaybeReactive, SIGNAL, Signal, Updater, batch, computed, effect, effectScope, isComputed, isEffect, isEffectScope, isReactive, isSignal, onCleanup, reactive, resolve, resolveProps, signal, trigger, untracked };
@@ -109,6 +109,8 @@ function resolve(value) {
109
109
  * ```
110
110
  */
111
111
  function resolveProps(raw) {
112
+ const ownKeys = Reflect.ownKeys(raw);
113
+ const ownKeySet = new Set(ownKeys);
112
114
  const cache = /* @__PURE__ */ new Map();
113
115
  const get = (key) => {
114
116
  let getter = cache.get(key);
@@ -121,9 +123,9 @@ function resolveProps(raw) {
121
123
  };
122
124
  return new Proxy(raw, {
123
125
  get: (_target, key) => get(key),
124
- has: (_target, key) => key in raw,
125
- ownKeys: (_target) => Reflect.ownKeys(raw),
126
- getOwnPropertyDescriptor: (_target, key) => key in raw ? {
126
+ has: (_target, key) => ownKeySet.has(key),
127
+ ownKeys: () => ownKeys,
128
+ getOwnPropertyDescriptor: (_target, key) => ownKeySet.has(key) ? {
127
129
  enumerable: true,
128
130
  configurable: true,
129
131
  writable: false,
@@ -0,0 +1,71 @@
1
+ //#region src/lib.d.ts
2
+ type PrimitiveNodeType = Node | string | boolean | number | bigint | symbol | Date | RegExp | null | undefined;
3
+ //#endregion
4
+ //#region src/polyfill.d.ts
5
+ declare global {
6
+ interface SymbolConstructor {
7
+ readonly dispose: symbol;
8
+ }
9
+ interface Disposable {
10
+ [Symbol.dispose](): void;
11
+ }
12
+ }
13
+ //#endregion
14
+ //#region src/slot.d.ts
15
+ /**
16
+ * A lightweight slot that reserves a region in the DOM using comment markers.
17
+ * Content between the markers can be replaced dynamically without wrapper elements.
18
+ */
19
+ declare class Slot {
20
+ #private;
21
+ /**
22
+ * Render the slot as a DocumentFragment.
23
+ * If not yet mounted, inserts the comment markers and optional default content.
24
+ * If already mounted, extracts and returns the current content WITHOUT disposing
25
+ * it — the caller takes ownership of the returned nodes and is responsible for
26
+ * their disposal.
27
+ */
28
+ render(defaultContent?: PrimitiveNodeType): DocumentFragment;
29
+ /** Dispose reactive children and remove all content between the markers. */
30
+ clear(): void;
31
+ /**
32
+ * Replace the slot's content with the given element.
33
+ * No-op if the slot is not mounted or the content is identical.
34
+ */
35
+ set(element: Node): void;
36
+ /**
37
+ * Extract and return the current slot content as a DocumentFragment.
38
+ * Returns `null` if the slot is not mounted.
39
+ * Content is NOT disposed — the caller takes ownership and is responsible
40
+ * for disposal.
41
+ */
42
+ get(): DocumentFragment | null;
43
+ /** Returns the parent node if the slot is mounted, otherwise `null`. */
44
+ parent(): ParentNode | null;
45
+ /** Whether the slot's comment markers are attached to the DOM. */
46
+ isMounted(): boolean;
47
+ }
48
+ /**
49
+ * Symbol key for attaching a slot collection to a custom element instance.
50
+ * Prevents collisions with public Element properties and signals to the JSX
51
+ * runtime that this property holds slot wiring (not regular children).
52
+ *
53
+ * The value at `[SLOTS]` is a plain object whose keys are slot names and whose
54
+ * values are {@link Slot} instances. Declare with `as const` so TypeScript
55
+ * preserves the literal key union — this is what `ElementProps<typeof Cls>`
56
+ * uses to synthesize `slot:${K}` entries.
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * class Card extends HTMLElement {
61
+ * // ✅ literal keys flow through — "header" | "footer"
62
+ * [SLOTS] = { header: new Slot(), footer: new Slot() } as const;
63
+ * }
64
+ *
65
+ * // ❌ widens — no typed slot:* props
66
+ * // [SLOTS] = { header: new Slot(), footer: new Slot() };
67
+ * ```
68
+ */
69
+ declare const SLOTS: unique symbol;
70
+ //#endregion
71
+ export { Slot as n, PrimitiveNodeType as r, SLOTS as t };
@@ -0,0 +1,124 @@
1
+ import "./polyfill-CdZVCxdo.mjs";
2
+ //#region src/lib.ts
3
+ var UnsupportedChildError = class extends Error {
4
+ constructor(value) {
5
+ super(`Unsupported child type: ${typeof value}`);
6
+ this.name = "UnsupportedChildError";
7
+ }
8
+ };
9
+ function resolveNode(c) {
10
+ if (c instanceof Node) return c;
11
+ if (c === null || c === void 0 || typeof c === "boolean") return document.createComment("");
12
+ if (typeof c === "string" || typeof c === "number" || typeof c === "bigint" || typeof c === "symbol" || c instanceof Date || c instanceof RegExp) return document.createTextNode(String(c));
13
+ throw new UnsupportedChildError(c);
14
+ }
15
+ //#endregion
16
+ //#region src/slot.ts
17
+ /**
18
+ * A lightweight slot that reserves a region in the DOM using comment markers.
19
+ * Content between the markers can be replaced dynamically without wrapper elements.
20
+ */
21
+ var Slot = class {
22
+ #start = document.createComment("{");
23
+ #end = document.createComment("}");
24
+ #pending;
25
+ /**
26
+ * Render the slot as a DocumentFragment.
27
+ * If not yet mounted, inserts the comment markers and optional default content.
28
+ * If already mounted, extracts and returns the current content WITHOUT disposing
29
+ * it — the caller takes ownership of the returned nodes and is responsible for
30
+ * their disposal.
31
+ */
32
+ render(defaultContent) {
33
+ const fragment = document.createDocumentFragment();
34
+ if (this.isMounted()) {
35
+ const range = document.createRange();
36
+ range.setStartAfter(this.#start);
37
+ range.setEndBefore(this.#end);
38
+ fragment.appendChild(range.extractContents());
39
+ return fragment;
40
+ }
41
+ fragment.appendChild(this.#start);
42
+ fragment.appendChild(this.#end);
43
+ const initialContent = this.#pending ?? resolveNode(defaultContent);
44
+ if (initialContent) fragment.insertBefore(initialContent, this.#end);
45
+ this.#pending = void 0;
46
+ return fragment;
47
+ }
48
+ /** Dispose reactive children and remove all content between the markers. */
49
+ clear() {
50
+ let node = this.#start.nextSibling;
51
+ while (node && node !== this.#end) {
52
+ const next = node.nextSibling;
53
+ if (node instanceof Element) node[Symbol.dispose]?.();
54
+ node = next;
55
+ }
56
+ const range = document.createRange();
57
+ range.setStartAfter(this.#start);
58
+ range.setEndBefore(this.#end);
59
+ range.deleteContents();
60
+ }
61
+ /**
62
+ * Replace the slot's content with the given element.
63
+ * No-op if the slot is not mounted or the content is identical.
64
+ */
65
+ set(element) {
66
+ const parent = this.parent();
67
+ if (!parent) {
68
+ this.#pending = element;
69
+ return;
70
+ }
71
+ if (this.#isSame(element)) return;
72
+ this.clear();
73
+ parent.insertBefore(element, this.#end);
74
+ this.#pending = void 0;
75
+ }
76
+ /**
77
+ * Extract and return the current slot content as a DocumentFragment.
78
+ * Returns `null` if the slot is not mounted.
79
+ * Content is NOT disposed — the caller takes ownership and is responsible
80
+ * for disposal.
81
+ */
82
+ get() {
83
+ if (!this.isMounted()) return null;
84
+ const range = document.createRange();
85
+ range.setStartAfter(this.#start);
86
+ range.setEndBefore(this.#end);
87
+ return range.extractContents();
88
+ }
89
+ /** Returns the parent node if the slot is mounted, otherwise `null`. */
90
+ parent() {
91
+ return this.isMounted() ? this.#start.parentNode : null;
92
+ }
93
+ /** Whether the slot's comment markers are attached to the DOM. */
94
+ isMounted() {
95
+ return this.#start.parentNode === this.#end.parentNode && !!this.#start.parentNode;
96
+ }
97
+ #isSame(element) {
98
+ return this.#start.nextSibling === element && this.#end === element.nextSibling;
99
+ }
100
+ };
101
+ /**
102
+ * Symbol key for attaching a slot collection to a custom element instance.
103
+ * Prevents collisions with public Element properties and signals to the JSX
104
+ * runtime that this property holds slot wiring (not regular children).
105
+ *
106
+ * The value at `[SLOTS]` is a plain object whose keys are slot names and whose
107
+ * values are {@link Slot} instances. Declare with `as const` so TypeScript
108
+ * preserves the literal key union — this is what `ElementProps<typeof Cls>`
109
+ * uses to synthesize `slot:${K}` entries.
110
+ *
111
+ * @example
112
+ * ```ts
113
+ * class Card extends HTMLElement {
114
+ * // ✅ literal keys flow through — "header" | "footer"
115
+ * [SLOTS] = { header: new Slot(), footer: new Slot() } as const;
116
+ * }
117
+ *
118
+ * // ❌ widens — no typed slot:* props
119
+ * // [SLOTS] = { header: new Slot(), footer: new Slot() };
120
+ * ```
121
+ */
122
+ const SLOTS = Symbol("slots");
123
+ //#endregion
124
+ export { Slot as n, resolveNode as r, SLOTS as t };
package/dist/slot.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { i as Slots, n as Slot, r as SlotInstance, t as SLOTS } from "./slot-CfafCBOW.mjs";
2
- export { SLOTS, Slot, SlotInstance, Slots };
1
+ import { n as Slot, t as SLOTS } from "./slot-B8y0aEoz.mjs";
2
+ export { SLOTS, Slot };
package/dist/slot.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { n as Slot, r as Slots, t as SLOTS } from "./slot-BnzxFBfO.mjs";
2
- export { SLOTS, Slot, Slots };
1
+ import { n as Slot, t as SLOTS } from "./slot-DLjSL6t1.mjs";
2
+ export { SLOTS, Slot };
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-LDn1TquI.mjs";
1
+ import { y as Computed } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/utilities/active-element.d.ts
4
4
  declare const activeElement: Computed<Element | null>;
@@ -1,4 +1,4 @@
1
- import { b as MaybeReactive } from "../infer-LDn1TquI.mjs";
1
+ import { b as MaybeReactive } from "../infer-K2Te9gn1.mjs";
2
2
  import { ComputedPromise } from "./promise.mjs";
3
3
 
4
4
  //#region src/utilities/async.d.ts
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-LDn1TquI.mjs";
1
+ import { y as Computed } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/utilities/debounced.d.ts
4
4
  /**
@@ -193,6 +193,7 @@ describe("dom-lifecycle", () => {
193
193
  });
194
194
  it("applies render-inert defaults: display:contents and role='none'", () => {
195
195
  const probe = makeProbe();
196
+ document.body.appendChild(probe);
196
197
  globalExpect(probe.style.display).toBe("contents");
197
198
  globalExpect(probe.getAttribute("role")).toBe("none");
198
199
  });
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-LDn1TquI.mjs";
1
+ import { y as Computed } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/utilities/element-rect.d.ts
4
4
  type RectResult = {
@@ -1,4 +1,4 @@
1
- import { x as Signal } from "../infer-LDn1TquI.mjs";
1
+ import { x as Signal } from "../infer-K2Te9gn1.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-LDn1TquI.mjs";
1
+ import { x as Signal, y as Computed } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/utilities/event-driven.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-LDn1TquI.mjs";
1
+ import { y as Computed } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/utilities/event-listener.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-LDn1TquI.mjs";
1
+ import { y as Computed } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/utilities/focus-within.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-LDn1TquI.mjs";
1
+ import { y as Computed } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/utilities/hover.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-LDn1TquI.mjs";
1
+ import { y as Computed } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/utilities/interval.d.ts
4
4
  type IntervalResult = {
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-LDn1TquI.mjs";
1
+ import { y as Computed } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/utilities/location.d.ts
4
4
  type LocationResult = {
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-LDn1TquI.mjs";
1
+ import { y as Computed } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/utilities/media-devices.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { x as Signal, y as Computed } from "../infer-LDn1TquI.mjs";
1
+ import { x as Signal, y as Computed } from "../infer-K2Te9gn1.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-LDn1TquI.mjs";
1
+ import { y as Computed } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/utilities/media-query.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-LDn1TquI.mjs";
1
+ import { y as Computed } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/utilities/network.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-LDn1TquI.mjs";
1
+ import { y as Computed } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/utilities/orientation.d.ts
4
4
  type OrientationResult = {
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-LDn1TquI.mjs";
1
+ import { y as Computed } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/utilities/previous.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-LDn1TquI.mjs";
1
+ import { y as Computed } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/utilities/promise.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-LDn1TquI.mjs";
1
+ import { y as Computed } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/utilities/routing.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-LDn1TquI.mjs";
1
+ import { y as Computed } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/utilities/search-params.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { x as Signal } from "../infer-LDn1TquI.mjs";
1
+ import { x as Signal } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/utilities/storage.d.ts
4
4
  type StorageOptions<T> = {
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-LDn1TquI.mjs";
1
+ import { y as Computed } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/utilities/throttled.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-LDn1TquI.mjs";
1
+ import { y as Computed } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/utilities/timeout.d.ts
4
4
  type TimeoutResult = {
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-LDn1TquI.mjs";
1
+ import { y as Computed } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/utilities/window-focus.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { y as Computed } from "../infer-LDn1TquI.mjs";
1
+ import { y as Computed } from "../infer-K2Te9gn1.mjs";
2
2
 
3
3
  //#region src/utilities/window-size.d.ts
4
4
  type WindowSizeResult = {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "elements-kit",
3
3
  "type": "module",
4
- "version": "0.3.2",
4
+ "version": "0.3.3",
5
5
  "description": "A lightweight reactive UI library that transforms native HTMLElements into reactive components with signals. Ideal for framework-agnostic applications and web components.",
6
6
  "keywords": [
7
7
  "webcomponents",
@@ -1,198 +0,0 @@
1
- import "./polyfill-CdZVCxdo.mjs";
2
- //#region src/lib.ts
3
- var UnsupportedChildError = class extends Error {
4
- constructor(value) {
5
- super(`Unsupported child type: ${typeof value}`);
6
- this.name = "UnsupportedChildError";
7
- }
8
- };
9
- function resolveNode(c) {
10
- if (c instanceof Node) return c;
11
- if (c === null || c === void 0 || typeof c === "boolean") return document.createComment("");
12
- if (typeof c === "string" || typeof c === "number" || typeof c === "bigint" || typeof c === "symbol" || c instanceof Date || c instanceof RegExp) return document.createTextNode(String(c));
13
- throw new UnsupportedChildError(c);
14
- }
15
- //#endregion
16
- //#region src/slot.ts
17
- /**
18
- * A lightweight slot that reserves a region in the DOM using comment markers.
19
- * Content between the markers can be replaced dynamically without wrapper elements.
20
- */
21
- var Slot = class Slot {
22
- start = document.createComment("{");
23
- end = document.createComment("}");
24
- #pending;
25
- /**
26
- * Render the slot as a DocumentFragment.
27
- * If not yet mounted, inserts the comment markers and optional default content.
28
- * If already mounted, extracts and returns the current content WITHOUT disposing
29
- * it — the caller takes ownership of the returned nodes and is responsible for
30
- * their disposal.
31
- */
32
- slot(defaultContent) {
33
- const fragment = document.createDocumentFragment();
34
- if (this.isMounted()) {
35
- const range = document.createRange();
36
- range.setStartAfter(this.start);
37
- range.setEndBefore(this.end);
38
- fragment.appendChild(range.extractContents());
39
- return fragment;
40
- }
41
- fragment.appendChild(this.start);
42
- fragment.appendChild(this.end);
43
- const initialContent = this.#pending ?? resolveNode(defaultContent);
44
- if (initialContent) fragment.insertBefore(initialContent, this.end);
45
- this.#pending = void 0;
46
- return fragment;
47
- }
48
- /** Dispose reactive children and remove all content between the markers. */
49
- clear() {
50
- let node = this.start.nextSibling;
51
- while (node && node !== this.end) {
52
- const next = node.nextSibling;
53
- if (node instanceof Element) node[Symbol.dispose]?.();
54
- node = next;
55
- }
56
- const range = document.createRange();
57
- range.setStartAfter(this.start);
58
- range.setEndBefore(this.end);
59
- range.deleteContents();
60
- }
61
- /**
62
- * Replace the slot's content with the given element.
63
- * No-op if the slot is not mounted or the content is identical.
64
- */
65
- set(element) {
66
- const parent = this.parent();
67
- if (!parent) {
68
- this.#pending = element;
69
- return;
70
- }
71
- if (this.isSame(element)) return;
72
- this.clear();
73
- parent.insertBefore(element, this.end);
74
- this.#pending = void 0;
75
- }
76
- /**
77
- * Extract and return the current slot content as a DocumentFragment.
78
- * Returns `null` if the slot is not mounted.
79
- * Content is NOT disposed — the caller takes ownership and is responsible
80
- * for disposal.
81
- */
82
- get() {
83
- if (!this.isMounted()) return null;
84
- const range = document.createRange();
85
- range.setStartAfter(this.start);
86
- range.setEndBefore(this.end);
87
- return range.extractContents();
88
- }
89
- /** Returns the parent node if the slot is mounted, otherwise `null`. */
90
- parent() {
91
- return this.isMounted() ? this.start.parentNode : null;
92
- }
93
- /** Whether the slot's comment markers are attached to the DOM. */
94
- isMounted() {
95
- return this.start.parentNode === this.end.parentNode && !!this.start.parentNode;
96
- }
97
- isSame(element) {
98
- return this.start.nextSibling === element && this.end === element.nextSibling;
99
- }
100
- /**
101
- * Create a callable slot instance.
102
- *
103
- * The returned value is both a function and an object:
104
- * - Call it to render the slot with optional default content.
105
- * - Access `.set()`, `.parent()`, `.isMounted()` for slot management.
106
- *
107
- * @example
108
- * ```ts
109
- * const slot = createSlot();
110
- * el.append(slot("default text")); // mount with default
111
- * slot.set(newElement); // replace content
112
- * ```
113
- */
114
- static new() {
115
- const instance = new Slot();
116
- return new Proxy(instance.slot.bind(instance), {
117
- apply(target, _thisArg, argArray) {
118
- return target(...argArray);
119
- },
120
- get(_target, prop) {
121
- const value = instance[prop];
122
- return typeof value === "function" ? value.bind(instance) : value;
123
- },
124
- getPrototypeOf() {
125
- return Slot.prototype;
126
- }
127
- });
128
- }
129
- };
130
- /**
131
- * Symbol key for attaching a `Slots` instance to a custom element instance.
132
- * This prevent collisions with Element properties and are not meant to be treated as JSX children.
133
- */
134
- const SLOTS = Symbol("slots");
135
- const $map = Symbol("map");
136
- const $keys = Symbol("keys");
137
- const $has = Symbol("has");
138
- /**
139
- * A keyed collection of slot instances.
140
- * Slots are pre-created from the provided keys and lazily created on first access for unknown keys.
141
- */
142
- var Slots = class Slots {
143
- [$map] = /* @__PURE__ */ new Map();
144
- constructor(keys = []) {
145
- for (const key of keys) this[$map].set(key, Slot.new());
146
- }
147
- [Symbol.iterator]() {
148
- return this[$map][Symbol.iterator]();
149
- }
150
- [Symbol.toStringTag]() {
151
- return "Slots";
152
- }
153
- [Symbol.hasInstance](instance) {
154
- return instance instanceof Slots;
155
- }
156
- [$has](key) {
157
- return this[$map].has(key);
158
- }
159
- /** Check whether a slot with the given key exists. */
160
- static has(slots, key) {
161
- return slots[$has](key);
162
- }
163
- [$keys]() {
164
- return this[$map].keys();
165
- }
166
- /** Iterate over all registered slot keys. */
167
- static keys(slots) {
168
- return slots[$keys]();
169
- }
170
- /**
171
- * Create a typed `Slots` collection from a list of key names.
172
- *
173
- * Pass the keys with `as const` so TS narrows them to a literal union —
174
- * this is what lets `ElementProps<typeof Cls>` synthesize `slot:${K}`
175
- * entries. Without `as const`, the array type widens to `string[]` and
176
- * the slot keys are lost.
177
- *
178
- * @example
179
- * ```ts
180
- * class Card extends HTMLElement {
181
- * // ✅ literal keys flow through — "header" | "footer"
182
- * [SLOTS] = Slots.new(["header", "footer"] as const);
183
- * }
184
- *
185
- * // ❌ widens to string; no typed slot:* props
186
- * // [SLOTS] = Slots.new(["header", "footer"]);
187
- * ```
188
- */
189
- static new(keys) {
190
- const instance = new Slots(keys);
191
- return new Proxy(instance, { get(target, prop, receiver) {
192
- if (typeof prop === "string" && target[$map].has(prop)) return target[$map].get(prop);
193
- return Reflect.get(target, prop, receiver);
194
- } });
195
- }
196
- };
197
- //#endregion
198
- export { resolveNode as i, Slot as n, Slots as r, SLOTS as t };
@@ -1,121 +0,0 @@
1
- //#region src/lib.d.ts
2
- type PrimitiveNodeType = Node | string | boolean | number | bigint | symbol | Date | RegExp | null | undefined;
3
- //#endregion
4
- //#region src/polyfill.d.ts
5
- declare global {
6
- interface SymbolConstructor {
7
- readonly dispose: symbol;
8
- }
9
- interface Disposable {
10
- [Symbol.dispose](): void;
11
- }
12
- }
13
- //#endregion
14
- //#region src/slot.d.ts
15
- /**
16
- * A lightweight slot that reserves a region in the DOM using comment markers.
17
- * Content between the markers can be replaced dynamically without wrapper elements.
18
- */
19
- declare class Slot {
20
- #private;
21
- private readonly start;
22
- private readonly end;
23
- /**
24
- * Render the slot as a DocumentFragment.
25
- * If not yet mounted, inserts the comment markers and optional default content.
26
- * If already mounted, extracts and returns the current content WITHOUT disposing
27
- * it — the caller takes ownership of the returned nodes and is responsible for
28
- * their disposal.
29
- */
30
- slot(defaultContent?: PrimitiveNodeType): DocumentFragment;
31
- /** Dispose reactive children and remove all content between the markers. */
32
- clear(): void;
33
- /**
34
- * Replace the slot's content with the given element.
35
- * No-op if the slot is not mounted or the content is identical.
36
- */
37
- set(element: Node): void;
38
- /**
39
- * Extract and return the current slot content as a DocumentFragment.
40
- * Returns `null` if the slot is not mounted.
41
- * Content is NOT disposed — the caller takes ownership and is responsible
42
- * for disposal.
43
- */
44
- get(): DocumentFragment | null;
45
- /** Returns the parent node if the slot is mounted, otherwise `null`. */
46
- parent(): ParentNode | null;
47
- /** Whether the slot's comment markers are attached to the DOM. */
48
- isMounted(): boolean;
49
- private isSame;
50
- /**
51
- * Create a callable slot instance.
52
- *
53
- * The returned value is both a function and an object:
54
- * - Call it to render the slot with optional default content.
55
- * - Access `.set()`, `.parent()`, `.isMounted()` for slot management.
56
- *
57
- * @example
58
- * ```ts
59
- * const slot = createSlot();
60
- * el.append(slot("default text")); // mount with default
61
- * slot.set(newElement); // replace content
62
- * ```
63
- */
64
- static new(): Slot & ((defaultContent?: PrimitiveNodeType) => DocumentFragment);
65
- }
66
- /**
67
- * A callable slot returned by {@link Slot.new}.
68
- *
69
- * - Invoke it (`slot()`) to render the slot region as a `DocumentFragment`,
70
- * optionally with default content on first mount.
71
- * - Call `.set()` to replace current content, `.clear()` to empty it, and
72
- * `.isMounted()` / `.parent()` to inspect mount state.
73
- */
74
- type SlotInstance = ReturnType<typeof Slot.new>;
75
- /**
76
- * Symbol key for attaching a `Slots` instance to a custom element instance.
77
- * This prevent collisions with Element properties and are not meant to be treated as JSX children.
78
- */
79
- declare const SLOTS: unique symbol;
80
- declare const $map: unique symbol;
81
- declare const $keys: unique symbol;
82
- declare const $has: unique symbol;
83
- /**
84
- * A keyed collection of slot instances.
85
- * Slots are pre-created from the provided keys and lazily created on first access for unknown keys.
86
- */
87
- declare class Slots<K extends string> implements Iterable<[K, SlotInstance]> {
88
- readonly [$map]: Map<K, Slot & ((defaultContent?: PrimitiveNodeType) => DocumentFragment)>;
89
- private constructor();
90
- [Symbol.iterator](): MapIterator<[K, Slot & ((defaultContent?: PrimitiveNodeType) => DocumentFragment)]>;
91
- [Symbol.toStringTag](): string;
92
- [Symbol.hasInstance](instance: unknown): instance is Slots<any>;
93
- [$has](key: K): boolean;
94
- /** Check whether a slot with the given key exists. */
95
- static has<K extends string>(slots: Slots<K>, key: K): boolean;
96
- [$keys](): MapIterator<K>;
97
- /** Iterate over all registered slot keys. */
98
- static keys<K extends string>(slots: Slots<K>): MapIterator<K>;
99
- /**
100
- * Create a typed `Slots` collection from a list of key names.
101
- *
102
- * Pass the keys with `as const` so TS narrows them to a literal union —
103
- * this is what lets `ElementProps<typeof Cls>` synthesize `slot:${K}`
104
- * entries. Without `as const`, the array type widens to `string[]` and
105
- * the slot keys are lost.
106
- *
107
- * @example
108
- * ```ts
109
- * class Card extends HTMLElement {
110
- * // ✅ literal keys flow through — "header" | "footer"
111
- * [SLOTS] = Slots.new(["header", "footer"] as const);
112
- * }
113
- *
114
- * // ❌ widens to string; no typed slot:* props
115
- * // [SLOTS] = Slots.new(["header", "footer"]);
116
- * ```
117
- */
118
- static new<K extends string>(keys: K[]): Slots<K> & { readonly [P in K]: SlotInstance };
119
- }
120
- //#endregion
121
- export { PrimitiveNodeType as a, Slots as i, Slot as n, SlotInstance as r, SLOTS as t };