@vielzeug/craftit 1.0.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/README.md +112 -401
  2. package/dist/core/component.cjs +2 -0
  3. package/dist/core/component.cjs.map +1 -0
  4. package/dist/core/component.d.ts +172 -0
  5. package/dist/core/component.d.ts.map +1 -0
  6. package/dist/core/component.js +2 -0
  7. package/dist/core/component.js.map +1 -0
  8. package/dist/core/host.cjs +2 -0
  9. package/dist/core/host.cjs.map +1 -0
  10. package/dist/core/host.d.ts +77 -0
  11. package/dist/core/host.d.ts.map +1 -0
  12. package/dist/core/host.js +2 -0
  13. package/dist/core/host.js.map +1 -0
  14. package/dist/core/internal.cjs +2 -0
  15. package/dist/core/internal.cjs.map +1 -0
  16. package/dist/core/internal.d.ts +105 -0
  17. package/dist/core/internal.d.ts.map +1 -0
  18. package/dist/core/internal.js +2 -0
  19. package/dist/core/internal.js.map +1 -0
  20. package/dist/core/runtime-bindings.cjs +2 -0
  21. package/dist/core/runtime-bindings.cjs.map +1 -0
  22. package/dist/core/runtime-bindings.d.ts +6 -0
  23. package/dist/core/runtime-bindings.d.ts.map +1 -0
  24. package/dist/core/runtime-bindings.js +2 -0
  25. package/dist/core/runtime-bindings.js.map +1 -0
  26. package/dist/core/runtime-lifecycle.cjs +2 -0
  27. package/dist/core/runtime-lifecycle.cjs.map +1 -0
  28. package/dist/core/runtime-lifecycle.d.ts +116 -0
  29. package/dist/core/runtime-lifecycle.d.ts.map +1 -0
  30. package/dist/core/runtime-lifecycle.js +2 -0
  31. package/dist/core/runtime-lifecycle.js.map +1 -0
  32. package/dist/core/runtime.cjs +1 -0
  33. package/dist/core/runtime.d.ts +3 -0
  34. package/dist/core/runtime.d.ts.map +1 -0
  35. package/dist/core/runtime.js +1 -0
  36. package/dist/core/template-bindings.cjs +2 -0
  37. package/dist/core/template-bindings.cjs.map +1 -0
  38. package/dist/core/template-bindings.d.ts +59 -0
  39. package/dist/core/template-bindings.d.ts.map +1 -0
  40. package/dist/core/template-bindings.js +2 -0
  41. package/dist/core/template-bindings.js.map +1 -0
  42. package/dist/core/template-compiler.cjs +2 -0
  43. package/dist/core/template-compiler.cjs.map +1 -0
  44. package/dist/core/template-compiler.d.ts +25 -0
  45. package/dist/core/template-compiler.d.ts.map +1 -0
  46. package/dist/core/template-compiler.js +2 -0
  47. package/dist/core/template-compiler.js.map +1 -0
  48. package/dist/core/template-dom.cjs +2 -0
  49. package/dist/core/template-dom.cjs.map +1 -0
  50. package/dist/core/template-dom.d.ts +13 -0
  51. package/dist/core/template-dom.d.ts.map +1 -0
  52. package/dist/core/template-dom.js +2 -0
  53. package/dist/core/template-dom.js.map +1 -0
  54. package/dist/core/template-html.cjs +2 -0
  55. package/dist/core/template-html.cjs.map +1 -0
  56. package/dist/core/template-html.d.ts +26 -0
  57. package/dist/core/template-html.d.ts.map +1 -0
  58. package/dist/core/template-html.js +2 -0
  59. package/dist/core/template-html.js.map +1 -0
  60. package/dist/core/template.cjs +2 -0
  61. package/dist/core/template.cjs.map +1 -0
  62. package/dist/core/template.d.ts +11 -0
  63. package/dist/core/template.d.ts.map +1 -0
  64. package/dist/core/template.js +2 -0
  65. package/dist/core/template.js.map +1 -0
  66. package/dist/core/utilities.cjs +2 -0
  67. package/dist/core/utilities.cjs.map +1 -0
  68. package/dist/core/utilities.d.ts +68 -0
  69. package/dist/core/utilities.d.ts.map +1 -0
  70. package/dist/core/utilities.js +2 -0
  71. package/dist/core/utilities.js.map +1 -0
  72. package/dist/craftit.cjs +2 -18
  73. package/dist/craftit.cjs.map +1 -1
  74. package/dist/craftit.js +2 -580
  75. package/dist/craftit.js.map +1 -1
  76. package/dist/directives/attr.cjs +2 -0
  77. package/dist/directives/attr.cjs.map +1 -0
  78. package/dist/directives/attr.d.ts +14 -0
  79. package/dist/directives/attr.d.ts.map +1 -0
  80. package/dist/directives/attr.js +2 -0
  81. package/dist/directives/attr.js.map +1 -0
  82. package/dist/directives/bind.cjs +2 -0
  83. package/dist/directives/bind.cjs.map +1 -0
  84. package/dist/directives/bind.d.ts +30 -0
  85. package/dist/directives/bind.d.ts.map +1 -0
  86. package/dist/directives/bind.js +2 -0
  87. package/dist/directives/bind.js.map +1 -0
  88. package/dist/directives/choose.cjs +2 -0
  89. package/dist/directives/choose.cjs.map +1 -0
  90. package/dist/directives/choose.d.ts +34 -0
  91. package/dist/directives/choose.d.ts.map +1 -0
  92. package/dist/directives/choose.js +2 -0
  93. package/dist/directives/choose.js.map +1 -0
  94. package/dist/directives/classes.cjs +2 -0
  95. package/dist/directives/classes.cjs.map +1 -0
  96. package/dist/directives/classes.d.ts +20 -0
  97. package/dist/directives/classes.d.ts.map +1 -0
  98. package/dist/directives/classes.js +2 -0
  99. package/dist/directives/classes.js.map +1 -0
  100. package/dist/directives/each.cjs +2 -0
  101. package/dist/directives/each.cjs.map +1 -0
  102. package/dist/directives/each.d.ts +68 -0
  103. package/dist/directives/each.d.ts.map +1 -0
  104. package/dist/directives/each.js +2 -0
  105. package/dist/directives/each.js.map +1 -0
  106. package/dist/directives/index.cjs +1 -0
  107. package/dist/directives/index.d.ts +14 -0
  108. package/dist/directives/index.d.ts.map +1 -0
  109. package/dist/directives/index.js +1 -0
  110. package/dist/directives/match.cjs +2 -0
  111. package/dist/directives/match.cjs.map +1 -0
  112. package/dist/directives/match.d.ts +31 -0
  113. package/dist/directives/match.d.ts.map +1 -0
  114. package/dist/directives/match.js +2 -0
  115. package/dist/directives/match.js.map +1 -0
  116. package/dist/directives/memo.cjs +2 -0
  117. package/dist/directives/memo.cjs.map +1 -0
  118. package/dist/directives/memo.d.ts +23 -0
  119. package/dist/directives/memo.d.ts.map +1 -0
  120. package/dist/directives/memo.js +2 -0
  121. package/dist/directives/memo.js.map +1 -0
  122. package/dist/directives/on.cjs +2 -0
  123. package/dist/directives/on.cjs.map +1 -0
  124. package/dist/directives/on.d.ts +25 -0
  125. package/dist/directives/on.d.ts.map +1 -0
  126. package/dist/directives/on.js +2 -0
  127. package/dist/directives/on.js.map +1 -0
  128. package/dist/directives/raw.cjs +2 -0
  129. package/dist/directives/raw.cjs.map +1 -0
  130. package/dist/directives/raw.d.ts +25 -0
  131. package/dist/directives/raw.d.ts.map +1 -0
  132. package/dist/directives/raw.js +2 -0
  133. package/dist/directives/raw.js.map +1 -0
  134. package/dist/directives/spread.cjs +2 -0
  135. package/dist/directives/spread.cjs.map +1 -0
  136. package/dist/directives/spread.d.ts +14 -0
  137. package/dist/directives/spread.d.ts.map +1 -0
  138. package/dist/directives/spread.js +2 -0
  139. package/dist/directives/spread.js.map +1 -0
  140. package/dist/directives/style.cjs +2 -0
  141. package/dist/directives/style.cjs.map +1 -0
  142. package/dist/directives/style.d.ts +22 -0
  143. package/dist/directives/style.d.ts.map +1 -0
  144. package/dist/directives/style.js +2 -0
  145. package/dist/directives/style.js.map +1 -0
  146. package/dist/directives/until.cjs +2 -0
  147. package/dist/directives/until.cjs.map +1 -0
  148. package/dist/directives/until.d.ts +26 -0
  149. package/dist/directives/until.d.ts.map +1 -0
  150. package/dist/directives/until.js +2 -0
  151. package/dist/directives/until.js.map +1 -0
  152. package/dist/directives/when.cjs +2 -0
  153. package/dist/directives/when.cjs.map +1 -0
  154. package/dist/directives/when.d.ts +17 -0
  155. package/dist/directives/when.d.ts.map +1 -0
  156. package/dist/directives/when.js +2 -0
  157. package/dist/directives/when.js.map +1 -0
  158. package/dist/index.cjs +1 -2
  159. package/dist/index.d.ts +10 -265
  160. package/dist/index.d.ts.map +1 -0
  161. package/dist/index.js +1 -13
  162. package/dist/labs/a11y.cjs +2 -0
  163. package/dist/labs/a11y.cjs.map +1 -0
  164. package/dist/labs/a11y.d.ts +61 -0
  165. package/dist/labs/a11y.d.ts.map +1 -0
  166. package/dist/labs/a11y.js +2 -0
  167. package/dist/labs/a11y.js.map +1 -0
  168. package/dist/labs/index.d.ts +8 -0
  169. package/dist/labs/index.d.ts.map +1 -0
  170. package/dist/labs/list.cjs +2 -0
  171. package/dist/labs/list.cjs.map +1 -0
  172. package/dist/labs/list.d.ts +26 -0
  173. package/dist/labs/list.d.ts.map +1 -0
  174. package/dist/labs/list.js +2 -0
  175. package/dist/labs/list.js.map +1 -0
  176. package/dist/labs/observers.cjs +2 -0
  177. package/dist/labs/observers.cjs.map +1 -0
  178. package/dist/labs/observers.d.ts +42 -0
  179. package/dist/labs/observers.d.ts.map +1 -0
  180. package/dist/labs/observers.js +2 -0
  181. package/dist/labs/observers.js.map +1 -0
  182. package/dist/labs/overlay.cjs +2 -0
  183. package/dist/labs/overlay.cjs.map +1 -0
  184. package/dist/labs/overlay.d.ts +35 -0
  185. package/dist/labs/overlay.d.ts.map +1 -0
  186. package/dist/labs/overlay.js +2 -0
  187. package/dist/labs/overlay.js.map +1 -0
  188. package/dist/labs/selectable.cjs +2 -0
  189. package/dist/labs/selectable.cjs.map +1 -0
  190. package/dist/labs/selectable.d.ts +70 -0
  191. package/dist/labs/selectable.d.ts.map +1 -0
  192. package/dist/labs/selectable.js +2 -0
  193. package/dist/labs/selectable.js.map +1 -0
  194. package/dist/labs/selection.cjs +2 -0
  195. package/dist/labs/selection.cjs.map +1 -0
  196. package/dist/labs/selection.d.ts +68 -0
  197. package/dist/labs/selection.d.ts.map +1 -0
  198. package/dist/labs/selection.js +2 -0
  199. package/dist/labs/selection.js.map +1 -0
  200. package/dist/labs.cjs +1 -0
  201. package/dist/labs.js +1 -0
  202. package/dist/test/index.d.ts +2 -0
  203. package/dist/test/index.d.ts.map +1 -0
  204. package/dist/test/test.cjs +2 -0
  205. package/dist/test/test.cjs.map +1 -0
  206. package/dist/test/test.d.ts +198 -0
  207. package/dist/test/test.d.ts.map +1 -0
  208. package/dist/test/test.js +2 -0
  209. package/dist/test/test.js.map +1 -0
  210. package/dist/test.cjs +1 -0
  211. package/dist/test.js +1 -0
  212. package/package.json +37 -9
  213. package/dist/index.cjs.map +0 -1
  214. package/dist/index.js.map +0 -1
