@seahax/elemental 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -25,6 +25,7 @@ import {
25
25
  useRoute,
26
26
  useLoading,
27
27
  useEffect,
28
+ useChildEffect,
28
29
  h,
29
30
  } from '@seahax/elemental';
30
31
 
@@ -50,7 +51,7 @@ export const MyComponent = defineComponent((shadow) => {
50
51
  });
51
52
  const globalStateRef = useStore(myStore, select, mutate);
52
53
  const [dataValueRef, ...] = useAttributes('data-value', ...);
53
- const [routeMatchRef, routeStateRef] = useRoute('/path/', {
54
+ const routeMatchRef = useRoute('/path/', {
54
55
  match: 'prefix', // 'exact' | 'prefix' | RegExp
55
56
  source: 'pathname', // 'pathname' | 'hash'
56
57
  });
@@ -83,6 +84,18 @@ export const MyComponent = defineComponent((shadow) => {
83
84
  // is disconnected from the document.
84
85
  };
85
86
  });
87
+
88
+ // React to child list changes.
89
+ useChildEffect(() => {
90
+ // Reactive code runs when the component is connected to the document,
91
+ // and when the children of the component change. Access the current
92
+ // children using the `shadow.host.children` property.
93
+
94
+ return () => {
95
+ // Cleanup before the next effect callback and after the component
96
+ // is disconnected from the document.
97
+ };
98
+ });
86
99
  });
