elements-kit 0.0.18 → 0.0.20

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 (110) hide show
  1. package/README.md +65 -118
  2. package/dist/{attributes-Dtn68R1u.d.mts → attributes-DILeh3-s.d.mts} +42 -9
  3. package/dist/attributes.d.mts +1 -1
  4. package/dist/attributes.mjs +32 -0
  5. package/dist/{define-CjbTZ3VG.d.mts → custom-elements-D5_NMNyD.d.mts} +20 -2
  6. package/dist/custom-elements.d.mts +2 -74
  7. package/dist/custom-elements.mjs +15 -86
  8. package/dist/{element-CGVy_8TW.mjs → element-w1GCIMVp.mjs} +33 -21
  9. package/dist/for.d.mts +31 -2
  10. package/dist/for.mjs +18 -2
  11. package/dist/infer-DuFY-y2b.d.mts +657 -0
  12. package/dist/integrations/react.d.mts +1 -1
  13. package/dist/integrations/react.mjs +6 -4
  14. package/dist/jsx-runtime/index.d.mts +2 -73
  15. package/dist/jsx-runtime/index.mjs +8 -14
  16. package/dist/{signals-J8dK_rA4.mjs → lib-D6duEs38.mjs} +1 -105
  17. package/dist/render.d.mts +21 -0
  18. package/dist/render.mjs +32 -0
  19. package/dist/scope-DM2gzOkb.mjs +45 -0
  20. package/dist/signals/index.d.mts +1 -1
  21. package/dist/signals/index.mjs +134 -1
  22. package/dist/{slot-Kb61AcgW.mjs → slot-CKtUoy2X.mjs} +0 -1
  23. package/dist/{slot-C7GQZe-r.d.mts → slot-D5iBUSAm.d.mts} +18 -1
  24. package/dist/slot.d.mts +1 -1
  25. package/dist/slot.mjs +1 -1
  26. package/dist/{test.BmQO5GaM-DfGStnii.mjs → test.BmQO5GaM-BeO5pvCo.mjs} +1 -1
  27. package/dist/utilities/_observe.mjs +2 -1
  28. package/dist/utilities/active-element.d.mts +1 -1
  29. package/dist/utilities/active-element.mjs +2 -1
  30. package/dist/utilities/active-element.test.mjs +1 -1
  31. package/dist/utilities/async.d.mts +39 -1
  32. package/dist/utilities/async.mjs +39 -1
  33. package/dist/utilities/async.test.mjs +3 -2
  34. package/dist/utilities/debounced.d.mts +12 -1
  35. package/dist/utilities/debounced.mjs +13 -1
  36. package/dist/utilities/debounced.test.mjs +3 -2
  37. package/dist/utilities/element-rect.d.mts +1 -1
  38. package/dist/utilities/element-rect.mjs +2 -1
  39. package/dist/utilities/element-rect.test.mjs +3 -2
  40. package/dist/utilities/element-scroll.d.mts +1 -1
  41. package/dist/utilities/element-scroll.test.mjs +3 -2
  42. package/dist/utilities/environment.d.mts +2 -0
  43. package/dist/utilities/environment.mjs +2 -0
  44. package/dist/utilities/event-driven.d.mts +1 -1
  45. package/dist/utilities/event-driven.mjs +2 -1
  46. package/dist/utilities/event-listener.d.mts +12 -1
  47. package/dist/utilities/event-listener.mjs +2 -1
  48. package/dist/utilities/event-listener.test.mjs +3 -2
  49. package/dist/utilities/focus-within.d.mts +1 -1
  50. package/dist/utilities/focus-within.mjs +2 -1
  51. package/dist/utilities/focus-within.test.mjs +3 -2
  52. package/dist/utilities/hover.d.mts +1 -1
  53. package/dist/utilities/hover.mjs +2 -1
  54. package/dist/utilities/hover.test.mjs +3 -2
  55. package/dist/utilities/intersection-observer.test.mjs +3 -2
  56. package/dist/utilities/interval.d.mts +14 -1
  57. package/dist/utilities/interval.mjs +2 -1
  58. package/dist/utilities/interval.test.mjs +3 -2
  59. package/dist/utilities/location.d.mts +1 -1
  60. package/dist/utilities/location.mjs +2 -1
  61. package/dist/utilities/location.test.mjs +1 -1
  62. package/dist/utilities/long-press.test.mjs +3 -2
  63. package/dist/utilities/media-devices.d.mts +1 -1
  64. package/dist/utilities/media-devices.mjs +2 -1
  65. package/dist/utilities/media-devices.test.mjs +3 -2
  66. package/dist/utilities/media-player.d.mts +1 -1
  67. package/dist/utilities/media-player.test.mjs +3 -2
  68. package/dist/utilities/media-query.d.mts +1 -1
  69. package/dist/utilities/media-query.mjs +2 -1
  70. package/dist/utilities/mutation-observer.test.mjs +3 -2
  71. package/dist/utilities/network.d.mts +1 -1
  72. package/dist/utilities/network.mjs +2 -1
  73. package/dist/utilities/network.test.mjs +1 -1
  74. package/dist/utilities/on-click-outside.test.mjs +3 -2
  75. package/dist/utilities/orientation.d.mts +1 -1
  76. package/dist/utilities/orientation.mjs +2 -1
  77. package/dist/utilities/previous.d.mts +13 -1
  78. package/dist/utilities/previous.mjs +14 -1
  79. package/dist/utilities/previous.test.mjs +3 -2
  80. package/dist/utilities/promise.d.mts +7 -1
  81. package/dist/utilities/promise.mjs +2 -1
  82. package/dist/utilities/promise.test.mjs +3 -2
  83. package/dist/utilities/retry.d.mts +15 -0
  84. package/dist/utilities/retry.mjs +17 -1
  85. package/dist/utilities/retry.test.mjs +3 -2
  86. package/dist/utilities/routing.d.mts +12 -1
  87. package/dist/utilities/routing.mjs +13 -1
  88. package/dist/utilities/routing.test.mjs +1 -1
  89. package/dist/utilities/search-params.d.mts +1 -1
  90. package/dist/utilities/search-params.test.mjs +3 -2
  91. package/dist/utilities/ssr.test.mjs +1 -1
  92. package/dist/utilities/storage.d.mts +18 -1
  93. package/dist/utilities/storage.mjs +17 -0
  94. package/dist/utilities/storage.test.mjs +3 -2
  95. package/dist/utilities/throttled.d.mts +12 -1
  96. package/dist/utilities/throttled.mjs +13 -1
  97. package/dist/utilities/throttled.test.mjs +3 -2
  98. package/dist/utilities/timeout.d.mts +1 -1
  99. package/dist/utilities/timeout.mjs +2 -1
  100. package/dist/utilities/timeout.test.mjs +3 -2
  101. package/dist/utilities/window-focus.d.mts +1 -1
  102. package/dist/utilities/window-focus.mjs +2 -1
  103. package/dist/utilities/window-size.d.mts +1 -1
  104. package/dist/utilities/window-size.mjs +2 -1
  105. package/dist/utilities/window-size.test.mjs +1 -1
  106. package/package.json +1 -1
  107. package/dist/index-DydGTqZU.d.mts +0 -315
  108. package/dist/infer-BfzRJoCn.d.mts +0 -203
  109. package/dist/polyfill-BVNd6ogU.d.mts +0 -9
  110. /package/dist/{magic-string.es-i62WTP6J.mjs → magic-string.es-cTgJnTCj.mjs} +0 -0