@@ -0,0 +1,26 @@
1
+ import type { HTMLResult } from '../core/internal';
2
+ /**
3
+ * Renders `pendingFn` while a Promise is pending, then switches to the resolved
4
+ * result. Lighter-weight alternative to `suspense()` for one-shot data loading
5
+ * with no error/retry UI.
6
+ *
7
+ * Returns a reactive getter the engine tracks automatically — no manual signal
8
+ * management needed at the call site.
9
+ *
10
+ * @param promise The promise to await. Should already resolve to a renderable value.
11
+ * @param pendingFn Optional function called while the promise is pending.
12
+ * @param onError Optional function called when the promise rejects. Receives the rejection reason.
13
+ *
14
+ * @example
15
+ * import { until } from '@vielzeug/craftit/directives';
16
+ *
17
+ * const data = fetch('/api/user').then(r => r.json());
18
+ *
19
+ * html`${until(
20
+ * data.then(u => html`<p>Hello, ${u.name}!</p>`),
21
+ * () => html`<p>Loading…</p>`,
22
+ * (err) => html`<p>Error: ${String(err)}</p>`,
23
+ * )}`
24
+ */
25
+ export declare function until(promise: Promise<string | HTMLResult>, pendingFn?: () => string | HTMLResult, onError?: (err: unknown) => string | HTMLResult): () => string | HTMLResult;
26
+ //# sourceMappingURL=until.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"until.d.ts","sourceRoot":"","sources":["../../src/directives/until.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAInD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,KAAK,CACnB,OAAO,EAAE,OAAO,CAAC,MAAM,GAAG,UAAU,CAAC,EACrC,SAAS,CAAC,EAAE,MAAM,MAAM,GAAG,UAAU,EACrC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,GAAG,UAAU,GAC9C,MAAM,MAAM,GAAG,UAAU,CAiB3B"}
@@ -0,0 +1,2 @@
1
+ import{signal as e}from"@vielzeug/stateit";function t(t,n,r){let i=e({done:!1});return t.then(e=>{i.value={done:!0,value:e}},e=>{r?i.value={done:!0,value:r(e)}:i.value={done:!0,value:`Error: ${String(e)}`}}),()=>i.value.done?i.value.value:n?.()??``}export{t as until};
2
+ //# sourceMappingURL=until.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"until.js","names":[],"sources":["../../src/directives/until.ts"],"sourcesContent":["import { signal } from '@vielzeug/stateit';\n\nimport type { HTMLResult } from '../core/internal';\n\ntype State = { done: false } | { done: true; value: string | HTMLResult };\n\n/**\n * Renders `pendingFn` while a Promise is pending, then switches to the resolved\n * result. Lighter-weight alternative to `suspense()` for one-shot data loading\n * with no error/retry UI.\n *\n * Returns a reactive getter the engine tracks automatically — no manual signal\n * management needed at the call site.\n *\n * @param promise The promise to await. Should already resolve to a renderable value.\n * @param pendingFn Optional function called while the promise is pending.\n * @param onError Optional function called when the promise rejects. Receives the rejection reason.\n *\n * @example\n * import { until } from '@vielzeug/craftit/directives';\n *\n * const data = fetch('/api/user').then(r => r.json());\n *\n * html`${until(\n * data.then(u => html`<p>Hello, ${u.name}!</p>`),\n * () => html`<p>Loading…</p>`,\n * (err) => html`<p>Error: ${String(err)}</p>`,\n * )}`\n */\nexport function until(\n promise: Promise<string | HTMLResult>,\n pendingFn?: () => string | HTMLResult,\n onError?: (err: unknown) => string | HTMLResult,\n): () => string | HTMLResult {\n const state = signal<State>({ done: false });\n\n promise.then(\n (val) => {\n state.value = { done: true, value: val };\n },\n (err) => {\n if (onError) {\n state.value = { done: true, value: onError(err) };\n } else {\n state.value = { done: true, value: `Error: ${String(err)}` };\n }\n },\n );\n\n return () => (state.value.done ? state.value.value : (pendingFn?.() ?? ''));\n}\n"],"mappings":"2CA6BA,SAAgB,EACd,EACA,EACA,EAC2B,CAC3B,IAAM,EAAQ,EAAc,CAAE,KAAM,GAAO,CAAC,CAe5C,OAbA,EAAQ,KACL,GAAQ,CACP,EAAM,MAAQ,CAAE,KAAM,GAAM,MAAO,EAAK,EAEzC,GAAQ,CACH,EACF,EAAM,MAAQ,CAAE,KAAM,GAAM,MAAO,EAAQ,EAAI,CAAE,CAEjD,EAAM,MAAQ,CAAE,KAAM,GAAM,MAAO,UAAU,OAAO,EAAI,GAAI,EAGjE,KAEa,EAAM,MAAM,KAAO,EAAM,MAAM,MAAS,KAAa,EAAI"}
@@ -0,0 +1,2 @@
1
+ let e=require(`@vielzeug/stateit`);function t(t,n,r){if((0,e.isSignal)(t)||typeof t==`function`){let i=(0,e.isSignal)(t)?()=>t.value:t;return{render:()=>i()?n():r?.()??``}}return t?n():r?.()??``}exports.when=t;
2
+ //# sourceMappingURL=when.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"when.cjs","names":[],"sources":["../../src/directives/when.ts"],"sourcesContent":["import { isSignal, type ReadonlySignal, type Signal } from '@vielzeug/stateit';\n\nimport type { Directive, HTMLResult } from '../core/internal';\n\n/**\n * Conditionally renders one of two templates based on a condition.\n *\n * - **Signal or getter** — returns a reactive function the engine re-runs automatically.\n * - **Static value** — evaluated once at call time, returns the result directly.\n *\n * @example\n * import { when } from '@vielzeug/craftit/directives';\n *\n * html`${when(isLoggedIn, () => html`<user-panel>`, () => html`<login-form>`)}`\n * html`${when(() => count.value > 0, () => html`<span>${count}</span>`)}`\n */\nexport function when<V extends string | HTMLResult>(\n condition: Signal<unknown> | ReadonlySignal<unknown> | (() => unknown),\n thenFn: () => V,\n elseFn?: () => V,\n): Directive;\nexport function when<V extends string | HTMLResult>(condition: unknown, thenFn: () => V, elseFn?: () => V): V | string;\nexport function when<V extends string | HTMLResult>(\n condition: unknown,\n thenFn: () => V,\n elseFn?: () => V,\n): V | string | Directive {\n if (isSignal(condition) || typeof condition === 'function') {\n const get = isSignal(condition) ? () => (condition as ReadonlySignal<unknown>).value : (condition as () => unknown);\n\n return {\n render: (): string | HTMLResult => (get() ? thenFn() : (elseFn?.() ?? '')),\n };\n }\n\n return condition ? thenFn() : (elseFn?.() ?? '');\n}\n"],"mappings":"mCAsBA,SAAgB,EACd,EACA,EACA,EACwB,CACxB,IAAA,EAAA,EAAA,UAAa,EAAU,EAAI,OAAO,GAAc,WAAY,CAC1D,IAAM,GAAA,EAAA,EAAA,UAAe,EAAU,KAAU,EAAsC,MAAS,EAExF,MAAO,CACL,WAAoC,GAAK,CAAG,GAAQ,CAAI,KAAU,EAAI,GACvE,CAGH,OAAO,EAAY,GAAQ,CAAI,KAAU,EAAI"}
@@ -0,0 +1,17 @@
1
+ import { type ReadonlySignal, type Signal } from '@vielzeug/stateit';
2
+ import type { Directive, HTMLResult } from '../core/internal';
3
+ /**
4
+ * Conditionally renders one of two templates based on a condition.
5
+ *
6
+ * - **Signal or getter** — returns a reactive function the engine re-runs automatically.
7
+ * - **Static value** — evaluated once at call time, returns the result directly.
8
+ *
9
+ * @example
10
+ * import { when } from '@vielzeug/craftit/directives';
11
+ *
12
+ * html`${when(isLoggedIn, () => html`<user-panel>`, () => html`<login-form>`)}`
13
+ * html`${when(() => count.value > 0, () => html`<span>${count}</span>`)}`
14
+ */
15
+ export declare function when<V extends string | HTMLResult>(condition: Signal<unknown> | ReadonlySignal<unknown> | (() => unknown), thenFn: () => V, elseFn?: () => V): Directive;
16
+ export declare function when<V extends string | HTMLResult>(condition: unknown, thenFn: () => V, elseFn?: () => V): V | string;
17
+ //# sourceMappingURL=when.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"when.d.ts","sourceRoot":"","sources":["../../src/directives/when.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,cAAc,EAAE,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE/E,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9D;;;;;;;;;;;GAWG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,MAAM,GAAG,UAAU,EAChD,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,OAAO,CAAC,EACtE,MAAM,EAAE,MAAM,CAAC,EACf,MAAM,CAAC,EAAE,MAAM,CAAC,GACf,SAAS,CAAC;AACb,wBAAgB,IAAI,CAAC,CAAC,SAAS,MAAM,GAAG,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC"}
@@ -0,0 +1,2 @@
1
+ import{isSignal as e}from"@vielzeug/stateit";function t(t,n,r){if(e(t)||typeof t==`function`){let i=e(t)?()=>t.value:t;return{render:()=>i()?n():r?.()??``}}return t?n():r?.()??``}export{t as when};
2
+ //# sourceMappingURL=when.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"when.js","names":[],"sources":["../../src/directives/when.ts"],"sourcesContent":["import { isSignal, type ReadonlySignal, type Signal } from '@vielzeug/stateit';\n\nimport type { Directive, HTMLResult } from '../core/internal';\n\n/**\n * Conditionally renders one of two templates based on a condition.\n *\n * - **Signal or getter** — returns a reactive function the engine re-runs automatically.\n * - **Static value** — evaluated once at call time, returns the result directly.\n *\n * @example\n * import { when } from '@vielzeug/craftit/directives';\n *\n * html`${when(isLoggedIn, () => html`<user-panel>`, () => html`<login-form>`)}`\n * html`${when(() => count.value > 0, () => html`<span>${count}</span>`)}`\n */\nexport function when<V extends string | HTMLResult>(\n condition: Signal<unknown> | ReadonlySignal<unknown> | (() => unknown),\n thenFn: () => V,\n elseFn?: () => V,\n): Directive;\nexport function when<V extends string | HTMLResult>(condition: unknown, thenFn: () => V, elseFn?: () => V): V | string;\nexport function when<V extends string | HTMLResult>(\n condition: unknown,\n thenFn: () => V,\n elseFn?: () => V,\n): V | string | Directive {\n if (isSignal(condition) || typeof condition === 'function') {\n const get = isSignal(condition) ? () => (condition as ReadonlySignal<unknown>).value : (condition as () => unknown);\n\n return {\n render: (): string | HTMLResult => (get() ? thenFn() : (elseFn?.() ?? '')),\n };\n }\n\n return condition ? thenFn() : (elseFn?.() ?? '');\n}\n"],"mappings":"6CAsBA,SAAgB,EACd,EACA,EACA,EACwB,CACxB,GAAI,EAAS,EAAU,EAAI,OAAO,GAAc,WAAY,CAC1D,IAAM,EAAM,EAAS,EAAU,KAAU,EAAsC,MAAS,EAExF,MAAO,CACL,WAAoC,GAAK,CAAG,GAAQ,CAAI,KAAU,EAAI,GACvE,CAGH,OAAO,EAAY,GAAQ,CAAI,KAAU,EAAI"}
package/dist/index.cjs CHANGED
@@ -1,2 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./craftit.cjs");exports.attach=e.attach;exports.classMap=e.classMap;exports.createComponent=e.createComponent;exports.css=e.css;exports.defineElement=e.defineElement;exports.destroy=e.destroy;exports.element=e.element;exports.html=e.html;exports.styleMap=e.styleMap;
2
- //# sourceMappingURL=index.cjs.map
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./core/internal.cjs`),t=require(`./core/runtime-lifecycle.cjs`),n=require(`./core/utilities.cjs`),r=require(`./core/host.cjs`),i=require(`./core/template.cjs`),a=require(`./core/component.cjs`),o=require(`./labs/observers.cjs`);exports.aria=t.aria,exports.createContext=r.createContext,exports.createFormIds=n.createFormIds,exports.createId=n.createId,exports.css=n.css,exports.defineComponent=a.defineComponent,exports.defineField=a.defineField,exports.effect=t.effect,exports.escapeHtml=n.escapeHtml,exports.fire=t.fire,exports.guard=n.guard,exports.handle=t.handle,exports.html=i.html,exports.inject=r.inject,exports.observeResize=o.observeResize,exports.onCleanup=t.onCleanup,exports.onError=t.onError,exports.onMount=t.onMount,exports.onSlotChange=r.onSlotChange,exports.prop=a.prop,exports.provide=r.provide,exports.ref=e.ref,exports.reflect=r.reflect,exports.refs=e.refs,exports.syncContextProps=r.syncContextProps,exports.toKebab=n.toKebab,exports.typed=a.typed,exports.watch=t.watch;var s=require(`@vielzeug/stateit`);Object.keys(s).forEach(function(e){e!==`default`&&!Object.prototype.hasOwnProperty.call(exports,e)&&Object.defineProperty(exports,e,{enumerable:!0,get:function(){return s[e]}})});
package/dist/index.d.ts CHANGED
@@ -1,265 +1,10 @@
1
- /**
2
- * Attach/mount a component to the DOM and wait for first render
3
- * @param element - The element to attach
4
- * @param container - Optional container (defaults to document.body)
5
- * @returns Promise that resolves when component is mounted and rendered
6
- * @example
7
- * const el = document.createElement('my-component');
8
- * await attach(el);
9
- * // Component is now in DOM and rendered
10
- */
11
- export declare function attach<T extends HTMLElement>(element: T, container?: HTMLElement): Promise<T>;
12
-
13
- /**
14
- * Callback invoked when an observed attribute changes
15
- * @template T - Root element type
16
- * @template S - State object type
17
- */
18
- export declare type AttributeChangeHook<T = HTMLElement, S extends object = object> = (name: string, oldValue: string | null, newValue: string | null, el: WebComponent<T, S>) => void;
19
-
20
- /**
21
- * Conditional class helper
22
- * @param classes - Object mapping class names to boolean conditions
23
- * @returns Space-separated class string
24
- * @example classMap({ active: true, disabled: false }) // 'active'
25
- */
26
- export declare const classMap: (classes: Record<string, boolean | undefined>) => string;
27
-
28
- /**
29
- * Configuration options for creating a web component
30
- * @template T - Root element type
31
- * @template S - State object type
32
- */
33
- export declare type ComponentOptions<T = HTMLElement, S extends object = object> = {
34
- /** Template for rendering the component */
35
- template: Template<T, S>;
36
- /** Initial reactive state */
37
- state?: S;
38
- /** CSS styles (strings or CSSStyleSheet objects) */
39
- styles?: (string | CSSStyleSheet)[];
40
- /** Attributes to observe for changes */
41
- observedAttributes?: readonly string[];
42
- /** Enable form association (allows component to participate in forms) */
43
- formAssociated?: boolean;
44
- /** Called when component is added to DOM */
45
- onConnected?: LifecycleHook<T, S>;
46
- /** Called when component is removed from DOM */
47
- onDisconnected?: LifecycleHook<T, S>;
48
- /** Called when an observed attribute changes */
49
- onAttributeChanged?: AttributeChangeHook<T, S>;
50
- /** Called after each render completes */
51
- onUpdated?: LifecycleHook<T, S>;
52
- } & FormCallbacks<T, S>;
53
-
54
- /**
55
- * Create a web component class
56
- * @template T - Root element type
57
- * @template S - State object type
58
- * @param options - Component configuration
59
- * @returns Custom element constructor
60
- */
61
- export declare const createComponent: <T = HTMLElement, S extends object = object>(options: ComponentOptions<T, S>) => CustomElementConstructor;
62
-
63
- export declare const css: ((strings: TemplateStringsArray, ...values: unknown[]) => string) & {
64
- /**
65
- * Create a typed theme with CSS variables and autocomplete
66
- *
67
- * Single theme mode:
68
- * Returns a typed proxy with autocomplete for all theme properties
69
- *
70
- * Light/dark mode:
71
- * Returns the same typed proxy - CSS handles which theme applies via media queries
72
- * You reference variables the same way regardless of theme mode
73
- *
74
- * @param light - Theme variables (or light theme for dual-mode)
75
- * @param dark - Optional dark theme variables
76
- * @param options - Configuration options
77
- * @param options.selector - CSS selector (default: ':host')
78
- * @param options.attribute - Attribute for manual override (default: 'data-theme')
79
- * @returns Typed proxy with autocomplete
80
- *
81
- * @example
82
- * // Single theme
83
- * const theme = css.theme({
84
- * primaryColor: '#3b82f6',
85
- * spacing: '1rem',
86
- * });
87
- *
88
- * css`
89
- * ${theme}
90
- * .button {
91
- * color: ${theme.primaryColor}; // Autocomplete!
92
- * padding: ${theme.spacing};
93
- * }
94
- * `
95
- *
96
- * @example
97
- * // Light/dark theme - same variable references!
98
- * const theme = css.theme(
99
- * { bg: '#fff', text: '#000' }, // Light
100
- * { bg: '#000', text: '#fff' } // Dark
101
- * );
102
- *
103
- * css`
104
- * ${theme}
105
- * .card {
106
- * background: ${theme.bg}; // Autocomplete! CSS handles light/dark
107
- * color: ${theme.text}; // Same variable for both themes
108
- * }
109
- * `
110
- */
111
- theme: {
112
- <T extends Record<string, string | number>>(vars: T, dark?: undefined, options?: {
113
- selector?: string;
114
- }): ThemeVars<T>;
115
- <T extends Record<string, string | number>>(light: T, dark: T, options?: {
116
- selector?: string;
117
- attribute?: string;
118
- }): ThemeVars<T>;
119
- };
120
- /**
121
- * Reference a CSS custom property with var()
122
- * Automatically converts camelCase to --kebab-case
123
- * @param name - Variable name (with or without --)
124
- * @param fallback - Optional fallback value
125
- * @returns var() function string
126
- * @example css.var('primaryColor') // "var(--primary-color)"
127
- */
128
- var: (name: string, fallback?: string | number) => string;
129
- };
130
-
131
- /**
132
- * Define a custom element
133
- * @template T - Root element type
134
- * @template S - State object type
135
- * @param name - Element tag name (must contain hyphen)
136
- * @param options - Component configuration
137
- */
138
- export declare const defineElement: <T = HTMLElement, S extends object = object>(name: string, options: ComponentOptions<T, S>) => void;
139
-
140
- /**
141
- * Remove a component from the DOM with cleanup
142
- * @param element - The element to destroy
143
- * @example
144
- * const el = await attach(document.createElement('my-component'));
145
- * // ... test code ...
146
- * destroy(el); // Clean removal
147
- */
148
- export declare function destroy(element: HTMLElement): void;
149
-
150
- /**
151
- * Create and define an element in one call
152
- * @template T - Root element type
153
- * @template S - State object type
154
- * @param name - Element tag name (must contain hyphen)
155
- * @param options - Component configuration
156
- * @returns Custom element constructor
157
- */
158
- export declare const element: <T = HTMLElement, S extends object = object>(name: string, options: ComponentOptions<T, S>) => CustomElementConstructor;
159
-
160
- /**
161
- * Callbacks for form-associated custom elements
162
- * @template T - Root element type
163
- * @template S - State object type
164
- */
165
- export declare type FormCallbacks<T = HTMLElement, S extends object = object> = {
166
- /** Invoked when parent form's disabled state changes */
167
- onFormDisabled?: (disabled: boolean, el: WebComponent<T, S>) => void;
168
- /** Invoked when parent form is reset */
169
- onFormReset?: (el: WebComponent<T, S>) => void;
170
- /** Invoked when browser restores form state (navigation/autocomplete) */
171
- onFormStateRestore?: (state: string | File | FormData | null, mode: 'restore' | 'autocomplete', el: WebComponent<T, S>) => void;
172
- };
173
-
174
- /**
175
- * HTML template string helper
176
- * @param strings - Template string array
177
- * @param values - Template values
178
- * @returns Interpolated HTML string
179
- */
180
- export declare const html: (strings: TemplateStringsArray, ...values: unknown[]) => string;
181
-
182
- /** biome-ignore-all lint/suspicious/noExplicitAny: Template values can be any type */
183
- /**
184
- * Lifecycle hook function called with component instance
185
- * @template T - Root element type
186
- * @template S - State object type
187
- */
188
- export declare type LifecycleHook<T = HTMLElement, S extends object = object> = (el: WebComponent<T, S>) => void;
189
-
190
- /**
191
- * Conditional style helper
192
- * @param styles - Object mapping CSS properties to values
193
- * @returns Semicolon-separated style string
194
- * @example styleMap({ color: 'red', display: undefined }) // 'color: red'
195
- */
196
- export declare const styleMap: (styles: Partial<CSSStyleDeclaration>) => string;
197
-
198
- /**
199
- * Component template - can be a string, DOM node, or function returning either
200
- * @template T - Root element type
201
- * @template S - State object type
202
- */
203
- export declare type Template<T = HTMLElement, S extends object = object> = string | Node | ((el: WebComponent<T, S>) => string | Node | DocumentFragment);
204
-
205
- /**
206
- * CSS template string helper with CSS variable utilities
207
- * @param strings - Template string array
208
- * @param values - Template values
209
- * @returns Interpolated CSS string
210
- * @example css`.button { color: ${color}; }`
211
- */
212
- /** Type helper for theme variable proxy */
213
- declare type ThemeVars<T extends Record<string, string | number>> = {
214
- [K in keyof T]: string;
215
- };
216
-
217
- /**
218
- * Web component instance interface
219
- * @template T - Root element type (first child in shadow DOM)
220
- * @template S - State object type
221
- */
222
- export declare type WebComponent<T = HTMLElement, S extends object = object> = HTMLElement & {
223
- /** Reactive state object (changes trigger re-renders) */
224
- readonly state: S;
225
- /** Shadow DOM root */
226
- readonly shadow: ShadowRoot;
227
- /** First element in shadow DOM */
228
- readonly root: T;
229
- /** ElementInternals (only when formAssociated: true) */
230
- readonly internals?: ElementInternals;
231
- /** Form value (only when formAssociated: true) */
232
- value?: string;
233
- /** Schedule a render in the next animation frame */
234
- render(): void;
235
- /** Wait for the pending render to complete */
236
- flush(): Promise<void>;
237
- /** Update state (merge, replace, or via function) */
238
- set(patch: Partial<S> | ((state: S) => S | Promise<S>), options?: {
239
- replace?: boolean;
240
- silent?: boolean;
241
- }): Promise<void>;
242
- /** Watch a state slice and react to changes */
243
- watch<U>(selector: (state: S) => U, callback: (value: U, prev: U) => void): () => void;
244
- /** Find a single element in shadow DOM */
245
- find<E extends Element = Element>(selector: string): E | null;
246
- /** Find all matching elements in shadow DOM */
247
- findAll<E extends Element = Element>(selector: string): E[];
248
- /** Add event listener with automatic cleanup and delegation support */
249
- on(target: string | EventTarget, event: string, handler: EventListener, options?: AddEventListenerOptions): void;
250
- /** Dispatch custom event */
251
- emit(name: string, detail?: unknown, options?: CustomEventInit): void;
252
- /** Set timeout with automatic cleanup */
253
- delay(callback: () => void, ms: number): number;
254
- /** Clear scheduled timeout */
255
- clear(id: number): void;
256
- /** Form utilities (only when formAssociated: true) */
257
- form?: {
258
- /** Set form value */
259
- value(value: string | File | FormData | null, state?: File | FormData | null): void;
260
- /** Set a validation state */
261
- valid(flags?: ValidityStateFlags, message?: string, anchor?: HTMLElement): void;
262
- };
263
- };
264
-
265
- export { }
1
+ export * from '@vielzeug/stateit';
2
+ export { aria, effect, fire, handle, onCleanup, onError, onMount, watch } from './core/runtime-lifecycle';
3
+ export { defineComponent, defineField, prop, typed, type BuildPropSchema, type DefineComponentOptions, type DefineComponentSetupContext, type FormFieldCallbacks, type FormFieldHandle, type FormFieldOptions, type InferPropsSignals, type PropDef, type PropOptions, } from './core/component';
4
+ export { createContext, inject, onSlotChange, provide, syncContextProps, type InjectionKey, type Slots, } from './core/host';
5
+ export { reflect, type HostBindingValue, type ReflectConfig } from './core/host';
6
+ export { html, type KeyedNode } from './core/template';
7
+ export { ref, refs, type Directive, type HTMLResult, type Ref, type RefCallback, type Refs } from './core/internal';
8
+ export { createFormIds, createId, css, escapeHtml, guard, toKebab, type CSSResult, type EmitFn, } from './core/utilities';
9
+ export { observeResize } from './labs/observers';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAElC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAE1G,OAAO,EACL,eAAe,EACf,WAAW,EACX,IAAI,EACJ,KAAK,EACL,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC3B,KAAK,2BAA2B,EAChC,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,OAAO,EACZ,KAAK,WAAW,GACjB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,aAAa,EACb,MAAM,EACN,YAAY,EACZ,OAAO,EACP,gBAAgB,EAChB,KAAK,YAAY,EACjB,KAAK,KAAK,GACX,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjF,OAAO,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEvD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,KAAK,GAAG,EAAE,KAAK,WAAW,EAAE,KAAK,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAEpH,OAAO,EACL,aAAa,EACb,QAAQ,EACR,GAAG,EACH,UAAU,EACV,KAAK,EACL,OAAO,EACP,KAAK,SAAS,EACd,KAAK,MAAM,GACZ,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -1,13 +1 @@
1
- import { attach as a, classMap as s, createComponent as l, css as m, defineElement as n, destroy as o, element as c, html as p, styleMap as r } from "./craftit.js";
2
- export {
3
- a as attach,
4
- s as classMap,
5
- l as createComponent,
6
- m as css,
7
- n as defineElement,
8
- o as destroy,
9
- c as element,
10
- p as html,
11
- r as styleMap
12
- };
13
- //# sourceMappingURL=index.js.map
1
+ import{ref as e,refs as t}from"./core/internal.js";import{aria as n,effect as r,fire as i,handle as a,onCleanup as o,onError as s,onMount as c,watch as l}from"./core/runtime-lifecycle.js";import{createFormIds as u,createId as d,css as f,escapeHtml as p,guard as m,toKebab as h}from"./core/utilities.js";import{createContext as g,inject as _,onSlotChange as v,provide as y,reflect as b,syncContextProps as x}from"./core/host.js";import{html as S}from"./core/template.js";import{defineComponent as C,defineField as w,prop as T,typed as E}from"./core/component.js";import{observeResize as D}from"./labs/observers.js";export*from"@vielzeug/stateit";export{n as aria,g as createContext,u as createFormIds,d as createId,f as css,C as defineComponent,w as defineField,r as effect,p as escapeHtml,i as fire,m as guard,a as handle,S as html,_ as inject,D as observeResize,o as onCleanup,s as onError,c as onMount,v as onSlotChange,T as prop,y as provide,e as ref,b as reflect,t as refs,x as syncContextProps,h as toKebab,E as typed,l as watch};
@@ -0,0 +1,2 @@
1
+ const e=require(`../core/runtime-lifecycle.cjs`),t=require(`../core/utilities.cjs`);require(`../core/runtime.cjs`);function n(n,r){let i=r.labelId||t.createId(`a11y-label`),a=r.helperId||t.createId(`a11y-helper`),o=null;return n.setAttribute(`role`,r.role),e.onMount(()=>{let t=n.shadowRoot;if(t&&(o=t.querySelector(`[data-a11y-helper]`)),t){let e=t.querySelector(`[data-a11y-label]`);if(e){let t=e.querySelector(`slot`);(t?t.assignedNodes().length>0:e.textContent?.trim().length??!1)&&(e.id=i,n.setAttribute(`aria-labelledby`,i))}}e.effect(()=>{if(r.checked){let e=r.checked();e!==void 0&&n.setAttribute(`aria-checked`,e)}if(r.invalid){let e=r.invalid();n.setAttribute(`aria-invalid`,String(e))}if(r.helperText&&o){let e=r.helperText();e?(o.textContent=e,o.hidden=!1,n.setAttribute(`aria-describedby`,a),(r.helperTone?.()??`default`)===`error`?o.setAttribute(`role`,`alert`):o.removeAttribute(`role`)):(o.hidden=!0,n.removeAttribute(`aria-describedby`))}})}),{helperId:a,labelId:i}}exports.useA11yControl=n;
2
+ //# sourceMappingURL=a11y.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"a11y.cjs","names":[],"sources":["../../src/labs/a11y.ts"],"sourcesContent":["import { effect, onMount } from '../core/runtime';\nimport { createId } from '../core/utilities';\n\n/**\n * Tone of helper/error text: 'default' for helper, 'error' for error message.\n */\nexport type A11yTone = 'default' | 'error';\n\n/**\n * Configuration for `useA11yControl()`.\n *\n * Label presence is detected via DOM query (not heuristics).\n * All other state getters are reactive and can change over time.\n */\nexport type A11yControlConfig = {\n /** Reactive aria-checked value ('true' | 'false' | 'mixed' | undefined) */\n checked?: () => 'true' | 'false' | 'mixed' | undefined;\n /** Optional: custom helper ID instead of auto-generated */\n helperId?: string;\n /** Helper text content (mutually exclusive with explicit label/helper management) */\n helperText?: () => string | undefined;\n /** Tone of helper text: 'error' to set role=\"alert\", 'default' otherwise */\n helperTone?: () => A11yTone;\n /** Reactive aria-invalid value */\n invalid?: () => boolean;\n /** Optional: custom label ID instead of auto-generated */\n labelId?: string;\n /** ARIA role (e.g., 'checkbox', 'radio', 'switch') */\n role: string;\n};\n\n/**\n * Return value from `useA11yControl()`.\n */\nexport type A11yControlHandle = {\n /** ID for helper text element */\n helperId: string;\n /** ID for label element */\n labelId: string;\n};\n\n/**\n * Manages ARIA attributes, IDs, and helper/error live region for accessible form controls.\n *\n * Encapsulates:\n * - Stable ID generation for labels and helpers\n * - `aria-labelledby` wiring when label is present (detected via DOM query)\n * - `aria-describedby` wiring when helper text is present\n * - `aria-invalid` sync with error state\n * - `aria-checked` for checkable controls\n * - Helper text live region with `aria-live=\"polite\"` or `role=\"alert\"` based on tone\n *\n * @example\n * const a11y = useA11yControl(host, {\n * role: 'checkbox',\n * checked: () => indeterminate.value ? 'mixed' : String(checked.value),\n * invalid: () => !!error.value,\n * helperText: () => error.value || helper.value,\n * helperTone: () => error.value ? 'error' : 'default',\n * });\n *\n * // Later in template:\n * // <span id=${a11y.labelId}>Label</span>\n * // <div id=${a11y.helperId} aria-live=\"polite\">Error or helper text</div>\n */\nexport function useA11yControl(host: HTMLElement, config: A11yControlConfig): A11yControlHandle {\n const labelId = config.labelId || createId('a11y-label');\n const helperId = config.helperId || createId('a11y-helper');\n\n let helperElement: HTMLDivElement | null = null;\n\n // Set role once at setup\n host.setAttribute('role', config.role);\n\n onMount(() => {\n // Find helper element in shadow DOM\n const shadow = host.shadowRoot;\n\n if (shadow) {\n helperElement = shadow.querySelector('[data-a11y-helper]') as HTMLDivElement | null;\n }\n\n // Detect label presence via DOM query: check if label span has slotted content\n if (shadow) {\n const labelSpan = shadow.querySelector('[data-a11y-label]') as HTMLElement | null;\n\n if (labelSpan) {\n // Check if the label slot has any assigned nodes\n const slot = labelSpan.querySelector('slot') as HTMLSlotElement | null;\n const hasLabelContent = slot\n ? slot.assignedNodes().length > 0\n : (labelSpan.textContent?.trim().length ?? 0 > 0);\n\n if (hasLabelContent) {\n labelSpan.id = labelId;\n host.setAttribute('aria-labelledby', labelId);\n }\n }\n }\n\n // Reactive effects for aria attrs that can change\n effect(() => {\n // aria-checked\n if (config.checked) {\n const checked = config.checked();\n\n if (checked !== undefined) {\n host.setAttribute('aria-checked', checked);\n }\n }\n\n // aria-invalid\n if (config.invalid) {\n const invalid = config.invalid();\n\n host.setAttribute('aria-invalid', String(invalid));\n }\n\n // Helper text and describedby\n if (config.helperText && helperElement) {\n const text = config.helperText();\n\n if (text) {\n helperElement.textContent = text;\n helperElement.hidden = false;\n host.setAttribute('aria-describedby', helperId);\n\n // Set role based on explicit tone (no text heuristics)\n const tone = config.helperTone?.() ?? 'default';\n\n if (tone === 'error') {\n helperElement.setAttribute('role', 'alert');\n } else {\n helperElement.removeAttribute('role');\n }\n } else {\n helperElement.hidden = true;\n host.removeAttribute('aria-describedby');\n }\n }\n });\n });\n\n return {\n helperId,\n labelId,\n };\n}\n"],"mappings":"mHAiEA,SAAgB,EAAe,EAAmB,EAA8C,CAC9F,IAAM,EAAU,EAAO,SAAW,EAAA,SAAS,aAAa,CAClD,EAAW,EAAO,UAAY,EAAA,SAAS,cAAc,CAEvD,EAAuC,KA0E3C,OAvEA,EAAK,aAAa,OAAQ,EAAO,KAAK,CAEtC,EAAA,YAAc,CAEZ,IAAM,EAAS,EAAK,WAOpB,GALI,IACF,EAAgB,EAAO,cAAc,qBAAqB,EAIxD,EAAQ,CACV,IAAM,EAAY,EAAO,cAAc,oBAAoB,CAE3D,GAAI,EAAW,CAEb,IAAM,EAAO,EAAU,cAAc,OAAO,EACpB,EACpB,EAAK,eAAe,CAAC,OAAS,EAC7B,EAAU,aAAa,MAAM,CAAC,QAAU,MAG3C,EAAU,GAAK,EACf,EAAK,aAAa,kBAAmB,EAAQ,GAMnD,EAAA,WAAa,CAEX,GAAI,EAAO,QAAS,CAClB,IAAM,EAAU,EAAO,SAAS,CAE5B,IAAY,IAAA,IACd,EAAK,aAAa,eAAgB,EAAQ,CAK9C,GAAI,EAAO,QAAS,CAClB,IAAM,EAAU,EAAO,SAAS,CAEhC,EAAK,aAAa,eAAgB,OAAO,EAAQ,CAAC,CAIpD,GAAI,EAAO,YAAc,EAAe,CACtC,IAAM,EAAO,EAAO,YAAY,CAE5B,GACF,EAAc,YAAc,EAC5B,EAAc,OAAS,GACvB,EAAK,aAAa,mBAAoB,EAAS,EAGlC,EAAO,cAAc,EAAI,aAEzB,QACX,EAAc,aAAa,OAAQ,QAAQ,CAE3C,EAAc,gBAAgB,OAAO,GAGvC,EAAc,OAAS,GACvB,EAAK,gBAAgB,mBAAmB,IAG5C,EACF,CAEK,CACL,WACA,UACD"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Tone of helper/error text: 'default' for helper, 'error' for error message.
3
+ */
4
+ export type A11yTone = 'default' | 'error';
5
+ /**
6
+ * Configuration for `useA11yControl()`.
7
+ *
8
+ * Label presence is detected via DOM query (not heuristics).
9
+ * All other state getters are reactive and can change over time.
10
+ */
11
+ export type A11yControlConfig = {
12
+ /** Reactive aria-checked value ('true' | 'false' | 'mixed' | undefined) */
13
+ checked?: () => 'true' | 'false' | 'mixed' | undefined;
14
+ /** Optional: custom helper ID instead of auto-generated */
15
+ helperId?: string;
16
+ /** Helper text content (mutually exclusive with explicit label/helper management) */
17
+ helperText?: () => string | undefined;
18
+ /** Tone of helper text: 'error' to set role="alert", 'default' otherwise */
19
+ helperTone?: () => A11yTone;
20
+ /** Reactive aria-invalid value */
21
+ invalid?: () => boolean;
22
+ /** Optional: custom label ID instead of auto-generated */
23
+ labelId?: string;
24
+ /** ARIA role (e.g., 'checkbox', 'radio', 'switch') */
25
+ role: string;
26
+ };
27
+ /**
28
+ * Return value from `useA11yControl()`.
29
+ */
30
+ export type A11yControlHandle = {
31
+ /** ID for helper text element */
32
+ helperId: string;
33
+ /** ID for label element */
34
+ labelId: string;
35
+ };
36
+ /**
37
+ * Manages ARIA attributes, IDs, and helper/error live region for accessible form controls.
38
+ *
39
+ * Encapsulates:
40
+ * - Stable ID generation for labels and helpers
41
+ * - `aria-labelledby` wiring when label is present (detected via DOM query)
42
+ * - `aria-describedby` wiring when helper text is present
43
+ * - `aria-invalid` sync with error state
44
+ * - `aria-checked` for checkable controls
45
+ * - Helper text live region with `aria-live="polite"` or `role="alert"` based on tone
46
+ *
47
+ * @example
48
+ * const a11y = useA11yControl(host, {
49
+ * role: 'checkbox',
50
+ * checked: () => indeterminate.value ? 'mixed' : String(checked.value),
51
+ * invalid: () => !!error.value,
52
+ * helperText: () => error.value || helper.value,
53
+ * helperTone: () => error.value ? 'error' : 'default',
54
+ * });
55
+ *
56
+ * // Later in template:
57
+ * // <span id=${a11y.labelId}>Label</span>
58
+ * // <div id=${a11y.helperId} aria-live="polite">Error or helper text</div>
59
+ */
60
+ export declare function useA11yControl(host: HTMLElement, config: A11yControlConfig): A11yControlHandle;
61
+ //# sourceMappingURL=a11y.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"a11y.d.ts","sourceRoot":"","sources":["../../src/labs/a11y.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;AAE3C;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;IACvD,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qFAAqF;IACrF,UAAU,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACtC,4EAA4E;IAC5E,UAAU,CAAC,EAAE,MAAM,QAAQ,CAAC;IAC5B,kCAAkC;IAClC,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC;IACxB,0DAA0D;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,iCAAiC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,2BAA2B;IAC3B,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,iBAAiB,GAAG,iBAAiB,CAkF9F"}
@@ -0,0 +1,2 @@
1
+ import{effect as e,onMount as t}from"../core/runtime-lifecycle.js";import{createId as n}from"../core/utilities.js";import"../core/runtime.js";function r(r,i){let a=i.labelId||n(`a11y-label`),o=i.helperId||n(`a11y-helper`),s=null;return r.setAttribute(`role`,i.role),t(()=>{let t=r.shadowRoot;if(t&&(s=t.querySelector(`[data-a11y-helper]`)),t){let e=t.querySelector(`[data-a11y-label]`);if(e){let t=e.querySelector(`slot`);(t?t.assignedNodes().length>0:e.textContent?.trim().length??!1)&&(e.id=a,r.setAttribute(`aria-labelledby`,a))}}e(()=>{if(i.checked){let e=i.checked();e!==void 0&&r.setAttribute(`aria-checked`,e)}if(i.invalid){let e=i.invalid();r.setAttribute(`aria-invalid`,String(e))}if(i.helperText&&s){let e=i.helperText();e?(s.textContent=e,s.hidden=!1,r.setAttribute(`aria-describedby`,o),(i.helperTone?.()??`default`)===`error`?s.setAttribute(`role`,`alert`):s.removeAttribute(`role`)):(s.hidden=!0,r.removeAttribute(`aria-describedby`))}})}),{helperId:o,labelId:a}}export{r as useA11yControl};
2
+ //# sourceMappingURL=a11y.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"a11y.js","names":[],"sources":["../../src/labs/a11y.ts"],"sourcesContent":["import { effect, onMount } from '../core/runtime';\nimport { createId } from '../core/utilities';\n\n/**\n * Tone of helper/error text: 'default' for helper, 'error' for error message.\n */\nexport type A11yTone = 'default' | 'error';\n\n/**\n * Configuration for `useA11yControl()`.\n *\n * Label presence is detected via DOM query (not heuristics).\n * All other state getters are reactive and can change over time.\n */\nexport type A11yControlConfig = {\n /** Reactive aria-checked value ('true' | 'false' | 'mixed' | undefined) */\n checked?: () => 'true' | 'false' | 'mixed' | undefined;\n /** Optional: custom helper ID instead of auto-generated */\n helperId?: string;\n /** Helper text content (mutually exclusive with explicit label/helper management) */\n helperText?: () => string | undefined;\n /** Tone of helper text: 'error' to set role=\"alert\", 'default' otherwise */\n helperTone?: () => A11yTone;\n /** Reactive aria-invalid value */\n invalid?: () => boolean;\n /** Optional: custom label ID instead of auto-generated */\n labelId?: string;\n /** ARIA role (e.g., 'checkbox', 'radio', 'switch') */\n role: string;\n};\n\n/**\n * Return value from `useA11yControl()`.\n */\nexport type A11yControlHandle = {\n /** ID for helper text element */\n helperId: string;\n /** ID for label element */\n labelId: string;\n};\n\n/**\n * Manages ARIA attributes, IDs, and helper/error live region for accessible form controls.\n *\n * Encapsulates:\n * - Stable ID generation for labels and helpers\n * - `aria-labelledby` wiring when label is present (detected via DOM query)\n * - `aria-describedby` wiring when helper text is present\n * - `aria-invalid` sync with error state\n * - `aria-checked` for checkable controls\n * - Helper text live region with `aria-live=\"polite\"` or `role=\"alert\"` based on tone\n *\n * @example\n * const a11y = useA11yControl(host, {\n * role: 'checkbox',\n * checked: () => indeterminate.value ? 'mixed' : String(checked.value),\n * invalid: () => !!error.value,\n * helperText: () => error.value || helper.value,\n * helperTone: () => error.value ? 'error' : 'default',\n * });\n *\n * // Later in template:\n * // <span id=${a11y.labelId}>Label</span>\n * // <div id=${a11y.helperId} aria-live=\"polite\">Error or helper text</div>\n */\nexport function useA11yControl(host: HTMLElement, config: A11yControlConfig): A11yControlHandle {\n const labelId = config.labelId || createId('a11y-label');\n const helperId = config.helperId || createId('a11y-helper');\n\n let helperElement: HTMLDivElement | null = null;\n\n // Set role once at setup\n host.setAttribute('role', config.role);\n\n onMount(() => {\n // Find helper element in shadow DOM\n const shadow = host.shadowRoot;\n\n if (shadow) {\n helperElement = shadow.querySelector('[data-a11y-helper]') as HTMLDivElement | null;\n }\n\n // Detect label presence via DOM query: check if label span has slotted content\n if (shadow) {\n const labelSpan = shadow.querySelector('[data-a11y-label]') as HTMLElement | null;\n\n if (labelSpan) {\n // Check if the label slot has any assigned nodes\n const slot = labelSpan.querySelector('slot') as HTMLSlotElement | null;\n const hasLabelContent = slot\n ? slot.assignedNodes().length > 0\n : (labelSpan.textContent?.trim().length ?? 0 > 0);\n\n if (hasLabelContent) {\n labelSpan.id = labelId;\n host.setAttribute('aria-labelledby', labelId);\n }\n }\n }\n\n // Reactive effects for aria attrs that can change\n effect(() => {\n // aria-checked\n if (config.checked) {\n const checked = config.checked();\n\n if (checked !== undefined) {\n host.setAttribute('aria-checked', checked);\n }\n }\n\n // aria-invalid\n if (config.invalid) {\n const invalid = config.invalid();\n\n host.setAttribute('aria-invalid', String(invalid));\n }\n\n // Helper text and describedby\n if (config.helperText && helperElement) {\n const text = config.helperText();\n\n if (text) {\n helperElement.textContent = text;\n helperElement.hidden = false;\n host.setAttribute('aria-describedby', helperId);\n\n // Set role based on explicit tone (no text heuristics)\n const tone = config.helperTone?.() ?? 'default';\n\n if (tone === 'error') {\n helperElement.setAttribute('role', 'alert');\n } else {\n helperElement.removeAttribute('role');\n }\n } else {\n helperElement.hidden = true;\n host.removeAttribute('aria-describedby');\n }\n }\n });\n });\n\n return {\n helperId,\n labelId,\n };\n}\n"],"mappings":"8IAiEA,SAAgB,EAAe,EAAmB,EAA8C,CAC9F,IAAM,EAAU,EAAO,SAAW,EAAS,aAAa,CAClD,EAAW,EAAO,UAAY,EAAS,cAAc,CAEvD,EAAuC,KA0E3C,OAvEA,EAAK,aAAa,OAAQ,EAAO,KAAK,CAEtC,MAAc,CAEZ,IAAM,EAAS,EAAK,WAOpB,GALI,IACF,EAAgB,EAAO,cAAc,qBAAqB,EAIxD,EAAQ,CACV,IAAM,EAAY,EAAO,cAAc,oBAAoB,CAE3D,GAAI,EAAW,CAEb,IAAM,EAAO,EAAU,cAAc,OAAO,EACpB,EACpB,EAAK,eAAe,CAAC,OAAS,EAC7B,EAAU,aAAa,MAAM,CAAC,QAAU,MAG3C,EAAU,GAAK,EACf,EAAK,aAAa,kBAAmB,EAAQ,GAMnD,MAAa,CAEX,GAAI,EAAO,QAAS,CAClB,IAAM,EAAU,EAAO,SAAS,CAE5B,IAAY,IAAA,IACd,EAAK,aAAa,eAAgB,EAAQ,CAK9C,GAAI,EAAO,QAAS,CAClB,IAAM,EAAU,EAAO,SAAS,CAEhC,EAAK,aAAa,eAAgB,OAAO,EAAQ,CAAC,CAIpD,GAAI,EAAO,YAAc,EAAe,CACtC,IAAM,EAAO,EAAO,YAAY,CAE5B,GACF,EAAc,YAAc,EAC5B,EAAc,OAAS,GACvB,EAAK,aAAa,mBAAoB,EAAS,EAGlC,EAAO,cAAc,EAAI,aAEzB,QACX,EAAc,aAAa,OAAQ,QAAQ,CAE3C,EAAc,gBAAgB,OAAO,GAGvC,EAAc,OAAS,GACvB,EAAK,gBAAgB,mBAAmB,IAG5C,EACF,CAEK,CACL,WACA,UACD"}
@@ -0,0 +1,8 @@
1
+ /** Experimental/labs API for @vielzeug/craftit. */
2
+ export { createListNavigation, type ListNavigationController, type ListNavigationOptions, type ListNavigationResult, type ListNavigationResultReason, } from './list';
3
+ export { createOverlayControl, type OverlayChangeContext, type OverlayCloseReason, type OverlayControl, type OverlayControlOptions, type OverlayOpenReason, type OverlayPositioner, } from './overlay';
4
+ export { createSelectionControl, type SelectionController, type SelectionControllerOptions, type SelectionKeyExtractor, type SelectionMode, } from './selection';
5
+ export { useA11yControl, type A11yControlConfig, type A11yControlHandle, type A11yTone } from './a11y';
6
+ export { createCheckableControl, type CheckableChangePayload, type CheckableControlConfig, type CheckableControlHandle, } from './selectable';
7
+ export { observeIntersection, observeMedia, observeResize } from './observers';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/labs/index.ts"],"names":[],"mappings":"AAAA,mDAAmD;AAGnD,OAAO,EACL,oBAAoB,EACpB,KAAK,wBAAwB,EAC7B,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,GAChC,MAAM,QAAQ,CAAC;AAChB,OAAO,EACL,oBAAoB,EACpB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,sBAAsB,EACtB,KAAK,mBAAmB,EACxB,KAAK,0BAA0B,EAC/B,KAAK,qBAAqB,EAC1B,KAAK,aAAa,GACnB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,cAAc,EAAE,KAAK,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACvG,OAAO,EACL,sBAAsB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,GAC5B,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,2 @@
1
+ var e=e=>{let t=(e,t,n=!1)=>e<0?{index:-1,moved:!1,reason:`no-enabled-item`,wrapped:n}:e===t?{index:e,moved:!1,reason:`unchanged`,wrapped:n}:{index:e,moved:!0,reason:`moved`,wrapped:n},n={index:-1,moved:!1,reason:`empty`,wrapped:!1},r=(t,n)=>e.isItemDisabled?e.isItemDisabled(t,n):!!t.disabled,i=(e,t)=>{for(let n=t;n<e.length;n++)if(!r(e[n],n))return n;return-1},a=(e,t)=>{for(let n=t;n>=0;n--)if(!r(e[n],n))return n;return-1},o=r=>{let a=e.getItems();if(a.length===0)return n;let o=e.getIndex(),s=i(a,Math.max(0,r));return s===-1?e.loop?t(i(a,0),o,!0):t(o,o):t(s,o)};return{first:()=>{let r=e.getItems();if(r.length===0)return n;let a=e.getIndex(),o=t(i(r,0),a);return o.index>=0&&e.setIndex(o.index),o},getActiveItem:()=>{let t=e.getItems(),n=e.getIndex();if(!(n<0||n>=t.length))return t[n]},getEnabledIndex:o,last:()=>{let r=e.getItems();if(r.length===0)return n;let i=e.getIndex(),o=t(a(r,r.length-1),i);return o.index>=0&&e.setIndex(o.index),o},next:()=>{let r=e.getItems();if(r.length===0)return n;let a=e.getIndex(),o=i(r,Math.max(0,a+1));if(o!==-1)return e.setIndex(o),t(o,a);if(e.loop){let n=i(r,0);return n!==-1&&e.setIndex(n),t(n,a,!0)}return t(a,a)},prev:()=>{let r=e.getItems();if(r.length===0)return n;let i=e.getIndex(),o=a(r,i-1);if(o!==-1)return e.setIndex(o),t(o,i);if(e.loop){let n=a(r,r.length-1);return n!==-1&&e.setIndex(n),t(n,i,!0)}return t(i,i)},reset:()=>{e.setIndex(-1)},set:t=>{let n=o(t);return n.index>=0&&e.setIndex(n.index),n}}};exports.createListNavigation=e;
2
+ //# sourceMappingURL=list.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.cjs","names":[],"sources":["../../src/labs/list.ts"],"sourcesContent":["export type ListNavigationOptions<T> = {\n getIndex: () => number;\n getItems: () => T[];\n isItemDisabled?: (item: T, index: number) => boolean;\n loop?: boolean;\n setIndex: (index: number) => void;\n};\n\nexport type ListNavigationResultReason = 'empty' | 'moved' | 'no-enabled-item' | 'unchanged';\n\nexport type ListNavigationResult = {\n index: number;\n moved: boolean;\n reason: ListNavigationResultReason;\n wrapped: boolean;\n};\n\nexport type ListNavigationController<T> = {\n first: () => ListNavigationResult;\n getActiveItem: () => T | undefined;\n getEnabledIndex: (index: number) => ListNavigationResult;\n last: () => ListNavigationResult;\n next: () => ListNavigationResult;\n prev: () => ListNavigationResult;\n reset: () => void;\n set: (index: number) => ListNavigationResult;\n};\n\nexport const createListNavigation = <T>(options: ListNavigationOptions<T>): ListNavigationController<T> => {\n const createResult = (nextIndex: number, currentIndex: number, wrapped = false): ListNavigationResult => {\n if (nextIndex < 0) {\n return {\n index: -1,\n moved: false,\n reason: 'no-enabled-item',\n wrapped,\n };\n }\n\n if (nextIndex === currentIndex) {\n return {\n index: nextIndex,\n moved: false,\n reason: 'unchanged',\n wrapped,\n };\n }\n\n return {\n index: nextIndex,\n moved: true,\n reason: 'moved',\n wrapped,\n };\n };\n\n const emptyResult: ListNavigationResult = {\n index: -1,\n moved: false,\n reason: 'empty',\n wrapped: false,\n };\n\n const isDisabled = (item: T, index: number): boolean => {\n if (options.isItemDisabled) return options.isItemDisabled(item, index);\n\n return Boolean((item as { disabled?: boolean }).disabled);\n };\n\n const findForward = (items: T[], start: number): number => {\n for (let idx = start; idx < items.length; idx++) {\n if (!isDisabled(items[idx], idx)) return idx;\n }\n\n return -1;\n };\n\n const findBackward = (items: T[], start: number): number => {\n for (let idx = start; idx >= 0; idx--) {\n if (!isDisabled(items[idx], idx)) return idx;\n }\n\n return -1;\n };\n\n const getEnabledIndex = (index: number): ListNavigationResult => {\n const items = options.getItems();\n\n if (items.length === 0) return emptyResult;\n\n const current = options.getIndex();\n const forward = findForward(items, Math.max(0, index));\n\n if (forward !== -1) return createResult(forward, current);\n\n if (options.loop) {\n const wrapped = findForward(items, 0);\n\n return createResult(wrapped, current, true);\n }\n\n return createResult(current, current);\n };\n\n const set = (index: number): ListNavigationResult => {\n const result = getEnabledIndex(index);\n\n if (result.index >= 0) options.setIndex(result.index);\n\n return result;\n };\n\n const first = (): ListNavigationResult => {\n const items = options.getItems();\n\n if (items.length === 0) return emptyResult;\n\n const current = options.getIndex();\n const next = findForward(items, 0);\n const result = createResult(next, current);\n\n if (result.index >= 0) options.setIndex(result.index);\n\n return result;\n };\n\n const last = (): ListNavigationResult => {\n const items = options.getItems();\n\n if (items.length === 0) return emptyResult;\n\n const current = options.getIndex();\n const next = findBackward(items, items.length - 1);\n const result = createResult(next, current);\n\n if (result.index >= 0) options.setIndex(result.index);\n\n return result;\n };\n\n const next = (): ListNavigationResult => {\n const items = options.getItems();\n\n if (items.length === 0) return emptyResult;\n\n const current = options.getIndex();\n const forward = findForward(items, Math.max(0, current + 1));\n\n if (forward !== -1) {\n options.setIndex(forward);\n\n return createResult(forward, current);\n }\n\n if (options.loop) {\n const wrapped = findForward(items, 0);\n\n if (wrapped !== -1) options.setIndex(wrapped);\n\n return createResult(wrapped, current, true);\n }\n\n return createResult(current, current);\n };\n\n const prev = (): ListNavigationResult => {\n const items = options.getItems();\n\n if (items.length === 0) return emptyResult;\n\n const current = options.getIndex();\n const backward = findBackward(items, current - 1);\n\n if (backward !== -1) {\n options.setIndex(backward);\n\n return createResult(backward, current);\n }\n\n if (options.loop) {\n const wrapped = findBackward(items, items.length - 1);\n\n if (wrapped !== -1) options.setIndex(wrapped);\n\n return createResult(wrapped, current, true);\n }\n\n return createResult(current, current);\n };\n\n const reset = (): void => {\n options.setIndex(-1);\n };\n\n const getActiveItem = (): T | undefined => {\n const items = options.getItems();\n const index = options.getIndex();\n\n if (index < 0 || index >= items.length) return undefined;\n\n return items[index];\n };\n\n return {\n first,\n getActiveItem,\n getEnabledIndex,\n last,\n next,\n prev,\n reset,\n set,\n };\n};\n"],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ export type ListNavigationOptions<T> = {
2
+ getIndex: () => number;
3
+ getItems: () => T[];
4
+ isItemDisabled?: (item: T, index: number) => boolean;
5
+ loop?: boolean;
6
+ setIndex: (index: number) => void;
7
+ };
8
+ export type ListNavigationResultReason = 'empty' | 'moved' | 'no-enabled-item' | 'unchanged';
9
+ export type ListNavigationResult = {
10
+ index: number;
11
+ moved: boolean;
12
+ reason: ListNavigationResultReason;
13
+ wrapped: boolean;
14
+ };
15
+ export type ListNavigationController<T> = {
16
+ first: () => ListNavigationResult;
17
+ getActiveItem: () => T | undefined;
18
+ getEnabledIndex: (index: number) => ListNavigationResult;
19
+ last: () => ListNavigationResult;
20
+ next: () => ListNavigationResult;
21
+ prev: () => ListNavigationResult;
22
+ reset: () => void;
23
+ set: (index: number) => ListNavigationResult;
24
+ };
25
+ export declare const createListNavigation: <T>(options: ListNavigationOptions<T>) => ListNavigationController<T>;
26
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/labs/list.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,qBAAqB,CAAC,CAAC,IAAI;IACrC,QAAQ,EAAE,MAAM,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC;IACpB,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IACrD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG,OAAO,GAAG,OAAO,GAAG,iBAAiB,GAAG,WAAW,CAAC;AAE7F,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,0BAA0B,CAAC;IACnC,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,wBAAwB,CAAC,CAAC,IAAI;IACxC,KAAK,EAAE,MAAM,oBAAoB,CAAC;IAClC,aAAa,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IACnC,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,oBAAoB,CAAC;IACzD,IAAI,EAAE,MAAM,oBAAoB,CAAC;IACjC,IAAI,EAAE,MAAM,oBAAoB,CAAC;IACjC,IAAI,EAAE,MAAM,oBAAoB,CAAC;IACjC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,oBAAoB,CAAC;CAC9C,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,CAAC,EAAE,SAAS,qBAAqB,CAAC,CAAC,CAAC,KAAG,wBAAwB,CAAC,CAAC,CAyLrG,CAAC"}
@@ -0,0 +1,2 @@
1
+ var e=e=>{let t=(e,t,n=!1)=>e<0?{index:-1,moved:!1,reason:`no-enabled-item`,wrapped:n}:e===t?{index:e,moved:!1,reason:`unchanged`,wrapped:n}:{index:e,moved:!0,reason:`moved`,wrapped:n},n={index:-1,moved:!1,reason:`empty`,wrapped:!1},r=(t,n)=>e.isItemDisabled?e.isItemDisabled(t,n):!!t.disabled,i=(e,t)=>{for(let n=t;n<e.length;n++)if(!r(e[n],n))return n;return-1},a=(e,t)=>{for(let n=t;n>=0;n--)if(!r(e[n],n))return n;return-1},o=r=>{let a=e.getItems();if(a.length===0)return n;let o=e.getIndex(),s=i(a,Math.max(0,r));return s===-1?e.loop?t(i(a,0),o,!0):t(o,o):t(s,o)};return{first:()=>{let r=e.getItems();if(r.length===0)return n;let a=e.getIndex(),o=t(i(r,0),a);return o.index>=0&&e.setIndex(o.index),o},getActiveItem:()=>{let t=e.getItems(),n=e.getIndex();if(!(n<0||n>=t.length))return t[n]},getEnabledIndex:o,last:()=>{let r=e.getItems();if(r.length===0)return n;let i=e.getIndex(),o=t(a(r,r.length-1),i);return o.index>=0&&e.setIndex(o.index),o},next:()=>{let r=e.getItems();if(r.length===0)return n;let a=e.getIndex(),o=i(r,Math.max(0,a+1));if(o!==-1)return e.setIndex(o),t(o,a);if(e.loop){let n=i(r,0);return n!==-1&&e.setIndex(n),t(n,a,!0)}return t(a,a)},prev:()=>{let r=e.getItems();if(r.length===0)return n;let i=e.getIndex(),o=a(r,i-1);if(o!==-1)return e.setIndex(o),t(o,i);if(e.loop){let n=a(r,r.length-1);return n!==-1&&e.setIndex(n),t(n,i,!0)}return t(i,i)},reset:()=>{e.setIndex(-1)},set:t=>{let n=o(t);return n.index>=0&&e.setIndex(n.index),n}}};export{e as createListNavigation};
2
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","names":[],"sources":["../../src/labs/list.ts"],"sourcesContent":["export type ListNavigationOptions<T> = {\n getIndex: () => number;\n getItems: () => T[];\n isItemDisabled?: (item: T, index: number) => boolean;\n loop?: boolean;\n setIndex: (index: number) => void;\n};\n\nexport type ListNavigationResultReason = 'empty' | 'moved' | 'no-enabled-item' | 'unchanged';\n\nexport type ListNavigationResult = {\n index: number;\n moved: boolean;\n reason: ListNavigationResultReason;\n wrapped: boolean;\n};\n\nexport type ListNavigationController<T> = {\n first: () => ListNavigationResult;\n getActiveItem: () => T | undefined;\n getEnabledIndex: (index: number) => ListNavigationResult;\n last: () => ListNavigationResult;\n next: () => ListNavigationResult;\n prev: () => ListNavigationResult;\n reset: () => void;\n set: (index: number) => ListNavigationResult;\n};\n\nexport const createListNavigation = <T>(options: ListNavigationOptions<T>): ListNavigationController<T> => {\n const createResult = (nextIndex: number, currentIndex: number, wrapped = false): ListNavigationResult => {\n if (nextIndex < 0) {\n return {\n index: -1,\n moved: false,\n reason: 'no-enabled-item',\n wrapped,\n };\n }\n\n if (nextIndex === currentIndex) {\n return {\n index: nextIndex,\n moved: false,\n reason: 'unchanged',\n wrapped,\n };\n }\n\n return {\n index: nextIndex,\n moved: true,\n reason: 'moved',\n wrapped,\n };\n };\n\n const emptyResult: ListNavigationResult = {\n index: -1,\n moved: false,\n reason: 'empty',\n wrapped: false,\n };\n\n const isDisabled = (item: T, index: number): boolean => {\n if (options.isItemDisabled) return options.isItemDisabled(item, index);\n\n return Boolean((item as { disabled?: boolean }).disabled);\n };\n\n const findForward = (items: T[], start: number): number => {\n for (let idx = start; idx < items.length; idx++) {\n if (!isDisabled(items[idx], idx)) return idx;\n }\n\n return -1;\n };\n\n const findBackward = (items: T[], start: number): number => {\n for (let idx = start; idx >= 0; idx--) {\n if (!isDisabled(items[idx], idx)) return idx;\n }\n\n return -1;\n };\n\n const getEnabledIndex = (index: number): ListNavigationResult => {\n const items = options.getItems();\n\n if (items.length === 0) return emptyResult;\n\n const current = options.getIndex();\n const forward = findForward(items, Math.max(0, index));\n\n if (forward !== -1) return createResult(forward, current);\n\n if (options.loop) {\n const wrapped = findForward(items, 0);\n\n return createResult(wrapped, current, true);\n }\n\n return createResult(current, current);\n };\n\n const set = (index: number): ListNavigationResult => {\n const result = getEnabledIndex(index);\n\n if (result.index >= 0) options.setIndex(result.index);\n\n return result;\n };\n\n const first = (): ListNavigationResult => {\n const items = options.getItems();\n\n if (items.length === 0) return emptyResult;\n\n const current = options.getIndex();\n const next = findForward(items, 0);\n const result = createResult(next, current);\n\n if (result.index >= 0) options.setIndex(result.index);\n\n return result;\n };\n\n const last = (): ListNavigationResult => {\n const items = options.getItems();\n\n if (items.length === 0) return emptyResult;\n\n const current = options.getIndex();\n const next = findBackward(items, items.length - 1);\n const result = createResult(next, current);\n\n if (result.index >= 0) options.setIndex(result.index);\n\n return result;\n };\n\n const next = (): ListNavigationResult => {\n const items = options.getItems();\n\n if (items.length === 0) return emptyResult;\n\n const current = options.getIndex();\n const forward = findForward(items, Math.max(0, current + 1));\n\n if (forward !== -1) {\n options.setIndex(forward);\n\n return createResult(forward, current);\n }\n\n if (options.loop) {\n const wrapped = findForward(items, 0);\n\n if (wrapped !== -1) options.setIndex(wrapped);\n\n return createResult(wrapped, current, true);\n }\n\n return createResult(current, current);\n };\n\n const prev = (): ListNavigationResult => {\n const items = options.getItems();\n\n if (items.length === 0) return emptyResult;\n\n const current = options.getIndex();\n const backward = findBackward(items, current - 1);\n\n if (backward !== -1) {\n options.setIndex(backward);\n\n return createResult(backward, current);\n }\n\n if (options.loop) {\n const wrapped = findBackward(items, items.length - 1);\n\n if (wrapped !== -1) options.setIndex(wrapped);\n\n return createResult(wrapped, current, true);\n }\n\n return createResult(current, current);\n };\n\n const reset = (): void => {\n options.setIndex(-1);\n };\n\n const getActiveItem = (): T | undefined => {\n const items = options.getItems();\n const index = options.getIndex();\n\n if (index < 0 || index >= items.length) return undefined;\n\n return items[index];\n };\n\n return {\n first,\n getActiveItem,\n getEnabledIndex,\n last,\n next,\n prev,\n reset,\n set,\n };\n};\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ const e=require(`../core/runtime-lifecycle.cjs`);require(`../core/runtime.cjs`);let t=require(`@vielzeug/stateit`);var n=n=>{let r=(0,t.signal)({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.onCleanup(()=>i.disconnect()),r},r=(n,r)=>{let i=(0,t.signal)(null),a=new IntersectionObserver(([e])=>{e&&(i.value=e)},r);return a.observe(n),e.onCleanup(()=>a.disconnect()),i},i=n=>{let r=window.matchMedia(n),i=(0,t.signal)(r.matches),a=e=>{i.value=e.matches};return r.addEventListener(`change`,a),e.onCleanup(()=>r.removeEventListener(`change`,a)),i};exports.observeIntersection=r,exports.observeMedia=i,exports.observeResize=n;
2
+ //# sourceMappingURL=observers.cjs.map