87
100
  ```
88
101
 
@@ -3,5 +3,7 @@ import { type ReadonlyRef, type Ref, type RefValues } from '../component.ts';
3
3
  export declare function useRef<T>(initialValue: T, onChange?: (value: T) => void): Ref<T>;
4
4
  /** React to observable (reference) changes. */
5
5
  export declare function useEffect<const TDeps extends readonly ReadonlyRef<any>[]>(deps: TDeps, callback: (...values: RefValues<TDeps>) => (() => void) | void): void;
6
+ /** React to child list changes (non-recursive). */
7
+ export declare function useChildEffect(callback: () => (() => void) | void): void;
6
8
  /** Observe attribute changes. */
7
9
  export declare function useAttributes<TName extends string>(...names: TName[]): Readonly<Record<TName, Ref<string | null>>>;
@@ -3,36 +3,42 @@ import { $$renderContextStack as t } from "../internal/constants.js";
3
3
  import "../component.js";
4
4
  //#region src/hooks/core.ts
5
5
  function n(e, t) {
6
- return a().useRef(e, t);
6
+ return o().useRef(e, t);
7
7
  }
8
8
  function r(t, n) {
9
- let { onSetRef: r, onDisconnect: i } = a(), o = e(), s = () => o.run({ clear: !0 }), c;
9
+ let { onSetRef: r, onDisconnect: i } = o(), a = e(), s = () => a.run({ clear: !0 }), c;
10
10
  r.push(() => {
11
11
  let e = t.map((e) => e.value);
12
12
  if (c?.length === e.length && c?.every((t, n) => t === e[n])) return;
13
13
  c = e, s();
14
14
  let r = n(...c);
15
- r && o.push(() => r());
15
+ r && a.push(() => r());
16
16
  }), i.push(s);
17
17
  }
18
- function i(...e) {
18
+ function i(e) {
19
+ let { host: t } = o(), i = n(0), a = new MutationObserver((e) => {
20
+ e.some((e) => e.type === "childList") && (i.value = (i.value + 1) % (2 ** 53 - 1));
21
+ });
22
+ r([], () => (a.observe(t, { childList: !0 }), () => a.disconnect())), r([i], () => e());
23
+ }
24
+ function a(...e) {
19
25
  if (e.length === 0) return {};
20
- let { host: t } = a(), i = Object.fromEntries(e.map((e) => [e, n(t.getAttribute(e), (n) => {
26
+ let { host: t } = o(), i = Object.fromEntries(e.map((e) => [e, n(t.getAttribute(e), (n) => {
21
27
  n == null ? t.removeAttribute(e) : t.setAttribute(e, n);
22
- })])), o = new MutationObserver((e) => {
28
+ })])), a = new MutationObserver((e) => {
23
29
  for (let { attributeName: n } of e) n != null && Object.hasOwn(i, n) && (i[n].value = t.getAttribute(n));
24
30
  });
25
- return r([], () => (o.observe(t, {
31
+ return r([], () => (a.observe(t, {
26
32
  attributeFilter: e,
27
33
  attributes: !0
28
- }), () => o.disconnect())), i;
34
+ }), () => a.disconnect())), i;
29
35
  }
30
- function a() {
36
+ function o() {
31
37
  let e = window[t].at(-1);
32
38
  if (!e) throw Error("hooks must be called inside a render function");
33
39
  return e;
34
40
  }
35
41
  //#endregion
36
- export { i as useAttributes, r as useEffect, n as useRef };
42
+ export { a as useAttributes, i as useChildEffect, r as useEffect, n as useRef };
37
43
 
38
44
  //# sourceMappingURL=core.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"core.js","names":[],"sources":["../../src/hooks/core.ts"],"sourcesContent":["import { type ReadonlyRef, type Ref, type RefValues } from '../component.ts';\nimport { createCallbacks } from '../internal/callbacks.ts';\nimport { $$renderContextStack } from '../internal/constants.ts';\n\n/** Create an observable value. */\nexport function useRef<T>(initialValue: T, onChange?: (value: T) => void): Ref<T> {\n return getHookContext().useRef(initialValue, onChange);\n}\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 const { onSetRef, onDisconnect } = getHookContext();\n const cleanupCallback = createCallbacks();\n const cleanup = (): void => cleanupCallback.run({ clear: true });\n let values: any[] | undefined;\n\n onSetRef.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 const maybeCleanup = callback(...(values as any));\n if (maybeCleanup) cleanupCallback.push(() => maybeCleanup());\n });\n\n onDisconnect.push(cleanup);\n}\n\n/** Observe attribute changes. */\nexport function useAttributes<TName extends string>(...names: TName[]): Readonly<Record<TName, Ref<string | null>>> {\n if (names.length === 0) return {} as any;\n const { host } = getHookContext();\n\n const refs = Object.fromEntries(\n names.map((name) => [\n name,\n useRef(host.getAttribute(name), (value) => {\n if (value == null) host.removeAttribute(name);\n else host.setAttribute(name, value);\n }),\n ]),\n );\n\n const observer = new MutationObserver((mutation) => {\n for (const { attributeName } of mutation) {\n if (attributeName != null && Object.hasOwn(refs, attributeName)) {\n refs[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 Readonly<Record<TName, Ref<string | null>>>;\n}\n\nfunction getHookContext(): (typeof window)[typeof $$renderContextStack][0] {\n const context = window[$$renderContextStack].at(-1);\n if (!context) throw new Error('hooks must be called inside a render function');\n return context;\n}\n"],"mappings":";;;;AAKA,SAAgB,EAAU,GAAiB,GAAuC;AAChF,QAAO,GAAgB,CAAC,OAAO,GAAc,EAAS;;AAIxD,SAAgB,EACd,GACA,GACM;CACN,IAAM,EAAE,aAAU,oBAAiB,GAAgB,EAC7C,IAAkB,GAAiB,EACnC,UAAsB,EAAgB,IAAI,EAAE,OAAO,IAAM,CAAC,EAC5D;AAWJ,CATA,EAAS,WAAiB;EACxB,IAAM,IAAY,EAAK,KAAK,MAAQ,EAAI,MAAM;AAC9C,MAAI,GAAQ,WAAW,EAAU,UAAU,GAAQ,OAAO,GAAO,MAAM,MAAU,EAAU,GAAG,CAAE;AAEhG,EADA,IAAS,GACT,GAAS;EACT,IAAM,IAAe,EAAS,GAAI,EAAe;AACjD,EAAI,KAAc,EAAgB,WAAW,GAAc,CAAC;GAC5D,EAEF,EAAa,KAAK,EAAQ;;AAI5B,SAAgB,EAAoC,GAAG,GAA6D;AAClH,KAAI,EAAM,WAAW,EAAG,QAAO,EAAE;CACjC,IAAM,EAAE,YAAS,GAAgB,EAE3B,IAAO,OAAO,YAClB,EAAM,KAAK,MAAS,CAClB,GACA,EAAO,EAAK,aAAa,EAAK,GAAG,MAAU;AACzC,EAAI,KAAS,OAAM,EAAK,gBAAgB,EAAK,GACxC,EAAK,aAAa,GAAM,EAAM;GACnC,CACH,CAAC,CACH,EAEK,IAAW,IAAI,kBAAkB,MAAa;AAClD,OAAK,IAAM,EAAE,sBAAmB,EAC9B,CAAI,KAAiB,QAAQ,OAAO,OAAO,GAAM,EAAc,KAC7D,EAAK,GAAgB,QAAQ,EAAK,aAAa,EAAc;GAGjE;AAOF,QALA,EAAU,EAAE,SACV,EAAS,QAAQ,GAAM;EAAE,iBAAiB;EAAO,YAAY;EAAM,CAAC,QACvD,EAAS,YAAY,EAClC,EAEK;;AAGT,SAAS,IAAkE;CACzE,IAAM,IAAU,OAAO,GAAsB,GAAG,GAAG;AACnD,KAAI,CAAC,EAAS,OAAU,MAAM,gDAAgD;AAC9E,QAAO"}
1
+ {"version":3,"file":"core.js","names":[],"sources":["../../src/hooks/core.ts"],"sourcesContent":["import { type ReadonlyRef, type Ref, type RefValues } from '../component.ts';\nimport { createCallbacks } from '../internal/callbacks.ts';\nimport { $$renderContextStack } from '../internal/constants.ts';\n\n/** Create an observable value. */\nexport function useRef<T>(initialValue: T, onChange?: (value: T) => void): Ref<T> {\n return getHookContext().useRef(initialValue, onChange);\n}\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 const { onSetRef, onDisconnect } = getHookContext();\n const cleanupCallback = createCallbacks();\n const cleanup = (): void => cleanupCallback.run({ clear: true });\n let values: any[] | undefined;\n\n onSetRef.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 const maybeCleanup = callback(...(values as any));\n if (maybeCleanup) cleanupCallback.push(() => maybeCleanup());\n });\n\n onDisconnect.push(cleanup);\n}\n\n/** React to child list changes (non-recursive). */\nexport function useChildEffect(callback: () => (() => void) | void): void {\n const { host } = getHookContext();\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\n/** Observe attribute changes. */\nexport function useAttributes<TName extends string>(...names: TName[]): Readonly<Record<TName, Ref<string | null>>> {\n if (names.length === 0) return {} as any;\n const { host } = getHookContext();\n\n const refs = Object.fromEntries(\n names.map((name) => [\n name,\n useRef(host.getAttribute(name), (value) => {\n if (value == null) host.removeAttribute(name);\n else host.setAttribute(name, value);\n }),\n ]),\n );\n\n const observer = new MutationObserver((mutation) => {\n for (const { attributeName } of mutation) {\n if (attributeName != null && Object.hasOwn(refs, attributeName)) {\n refs[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 Readonly<Record<TName, Ref<string | null>>>;\n}\n\nfunction getHookContext(): (typeof window)[typeof $$renderContextStack][0] {\n const context = window[$$renderContextStack].at(-1);\n if (!context) throw new Error('hooks must be called inside a render function');\n return context;\n}\n"],"mappings":";;;;AAKA,SAAgB,EAAU,GAAiB,GAAuC;AAChF,QAAO,GAAgB,CAAC,OAAO,GAAc,EAAS;;AAIxD,SAAgB,EACd,GACA,GACM;CACN,IAAM,EAAE,aAAU,oBAAiB,GAAgB,EAC7C,IAAkB,GAAiB,EACnC,UAAsB,EAAgB,IAAI,EAAE,OAAO,IAAM,CAAC,EAC5D;AAWJ,CATA,EAAS,WAAiB;EACxB,IAAM,IAAY,EAAK,KAAK,MAAQ,EAAI,MAAM;AAC9C,MAAI,GAAQ,WAAW,EAAU,UAAU,GAAQ,OAAO,GAAO,MAAM,MAAU,EAAU,GAAG,CAAE;AAEhG,EADA,IAAS,GACT,GAAS;EACT,IAAM,IAAe,EAAS,GAAI,EAAe;AACjD,EAAI,KAAc,EAAgB,WAAW,GAAc,CAAC;GAC5D,EAEF,EAAa,KAAK,EAAQ;;AAI5B,SAAgB,EAAe,GAA2C;CACxE,IAAM,EAAE,YAAS,GAAgB,EAC3B,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;;AAIJ,SAAgB,EAAoC,GAAG,GAA6D;AAClH,KAAI,EAAM,WAAW,EAAG,QAAO,EAAE;CACjC,IAAM,EAAE,YAAS,GAAgB,EAE3B,IAAO,OAAO,YAClB,EAAM,KAAK,MAAS,CAClB,GACA,EAAO,EAAK,aAAa,EAAK,GAAG,MAAU;AACzC,EAAI,KAAS,OAAM,EAAK,gBAAgB,EAAK,GACxC,EAAK,aAAa,GAAM,EAAM;GACnC,CACH,CAAC,CACH,EAEK,IAAW,IAAI,kBAAkB,MAAa;AAClD,OAAK,IAAM,EAAE,sBAAmB,EAC9B,CAAI,KAAiB,QAAQ,OAAO,OAAO,GAAM,EAAc,KAC7D,EAAK,GAAgB,QAAQ,EAAK,aAAa,EAAc;GAGjE;AAOF,QALA,EAAU,EAAE,SACV,EAAS,QAAQ,GAAM;EAAE,iBAAiB;EAAO,YAAY;EAAM,CAAC,QACvD,EAAS,YAAY,EAClC,EAEK;;AAGT,SAAS,IAAkE;CACzE,IAAM,IAAU,OAAO,GAAsB,GAAG,GAAG;AACnD,KAAI,CAAC,EAAS,OAAU,MAAM,gDAAgD;AAC9E,QAAO"}
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { defineComponent as e } from "./component.js";
2
- import { useAttributes as t, useEffect as n, useRef as r } from "./hooks/core.js";
3
- import { useLoading as i } from "./hooks/loading.js";
4
- import { createStore as a } from "./store.js";
5
- import { getRouter as o } from "./router.js";
6
- import { useStore as s } from "./hooks/store.js";
7
- import { useRoute as c } from "./hooks/route.js";
8
- import { html as l } from "./html.js";
9
- export { a as createStore, e as defineComponent, o as getRouter, l as h, l as html, t as useAttributes, n as useEffect, i as useLoading, r as useRef, c as useRoute, s as useStore };
2
+ import { useAttributes as t, useChildEffect as n, useEffect as r, useRef as i } from "./hooks/core.js";
3
+ import { useLoading as a } from "./hooks/loading.js";
4
+ import { createStore as o } from "./store.js";
5
+ import { getRouter as s } from "./router.js";
6
+ import { useStore as c } from "./hooks/store.js";
7
+ import { useRoute as l } from "./hooks/route.js";
8
+ import { html as u } from "./html.js";
9
+ export { o as createStore, e as defineComponent, s as getRouter, u as h, u as html, t as useAttributes, n as useChildEffect, r as useEffect, a as useLoading, i as useRef, l as useRoute, c as useStore };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seahax/elemental",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Functional, reactive, web component base library.",
5
5
  "repository": {
6
6
  "type": "git",