@@ -4,6 +4,21 @@ type RetryDelay = number | ((attempt: number) => number);
4
4
  * Wraps `fn` to retry up to `attempts` times on failure.
5
5
  * Delay (if provided) is inserted between failures only — not after the last.
6
6
  * Each attempt runs in an effect scope so `onCleanup` inside `fn` fires before each retry.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { retry } from "elements-kit/utilities/retry";
11
+ *
12
+ * // Constant 500ms delay between retries
13
+ * const load = retry(() => fetch("/api").then(r => r.json()), 3, 500);
14
+ *
15
+ * // Exponential backoff
16
+ * const loadBackoff = retry(
17
+ * () => fetch("/api").then(r => r.json()),
18
+ * 5,
19
+ * (attempt) => 2 ** attempt * 100,
20
+ * );
21
+ * ```
7
22
  */
8
23
  declare function retry<T>(fn: () => Promise<T>, attempts: number, delay?: RetryDelay): () => Promise<T>;
9
24
  //#endregion
@@ -1,9 +1,25 @@
1
- import { b as untracked, d as effect } from "../signals-J8dK_rA4.mjs";
1
+ import { g as untracked, s as effect } from "../lib-D6duEs38.mjs";
2
+ import "../signals/index.mjs";
2
3
  //#region src/utilities/retry.ts
3
4
  /**
4
5
  * Wraps `fn` to retry up to `attempts` times on failure.
5
6
  * Delay (if provided) is inserted between failures only — not after the last.
6
7
  * Each attempt runs in an effect scope so `onCleanup` inside `fn` fires before each retry.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { retry } from "elements-kit/utilities/retry";
12
+ *
13
+ * // Constant 500ms delay between retries
14
+ * const load = retry(() => fetch("/api").then(r => r.json()), 3, 500);
15
+ *
16
+ * // Exponential backoff
17
+ * const loadBackoff = retry(
18
+ * () => fetch("/api").then(r => r.json()),
19
+ * 5,
20
+ * (attempt) => 2 ** attempt * 100,
21
+ * );
22
+ * ```
7
23
  */
