@vielzeug/craftit 1.0.1 → 2.0.1
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 +112 -401
- package/dist/core/component.cjs +2 -0
- package/dist/core/component.cjs.map +1 -0
- package/dist/core/component.d.ts +172 -0
- package/dist/core/component.d.ts.map +1 -0
- package/dist/core/component.js +2 -0
- package/dist/core/component.js.map +1 -0
- package/dist/core/host.cjs +2 -0
- package/dist/core/host.cjs.map +1 -0
- package/dist/core/host.d.ts +77 -0
- package/dist/core/host.d.ts.map +1 -0
- package/dist/core/host.js +2 -0
- package/dist/core/host.js.map +1 -0
- package/dist/core/internal.cjs +2 -0
- package/dist/core/internal.cjs.map +1 -0
- package/dist/core/internal.d.ts +107 -0
- package/dist/core/internal.d.ts.map +1 -0
- package/dist/core/internal.js +2 -0
- package/dist/core/internal.js.map +1 -0
- package/dist/core/runtime-bindings.cjs +2 -0
- package/dist/core/runtime-bindings.cjs.map +1 -0
- package/dist/core/runtime-bindings.d.ts +6 -0
- package/dist/core/runtime-bindings.d.ts.map +1 -0
- package/dist/core/runtime-bindings.js +2 -0
- package/dist/core/runtime-bindings.js.map +1 -0
- package/dist/core/runtime-lifecycle.cjs +2 -0
- package/dist/core/runtime-lifecycle.cjs.map +1 -0
- package/dist/core/runtime-lifecycle.d.ts +116 -0
- package/dist/core/runtime-lifecycle.d.ts.map +1 -0
- package/dist/core/runtime-lifecycle.js +2 -0
- package/dist/core/runtime-lifecycle.js.map +1 -0
- package/dist/core/runtime.cjs +1 -0
- package/dist/core/runtime.d.ts +3 -0
- package/dist/core/runtime.d.ts.map +1 -0
- package/dist/core/runtime.js +1 -0
- package/dist/core/template-bindings.cjs +2 -0
- package/dist/core/template-bindings.cjs.map +1 -0
- package/dist/core/template-bindings.d.ts +59 -0
- package/dist/core/template-bindings.d.ts.map +1 -0
- package/dist/core/template-bindings.js +2 -0
- package/dist/core/template-bindings.js.map +1 -0
- package/dist/core/template-compiler.cjs +2 -0
- package/dist/core/template-compiler.cjs.map +1 -0
- package/dist/core/template-compiler.d.ts +25 -0
- package/dist/core/template-compiler.d.ts.map +1 -0
- package/dist/core/template-compiler.js +2 -0
- package/dist/core/template-compiler.js.map +1 -0
- package/dist/core/template-dom.cjs +2 -0
- package/dist/core/template-dom.cjs.map +1 -0
- package/dist/core/template-dom.d.ts +13 -0
- package/dist/core/template-dom.d.ts.map +1 -0
- package/dist/core/template-dom.js +2 -0
- package/dist/core/template-dom.js.map +1 -0
- package/dist/core/template-html.cjs +2 -0
- package/dist/core/template-html.cjs.map +1 -0
- package/dist/core/template-html.d.ts +26 -0
- package/dist/core/template-html.d.ts.map +1 -0
- package/dist/core/template-html.js +2 -0
- package/dist/core/template-html.js.map +1 -0
- package/dist/core/template.cjs +2 -0
- package/dist/core/template.cjs.map +1 -0
- package/dist/core/template.d.ts +11 -0
- package/dist/core/template.d.ts.map +1 -0
- package/dist/core/template.js +2 -0
- package/dist/core/template.js.map +1 -0
- package/dist/core/utilities.cjs +2 -0
- package/dist/core/utilities.cjs.map +1 -0
- package/dist/core/utilities.d.ts +68 -0
- package/dist/core/utilities.d.ts.map +1 -0
- package/dist/core/utilities.js +2 -0
- package/dist/core/utilities.js.map +1 -0
- package/dist/craftit.cjs +2 -18
- package/dist/craftit.cjs.map +1 -1
- package/dist/craftit.js +2 -580
- package/dist/craftit.js.map +1 -1
- package/dist/directives/attr.cjs +2 -0
- package/dist/directives/attr.cjs.map +1 -0
- package/dist/directives/attr.d.ts +14 -0
- package/dist/directives/attr.d.ts.map +1 -0
- package/dist/directives/attr.js +2 -0
- package/dist/directives/attr.js.map +1 -0
- package/dist/directives/bind.cjs +2 -0
- package/dist/directives/bind.cjs.map +1 -0
- package/dist/directives/bind.d.ts +30 -0
- package/dist/directives/bind.d.ts.map +1 -0
- package/dist/directives/bind.js +2 -0
- package/dist/directives/bind.js.map +1 -0
- package/dist/directives/choose.cjs +2 -0
- package/dist/directives/choose.cjs.map +1 -0
- package/dist/directives/choose.d.ts +34 -0
- package/dist/directives/choose.d.ts.map +1 -0
- package/dist/directives/choose.js +2 -0
- package/dist/directives/choose.js.map +1 -0
- package/dist/directives/classes.cjs +2 -0
- package/dist/directives/classes.cjs.map +1 -0
- package/dist/directives/classes.d.ts +20 -0
- package/dist/directives/classes.d.ts.map +1 -0
- package/dist/directives/classes.js +2 -0
- package/dist/directives/classes.js.map +1 -0
- package/dist/directives/each.cjs +2 -0
- package/dist/directives/each.cjs.map +1 -0
- package/dist/directives/each.d.ts +68 -0
- package/dist/directives/each.d.ts.map +1 -0
- package/dist/directives/each.js +2 -0
- package/dist/directives/each.js.map +1 -0
- package/dist/directives/index.cjs +1 -0
- package/dist/directives/index.d.ts +14 -0
- package/dist/directives/index.d.ts.map +1 -0
- package/dist/directives/index.js +1 -0
- package/dist/directives/match.cjs +2 -0
- package/dist/directives/match.cjs.map +1 -0
- package/dist/directives/match.d.ts +31 -0
- package/dist/directives/match.d.ts.map +1 -0
- package/dist/directives/match.js +2 -0
- package/dist/directives/match.js.map +1 -0
- package/dist/directives/memo.cjs +2 -0
- package/dist/directives/memo.cjs.map +1 -0
- package/dist/directives/memo.d.ts +23 -0
- package/dist/directives/memo.d.ts.map +1 -0
- package/dist/directives/memo.js +2 -0
- package/dist/directives/memo.js.map +1 -0
- package/dist/directives/on.cjs +2 -0
- package/dist/directives/on.cjs.map +1 -0
- package/dist/directives/on.d.ts +25 -0
- package/dist/directives/on.d.ts.map +1 -0
- package/dist/directives/on.js +2 -0
- package/dist/directives/on.js.map +1 -0
- package/dist/directives/raw.cjs +2 -0
- package/dist/directives/raw.cjs.map +1 -0
- package/dist/directives/raw.d.ts +25 -0
- package/dist/directives/raw.d.ts.map +1 -0
- package/dist/directives/raw.js +2 -0
- package/dist/directives/raw.js.map +1 -0
- package/dist/directives/spread.cjs +2 -0
- package/dist/directives/spread.cjs.map +1 -0
- package/dist/directives/spread.d.ts +14 -0
- package/dist/directives/spread.d.ts.map +1 -0
- package/dist/directives/spread.js +2 -0
- package/dist/directives/spread.js.map +1 -0
- package/dist/directives/style.cjs +2 -0
- package/dist/directives/style.cjs.map +1 -0
- package/dist/directives/style.d.ts +22 -0
- package/dist/directives/style.d.ts.map +1 -0
- package/dist/directives/style.js +2 -0
- package/dist/directives/style.js.map +1 -0
- package/dist/directives/until.cjs +2 -0
- package/dist/directives/until.cjs.map +1 -0
- package/dist/directives/until.d.ts +26 -0
- package/dist/directives/until.d.ts.map +1 -0
- package/dist/directives/until.js +2 -0
- package/dist/directives/until.js.map +1 -0
- package/dist/directives/when.cjs +2 -0
- package/dist/directives/when.cjs.map +1 -0
- package/dist/directives/when.d.ts +17 -0
- package/dist/directives/when.d.ts.map +1 -0
- package/dist/directives/when.js +2 -0
- package/dist/directives/when.js.map +1 -0
- package/dist/index.cjs +1 -2
- package/dist/index.d.ts +10 -265
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -13
- package/dist/labs/a11y.cjs +2 -0
- package/dist/labs/a11y.cjs.map +1 -0
- package/dist/labs/a11y.d.ts +61 -0
- package/dist/labs/a11y.d.ts.map +1 -0
- package/dist/labs/a11y.js +2 -0
- package/dist/labs/a11y.js.map +1 -0
- package/dist/labs/index.d.ts +8 -0
- package/dist/labs/index.d.ts.map +1 -0
- package/dist/labs/list.cjs +2 -0
- package/dist/labs/list.cjs.map +1 -0
- package/dist/labs/list.d.ts +26 -0
- package/dist/labs/list.d.ts.map +1 -0
- package/dist/labs/list.js +2 -0
- package/dist/labs/list.js.map +1 -0
- package/dist/labs/observers.cjs +2 -0
- package/dist/labs/observers.cjs.map +1 -0
- package/dist/labs/observers.d.ts +42 -0
- package/dist/labs/observers.d.ts.map +1 -0
- package/dist/labs/observers.js +2 -0
- package/dist/labs/observers.js.map +1 -0
- package/dist/labs/overlay.cjs +2 -0
- package/dist/labs/overlay.cjs.map +1 -0
- package/dist/labs/overlay.d.ts +35 -0
- package/dist/labs/overlay.d.ts.map +1 -0
- package/dist/labs/overlay.js +2 -0
- package/dist/labs/overlay.js.map +1 -0
- package/dist/labs/selectable.cjs +2 -0
- package/dist/labs/selectable.cjs.map +1 -0
- package/dist/labs/selectable.d.ts +70 -0
- package/dist/labs/selectable.d.ts.map +1 -0
- package/dist/labs/selectable.js +2 -0
- package/dist/labs/selectable.js.map +1 -0
- package/dist/labs/selection.cjs +2 -0
- package/dist/labs/selection.cjs.map +1 -0
- package/dist/labs/selection.d.ts +68 -0
- package/dist/labs/selection.d.ts.map +1 -0
- package/dist/labs/selection.js +2 -0
- package/dist/labs/selection.js.map +1 -0
- package/dist/labs.cjs +1 -0
- package/dist/labs.js +1 -0
- package/dist/test/index.d.ts +2 -0
- package/dist/test/index.d.ts.map +1 -0
- package/dist/test/test.cjs +2 -0
- package/dist/test/test.cjs.map +1 -0
- package/dist/test/test.d.ts +198 -0
- package/dist/test/test.d.ts.map +1 -0
- package/dist/test/test.js +2 -0
- package/dist/test/test.js.map +1 -0
- package/dist/test.cjs +1 -0
- package/dist/test.js +1 -0
- package/package.json +37 -9
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observers.cjs","names":[],"sources":["../../src/labs/observers.ts"],"sourcesContent":["import { signal, type ReadonlySignal } from '@vielzeug/stateit';\n\nimport { onCleanup } from '../core/runtime';\n\n/**\n * Observes an element's content-box size via `ResizeObserver`.\n * Returns a `ReadonlySignal` that updates whenever the dimensions change.\n * Must be called inside an {@link onMount} callback.\n *\n * @example\n * onMount(() => {\n * const size = observeResize(containerRef.value!);\n * effect(() => console.log(size.value.width, size.value.height));\n * });\n */\nexport const observeResize = (el: Element): ReadonlySignal<{ height: number; width: number }> => {\n const size = signal({ height: 0, width: 0 });\n const ro = new ResizeObserver(([entry]) => {\n if (!entry) return;\n\n const box = entry.contentBoxSize[0];\n\n if (box) size.value = { height: box.blockSize, width: box.inlineSize };\n });\n\n ro.observe(el);\n onCleanup(() => ro.disconnect());\n\n return size;\n};\n\n/**\n * Observes an element's intersection with the viewport (or a given root) via\n * `IntersectionObserver`. Returns a `ReadonlySignal` that updates whenever the\n * intersection ratio changes.\n * Must be called inside an {@link onMount} callback.\n *\n * @example\n * onMount(() => {\n * const entry = observeIntersection(cardRef.value!);\n * effect(() => console.log(entry.value.isIntersecting));\n * });\n */\nexport const observeIntersection = (\n el: Element,\n options?: IntersectionObserverInit,\n): ReadonlySignal<IntersectionObserverEntry | null> => {\n const entry = signal<IntersectionObserverEntry | null>(null);\n const io = new IntersectionObserver(([e]) => {\n if (e) entry.value = e;\n }, options);\n\n io.observe(el);\n onCleanup(() => io.disconnect());\n\n return entry;\n};\n\n/**\n * Observes a CSS media query via `window.matchMedia`. Returns a `ReadonlySignal`\n * that is `true` when the query matches and `false` when it does not.\n * Must be called inside an {@link onMount} callback.\n *\n * @example\n * onMount(() => {\n * const prefersReducedMotion = observeMedia('(prefers-reduced-motion: reduce)');\n * effect(() => console.log(prefersReducedMotion.value));\n * });\n */\nexport const observeMedia = (query: string): ReadonlySignal<boolean> => {\n const mql = window.matchMedia(query);\n const matches = signal(mql.matches);\n const handler = (e: MediaQueryListEvent) => {\n matches.value = e.matches;\n };\n\n mql.addEventListener('change', handler);\n onCleanup(() => mql.removeEventListener('change', handler));\n\n return matches;\n};\n"],"mappings":"mHAeA,IAAa,EAAiB,GAAmE,CAC/F,IAAM,GAAA,EAAA,EAAA,QAAc,CAAE,OAAQ,EAAG,MAAO,EAAG,CAAC,CACtC,EAAK,IAAI,gBAAgB,CAAC,KAAW,CACzC,GAAI,CAAC,EAAO,OAEZ,IAAM,EAAM,EAAM,eAAe,GAE7B,IAAK,EAAK,MAAQ,CAAE,OAAQ,EAAI,UAAW,MAAO,EAAI,WAAY,GACtE,CAKF,OAHA,EAAG,QAAQ,EAAG,CACd,EAAA,cAAgB,EAAG,YAAY,CAAC,CAEzB,GAeI,GACX,EACA,IACqD,CACrD,IAAM,GAAA,EAAA,EAAA,QAAiD,KAAK,CACtD,EAAK,IAAI,sBAAsB,CAAC,KAAO,CACvC,IAAG,EAAM,MAAQ,IACpB,EAAQ,CAKX,OAHA,EAAG,QAAQ,EAAG,CACd,EAAA,cAAgB,EAAG,YAAY,CAAC,CAEzB,GAcI,EAAgB,GAA2C,CACtE,IAAM,EAAM,OAAO,WAAW,EAAM,CAC9B,GAAA,EAAA,EAAA,QAAiB,EAAI,QAAQ,CAC7B,EAAW,GAA2B,CAC1C,EAAQ,MAAQ,EAAE,SAMpB,OAHA,EAAI,iBAAiB,SAAU,EAAQ,CACvC,EAAA,cAAgB,EAAI,oBAAoB,SAAU,EAAQ,CAAC,CAEpD"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type ReadonlySignal } from '@vielzeug/stateit';
|
|
2
|
+
/**
|
|
3
|
+
* Observes an element's content-box size via `ResizeObserver`.
|
|
4
|
+
* Returns a `ReadonlySignal` that updates whenever the dimensions change.
|
|
5
|
+
* Must be called inside an {@link onMount} callback.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* onMount(() => {
|
|
9
|
+
* const size = observeResize(containerRef.value!);
|
|
10
|
+
* effect(() => console.log(size.value.width, size.value.height));
|
|
11
|
+
* });
|
|
12
|
+
*/
|
|
13
|
+
export declare const observeResize: (el: Element) => ReadonlySignal<{
|
|
14
|
+
height: number;
|
|
15
|
+
width: number;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Observes an element's intersection with the viewport (or a given root) via
|
|
19
|
+
* `IntersectionObserver`. Returns a `ReadonlySignal` that updates whenever the
|
|
20
|
+
* intersection ratio changes.
|
|
21
|
+
* Must be called inside an {@link onMount} callback.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* onMount(() => {
|
|
25
|
+
* const entry = observeIntersection(cardRef.value!);
|
|
26
|
+
* effect(() => console.log(entry.value.isIntersecting));
|
|
27
|
+
* });
|
|
28
|
+
*/
|
|
29
|
+
export declare const observeIntersection: (el: Element, options?: IntersectionObserverInit) => ReadonlySignal<IntersectionObserverEntry | null>;
|
|
30
|
+
/**
|
|
31
|
+
* Observes a CSS media query via `window.matchMedia`. Returns a `ReadonlySignal`
|
|
32
|
+
* that is `true` when the query matches and `false` when it does not.
|
|
33
|
+
* Must be called inside an {@link onMount} callback.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* onMount(() => {
|
|
37
|
+
* const prefersReducedMotion = observeMedia('(prefers-reduced-motion: reduce)');
|
|
38
|
+
* effect(() => console.log(prefersReducedMotion.value));
|
|
39
|
+
* });
|
|
40
|
+
*/
|
|
41
|
+
export declare const observeMedia: (query: string) => ReadonlySignal<boolean>;
|
|
42
|
+
//# sourceMappingURL=observers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observers.d.ts","sourceRoot":"","sources":["../../src/labs/observers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAIhE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,GAAI,IAAI,OAAO,KAAG,cAAc,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAc3F,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mBAAmB,GAC9B,IAAI,OAAO,EACX,UAAU,wBAAwB,KACjC,cAAc,CAAC,yBAAyB,GAAG,IAAI,CAUjD,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,GAAI,OAAO,MAAM,KAAG,cAAc,CAAC,OAAO,CAWlE,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{onCleanup as e}from"../core/runtime-lifecycle.js";import"../core/runtime.js";import{signal as t}from"@vielzeug/stateit";var n=n=>{let r=t({height:0,width:0}),i=new ResizeObserver(([e])=>{if(!e)return;let t=e.contentBoxSize[0];t&&(r.value={height:t.blockSize,width:t.inlineSize})});return i.observe(n),e(()=>i.disconnect()),r},r=(n,r)=>{let i=t(null),a=new IntersectionObserver(([e])=>{e&&(i.value=e)},r);return a.observe(n),e(()=>a.disconnect()),i},i=n=>{let r=window.matchMedia(n),i=t(r.matches),a=e=>{i.value=e.matches};return r.addEventListener(`change`,a),e(()=>r.removeEventListener(`change`,a)),i};export{r as observeIntersection,i as observeMedia,n as observeResize};
|
|
2
|
+
//# sourceMappingURL=observers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observers.js","names":[],"sources":["../../src/labs/observers.ts"],"sourcesContent":["import { signal, type ReadonlySignal } from '@vielzeug/stateit';\n\nimport { onCleanup } from '../core/runtime';\n\n/**\n * Observes an element's content-box size via `ResizeObserver`.\n * Returns a `ReadonlySignal` that updates whenever the dimensions change.\n * Must be called inside an {@link onMount} callback.\n *\n * @example\n * onMount(() => {\n * const size = observeResize(containerRef.value!);\n * effect(() => console.log(size.value.width, size.value.height));\n * });\n */\nexport const observeResize = (el: Element): ReadonlySignal<{ height: number; width: number }> => {\n const size = signal({ height: 0, width: 0 });\n const ro = new ResizeObserver(([entry]) => {\n if (!entry) return;\n\n const box = entry.contentBoxSize[0];\n\n if (box) size.value = { height: box.blockSize, width: box.inlineSize };\n });\n\n ro.observe(el);\n onCleanup(() => ro.disconnect());\n\n return size;\n};\n\n/**\n * Observes an element's intersection with the viewport (or a given root) via\n * `IntersectionObserver`. Returns a `ReadonlySignal` that updates whenever the\n * intersection ratio changes.\n * Must be called inside an {@link onMount} callback.\n *\n * @example\n * onMount(() => {\n * const entry = observeIntersection(cardRef.value!);\n * effect(() => console.log(entry.value.isIntersecting));\n * });\n */\nexport const observeIntersection = (\n el: Element,\n options?: IntersectionObserverInit,\n): ReadonlySignal<IntersectionObserverEntry | null> => {\n const entry = signal<IntersectionObserverEntry | null>(null);\n const io = new IntersectionObserver(([e]) => {\n if (e) entry.value = e;\n }, options);\n\n io.observe(el);\n onCleanup(() => io.disconnect());\n\n return entry;\n};\n\n/**\n * Observes a CSS media query via `window.matchMedia`. Returns a `ReadonlySignal`\n * that is `true` when the query matches and `false` when it does not.\n * Must be called inside an {@link onMount} callback.\n *\n * @example\n * onMount(() => {\n * const prefersReducedMotion = observeMedia('(prefers-reduced-motion: reduce)');\n * effect(() => console.log(prefersReducedMotion.value));\n * });\n */\nexport const observeMedia = (query: string): ReadonlySignal<boolean> => {\n const mql = window.matchMedia(query);\n const matches = signal(mql.matches);\n const handler = (e: MediaQueryListEvent) => {\n matches.value = e.matches;\n };\n\n mql.addEventListener('change', handler);\n onCleanup(() => mql.removeEventListener('change', handler));\n\n return matches;\n};\n"],"mappings":"+HAeA,IAAa,EAAiB,GAAmE,CAC/F,IAAM,EAAO,EAAO,CAAE,OAAQ,EAAG,MAAO,EAAG,CAAC,CACtC,EAAK,IAAI,gBAAgB,CAAC,KAAW,CACzC,GAAI,CAAC,EAAO,OAEZ,IAAM,EAAM,EAAM,eAAe,GAE7B,IAAK,EAAK,MAAQ,CAAE,OAAQ,EAAI,UAAW,MAAO,EAAI,WAAY,GACtE,CAKF,OAHA,EAAG,QAAQ,EAAG,CACd,MAAgB,EAAG,YAAY,CAAC,CAEzB,GAeI,GACX,EACA,IACqD,CACrD,IAAM,EAAQ,EAAyC,KAAK,CACtD,EAAK,IAAI,sBAAsB,CAAC,KAAO,CACvC,IAAG,EAAM,MAAQ,IACpB,EAAQ,CAKX,OAHA,EAAG,QAAQ,EAAG,CACd,MAAgB,EAAG,YAAY,CAAC,CAEzB,GAcI,EAAgB,GAA2C,CACtE,IAAM,EAAM,OAAO,WAAW,EAAM,CAC9B,EAAU,EAAO,EAAI,QAAQ,CAC7B,EAAW,GAA2B,CAC1C,EAAQ,MAAQ,EAAE,SAMpB,OAHA,EAAI,iBAAiB,SAAU,EAAQ,CACvC,MAAgB,EAAI,oBAAoB,SAAU,EAAQ,CAAC,CAEpD"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
let e=require(`@vielzeug/floatit`);var t=t=>{let n=null,r=()=>typeof t.restoreFocus==`function`?t.restoreFocus():t.restoreFocus??!0,i=()=>{let r=t.positioner;if(n?.(),n=null,!r)return;let i=r.reference(),a=r.floating();if(!i||!a){r.update();return}n=(0,e.autoUpdate)(i,a,r.update)},a=()=>{n?.(),n=null},o=e=>{if(t.isDisabled?.()||t.isOpen())return;let n=e?.reason??`programmatic`;t.setOpen(!0,{reason:n}),i(),requestAnimationFrame(()=>t.positioner?.update()),t.onOpen?.(n)},s=e=>{if(!t.isOpen())return;let n=e?.reason??`programmatic`;t.setOpen(!1,{reason:n}),a(),(e?.restoreFocus??r())&&t.getTriggerElement?.()?.focus(),t.onClose?.(n)};return{bindOutsideClick:(e=document,n=!0)=>{let r=e=>{if(!t.isOpen())return;let n=t.getBoundaryElement(),r=t.getPanelElement?.(),i=e.target,a=typeof e.composedPath==`function`?e.composedPath():[];i&&(n&&(n.contains(i)||a.includes(n))||r&&(r.contains(i)||a.includes(r))||s({reason:`outside-click`}))};return e.addEventListener(`click`,r,n),()=>{e.removeEventListener(`click`,r,n)}},close:s,open:o,toggle:()=>{if(t.isOpen()){s({reason:`toggle`});return}o({reason:`toggle`})}}};exports.createOverlayControl=t;
|
|
2
|
+
//# sourceMappingURL=overlay.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlay.cjs","names":[],"sources":["../../src/labs/overlay.ts"],"sourcesContent":["import { autoUpdate } from '@vielzeug/floatit';\n\nexport type OverlayPositioner = {\n floating: () => HTMLElement | null;\n reference: () => HTMLElement | null;\n update: () => void;\n};\n\nexport type OverlayOpenReason = 'programmatic' | 'toggle' | 'trigger';\n\nexport type OverlayCloseReason = 'escape' | 'outside-click' | 'programmatic' | 'toggle';\n\nexport type OverlayChangeContext = {\n reason: OverlayCloseReason | OverlayOpenReason;\n};\n\nexport type OverlayControlOptions = {\n getBoundaryElement: () => HTMLElement | null;\n getPanelElement?: () => HTMLElement | null;\n getTriggerElement?: () => HTMLElement | null;\n isDisabled?: () => boolean;\n isOpen: () => boolean;\n onClose?: (reason: OverlayCloseReason) => void;\n onOpen?: (reason: OverlayOpenReason) => void;\n positioner?: OverlayPositioner;\n restoreFocus?: boolean | (() => boolean);\n setOpen: (next: boolean, context: OverlayChangeContext) => void;\n};\n\nexport type OverlayControl = {\n bindOutsideClick: (target?: Document | HTMLElement, capture?: boolean) => () => void;\n close: (opts?: { reason?: OverlayCloseReason; restoreFocus?: boolean }) => void;\n open: (opts?: { reason?: OverlayOpenReason }) => void;\n toggle: () => void;\n};\n\nexport const createOverlayControl = (options: OverlayControlOptions): OverlayControl => {\n let cleanupPositioning: (() => void) | null = null;\n\n const shouldRestoreFocus = (): boolean => {\n if (typeof options.restoreFocus === 'function') return options.restoreFocus();\n\n return options.restoreFocus ?? true;\n };\n\n const startPositioning = (): void => {\n const positioner = options.positioner;\n\n cleanupPositioning?.();\n cleanupPositioning = null;\n\n if (!positioner) return;\n\n const reference = positioner.reference();\n const floating = positioner.floating();\n\n if (!reference || !floating) {\n positioner.update();\n\n return;\n }\n\n cleanupPositioning = autoUpdate(reference, floating, positioner.update);\n };\n\n const stopPositioning = (): void => {\n cleanupPositioning?.();\n cleanupPositioning = null;\n };\n\n const open = (opts?: { reason?: OverlayOpenReason }): void => {\n if (options.isDisabled?.()) return;\n\n if (options.isOpen()) return;\n\n const reason = opts?.reason ?? 'programmatic';\n\n options.setOpen(true, { reason });\n startPositioning();\n requestAnimationFrame(() => options.positioner?.update());\n options.onOpen?.(reason);\n };\n\n const close = (opts?: { reason?: OverlayCloseReason; restoreFocus?: boolean }): void => {\n if (!options.isOpen()) return;\n\n const reason = opts?.reason ?? 'programmatic';\n\n options.setOpen(false, { reason });\n stopPositioning();\n\n const restore = opts?.restoreFocus ?? shouldRestoreFocus();\n\n if (restore) options.getTriggerElement?.()?.focus();\n\n options.onClose?.(reason);\n };\n\n const toggle = (): void => {\n if (options.isOpen()) {\n close({ reason: 'toggle' });\n\n return;\n }\n\n open({ reason: 'toggle' });\n };\n\n const bindOutsideClick = (target: Document | HTMLElement = document, capture = true): (() => void) => {\n const handler = (event: Event) => {\n if (!options.isOpen()) return;\n\n const boundary = options.getBoundaryElement();\n const panel = options.getPanelElement?.();\n const eventTarget = event.target as Node | null;\n const path = typeof event.composedPath === 'function' ? event.composedPath() : [];\n\n if (!eventTarget) return;\n\n if (boundary && (boundary.contains(eventTarget) || path.includes(boundary))) return;\n\n if (panel && (panel.contains(eventTarget) || path.includes(panel))) return;\n\n close({ reason: 'outside-click' });\n };\n\n target.addEventListener('click', handler, capture);\n\n return () => {\n target.removeEventListener('click', handler, capture);\n };\n };\n\n return { bindOutsideClick, close, open, toggle };\n};\n"],"mappings":"mCAoCA,IAAa,EAAwB,GAAmD,CACtF,IAAI,EAA0C,KAExC,MACA,OAAO,EAAQ,cAAiB,WAAmB,EAAQ,cAAc,CAEtE,EAAQ,cAAgB,GAG3B,MAA+B,CACnC,IAAM,EAAa,EAAQ,WAK3B,GAHA,KAAsB,CACtB,EAAqB,KAEjB,CAAC,EAAY,OAEjB,IAAM,EAAY,EAAW,WAAW,CAClC,EAAW,EAAW,UAAU,CAEtC,GAAI,CAAC,GAAa,CAAC,EAAU,CAC3B,EAAW,QAAQ,CAEnB,OAGF,GAAA,EAAA,EAAA,YAAgC,EAAW,EAAU,EAAW,OAAO,EAGnE,MAA8B,CAClC,KAAsB,CACtB,EAAqB,MAGjB,EAAQ,GAAgD,CAG5D,GAFI,EAAQ,cAAc,EAEtB,EAAQ,QAAQ,CAAE,OAEtB,IAAM,EAAS,GAAM,QAAU,eAE/B,EAAQ,QAAQ,GAAM,CAAE,SAAQ,CAAC,CACjC,GAAkB,CAClB,0BAA4B,EAAQ,YAAY,QAAQ,CAAC,CACzD,EAAQ,SAAS,EAAO,EAGpB,EAAS,GAAyE,CACtF,GAAI,CAAC,EAAQ,QAAQ,CAAE,OAEvB,IAAM,EAAS,GAAM,QAAU,eAE/B,EAAQ,QAAQ,GAAO,CAAE,SAAQ,CAAC,CAClC,GAAiB,EAED,GAAM,cAAgB,GAAoB,GAE7C,EAAQ,qBAAqB,EAAE,OAAO,CAEnD,EAAQ,UAAU,EAAO,EAsC3B,MAAO,CAAE,kBAzBiB,EAAiC,SAAU,EAAU,KAAuB,CACpG,IAAM,EAAW,GAAiB,CAChC,GAAI,CAAC,EAAQ,QAAQ,CAAE,OAEvB,IAAM,EAAW,EAAQ,oBAAoB,CACvC,EAAQ,EAAQ,mBAAmB,CACnC,EAAc,EAAM,OACpB,EAAO,OAAO,EAAM,cAAiB,WAAa,EAAM,cAAc,CAAG,EAAE,CAE5E,IAED,IAAa,EAAS,SAAS,EAAY,EAAI,EAAK,SAAS,EAAS,GAEtE,IAAU,EAAM,SAAS,EAAY,EAAI,EAAK,SAAS,EAAM,GAEjE,EAAM,CAAE,OAAQ,gBAAiB,CAAC,GAKpC,OAFA,EAAO,iBAAiB,QAAS,EAAS,EAAQ,KAErC,CACX,EAAO,oBAAoB,QAAS,EAAS,EAAQ,GAI9B,QAAO,OAAM,WAnCb,CACzB,GAAI,EAAQ,QAAQ,CAAE,CACpB,EAAM,CAAE,OAAQ,SAAU,CAAC,CAE3B,OAGF,EAAK,CAAE,OAAQ,SAAU,CAAC,EA4BoB"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export type OverlayPositioner = {
|
|
2
|
+
floating: () => HTMLElement | null;
|
|
3
|
+
reference: () => HTMLElement | null;
|
|
4
|
+
update: () => void;
|
|
5
|
+
};
|
|
6
|
+
export type OverlayOpenReason = 'programmatic' | 'toggle' | 'trigger';
|
|
7
|
+
export type OverlayCloseReason = 'escape' | 'outside-click' | 'programmatic' | 'toggle';
|
|
8
|
+
export type OverlayChangeContext = {
|
|
9
|
+
reason: OverlayCloseReason | OverlayOpenReason;
|
|
10
|
+
};
|
|
11
|
+
export type OverlayControlOptions = {
|
|
12
|
+
getBoundaryElement: () => HTMLElement | null;
|
|
13
|
+
getPanelElement?: () => HTMLElement | null;
|
|
14
|
+
getTriggerElement?: () => HTMLElement | null;
|
|
15
|
+
isDisabled?: () => boolean;
|
|
16
|
+
isOpen: () => boolean;
|
|
17
|
+
onClose?: (reason: OverlayCloseReason) => void;
|
|
18
|
+
onOpen?: (reason: OverlayOpenReason) => void;
|
|
19
|
+
positioner?: OverlayPositioner;
|
|
20
|
+
restoreFocus?: boolean | (() => boolean);
|
|
21
|
+
setOpen: (next: boolean, context: OverlayChangeContext) => void;
|
|
22
|
+
};
|
|
23
|
+
export type OverlayControl = {
|
|
24
|
+
bindOutsideClick: (target?: Document | HTMLElement, capture?: boolean) => () => void;
|
|
25
|
+
close: (opts?: {
|
|
26
|
+
reason?: OverlayCloseReason;
|
|
27
|
+
restoreFocus?: boolean;
|
|
28
|
+
}) => void;
|
|
29
|
+
open: (opts?: {
|
|
30
|
+
reason?: OverlayOpenReason;
|
|
31
|
+
}) => void;
|
|
32
|
+
toggle: () => void;
|
|
33
|
+
};
|
|
34
|
+
export declare const createOverlayControl: (options: OverlayControlOptions) => OverlayControl;
|
|
35
|
+
//# sourceMappingURL=overlay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/labs/overlay.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,MAAM,WAAW,GAAG,IAAI,CAAC;IACnC,SAAS,EAAE,MAAM,WAAW,GAAG,IAAI,CAAC;IACpC,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,cAAc,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEtE,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,eAAe,GAAG,cAAc,GAAG,QAAQ,CAAC;AAExF,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,kBAAkB,GAAG,iBAAiB,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,kBAAkB,EAAE,MAAM,WAAW,GAAG,IAAI,CAAC;IAC7C,eAAe,CAAC,EAAE,MAAM,WAAW,GAAG,IAAI,CAAC;IAC3C,iBAAiB,CAAC,EAAE,MAAM,WAAW,GAAG,IAAI,CAAC;IAC7C,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC;IAC3B,MAAM,EAAE,MAAM,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC/C,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC7C,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,YAAY,CAAC,EAAE,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC,CAAC;IACzC,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAC;CACjE,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,gBAAgB,EAAE,CAAC,MAAM,CAAC,EAAE,QAAQ,GAAG,WAAW,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;IACrF,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,kBAAkB,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;IAChF,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,iBAAiB,CAAA;KAAE,KAAK,IAAI,CAAC;IACtD,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,SAAS,qBAAqB,KAAG,cAkGrE,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{autoUpdate as e}from"@vielzeug/floatit";var t=t=>{let n=null,r=()=>typeof t.restoreFocus==`function`?t.restoreFocus():t.restoreFocus??!0,i=()=>{let r=t.positioner;if(n?.(),n=null,!r)return;let i=r.reference(),a=r.floating();if(!i||!a){r.update();return}n=e(i,a,r.update)},a=()=>{n?.(),n=null},o=e=>{if(t.isDisabled?.()||t.isOpen())return;let n=e?.reason??`programmatic`;t.setOpen(!0,{reason:n}),i(),requestAnimationFrame(()=>t.positioner?.update()),t.onOpen?.(n)},s=e=>{if(!t.isOpen())return;let n=e?.reason??`programmatic`;t.setOpen(!1,{reason:n}),a(),(e?.restoreFocus??r())&&t.getTriggerElement?.()?.focus(),t.onClose?.(n)};return{bindOutsideClick:(e=document,n=!0)=>{let r=e=>{if(!t.isOpen())return;let n=t.getBoundaryElement(),r=t.getPanelElement?.(),i=e.target,a=typeof e.composedPath==`function`?e.composedPath():[];i&&(n&&(n.contains(i)||a.includes(n))||r&&(r.contains(i)||a.includes(r))||s({reason:`outside-click`}))};return e.addEventListener(`click`,r,n),()=>{e.removeEventListener(`click`,r,n)}},close:s,open:o,toggle:()=>{if(t.isOpen()){s({reason:`toggle`});return}o({reason:`toggle`})}}};export{t as createOverlayControl};
|
|
2
|
+
//# sourceMappingURL=overlay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlay.js","names":[],"sources":["../../src/labs/overlay.ts"],"sourcesContent":["import { autoUpdate } from '@vielzeug/floatit';\n\nexport type OverlayPositioner = {\n floating: () => HTMLElement | null;\n reference: () => HTMLElement | null;\n update: () => void;\n};\n\nexport type OverlayOpenReason = 'programmatic' | 'toggle' | 'trigger';\n\nexport type OverlayCloseReason = 'escape' | 'outside-click' | 'programmatic' | 'toggle';\n\nexport type OverlayChangeContext = {\n reason: OverlayCloseReason | OverlayOpenReason;\n};\n\nexport type OverlayControlOptions = {\n getBoundaryElement: () => HTMLElement | null;\n getPanelElement?: () => HTMLElement | null;\n getTriggerElement?: () => HTMLElement | null;\n isDisabled?: () => boolean;\n isOpen: () => boolean;\n onClose?: (reason: OverlayCloseReason) => void;\n onOpen?: (reason: OverlayOpenReason) => void;\n positioner?: OverlayPositioner;\n restoreFocus?: boolean | (() => boolean);\n setOpen: (next: boolean, context: OverlayChangeContext) => void;\n};\n\nexport type OverlayControl = {\n bindOutsideClick: (target?: Document | HTMLElement, capture?: boolean) => () => void;\n close: (opts?: { reason?: OverlayCloseReason; restoreFocus?: boolean }) => void;\n open: (opts?: { reason?: OverlayOpenReason }) => void;\n toggle: () => void;\n};\n\nexport const createOverlayControl = (options: OverlayControlOptions): OverlayControl => {\n let cleanupPositioning: (() => void) | null = null;\n\n const shouldRestoreFocus = (): boolean => {\n if (typeof options.restoreFocus === 'function') return options.restoreFocus();\n\n return options.restoreFocus ?? true;\n };\n\n const startPositioning = (): void => {\n const positioner = options.positioner;\n\n cleanupPositioning?.();\n cleanupPositioning = null;\n\n if (!positioner) return;\n\n const reference = positioner.reference();\n const floating = positioner.floating();\n\n if (!reference || !floating) {\n positioner.update();\n\n return;\n }\n\n cleanupPositioning = autoUpdate(reference, floating, positioner.update);\n };\n\n const stopPositioning = (): void => {\n cleanupPositioning?.();\n cleanupPositioning = null;\n };\n\n const open = (opts?: { reason?: OverlayOpenReason }): void => {\n if (options.isDisabled?.()) return;\n\n if (options.isOpen()) return;\n\n const reason = opts?.reason ?? 'programmatic';\n\n options.setOpen(true, { reason });\n startPositioning();\n requestAnimationFrame(() => options.positioner?.update());\n options.onOpen?.(reason);\n };\n\n const close = (opts?: { reason?: OverlayCloseReason; restoreFocus?: boolean }): void => {\n if (!options.isOpen()) return;\n\n const reason = opts?.reason ?? 'programmatic';\n\n options.setOpen(false, { reason });\n stopPositioning();\n\n const restore = opts?.restoreFocus ?? shouldRestoreFocus();\n\n if (restore) options.getTriggerElement?.()?.focus();\n\n options.onClose?.(reason);\n };\n\n const toggle = (): void => {\n if (options.isOpen()) {\n close({ reason: 'toggle' });\n\n return;\n }\n\n open({ reason: 'toggle' });\n };\n\n const bindOutsideClick = (target: Document | HTMLElement = document, capture = true): (() => void) => {\n const handler = (event: Event) => {\n if (!options.isOpen()) return;\n\n const boundary = options.getBoundaryElement();\n const panel = options.getPanelElement?.();\n const eventTarget = event.target as Node | null;\n const path = typeof event.composedPath === 'function' ? event.composedPath() : [];\n\n if (!eventTarget) return;\n\n if (boundary && (boundary.contains(eventTarget) || path.includes(boundary))) return;\n\n if (panel && (panel.contains(eventTarget) || path.includes(panel))) return;\n\n close({ reason: 'outside-click' });\n };\n\n target.addEventListener('click', handler, capture);\n\n return () => {\n target.removeEventListener('click', handler, capture);\n };\n };\n\n return { bindOutsideClick, close, open, toggle };\n};\n"],"mappings":"+CAoCA,IAAa,EAAwB,GAAmD,CACtF,IAAI,EAA0C,KAExC,MACA,OAAO,EAAQ,cAAiB,WAAmB,EAAQ,cAAc,CAEtE,EAAQ,cAAgB,GAG3B,MAA+B,CACnC,IAAM,EAAa,EAAQ,WAK3B,GAHA,KAAsB,CACtB,EAAqB,KAEjB,CAAC,EAAY,OAEjB,IAAM,EAAY,EAAW,WAAW,CAClC,EAAW,EAAW,UAAU,CAEtC,GAAI,CAAC,GAAa,CAAC,EAAU,CAC3B,EAAW,QAAQ,CAEnB,OAGF,EAAqB,EAAW,EAAW,EAAU,EAAW,OAAO,EAGnE,MAA8B,CAClC,KAAsB,CACtB,EAAqB,MAGjB,EAAQ,GAAgD,CAG5D,GAFI,EAAQ,cAAc,EAEtB,EAAQ,QAAQ,CAAE,OAEtB,IAAM,EAAS,GAAM,QAAU,eAE/B,EAAQ,QAAQ,GAAM,CAAE,SAAQ,CAAC,CACjC,GAAkB,CAClB,0BAA4B,EAAQ,YAAY,QAAQ,CAAC,CACzD,EAAQ,SAAS,EAAO,EAGpB,EAAS,GAAyE,CACtF,GAAI,CAAC,EAAQ,QAAQ,CAAE,OAEvB,IAAM,EAAS,GAAM,QAAU,eAE/B,EAAQ,QAAQ,GAAO,CAAE,SAAQ,CAAC,CAClC,GAAiB,EAED,GAAM,cAAgB,GAAoB,GAE7C,EAAQ,qBAAqB,EAAE,OAAO,CAEnD,EAAQ,UAAU,EAAO,EAsC3B,MAAO,CAAE,kBAzBiB,EAAiC,SAAU,EAAU,KAAuB,CACpG,IAAM,EAAW,GAAiB,CAChC,GAAI,CAAC,EAAQ,QAAQ,CAAE,OAEvB,IAAM,EAAW,EAAQ,oBAAoB,CACvC,EAAQ,EAAQ,mBAAmB,CACnC,EAAc,EAAM,OACpB,EAAO,OAAO,EAAM,cAAiB,WAAa,EAAM,cAAc,CAAG,EAAE,CAE5E,IAED,IAAa,EAAS,SAAS,EAAY,EAAI,EAAK,SAAS,EAAS,GAEtE,IAAU,EAAM,SAAS,EAAY,EAAI,EAAK,SAAS,EAAM,GAEjE,EAAM,CAAE,OAAQ,gBAAiB,CAAC,GAKpC,OAFA,EAAO,iBAAiB,QAAS,EAAS,EAAQ,KAErC,CACX,EAAO,oBAAoB,QAAS,EAAS,EAAQ,GAI9B,QAAO,OAAM,WAnCb,CACzB,GAAI,EAAQ,QAAQ,CAAE,CACpB,EAAM,CAAE,OAAQ,SAAU,CAAC,CAE3B,OAGF,EAAK,CAAE,OAAQ,SAAU,CAAC,EA4BoB"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
let e=require(`@vielzeug/stateit`);function t(t){let n=t.indeterminate??(0,e.signal)(!1);return{changePayload:e=>({checked:t.checked.value,fieldValue:t.value.value??``,originalEvent:e,value:t.checked.value}),checked:t.checked,indeterminate:n,toggle:e=>{if(!(t.disabled.value??!1)){if(t.group){n.value=!1,t.group.toggle(t.value.value??``,e),t.onToggle?.(e);return}t.clearIndeterminateFirst&&n.value||(t.checked.value=!t.checked.value),n.value=!1,t.onToggle?.(e)}}}}exports.createCheckableControl=t;
|
|
2
|
+
//# sourceMappingURL=selectable.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selectable.cjs","names":[],"sources":["../../src/labs/selectable.ts"],"sourcesContent":["import { type ReadonlySignal, type Signal, signal } from '@vielzeug/stateit';\n\n/**\n * Change event payload emitted by checkable controls.\n */\nexport type CheckableChangePayload = {\n checked: boolean;\n fieldValue: string;\n originalEvent?: Event;\n value: boolean;\n};\n\n/**\n * Configuration for `createCheckableControl()`.\n */\nexport type CheckableControlConfig = {\n /** Writable checked signal — mutated directly by toggle() so all reactive bindings stay in sync */\n checked: Signal<boolean>;\n /** When `true`, the first click clears indeterminate instead of toggling checked */\n clearIndeterminateFirst?: boolean;\n /** Disabled signal (usually from props) */\n disabled: ReadonlySignal<boolean | undefined>;\n /** Optional: checkbox group context for syncing multiple checkboxes */\n group?: { toggle(value: string, originalEvent?: Event): void } | undefined;\n /** Writable indeterminate signal — managed by the caller, cleared by toggle() */\n indeterminate?: Signal<boolean>;\n /** Optional: callback when toggle occurs (for form validation / event emission) */\n onToggle?: (e: Event) => void;\n /** Value signal (usually from props) */\n value: ReadonlySignal<string | undefined>;\n};\n\n/**\n * Handle returned from `createCheckableControl()`.\n */\nexport type CheckableControlHandle = {\n /** Create a standard change payload from an event */\n changePayload: (e: Event) => CheckableChangePayload;\n /** Current checked state — the same signal passed in via config.checked */\n checked: ReadonlySignal<boolean>;\n /** Current indeterminate state signal */\n indeterminate: ReadonlySignal<boolean>;\n /** Toggle function (respecting disabled state and indeterminate rules) */\n toggle: (e: Event) => void;\n};\n\n/**\n * Manages checked/indeterminate state logic for checkable form controls (checkbox, radio, switch).\n *\n * Encapsulates:\n * - Controlled state management (operates directly on the caller's signals — no internal copy)\n * - Indeterminate-first clearing behavior\n * - Disabled guard\n * - Group integration (for checkbox-group context)\n * - Standard change payload creation\n *\n * @example\n * const checkedSignal = signal(false);\n * const control = createCheckableControl({\n * checked: checkedSignal,\n * disabled: props.disabled,\n * value: props.value,\n * clearIndeterminateFirst: true,\n * });\n *\n * reflect({\n * checked: () => control.checked.value,\n * onClick: (e) => control.toggle(e),\n * });\n */\nexport function createCheckableControl(config: CheckableControlConfig): CheckableControlHandle {\n const indeterminate = config.indeterminate ?? signal<boolean>(false);\n\n const toggle = (e: Event) => {\n if (config.disabled.value ?? false) return;\n\n if (config.group) {\n indeterminate.value = false;\n config.group.toggle(config.value.value ?? '', e);\n config.onToggle?.(e);\n\n return;\n }\n\n if (config.clearIndeterminateFirst && indeterminate.value) {\n indeterminate.value = false;\n } else {\n config.checked.value = !config.checked.value;\n indeterminate.value = false;\n }\n\n config.onToggle?.(e);\n };\n\n const changePayload = (e: Event): CheckableChangePayload => ({\n checked: config.checked.value,\n fieldValue: config.value.value ?? '',\n originalEvent: e,\n value: config.checked.value,\n });\n\n return {\n changePayload,\n checked: config.checked,\n indeterminate,\n toggle,\n };\n}\n"],"mappings":"mCAsEA,SAAgB,EAAuB,EAAwD,CAC7F,IAAM,EAAgB,EAAO,gBAAA,EAAA,EAAA,QAAiC,GAAM,CA8BpE,MAAO,CACL,cARqB,IAAsC,CAC3D,QAAS,EAAO,QAAQ,MACxB,WAAY,EAAO,MAAM,OAAS,GAClC,cAAe,EACf,MAAO,EAAO,QAAQ,MACvB,EAIC,QAAS,EAAO,QAChB,gBACA,OAhCc,GAAa,CACvB,OAAO,SAAS,OAAS,IAE7B,IAAI,EAAO,MAAO,CAChB,EAAc,MAAQ,GACtB,EAAO,MAAM,OAAO,EAAO,MAAM,OAAS,GAAI,EAAE,CAChD,EAAO,WAAW,EAAE,CAEpB,OAGE,EAAO,yBAA2B,EAAc,QAGlD,EAAO,QAAQ,MAAQ,CAAC,EAAO,QAAQ,OAFvC,EAAc,MAAQ,GAMxB,EAAO,WAAW,EAAE,GAerB"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { type ReadonlySignal, type Signal } from '@vielzeug/stateit';
|
|
2
|
+
/**
|
|
3
|
+
* Change event payload emitted by checkable controls.
|
|
4
|
+
*/
|
|
5
|
+
export type CheckableChangePayload = {
|
|
6
|
+
checked: boolean;
|
|
7
|
+
fieldValue: string;
|
|
8
|
+
originalEvent?: Event;
|
|
9
|
+
value: boolean;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Configuration for `createCheckableControl()`.
|
|
13
|
+
*/
|
|
14
|
+
export type CheckableControlConfig = {
|
|
15
|
+
/** Writable checked signal — mutated directly by toggle() so all reactive bindings stay in sync */
|
|
16
|
+
checked: Signal<boolean>;
|
|
17
|
+
/** When `true`, the first click clears indeterminate instead of toggling checked */
|
|
18
|
+
clearIndeterminateFirst?: boolean;
|
|
19
|
+
/** Disabled signal (usually from props) */
|
|
20
|
+
disabled: ReadonlySignal<boolean | undefined>;
|
|
21
|
+
/** Optional: checkbox group context for syncing multiple checkboxes */
|
|
22
|
+
group?: {
|
|
23
|
+
toggle(value: string, originalEvent?: Event): void;
|
|
24
|
+
} | undefined;
|
|
25
|
+
/** Writable indeterminate signal — managed by the caller, cleared by toggle() */
|
|
26
|
+
indeterminate?: Signal<boolean>;
|
|
27
|
+
/** Optional: callback when toggle occurs (for form validation / event emission) */
|
|
28
|
+
onToggle?: (e: Event) => void;
|
|
29
|
+
/** Value signal (usually from props) */
|
|
30
|
+
value: ReadonlySignal<string | undefined>;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Handle returned from `createCheckableControl()`.
|
|
34
|
+
*/
|
|
35
|
+
export type CheckableControlHandle = {
|
|
36
|
+
/** Create a standard change payload from an event */
|
|
37
|
+
changePayload: (e: Event) => CheckableChangePayload;
|
|
38
|
+
/** Current checked state — the same signal passed in via config.checked */
|
|
39
|
+
checked: ReadonlySignal<boolean>;
|
|
40
|
+
/** Current indeterminate state signal */
|
|
41
|
+
indeterminate: ReadonlySignal<boolean>;
|
|
42
|
+
/** Toggle function (respecting disabled state and indeterminate rules) */
|
|
43
|
+
toggle: (e: Event) => void;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Manages checked/indeterminate state logic for checkable form controls (checkbox, radio, switch).
|
|
47
|
+
*
|
|
48
|
+
* Encapsulates:
|
|
49
|
+
* - Controlled state management (operates directly on the caller's signals — no internal copy)
|
|
50
|
+
* - Indeterminate-first clearing behavior
|
|
51
|
+
* - Disabled guard
|
|
52
|
+
* - Group integration (for checkbox-group context)
|
|
53
|
+
* - Standard change payload creation
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* const checkedSignal = signal(false);
|
|
57
|
+
* const control = createCheckableControl({
|
|
58
|
+
* checked: checkedSignal,
|
|
59
|
+
* disabled: props.disabled,
|
|
60
|
+
* value: props.value,
|
|
61
|
+
* clearIndeterminateFirst: true,
|
|
62
|
+
* });
|
|
63
|
+
*
|
|
64
|
+
* reflect({
|
|
65
|
+
* checked: () => control.checked.value,
|
|
66
|
+
* onClick: (e) => control.toggle(e),
|
|
67
|
+
* });
|
|
68
|
+
*/
|
|
69
|
+
export declare function createCheckableControl(config: CheckableControlConfig): CheckableControlHandle;
|
|
70
|
+
//# sourceMappingURL=selectable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selectable.d.ts","sourceRoot":"","sources":["../../src/labs/selectable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,MAAM,EAAU,MAAM,mBAAmB,CAAC;AAE7E;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,KAAK,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,mGAAmG;IACnG,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACzB,oFAAoF;IACpF,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,2CAA2C;IAC3C,QAAQ,EAAE,cAAc,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IAC9C,uEAAuE;IACvE,KAAK,CAAC,EAAE;QAAE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,KAAK,GAAG,IAAI,CAAA;KAAE,GAAG,SAAS,CAAC;IAC3E,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAChC,mFAAmF;IACnF,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC;IAC9B,wCAAwC;IACxC,KAAK,EAAE,cAAc,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CAC3C,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,qDAAqD;IACrD,aAAa,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,sBAAsB,CAAC;IACpD,2EAA2E;IAC3E,OAAO,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;IACjC,yCAAyC;IACzC,aAAa,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;IACvC,0EAA0E;IAC1E,MAAM,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC;CAC5B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,sBAAsB,GAAG,sBAAsB,CAqC7F"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{signal as e}from"@vielzeug/stateit";function t(t){let n=t.indeterminate??e(!1);return{changePayload:e=>({checked:t.checked.value,fieldValue:t.value.value??``,originalEvent:e,value:t.checked.value}),checked:t.checked,indeterminate:n,toggle:e=>{if(!(t.disabled.value??!1)){if(t.group){n.value=!1,t.group.toggle(t.value.value??``,e),t.onToggle?.(e);return}t.clearIndeterminateFirst&&n.value||(t.checked.value=!t.checked.value),n.value=!1,t.onToggle?.(e)}}}}export{t as createCheckableControl};
|
|
2
|
+
//# sourceMappingURL=selectable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selectable.js","names":[],"sources":["../../src/labs/selectable.ts"],"sourcesContent":["import { type ReadonlySignal, type Signal, signal } from '@vielzeug/stateit';\n\n/**\n * Change event payload emitted by checkable controls.\n */\nexport type CheckableChangePayload = {\n checked: boolean;\n fieldValue: string;\n originalEvent?: Event;\n value: boolean;\n};\n\n/**\n * Configuration for `createCheckableControl()`.\n */\nexport type CheckableControlConfig = {\n /** Writable checked signal — mutated directly by toggle() so all reactive bindings stay in sync */\n checked: Signal<boolean>;\n /** When `true`, the first click clears indeterminate instead of toggling checked */\n clearIndeterminateFirst?: boolean;\n /** Disabled signal (usually from props) */\n disabled: ReadonlySignal<boolean | undefined>;\n /** Optional: checkbox group context for syncing multiple checkboxes */\n group?: { toggle(value: string, originalEvent?: Event): void } | undefined;\n /** Writable indeterminate signal — managed by the caller, cleared by toggle() */\n indeterminate?: Signal<boolean>;\n /** Optional: callback when toggle occurs (for form validation / event emission) */\n onToggle?: (e: Event) => void;\n /** Value signal (usually from props) */\n value: ReadonlySignal<string | undefined>;\n};\n\n/**\n * Handle returned from `createCheckableControl()`.\n */\nexport type CheckableControlHandle = {\n /** Create a standard change payload from an event */\n changePayload: (e: Event) => CheckableChangePayload;\n /** Current checked state — the same signal passed in via config.checked */\n checked: ReadonlySignal<boolean>;\n /** Current indeterminate state signal */\n indeterminate: ReadonlySignal<boolean>;\n /** Toggle function (respecting disabled state and indeterminate rules) */\n toggle: (e: Event) => void;\n};\n\n/**\n * Manages checked/indeterminate state logic for checkable form controls (checkbox, radio, switch).\n *\n * Encapsulates:\n * - Controlled state management (operates directly on the caller's signals — no internal copy)\n * - Indeterminate-first clearing behavior\n * - Disabled guard\n * - Group integration (for checkbox-group context)\n * - Standard change payload creation\n *\n * @example\n * const checkedSignal = signal(false);\n * const control = createCheckableControl({\n * checked: checkedSignal,\n * disabled: props.disabled,\n * value: props.value,\n * clearIndeterminateFirst: true,\n * });\n *\n * reflect({\n * checked: () => control.checked.value,\n * onClick: (e) => control.toggle(e),\n * });\n */\nexport function createCheckableControl(config: CheckableControlConfig): CheckableControlHandle {\n const indeterminate = config.indeterminate ?? signal<boolean>(false);\n\n const toggle = (e: Event) => {\n if (config.disabled.value ?? false) return;\n\n if (config.group) {\n indeterminate.value = false;\n config.group.toggle(config.value.value ?? '', e);\n config.onToggle?.(e);\n\n return;\n }\n\n if (config.clearIndeterminateFirst && indeterminate.value) {\n indeterminate.value = false;\n } else {\n config.checked.value = !config.checked.value;\n indeterminate.value = false;\n }\n\n config.onToggle?.(e);\n };\n\n const changePayload = (e: Event): CheckableChangePayload => ({\n checked: config.checked.value,\n fieldValue: config.value.value ?? '',\n originalEvent: e,\n value: config.checked.value,\n });\n\n return {\n changePayload,\n checked: config.checked,\n indeterminate,\n toggle,\n };\n}\n"],"mappings":"2CAsEA,SAAgB,EAAuB,EAAwD,CAC7F,IAAM,EAAgB,EAAO,eAAiB,EAAgB,GAAM,CA8BpE,MAAO,CACL,cARqB,IAAsC,CAC3D,QAAS,EAAO,QAAQ,MACxB,WAAY,EAAO,MAAM,OAAS,GAClC,cAAe,EACf,MAAO,EAAO,QAAQ,MACvB,EAIC,QAAS,EAAO,QAChB,gBACA,OAhCc,GAAa,CACvB,OAAO,SAAS,OAAS,IAE7B,IAAI,EAAO,MAAO,CAChB,EAAc,MAAQ,GACtB,EAAO,MAAM,OAAO,EAAO,MAAM,OAAS,GAAI,EAAE,CAChD,EAAO,WAAW,EAAE,CAEpB,OAGE,EAAO,yBAA2B,EAAc,QAGlD,EAAO,QAAQ,MAAQ,CAAC,EAAO,QAAQ,OAFvC,EAAc,MAAQ,GAMxB,EAAO,WAAW,EAAE,GAerB"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=e=>{let t=()=>e.getSelected().map(e.keyExtractor),n=e=>t().includes(e);return{clear:()=>{e.setSelected([])},isSelected:n,remove:t=>{e.setSelected(e.getSelected().filter(n=>e.keyExtractor(n)!==t))},select:t=>{let r=e.findByKey(t);if(r){if(e.getMode()===`single`){e.setSelected([r]);return}n(t)||e.setSelected([...e.getSelected(),r])}},serialize:(e=`,`)=>t().join(e),toggle:t=>{let r=e.findByKey(t);if(r){if(e.getMode()===`single`){e.setSelected([r]);return}if(n(t)){e.setSelected(e.getSelected().filter(n=>e.keyExtractor(n)!==t));return}e.setSelected([...e.getSelected(),r])}}}};exports.createSelectionControl=e;
|
|
2
|
+
//# sourceMappingURL=selection.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection.cjs","names":[],"sources":["../../src/labs/selection.ts"],"sourcesContent":["/**\n * Selection mode: single or multiple.\n */\nexport type SelectionMode = 'multiple' | 'single';\n\n/**\n * Key-driven selection controller.\n *\n * Works with arbitrary data structures via constructor options.\n * Manages selection state, deduplication, and serialization independently of item shape.\n */\nexport type SelectionController = {\n /** Clear all selections. */\n clear: () => void;\n /** Check if a key is currently selected. */\n isSelected: (key: string) => boolean;\n /** Remove a key from selection. */\n remove: (key: string) => void;\n /** Select a key (single or add to multiple). */\n select: (key: string) => void;\n /** Serialize all selected keys to a string (comma-separated by default). */\n serialize: (separator?: string) => string;\n /** Toggle a key's selection state. */\n toggle: (key: string) => void;\n};\n\n/**\n * Key extractor function: given an item, extract its unique key.\n */\nexport type SelectionKeyExtractor<T> = (item: T) => string;\n\n/**\n * Selection controller options.\n *\n * @typeParam T - Item type (any data structure)\n */\nexport type SelectionControllerOptions<T> = {\n /** Lookup function: given a key, find or reconstruct the item */\n findByKey: (key: string) => T | undefined;\n /** Getter: current selection mode */\n getMode: () => SelectionMode;\n /** Getter: currently selected items */\n getSelected: () => T[];\n /** Extractor: derive the unique key from an item */\n keyExtractor: SelectionKeyExtractor<T>;\n /** Setter: update selection to a new array of items */\n setSelected: (next: T[]) => void;\n};\n\n/**\n * Creates a key-driven selection controller.\n *\n * Decouples selection logic from item shape by working exclusively with extracted keys.\n * Manages deduplication and mode-aware selection (single vs. multiple).\n *\n * @example\n * ```typescript\n * const controller = createSelectionControl({\n * getMode: () => 'multiple',\n * getSelected: () => selected.value,\n * setSelected: (next) => { selected.value = next; },\n * keyExtractor: (item) => item.id,\n * findByKey: (id) => allItems.find((i) => i.id === id),\n * });\n *\n * controller.select('item-1');\n * controller.toggle('item-2');\n * if (controller.isSelected('item-1')) { ... }\n * ```\n */\nexport const createSelectionControl = <T>(options: SelectionControllerOptions<T>): SelectionController => {\n const getSelectedKeys = (): string[] => options.getSelected().map(options.keyExtractor);\n\n const isSelected = (key: string): boolean => getSelectedKeys().includes(key);\n\n const clear = (): void => {\n options.setSelected([]);\n };\n\n const select = (key: string): void => {\n const item = options.findByKey(key);\n\n if (!item) return;\n\n if (options.getMode() === 'single') {\n options.setSelected([item]);\n\n return;\n }\n\n if (isSelected(key)) return;\n\n options.setSelected([...options.getSelected(), item]);\n };\n\n const toggle = (key: string): void => {\n const item = options.findByKey(key);\n\n if (!item) return;\n\n if (options.getMode() === 'single') {\n options.setSelected([item]);\n\n return;\n }\n\n if (isSelected(key)) {\n options.setSelected(options.getSelected().filter((entry) => options.keyExtractor(entry) !== key));\n\n return;\n }\n\n options.setSelected([...options.getSelected(), item]);\n };\n\n const remove = (key: string): void => {\n options.setSelected(options.getSelected().filter((entry) => options.keyExtractor(entry) !== key));\n };\n\n const serialize = (separator = ','): string => getSelectedKeys().join(separator);\n\n return {\n clear,\n isSelected,\n remove,\n select,\n serialize,\n toggle,\n };\n};\n"],"mappings":"AAsEA,IAAa,EAA6B,GAAgE,CACxG,IAAM,MAAkC,EAAQ,aAAa,CAAC,IAAI,EAAQ,aAAa,CAEjF,EAAc,GAAyB,GAAiB,CAAC,SAAS,EAAI,CAgD5E,MAAO,CACL,UA/CwB,CACxB,EAAQ,YAAY,EAAE,CAAC,EA+CvB,aACA,OATc,GAAsB,CACpC,EAAQ,YAAY,EAAQ,aAAa,CAAC,OAAQ,GAAU,EAAQ,aAAa,EAAM,GAAK,EAAI,CAAC,EASjG,OA9Cc,GAAsB,CACpC,IAAM,EAAO,EAAQ,UAAU,EAAI,CAE9B,KAEL,IAAI,EAAQ,SAAS,GAAK,SAAU,CAClC,EAAQ,YAAY,CAAC,EAAK,CAAC,CAE3B,OAGE,EAAW,EAAI,EAEnB,EAAQ,YAAY,CAAC,GAAG,EAAQ,aAAa,CAAE,EAAK,CAAC,GAkCrD,WAPiB,EAAY,MAAgB,GAAiB,CAAC,KAAK,EAAU,CAQ9E,OAhCc,GAAsB,CACpC,IAAM,EAAO,EAAQ,UAAU,EAAI,CAE9B,KAEL,IAAI,EAAQ,SAAS,GAAK,SAAU,CAClC,EAAQ,YAAY,CAAC,EAAK,CAAC,CAE3B,OAGF,GAAI,EAAW,EAAI,CAAE,CACnB,EAAQ,YAAY,EAAQ,aAAa,CAAC,OAAQ,GAAU,EAAQ,aAAa,EAAM,GAAK,EAAI,CAAC,CAEjG,OAGF,EAAQ,YAAY,CAAC,GAAG,EAAQ,aAAa,CAAE,EAAK,CAAC,GAgBtD"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Selection mode: single or multiple.
|
|
3
|
+
*/
|
|
4
|
+
export type SelectionMode = 'multiple' | 'single';
|
|
5
|
+
/**
|
|
6
|
+
* Key-driven selection controller.
|
|
7
|
+
*
|
|
8
|
+
* Works with arbitrary data structures via constructor options.
|
|
9
|
+
* Manages selection state, deduplication, and serialization independently of item shape.
|
|
10
|
+
*/
|
|
11
|
+
export type SelectionController = {
|
|
12
|
+
/** Clear all selections. */
|
|
13
|
+
clear: () => void;
|
|
14
|
+
/** Check if a key is currently selected. */
|
|
15
|
+
isSelected: (key: string) => boolean;
|
|
16
|
+
/** Remove a key from selection. */
|
|
17
|
+
remove: (key: string) => void;
|
|
18
|
+
/** Select a key (single or add to multiple). */
|
|
19
|
+
select: (key: string) => void;
|
|
20
|
+
/** Serialize all selected keys to a string (comma-separated by default). */
|
|
21
|
+
serialize: (separator?: string) => string;
|
|
22
|
+
/** Toggle a key's selection state. */
|
|
23
|
+
toggle: (key: string) => void;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Key extractor function: given an item, extract its unique key.
|
|
27
|
+
*/
|
|
28
|
+
export type SelectionKeyExtractor<T> = (item: T) => string;
|
|
29
|
+
/**
|
|
30
|
+
* Selection controller options.
|
|
31
|
+
*
|
|
32
|
+
* @typeParam T - Item type (any data structure)
|
|
33
|
+
*/
|
|
34
|
+
export type SelectionControllerOptions<T> = {
|
|
35
|
+
/** Lookup function: given a key, find or reconstruct the item */
|
|
36
|
+
findByKey: (key: string) => T | undefined;
|
|
37
|
+
/** Getter: current selection mode */
|
|
38
|
+
getMode: () => SelectionMode;
|
|
39
|
+
/** Getter: currently selected items */
|
|
40
|
+
getSelected: () => T[];
|
|
41
|
+
/** Extractor: derive the unique key from an item */
|
|
42
|
+
keyExtractor: SelectionKeyExtractor<T>;
|
|
43
|
+
/** Setter: update selection to a new array of items */
|
|
44
|
+
setSelected: (next: T[]) => void;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Creates a key-driven selection controller.
|
|
48
|
+
*
|
|
49
|
+
* Decouples selection logic from item shape by working exclusively with extracted keys.
|
|
50
|
+
* Manages deduplication and mode-aware selection (single vs. multiple).
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* const controller = createSelectionControl({
|
|
55
|
+
* getMode: () => 'multiple',
|
|
56
|
+
* getSelected: () => selected.value,
|
|
57
|
+
* setSelected: (next) => { selected.value = next; },
|
|
58
|
+
* keyExtractor: (item) => item.id,
|
|
59
|
+
* findByKey: (id) => allItems.find((i) => i.id === id),
|
|
60
|
+
* });
|
|
61
|
+
*
|
|
62
|
+
* controller.select('item-1');
|
|
63
|
+
* controller.toggle('item-2');
|
|
64
|
+
* if (controller.isSelected('item-1')) { ... }
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare const createSelectionControl: <T>(options: SelectionControllerOptions<T>) => SelectionController;
|
|
68
|
+
//# sourceMappingURL=selection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../../src/labs/selection.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,QAAQ,CAAC;AAElD;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,4BAA4B;IAC5B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,4CAA4C;IAC5C,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACrC,mCAAmC;IACnC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,gDAAgD;IAChD,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,4EAA4E;IAC5E,SAAS,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAC1C,sCAAsC;IACtC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,qBAAqB,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC;AAE3D;;;;GAIG;AACH,MAAM,MAAM,0BAA0B,CAAC,CAAC,IAAI;IAC1C,iEAAiE;IACjE,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,CAAC,GAAG,SAAS,CAAC;IAC1C,qCAAqC;IACrC,OAAO,EAAE,MAAM,aAAa,CAAC;IAC7B,uCAAuC;IACvC,WAAW,EAAE,MAAM,CAAC,EAAE,CAAC;IACvB,oDAAoD;IACpD,YAAY,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAAC;IACvC,uDAAuD;IACvD,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC;CAClC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,sBAAsB,GAAI,CAAC,EAAE,SAAS,0BAA0B,CAAC,CAAC,CAAC,KAAG,mBA2DlF,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=e=>{let t=()=>e.getSelected().map(e.keyExtractor),n=e=>t().includes(e);return{clear:()=>{e.setSelected([])},isSelected:n,remove:t=>{e.setSelected(e.getSelected().filter(n=>e.keyExtractor(n)!==t))},select:t=>{let r=e.findByKey(t);if(r){if(e.getMode()===`single`){e.setSelected([r]);return}n(t)||e.setSelected([...e.getSelected(),r])}},serialize:(e=`,`)=>t().join(e),toggle:t=>{let r=e.findByKey(t);if(r){if(e.getMode()===`single`){e.setSelected([r]);return}if(n(t)){e.setSelected(e.getSelected().filter(n=>e.keyExtractor(n)!==t));return}e.setSelected([...e.getSelected(),r])}}}};export{e as createSelectionControl};
|
|
2
|
+
//# sourceMappingURL=selection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection.js","names":[],"sources":["../../src/labs/selection.ts"],"sourcesContent":["/**\n * Selection mode: single or multiple.\n */\nexport type SelectionMode = 'multiple' | 'single';\n\n/**\n * Key-driven selection controller.\n *\n * Works with arbitrary data structures via constructor options.\n * Manages selection state, deduplication, and serialization independently of item shape.\n */\nexport type SelectionController = {\n /** Clear all selections. */\n clear: () => void;\n /** Check if a key is currently selected. */\n isSelected: (key: string) => boolean;\n /** Remove a key from selection. */\n remove: (key: string) => void;\n /** Select a key (single or add to multiple). */\n select: (key: string) => void;\n /** Serialize all selected keys to a string (comma-separated by default). */\n serialize: (separator?: string) => string;\n /** Toggle a key's selection state. */\n toggle: (key: string) => void;\n};\n\n/**\n * Key extractor function: given an item, extract its unique key.\n */\nexport type SelectionKeyExtractor<T> = (item: T) => string;\n\n/**\n * Selection controller options.\n *\n * @typeParam T - Item type (any data structure)\n */\nexport type SelectionControllerOptions<T> = {\n /** Lookup function: given a key, find or reconstruct the item */\n findByKey: (key: string) => T | undefined;\n /** Getter: current selection mode */\n getMode: () => SelectionMode;\n /** Getter: currently selected items */\n getSelected: () => T[];\n /** Extractor: derive the unique key from an item */\n keyExtractor: SelectionKeyExtractor<T>;\n /** Setter: update selection to a new array of items */\n setSelected: (next: T[]) => void;\n};\n\n/**\n * Creates a key-driven selection controller.\n *\n * Decouples selection logic from item shape by working exclusively with extracted keys.\n * Manages deduplication and mode-aware selection (single vs. multiple).\n *\n * @example\n * ```typescript\n * const controller = createSelectionControl({\n * getMode: () => 'multiple',\n * getSelected: () => selected.value,\n * setSelected: (next) => { selected.value = next; },\n * keyExtractor: (item) => item.id,\n * findByKey: (id) => allItems.find((i) => i.id === id),\n * });\n *\n * controller.select('item-1');\n * controller.toggle('item-2');\n * if (controller.isSelected('item-1')) { ... }\n * ```\n */\nexport const createSelectionControl = <T>(options: SelectionControllerOptions<T>): SelectionController => {\n const getSelectedKeys = (): string[] => options.getSelected().map(options.keyExtractor);\n\n const isSelected = (key: string): boolean => getSelectedKeys().includes(key);\n\n const clear = (): void => {\n options.setSelected([]);\n };\n\n const select = (key: string): void => {\n const item = options.findByKey(key);\n\n if (!item) return;\n\n if (options.getMode() === 'single') {\n options.setSelected([item]);\n\n return;\n }\n\n if (isSelected(key)) return;\n\n options.setSelected([...options.getSelected(), item]);\n };\n\n const toggle = (key: string): void => {\n const item = options.findByKey(key);\n\n if (!item) return;\n\n if (options.getMode() === 'single') {\n options.setSelected([item]);\n\n return;\n }\n\n if (isSelected(key)) {\n options.setSelected(options.getSelected().filter((entry) => options.keyExtractor(entry) !== key));\n\n return;\n }\n\n options.setSelected([...options.getSelected(), item]);\n };\n\n const remove = (key: string): void => {\n options.setSelected(options.getSelected().filter((entry) => options.keyExtractor(entry) !== key));\n };\n\n const serialize = (separator = ','): string => getSelectedKeys().join(separator);\n\n return {\n clear,\n isSelected,\n remove,\n select,\n serialize,\n toggle,\n };\n};\n"],"mappings":"AAsEA,IAAa,EAA6B,GAAgE,CACxG,IAAM,MAAkC,EAAQ,aAAa,CAAC,IAAI,EAAQ,aAAa,CAEjF,EAAc,GAAyB,GAAiB,CAAC,SAAS,EAAI,CAgD5E,MAAO,CACL,UA/CwB,CACxB,EAAQ,YAAY,EAAE,CAAC,EA+CvB,aACA,OATc,GAAsB,CACpC,EAAQ,YAAY,EAAQ,aAAa,CAAC,OAAQ,GAAU,EAAQ,aAAa,EAAM,GAAK,EAAI,CAAC,EASjG,OA9Cc,GAAsB,CACpC,IAAM,EAAO,EAAQ,UAAU,EAAI,CAE9B,KAEL,IAAI,EAAQ,SAAS,GAAK,SAAU,CAClC,EAAQ,YAAY,CAAC,EAAK,CAAC,CAE3B,OAGE,EAAW,EAAI,EAEnB,EAAQ,YAAY,CAAC,GAAG,EAAQ,aAAa,CAAE,EAAK,CAAC,GAkCrD,WAPiB,EAAY,MAAgB,GAAiB,CAAC,KAAK,EAAU,CAQ9E,OAhCc,GAAsB,CACpC,IAAM,EAAO,EAAQ,UAAU,EAAI,CAE9B,KAEL,IAAI,EAAQ,SAAS,GAAK,SAAU,CAClC,EAAQ,YAAY,CAAC,EAAK,CAAC,CAE3B,OAGF,GAAI,EAAW,EAAI,CAAE,CACnB,EAAQ,YAAY,EAAQ,aAAa,CAAC,OAAQ,GAAU,EAAQ,aAAa,EAAM,GAAK,EAAI,CAAC,CAEjG,OAGF,EAAQ,YAAY,CAAC,GAAG,EAAQ,aAAa,CAAE,EAAK,CAAC,GAgBtD"}
|
package/dist/labs.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./labs/observers.cjs`),t=require(`./labs/list.cjs`),n=require(`./labs/overlay.cjs`),r=require(`./labs/selection.cjs`),i=require(`./labs/a11y.cjs`),a=require(`./labs/selectable.cjs`);exports.createCheckableControl=a.createCheckableControl,exports.createListNavigation=t.createListNavigation,exports.createOverlayControl=n.createOverlayControl,exports.createSelectionControl=r.createSelectionControl,exports.observeIntersection=e.observeIntersection,exports.observeMedia=e.observeMedia,exports.observeResize=e.observeResize,exports.useA11yControl=i.useA11yControl;
|
package/dist/labs.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{observeIntersection as e,observeMedia as t,observeResize as n}from"./labs/observers.js";import{createListNavigation as r}from"./labs/list.js";import{createOverlayControl as i}from"./labs/overlay.js";import{createSelectionControl as a}from"./labs/selection.js";import{useA11yControl as o}from"./labs/a11y.js";import{createCheckableControl as s}from"./labs/selectable.js";export{s as createCheckableControl,r as createListNavigation,i as createOverlayControl,a as createSelectionControl,e as observeIntersection,t as observeMedia,n as observeResize,o as useA11yControl};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require(`../core/utilities.cjs`),t=require(`../core/template.cjs`),n=require(`../core/component.cjs`);var r=[],i=0,a=()=>{e._resetIdCounter(),t._resetMarkerIndex()};function o(){return(()=>{let e=0,t=()=>Promise.resolve().then(()=>{if(++e<10)return t()});return t()})().then(()=>new Promise(e=>typeof requestAnimationFrame<`u`?requestAnimationFrame(()=>e()):e()))}function s(e){e(b)}function c(e,t,n){n===!1?e.removeAttribute(t):e.setAttribute(t,n===!0?``:String(n))}async function l(e,t={}){let{attrs:a={},componentOptions:s,container:l=document.body,html:f,props:p={}}=t,m,h;typeof e==`string`?m=e:typeof e==`function`?(m=`trial-${++i}`,h={...s??{},setup:e}):(m=`trial-${++i}`,h=e),h&&n.defineComponent({tag:m,...h});let g=document.createElement(m);f&&(g.innerHTML=f),Object.keys(p).length&&Object.assign(g,p);for(let[e,t]of Object.entries(a))c(g,e,t);return l.appendChild(g),r.push(g),await o(),{async act(e){await e(),await o()},async attr(e,t){c(g,e,t),await o()},async attrs(e){for(let[t,n]of Object.entries(e))c(g,t,n);await o()},destroy(){g.remove();let e=r.indexOf(g);e!==-1&&r.splice(e,1)},element:g,flush:o,query(e){return g.shadowRoot?.querySelector(e)??null},queryAll(e){return Array.from(g.shadowRoot?.querySelectorAll(e)??[])},queryAllByTestId(e){return Array.from(g.shadowRoot?.querySelectorAll(`[data-testid="${e}"]`)??[])},queryAllByText(e,t=`*`){return d(g.shadowRoot,e,t)},queryByTestId(e){return g.shadowRoot?.querySelector(`[data-testid="${e}"]`)??null},queryByText(e,t=`*`){return u(g.shadowRoot,e,t)},get shadow(){return g.shadowRoot}}}function u(e,t,n){for(let r of e.querySelectorAll(n))if(r.textContent?.trim()===t)return r;return null}function d(e,t,n){return Array.from(e.querySelectorAll(n)).filter(e=>e.textContent?.trim()===t)}function f(e){return{query:t=>e.querySelector(t),queryAll:t=>Array.from(e.querySelectorAll(t)),queryAllByTestId:t=>Array.from(e.querySelectorAll(`[data-testid="${t}"]`)),queryAllByText:(t,n=`*`)=>d(e,t,n),queryByTestId:t=>e.querySelector(`[data-testid="${t}"]`),queryByText:(t,n=`*`)=>u(e,t,n)}}var p=(e,t={})=>typeof PointerEvent<`u`?new PointerEvent(e,t):new MouseEvent(e,t),m={blur:(e,t)=>e.dispatchEvent(new FocusEvent(`blur`,{bubbles:!0,...t})),change:(e,t)=>e.dispatchEvent(new Event(`change`,{bubbles:!0,...t})),click:(e,t)=>e.dispatchEvent(new MouseEvent(`click`,{bubbles:!0,cancelable:!0,...t})),custom(e,t,n,r){e.dispatchEvent(new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:n,...r}))},focus:(e,t)=>e.dispatchEvent(new FocusEvent(`focus`,{bubbles:!0,...t})),input:(e,t)=>e.dispatchEvent(new Event(`input`,{bubbles:!0,...t})),keyDown:(e,t)=>e.dispatchEvent(new KeyboardEvent(`keydown`,{bubbles:!0,cancelable:!0,...t})),keyUp:(e,t)=>e.dispatchEvent(new KeyboardEvent(`keyup`,{bubbles:!0,cancelable:!0,...t})),pointerDown:(e,t)=>e.dispatchEvent(p(`pointerdown`,{bubbles:!0,cancelable:!0,...t})),pointerEnter:(e,t)=>e.dispatchEvent(p(`pointerenter`,{bubbles:!1,...t})),pointerLeave:(e,t)=>e.dispatchEvent(p(`pointerleave`,{bubbles:!1,...t})),pointerUp:(e,t)=>e.dispatchEvent(p(`pointerup`,{bubbles:!0,cancelable:!0,...t})),submit:(e,t)=>e.dispatchEvent(new Event(`submit`,{bubbles:!0,cancelable:!0,...t}))},h=()=>Promise.resolve(),g={async clear(e){e.focus(),e.value=``,m.input(e),m.change(e),await h()},async click(e,t){m.pointerEnter(e,t),m.click(e,t),await h()},async dblClick(e){for(let t=0;t<2;t++)m.pointerDown(e),m.pointerUp(e),m.click(e);e.dispatchEvent(new MouseEvent(`dblclick`,{bubbles:!0,cancelable:!0})),await h()},async fill(e,t){e.focus(),e.value=``;for(let n of t)e.value+=n,m.input(e),m.keyDown(e,{key:n}),m.keyUp(e,{key:n}),await h();m.change(e)},async hover(e){m.pointerEnter(e),await h()},async press(e,t,n){m.keyDown(e,{key:t,...n}),m.keyUp(e,{key:t,...n}),await h()},async select(e,t){let n=Array.isArray(t)?t:[t];for(let t of e.options)t.selected=n.includes(t.value);m.change(e),await h()},async type(e,t){e.focus();for(let n of t)e.value+=n,m.input(e),m.keyDown(e,{key:n}),m.keyUp(e,{key:n}),await h();m.change(e)},async unhover(e){m.pointerLeave(e),await h()}};async function _(e,{interval:t=50,message:n,timeout:r=1e3}={}){let i=Date.now()+r,a,o=async()=>{try{let t=await e();return t===void 0||!!t}catch(e){return a=e,!1}};for(;Date.now()<i;){if(await o())return;await new Promise(e=>setTimeout(e,t))}if(await o())return;let s=n??`waitFor timed out after ${r}ms`;throw a instanceof Error?(a.message=`${s}\n${a.message}`,a):Error(a==null?s:`${s}\nCause: ${a}`)}function v(e,t,n=1e3){return new Promise((r,i)=>{let a=setTimeout(()=>i(Error(`waitForEvent: "${t}" timed out after ${n}ms`)),n);e.addEventListener(t,e=>{clearTimeout(a),r(e)},{once:!0})})}function y(e,t=``){customElements.get(e)||customElements.define(e,class extends HTMLElement{connectedCallback(){this.innerHTML=t}})}function b(){for(let e of r)e.remove();r.length=0}exports._resetCounters=a,exports.cleanup=b,exports.fire=m,exports.flush=o,exports.install=s,exports.mock=y,exports.mount=l,exports.user=g,exports.waitFor=_,exports.waitForEvent=v,exports.within=f;
|
|
2
|
+
//# sourceMappingURL=test.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test.cjs","names":[],"sources":["../../src/test/test.ts"],"sourcesContent":["/**\n * Testing utilities for Craftit components\n *\n * ⚠️ Requires DOM environment (browser / jsdom / happy-dom)\n */\n\nimport { defineComponent, type BuildPropSchema, type DefineComponentOptions } from '../core/component';\nimport { _resetMarkerIndex } from '../core/template';\nimport { _resetIdCounter } from '../core/utilities';\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\nexport interface Fixture<T extends HTMLElement = HTMLElement> {\n /** The component element */\n element: T;\n /** The component's shadow root */\n readonly shadow: ShadowRoot;\n /** Query a single element within shadow root */\n query<E extends Element = Element>(selector: string): E | null;\n /** Query all elements within shadow root */\n queryAll<E extends Element = Element>(selector: string): E[];\n /** Query the first element whose trimmed text content matches */\n queryByText<E extends Element = Element>(text: string, selector?: string): E | null;\n /** Query all elements whose trimmed text content matches */\n queryAllByText<E extends Element = Element>(text: string, selector?: string): E[];\n /** Query a single element by its `data-testid` attribute */\n queryByTestId<E extends Element = Element>(testId: string): E | null;\n /** Query all elements by their `data-testid` attribute */\n queryAllByTestId<E extends Element = Element>(testId: string): E[];\n /** Set an attribute (boolean `false` removes it) then flush */\n attr(name: string, value: string | number | boolean): Promise<void>;\n /** Set multiple attributes then flush */\n attrs(record: Record<string, string | number | boolean>): Promise<void>;\n /** Wait for all reactive updates and animation frames */\n flush(): Promise<void>;\n /** Run a callback then flush — the standard way to trigger and assert a reactive update */\n act(fn: () => unknown): Promise<void>;\n /** Remove the component from the DOM */\n destroy(): void;\n}\n\n/** Scoped query helpers for any DOM element — see {@link within} */\nexport interface QueryScope {\n query<E extends Element = Element>(selector: string): E | null;\n queryAll<E extends Element = Element>(selector: string): E[];\n queryByText<E extends Element = Element>(text: string, selector?: string): E | null;\n queryAllByText<E extends Element = Element>(text: string, selector?: string): E[];\n queryByTestId<E extends Element = Element>(testId: string): E | null;\n queryAllByTestId<E extends Element = Element>(testId: string): E[];\n}\n\nexport interface MountOptions {\n /** Properties assigned directly onto the element */\n props?: Record<string, unknown>;\n /** HTML attributes to set on the element */\n attrs?: Record<string, string | number | boolean>;\n /** Inner HTML for slot content */\n html?: string;\n /** Parent container (default: document.body) */\n container?: HTMLElement;\n /** Extra defineComponent options when passing an inline setup function */\n componentOptions?: Omit<DefineComponentOptions<any, any>, 'setup' | 'tag'>;\n}\n\ntype TestComponentOptions<\n Props extends Record<string, unknown> = Record<string, never>,\n Events extends Record<string, unknown> = Record<string, unknown>,\n> = Omit<DefineComponentOptions<BuildPropSchema<Props>, Events>, 'tag'>;\n\nexport interface WaitOptions {\n /** Maximum wait time in ms (default: 1000) */\n timeout?: number;\n /** Polling interval in ms (default: 50) */\n interval?: number;\n /** Message included in timeout error */\n message?: string;\n}\n\n// ─── Test environment state ───────────────────────────────────────────────────\n\nconst _mountedElements: HTMLElement[] = [];\nlet _componentTagCounter = 0;\n\n/**\n * Resets global test counters used for deterministic IDs/markers.\n * @internal\n */\nexport const _resetCounters = (): void => {\n _resetIdCounter();\n _resetMarkerIndex();\n};\n\n// ─── Core ────────────────────────────────────────────────────────────────────\n\n/**\n * Flush pending reactive updates.\n * Drains the microtask queue completely, then yields one animation frame\n * for any rAF-scheduled work.\n */\nexport function flush(): Promise<void> {\n // Drain all pending microtasks by repeatedly yielding until the queue is empty.\n // Fixed tick approaches can under-flush when signal batching schedules additional microtasks.\n const drainMicrotasks = (): Promise<void> => {\n let ticks = 0;\n const drain = (): Promise<void> =>\n Promise.resolve().then(() => {\n if (++ticks < 10) return drain();\n });\n\n return drain();\n };\n\n return drainMicrotasks().then(\n () =>\n new Promise<void>((r) => (typeof requestAnimationFrame !== 'undefined' ? requestAnimationFrame(() => r()) : r())),\n );\n}\n\n/**\n * Register auto-cleanup after each test. Call once in your test setup file.\n *\n * @example\n * // vitest.setup.ts\n * import { afterEach } from 'vitest';\n * import { install } from '@vielzeug/craftit/test';\n * install(afterEach);\n */\nexport function install(afterEachHook: (fn: () => void) => void): void {\n afterEachHook(cleanup);\n}\n\nfunction applyAttr(element: Element, name: string, value: string | number | boolean): void {\n if (value === false) element.removeAttribute(name);\n else element.setAttribute(name, value === true ? '' : String(value));\n}\n\n/**\n * Mount a component into the DOM and return a test fixture.\n *\n * Accepts a registered tag name, an inline setup function, or a component\n * options object. Setup functions are auto-registered with generated tag names.\n *\n * @example — inline setup function\n * const { query } = await mount(() => {\n * const count = signal(0);\n * return html`<button @click=${() => count.value++}>${count}</button>`;\n * });\n *\n * @example — registered tag name\n * const { query } = await mount('my-counter');\n */\nexport async function mount<T extends HTMLElement = HTMLElement>(\n tagOrSetupOrOptions: string,\n options?: MountOptions,\n): Promise<Fixture<T>>;\nexport async function mount<T extends HTMLElement = HTMLElement>(\n tagOrSetupOrOptions: TestComponentOptions['setup'],\n options?: MountOptions,\n): Promise<Fixture<T>>;\nexport async function mount<T extends HTMLElement = HTMLElement>(\n tagOrSetupOrOptions: TestComponentOptions<any, any>,\n options?: MountOptions,\n): Promise<Fixture<T>>;\nexport async function mount<T extends HTMLElement = HTMLElement>(\n tagOrSetupOrOptions: string | TestComponentOptions['setup'] | TestComponentOptions<any, any>,\n options: MountOptions = {},\n): Promise<Fixture<T>> {\n const { attrs = {}, componentOptions, container = document.body, html, props = {} } = options;\n\n let tagName: string;\n let inlineDefinition: TestComponentOptions<any, any> | undefined;\n\n if (typeof tagOrSetupOrOptions === 'string') {\n tagName = tagOrSetupOrOptions;\n } else if (typeof tagOrSetupOrOptions === 'function') {\n tagName = `trial-${++_componentTagCounter}`;\n inlineDefinition = {\n ...(componentOptions ?? {}),\n setup: tagOrSetupOrOptions as TestComponentOptions<any, any>['setup'],\n };\n } else {\n tagName = `trial-${++_componentTagCounter}`;\n inlineDefinition = tagOrSetupOrOptions;\n }\n\n if (inlineDefinition) {\n defineComponent({ tag: tagName, ...(inlineDefinition as TestComponentOptions<any, any>) });\n }\n\n const element = document.createElement(tagName) as T;\n\n if (html) element.innerHTML = html;\n\n if (Object.keys(props).length) Object.assign(element, props);\n\n for (const [name, value] of Object.entries(attrs)) applyAttr(element, name, value);\n\n container.appendChild(element);\n _mountedElements.push(element);\n await flush();\n\n return {\n async act(fn) {\n await fn();\n await flush();\n },\n\n async attr(name, value) {\n applyAttr(element, name, value);\n await flush();\n },\n\n async attrs(record) {\n for (const [name, value] of Object.entries(record)) applyAttr(element, name, value);\n await flush();\n },\n\n destroy() {\n element.remove();\n\n const i = _mountedElements.indexOf(element);\n\n if (i !== -1) _mountedElements.splice(i, 1);\n },\n element,\n\n flush,\n\n query<E extends Element = Element>(selector: string): E | null {\n return element.shadowRoot?.querySelector<E>(selector) ?? null;\n },\n\n queryAll<E extends Element = Element>(selector: string): E[] {\n return Array.from(element.shadowRoot?.querySelectorAll<E>(selector) ?? []);\n },\n\n queryAllByTestId<E extends Element = Element>(testId: string): E[] {\n return Array.from(element.shadowRoot?.querySelectorAll<E>(`[data-testid=\"${testId}\"]`) ?? []);\n },\n\n queryAllByText<E extends Element = Element>(text: string, selector = '*'): E[] {\n return queryAllByText<E>(element.shadowRoot!, text, selector);\n },\n\n queryByTestId<E extends Element = Element>(testId: string): E | null {\n return element.shadowRoot?.querySelector<E>(`[data-testid=\"${testId}\"]`) ?? null;\n },\n\n queryByText<E extends Element = Element>(text: string, selector = '*'): E | null {\n return queryByText<E>(element.shadowRoot!, text, selector);\n },\n\n get shadow(): ShadowRoot {\n return element.shadowRoot!;\n },\n };\n}\n\n// ─── Scoped queries ───────────────────────────────────────────────────────────\n\nfunction queryByText<E extends Element = Element>(\n root: Element | ShadowRoot,\n text: string,\n selector: string,\n): E | null {\n for (const el of root.querySelectorAll<E>(selector)) {\n if (el.textContent?.trim() === text) return el;\n }\n\n return null;\n}\n\nfunction queryAllByText<E extends Element = Element>(root: Element | ShadowRoot, text: string, selector: string): E[] {\n return Array.from(root.querySelectorAll<E>(selector)).filter((el) => el.textContent?.trim() === text);\n}\n\n/**\n * Create query helpers scoped to any element — useful for slotted/light DOM content.\n *\n * @example\n * const panel = fixture.query('.panel')!;\n * const { query } = within(panel);\n * expect(query('.title')?.textContent).toBe('Hello');\n */\nexport function within(element: Element): QueryScope {\n return {\n query: <E extends Element = Element>(selector: string) => element.querySelector<E>(selector),\n queryAll: <E extends Element = Element>(selector: string) => Array.from(element.querySelectorAll<E>(selector)),\n queryAllByTestId: <E extends Element = Element>(testId: string) =>\n Array.from(element.querySelectorAll<E>(`[data-testid=\"${testId}\"]`)),\n queryAllByText: <E extends Element = Element>(text: string, selector = '*') =>\n queryAllByText<E>(element, text, selector),\n queryByTestId: <E extends Element = Element>(testId: string) =>\n element.querySelector<E>(`[data-testid=\"${testId}\"]`),\n queryByText: <E extends Element = Element>(text: string, selector = '*') => queryByText<E>(element, text, selector),\n };\n}\n\n// ─── Events ──────────────────────────────────────────────────────────────────\n\nconst createPointerEvent = (type: string, init: PointerEventInit = {}): Event => {\n if (typeof PointerEvent !== 'undefined') {\n return new PointerEvent(type, init);\n }\n\n return new MouseEvent(type, init);\n};\n\n/**\n * Fire low-level DOM events synchronously.\n *\n * @example\n * fire.click(button);\n * fire.keyDown(input, { key: 'Enter' });\n * fire.custom(el, 'value-change', 42);\n */\nexport const fire = {\n blur: (el: Element, opts?: FocusEventInit) => el.dispatchEvent(new FocusEvent('blur', { bubbles: true, ...opts })),\n change: (el: Element, opts?: EventInit) => el.dispatchEvent(new Event('change', { bubbles: true, ...opts })),\n click: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, ...opts })),\n custom<D = unknown>(el: Element, name: string, detail?: D, opts?: Omit<CustomEventInit<D>, 'detail'>): void {\n el.dispatchEvent(new CustomEvent<D>(name, { bubbles: true, cancelable: true, detail, ...opts }));\n },\n focus: (el: Element, opts?: FocusEventInit) => el.dispatchEvent(new FocusEvent('focus', { bubbles: true, ...opts })),\n input: (el: Element, opts?: EventInit) => el.dispatchEvent(new Event('input', { bubbles: true, ...opts })),\n keyDown: (el: Element, opts?: KeyboardEventInit) =>\n el.dispatchEvent(new KeyboardEvent('keydown', { bubbles: true, cancelable: true, ...opts })),\n keyUp: (el: Element, opts?: KeyboardEventInit) =>\n el.dispatchEvent(new KeyboardEvent('keyup', { bubbles: true, cancelable: true, ...opts })),\n pointerDown: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(createPointerEvent('pointerdown', { bubbles: true, cancelable: true, ...opts })),\n pointerEnter: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(createPointerEvent('pointerenter', { bubbles: false, ...opts })),\n pointerLeave: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(createPointerEvent('pointerleave', { bubbles: false, ...opts })),\n pointerUp: (el: Element, opts?: PointerEventInit) =>\n el.dispatchEvent(createPointerEvent('pointerup', { bubbles: true, cancelable: true, ...opts })),\n submit: (el: Element, opts?: EventInit) =>\n el.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true, ...opts })),\n} as const;\n\n// ─── User interactions ────────────────────────────────────────────────────────\n\nconst tick = (): Promise<void> => Promise.resolve();\n\n/**\n * Higher-level async user interactions that mirror real browser behavior.\n *\n * @example\n * await user.type(input, 'hello');\n * await user.fill(input, 'replacement'); // clear then type\n * await user.click(button);\n * await user.press(input, 'Enter');\n */\nexport const user = {\n async clear(el: HTMLInputElement | HTMLTextAreaElement): Promise<void> {\n el.focus();\n el.value = '';\n fire.input(el);\n fire.change(el);\n await tick();\n },\n async click(el: Element, opts?: PointerEventInit): Promise<void> {\n fire.pointerEnter(el, opts);\n fire.click(el, opts);\n await tick();\n },\n\n async dblClick(el: Element): Promise<void> {\n for (let i = 0; i < 2; i++) {\n fire.pointerDown(el);\n fire.pointerUp(el);\n fire.click(el);\n }\n el.dispatchEvent(new MouseEvent('dblclick', { bubbles: true, cancelable: true }));\n await tick();\n },\n\n /** Clear existing value and type new text (select-all-and-replace semantics) */\n async fill(el: HTMLInputElement | HTMLTextAreaElement, text: string): Promise<void> {\n el.focus();\n el.value = '';\n for (const char of text) {\n el.value += char;\n fire.input(el);\n fire.keyDown(el, { key: char });\n fire.keyUp(el, { key: char });\n await tick();\n }\n fire.change(el);\n },\n\n async hover(el: Element): Promise<void> {\n fire.pointerEnter(el);\n await tick();\n },\n\n /** Dispatch keydown + keyup for a single key */\n async press(el: Element, key: string, opts?: KeyboardEventInit): Promise<void> {\n fire.keyDown(el, { key, ...opts });\n fire.keyUp(el, { key, ...opts });\n await tick();\n },\n\n async select(el: HTMLSelectElement, value: string | string[]): Promise<void> {\n const values = Array.isArray(value) ? value : [value];\n\n for (const opt of el.options) opt.selected = values.includes(opt.value);\n fire.change(el);\n await tick();\n },\n\n /** Type text character-by-character, appending to any existing value */\n async type(el: HTMLInputElement | HTMLTextAreaElement, text: string): Promise<void> {\n el.focus();\n for (const char of text) {\n el.value += char;\n fire.input(el);\n fire.keyDown(el, { key: char });\n fire.keyUp(el, { key: char });\n await tick();\n }\n fire.change(el);\n },\n\n async unhover(el: Element): Promise<void> {\n fire.pointerLeave(el);\n await tick();\n },\n} as const;\n\n// ─── Waiting ─────────────────────────────────────────────────────────────────\n\n/**\n * Poll until a callback returns truthy (or void) without throwing.\n * Supports both boolean conditions and `expect()` assertions.\n *\n * - Returns truthy → success\n * - Returns `undefined` (e.g. bare `expect()` call) → success\n * - Returns falsy value → retry\n * - Throws → retry, re-throw original error on timeout\n *\n * @example\n * await waitFor(() => query('.status')?.textContent === 'loaded');\n * await waitFor(() => expect(count).toBe(3));\n */\nexport async function waitFor(\n fn: () => unknown,\n { interval = 50, message, timeout = 1000 }: WaitOptions = {},\n): Promise<void> {\n const deadline = Date.now() + timeout;\n let lastError: unknown;\n\n const attempt = async (): Promise<boolean> => {\n try {\n const result = await fn();\n\n return result === undefined || !!result;\n } catch (e) {\n lastError = e;\n\n return false;\n }\n };\n\n while (Date.now() < deadline) {\n if (await attempt()) return;\n\n await new Promise((r) => setTimeout(r, interval));\n }\n\n if (await attempt()) return;\n\n const base = message ?? `waitFor timed out after ${timeout}ms`;\n\n if (lastError instanceof Error) {\n lastError.message = `${base}\\n${lastError.message}`;\n throw lastError;\n }\n\n throw new Error(lastError != null ? `${base}\\nCause: ${lastError}` : base);\n}\n\n/**\n * Resolve when the target element emits the given event.\n *\n * @example\n * const promise = waitForEvent(el, 'change');\n * fire.click(trigger);\n * const event = await promise;\n */\nexport function waitForEvent<T extends Event = Event>(element: Element, name: string, timeout = 1000): Promise<T> {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`waitForEvent: \"${name}\" timed out after ${timeout}ms`)), timeout);\n\n element.addEventListener(\n name,\n (e) => {\n clearTimeout(timer);\n resolve(e as T);\n },\n { once: true },\n );\n });\n}\n\n// ─── Stubs & cleanup ─────────────────────────────────────────────────────────\n\n/**\n * Register a stub custom element (no-op if already defined).\n *\n * @example\n * mock('child-button', '<slot></slot>');\n */\nexport function mock(tagName: string, template = ''): void {\n if (!customElements.get(tagName)) {\n customElements.define(\n tagName,\n class extends HTMLElement {\n connectedCallback() {\n this.innerHTML = template;\n }\n },\n );\n }\n}\n\n/**\n * Remove all elements mounted via `mount()`.\n * Call in `afterEach` to keep tests isolated.\n *\n * @example\n * afterEach(() => cleanup());\n */\nexport function cleanup(): void {\n for (const el of _mountedElements) el.remove();\n _mountedElements.length = 0;\n}\n"],"mappings":"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"}
|