@seahax/elemental 0.5.0 → 0.5.2

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 (101) hide show
  1. package/dist/{store.js → createStore.js} +3 -3
  2. package/dist/createStore.js.map +1 -0
  3. package/dist/{component.d.ts → defineComponent.d.ts} +6 -7
  4. package/dist/{component.js → defineComponent.js} +3 -3
  5. package/dist/defineComponent.js.map +1 -0
  6. package/dist/{router.d.ts → getRouter.d.ts} +3 -2
  7. package/dist/getRouter.js +33 -0
  8. package/dist/getRouter.js.map +1 -0
  9. package/dist/hooks/{async.d.ts → useAsync.d.ts} +1 -1
  10. package/dist/hooks/{async.js → useAsync.js} +4 -4
  11. package/dist/hooks/useAsync.js.map +1 -0
  12. package/dist/hooks/{attributes.d.ts → useAttributes.d.ts} +1 -1
  13. package/dist/hooks/useAttributes.js +37 -0
  14. package/dist/hooks/useAttributes.js.map +1 -0
  15. package/dist/hooks/useChildEffect.js +24 -0
  16. package/dist/hooks/useChildEffect.js.map +1 -0
  17. package/dist/hooks/useDisconnect.js +9 -0
  18. package/dist/hooks/useDisconnect.js.map +1 -0
  19. package/dist/hooks/{document.d.ts → useDocument.d.ts} +1 -1
  20. package/dist/hooks/useDocument.js +9 -0
  21. package/dist/hooks/useDocument.js.map +1 -0
  22. package/dist/hooks/{effect.d.ts → useEffect.d.ts} +1 -1
  23. package/dist/hooks/{effect.js → useEffect.js} +4 -4
  24. package/dist/hooks/useEffect.js.map +1 -0
  25. package/dist/hooks/useElementInternals.js +9 -0
  26. package/dist/hooks/useElementInternals.js.map +1 -0
  27. package/dist/hooks/{form.d.ts → useForm.d.ts} +1 -1
  28. package/dist/hooks/{form.js → useForm.js} +3 -3
  29. package/dist/hooks/useForm.js.map +1 -0
  30. package/dist/hooks/useHost.js +9 -0
  31. package/dist/hooks/useHost.js.map +1 -0
  32. package/dist/hooks/useInternalController.d.ts +3 -0
  33. package/dist/hooks/useInternalController.js +11 -0
  34. package/dist/hooks/useInternalController.js.map +1 -0
  35. package/dist/hooks/{parent.d.ts → useParent.d.ts} +1 -1
  36. package/dist/hooks/useParent.js +9 -0
  37. package/dist/hooks/useParent.js.map +1 -0
  38. package/dist/hooks/{ref.d.ts → useRef.d.ts} +1 -1
  39. package/dist/hooks/useRef.js +9 -0
  40. package/dist/hooks/useRef.js.map +1 -0
  41. package/dist/hooks/{route.d.ts → useRoute.d.ts} +1 -1
  42. package/dist/hooks/{route.js → useRoute.js} +6 -6
  43. package/dist/hooks/useRoute.js.map +1 -0
  44. package/dist/hooks/{store.d.ts → useStore.d.ts} +2 -2
  45. package/dist/hooks/{store.js → useStore.js} +4 -4
  46. package/dist/hooks/useStore.js.map +1 -0
  47. package/dist/html.d.ts +1 -1
  48. package/dist/html.js.map +1 -1
  49. package/dist/index.d.ts +15 -16
  50. package/dist/index.js +17 -18
  51. package/dist/internal/constants.d.ts +1 -0
  52. package/dist/internal/constants.js +6 -0
  53. package/dist/internal/constants.js.map +1 -0
  54. package/dist/internal/controllers.d.ts +2 -0
  55. package/dist/internal/controllers.js +6 -0
  56. package/dist/internal/controllers.js.map +1 -0
  57. package/dist/internal/{callbacks.js → createCallbacks.js} +2 -2
  58. package/dist/internal/createCallbacks.js.map +1 -0
  59. package/dist/internal/{controller.d.ts → createController.d.ts} +5 -5
  60. package/dist/internal/{controller.js → createController.js} +21 -20
  61. package/dist/internal/createController.js.map +1 -0
  62. package/dist/internal/getOrInsert.d.ts +4 -0
  63. package/dist/internal/getOrInsert.js +10 -0
  64. package/dist/internal/getOrInsert.js.map +1 -0
  65. package/package.json +8 -4
  66. package/dist/component.js.map +0 -1
  67. package/dist/hooks/async.js.map +0 -1
  68. package/dist/hooks/attributes.js +0 -25
  69. package/dist/hooks/attributes.js.map +0 -1
  70. package/dist/hooks/child.js +0 -14
  71. package/dist/hooks/child.js.map +0 -1
  72. package/dist/hooks/controller.d.ts +0 -3
  73. package/dist/hooks/controller.js +0 -11
  74. package/dist/hooks/controller.js.map +0 -1
  75. package/dist/hooks/disconnect.js +0 -9
  76. package/dist/hooks/disconnect.js.map +0 -1
  77. package/dist/hooks/document.js +0 -9
  78. package/dist/hooks/document.js.map +0 -1
  79. package/dist/hooks/effect.js.map +0 -1
  80. package/dist/hooks/form.js.map +0 -1
  81. package/dist/hooks/host.js +0 -9
  82. package/dist/hooks/host.js.map +0 -1
  83. package/dist/hooks/internals.js +0 -9
  84. package/dist/hooks/internals.js.map +0 -1
  85. package/dist/hooks/parent.js +0 -9
  86. package/dist/hooks/parent.js.map +0 -1
  87. package/dist/hooks/ref.js +0 -9
  88. package/dist/hooks/ref.js.map +0 -1
  89. package/dist/hooks/route.js.map +0 -1
  90. package/dist/hooks/store.js.map +0 -1
  91. package/dist/internal/callbacks.js.map +0 -1
  92. package/dist/internal/controller.js.map +0 -1
  93. package/dist/router.js +0 -35
  94. package/dist/router.js.map +0 -1
  95. package/dist/store.js.map +0 -1
  96. /package/dist/{store.d.ts → createStore.d.ts} +0 -0
  97. /package/dist/hooks/{child.d.ts → useChildEffect.d.ts} +0 -0
  98. /package/dist/hooks/{disconnect.d.ts → useDisconnect.d.ts} +0 -0
  99. /package/dist/hooks/{internals.d.ts → useElementInternals.d.ts} +0 -0
  100. /package/dist/hooks/{host.d.ts → useHost.d.ts} +0 -0
  101. /package/dist/internal/{callbacks.d.ts → createCallbacks.d.ts} +0 -0