8
24
  function retry(fn, attempts, delay) {
9
25
  return async () => {
@@ -1,5 +1,6 @@
1
- import { _ as onCleanup } from "../signals-J8dK_rA4.mjs";
2
- import { n as vi, o as describe, s as it, t as globalExpect } from "../test.BmQO5GaM-DfGStnii.mjs";
1
+ import { p as onCleanup } from "../lib-D6duEs38.mjs";
2
+ import "../signals/index.mjs";
3
+ import { n as vi, o as describe, s as it, t as globalExpect } from "../test.BmQO5GaM-BeO5pvCo.mjs";
3
4
  import { retry } from "./retry.mjs";
4
5
  //#region src/utilities/retry.test.ts
5
6
  describe("retry", () => {
@@ -1,6 +1,17 @@
1
- import { t as Computed } from "../index-DydGTqZU.mjs";
1
+ import { y as Computed } from "../infer-DuFY-y2b.mjs";
2
2
 
3
3
  //#region src/utilities/routing.d.ts
4
+ /**
5
+ * Monkey-patches `history.pushState` / `history.replaceState` to dispatch
6
+ * `pushstate` and `replacestate` events on `window`.
7
+ *
8
+ * Needed because the platform only fires `popstate` on back/forward
9
+ * navigation — `currentLocation` and anything else that reacts to
10
+ * programmatic navigation needs these synthetic events.
11
+ *
12
+ * Call once at app boot (or before any router-driven navigation). Safe to
13
+ * call outside a browser — it no-ops.
14
+ */
4
15
  declare function patchHistory(): void;
5
16
  type NavigateOptions = {
6
17
  replace?: boolean;
@@ -1,4 +1,5 @@
1
- import { u as computed } from "../signals-J8dK_rA4.mjs";
1
+ import { o as computed } from "../lib-D6duEs38.mjs";
2
+ import "../signals/index.mjs";
2
3
  import { currentLocation } from "./location.mjs";
3
4
  //#region src/utilities/routing.ts
4
5
  const patchHistoryMethod = (method) => {
@@ -15,6 +16,17 @@ const patchHistoryMethod = (method) => {
15
16
  return result;
16
17
  };
17
18
  };
19
+ /**
20
+ * Monkey-patches `history.pushState` / `history.replaceState` to dispatch
21
+ * `pushstate` and `replacestate` events on `window`.
22
+ *
23
+ * Needed because the platform only fires `popstate` on back/forward
24
+ * navigation — `currentLocation` and anything else that reacts to
25
+ * programmatic navigation needs these synthetic events.
26
+ *
27
+ * Call once at app boot (or before any router-driven navigation). Safe to
28
+ * call outside a browser — it no-ops.
29
+ */
18
30
  function patchHistory() {
19
31
  if (typeof window !== "undefined" && typeof history !== "undefined") {
20
32
  patchHistoryMethod("pushState");
@@ -1,4 +1,4 @@
1
- import { i as beforeAll, n as vi, o as describe, r as afterEach, s as it, t as globalExpect } from "../test.BmQO5GaM-DfGStnii.mjs";
1
+ import { i as beforeAll, n as vi, o as describe, r as afterEach, s as it, t as globalExpect } from "../test.BmQO5GaM-BeO5pvCo.mjs";
2
2
  import { isLocalNavigationEvent, match, matches, navigate, patchHistory } from "./routing.mjs";
3
3
  //#region src/utilities/routing.test.ts
4
4
  beforeAll(() => {
@@ -1,4 +1,4 @@
1
- import { t as Computed } from "../index-DydGTqZU.mjs";
1
+ import { y as Computed } from "../infer-DuFY-y2b.mjs";
2
2
 
3
3
  //#region src/utilities/search-params.d.ts
4
4
  /**
@@ -1,5 +1,6 @@
1
- import { f as effectScope } from "../signals-J8dK_rA4.mjs";
2
- import { o as describe, r as afterEach, s as it, t as globalExpect } from "../test.BmQO5GaM-DfGStnii.mjs";
1
+ import { c as effectScope } from "../lib-D6duEs38.mjs";
2
+ import "../signals/index.mjs";
3
+ import { o as describe, r as afterEach, s as it, t as globalExpect } from "../test.BmQO5GaM-BeO5pvCo.mjs";
3
4
  import { createSearchParam } from "./search-params.mjs";
4
5
  //#region src/utilities/search-params.test.ts
5
6
  afterEach(() => {
@@ -1,4 +1,4 @@
1
- import { c as test, t as globalExpect } from "../test.BmQO5GaM-DfGStnii.mjs";
1
+ import { c as test, t as globalExpect } from "../test.BmQO5GaM-BeO5pvCo.mjs";
2
2
  //#region src/utilities/ssr.test.ts
3
3
  // @vitest-environment node
4
4
  test.each([
@@ -1,4 +1,4 @@
1
- import { r as Signal } from "../index-DydGTqZU.mjs";
1
+ import { x as Signal } from "../infer-DuFY-y2b.mjs";
2
2
 
3
3
  //#region src/utilities/storage.d.ts
4
4
  type StorageOptions<T> = {
@@ -10,12 +10,29 @@ type StorageOptions<T> = {
10
10
  *
11
11
  * Changes made in other tabs/windows are synchronised automatically via
12
12
  * the `StorageEvent`.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * import { createLocalStorage } from "elements-kit/utilities/storage";
17
+ *
18
+ * const theme = createLocalStorage<"light" | "dark">("theme", "light");
19
+ * theme(); // read current
20
+ * theme("dark"); // write — persists and notifies
21
+ * ```
13
22
  */
14
23
  declare function createLocalStorage<T>(key: string, initialValue: T, options?: StorageOptions<T>): Signal<T>;
15
24
  /**
16
25
  * Returns a `Signal` persisted to `sessionStorage`.
17
26
  *
18
27
  * Session storage is scoped to the current tab — no cross-tab sync.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * import { createSessionStorage } from "elements-kit/utilities/storage";
32
+ *
33
+ * const draft = createSessionStorage("draft", { title: "", body: "" });
34
+ * draft({ title: "hi", body: "…" });
35
+ * ```
19
36
  */
20
37
  declare function createSessionStorage<T>(key: string, initialValue: T, options?: StorageOptions<T>): Signal<T>;
21
38
  //#endregion
@@ -12,6 +12,15 @@ function readOrDefault(storage, key, initialValue, deserialise) {
12
12
  *
13
13
  * Changes made in other tabs/windows are synchronised automatically via
14
14
  * the `StorageEvent`.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import { createLocalStorage } from "elements-kit/utilities/storage";
19
+ *
20
+ * const theme = createLocalStorage<"light" | "dark">("theme", "light");
21
+ * theme(); // read current
22
+ * theme("dark"); // write — persists and notifies
23
+ * ```
15
24
  */
16
25
  function createLocalStorage(key, initialValue, options) {
17
26
  const serialise = options?.serialise ?? ((v) => JSON.stringify(v));
@@ -41,6 +50,14 @@ function createLocalStorage(key, initialValue, options) {
41
50
  * Returns a `Signal` persisted to `sessionStorage`.
42
51
  *
43
52
  * Session storage is scoped to the current tab — no cross-tab sync.
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * import { createSessionStorage } from "elements-kit/utilities/storage";
57
+ *
58
+ * const draft = createSessionStorage("draft", { title: "", body: "" });
59
+ * draft({ title: "hi", body: "…" });
60
+ * ```
44
61
  */
45
62
  function createSessionStorage(key, initialValue, options) {
46
63
  const serialise = options?.serialise ?? ((v) => JSON.stringify(v));
@@ -1,5 +1,6 @@
1
- import { f as effectScope } from "../signals-J8dK_rA4.mjs";
2
- import { o as describe, r as afterEach, s as it, t as globalExpect } from "../test.BmQO5GaM-DfGStnii.mjs";
1
+ import { c as effectScope } from "../lib-D6duEs38.mjs";
2
+ import "../signals/index.mjs";
3
+ import { o as describe, r as afterEach, s as it, t as globalExpect } from "../test.BmQO5GaM-BeO5pvCo.mjs";
3
4
  import { createLocalStorage, createSessionStorage } from "./storage.mjs";
4
5
  //#region src/utilities/storage.test.ts
5
6
  describe("createLocalStorage", () => {
@@ -1,4 +1,4 @@
1
- import { t as Computed } from "../index-DydGTqZU.mjs";
1
+ import { y as Computed } from "../infer-DuFY-y2b.mjs";
2
2
 
3
3
  //#region src/utilities/throttled.d.ts
4
4
  /**
@@ -7,6 +7,17 @@ import { t as Computed } from "../index-DydGTqZU.mjs";
7
7
  * value is never lost.
8
8
  *
9
9
  * The initial value is read synchronously.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { signal } from "elements-kit/signals";
14
+ * import { createThrottled } from "elements-kit/utilities/throttled";
15
+ *
16
+ * const scrollY = signal(0);
17
+ * const sampled = createThrottled(scrollY, 100);
18
+ *
19
+ * effect(() => analytics.record(sampled()));
20
+ * ```
10
21
  */
11
22
  declare function createThrottled<T>(getter: () => T, interval: number): Computed<T>;
12
23
  //#endregion
@@ -1,4 +1,5 @@
1
- import { d as effect, v as signal } from "../signals-J8dK_rA4.mjs";
1
+ import { m as signal, s as effect } from "../lib-D6duEs38.mjs";
2
+ import "../signals/index.mjs";
2
3
  import { createTimeout } from "./timeout.mjs";
3
4
  //#region src/utilities/throttled.ts
4
5
  /**
@@ -7,6 +8,17 @@ import { createTimeout } from "./timeout.mjs";
7
8
  * value is never lost.
8
9
  *
9
10
  * The initial value is read synchronously.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import { signal } from "elements-kit/signals";
15
+ * import { createThrottled } from "elements-kit/utilities/throttled";
16
+ *
17
+ * const scrollY = signal(0);
18
+ * const sampled = createThrottled(scrollY, 100);
19
+ *
20
+ * effect(() => analytics.record(sampled()));
21
+ * ```
10
22
  */
11
23
  function createThrottled(getter, interval) {
12
24
  const s = signal(getter());
@@ -1,5 +1,6 @@
1
- import { f as effectScope, v as signal } from "../signals-J8dK_rA4.mjs";
2
- import { a as beforeEach, n as vi, o as describe, r as afterEach, s as it, t as globalExpect } from "../test.BmQO5GaM-DfGStnii.mjs";
1
+ import { c as effectScope, m as signal } from "../lib-D6duEs38.mjs";
2
+ import "../signals/index.mjs";
3
+ import { a as beforeEach, n as vi, o as describe, r as afterEach, s as it, t as globalExpect } from "../test.BmQO5GaM-BeO5pvCo.mjs";
3
4
  import { createThrottled } from "./throttled.mjs";
4
5
  //#region src/utilities/throttled.test.ts
5
6
  beforeEach(() => {
@@ -1,4 +1,4 @@
1
- import { t as Computed } from "../index-DydGTqZU.mjs";
1
+ import { y as Computed } from "../infer-DuFY-y2b.mjs";
2
2
 
3
3
  //#region src/utilities/timeout.d.ts
4
4
  type TimeoutResult = {
@@ -1,4 +1,5 @@
1
- import { _ as onCleanup, v as signal } from "../signals-J8dK_rA4.mjs";
1
+ import { m as signal, p as onCleanup } from "../lib-D6duEs38.mjs";
2
+ import "../signals/index.mjs";
2
3
  //#region src/utilities/timeout.ts
3
4
  /**
4
5
  * Reactive `setTimeout` wrapper with pause/resume/reset control.
@@ -1,5 +1,6 @@
1
- import { f as effectScope } from "../signals-J8dK_rA4.mjs";
2
- import { n as vi, o as describe, r as afterEach, s as it, t as globalExpect } from "../test.BmQO5GaM-DfGStnii.mjs";
1
+ import { c as effectScope } from "../lib-D6duEs38.mjs";
2
+ import "../signals/index.mjs";
3
+ import { n as vi, o as describe, r as afterEach, s as it, t as globalExpect } from "../test.BmQO5GaM-BeO5pvCo.mjs";
3
4
  import { createTimeout } from "./timeout.mjs";
4
5
  //#region src/utilities/timeout.test.ts
5
6
  afterEach(() => {
@@ -1,4 +1,4 @@
1
- import { t as Computed } from "../index-DydGTqZU.mjs";
1
+ import { y as Computed } from "../infer-DuFY-y2b.mjs";
2
2
 
3
3
  //#region src/utilities/window-focus.d.ts
4
4
  /**
@@ -1,4 +1,5 @@
1
- import { v as signal } from "../signals-J8dK_rA4.mjs";
1
+ import { m as signal } from "../lib-D6duEs38.mjs";
2
+ import "../signals/index.mjs";
2
3
  import { on } from "./event-listener.mjs";
3
4
  import { isBrowser } from "./environment.mjs";
4
5
  //#region src/utilities/window-focus.ts
@@ -1,4 +1,4 @@
1
- import { t as Computed } from "../index-DydGTqZU.mjs";
1
+ import { y as Computed } from "../infer-DuFY-y2b.mjs";
2
2
 
3
3
  //#region src/utilities/window-size.d.ts
4
4
  type WindowSizeResult = {
@@ -1,4 +1,5 @@
1
- import { u as computed } from "../signals-J8dK_rA4.mjs";
1
+ import { o as computed } from "../lib-D6duEs38.mjs";
2
+ import "../signals/index.mjs";
2
3
  import { fromEvent, sync } from "./event-driven.mjs";
3
4
  import { isBrowser } from "./environment.mjs";
4
5
  //#region src/utilities/window-size.ts
@@ -1,4 +1,4 @@
1
- import { o as describe, s as it, t as globalExpect } from "../test.BmQO5GaM-DfGStnii.mjs";
1
+ import { o as describe, s as it, t as globalExpect } from "../test.BmQO5GaM-BeO5pvCo.mjs";
2
2
  import { windowSize } from "./window-size.mjs";
3
3
  //#region src/utilities/window-size.test.ts
4
4
  describe("windowSize (singleton)", () => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "elements-kit",
3
3
  "type": "module",
4
- "version": "0.0.18",
4
+ "version": "0.0.20",
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,315 +0,0 @@
1
- //#region src/signals/lib.d.ts
2
- declare const SIGNAL: unique symbol;
3
- declare const COMPUTED: unique symbol;
4
- declare const EFFECT: unique symbol;
5
- declare const EFFECT_SCOPE: unique symbol;
6
- /**
7
- * Returns `true` if `fn` is a signal handle created by {@link signal}.
8
- *
9
- * Relies on the SIGNAL symbol.
10
- */
11
- declare function isSignal(fn: unknown): boolean;
12
- /**
13
- * Returns `true` if `fn` is a computed handle created by {@link computed}.
14
- *
15
- * Relies on the COMPUTED symbol.
16
- */
17
- declare function isComputed(fn: unknown): boolean;
18
- /**
19
- * Returns `true` if `fn` is an effect cleanup handle created by {@link effect}.
20
- *
21
- * Relies on the EFFECT symbol.
22
- */
23
- declare function isEffect(fn: unknown): boolean;
24
- /**
25
- * Returns `true` if `fn` is an effectScope cleanup handle created by
26
- * {@link effectScope}.
27
- *
28
- * Relies on `Function.name` matching the internal `effectScopeOper` function name.
29
- */
30
- declare function isEffectScope(fn: () => void): boolean;
31
- /**
32
- * Creates a mutable reactive signal.
33
- *
34
- * - **Read**: call with no arguments → returns the current value and
35
- * subscribes the active tracking context.
36
- * - **Write**: call with a value → updates the signal and schedules
37
- * downstream effects if the value changed.
38
- *
39
- * @example
40
- * ```ts
41
- * const count = signal(0);
42
- * count(); // → 0 (read)
43
- * count(1); // write – effects depending on count will re-run
44
- * count(); // → 1
45
- * ```
46
- */
47
- declare function signal<T>(): Updater<T> & Computed<T>;
48
- declare function signal<T>(initialValue: T): Updater<T> & Computed<T>;
49
- /**
50
- * Creates a lazily-evaluated computed value.
51
- *
52
- * The `getter` is only called when the computed value is read **and** one of
53
- * its dependencies has changed since the last evaluation. If nothing has
54
- * changed the cached `value` is returned without re-running `getter`.
55
- *
56
- * Computed values are read-only; they cannot be set directly.
57
- *
58
- * @param getter - Pure function deriving a value from other reactive sources.
59
- * Receives the previous value as an optional optimisation hint.
60
- *
61
- * @example
62
- * ```ts
63
- * const a = signal(1);
64
- * const b = signal(2);
65
- * const sum = computed(() => a() + b());
66
- *
67
- * sum(); // → 3
68
- * a(10);
69
- * sum(); // → 12 (re-evaluated lazily)
70
- * ```
71
- */
72
- declare function computed<T>(getter: (previousValue?: T) => T): () => T;
73
- /**
74
- * Creates a reactive side-effect that runs immediately and re-runs whenever
75
- * any signal or computed it read during its last execution changes.
76
- *
77
- * Use {@link onCleanup} inside `fn` to register teardown logic that runs
78
- * before each re-execution and on final disposal.
79
- *
80
- * If `effect` is called inside an `effectScope` or another `effect`, the
81
- * new effect is automatically owned by the outer scope and will be disposed
82
- * when the scope is disposed.
83
- *
84
- * @param fn - The side-effect body. Reactive reads inside this function
85
- * establish dependency links.
86
- * @returns A disposal function. Call it to stop the effect and run any
87
- * registered cleanup.
88
- *
89
- * @example
90
- * ```ts
91
- * const url = signal('/api/data');
92
- *
93
- * const stop = effect(() => {
94
- * const controller = new AbortController();
95
- * fetch(url(), { signal: controller.signal });
96
- * onCleanup(() => controller.abort());
97
- * });
98
- *
99
- * url('/api/other'); // previous fetch is aborted, new one starts
100
- * stop(); // final cleanup: abort the last fetch
101
- * ```
102
- */
103
- declare function effect(fn: () => void): () => void;
104
- /**
105
- * Creates an ownership scope that groups reactive effects so they can all be
106
- * disposed at once.
107
- *
108
- * Effects and nested scopes created inside `fn` are linked to this scope.
109
- * When the returned disposal function is called, all owned effects are stopped
110
- * in cascade – triggering their registered {@link onCleanup} callbacks – and
111
- * the scope itself is removed from any parent scope that owns it.
112
- *
113
- * @param fn - Synchronous setup function. Create effects and nested scopes
114
- * here.
115
- * @returns A disposal function that tears down all owned effects and the scope
116
- * itself.
117
- *
118
- * @example
119
- * ```ts
120
- * const stopAll = effectScope(() => {
121
- * effect(() => console.log('a:', a()));
122
- * effect(() => console.log('b:', b()));
123
- * });
124
- *
125
- * stopAll(); // both effects stopped simultaneously
126
- * ```
127
- */
128
- declare function effectScope(fn: () => void): () => void;
129
- /**
130
- * Registers a cleanup callback for the currently executing effect or scope.
131
- *
132
- * The callback will be called:
133
- * 1. **Before the next re-run** of the enclosing effect (so resources from
134
- * the previous run are released before the new run sets them up again).
135
- * 2. **On final disposal** of the effect, whether triggered explicitly by
136
- * calling the effect's cleanup handle or implicitly by an owning
137
- * `effectScope` being disposed.
138
- *
139
- * Calling `onCleanup` outside of a tracking context (no active effect) is a
140
- * no-op; it does **not** throw.
141
- *
142
- * Only one cleanup function per effect run is supported. Calling `onCleanup`
143
- * multiple times within the same run overwrites the previous registration.
144
- *
145
- * @param fn - The teardown callback.
146
- *
147
- * @example
148
- * ```ts
149
- * effect(() => {
150
- * const id = setInterval(() => tick(), 1000);
151
- * onCleanup(() => clearInterval(id));
152
- * });
153
- * ```
154
- *
155
- * @example Composable helper – no prop-drilling needed:
156
- * ```ts
157
- * function useEventListener(target: EventTarget, type: string, handler: EventListener) {
158
- * target.addEventListener(type, handler);
159
- * onCleanup(() => target.removeEventListener(type, handler));
160
- * }
161
- *
162
- * effect(() => {
163
- * useEventListener(window, 'resize', onResize);
164
- * });
165
- * ```
166
- */
167
- declare function onCleanup(fn: () => void): void;
168
- /**
169
- * Runs `fn` as a single atomic update: all signal writes inside `fn` are
170
- * collected and effects are flushed only once after `fn` returns, rather than
171
- * after each individual write.
172
- *
173
- * Batches can be nested; the flush only occurs when the outermost batch
174
- * completes.
175
- *
176
- * @example
177
- * ```ts
178
- * batch(() => {
179
- * x(1);
180
- * y(2);
181
- * z(3);
182
- * }); // effects that depend on x, y, or z run once here
183
- * ```
184
- */
185
- declare function batch(fn: () => void): void;
186
- /**
187
- * Executes `fn` in a non-tracking context: any signals read inside `fn` do
188
- * **not** create dependency links on the currently active subscriber.
189
- *
190
- * Useful when you need to read a signal's current value without subscribing to
191
- * future changes.
192
- *
193
- * @returns The value returned by `fn`.
194
- *
195
- * @example
196
- * ```ts
197
- * const logCount = effect(() => {
198
- * console.log('triggered by a:', a());
199
- * // read b without subscribing – effect won't re-run when b changes
200
- * console.log('current b:', untracked(b));
201
- * });
202
- * ```
203
- */
204
- declare function untracked<T>(fn: Computed<T>): T;
205
- /**
206
- * Manually triggers all subscribers of every signal read inside `fn`.
207
- *
208
- * Unlike writing to a signal, `trigger` does not change the signal's value; it
209
- * only forces downstream effects and computeds to re-evaluate.
210
- *
211
- * @param fn - Function whose reactive reads identify the signals to trigger.
212
- *
213
- * @example
214
- * ```ts
215
- * const items = signal([1, 2, 3]);
216
- *
217
- * // Mutate in place (referential equality won't detect the change):
218
- * items().push(4);
219
- * trigger(items); // manually notify subscribers
220
- * ```
221
- */
222
- declare function trigger<T = void>(fn: Computed<T>): void;
223
- //#endregion
224
- //#region src/signals/index.d.ts
225
- declare function isReactive<T>(value: MaybeReactive<T>): value is () => T;
226
- type Updater<T> = (value: T) => void;
227
- type Computed<T> = () => T;
228
- type Signal<T> = Updater<T> & Computed<T>;
229
- /**
230
- * A decorator that makes a class field reactive by automatically wrapping its value in a signal.
231
- *
232
- * The field behaves like a normal property (get/set) but reactivity is tracked under the hood.
233
- * Any reads will subscribe to the signal and any writes will trigger updates.
234
- *
235
- * @example
236
- * ```ts
237
- * class Counter {
238
- * @reactive()
239
- * count: number = 0;
240
- * }
241
- *
242
- * const counter = new Counter();
243
- * counter.count++; // Triggers reactivity
244
- * console.log(counter.count); // Subscribes to changes
245
- * ```
246
- *
247
- * @remarks
248
- * Equivalent to manually creating a private signal and getter/setter:
249
- * ```ts
250
- * class Counter {
251
- * #count = signal(0);
252
- * get count() { return this.#count(); }
253
- * set count(value) { this.#count(value); }
254
- * }
255
- * ```
256
- */
257
- declare function reactive<This extends object, Value>(source?: (self: This) => Signal<Value>): (_target: unknown, context: ClassFieldDecoratorContext<This, Value>) => (this: This, initialValue: Value) => Value;
258
- /**
259
- * A value that may be static or reactive. Accepts a plain `T` or a
260
- * zero-arg getter (`() => T`) — typically a `signal` or `computed`.
261
- *
262
- * Used across the library anywhere a prop or attribute may be bound to
263
- * reactive state. Resolve with {@link resolve}, detect with {@link isReactive}.
264
- *
265
- * @template T — the value type.
266
- *
267
- * @example
268
- * ```ts
269
- * import { signal, computed } from "elements-kit/signals";
270
- *
271
- * const count = signal(0);
272
- * const double = computed(() => count() * 2);
273
- *
274
- * const a: MaybeReactive<number> = 5; // static
275
- * const b: MaybeReactive<number> = count; // signal (getter)
276
- * const c: MaybeReactive<number> = double; // computed (getter)
277
- * ```
278
- */
279
- type MaybeReactive<T> = T | Computed<T>;
280
- /**
281
- * Resolve a {@link MaybeReactive} to its current value. Calls the getter
282
- * when reactive; returns the value as-is when static.
283
- *
284
- * @example
285
- * ```ts
286
- * resolve(5); // 5
287
- * resolve(() => count()); // current count value
288
- * ```
289
- */
290
- declare function resolve<T>(value: MaybeReactive<T>): T;
291
- /**
292
- * Turn a reactive-props object into a bag of per-key getters. Callers may
293
- * pass values or reactive sources (`signal`, `computed`); reading
294
- * `props.name()` inside an effect or JSX getter subscribes to whatever
295
- * drives it. Static values become stable thunks, signals and computed pass
296
- * through unchanged — so identity is preserved (`props.name === props.name`).
297
- *
298
- * @example
299
- * ```tsx
300
- * import { resolveProps } from "elements-kit/signals";
301
- *
302
- * function Greeting(raw: MaybeReactiveProps<{ name: string; excited?: boolean }>) {
303
- * const props = resolveProps(raw);
304
- * return (
305
- * <p>
306
- * Hello, {props.name}
307
- * {() => (props.excited() ? "!" : ".")}
308
- * </p>
309
- * );
310
- * }
311
- * ```
312
- */
313
- declare function resolveProps<P extends object>(raw: { [K in keyof P]: MaybeReactive<P[K]> }): { readonly [K in keyof P]: Computed<P[K]> };
314
- //#endregion
315
- export { trigger as C, signal as S, isComputed as _, isReactive as a, isSignal as b, resolveProps as c, EFFECT_SCOPE as d, SIGNAL as f, effectScope as g, effect as h, Updater as i, COMPUTED as l, computed as m, MaybeReactive as n, reactive as o, batch as p, Signal as r, resolve as s, Computed as t, EFFECT as u, isEffect as v, untracked as w, onCleanup as x, isEffectScope as y };