package/dist/index.js CHANGED
@@ -1,18 +1,17 @@
1
- import { useRef as e } from "./hooks/ref.js";
2
- import { defineComponent as t } from "./component.js";
3
- import { useDisconnectCallback as n } from "./hooks/disconnect.js";
4
- import { useEffect as r } from "./hooks/effect.js";
5
- import { useAsync as i } from "./hooks/async.js";
6
- import { useHost as a } from "./hooks/host.js";
7
- import { useAttributes as o } from "./hooks/attributes.js";
8
- import { useChildEffect as s } from "./hooks/child.js";
9
- import { useDocument as c } from "./hooks/document.js";
10
- import { useForm as l, useFormDisabled as u, useFormResetCallback as d, useFormRestoreCallback as f } from "./hooks/form.js";
11
- import { useElementInternals as p } from "./hooks/internals.js";
12
- import { useParent as m } from "./hooks/parent.js";
13
- import { createStore as h } from "./store.js";
14
- import { getRouter as g } from "./router.js";
15
- import { useStore as _ } from "./hooks/store.js";
16
- import { useRoute as v } from "./hooks/route.js";
17
- import { html as y } from "./html.js";
18
- export { h as createStore, t as defineComponent, g as getRouter, y as h, y as html, i as useAsync, o as useAttributes, s as useChildEffect, n as useDisconnectCallback, c as useDocument, r as useEffect, p as useElementInternals, l as useForm, u as useFormDisabled, d as useFormResetCallback, f as useFormRestoreCallback, a as useHost, m as useParent, e as useRef, v as useRoute, _ as useStore };
1
+ import { createStore as e } from "./createStore.js";
2
+ import { useRef as t } from "./hooks/useRef.js";
3
+ import { defineComponent as n } from "./defineComponent.js";
4
+ import { useDisconnectCallback as r } from "./hooks/useDisconnect.js";
5
+ import { useEffect as i } from "./hooks/useEffect.js";
6
+ import { useAsync as a } from "./hooks/useAsync.js";
7
+ import { useHost as o } from "./hooks/useHost.js";
8
+ import { useAttributes as s } from "./hooks/useAttributes.js";
9
+ import { useChildEffect as c } from "./hooks/useChildEffect.js";
10
+ import { useDocument as l } from "./hooks/useDocument.js";
11
+ import { useElementInternals as u } from "./hooks/useElementInternals.js";
12
+ import { useForm as d, useFormDisabled as f, useFormResetCallback as p, useFormRestoreCallback as m } from "./hooks/useForm.js";
13
+ import { useParent as h } from "./hooks/useParent.js";
14
+ import { useStore as g } from "./hooks/useStore.js";
15
+ import { useRoute as _ } from "./hooks/useRoute.js";
16
+ import { html as v } from "./html.js";
17
+ export { e as createStore, n as defineComponent, v as h, v as html, a as useAsync, s as useAttributes, c as useChildEffect, r as useDisconnectCallback, l as useDocument, i as useEffect, u as useElementInternals, d as useForm, f as useFormDisabled, p as useFormResetCallback, m as useFormRestoreCallback, o as useHost, h as useParent, t as useRef, _ as useRoute, g as useStore };
@@ -0,0 +1 @@
1
+ export declare const $$ref: unique symbol;
@@ -0,0 +1,6 @@
1
+ //#region src/internal/constants.ts
2
+ var e = Symbol();
3
+ //#endregion
4
+ export { e as $$ref };
5
+
6
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","names":[],"sources":["../../src/internal/constants.ts"],"sourcesContent":["export const $$ref = Symbol();\n"],"mappings":";AAAA,IAAa,IAAQ,QAAQ"}
@@ -0,0 +1,2 @@
1
+ import type { Controller } from './createController.ts';
2
+ export declare const controllers: Controller[];
@@ -0,0 +1,6 @@
1
+ //#region src/internal/controllers.ts
2
+ var e = [];
3
+ //#endregion
4
+ export { e as controllers };
5
+
6
+ //# sourceMappingURL=controllers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controllers.js","names":[],"sources":["../../src/internal/controllers.ts"],"sourcesContent":["import type { Controller } from './createController.ts';\n\nexport const controllers: Controller[] = [];\n"],"mappings":";AAEA,IAAa,IAA4B,EAAE"}
@@ -1,4 +1,4 @@
1
- //#region src/internal/callbacks.ts
1
+ //#region src/internal/createCallbacks.ts
2
2
  function e() {
3
3
  let e = /* @__PURE__ */ new Set(), t = {
4
4
  push: (t) => (e.add(t), () => e.delete(t)),
@@ -27,4 +27,4 @@ function e() {
27
27
  //#endregion
28
28
  export { e as createCallbacks };
29
29
 
30
- //# sourceMappingURL=callbacks.js.map
30
+ //# sourceMappingURL=createCallbacks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createCallbacks.js","names":[],"sources":["../../src/internal/createCallbacks.ts"],"sourcesContent":["export interface Callbacks<TArgs extends unknown[] = []> {\n readonly push: (callback: (...args: TArgs) => void) => () => void;\n readonly run: (...args: TArgs) => void;\n readonly runAndClear: (...args: TArgs) => void;\n readonly clear: () => void;\n}\n\nexport function createCallbacks<TArgs extends unknown[] = []>(): Callbacks<TArgs> {\n const callbacks = new Set<(...args: TArgs) => void>();\n\n const self: Callbacks<TArgs> = {\n push: (callback) => {\n callbacks.add(callback);\n return () => callbacks.delete(callback);\n },\n run: (...args) => {\n const errors: unknown[] = [];\n const callbacksCopy = [...callbacks];\n\n for (const callback of callbacksCopy) {\n try {\n callback(...args);\n } catch (error: unknown) {\n errors.push(error);\n }\n }\n\n if (errors.length > 0) throw new AggregateError(errors);\n },\n runAndClear: (...args: TArgs) => {\n try {\n self.run(...args);\n } finally {\n self.clear();\n }\n },\n clear: () => {\n callbacks.clear();\n },\n };\n\n return self;\n}\n"],"mappings":";AAOA,SAAgB,IAAkE;CAChF,IAAM,oBAAY,IAAI,KAA+B,EAE/C,IAAyB;EAC7B,OAAO,OACL,EAAU,IAAI,EAAS,QACV,EAAU,OAAO,EAAS;EAEzC,MAAM,GAAG,MAAS;GAChB,IAAM,IAAoB,EAAE,EACtB,IAAgB,CAAC,GAAG,EAAU;AAEpC,QAAK,IAAM,KAAY,EACrB,KAAI;AACF,MAAS,GAAG,EAAK;YACV,GAAgB;AACvB,MAAO,KAAK,EAAM;;AAItB,OAAI,EAAO,SAAS,EAAG,OAAU,eAAe,EAAO;;EAEzD,cAAc,GAAG,MAAgB;AAC/B,OAAI;AACF,MAAK,IAAI,GAAG,EAAK;aACT;AACR,MAAK,OAAO;;;EAGhB,aAAa;AACX,KAAU,OAAO;;EAEpB;AAED,QAAO"}
@@ -1,8 +1,9 @@
1
- import { type ReadonlyRef, type Ref } from '../hooks/ref.ts';
2
- import { type Callbacks } from './callbacks.ts';
1
+ import { type ReadonlyRef, type Ref } from '../hooks/useRef.ts';
2
+ import { type Callbacks } from './createCallbacks.ts';
3
3
  export interface Controller {
4
4
  readonly host: HTMLElement;
5
5
  readonly onNotify: Callbacks;
6
+ readonly onAfterRender: Callbacks;
6
7
  readonly onDisconnect: Callbacks;
7
8
  readonly refDocument: ReadonlyRef<Document>;
8
9
  readonly refParent: ReadonlyRef<ParentNode | null>;
@@ -22,12 +23,11 @@ export interface Controller {
22
23
  readonly formResetCallback: () => void;
23
24
  readonly formStateRestoreCallback: (state: string | File | FormData, reason: 'restore' | 'autocomplete') => void;
24
25
  }
25
- export interface ControllerConfig {
26
+ interface ControllerConfig {
26
27
  readonly host: HTMLElement;
27
28
  readonly formAssociated: boolean;
28
29
  readonly render: (controller: Controller) => void;
29
30
  readonly attachInternals: () => ElementInternals;
30
31
  }
31
- export declare const $$ref: unique symbol;
32
- export declare function getController(): Controller | undefined;
33
32
  export declare function createController({ host, formAssociated, render, attachInternals }: ControllerConfig): Controller;
33
+ export {};
@@ -1,19 +1,17 @@
1
- import { createCallbacks as e } from "./callbacks.js";
2
- //#region src/internal/controller.ts
3
- var t = Symbol(), n = [];
4
- function r() {
5
- return n.at(-1);
6
- }
7
- function i({ host: r, formAssociated: i, render: a, attachInternals: o }) {
8
- let s = !1, c = !1, l, u, d = e(), f = (e, n) => {
1
+ import { createCallbacks as e } from "./createCallbacks.js";
2
+ import { controllers as t } from "./controllers.js";
3
+ import { $$ref as n } from "./constants.js";
4
+ //#region src/internal/createController.ts
5
+ function r({ host: r, formAssociated: i, render: a, attachInternals: o }) {
6
+ let s = !1, c = !1, l, u, d = e(), f = (e, t) => {
9
7
  let r = e;
10
8
  return {
11
- [t]: !0,
9
+ [n]: !0,
12
10
  get value() {
13
11
  return r;
14
12
  },
15
13
  set value(e) {
16
- e !== r && (r = e, n?.(r), !(!c || s) && (s = !0, queueMicrotask(() => {
14
+ e !== r && (r = e, t?.(r), !(!c || s) && (s = !0, queueMicrotask(() => {
17
15
  s = !1, d.run();
18
16
  })));
19
17
  }
@@ -21,6 +19,7 @@ function i({ host: r, formAssociated: i, render: a, attachInternals: o }) {
21
19
  }, p = {
22
20
  host: r,
23
21
  onNotify: d,
22
+ onAfterRender: e(),
24
23
  onDisconnect: e(),
25
24
  refDocument: f(r.ownerDocument),
26
25
  refParent: f(r.parentNode),
@@ -33,19 +32,21 @@ function i({ host: r, formAssociated: i, render: a, attachInternals: o }) {
33
32
  createRef: f,
34
33
  attachInternals: () => l ??= o(),
35
34
  connectedCallback: () => {
36
- c = !0, p.refParent.value = r.parentNode;
37
- try {
38
- n.push(p), a(p);
39
- } finally {
40
- n.pop();
35
+ if (!c) {
36
+ c = !0, p.refParent.value = r.parentNode;
37
+ try {
38
+ t.push(p), a(p);
39
+ } finally {
40
+ t.pop();
41
+ }
42
+ p.onAfterRender.runAndClear(), u?.type === "reset" ? p.formAssociated?.onReset.run() : u?.type === "restore" && p.formAssociated?.onRestore.run(u.state, u.reason), p.onNotify.run();
41
43
  }
42
- u?.type === "reset" ? p.formAssociated?.onReset.run() : u?.type === "restore" && p.formAssociated?.onRestore.run(u.state, u.reason), p.onNotify.run();
43
44
  },
44
45
  connectedMoveCallback: () => {
45
- p.refParent.value = r.parentNode, p.onNotify.run();
46
+ c && (p.refParent.value = r.parentNode, p.onNotify.run());
46
47
  },
47
48
  disconnectedCallback: () => {
48
- p.onNotify.clear(), p.formAssociated?.onReset.clear(), p.formAssociated?.onRestore.clear(), p.onDisconnect.runAndClear();
49
+ c && (p.onNotify.clear(), p.formAssociated?.onReset.clear(), p.formAssociated?.onRestore.clear(), p.onDisconnect.runAndClear());
49
50
  },
50
51
  adoptedCallback: () => {
51
52
  p.refDocument.value = r.ownerDocument, p.onNotify.run();
@@ -67,6 +68,6 @@ function i({ host: r, formAssociated: i, render: a, attachInternals: o }) {
67
68
  return p;
68
69
  }
69
70
  //#endregion
70
- export { i as createController, r as getController };
71
+ export { r as createController };
71
72
 
72
- //# sourceMappingURL=controller.js.map
73
+ //# sourceMappingURL=createController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createController.js","names":[],"sources":["../../src/internal/createController.ts"],"sourcesContent":["import { type ReadonlyRef, type Ref } from '../hooks/useRef.ts';\nimport { $$ref } from './constants.ts';\nimport { controllers } from './controllers.ts';\nimport { type Callbacks, createCallbacks } from './createCallbacks.ts';\n\nexport interface Controller {\n readonly host: HTMLElement;\n readonly onNotify: Callbacks;\n readonly onAfterRender: Callbacks;\n readonly onDisconnect: Callbacks;\n readonly refDocument: ReadonlyRef<Document>;\n readonly refParent: ReadonlyRef<ParentNode | null>;\n readonly formAssociated:\n | {\n readonly refForm: ReadonlyRef<HTMLFormElement | null>;\n readonly refDisabled: ReadonlyRef<boolean>;\n readonly onReset: Callbacks;\n readonly onRestore: Callbacks<[state: string | File | FormData, reason: 'restore' | 'autocomplete']>;\n }\n | undefined;\n readonly createRef: <T>(value: T, onChange?: (value: T) => void) => Ref<T>;\n readonly attachInternals: () => ElementInternals;\n readonly connectedCallback: () => void;\n readonly connectedMoveCallback: () => void;\n readonly disconnectedCallback: () => void;\n readonly adoptedCallback: () => void;\n readonly formDisabledCallback: (disabled: boolean) => void;\n readonly formResetCallback: () => void;\n readonly formStateRestoreCallback: (state: string | File | FormData, reason: 'restore' | 'autocomplete') => void;\n}\n\ninterface ControllerConfig {\n readonly host: HTMLElement;\n readonly formAssociated: boolean;\n readonly render: (controller: Controller) => void;\n readonly attachInternals: () => ElementInternals;\n}\n\nexport function createController({ host, formAssociated, render, attachInternals }: ControllerConfig): Controller {\n let notifying = false;\n let connected = false;\n let internals: ElementInternals | undefined;\n\n let deferredFormUpdate:\n | { readonly type: 'reset' }\n | { readonly type: 'restore'; state: string | File | FormData; reason: 'restore' | 'autocomplete' }\n | undefined;\n\n const onNotify = createCallbacks();\n\n const createRef = <T>(initialValue: T, onChange?: (value: T) => void): Ref<T> => {\n let value = initialValue;\n\n return {\n [$$ref]: true,\n get value() {\n return value;\n },\n set value(newValue) {\n if (newValue === value) return;\n value = newValue;\n onChange?.(value);\n if (!connected || notifying) return;\n notifying = true;\n\n queueMicrotask(() => {\n notifying = false;\n onNotify.run();\n });\n },\n };\n };\n\n const controller = {\n host,\n onNotify,\n onAfterRender: createCallbacks(),\n onDisconnect: createCallbacks(),\n refDocument: createRef(host.ownerDocument),\n refParent: createRef(host.parentNode),\n formAssociated: formAssociated\n ? {\n refForm: createRef<HTMLFormElement | null>(null),\n refDisabled: createRef(false),\n onReset: createCallbacks(),\n onRestore: createCallbacks(),\n }\n : undefined,\n createRef,\n attachInternals: () => {\n return (internals ??= attachInternals());\n },\n connectedCallback: () => {\n if (connected) return;\n connected = true;\n controller.refParent.value = host.parentNode;\n\n try {\n controllers.push(controller);\n render(controller);\n } finally {\n controllers.pop();\n }\n\n controller.onAfterRender.runAndClear();\n\n if (deferredFormUpdate?.type === 'reset') {\n controller.formAssociated?.onReset.run();\n } else if (deferredFormUpdate?.type === 'restore') {\n controller.formAssociated?.onRestore.run(deferredFormUpdate.state, deferredFormUpdate.reason);\n }\n\n controller.onNotify.run();\n },\n connectedMoveCallback: () => {\n if (!connected) return;\n controller.refParent.value = host.parentNode;\n controller.onNotify.run();\n },\n disconnectedCallback: () => {\n if (!connected) return;\n controller.onNotify.clear();\n controller.formAssociated?.onReset.clear();\n controller.formAssociated?.onRestore.clear();\n controller.onDisconnect.runAndClear();\n },\n adoptedCallback: () => {\n controller.refDocument.value = host.ownerDocument;\n controller.onNotify.run();\n },\n formDisabledCallback: (disabled: boolean) => {\n if (!controller.formAssociated) return;\n controller.formAssociated.refDisabled.value = disabled;\n controller.onNotify.run();\n },\n formResetCallback: () => {\n if (!controller.formAssociated) return;\n if (connected) controller.formAssociated.onReset.run();\n else deferredFormUpdate = { type: 'reset' };\n },\n formStateRestoreCallback: (state, reason) => {\n if (!controller.formAssociated) return;\n if (connected) controller.formAssociated.onRestore.run(state, reason);\n else deferredFormUpdate = { type: 'restore', state, reason };\n },\n } satisfies Controller;\n\n return controller;\n}\n"],"mappings":";;;;AAsCA,SAAgB,EAAiB,EAAE,SAAM,mBAAgB,WAAQ,sBAAiD;CAChH,IAAI,IAAY,IACZ,IAAY,IACZ,GAEA,GAKE,IAAW,GAAiB,EAE5B,KAAgB,GAAiB,MAA0C;EAC/E,IAAI,IAAQ;AAEZ,SAAO;IACJ,IAAQ;GACT,IAAI,QAAQ;AACV,WAAO;;GAET,IAAI,MAAM,GAAU;AACd,UAAa,MACjB,IAAQ,GACR,IAAW,EAAM,EACb,GAAC,KAAa,OAClB,IAAY,IAEZ,qBAAqB;AAEnB,KADA,IAAY,IACZ,EAAS,KAAK;MACd;;GAEL;IAGG,IAAa;EACjB;EACA;EACA,eAAe,GAAiB;EAChC,cAAc,GAAiB;EAC/B,aAAa,EAAU,EAAK,cAAc;EAC1C,WAAW,EAAU,EAAK,WAAW;EACrC,gBAAgB,IACZ;GACE,SAAS,EAAkC,KAAK;GAChD,aAAa,EAAU,GAAM;GAC7B,SAAS,GAAiB;GAC1B,WAAW,GAAiB;GAC7B,GACD,KAAA;EACJ;EACA,uBACU,MAAc,GAAiB;EAEzC,yBAAyB;AACnB,WAEJ;IADA,IAAY,IACZ,EAAW,UAAU,QAAQ,EAAK;AAElC,QAAI;AAEF,KADA,EAAY,KAAK,EAAW,EAC5B,EAAO,EAAW;cACV;AACR,OAAY,KAAK;;AAWnB,IARA,EAAW,cAAc,aAAa,EAElC,GAAoB,SAAS,UAC/B,EAAW,gBAAgB,QAAQ,KAAK,GAC/B,GAAoB,SAAS,aACtC,EAAW,gBAAgB,UAAU,IAAI,EAAmB,OAAO,EAAmB,OAAO,EAG/F,EAAW,SAAS,KAAK;;;EAE3B,6BAA6B;AACtB,SACL,EAAW,UAAU,QAAQ,EAAK,YAClC,EAAW,SAAS,KAAK;;EAE3B,4BAA4B;AACrB,SACL,EAAW,SAAS,OAAO,EAC3B,EAAW,gBAAgB,QAAQ,OAAO,EAC1C,EAAW,gBAAgB,UAAU,OAAO,EAC5C,EAAW,aAAa,aAAa;;EAEvC,uBAAuB;AAErB,GADA,EAAW,YAAY,QAAQ,EAAK,eACpC,EAAW,SAAS,KAAK;;EAE3B,uBAAuB,MAAsB;AACtC,KAAW,mBAChB,EAAW,eAAe,YAAY,QAAQ,GAC9C,EAAW,SAAS,KAAK;;EAE3B,yBAAyB;AAClB,KAAW,mBACZ,IAAW,EAAW,eAAe,QAAQ,KAAK,GACjD,IAAqB,EAAE,MAAM,SAAS;;EAE7C,2BAA2B,GAAO,MAAW;AACtC,KAAW,mBACZ,IAAW,EAAW,eAAe,UAAU,IAAI,GAAO,EAAO,GAChE,IAAqB;IAAE,MAAM;IAAW;IAAO;IAAQ;;EAE/D;AAED,QAAO"}
@@ -0,0 +1,4 @@
1
+ type MapKey<T> = T extends Map<infer TKey, any> ? TKey : T extends WeakMap<infer TKey, any> ? TKey : never;
2
+ type MapValue<T> = T extends Map<any, infer TValue> ? TValue : T extends WeakMap<any, infer TValue> ? TValue : never;
3
+ export declare function getOrInsert<TMap extends Map<any, any> | WeakMap<any, any>>(map: TMap, key: MapKey<TMap>, createValue: (key: MapKey<TMap>) => MapValue<TMap>): MapValue<TMap>;
4
+ export {};
@@ -0,0 +1,10 @@
1
+ //#region src/internal/getOrInsert.ts
2
+ function e(e, t, n) {
3
+ if (e.has(t)) return e.get(t);
4
+ let r = n(t);
5
+ return e.set(t, r), r;
6
+ }
7
+ //#endregion
8
+ export { e as getOrInsert };
9
+
10
+ //# sourceMappingURL=getOrInsert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getOrInsert.js","names":[],"sources":["../../src/internal/getOrInsert.ts"],"sourcesContent":["type MapKey<T> = T extends Map<infer TKey, any> ? TKey : T extends WeakMap<infer TKey, any> ? TKey : never;\ntype MapValue<T> = T extends Map<any, infer TValue> ? TValue : T extends WeakMap<any, infer TValue> ? TValue : never;\n\nexport function getOrInsert<TMap extends Map<any, any> | WeakMap<any, any>>(\n map: TMap,\n key: MapKey<TMap>,\n createValue: (key: MapKey<TMap>) => MapValue<TMap>,\n): MapValue<TMap> {\n if (map.has(key)) return map.get(key)!;\n const value = createValue(key);\n map.set(key, value);\n return value;\n}\n"],"mappings":";AAGA,SAAgB,EACd,GACA,GACA,GACgB;AAChB,KAAI,EAAI,IAAI,EAAI,CAAE,QAAO,EAAI,IAAI,EAAI;CACrC,IAAM,IAAQ,EAAY,EAAI;AAE9B,QADA,EAAI,IAAI,GAAK,EAAM,EACZ"}
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@seahax/elemental",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Functional, reactive, web component base library.",
5
5
  "repository": {
6
6
  "type": "git",
7
- "url": "git+https://github.com/seahax/elemental.git"
7
+ "url": "https://git.sr.ht/~seahax/elemental"
8
8
  },
9
9
  "license": "MIT-0",
10
10
  "type": "module",
@@ -20,22 +20,26 @@
20
20
  ],
21
21
  "scripts": {
22
22
  "build": "vite build && tsc -b -f tsconfig.lib.json",
23
+ "postinstall": "playwright install",
23
24
  "prepublishOnly": "npm run build && npm test",
24
- "test": "eslint src"
25
+ "test": "eslint src && vitest run"
25
26
  },
26
27
  "devDependencies": {
27
28
  "@eslint/js": "^10.0.1",
28
29
  "@seahax/eslint-progress": "^0.1.17",
29
30
  "@types/node": "^25.6.0",
31
+ "@vitest/browser-playwright": "^4.1.6",
30
32
  "eslint": "^10.3.0",
31
33
  "eslint-config-prettier": "^10.1.8",
32
34
  "eslint-plugin-prettier": "^5.5.5",
33
35
  "eslint-plugin-regexp": "^3.1.0",
34
36
  "eslint-plugin-simple-import-sort": "^13.0.0",
35
37
  "jiti": "^2.6.1",
38
+ "playwright": "^1.60.0",
36
39
  "typescript-eslint": "^8.59.1",
37
40
  "vite": "^8.0.10",
38
- "vite-bundle-analyzer": "^1.3.8"
41
+ "vite-bundle-analyzer": "^1.3.8",
42
+ "vitest": "^4.1.6"
39
43
  },
40
44
  "publishConfig": {
41
45
  "access": "public"
@@ -1 +0,0 @@
1
- {"version":3,"file":"component.js","names":["#shadow","#controller","#props"],"sources":["../src/component.ts"],"sourcesContent":["import { type Ref } from './hooks/ref.ts';\nimport { type Controller, createController } from './internal/controller.ts';\n\ntype SafeProps<TProps> = any extends any\n ? { [P in keyof TProps as P extends keyof HTMLElement ? never : P]: TProps[P] }\n : never;\n\nexport interface ComponentConstructor<TProps extends object> {\n readonly formAssociated: boolean;\n new (): ComponentWithProps<TProps>;\n}\n\nexport interface ComponentOptions<TProps extends object> {\n /** Shadow root attachment options. */\n readonly shadow?: Partial<ShadowRootInit>;\n /** Component custom property descriptors. */\n readonly props?: ComponentPropDescriptors<TProps>;\n /** True to mark the component as form-associated. */\n readonly formAssociated?: boolean;\n}\n\nexport type ComponentPropDescriptors<TProps extends object> = {\n readonly [P in keyof SafeProps<TProps>]: ComponentPropDescriptorFactory<TProps[P]>;\n};\n\nexport type ComponentPropDescriptorFactory<TType> = (\n ref: Ref<TType | undefined>,\n host: HTMLElement,\n) => ComponentPropDescriptor<TType>;\n\nexport interface ComponentPropDescriptor<T> extends Omit<PropertyDescriptor, 'value' | 'get' | 'set'> {\n get(): T;\n set?(value: T): void;\n}\n\nexport type ComponentWithProps<TProps extends object> = HTMLElement & {\n -readonly [P in keyof SafeProps<TProps>]: TProps[P];\n};\n\nexport type ComponentShadowRoot<TProps extends object> = Omit<ShadowRoot, 'host'> & {\n readonly host: ComponentWithProps<TProps>;\n};\n\nexport type ComponentPropRefs<TProps extends object> = {\n readonly [P in keyof SafeProps<TProps>]: Ref<TProps[P] | undefined>;\n};\n\n/** Define a custom `HTMLElement` that is functional and reactive. */\nexport function defineComponent<TProps extends object = {}>(\n render: (shadowRoot: ComponentShadowRoot<TProps>, props: ComponentPropRefs<TProps>) => void,\n options?: ComponentOptions<TProps>,\n): ComponentConstructor<TProps>;\nexport function defineComponent(\n render: (\n shadowRoot: ComponentShadowRoot<Record<string, unknown>>,\n props: ComponentPropRefs<Record<string, unknown>>,\n ) => void,\n { props, shadow, formAssociated = false }: ComponentOptions<Record<string, unknown>> = {},\n): ComponentConstructor<{}> {\n return class extends HTMLElement {\n static readonly formAssociated = formAssociated;\n\n readonly #shadow: ComponentShadowRoot<Record<string, unknown>>;\n readonly #controller: Controller;\n readonly #props: ComponentPropRefs<Record<string, unknown>> = {};\n\n constructor() {\n super();\n\n this.#shadow = this.attachShadow({\n ...shadow,\n mode: shadow?.mode ?? 'open',\n }) as ComponentShadowRoot<Record<string, unknown>>;\n\n this.#controller = createController({\n host: this,\n formAssociated,\n render: () => render(this.#shadow, this.#props),\n attachInternals: () => super.attachInternals(),\n });\n\n if (props) {\n const propRefs: Record<string, Ref<unknown>> = this.#props;\n\n for (const [key, getDescriptor] of Object.entries(props)) {\n if (key in this) continue;\n const ref = (propRefs[key] = this.#controller.createRef<any>(undefined));\n const descriptor = getDescriptor(ref, this);\n Object.defineProperty(this, key, descriptor);\n }\n }\n\n if (formAssociated) {\n this.attachInternals();\n }\n }\n\n override attachInternals(): ElementInternals {\n return this.#controller.attachInternals();\n }\n\n protected connectedCallback(): void {\n this.#controller.connectedCallback();\n }\n\n protected connectedMoveCallback(): void {\n this.#controller.connectedMoveCallback();\n }\n\n protected disconnectedCallback(): void {\n this.#controller.disconnectedCallback();\n }\n\n protected adoptedCallback(): void {\n this.#controller.adoptedCallback();\n }\n\n protected formDisabledCallback(disabled: boolean): void {\n this.#controller.formDisabledCallback(disabled);\n }\n\n protected formResetCallback(): void {\n this.#controller.formResetCallback();\n }\n\n protected formStateRestoreCallback(state: string | File | FormData, reason: 'restore' | 'autocomplete'): void {\n this.#controller.formStateRestoreCallback(state, reason);\n }\n };\n}\n"],"mappings":";;AAoDA,SAAgB,EACd,GAIA,EAAE,UAAO,WAAQ,oBAAiB,OAAqD,EAAE,EAC/D;AAC1B,QAAO,cAAc,YAAY;EAC/B,OAAgB,iBAAiB;EAEjC;EACA;EACA,KAA8D,EAAE;EAEhE,cAAc;AAeZ,OAdA,OAAO,EAEP,MAAA,IAAe,KAAK,aAAa;IAC/B,GAAG;IACH,MAAM,GAAQ,QAAQ;IACvB,CAAC,EAEF,MAAA,IAAmB,EAAiB;IAClC,MAAM;IACN;IACA,cAAc,EAAO,MAAA,GAAc,MAAA,EAAY;IAC/C,uBAAuB,MAAM,iBAAiB;IAC/C,CAAC,EAEE,GAAO;IACT,IAAM,IAAyC,MAAA;AAE/C,SAAK,IAAM,CAAC,GAAK,MAAkB,OAAO,QAAQ,EAAM,EAAE;AACxD,SAAI,KAAO,KAAM;KAEjB,IAAM,IAAa,EAAc,EADX,KAAO,MAAA,EAAiB,UAAe,KAAA,EAAU,EACjC,KAAK;AAC3C,YAAO,eAAe,MAAM,GAAK,EAAW;;;AAIhD,GAAI,KACF,KAAK,iBAAiB;;EAI1B,kBAA6C;AAC3C,UAAO,MAAA,EAAiB,iBAAiB;;EAG3C,oBAAoC;AAClC,SAAA,EAAiB,mBAAmB;;EAGtC,wBAAwC;AACtC,SAAA,EAAiB,uBAAuB;;EAG1C,uBAAuC;AACrC,SAAA,EAAiB,sBAAsB;;EAGzC,kBAAkC;AAChC,SAAA,EAAiB,iBAAiB;;EAGpC,qBAA+B,GAAyB;AACtD,SAAA,EAAiB,qBAAqB,EAAS;;EAGjD,oBAAoC;AAClC,SAAA,EAAiB,mBAAmB;;EAGtC,yBAAmC,GAAiC,GAA0C;AAC5G,SAAA,EAAiB,yBAAyB,GAAO,EAAO"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"async.js","names":[],"sources":["../../src/hooks/async.ts"],"sourcesContent":["import { useEffect } from './effect.ts';\nimport { type ReadonlyRef, type Ref, type RefValues, useRef } from './ref.ts';\n\nexport interface AsyncValue<TValue> {\n readonly value: TValue | undefined;\n readonly error: unknown;\n readonly isLoading: boolean;\n}\n\nexport interface AsyncOptions {\n readonly debounceMs?: number;\n}\n\n/** Use a reference (reactive state) bound to an async loader function. */\nexport function useAsync<const TDeps extends readonly ReadonlyRef<any>[], TValue>(\n deps: TDeps,\n callback: (signal: AbortSignal, ...values: RefValues<TDeps>) => Promise<TValue>,\n { debounceMs }: AsyncOptions = {},\n): Ref<AsyncValue<TValue>> {\n const ref = useRef<AsyncValue<TValue>>({ value: undefined, error: undefined, isLoading: true });\n let skipDebounce = true;\n\n useEffect(deps, () => (...values) => {\n const ac = new AbortController();\n\n Promise.race(\n skipDebounce\n ? [Promise.resolve()]\n : [\n new Promise((resolve) => setTimeout(resolve, debounceMs)),\n new Promise((resolve) => ac.signal.addEventListener('abort', resolve, { once: true })),\n ],\n )\n .then(() => {\n if (ac.signal.aborted) return;\n return callback(ac.signal, ...(values as any));\n })\n .then((value) => {\n if (ac.signal.aborted) return;\n ref.value = { isLoading: false, value, error: undefined };\n })\n .catch((error: unknown) => {\n if (ac.signal.aborted) return;\n ref.value = { isLoading: false, value: undefined, error };\n });\n\n skipDebounce = false;\n return () => ac.abort();\n });\n\n // Skip the debounce again if the component unmounts.\n useEffect([], () => () => (skipDebounce = true));\n\n return ref;\n}\n"],"mappings":";;;AAcA,SAAgB,EACd,GACA,GACA,EAAE,kBAA6B,EAAE,EACR;CACzB,IAAM,IAAM,EAA2B;EAAE,OAAO,KAAA;EAAW,OAAO,KAAA;EAAW,WAAW;EAAM,CAAC,EAC3F,IAAe;AAiCnB,QA/BA,EAAU,UAAa,GAAG,MAAW;EACnC,IAAM,IAAK,IAAI,iBAAiB;AAwBhC,SAtBA,QAAQ,KACN,IACI,CAAC,QAAQ,SAAS,CAAC,GACnB,CACE,IAAI,SAAS,MAAY,WAAW,GAAS,EAAW,CAAC,EACzD,IAAI,SAAS,MAAY,EAAG,OAAO,iBAAiB,SAAS,GAAS,EAAE,MAAM,IAAM,CAAC,CAAC,CACvF,CACN,CACE,WAAW;AACN,UAAG,OAAO,QACd,QAAO,EAAS,EAAG,QAAQ,GAAI,EAAe;IAC9C,CACD,MAAM,MAAU;AACX,KAAG,OAAO,YACd,EAAI,QAAQ;IAAE,WAAW;IAAO;IAAO,OAAO,KAAA;IAAW;IACzD,CACD,OAAO,MAAmB;AACrB,KAAG,OAAO,YACd,EAAI,QAAQ;IAAE,WAAW;IAAO,OAAO,KAAA;IAAW;IAAO;IACzD,EAEJ,IAAe,UACF,EAAG,OAAO;GACvB,EAGF,EAAU,EAAE,cAAe,IAAe,GAAM,EAEzC"}
@@ -1,25 +0,0 @@
1
- import { useRef as e } from "./ref.js";
2
- import { useEffect as t } from "./effect.js";
3
- import { useHost as n } from "./host.js";
4
- //#region src/hooks/attributes.ts
5
- function r(...r) {
6
- if (r.length === 0) return {};
7
- let i = n(), a = [], o = /* @__PURE__ */ new Map();
8
- for (let t of r) {
9
- let n = e(i.getAttribute(t), (e) => {
10
- e == null ? i.removeAttribute(t) : i.setAttribute(t, e);
11
- });
12
- a.push(n), o.set(t, n);
13
- }
14
- let s = new MutationObserver((e) => {
15
- for (let { attributeName: t } of e) t != null && Object.hasOwn(a, t) && (o.get(t).value = i.getAttribute(t));
16
- });
17
- return t([], () => (s.observe(i, {
18
- attributeFilter: r,
19
- attributes: !0
20
- }), () => s.disconnect())), a;
21
- }
22
- //#endregion
23
- export { r as useAttributes };
24
-
25
- //# sourceMappingURL=attributes.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"attributes.js","names":[],"sources":["../../src/hooks/attributes.ts"],"sourcesContent":["import { useEffect } from './effect.ts';\nimport { useHost } from './host.ts';\nimport { type Ref, useRef } from './ref.ts';\n\n/** Use references (reactive state) bound to attributes. */\nexport function useAttributes<const TNames extends string[]>(\n ...names: TNames\n): { -readonly [P in keyof TNames]: Ref<string | null> } {\n if (names.length === 0) return {} as any;\n const host = useHost();\n const refs: Ref<string | null>[] = [];\n const refMap = new Map<string, Ref<string | null>>();\n\n for (const name of names) {\n const ref = useRef(host.getAttribute(name), (value) => {\n if (value == null) host.removeAttribute(name);\n else host.setAttribute(name, value);\n });\n\n refs.push(ref);\n refMap.set(name, ref);\n }\n\n const observer = new MutationObserver((mutation) => {\n for (const { attributeName } of mutation) {\n if (attributeName != null && Object.hasOwn(refs, attributeName)) {\n refMap.get(attributeName)!.value = host.getAttribute(attributeName);\n }\n }\n });\n\n useEffect([], () => {\n observer.observe(host, { attributeFilter: names, attributes: true });\n return () => observer.disconnect();\n });\n\n return refs as any;\n}\n"],"mappings":";;;;AAKA,SAAgB,EACd,GAAG,GACoD;AACvD,KAAI,EAAM,WAAW,EAAG,QAAO,EAAE;CACjC,IAAM,IAAO,GAAS,EAChB,IAA6B,EAAE,EAC/B,oBAAS,IAAI,KAAiC;AAEpD,MAAK,IAAM,KAAQ,GAAO;EACxB,IAAM,IAAM,EAAO,EAAK,aAAa,EAAK,GAAG,MAAU;AACrD,GAAI,KAAS,OAAM,EAAK,gBAAgB,EAAK,GACxC,EAAK,aAAa,GAAM,EAAM;IACnC;AAGF,EADA,EAAK,KAAK,EAAI,EACd,EAAO,IAAI,GAAM,EAAI;;CAGvB,IAAM,IAAW,IAAI,kBAAkB,MAAa;AAClD,OAAK,IAAM,EAAE,sBAAmB,EAC9B,CAAI,KAAiB,QAAQ,OAAO,OAAO,GAAM,EAAc,KAC7D,EAAO,IAAI,EAAc,CAAE,QAAQ,EAAK,aAAa,EAAc;GAGvE;AAOF,QALA,EAAU,EAAE,SACV,EAAS,QAAQ,GAAM;EAAE,iBAAiB;EAAO,YAAY;EAAM,CAAC,QACvD,EAAS,YAAY,EAClC,EAEK"}
@@ -1,14 +0,0 @@
1
- import { useRef as e } from "./ref.js";
2
- import { useEffect as t } from "./effect.js";
3
- import { useHost as n } from "./host.js";
4
- //#region src/hooks/child.ts
5
- function r(r) {
6
- let i = n(), a = e(0), o = new MutationObserver((e) => {
7
- e.some((e) => e.type === "childList") && (a.value = (a.value + 1) % (2 ** 53 - 1));
8
- });
9
- t([], () => (o.observe(i, { childList: !0 }), () => o.disconnect())), t([a], () => r());
10
- }
11
- //#endregion
12
- export { r as useChildEffect };
13
-
14
- //# sourceMappingURL=child.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"child.js","names":[],"sources":["../../src/hooks/child.ts"],"sourcesContent":["import { useEffect } from './effect.ts';\nimport { useHost } from './host.ts';\nimport { useRef } from './ref.ts';\n\n/** React to child list changes (non-recursive). */\nexport function useChildEffect(callback: () => (() => void) | void): void {\n const host = useHost();\n const ref = useRef(0);\n\n const observer = new MutationObserver((mutation) => {\n if (mutation.some((m) => m.type === 'childList')) {\n ref.value = (ref.value + 1) % Number.MAX_SAFE_INTEGER;\n }\n });\n\n useEffect([], () => {\n observer.observe(host, { childList: true });\n return () => observer.disconnect();\n });\n\n useEffect([ref], () => {\n return callback();\n });\n}\n"],"mappings":";;;;AAKA,SAAgB,EAAe,GAA2C;CACxE,IAAM,IAAO,GAAS,EAChB,IAAM,EAAO,EAAE,EAEf,IAAW,IAAI,kBAAkB,MAAa;AAClD,EAAI,EAAS,MAAM,MAAM,EAAE,SAAS,YAAY,KAC9C,EAAI,SAAS,EAAI,QAAQ;GAE3B;AAOF,CALA,EAAU,EAAE,SACV,EAAS,QAAQ,GAAM,EAAE,WAAW,IAAM,CAAC,QAC9B,EAAS,YAAY,EAClC,EAEF,EAAU,CAAC,EAAI,QACN,GAAU,CACjB"}
@@ -1,3 +0,0 @@
1
- import { type Controller } from '../internal/controller.ts';
2
- /** @internal Get the controller of the currently rendering component. */
3
- export declare function useController(): Controller;
@@ -1,11 +0,0 @@
1
- import { getController as e } from "../internal/controller.js";
2
- //#region src/hooks/controller.ts
3
- function t() {
4
- let t = e();
5
- if (!t) throw Error("hooks must be called by a render function");
6
- return t;
7
- }
8
- //#endregion
9
- export { t as useController };
10
-
11
- //# sourceMappingURL=controller.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"controller.js","names":[],"sources":["../../src/hooks/controller.ts"],"sourcesContent":["import { type Controller, getController } from '../internal/controller.ts';\n\n/** @internal Get the controller of the currently rendering component. */\nexport function useController(): Controller {\n const controller = getController();\n if (!controller) throw new Error('hooks must be called by a render function');\n return controller;\n}\n"],"mappings":";;AAGA,SAAgB,IAA4B;CAC1C,IAAM,IAAa,GAAe;AAClC,KAAI,CAAC,EAAY,OAAU,MAAM,4CAA4C;AAC7E,QAAO"}
@@ -1,9 +0,0 @@
1
- import { useController as e } from "./controller.js";
2
- //#region src/hooks/disconnect.ts
3
- function t(t) {
4
- e().onDisconnect.push(t);
5
- }
6
- //#endregion
7
- export { t as useDisconnectCallback };
8
-
9
- //# sourceMappingURL=disconnect.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"disconnect.js","names":[],"sources":["../../src/hooks/disconnect.ts"],"sourcesContent":["import { useController } from './controller.ts';\n\n/** Register a callback for disconnections. */\nexport function useDisconnectCallback(callback: () => void): void {\n useController().onDisconnect.push(callback);\n}\n"],"mappings":";;AAGA,SAAgB,EAAsB,GAA4B;AAChE,IAAe,CAAC,aAAa,KAAK,EAAS"}
@@ -1,9 +0,0 @@
1
- import { useController as e } from "./controller.js";
2
- //#region src/hooks/document.ts
3
- function t() {
4
- return e().refDocument;
5
- }
6
- //#endregion
7
- export { t as useDocument };
8
-
9
- //# sourceMappingURL=document.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"document.js","names":[],"sources":["../../src/hooks/document.ts"],"sourcesContent":["import { useController } from './controller.ts';\nimport type { ReadonlyRef } from './ref.ts';\n\n/** Use a reference (reactive state) bound to the owner document. */\nexport function useDocument(): ReadonlyRef<Document> {\n return useController().refDocument;\n}\n"],"mappings":";;AAIA,SAAgB,IAAqC;AACnD,QAAO,GAAe,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"effect.js","names":[],"sources":["../../src/hooks/effect.ts"],"sourcesContent":["import { useController } from './controller.ts';\nimport { useDisconnectCallback } from './disconnect.ts';\nimport type { ReadonlyRef, RefValues } from './ref.ts';\n\n/** React to observable (reference) changes. */\nexport function useEffect<const TDeps extends readonly ReadonlyRef<any>[]>(\n deps: TDeps,\n callback: (...values: RefValues<TDeps>) => (() => void) | void,\n): void {\n let cleanupCallback: (() => void) | void;\n let values: any[] | undefined;\n\n const cleanup = () => {\n const callback = cleanupCallback;\n cleanupCallback = undefined;\n callback?.();\n };\n\n useController().onNotify.push((): void => {\n const newValues = deps.map((dep) => dep.value);\n if (values?.length === newValues.length && values?.every((value, i) => value === newValues[i])) return;\n values = newValues;\n cleanup();\n cleanupCallback = callback(...(values as any));\n });\n\n useDisconnectCallback(cleanup);\n}\n"],"mappings":";;;AAKA,SAAgB,EACd,GACA,GACM;CACN,IAAI,GACA,GAEE,UAAgB;EACpB,IAAM,IAAW;AAEjB,EADA,IAAkB,KAAA,GAClB,KAAY;;AAWd,CARA,GAAe,CAAC,SAAS,WAAiB;EACxC,IAAM,IAAY,EAAK,KAAK,MAAQ,EAAI,MAAM;AAC1C,KAAQ,WAAW,EAAU,UAAU,GAAQ,OAAO,GAAO,MAAM,MAAU,EAAU,GAAG,KAC9F,IAAS,GACT,GAAS,EACT,IAAkB,EAAS,GAAI,EAAe;GAC9C,EAEF,EAAsB,EAAQ"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"form.js","names":[],"sources":["../../src/hooks/form.ts"],"sourcesContent":["import type { Controller } from '../internal/controller.ts';\nimport { useController } from './controller.ts';\nimport type { ReadonlyRef } from './ref.ts';\n\n/** Use a reference (reactive state) bound to the associated form. */\nexport function useForm(): ReadonlyRef<HTMLFormElement | null> {\n return useFormAssociated().refForm;\n}\n\n/** Use a reference (reactive state) bound to the form disabled state. */\nexport function useFormDisabled(): ReadonlyRef<boolean> {\n return useFormAssociated().refDisabled;\n}\n\n/** Register a callback for form resets. */\nexport function useFormResetCallback(callback: () => void): void {\n useFormAssociated().onReset.push(callback);\n}\n\n/** Register a callback for form restorations. */\nexport function useFormRestoreCallback(\n callback: (state: string | File | FormData, reason: 'restore' | 'autocomplete') => void,\n): void {\n useFormAssociated().onRestore.push(callback);\n}\n\nfunction useFormAssociated(): Controller['formAssociated'] & {} {\n const { formAssociated } = useController();\n if (!formAssociated) throw new Error('form hooks must be called in a form-associated component');\n return formAssociated;\n}\n"],"mappings":";;AAKA,SAAgB,IAA+C;AAC7D,QAAO,GAAmB,CAAC;;AAI7B,SAAgB,IAAwC;AACtD,QAAO,GAAmB,CAAC;;AAI7B,SAAgB,EAAqB,GAA4B;AAC/D,IAAmB,CAAC,QAAQ,KAAK,EAAS;;AAI5C,SAAgB,EACd,GACM;AACN,IAAmB,CAAC,UAAU,KAAK,EAAS;;AAG9C,SAAS,IAAuD;CAC9D,IAAM,EAAE,sBAAmB,GAAe;AAC1C,KAAI,CAAC,EAAgB,OAAU,MAAM,2DAA2D;AAChG,QAAO"}
@@ -1,9 +0,0 @@
1
- import { useController as e } from "./controller.js";
2
- //#region src/hooks/host.ts
3
- function t() {
4
- return e().host;
5
- }
6
- //#endregion
7
- export { t as useHost };
8
-
9
- //# sourceMappingURL=host.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"host.js","names":[],"sources":["../../src/hooks/host.ts"],"sourcesContent":["import { useController } from './controller.ts';\n\n/** Use the component host element. */\nexport function useHost(): HTMLElement {\n return useController().host;\n}\n"],"mappings":";;AAGA,SAAgB,IAAuB;AACrC,QAAO,GAAe,CAAC"}
@@ -1,9 +0,0 @@
1
- import { useController as e } from "./controller.js";
2
- //#region src/hooks/internals.ts
3
- function t() {
4
- return e().attachInternals();
5
- }
6
- //#endregion
7
- export { t as useElementInternals };
8
-
9
- //# sourceMappingURL=internals.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"internals.js","names":[],"sources":["../../src/hooks/internals.ts"],"sourcesContent":["import { useController } from './controller.ts';\n\n/** Use the element internals. */\nexport function useElementInternals(): ElementInternals {\n return useController().attachInternals();\n}\n"],"mappings":";;AAGA,SAAgB,IAAwC;AACtD,QAAO,GAAe,CAAC,iBAAiB"}
@@ -1,9 +0,0 @@
1
- import { useController as e } from "./controller.js";
2
- //#region src/hooks/parent.ts
3
- function t() {
4
- return e().refParent;
5
- }
6
- //#endregion
7
- export { t as useParent };
8
-
9
- //# sourceMappingURL=parent.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"parent.js","names":[],"sources":["../../src/hooks/parent.ts"],"sourcesContent":["import { useController } from './controller.ts';\nimport type { ReadonlyRef } from './ref.ts';\n\n/** Use a reference (reactive state) bound to the parent node. */\nexport function useParent(): ReadonlyRef<ParentNode | null> {\n return useController().refParent;\n}\n"],"mappings":";;AAIA,SAAgB,IAA4C;AAC1D,QAAO,GAAe,CAAC"}
package/dist/hooks/ref.js DELETED
@@ -1,9 +0,0 @@
1
- import { useController as e } from "./controller.js";
2
- //#region src/hooks/ref.ts
3
- function t(t, n) {
4
- return e().createRef(t, n);
5
- }
6
- //#endregion
7
- export { t as useRef };
8
-
9
- //# sourceMappingURL=ref.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ref.js","names":[],"sources":["../../src/hooks/ref.ts"],"sourcesContent":["import type { $$ref } from '../internal/controller.ts';\nimport { useController } from './controller.ts';\n\nexport interface Ref<T> extends ReadonlyRef<T> {\n value: T;\n}\n\nexport interface ReadonlyRef<T> {\n /** @hidden */\n [$$ref]: unknown;\n readonly value: T;\n}\n\nexport type RefValues<T> = T extends readonly any[]\n ? { [K in keyof T]: T[K] extends ReadonlyRef<infer V> ? V : never }\n : never;\n\n/** Use a reference (reactive state) value. */\nexport function useRef<T>(initialValue: T, onChange?: (value: T) => void): Ref<T> {\n return useController().createRef(initialValue, onChange);\n}\n"],"mappings":";;AAkBA,SAAgB,EAAU,GAAiB,GAAuC;AAChF,QAAO,GAAe,CAAC,UAAU,GAAc,EAAS"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"route.js","names":[],"sources":["../../src/hooks/route.ts"],"sourcesContent":["import { getRouter } from '../router.ts';\nimport { useEffect } from './effect.ts';\nimport { type Ref, useRef } from './ref.ts';\nimport { useStore } from './store.ts';\n\nexport interface RouteOptions {\n readonly match?: 'prefix' | 'exact' | RegExp;\n readonly source?: 'pathname' | 'hash';\n}\n\nexport type RouteMatch = readonly [string, ...string[]] & { readonly groups: Record<string, string> };\n\n/** Use a reference (reactive state) bound to route matching. */\nexport function useRoute(\n path: string | readonly string[],\n { match = 'prefix', source = 'pathname' }: RouteOptions = {},\n): Ref<RouteMatch | null> {\n const matchRx = match === 'exact' ? /^$/u : match === 'prefix' ? /^.*$/u : match;\n const paths = Array.isArray(path) ? (path as readonly string[]) : [path as string];\n const refRoute = useStore(getRouter(), (state) => state[source]);\n const refMatch = useRef<RouteMatch | null>(getMatch(refRoute.value));\n\n useEffect([refRoute], (route) => {\n refMatch.value = getMatch(route);\n });\n\n return refMatch;\n\n function getMatch(route: string): RouteMatch | null {\n const prefix = paths.find((path) => route.endsWith(path)) ?? null;\n if (prefix == null) return null;\n route = route.slice(prefix.length);\n return route.match(matchRx) as RouteMatch | null;\n }\n}\n"],"mappings":";;;;;AAaA,SAAgB,EACd,GACA,EAAE,WAAQ,UAAU,YAAS,eAA6B,EAAE,EACpC;CACxB,IAAM,IAAU,MAAU,UAAU,QAAQ,MAAU,WAAW,UAAU,GACrE,IAAQ,MAAM,QAAQ,EAAK,GAAI,IAA6B,CAAC,EAAe,EAC5E,IAAW,EAAS,GAAW,GAAG,MAAU,EAAM,GAAQ,EAC1D,IAAW,EAA0B,EAAS,EAAS,MAAM,CAAC;AAMpE,QAJA,EAAU,CAAC,EAAS,GAAG,MAAU;AAC/B,IAAS,QAAQ,EAAS,EAAM;GAChC,EAEK;CAEP,SAAS,EAAS,GAAkC;EAClD,IAAM,IAAS,EAAM,MAAM,MAAS,EAAM,SAAS,EAAK,CAAC,IAAI;AAG7D,SAFI,KAAU,OAAa,QAC3B,IAAQ,EAAM,MAAM,EAAO,OAAO,EAC3B,EAAM,MAAM,EAAQ"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"store.js","names":[],"sources":["../../src/hooks/store.ts"],"sourcesContent":["import type { Store } from '../store.ts';\nimport { useEffect } from './effect.ts';\nimport { type ReadonlyRef, type Ref, useRef } from './ref.ts';\n\n/** Use a reference (reactive state) bound to a (shared) store. */\nexport function useStore<TState, TValue = TState>(\n store: Store<TState>,\n select: (state: TState) => TValue,\n mutate: (store: Store<TState>, value: TValue) => void,\n): Ref<TValue>;\nexport function useStore<TState, TValue = TState>(\n store: Store<TState>,\n select?: (state: TState) => TValue,\n): ReadonlyRef<TValue>;\nexport function useStore<TState, TValue = TState>(\n store: Store<TState>,\n select: (state: TState) => TValue = (state) => state as unknown as TValue,\n mutate?: (store: Store<TState>, value: TValue) => void,\n): Ref<TValue> {\n const ref = useRef(select(store.state), mutate && ((value) => mutate(store, value)));\n useEffect([], () => store.subscribe((state) => (ref.value = select(state))));\n return ref;\n}\n"],"mappings":";;;AAcA,SAAgB,EACd,GACA,KAAqC,MAAU,GAC/C,GACa;CACb,IAAM,IAAM,EAAO,EAAO,EAAM,MAAM,EAAE,OAAY,MAAU,EAAO,GAAO,EAAM,EAAE;AAEpF,QADA,EAAU,EAAE,QAAQ,EAAM,WAAW,MAAW,EAAI,QAAQ,EAAO,EAAM,CAAE,CAAC,EACrE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"callbacks.js","names":[],"sources":["../../src/internal/callbacks.ts"],"sourcesContent":["export interface Callbacks<TArgs extends unknown[] = []> {\n readonly push: (callback: (...args: TArgs) => void) => () => void;\n readonly run: (...args: TArgs) => void;\n readonly runAndClear: (...args: TArgs) => void;\n readonly clear: () => void;\n}\n\nexport function createCallbacks<TArgs extends unknown[] = []>(): Callbacks<TArgs> {\n const callbacks = new Set<(...args: TArgs) => void>();\n\n const self: Callbacks<TArgs> = {\n push: (callback) => {\n callbacks.add(callback);\n return () => callbacks.delete(callback);\n },\n run: (...args) => {\n const errors: unknown[] = [];\n const callbacksCopy = [...callbacks];\n\n for (const callback of callbacksCopy) {\n try {\n callback(...args);\n } catch (error: unknown) {\n errors.push(error);\n }\n }\n\n if (errors.length > 0) throw new AggregateError(errors);\n },\n runAndClear: (...args: TArgs) => {\n try {\n self.run(...args);\n } finally {\n self.clear();\n }\n },\n clear: () => {\n callbacks.clear();\n },\n };\n\n return self;\n}\n"],"mappings":";AAOA,SAAgB,IAAkE;CAChF,IAAM,oBAAY,IAAI,KAA+B,EAE/C,IAAyB;EAC7B,OAAO,OACL,EAAU,IAAI,EAAS,QACV,EAAU,OAAO,EAAS;EAEzC,MAAM,GAAG,MAAS;GAChB,IAAM,IAAoB,EAAE,EACtB,IAAgB,CAAC,GAAG,EAAU;AAEpC,QAAK,IAAM,KAAY,EACrB,KAAI;AACF,MAAS,GAAG,EAAK;YACV,GAAgB;AACvB,MAAO,KAAK,EAAM;;AAItB,OAAI,EAAO,SAAS,EAAG,OAAU,eAAe,EAAO;;EAEzD,cAAc,GAAG,MAAgB;AAC/B,OAAI;AACF,MAAK,IAAI,GAAG,EAAK;aACT;AACR,MAAK,OAAO;;;EAGhB,aAAa;AACX,KAAU,OAAO;;EAEpB;AAED,QAAO"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"controller.js","names":[],"sources":["../../src/internal/controller.ts"],"sourcesContent":["import { type ReadonlyRef, type Ref } from '../hooks/ref.ts';\nimport { type Callbacks, createCallbacks } from './callbacks.ts';\n\nexport interface Controller {\n readonly host: HTMLElement;\n readonly onNotify: Callbacks;\n readonly onDisconnect: Callbacks;\n readonly refDocument: ReadonlyRef<Document>;\n readonly refParent: ReadonlyRef<ParentNode | null>;\n readonly formAssociated:\n | {\n readonly refForm: ReadonlyRef<HTMLFormElement | null>;\n readonly refDisabled: ReadonlyRef<boolean>;\n readonly onReset: Callbacks;\n readonly onRestore: Callbacks<[state: string | File | FormData, reason: 'restore' | 'autocomplete']>;\n }\n | undefined;\n readonly createRef: <T>(value: T, onChange?: (value: T) => void) => Ref<T>;\n readonly attachInternals: () => ElementInternals;\n readonly connectedCallback: () => void;\n readonly connectedMoveCallback: () => void;\n readonly disconnectedCallback: () => void;\n readonly adoptedCallback: () => void;\n readonly formDisabledCallback: (disabled: boolean) => void;\n readonly formResetCallback: () => void;\n readonly formStateRestoreCallback: (state: string | File | FormData, reason: 'restore' | 'autocomplete') => void;\n}\n\nexport interface ControllerConfig {\n readonly host: HTMLElement;\n readonly formAssociated: boolean;\n readonly render: (controller: Controller) => void;\n readonly attachInternals: () => ElementInternals;\n}\n\nexport const $$ref = Symbol();\n\nconst controllers: Controller[] = [];\n\nexport function getController(): Controller | undefined {\n return controllers.at(-1);\n}\n\nexport function createController({ host, formAssociated, render, attachInternals }: ControllerConfig): Controller {\n let notifying = false;\n let connected = false;\n let internals: ElementInternals | undefined;\n\n let deferredFormUpdate:\n | { readonly type: 'reset' }\n | { readonly type: 'restore'; state: string | File | FormData; reason: 'restore' | 'autocomplete' }\n | undefined;\n\n const onNotify = createCallbacks();\n\n const createRef = <T>(initialValue: T, onChange?: (value: T) => void): Ref<T> => {\n let value = initialValue;\n\n return {\n [$$ref]: true,\n get value() {\n return value;\n },\n set value(newValue) {\n if (newValue === value) return;\n value = newValue;\n onChange?.(value);\n if (!connected || notifying) return;\n notifying = true;\n\n queueMicrotask(() => {\n notifying = false;\n onNotify.run();\n });\n },\n };\n };\n\n const controller = {\n host,\n onNotify,\n onDisconnect: createCallbacks(),\n refDocument: createRef(host.ownerDocument),\n refParent: createRef(host.parentNode),\n formAssociated: formAssociated\n ? {\n refForm: createRef<HTMLFormElement | null>(null),\n refDisabled: createRef(false),\n onReset: createCallbacks(),\n onRestore: createCallbacks(),\n }\n : undefined,\n createRef,\n attachInternals: () => {\n return (internals ??= attachInternals());\n },\n connectedCallback: () => {\n connected = true;\n controller.refParent.value = host.parentNode;\n\n try {\n controllers.push(controller);\n render(controller);\n } finally {\n controllers.pop();\n }\n\n if (deferredFormUpdate?.type === 'reset') {\n controller.formAssociated?.onReset.run();\n } else if (deferredFormUpdate?.type === 'restore') {\n controller.formAssociated?.onRestore.run(deferredFormUpdate.state, deferredFormUpdate.reason);\n }\n\n controller.onNotify.run();\n },\n connectedMoveCallback: () => {\n controller.refParent.value = host.parentNode;\n controller.onNotify.run();\n },\n disconnectedCallback: () => {\n controller.onNotify.clear();\n controller.formAssociated?.onReset.clear();\n controller.formAssociated?.onRestore.clear();\n controller.onDisconnect.runAndClear();\n },\n adoptedCallback: () => {\n controller.refDocument.value = host.ownerDocument;\n controller.onNotify.run();\n },\n formDisabledCallback: (disabled: boolean) => {\n if (!controller.formAssociated) return;\n controller.formAssociated.refDisabled.value = disabled;\n controller.onNotify.run();\n },\n formResetCallback: () => {\n if (!controller.formAssociated) return;\n if (connected) controller.formAssociated.onReset.run();\n else deferredFormUpdate = { type: 'reset' };\n },\n formStateRestoreCallback: (state, reason) => {\n if (!controller.formAssociated) return;\n if (connected) controller.formAssociated.onRestore.run(state, reason);\n else deferredFormUpdate = { type: 'restore', state, reason };\n },\n } satisfies Controller;\n\n return controller;\n}\n"],"mappings":";;AAmCA,IAAa,IAAQ,QAAQ,EAEvB,IAA4B,EAAE;AAEpC,SAAgB,IAAwC;AACtD,QAAO,EAAY,GAAG,GAAG;;AAG3B,SAAgB,EAAiB,EAAE,SAAM,mBAAgB,WAAQ,sBAAiD;CAChH,IAAI,IAAY,IACZ,IAAY,IACZ,GAEA,GAKE,IAAW,GAAiB,EAE5B,KAAgB,GAAiB,MAA0C;EAC/E,IAAI,IAAQ;AAEZ,SAAO;IACJ,IAAQ;GACT,IAAI,QAAQ;AACV,WAAO;;GAET,IAAI,MAAM,GAAU;AACd,UAAa,MACjB,IAAQ,GACR,IAAW,EAAM,EACb,GAAC,KAAa,OAClB,IAAY,IAEZ,qBAAqB;AAEnB,KADA,IAAY,IACZ,EAAS,KAAK;MACd;;GAEL;IAGG,IAAa;EACjB;EACA;EACA,cAAc,GAAiB;EAC/B,aAAa,EAAU,EAAK,cAAc;EAC1C,WAAW,EAAU,EAAK,WAAW;EACrC,gBAAgB,IACZ;GACE,SAAS,EAAkC,KAAK;GAChD,aAAa,EAAU,GAAM;GAC7B,SAAS,GAAiB;GAC1B,WAAW,GAAiB;GAC7B,GACD,KAAA;EACJ;EACA,uBACU,MAAc,GAAiB;EAEzC,yBAAyB;AAEvB,GADA,IAAY,IACZ,EAAW,UAAU,QAAQ,EAAK;AAElC,OAAI;AAEF,IADA,EAAY,KAAK,EAAW,EAC5B,EAAO,EAAW;aACV;AACR,MAAY,KAAK;;AASnB,GANI,GAAoB,SAAS,UAC/B,EAAW,gBAAgB,QAAQ,KAAK,GAC/B,GAAoB,SAAS,aACtC,EAAW,gBAAgB,UAAU,IAAI,EAAmB,OAAO,EAAmB,OAAO,EAG/F,EAAW,SAAS,KAAK;;EAE3B,6BAA6B;AAE3B,GADA,EAAW,UAAU,QAAQ,EAAK,YAClC,EAAW,SAAS,KAAK;;EAE3B,4BAA4B;AAI1B,GAHA,EAAW,SAAS,OAAO,EAC3B,EAAW,gBAAgB,QAAQ,OAAO,EAC1C,EAAW,gBAAgB,UAAU,OAAO,EAC5C,EAAW,aAAa,aAAa;;EAEvC,uBAAuB;AAErB,GADA,EAAW,YAAY,QAAQ,EAAK,eACpC,EAAW,SAAS,KAAK;;EAE3B,uBAAuB,MAAsB;AACtC,KAAW,mBAChB,EAAW,eAAe,YAAY,QAAQ,GAC9C,EAAW,SAAS,KAAK;;EAE3B,yBAAyB;AAClB,KAAW,mBACZ,IAAW,EAAW,eAAe,QAAQ,KAAK,GACjD,IAAqB,EAAE,MAAM,SAAS;;EAE7C,2BAA2B,GAAO,MAAW;AACtC,KAAW,mBACZ,IAAW,EAAW,eAAe,UAAU,IAAI,GAAO,EAAO,GAChE,IAAqB;IAAE,MAAM;IAAW;IAAO;IAAQ;;EAE/D;AAED,QAAO"}
package/dist/router.js DELETED
@@ -1,35 +0,0 @@
1
- import { createStore as e } from "./store.js";
2
- //#region src/router.ts
3
- function t() {
4
- return n ??= r();
5
- }
6
- var n;
7
- function r() {
8
- let t = e({
9
- pathname: window.location.pathname,
10
- hash: window.location.hash
11
- }), n = () => {
12
- let e = t.state;
13
- t.state.pathname !== window.location.pathname && (e = {
14
- ...e,
15
- pathname: window.location.pathname
16
- }), t.state.hash !== window.location.hash && (e = {
17
- ...e,
18
- hash: window.location.hash
19
- }), t.state = e;
20
- };
21
- return Object.defineProperties(history, Object.fromEntries(["pushState", "replaceState"].map((e) => {
22
- let t = history[e].bind(history);
23
- return [e, {
24
- value: (...e) => {
25
- t(...e), n();
26
- },
27
- enumerable: !0,
28
- configurable: !0
29
- }];
30
- }))), window.addEventListener("popstate", n), t;
31
- }
32
- //#endregion
33
- export { t as getRouter };
34
-
35
- //# sourceMappingURL=router.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"router.js","names":[],"sources":["../src/router.ts"],"sourcesContent":["import { createStore, type Store } from './store.ts';\n\nexport interface RouterState {\n readonly pathname: string;\n readonly hash: string;\n}\n\n/**\n * Get a router {@link Store} that is updated when the client side route (aka:\n * `History`) changes. This method returns the same store every time it is\n * called (ie. a singleton).\n */\nexport function getRouter(): Store<RouterState> {\n return (singleton ??= createRouter());\n}\n\nlet singleton: Store<RouterState> | undefined;\n\nfunction createRouter(): Store<RouterState> {\n const store = createStore<RouterState>({\n pathname: window.location.pathname,\n hash: window.location.hash,\n });\n\n const onUpdate = (): void => {\n let state = store.state;\n\n if (store.state.pathname !== window.location.pathname) {\n state = { ...state, pathname: window.location.pathname };\n }\n\n if (store.state.hash !== window.location.hash) {\n state = { ...state, hash: window.location.hash };\n }\n\n store.state = state;\n };\n\n Object.defineProperties(\n history,\n Object.fromEntries(\n (['pushState', 'replaceState'] as const).map((method: 'pushState' | 'replaceState') => {\n const original = history[method].bind(history) as History['pushState'] & History['replaceState'];\n const descriptor: PropertyDescriptor = {\n value: (...args: Parameters<typeof original>) => {\n original(...args);\n onUpdate();\n },\n enumerable: true,\n configurable: true,\n };\n\n return [method, descriptor];\n }),\n ),\n );\n\n window.addEventListener('popstate', onUpdate);\n\n return store;\n}\n"],"mappings":";;AAYA,SAAgB,IAAgC;AAC9C,QAAQ,MAAc,GAAc;;AAGtC,IAAI;AAEJ,SAAS,IAAmC;CAC1C,IAAM,IAAQ,EAAyB;EACrC,UAAU,OAAO,SAAS;EAC1B,MAAM,OAAO,SAAS;EACvB,CAAC,EAEI,UAAuB;EAC3B,IAAI,IAAQ,EAAM;AAUlB,EARI,EAAM,MAAM,aAAa,OAAO,SAAS,aAC3C,IAAQ;GAAE,GAAG;GAAO,UAAU,OAAO,SAAS;GAAU,GAGtD,EAAM,MAAM,SAAS,OAAO,SAAS,SACvC,IAAQ;GAAE,GAAG;GAAO,MAAM,OAAO,SAAS;GAAM,GAGlD,EAAM,QAAQ;;AAwBhB,QArBA,OAAO,iBACL,SACA,OAAO,YACJ,CAAC,aAAa,eAAe,CAAW,KAAK,MAAyC;EACrF,IAAM,IAAW,QAAQ,GAAQ,KAAK,QAAQ;AAU9C,SAAO,CAAC,GAAQ;GARd,QAAQ,GAAG,MAAsC;AAE/C,IADA,EAAS,GAAG,EAAK,EACjB,GAAU;;GAEZ,YAAY;GACZ,cAAc;GAGA,CAAW;GAC3B,CACH,CACF,EAED,OAAO,iBAAiB,YAAY,EAAS,EAEtC"}
package/dist/store.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"store.js","names":[],"sources":["../src/store.ts"],"sourcesContent":["import { createCallbacks } from './internal/callbacks.ts';\n\nexport interface Store<TState> {\n state: TState;\n subscribe: (callback: (state: TState) => void) => () => void;\n}\n\n/** Create a new store containing an observable state. */\nexport function createStore<TState>(initialState: TState): Store<TState> {\n const callbacks = createCallbacks();\n let state = initialState;\n\n return {\n get state() {\n return state;\n },\n set state(newState) {\n if (newState === state) return;\n state = newState;\n callbacks.run();\n },\n subscribe: (callback) => callbacks.push(() => callback(state)),\n };\n}\n"],"mappings":";;AAQA,SAAgB,EAAoB,GAAqC;CACvE,IAAM,IAAY,GAAiB,EAC/B,IAAQ;AAEZ,QAAO;EACL,IAAI,QAAQ;AACV,UAAO;;EAET,IAAI,MAAM,GAAU;AACd,SAAa,MACjB,IAAQ,GACR,EAAU,KAAK;;EAEjB,YAAY,MAAa,EAAU,WAAW,EAAS,EAAM,CAAC;EAC/D"}
File without changes
File without changes
File without changes