@vielzeug/craftit 2.1.0 → 3.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.
Files changed (325) hide show
  1. package/README.md +58 -124
  2. package/dist/controls/a11y-control.cjs +1 -1
  3. package/dist/controls/a11y-control.cjs.map +1 -1
  4. package/dist/controls/a11y-control.d.ts +1 -1
  5. package/dist/controls/a11y-control.d.ts.map +1 -1
  6. package/dist/controls/a11y-control.js +1 -1
  7. package/dist/controls/a11y-control.js.map +1 -1
  8. package/dist/controls/checkable-control.cjs +1 -1
  9. package/dist/controls/checkable-control.cjs.map +1 -1
  10. package/dist/controls/checkable-control.d.ts +7 -7
  11. package/dist/controls/checkable-control.d.ts.map +1 -1
  12. package/dist/controls/checkable-control.js +1 -1
  13. package/dist/controls/checkable-control.js.map +1 -1
  14. package/dist/controls/choice-field-control.cjs +2 -0
  15. package/dist/controls/choice-field-control.cjs.map +1 -0
  16. package/dist/controls/choice-field-control.d.ts +3 -0
  17. package/dist/controls/choice-field-control.d.ts.map +1 -0
  18. package/dist/controls/choice-field-control.js +2 -0
  19. package/dist/controls/choice-field-control.js.map +1 -0
  20. package/dist/controls/field-control.cjs +1 -1
  21. package/dist/controls/field-control.cjs.map +1 -1
  22. package/dist/controls/field-control.d.ts +28 -73
  23. package/dist/controls/field-control.d.ts.map +1 -1
  24. package/dist/controls/field-control.js +1 -1
  25. package/dist/controls/field-control.js.map +1 -1
  26. package/dist/controls/index.d.ts +11 -9
  27. package/dist/controls/index.d.ts.map +1 -1
  28. package/dist/controls/internal/control-state.cjs +1 -1
  29. package/dist/controls/internal/control-state.cjs.map +1 -1
  30. package/dist/controls/internal/control-state.d.ts +6 -4
  31. package/dist/controls/internal/control-state.d.ts.map +1 -1
  32. package/dist/controls/internal/control-state.js +1 -1
  33. package/dist/controls/internal/control-state.js.map +1 -1
  34. package/dist/controls/internal/keyboard-utils.cjs.map +1 -1
  35. package/dist/controls/internal/keyboard-utils.js.map +1 -1
  36. package/dist/controls/internal/number-utils.cjs.map +1 -1
  37. package/dist/controls/internal/number-utils.js.map +1 -1
  38. package/dist/controls/internal/validation-utils.cjs.map +1 -1
  39. package/dist/controls/internal/validation-utils.js.map +1 -1
  40. package/dist/controls/list-control.cjs +1 -1
  41. package/dist/controls/list-control.cjs.map +1 -1
  42. package/dist/controls/list-control.d.ts +10 -8
  43. package/dist/controls/list-control.d.ts.map +1 -1
  44. package/dist/controls/list-control.js +1 -1
  45. package/dist/controls/list-control.js.map +1 -1
  46. package/dist/controls/overlay-control.cjs +1 -1
  47. package/dist/controls/overlay-control.cjs.map +1 -1
  48. package/dist/controls/overlay-control.d.ts +17 -14
  49. package/dist/controls/overlay-control.d.ts.map +1 -1
  50. package/dist/controls/overlay-control.js +1 -1
  51. package/dist/controls/overlay-control.js.map +1 -1
  52. package/dist/controls/popup-list-control.cjs +2 -0
  53. package/dist/controls/popup-list-control.cjs.map +1 -0
  54. package/dist/controls/popup-list-control.d.ts +160 -0
  55. package/dist/controls/popup-list-control.d.ts.map +1 -0
  56. package/dist/controls/popup-list-control.js +2 -0
  57. package/dist/controls/popup-list-control.js.map +1 -0
  58. package/dist/controls/press-control.cjs.map +1 -1
  59. package/dist/controls/press-control.js.map +1 -1
  60. package/dist/controls/slider-control.cjs.map +1 -1
  61. package/dist/controls/slider-control.js.map +1 -1
  62. package/dist/controls/spinner-control.cjs.map +1 -1
  63. package/dist/controls/spinner-control.js.map +1 -1
  64. package/dist/controls/swipe-control.cjs +2 -0
  65. package/dist/controls/swipe-control.cjs.map +1 -0
  66. package/dist/controls/swipe-control.d.ts +32 -0
  67. package/dist/controls/swipe-control.d.ts.map +1 -0
  68. package/dist/controls/swipe-control.js +2 -0
  69. package/dist/controls/swipe-control.js.map +1 -0
  70. package/dist/controls/text-field-control.cjs +2 -0
  71. package/dist/controls/text-field-control.cjs.map +1 -0
  72. package/dist/controls/text-field-control.d.ts +3 -0
  73. package/dist/controls/text-field-control.d.ts.map +1 -0
  74. package/dist/controls/text-field-control.js +2 -0
  75. package/dist/controls/text-field-control.js.map +1 -0
  76. package/dist/controls.cjs +1 -1
  77. package/dist/controls.js +1 -1
  78. package/dist/craftit.cjs +1 -1
  79. package/dist/craftit.cjs.map +1 -1
  80. package/dist/craftit.js +1 -1
  81. package/dist/craftit.js.map +1 -1
  82. package/dist/directives/classMap.cjs +2 -0
  83. package/dist/directives/classMap.cjs.map +1 -0
  84. package/dist/directives/classMap.d.ts +19 -0
  85. package/dist/directives/classMap.d.ts.map +1 -0
  86. package/dist/directives/classMap.js +2 -0
  87. package/dist/directives/classMap.js.map +1 -0
  88. package/dist/directives/each.cjs +1 -1
  89. package/dist/directives/each.cjs.map +1 -1
  90. package/dist/directives/each.d.ts +5 -30
  91. package/dist/directives/each.d.ts.map +1 -1
  92. package/dist/directives/each.js +1 -1
  93. package/dist/directives/each.js.map +1 -1
  94. package/dist/directives/guard.cjs +2 -0
  95. package/dist/directives/guard.cjs.map +1 -0
  96. package/dist/directives/guard.d.ts +10 -0
  97. package/dist/directives/guard.d.ts.map +1 -0
  98. package/dist/directives/guard.js +2 -0
  99. package/dist/directives/guard.js.map +1 -0
  100. package/dist/directives/live.cjs +2 -0
  101. package/dist/directives/live.cjs.map +1 -0
  102. package/dist/directives/live.d.ts +23 -0
  103. package/dist/directives/live.d.ts.map +1 -0
  104. package/dist/directives/live.js +2 -0
  105. package/dist/directives/live.js.map +1 -0
  106. package/dist/directives/raw.cjs +1 -1
  107. package/dist/directives/raw.cjs.map +1 -1
  108. package/dist/directives/raw.d.ts +3 -5
  109. package/dist/directives/raw.d.ts.map +1 -1
  110. package/dist/directives/raw.js +1 -1
  111. package/dist/directives/raw.js.map +1 -1
  112. package/dist/directives/resource.cjs +2 -0
  113. package/dist/directives/resource.cjs.map +1 -0
  114. package/dist/directives/resource.d.ts +32 -0
  115. package/dist/directives/resource.d.ts.map +1 -0
  116. package/dist/directives/resource.js +2 -0
  117. package/dist/directives/resource.js.map +1 -0
  118. package/dist/directives/styleMap.cjs +2 -0
  119. package/dist/directives/styleMap.cjs.map +1 -0
  120. package/dist/directives/styleMap.d.ts +11 -0
  121. package/dist/directives/styleMap.d.ts.map +1 -0
  122. package/dist/directives/styleMap.js +2 -0
  123. package/dist/directives/styleMap.js.map +1 -0
  124. package/dist/directives/when.cjs +1 -1
  125. package/dist/directives/when.cjs.map +1 -1
  126. package/dist/directives/when.d.ts +6 -19
  127. package/dist/directives/when.d.ts.map +1 -1
  128. package/dist/directives/when.js +1 -1
  129. package/dist/directives/when.js.map +1 -1
  130. package/dist/errors.cjs +2 -0
  131. package/dist/errors.cjs.map +1 -0
  132. package/dist/errors.d.ts +12 -0
  133. package/dist/errors.d.ts.map +1 -0
  134. package/dist/errors.js +2 -0
  135. package/dist/errors.js.map +1 -0
  136. package/dist/form.cjs +1 -1
  137. package/dist/form.cjs.map +1 -1
  138. package/dist/form.d.ts +3 -17
  139. package/dist/form.d.ts.map +1 -1
  140. package/dist/form.js +1 -1
  141. package/dist/form.js.map +1 -1
  142. package/dist/host.cjs +1 -1
  143. package/dist/host.cjs.map +1 -1
  144. package/dist/host.d.ts +40 -37
  145. package/dist/host.d.ts.map +1 -1
  146. package/dist/host.js +1 -1
  147. package/dist/host.js.map +1 -1
  148. package/dist/index.cjs +1 -1
  149. package/dist/index.d.ts +16 -8
  150. package/dist/index.d.ts.map +1 -1
  151. package/dist/index.js +1 -1
  152. package/dist/internal.cjs +1 -1
  153. package/dist/internal.cjs.map +1 -1
  154. package/dist/internal.d.ts +60 -120
  155. package/dist/internal.d.ts.map +1 -1
  156. package/dist/internal.js +1 -1
  157. package/dist/internal.js.map +1 -1
  158. package/dist/observers/index.d.ts +1 -0
  159. package/dist/observers/index.d.ts.map +1 -1
  160. package/dist/observers/intersection-observe.cjs +1 -1
  161. package/dist/observers/intersection-observe.cjs.map +1 -1
  162. package/dist/observers/intersection-observe.d.ts +1 -1
  163. package/dist/observers/intersection-observe.js +1 -1
  164. package/dist/observers/intersection-observe.js.map +1 -1
  165. package/dist/observers/media-observe.cjs +1 -1
  166. package/dist/observers/media-observe.cjs.map +1 -1
  167. package/dist/observers/media-observe.d.ts +1 -1
  168. package/dist/observers/media-observe.js +1 -1
  169. package/dist/observers/media-observe.js.map +1 -1
  170. package/dist/observers/mutation-observe.cjs +2 -0
  171. package/dist/observers/mutation-observe.cjs.map +1 -0
  172. package/dist/observers/mutation-observe.d.ts +10 -0
  173. package/dist/observers/mutation-observe.d.ts.map +1 -0
  174. package/dist/observers/mutation-observe.js +2 -0
  175. package/dist/observers/mutation-observe.js.map +1 -0
  176. package/dist/observers/resize-observe.cjs +1 -1
  177. package/dist/observers/resize-observe.cjs.map +1 -1
  178. package/dist/observers/resize-observe.d.ts +1 -1
  179. package/dist/observers/resize-observe.js +1 -1
  180. package/dist/observers/resize-observe.js.map +1 -1
  181. package/dist/observers.cjs +1 -1
  182. package/dist/observers.js +1 -1
  183. package/dist/props.cjs +1 -1
  184. package/dist/props.cjs.map +1 -1
  185. package/dist/props.d.ts +18 -31
  186. package/dist/props.d.ts.map +1 -1
  187. package/dist/props.js +1 -1
  188. package/dist/props.js.map +1 -1
  189. package/dist/registration.cjs +1 -1
  190. package/dist/registration.cjs.map +1 -1
  191. package/dist/registration.d.ts +27 -7
  192. package/dist/registration.d.ts.map +1 -1
  193. package/dist/registration.js +1 -1
  194. package/dist/registration.js.map +1 -1
  195. package/dist/runtime.cjs +1 -1
  196. package/dist/runtime.cjs.map +1 -1
  197. package/dist/runtime.d.ts +29 -17
  198. package/dist/runtime.d.ts.map +1 -1
  199. package/dist/runtime.js +1 -1
  200. package/dist/runtime.js.map +1 -1
  201. package/dist/template-bindings.cjs +1 -1
  202. package/dist/template-bindings.cjs.map +1 -1
  203. package/dist/template-bindings.d.ts +10 -47
  204. package/dist/template-bindings.d.ts.map +1 -1
  205. package/dist/template-bindings.js +1 -1
  206. package/dist/template-bindings.js.map +1 -1
  207. package/dist/template-compiler.cjs +1 -1
  208. package/dist/template-compiler.cjs.map +1 -1
  209. package/dist/template-compiler.d.ts +1 -21
  210. package/dist/template-compiler.d.ts.map +1 -1
  211. package/dist/template-compiler.js +1 -1
  212. package/dist/template-compiler.js.map +1 -1
  213. package/dist/testing/testing.cjs +1 -1
  214. package/dist/testing/testing.cjs.map +1 -1
  215. package/dist/testing/testing.d.ts +12 -5
  216. package/dist/testing/testing.d.ts.map +1 -1
  217. package/dist/testing/testing.js +1 -1
  218. package/dist/testing/testing.js.map +1 -1
  219. package/package.json +6 -12
  220. package/dist/component.cjs +0 -2
  221. package/dist/component.cjs.map +0 -1
  222. package/dist/component.d.ts +0 -39
  223. package/dist/component.d.ts.map +0 -1
  224. package/dist/component.js +0 -2
  225. package/dist/component.js.map +0 -1
  226. package/dist/controls/list-key-control.cjs +0 -2
  227. package/dist/controls/list-key-control.cjs.map +0 -1
  228. package/dist/controls/list-key-control.d.ts +0 -14
  229. package/dist/controls/list-key-control.d.ts.map +0 -1
  230. package/dist/controls/list-key-control.js +0 -2
  231. package/dist/controls/list-key-control.js.map +0 -1
  232. package/dist/directives/attr.cjs +0 -2
  233. package/dist/directives/attr.cjs.map +0 -1
  234. package/dist/directives/attr.d.ts +0 -12
  235. package/dist/directives/attr.d.ts.map +0 -1
  236. package/dist/directives/attr.js +0 -2
  237. package/dist/directives/attr.js.map +0 -1
  238. package/dist/directives/bind.cjs +0 -2
  239. package/dist/directives/bind.cjs.map +0 -1
  240. package/dist/directives/bind.d.ts +0 -38
  241. package/dist/directives/bind.d.ts.map +0 -1
  242. package/dist/directives/bind.js +0 -2
  243. package/dist/directives/bind.js.map +0 -1
  244. package/dist/directives/choose.cjs +0 -2
  245. package/dist/directives/choose.cjs.map +0 -1
  246. package/dist/directives/choose.d.ts +0 -39
  247. package/dist/directives/choose.d.ts.map +0 -1
  248. package/dist/directives/choose.js +0 -2
  249. package/dist/directives/choose.js.map +0 -1
  250. package/dist/directives/classes.cjs +0 -2
  251. package/dist/directives/classes.cjs.map +0 -1
  252. package/dist/directives/classes.d.ts +0 -20
  253. package/dist/directives/classes.d.ts.map +0 -1
  254. package/dist/directives/classes.js +0 -2
  255. package/dist/directives/classes.js.map +0 -1
  256. package/dist/directives/index.d.ts +0 -13
  257. package/dist/directives/index.d.ts.map +0 -1
  258. package/dist/directives/memo.cjs +0 -2
  259. package/dist/directives/memo.cjs.map +0 -1
  260. package/dist/directives/memo.d.ts +0 -27
  261. package/dist/directives/memo.d.ts.map +0 -1
  262. package/dist/directives/memo.js +0 -2
  263. package/dist/directives/memo.js.map +0 -1
  264. package/dist/directives/on.cjs +0 -2
  265. package/dist/directives/on.cjs.map +0 -1
  266. package/dist/directives/on.d.ts +0 -25
  267. package/dist/directives/on.d.ts.map +0 -1
  268. package/dist/directives/on.js +0 -2
  269. package/dist/directives/on.js.map +0 -1
  270. package/dist/directives/spread.cjs +0 -2
  271. package/dist/directives/spread.cjs.map +0 -1
  272. package/dist/directives/spread.d.ts +0 -14
  273. package/dist/directives/spread.d.ts.map +0 -1
  274. package/dist/directives/spread.js +0 -2
  275. package/dist/directives/spread.js.map +0 -1
  276. package/dist/directives/style.cjs +0 -2
  277. package/dist/directives/style.cjs.map +0 -1
  278. package/dist/directives/style.d.ts +0 -22
  279. package/dist/directives/style.d.ts.map +0 -1
  280. package/dist/directives/style.js +0 -2
  281. package/dist/directives/style.js.map +0 -1
  282. package/dist/directives/until.cjs +0 -2
  283. package/dist/directives/until.cjs.map +0 -1
  284. package/dist/directives/until.d.ts +0 -26
  285. package/dist/directives/until.d.ts.map +0 -1
  286. package/dist/directives/until.js +0 -2
  287. package/dist/directives/until.js.map +0 -1
  288. package/dist/directives.cjs +0 -1
  289. package/dist/directives.js +0 -1
  290. package/dist/runtime-bindings.cjs +0 -2
  291. package/dist/runtime-bindings.cjs.map +0 -1
  292. package/dist/runtime-bindings.d.ts +0 -6
  293. package/dist/runtime-bindings.d.ts.map +0 -1
  294. package/dist/runtime-bindings.js +0 -2
  295. package/dist/runtime-bindings.js.map +0 -1
  296. package/dist/runtime-core.cjs +0 -2
  297. package/dist/runtime-core.cjs.map +0 -1
  298. package/dist/runtime-core.d.ts +0 -21
  299. package/dist/runtime-core.d.ts.map +0 -1
  300. package/dist/runtime-core.js +0 -2
  301. package/dist/runtime-core.js.map +0 -1
  302. package/dist/runtime-lifecycle.cjs +0 -2
  303. package/dist/runtime-lifecycle.cjs.map +0 -1
  304. package/dist/runtime-lifecycle.d.ts +0 -24
  305. package/dist/runtime-lifecycle.d.ts.map +0 -1
  306. package/dist/runtime-lifecycle.js +0 -2
  307. package/dist/runtime-lifecycle.js.map +0 -1
  308. package/dist/template-dom.cjs +0 -2
  309. package/dist/template-dom.cjs.map +0 -1
  310. package/dist/template-dom.d.ts +0 -13
  311. package/dist/template-dom.d.ts.map +0 -1
  312. package/dist/template-dom.js +0 -2
  313. package/dist/template-dom.js.map +0 -1
  314. package/dist/template-html.cjs +0 -2
  315. package/dist/template-html.cjs.map +0 -1
  316. package/dist/template-html.d.ts +0 -23
  317. package/dist/template-html.d.ts.map +0 -1
  318. package/dist/template-html.js +0 -2
  319. package/dist/template-html.js.map +0 -1
  320. package/dist/template.cjs +0 -2
  321. package/dist/template.cjs.map +0 -1
  322. package/dist/template.d.ts +0 -10
  323. package/dist/template.d.ts.map +0 -1
  324. package/dist/template.js +0 -2
  325. package/dist/template.js.map +0 -1
package/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # @vielzeug/craftit
2
2
 
3
- > Functional web components with signals, typed props, and template bindings
3
+ > Functional web components with signals, typed props, lifecycle hooks, and headless controls.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@vielzeug/craftit)](https://www.npmjs.com/package/@vielzeug/craftit) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
6
 
7
- **Craftit** provides a compact API for authoring custom elements with fine-grained reactivity. It builds on `@vielzeug/stateit` (re-exported from the main entry) and adds component lifecycle, templating, typed props, typed emits, setup-context slots, form-associated helpers, and observer utilities.
7
+ Craftit is Vielzeug's custom-element authoring library built on `@vielzeug/stateit`.
8
8
 
9
9
  ## Installation
10
10
 
@@ -17,162 +17,96 @@ pnpm add @vielzeug/craftit
17
17
  ## Quick Start
18
18
 
19
19
  ```ts
20
- import { computed, define, html, signal } from '@vielzeug/craftit';
20
+ import { computed, css, define, html, prop, signal } from '@vielzeug/craftit';
21
21
 
22
22
  define('my-counter', {
23
- setup() {
23
+ props: {
24
+ label: prop.string('Count'),
25
+ step: prop.number(1),
26
+ },
27
+ setup(props, { host }) {
24
28
  const count = signal(0);
25
29
  const doubled = computed(() => count.value * 2);
26
30
 
27
- return html`
28
- <button @click=${() => count.value++}>Count: ${count}</button>
31
+ host.class({ 'is-positive': () => count.value > 0 });
32
+
33
+ return () => html`
34
+ <button @click=${() => (count.value += props.step.value)}>
35
+ ${props.label}: ${count}
36
+ </button>
29
37
  <p>Doubled: ${doubled}</p>
30
38
  `;
31
39
  },
40
+ styles: [
41
+ css`
42
+ :host {
43
+ display: inline-grid;
44
+ gap: 0.5rem;
45
+ }
46
+ `,
47
+ ],
32
48
  });
33
49
  ```
34
50
 
35
- ## Features
36
-
37
- - ✅ **Component authoring** — `define(tag, { props, setup, ... })`
38
- - ✅ **Signals included** — all `@vielzeug/stateit` exports are re-exported
39
- - ✅ **Reactive templates** — `html` tagged template with text/attr/prop/event/ref bindings
40
- - ✅ **Lifecycle helpers** — `onMount`, `onCleanup`, `onError`, `handle`, `watch`, `effect`, `fire.*`
41
- - ✅ **Typed component APIs** — `define`, `prop`, `typed`, setup-context `emit` and `slots`
42
- - ✅ **Context / DI** — `createContext`, `provide`, `inject`, `syncContextProps`
43
- - ✅ **Form-associated controls** — `defineField` with `ElementInternals`
44
- - ✅ **Observer utilities (observers)** — `resizeObserver`, `intersectionObserver`, and `mediaObserver`
45
- - ✅ **Directive subpath** — `@vielzeug/craftit/directives`
46
- - ✅ **Test subpath** — `@vielzeug/craftit/testing`
47
-
48
- ## Entry Points
49
-
50
- - `@vielzeug/craftit` — Main API with component authoring and stateit re-exports.
51
- - `@vielzeug/craftit/controls` — Stable composables for controls and overlays.
52
- - `@vielzeug/craftit/observers` — Stable browser observer composables.
53
- - `@vielzeug/craftit/directives` — Directive helpers like `attrs`, `bind`, `choose`, `each`, `when`, and `until`.
54
- - `@vielzeug/craftit/testing` — Mount, query, and event testing utilities.
55
-
56
- ## Usage Highlights
57
-
58
- ### Typed props + emits
59
-
60
- ```ts
61
- import { define, html } from '@vielzeug/craftit';
51
+ ## Authoring Model
62
52
 
63
- define<{ disabled: boolean; label: string }, { change: string }>('name-input', {
64
- props: {
65
- disabled: false,
66
- label: 'Name',
67
- },
68
- setup({ emit, props }) {
69
- return html`
70
- <label>${props.label}</label>
71
- <input :disabled=${props.disabled} @input=${(e: Event) => emit('change', (e.target as HTMLInputElement).value)} />
72
- `;
73
- },
74
- });
75
- ```
76
-
77
- ### Directives subpath
53
+ - `setup(props, ctx)` returns a template function: `() => html\`...\``
54
+ - Use `onMounted()` for post-mount DOM initialization
55
+ - Use `onCleanup()` for teardown
56
+ - Use `onElement(ref, cb)` for ref-driven effects
78
57
 
79
58
  ```ts
80
- import { define, html, signal } from '@vielzeug/craftit';
81
- import { each, when } from '@vielzeug/craftit/directives';
59
+ import { define, html, onCleanup, onMounted, signal } from '@vielzeug/craftit';
82
60
 
83
- define('todo-list', {
61
+ define('auto-save-field', {
84
62
  setup() {
85
- const todos = signal([{ id: 1, text: 'Write docs', done: false }]);
86
-
87
- return html`
88
- ${when({
89
- condition: () => todos.value.length > 0,
90
- else: () => html`<p>No todos</p>`,
91
- then: () =>
92
- html`<ul>${each(todos, { key: (todo) => todo.id, render: (todo) => html`<li>${todo.text}</li>` })}</ul>`,
93
- })}
94
- `;
95
- },
96
- });
97
- ```
98
-
99
- ### Setup-context slots
100
-
101
- ```ts
102
- import { define, effect, html } from '@vielzeug/craftit';
103
- import { when } from '@vielzeug/craftit/directives';
63
+ const value = signal('');
104
64
 
105
- define('slot-panel', {
106
- setup({ slots }) {
107
- effect(() => {
108
- console.log('default elements:', slots.elements().value.length);
65
+ onMounted(() => {
66
+ console.log('ready for DOM interactions');
109
67
  });
110
68
 
111
- return html`
112
- ${when({
113
- condition: () => slots.has('header').value,
114
- else: () => html`<h2>Fallback header</h2>`,
115
- then: () => html`<slot name="header"></slot>`,
116
- })}
117
- ${when({
118
- condition: () => slots.has().value,
119
- else: () => html`<p>No content yet</p>`,
120
- then: () => html`<slot></slot>`,
121
- })}
122
- `;
123
- },
124
- });
125
- ```
126
-
127
- Use `slots.has(name?)` for presence checks and `slots.elements(name?)` when you need flattened assigned elements.
128
-
129
- ### Form-associated field
130
-
131
- ```ts
132
- import { define, defineField, html, signal } from '@vielzeug/craftit';
133
-
134
- define('email-field', {
135
- formAssociated: true,
136
- setup() {
137
- const value = signal('');
138
- const field = defineField({ value });
69
+ onCleanup(() => {
70
+ console.log('saving', value.value);
71
+ });
139
72
 
140
- return html`
141
- <input
142
- type="email"
143
- :value=${value}
73
+ return () => html`
74
+ <textarea
144
75
  @input=${(e: Event) => {
145
- value.value = (e.target as HTMLInputElement).value;
146
- field.setCustomValidity(value.value.includes('@') ? '' : 'Invalid email');
76
+ value.value = (e.target as HTMLTextAreaElement).value;
147
77
  }}
148
- />
78
+ ></textarea>
149
79
  `;
150
80
  },
151
81
  });
152
82
  ```
153
83
 
84
+ ## Features
85
+
86
+ - Signals included: `signal`, `computed`, `watch`, `batch`, `untrack`, `scope`, and related primitives from `@vielzeug/stateit`
87
+ - Component authoring: `define(tag, { props, setup, styles, formAssociated })`
88
+ - Props: `prop.*` helpers and raw `PropDef` objects; shared bundles can type against `PropsDef<...>`
89
+ - Lifecycle hooks: `onMounted`, `onCleanup`, `onElement`, `effect`, `handle` (auto-cleans inside setup/scope; returns manual cleanup outside it)
90
+ - Directives: `each`, `classMap`, `styleMap`, `guard`, `when`, `live`, `until`, `raw`
91
+ - Host/slot APIs: `host.bind`, `syncAria`, `slots.has`, `slots.elements`
92
+ - Form-associated elements: `defineField()`
93
+ - Published subpaths: `@vielzeug/craftit/controls`, `@vielzeug/craftit/observers`, `@vielzeug/craftit/testing`
94
+
154
95
  ## API Summary
155
96
 
156
- - Components: `define`, `ComponentOptions`, `ComponentSetupContext`
157
- - Runtime: `onMount`, `onCleanup`, `onError`, `handle`, `aria`, `effect`, `watch`, `fire`
158
- - Props: `prop`, `typed`, `PropOptions`, `PropDef`, `InferPropsSignals`
159
- - Slots / emits: setup-context `slots`, setup-context `emit`, `EmitFn`
160
- - Context: `createContext`, `provide`, `inject`, `syncContextProps`, `InjectionKey`
161
- - Form: `defineField`, `FormFieldOptions`, `FormFieldCallbacks`, `FormFieldHandle`
162
- - Observers: `resizeObserver`, `intersectionObserver`, `mediaObserver`
163
- - Controls: `createFieldIds`
164
- - Utilities: `html`, `css`, `createId`
165
- - Re-exported from stateit: `signal`, `computed`, `batch`, `untrack`, `readonly`, and more
97
+ | Area | Exports |
98
+ | --- | --- |
99
+ | Component authoring | `define`, `prop`, `type ComponentDefinition`, `type SetupContextBag`, `type PropsDef`, `type PropDef` |
100
+ | Runtime | `onMounted`, `effect`, `handle`, `onCleanup`, `onElement` |
101
+ | Templates and directives | `html`, `css`, `each`, `classMap`, `styleMap`, `guard`, `when`, `live`, `until`, `raw` |
102
+ | Element references | `ref`, `refs`, `createId` |
103
+ | Context and slots | `createContext`, `provide`, `inject`, `injectStrict`, `syncAria` |
104
+ | Form | `defineField`, `type FormFieldOptions`, `type FormFieldHandle` |
166
105
 
167
106
  ## Documentation
168
107
 
169
108
  Full docs at **[vielzeug.dev/craftit](https://vielzeug.dev/craftit)**
170
109
 
171
- - [Overview](https://vielzeug.dev/craftit/) — Install and architecture overview
172
- - [Usage Guide](https://vielzeug.dev/craftit/usage) — Practical patterns and subpath usage
173
- - [API Reference](https://vielzeug.dev/craftit/api) — Complete signatures and types
174
- - [Examples](https://vielzeug.dev/craftit/examples) — End-to-end component examples
175
-
176
110
  ## License
177
111
 
178
112
  MIT © [Helmuth Saatkamp](https://github.com/helmuthdu) — Part of the [Vielzeug](https://github.com/helmuthdu/vielzeug) monorepo.
@@ -1,2 +1,2 @@
1
- const e=require(`../runtime-lifecycle.cjs`),t=require(`../internal.cjs`);var n=e=>{let t=e.querySelector(`slot`);return t instanceof HTMLSlotElement?t.assignedNodes({flatten:!0}).some(e=>(e.textContent?.trim().length??0)>0):(e.textContent?.trim().length??0)>0};function r(r,i){let a=i.labelId||t.createId(`a11y-label`),o=i.helperId||t.createId(`a11y-helper`),s=(e,t,n)=>{e.getAttribute(t)!==n&&e.setAttribute(t,n)},c=(e,t)=>{e.textContent!==t&&(e.textContent=t)};s(r,`role`,i.role);let l=()=>{let e=r.shadowRoot;if(!e)return;let t=e.querySelector(`[data-a11y-label]`),l=e.querySelector(`[data-a11y-helper]`),u=i.checked?.(),d=i.invalid?.(),f=i.helperText?.();t?(t.id!==a&&(t.id=a),n(t)?s(r,`aria-labelledby`,a):r.removeAttribute(`aria-labelledby`)):r.removeAttribute(`aria-labelledby`),l?(l.id!==o&&(l.id=o),f?(c(l,f),l.hidden&&=!1,s(r,`aria-describedby`,o),(i.helperTone?.()??`default`)===`error`?s(l,`role`,`alert`):l.removeAttribute(`role`)):(c(l,``),l.hidden||=!0,l.removeAttribute(`role`),r.removeAttribute(`aria-describedby`))):r.removeAttribute(`aria-describedby`),u===void 0?r.removeAttribute(`aria-checked`):s(r,`aria-checked`,u),d===void 0?r.removeAttribute(`aria-invalid`):s(r,`aria-invalid`,String(d))};return e.effect(()=>{l()}),e.onMount(()=>{let t=r.shadowRoot;if(!t)return;l();let n=[t.querySelector(`[data-a11y-label]`),t.querySelector(`[data-a11y-helper]`)].filter(Boolean);if(n.length===0)return;let i=new MutationObserver(()=>{l()});n.forEach(t=>{i.observe(t,{characterData:!0,childList:!0,subtree:!0});let n=t.querySelector(`slot`);if(n){let t=()=>l();n.addEventListener(`slotchange`,t),e.onCleanup(()=>n.removeEventListener(`slotchange`,t))}}),e.onCleanup(()=>i.disconnect())}),{helperId:o,labelId:a}}exports.createA11yControl=r;
1
+ const e=require(`../runtime.cjs`),t=require(`../internal.cjs`);var n=e=>{let t=e.querySelector(`slot`);return t instanceof HTMLSlotElement?t.assignedNodes({flatten:!0}).some(e=>(e.textContent?.trim().length??0)>0):(e.textContent?.trim().length??0)>0};function r(r){let i=e.currentElementOrThrow(),a=r.labelId||t.createId(`a11y-label`),o=r.helperId||t.createId(`a11y-helper`),s=(e,t,n)=>{e.getAttribute(t)!==n&&e.setAttribute(t,n)},c=(e,t)=>{e.textContent!==t&&(e.textContent=t)};s(i,`role`,r.role);let l=null,u=null,d=new Map,f=(e,t)=>{let n=new Set;for(let r of[e,t])if(r)for(let e of Array.from(r.querySelectorAll(`slot`)))e instanceof HTMLSlotElement&&n.add(e);for(let[e,t]of d)n.has(e)||(t(),d.delete(e));for(let e of n){if(d.has(e))continue;let t=()=>p();e.addEventListener(`slotchange`,t),d.set(e,()=>e.removeEventListener(`slotchange`,t))}},p=()=>{if(!i.shadowRoot)return;let e=l,t=u;f(e,t);let d=r.checked?.(),p=r.invalid?.(),m=r.helperText?.();e?(e.id!==a&&(e.id=a),n(e)?s(i,`aria-labelledby`,a):i.removeAttribute(`aria-labelledby`)):i.removeAttribute(`aria-labelledby`),t?(t.id!==o&&(t.id=o),m?(c(t,m),t.hidden&&=!1,s(i,`aria-describedby`,o),(r.helperTone?.()??`default`)===`error`?s(t,`role`,`alert`):t.removeAttribute(`role`)):(c(t,``),t.hidden||=!0,t.removeAttribute(`role`),i.removeAttribute(`aria-describedby`))):i.removeAttribute(`aria-describedby`),d===void 0?i.removeAttribute(`aria-checked`):s(i,`aria-checked`,d),p===void 0?i.removeAttribute(`aria-invalid`):s(i,`aria-invalid`,String(p))};return e.effect(()=>{p()}),e.onMounted(()=>{l=i.shadowRoot?.querySelector(`[data-a11y-label]`)??null,u=i.shadowRoot?.querySelector(`[data-a11y-helper]`)??null,p()}),e.onCleanup(()=>{for(let e of d.values())e();d.clear()}),{helperId:o,labelId:a}}exports.createA11yControl=r;
2
2
  //# sourceMappingURL=a11y-control.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"a11y-control.cjs","names":[],"sources":["../../src/controls/a11y-control.ts"],"sourcesContent":["import { createId } from '../internal';\nimport { effect, onCleanup, onMount } from '../runtime-lifecycle';\n\nexport type A11yTone = 'default' | 'error';\n\nexport type A11yControlConfig = {\n checked?: () => 'true' | 'false' | 'mixed' | undefined;\n helperId?: string;\n helperText?: () => string | undefined;\n helperTone?: () => A11yTone;\n invalid?: () => boolean;\n labelId?: string;\n role: string;\n};\n\nexport type A11yControlHandle = {\n helperId: string;\n labelId: string;\n};\n\nconst hasLabelContent = (labelElement: HTMLElement): boolean => {\n const slot = labelElement.querySelector('slot');\n\n if (slot instanceof HTMLSlotElement) {\n return slot.assignedNodes({ flatten: true }).some((node) => (node.textContent?.trim().length ?? 0) > 0);\n }\n\n return (labelElement.textContent?.trim().length ?? 0) > 0;\n};\n\nexport function createA11yControl(host: HTMLElement, config: A11yControlConfig): A11yControlHandle {\n const labelId = config.labelId || createId('a11y-label');\n const helperId = config.helperId || createId('a11y-helper');\n\n const setAttr = (element: Element, name: string, value: string): void => {\n if (element.getAttribute(name) !== value) element.setAttribute(name, value);\n };\n\n const setText = (element: Node, value: string): void => {\n if (element.textContent !== value) element.textContent = value;\n };\n\n setAttr(host, 'role', config.role);\n\n const sync = (): void => {\n const shadow = host.shadowRoot;\n\n if (!shadow) return;\n\n const labelElement = shadow.querySelector('[data-a11y-label]') as HTMLElement | null;\n const helperElement = shadow.querySelector('[data-a11y-helper]') as HTMLDivElement | null;\n const checked = config.checked?.();\n const invalid = config.invalid?.();\n const helperText = config.helperText?.();\n\n // Sync label\n if (labelElement) {\n if (labelElement.id !== labelId) labelElement.id = labelId;\n\n if (hasLabelContent(labelElement)) setAttr(host, 'aria-labelledby', labelId);\n else host.removeAttribute('aria-labelledby');\n } else {\n host.removeAttribute('aria-labelledby');\n }\n\n // Sync helper\n if (helperElement) {\n if (helperElement.id !== helperId) helperElement.id = helperId;\n\n if (helperText) {\n setText(helperElement, helperText);\n\n if (helperElement.hidden) helperElement.hidden = false;\n\n setAttr(host, 'aria-describedby', helperId);\n\n if ((config.helperTone?.() ?? 'default') === 'error') setAttr(helperElement, 'role', 'alert');\n else helperElement.removeAttribute('role');\n } else {\n setText(helperElement, '');\n\n if (!helperElement.hidden) helperElement.hidden = true;\n\n helperElement.removeAttribute('role');\n host.removeAttribute('aria-describedby');\n }\n } else {\n host.removeAttribute('aria-describedby');\n }\n\n // Sync checked\n if (checked === undefined) host.removeAttribute('aria-checked');\n else setAttr(host, 'aria-checked', checked);\n\n // Sync invalid\n if (invalid === undefined) host.removeAttribute('aria-invalid');\n else setAttr(host, 'aria-invalid', String(invalid));\n };\n\n // Effect for reactive config changes\n effect(() => {\n sync();\n });\n\n // Watch for DOM mutations to label/helper content (slot changes, etc.)\n onMount(() => {\n const shadow = host.shadowRoot;\n\n if (!shadow) return;\n\n sync();\n\n const labelElement = shadow.querySelector('[data-a11y-label]') as HTMLElement | null;\n const helperElement = shadow.querySelector('[data-a11y-helper]') as HTMLElement | null;\n\n const elementsToWatch = [labelElement, helperElement].filter(Boolean) as HTMLElement[];\n\n if (elementsToWatch.length === 0) return;\n\n const observer = new MutationObserver(() => {\n sync();\n });\n\n // Watch label and helper elements for content changes (including slot changes)\n elementsToWatch.forEach((el) => {\n observer.observe(el, { characterData: true, childList: true, subtree: true });\n\n // Also listen for slotchange event to catch slot content updates\n const slot = el.querySelector('slot') as HTMLSlotElement | null;\n\n if (slot) {\n const slotHandler = () => sync();\n\n slot.addEventListener('slotchange', slotHandler);\n onCleanup(() => slot.removeEventListener('slotchange', slotHandler));\n }\n });\n\n onCleanup(() => observer.disconnect());\n });\n\n return { helperId, labelId };\n}\n"],"mappings":"yEAoBA,IAAM,EAAmB,GAAuC,CAC9D,IAAM,EAAO,EAAa,cAAc,OAAO,CAM/C,OAJI,aAAgB,gBACX,EAAK,cAAc,CAAE,QAAS,GAAM,CAAC,CAAC,KAAM,IAAU,EAAK,aAAa,MAAM,CAAC,QAAU,GAAK,EAAE,EAGjG,EAAa,aAAa,MAAM,CAAC,QAAU,GAAK,GAG1D,SAAgB,EAAkB,EAAmB,EAA8C,CACjG,IAAM,EAAU,EAAO,SAAW,EAAA,SAAS,aAAa,CAClD,EAAW,EAAO,UAAY,EAAA,SAAS,cAAc,CAErD,GAAW,EAAkB,EAAc,IAAwB,CACnE,EAAQ,aAAa,EAAK,GAAK,GAAO,EAAQ,aAAa,EAAM,EAAM,EAGvE,GAAW,EAAe,IAAwB,CAClD,EAAQ,cAAgB,IAAO,EAAQ,YAAc,IAG3D,EAAQ,EAAM,OAAQ,EAAO,KAAK,CAElC,IAAM,MAAmB,CACvB,IAAM,EAAS,EAAK,WAEpB,GAAI,CAAC,EAAQ,OAEb,IAAM,EAAe,EAAO,cAAc,oBAAoB,CACxD,EAAgB,EAAO,cAAc,qBAAqB,CAC1D,EAAU,EAAO,WAAW,CAC5B,EAAU,EAAO,WAAW,CAC5B,EAAa,EAAO,cAAc,CAGpC,GACE,EAAa,KAAO,IAAS,EAAa,GAAK,GAE/C,EAAgB,EAAa,CAAE,EAAQ,EAAM,kBAAmB,EAAQ,CACvE,EAAK,gBAAgB,kBAAkB,EAE5C,EAAK,gBAAgB,kBAAkB,CAIrC,GACE,EAAc,KAAO,IAAU,EAAc,GAAK,GAElD,GACF,EAAQ,EAAe,EAAW,CAElC,AAA0B,EAAc,SAAS,GAEjD,EAAQ,EAAM,mBAAoB,EAAS,EAEtC,EAAO,cAAc,EAAI,aAAe,QAAS,EAAQ,EAAe,OAAQ,QAAQ,CACxF,EAAc,gBAAgB,OAAO,GAE1C,EAAQ,EAAe,GAAG,CAE1B,AAA2B,EAAc,SAAS,GAElD,EAAc,gBAAgB,OAAO,CACrC,EAAK,gBAAgB,mBAAmB,GAG1C,EAAK,gBAAgB,mBAAmB,CAItC,IAAY,IAAA,GAAW,EAAK,gBAAgB,eAAe,CAC1D,EAAQ,EAAM,eAAgB,EAAQ,CAGvC,IAAY,IAAA,GAAW,EAAK,gBAAgB,eAAe,CAC1D,EAAQ,EAAM,eAAgB,OAAO,EAAQ,CAAC,EA6CrD,OAzCA,EAAA,WAAa,CACX,GAAM,EACN,CAGF,EAAA,YAAc,CACZ,IAAM,EAAS,EAAK,WAEpB,GAAI,CAAC,EAAQ,OAEb,GAAM,CAKN,IAAM,EAAkB,CAHH,EAAO,cAAc,oBAAoB,CACxC,EAAO,cAAc,qBAAqB,CAEX,CAAC,OAAO,QAAQ,CAErE,GAAI,EAAgB,SAAW,EAAG,OAElC,IAAM,EAAW,IAAI,qBAAuB,CAC1C,GAAM,EACN,CAGF,EAAgB,QAAS,GAAO,CAC9B,EAAS,QAAQ,EAAI,CAAE,cAAe,GAAM,UAAW,GAAM,QAAS,GAAM,CAAC,CAG7E,IAAM,EAAO,EAAG,cAAc,OAAO,CAErC,GAAI,EAAM,CACR,IAAM,MAAoB,GAAM,CAEhC,EAAK,iBAAiB,aAAc,EAAY,CAChD,EAAA,cAAgB,EAAK,oBAAoB,aAAc,EAAY,CAAC,GAEtE,CAEF,EAAA,cAAgB,EAAS,YAAY,CAAC,EACtC,CAEK,CAAE,WAAU,UAAS"}
1
+ {"version":3,"file":"a11y-control.cjs","names":[],"sources":["../../src/controls/a11y-control.ts"],"sourcesContent":["import { createId } from '../internal';\nimport { currentElementOrThrow, effect, onCleanup, onMounted } from '../runtime';\n\nexport type A11yTone = 'default' | 'error';\n\nexport type A11yControlConfig = {\n checked?: () => 'true' | 'false' | 'mixed' | undefined;\n helperId?: string;\n helperText?: () => string | undefined;\n helperTone?: () => A11yTone;\n invalid?: () => boolean;\n labelId?: string;\n role: string;\n};\n\nexport type A11yControlHandle = {\n helperId: string;\n labelId: string;\n};\n\nconst hasLabelContent = (labelElement: HTMLElement): boolean => {\n const slot = labelElement.querySelector('slot');\n\n if (slot instanceof HTMLSlotElement) {\n return slot.assignedNodes({ flatten: true }).some((node) => (node.textContent?.trim().length ?? 0) > 0);\n }\n\n return (labelElement.textContent?.trim().length ?? 0) > 0;\n};\n\nexport function createA11yControl(config: A11yControlConfig): A11yControlHandle {\n const host = currentElementOrThrow();\n const labelId = config.labelId || createId('a11y-label');\n const helperId = config.helperId || createId('a11y-helper');\n\n const setAttr = (element: Element, name: string, value: string): void => {\n if (element.getAttribute(name) !== value) element.setAttribute(name, value);\n };\n\n const setText = (element: Node, value: string): void => {\n if (element.textContent !== value) element.textContent = value;\n };\n\n setAttr(host, 'role', config.role);\n\n let labelEl: HTMLElement | null = null;\n let helperEl: HTMLDivElement | null = null;\n\n const slotCleanupByElement = new Map<HTMLSlotElement, () => void>();\n\n const syncSlotListeners = (labelElement: HTMLElement | null, helperElement: HTMLDivElement | null): void => {\n const nextSlots = new Set<HTMLSlotElement>();\n\n for (const container of [labelElement, helperElement]) {\n if (!container) continue;\n\n for (const slot of Array.from(container.querySelectorAll('slot'))) {\n if (slot instanceof HTMLSlotElement) nextSlots.add(slot);\n }\n }\n\n for (const [slot, cleanup] of slotCleanupByElement) {\n if (nextSlots.has(slot)) continue;\n\n cleanup();\n slotCleanupByElement.delete(slot);\n }\n\n for (const slot of nextSlots) {\n if (slotCleanupByElement.has(slot)) continue;\n\n const slotHandler = () => sync();\n\n slot.addEventListener('slotchange', slotHandler);\n slotCleanupByElement.set(slot, () => slot.removeEventListener('slotchange', slotHandler));\n }\n };\n\n const sync = (): void => {\n const shadow = host.shadowRoot;\n\n if (!shadow) return;\n\n const labelElement = labelEl;\n const helperElement = helperEl;\n\n syncSlotListeners(labelElement, helperElement);\n\n const checked = config.checked?.();\n const invalid = config.invalid?.();\n const helperText = config.helperText?.();\n\n // Sync label\n if (labelElement) {\n if (labelElement.id !== labelId) labelElement.id = labelId;\n\n if (hasLabelContent(labelElement)) setAttr(host, 'aria-labelledby', labelId);\n else host.removeAttribute('aria-labelledby');\n } else {\n host.removeAttribute('aria-labelledby');\n }\n\n // Sync helper\n if (helperElement) {\n if (helperElement.id !== helperId) helperElement.id = helperId;\n\n if (helperText) {\n setText(helperElement, helperText);\n\n if (helperElement.hidden) helperElement.hidden = false;\n\n setAttr(host, 'aria-describedby', helperId);\n\n if ((config.helperTone?.() ?? 'default') === 'error') setAttr(helperElement, 'role', 'alert');\n else helperElement.removeAttribute('role');\n } else {\n setText(helperElement, '');\n\n if (!helperElement.hidden) helperElement.hidden = true;\n\n helperElement.removeAttribute('role');\n host.removeAttribute('aria-describedby');\n }\n } else {\n host.removeAttribute('aria-describedby');\n }\n\n // Sync checked\n if (checked === undefined) host.removeAttribute('aria-checked');\n else setAttr(host, 'aria-checked', checked);\n\n // Sync invalid\n if (invalid === undefined) host.removeAttribute('aria-invalid');\n else setAttr(host, 'aria-invalid', String(invalid));\n };\n\n // Keep ARIA in sync with reactive config changes.\n effect(() => {\n sync();\n });\n\n // Query shadow DOM refs once after first render, then sync.\n onMounted(() => {\n labelEl = (host.shadowRoot?.querySelector('[data-a11y-label]') ?? null) as HTMLElement | null;\n helperEl = (host.shadowRoot?.querySelector('[data-a11y-helper]') ?? null) as HTMLDivElement | null;\n sync();\n });\n\n onCleanup(() => {\n for (const cleanup of slotCleanupByElement.values()) cleanup();\n slotCleanupByElement.clear();\n });\n\n return { helperId, labelId };\n}\n"],"mappings":"+DAoBA,IAAM,EAAmB,GAAuC,CAC9D,IAAM,EAAO,EAAa,cAAc,MAAM,EAM9C,OAJI,aAAgB,gBACX,EAAK,cAAc,CAAE,QAAS,EAAK,CAAC,EAAE,KAAM,IAAU,EAAK,aAAa,KAAK,EAAE,QAAU,GAAK,CAAC,GAGhG,EAAa,aAAa,KAAK,EAAE,QAAU,GAAK,CAC1D,EAEA,SAAgB,EAAkB,EAA8C,CAC9E,IAAM,EAAO,EAAA,sBAAsB,EAC7B,EAAU,EAAO,SAAW,EAAA,SAAS,YAAY,EACjD,EAAW,EAAO,UAAY,EAAA,SAAS,aAAa,EAEpD,GAAW,EAAkB,EAAc,IAAwB,CACnE,EAAQ,aAAa,CAAI,IAAM,GAAO,EAAQ,aAAa,EAAM,CAAK,CAC5E,EAEM,GAAW,EAAe,IAAwB,CAClD,EAAQ,cAAgB,IAAO,EAAQ,YAAc,EAC3D,EAEA,EAAQ,EAAM,OAAQ,EAAO,IAAI,EAEjC,IAAI,EAA8B,KAC9B,EAAkC,KAEhC,EAAuB,IAAI,IAE3B,GAAqB,EAAkC,IAA+C,CAC1G,IAAM,EAAY,IAAI,IAEtB,IAAK,IAAM,IAAa,CAAC,EAAc,CAAa,EAC7C,KAEL,IAAK,IAAM,KAAQ,MAAM,KAAK,EAAU,iBAAiB,MAAM,CAAC,EAC1D,aAAgB,iBAAiB,EAAU,IAAI,CAAI,EAI3D,IAAK,GAAM,CAAC,EAAM,KAAY,EACxB,EAAU,IAAI,CAAI,IAEtB,EAAQ,EACR,EAAqB,OAAO,CAAI,GAGlC,IAAK,IAAM,KAAQ,EAAW,CAC5B,GAAI,EAAqB,IAAI,CAAI,EAAG,SAEpC,IAAM,MAAoB,EAAK,EAE/B,EAAK,iBAAiB,aAAc,CAAW,EAC/C,EAAqB,IAAI,MAAY,EAAK,oBAAoB,aAAc,CAAW,CAAC,CAC1F,CACF,EAEM,MAAmB,CAGvB,GAAI,CAFW,EAAK,WAEP,OAEb,IAAM,EAAe,EACf,EAAgB,EAEtB,EAAkB,EAAc,CAAa,EAE7C,IAAM,EAAU,EAAO,UAAU,EAC3B,EAAU,EAAO,UAAU,EAC3B,EAAa,EAAO,aAAa,EAGnC,GACE,EAAa,KAAO,IAAS,EAAa,GAAK,GAE/C,EAAgB,CAAY,EAAG,EAAQ,EAAM,kBAAmB,CAAO,EACtE,EAAK,gBAAgB,iBAAiB,GAE3C,EAAK,gBAAgB,iBAAiB,EAIpC,GACE,EAAc,KAAO,IAAU,EAAc,GAAK,GAElD,GACF,EAAQ,EAAe,CAAU,EAEjC,AAA0B,EAAc,SAAS,GAEjD,EAAQ,EAAM,mBAAoB,CAAQ,GAErC,EAAO,aAAa,GAAK,aAAe,QAAS,EAAQ,EAAe,OAAQ,OAAO,EACvF,EAAc,gBAAgB,MAAM,IAEzC,EAAQ,EAAe,EAAE,EAEzB,AAA2B,EAAc,SAAS,GAElD,EAAc,gBAAgB,MAAM,EACpC,EAAK,gBAAgB,kBAAkB,IAGzC,EAAK,gBAAgB,kBAAkB,EAIrC,IAAY,IAAA,GAAW,EAAK,gBAAgB,cAAc,EACzD,EAAQ,EAAM,eAAgB,CAAO,EAGtC,IAAY,IAAA,GAAW,EAAK,gBAAgB,cAAc,EACzD,EAAQ,EAAM,eAAgB,OAAO,CAAO,CAAC,CACpD,EAmBA,OAhBA,EAAA,WAAa,CACX,EAAK,CACP,CAAC,EAGD,EAAA,cAAgB,CACd,EAAW,EAAK,YAAY,cAAc,mBAAmB,GAAK,KAClE,EAAY,EAAK,YAAY,cAAc,oBAAoB,GAAK,KACpE,EAAK,CACP,CAAC,EAED,EAAA,cAAgB,CACd,IAAK,IAAM,KAAW,EAAqB,OAAO,EAAG,EAAQ,EAC7D,EAAqB,MAAM,CAC7B,CAAC,EAEM,CAAE,WAAU,SAAQ,CAC7B"}
@@ -12,5 +12,5 @@ export type A11yControlHandle = {
12
12
  helperId: string;
13
13
  labelId: string;
14
14
  };
15
- export declare function createA11yControl(host: HTMLElement, config: A11yControlConfig): A11yControlHandle;
15
+ export declare function createA11yControl(config: A11yControlConfig): A11yControlHandle;
16
16
  //# sourceMappingURL=a11y-control.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"a11y-control.d.ts","sourceRoot":"","sources":["../../src/controls/a11y-control.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;AAE3C,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,CAAC,EAAE,MAAM,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACtC,UAAU,CAAC,EAAE,MAAM,QAAQ,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAYF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,iBAAiB,GAAG,iBAAiB,CAgHjG"}
1
+ {"version":3,"file":"a11y-control.d.ts","sourceRoot":"","sources":["../../src/controls/a11y-control.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;AAE3C,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,CAAC,EAAE,MAAM,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACtC,UAAU,CAAC,EAAE,MAAM,QAAQ,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAYF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,iBAAiB,CA4H9E"}
@@ -1,2 +1,2 @@
1
- import{effect as e,onCleanup as t,onMount as n}from"../runtime-lifecycle.js";import{createId as r}from"../internal.js";var i=e=>{let t=e.querySelector(`slot`);return t instanceof HTMLSlotElement?t.assignedNodes({flatten:!0}).some(e=>(e.textContent?.trim().length??0)>0):(e.textContent?.trim().length??0)>0};function a(a,o){let s=o.labelId||r(`a11y-label`),c=o.helperId||r(`a11y-helper`),l=(e,t,n)=>{e.getAttribute(t)!==n&&e.setAttribute(t,n)},u=(e,t)=>{e.textContent!==t&&(e.textContent=t)};l(a,`role`,o.role);let d=()=>{let e=a.shadowRoot;if(!e)return;let t=e.querySelector(`[data-a11y-label]`),n=e.querySelector(`[data-a11y-helper]`),r=o.checked?.(),d=o.invalid?.(),f=o.helperText?.();t?(t.id!==s&&(t.id=s),i(t)?l(a,`aria-labelledby`,s):a.removeAttribute(`aria-labelledby`)):a.removeAttribute(`aria-labelledby`),n?(n.id!==c&&(n.id=c),f?(u(n,f),n.hidden&&=!1,l(a,`aria-describedby`,c),(o.helperTone?.()??`default`)===`error`?l(n,`role`,`alert`):n.removeAttribute(`role`)):(u(n,``),n.hidden||=!0,n.removeAttribute(`role`),a.removeAttribute(`aria-describedby`))):a.removeAttribute(`aria-describedby`),r===void 0?a.removeAttribute(`aria-checked`):l(a,`aria-checked`,r),d===void 0?a.removeAttribute(`aria-invalid`):l(a,`aria-invalid`,String(d))};return e(()=>{d()}),n(()=>{let e=a.shadowRoot;if(!e)return;d();let n=[e.querySelector(`[data-a11y-label]`),e.querySelector(`[data-a11y-helper]`)].filter(Boolean);if(n.length===0)return;let r=new MutationObserver(()=>{d()});n.forEach(e=>{r.observe(e,{characterData:!0,childList:!0,subtree:!0});let n=e.querySelector(`slot`);if(n){let e=()=>d();n.addEventListener(`slotchange`,e),t(()=>n.removeEventListener(`slotchange`,e))}}),t(()=>r.disconnect())}),{helperId:c,labelId:s}}export{a as createA11yControl};
1
+ import{currentElementOrThrow as e,effect as t,onCleanup as n,onMounted as r}from"../runtime.js";import{createId as i}from"../internal.js";var a=e=>{let t=e.querySelector(`slot`);return t instanceof HTMLSlotElement?t.assignedNodes({flatten:!0}).some(e=>(e.textContent?.trim().length??0)>0):(e.textContent?.trim().length??0)>0};function o(o){let s=e(),c=o.labelId||i(`a11y-label`),l=o.helperId||i(`a11y-helper`),u=(e,t,n)=>{e.getAttribute(t)!==n&&e.setAttribute(t,n)},d=(e,t)=>{e.textContent!==t&&(e.textContent=t)};u(s,`role`,o.role);let f=null,p=null,m=new Map,h=(e,t)=>{let n=new Set;for(let r of[e,t])if(r)for(let e of Array.from(r.querySelectorAll(`slot`)))e instanceof HTMLSlotElement&&n.add(e);for(let[e,t]of m)n.has(e)||(t(),m.delete(e));for(let e of n){if(m.has(e))continue;let t=()=>g();e.addEventListener(`slotchange`,t),m.set(e,()=>e.removeEventListener(`slotchange`,t))}},g=()=>{if(!s.shadowRoot)return;let e=f,t=p;h(e,t);let n=o.checked?.(),r=o.invalid?.(),i=o.helperText?.();e?(e.id!==c&&(e.id=c),a(e)?u(s,`aria-labelledby`,c):s.removeAttribute(`aria-labelledby`)):s.removeAttribute(`aria-labelledby`),t?(t.id!==l&&(t.id=l),i?(d(t,i),t.hidden&&=!1,u(s,`aria-describedby`,l),(o.helperTone?.()??`default`)===`error`?u(t,`role`,`alert`):t.removeAttribute(`role`)):(d(t,``),t.hidden||=!0,t.removeAttribute(`role`),s.removeAttribute(`aria-describedby`))):s.removeAttribute(`aria-describedby`),n===void 0?s.removeAttribute(`aria-checked`):u(s,`aria-checked`,n),r===void 0?s.removeAttribute(`aria-invalid`):u(s,`aria-invalid`,String(r))};return t(()=>{g()}),r(()=>{f=s.shadowRoot?.querySelector(`[data-a11y-label]`)??null,p=s.shadowRoot?.querySelector(`[data-a11y-helper]`)??null,g()}),n(()=>{for(let e of m.values())e();m.clear()}),{helperId:l,labelId:c}}export{o as createA11yControl};
2
2
  //# sourceMappingURL=a11y-control.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"a11y-control.js","names":[],"sources":["../../src/controls/a11y-control.ts"],"sourcesContent":["import { createId } from '../internal';\nimport { effect, onCleanup, onMount } from '../runtime-lifecycle';\n\nexport type A11yTone = 'default' | 'error';\n\nexport type A11yControlConfig = {\n checked?: () => 'true' | 'false' | 'mixed' | undefined;\n helperId?: string;\n helperText?: () => string | undefined;\n helperTone?: () => A11yTone;\n invalid?: () => boolean;\n labelId?: string;\n role: string;\n};\n\nexport type A11yControlHandle = {\n helperId: string;\n labelId: string;\n};\n\nconst hasLabelContent = (labelElement: HTMLElement): boolean => {\n const slot = labelElement.querySelector('slot');\n\n if (slot instanceof HTMLSlotElement) {\n return slot.assignedNodes({ flatten: true }).some((node) => (node.textContent?.trim().length ?? 0) > 0);\n }\n\n return (labelElement.textContent?.trim().length ?? 0) > 0;\n};\n\nexport function createA11yControl(host: HTMLElement, config: A11yControlConfig): A11yControlHandle {\n const labelId = config.labelId || createId('a11y-label');\n const helperId = config.helperId || createId('a11y-helper');\n\n const setAttr = (element: Element, name: string, value: string): void => {\n if (element.getAttribute(name) !== value) element.setAttribute(name, value);\n };\n\n const setText = (element: Node, value: string): void => {\n if (element.textContent !== value) element.textContent = value;\n };\n\n setAttr(host, 'role', config.role);\n\n const sync = (): void => {\n const shadow = host.shadowRoot;\n\n if (!shadow) return;\n\n const labelElement = shadow.querySelector('[data-a11y-label]') as HTMLElement | null;\n const helperElement = shadow.querySelector('[data-a11y-helper]') as HTMLDivElement | null;\n const checked = config.checked?.();\n const invalid = config.invalid?.();\n const helperText = config.helperText?.();\n\n // Sync label\n if (labelElement) {\n if (labelElement.id !== labelId) labelElement.id = labelId;\n\n if (hasLabelContent(labelElement)) setAttr(host, 'aria-labelledby', labelId);\n else host.removeAttribute('aria-labelledby');\n } else {\n host.removeAttribute('aria-labelledby');\n }\n\n // Sync helper\n if (helperElement) {\n if (helperElement.id !== helperId) helperElement.id = helperId;\n\n if (helperText) {\n setText(helperElement, helperText);\n\n if (helperElement.hidden) helperElement.hidden = false;\n\n setAttr(host, 'aria-describedby', helperId);\n\n if ((config.helperTone?.() ?? 'default') === 'error') setAttr(helperElement, 'role', 'alert');\n else helperElement.removeAttribute('role');\n } else {\n setText(helperElement, '');\n\n if (!helperElement.hidden) helperElement.hidden = true;\n\n helperElement.removeAttribute('role');\n host.removeAttribute('aria-describedby');\n }\n } else {\n host.removeAttribute('aria-describedby');\n }\n\n // Sync checked\n if (checked === undefined) host.removeAttribute('aria-checked');\n else setAttr(host, 'aria-checked', checked);\n\n // Sync invalid\n if (invalid === undefined) host.removeAttribute('aria-invalid');\n else setAttr(host, 'aria-invalid', String(invalid));\n };\n\n // Effect for reactive config changes\n effect(() => {\n sync();\n });\n\n // Watch for DOM mutations to label/helper content (slot changes, etc.)\n onMount(() => {\n const shadow = host.shadowRoot;\n\n if (!shadow) return;\n\n sync();\n\n const labelElement = shadow.querySelector('[data-a11y-label]') as HTMLElement | null;\n const helperElement = shadow.querySelector('[data-a11y-helper]') as HTMLElement | null;\n\n const elementsToWatch = [labelElement, helperElement].filter(Boolean) as HTMLElement[];\n\n if (elementsToWatch.length === 0) return;\n\n const observer = new MutationObserver(() => {\n sync();\n });\n\n // Watch label and helper elements for content changes (including slot changes)\n elementsToWatch.forEach((el) => {\n observer.observe(el, { characterData: true, childList: true, subtree: true });\n\n // Also listen for slotchange event to catch slot content updates\n const slot = el.querySelector('slot') as HTMLSlotElement | null;\n\n if (slot) {\n const slotHandler = () => sync();\n\n slot.addEventListener('slotchange', slotHandler);\n onCleanup(() => slot.removeEventListener('slotchange', slotHandler));\n }\n });\n\n onCleanup(() => observer.disconnect());\n });\n\n return { helperId, labelId };\n}\n"],"mappings":"uHAoBA,IAAM,EAAmB,GAAuC,CAC9D,IAAM,EAAO,EAAa,cAAc,OAAO,CAM/C,OAJI,aAAgB,gBACX,EAAK,cAAc,CAAE,QAAS,GAAM,CAAC,CAAC,KAAM,IAAU,EAAK,aAAa,MAAM,CAAC,QAAU,GAAK,EAAE,EAGjG,EAAa,aAAa,MAAM,CAAC,QAAU,GAAK,GAG1D,SAAgB,EAAkB,EAAmB,EAA8C,CACjG,IAAM,EAAU,EAAO,SAAW,EAAS,aAAa,CAClD,EAAW,EAAO,UAAY,EAAS,cAAc,CAErD,GAAW,EAAkB,EAAc,IAAwB,CACnE,EAAQ,aAAa,EAAK,GAAK,GAAO,EAAQ,aAAa,EAAM,EAAM,EAGvE,GAAW,EAAe,IAAwB,CAClD,EAAQ,cAAgB,IAAO,EAAQ,YAAc,IAG3D,EAAQ,EAAM,OAAQ,EAAO,KAAK,CAElC,IAAM,MAAmB,CACvB,IAAM,EAAS,EAAK,WAEpB,GAAI,CAAC,EAAQ,OAEb,IAAM,EAAe,EAAO,cAAc,oBAAoB,CACxD,EAAgB,EAAO,cAAc,qBAAqB,CAC1D,EAAU,EAAO,WAAW,CAC5B,EAAU,EAAO,WAAW,CAC5B,EAAa,EAAO,cAAc,CAGpC,GACE,EAAa,KAAO,IAAS,EAAa,GAAK,GAE/C,EAAgB,EAAa,CAAE,EAAQ,EAAM,kBAAmB,EAAQ,CACvE,EAAK,gBAAgB,kBAAkB,EAE5C,EAAK,gBAAgB,kBAAkB,CAIrC,GACE,EAAc,KAAO,IAAU,EAAc,GAAK,GAElD,GACF,EAAQ,EAAe,EAAW,CAElC,AAA0B,EAAc,SAAS,GAEjD,EAAQ,EAAM,mBAAoB,EAAS,EAEtC,EAAO,cAAc,EAAI,aAAe,QAAS,EAAQ,EAAe,OAAQ,QAAQ,CACxF,EAAc,gBAAgB,OAAO,GAE1C,EAAQ,EAAe,GAAG,CAE1B,AAA2B,EAAc,SAAS,GAElD,EAAc,gBAAgB,OAAO,CACrC,EAAK,gBAAgB,mBAAmB,GAG1C,EAAK,gBAAgB,mBAAmB,CAItC,IAAY,IAAA,GAAW,EAAK,gBAAgB,eAAe,CAC1D,EAAQ,EAAM,eAAgB,EAAQ,CAGvC,IAAY,IAAA,GAAW,EAAK,gBAAgB,eAAe,CAC1D,EAAQ,EAAM,eAAgB,OAAO,EAAQ,CAAC,EA6CrD,OAzCA,MAAa,CACX,GAAM,EACN,CAGF,MAAc,CACZ,IAAM,EAAS,EAAK,WAEpB,GAAI,CAAC,EAAQ,OAEb,GAAM,CAKN,IAAM,EAAkB,CAHH,EAAO,cAAc,oBAAoB,CACxC,EAAO,cAAc,qBAAqB,CAEX,CAAC,OAAO,QAAQ,CAErE,GAAI,EAAgB,SAAW,EAAG,OAElC,IAAM,EAAW,IAAI,qBAAuB,CAC1C,GAAM,EACN,CAGF,EAAgB,QAAS,GAAO,CAC9B,EAAS,QAAQ,EAAI,CAAE,cAAe,GAAM,UAAW,GAAM,QAAS,GAAM,CAAC,CAG7E,IAAM,EAAO,EAAG,cAAc,OAAO,CAErC,GAAI,EAAM,CACR,IAAM,MAAoB,GAAM,CAEhC,EAAK,iBAAiB,aAAc,EAAY,CAChD,MAAgB,EAAK,oBAAoB,aAAc,EAAY,CAAC,GAEtE,CAEF,MAAgB,EAAS,YAAY,CAAC,EACtC,CAEK,CAAE,WAAU,UAAS"}
1
+ {"version":3,"file":"a11y-control.js","names":[],"sources":["../../src/controls/a11y-control.ts"],"sourcesContent":["import { createId } from '../internal';\nimport { currentElementOrThrow, effect, onCleanup, onMounted } from '../runtime';\n\nexport type A11yTone = 'default' | 'error';\n\nexport type A11yControlConfig = {\n checked?: () => 'true' | 'false' | 'mixed' | undefined;\n helperId?: string;\n helperText?: () => string | undefined;\n helperTone?: () => A11yTone;\n invalid?: () => boolean;\n labelId?: string;\n role: string;\n};\n\nexport type A11yControlHandle = {\n helperId: string;\n labelId: string;\n};\n\nconst hasLabelContent = (labelElement: HTMLElement): boolean => {\n const slot = labelElement.querySelector('slot');\n\n if (slot instanceof HTMLSlotElement) {\n return slot.assignedNodes({ flatten: true }).some((node) => (node.textContent?.trim().length ?? 0) > 0);\n }\n\n return (labelElement.textContent?.trim().length ?? 0) > 0;\n};\n\nexport function createA11yControl(config: A11yControlConfig): A11yControlHandle {\n const host = currentElementOrThrow();\n const labelId = config.labelId || createId('a11y-label');\n const helperId = config.helperId || createId('a11y-helper');\n\n const setAttr = (element: Element, name: string, value: string): void => {\n if (element.getAttribute(name) !== value) element.setAttribute(name, value);\n };\n\n const setText = (element: Node, value: string): void => {\n if (element.textContent !== value) element.textContent = value;\n };\n\n setAttr(host, 'role', config.role);\n\n let labelEl: HTMLElement | null = null;\n let helperEl: HTMLDivElement | null = null;\n\n const slotCleanupByElement = new Map<HTMLSlotElement, () => void>();\n\n const syncSlotListeners = (labelElement: HTMLElement | null, helperElement: HTMLDivElement | null): void => {\n const nextSlots = new Set<HTMLSlotElement>();\n\n for (const container of [labelElement, helperElement]) {\n if (!container) continue;\n\n for (const slot of Array.from(container.querySelectorAll('slot'))) {\n if (slot instanceof HTMLSlotElement) nextSlots.add(slot);\n }\n }\n\n for (const [slot, cleanup] of slotCleanupByElement) {\n if (nextSlots.has(slot)) continue;\n\n cleanup();\n slotCleanupByElement.delete(slot);\n }\n\n for (const slot of nextSlots) {\n if (slotCleanupByElement.has(slot)) continue;\n\n const slotHandler = () => sync();\n\n slot.addEventListener('slotchange', slotHandler);\n slotCleanupByElement.set(slot, () => slot.removeEventListener('slotchange', slotHandler));\n }\n };\n\n const sync = (): void => {\n const shadow = host.shadowRoot;\n\n if (!shadow) return;\n\n const labelElement = labelEl;\n const helperElement = helperEl;\n\n syncSlotListeners(labelElement, helperElement);\n\n const checked = config.checked?.();\n const invalid = config.invalid?.();\n const helperText = config.helperText?.();\n\n // Sync label\n if (labelElement) {\n if (labelElement.id !== labelId) labelElement.id = labelId;\n\n if (hasLabelContent(labelElement)) setAttr(host, 'aria-labelledby', labelId);\n else host.removeAttribute('aria-labelledby');\n } else {\n host.removeAttribute('aria-labelledby');\n }\n\n // Sync helper\n if (helperElement) {\n if (helperElement.id !== helperId) helperElement.id = helperId;\n\n if (helperText) {\n setText(helperElement, helperText);\n\n if (helperElement.hidden) helperElement.hidden = false;\n\n setAttr(host, 'aria-describedby', helperId);\n\n if ((config.helperTone?.() ?? 'default') === 'error') setAttr(helperElement, 'role', 'alert');\n else helperElement.removeAttribute('role');\n } else {\n setText(helperElement, '');\n\n if (!helperElement.hidden) helperElement.hidden = true;\n\n helperElement.removeAttribute('role');\n host.removeAttribute('aria-describedby');\n }\n } else {\n host.removeAttribute('aria-describedby');\n }\n\n // Sync checked\n if (checked === undefined) host.removeAttribute('aria-checked');\n else setAttr(host, 'aria-checked', checked);\n\n // Sync invalid\n if (invalid === undefined) host.removeAttribute('aria-invalid');\n else setAttr(host, 'aria-invalid', String(invalid));\n };\n\n // Keep ARIA in sync with reactive config changes.\n effect(() => {\n sync();\n });\n\n // Query shadow DOM refs once after first render, then sync.\n onMounted(() => {\n labelEl = (host.shadowRoot?.querySelector('[data-a11y-label]') ?? null) as HTMLElement | null;\n helperEl = (host.shadowRoot?.querySelector('[data-a11y-helper]') ?? null) as HTMLDivElement | null;\n sync();\n });\n\n onCleanup(() => {\n for (const cleanup of slotCleanupByElement.values()) cleanup();\n slotCleanupByElement.clear();\n });\n\n return { helperId, labelId };\n}\n"],"mappings":"0IAoBA,IAAM,EAAmB,GAAuC,CAC9D,IAAM,EAAO,EAAa,cAAc,MAAM,EAM9C,OAJI,aAAgB,gBACX,EAAK,cAAc,CAAE,QAAS,EAAK,CAAC,EAAE,KAAM,IAAU,EAAK,aAAa,KAAK,EAAE,QAAU,GAAK,CAAC,GAGhG,EAAa,aAAa,KAAK,EAAE,QAAU,GAAK,CAC1D,EAEA,SAAgB,EAAkB,EAA8C,CAC9E,IAAM,EAAO,EAAsB,EAC7B,EAAU,EAAO,SAAW,EAAS,YAAY,EACjD,EAAW,EAAO,UAAY,EAAS,aAAa,EAEpD,GAAW,EAAkB,EAAc,IAAwB,CACnE,EAAQ,aAAa,CAAI,IAAM,GAAO,EAAQ,aAAa,EAAM,CAAK,CAC5E,EAEM,GAAW,EAAe,IAAwB,CAClD,EAAQ,cAAgB,IAAO,EAAQ,YAAc,EAC3D,EAEA,EAAQ,EAAM,OAAQ,EAAO,IAAI,EAEjC,IAAI,EAA8B,KAC9B,EAAkC,KAEhC,EAAuB,IAAI,IAE3B,GAAqB,EAAkC,IAA+C,CAC1G,IAAM,EAAY,IAAI,IAEtB,IAAK,IAAM,IAAa,CAAC,EAAc,CAAa,EAC7C,KAEL,IAAK,IAAM,KAAQ,MAAM,KAAK,EAAU,iBAAiB,MAAM,CAAC,EAC1D,aAAgB,iBAAiB,EAAU,IAAI,CAAI,EAI3D,IAAK,GAAM,CAAC,EAAM,KAAY,EACxB,EAAU,IAAI,CAAI,IAEtB,EAAQ,EACR,EAAqB,OAAO,CAAI,GAGlC,IAAK,IAAM,KAAQ,EAAW,CAC5B,GAAI,EAAqB,IAAI,CAAI,EAAG,SAEpC,IAAM,MAAoB,EAAK,EAE/B,EAAK,iBAAiB,aAAc,CAAW,EAC/C,EAAqB,IAAI,MAAY,EAAK,oBAAoB,aAAc,CAAW,CAAC,CAC1F,CACF,EAEM,MAAmB,CAGvB,GAAI,CAFW,EAAK,WAEP,OAEb,IAAM,EAAe,EACf,EAAgB,EAEtB,EAAkB,EAAc,CAAa,EAE7C,IAAM,EAAU,EAAO,UAAU,EAC3B,EAAU,EAAO,UAAU,EAC3B,EAAa,EAAO,aAAa,EAGnC,GACE,EAAa,KAAO,IAAS,EAAa,GAAK,GAE/C,EAAgB,CAAY,EAAG,EAAQ,EAAM,kBAAmB,CAAO,EACtE,EAAK,gBAAgB,iBAAiB,GAE3C,EAAK,gBAAgB,iBAAiB,EAIpC,GACE,EAAc,KAAO,IAAU,EAAc,GAAK,GAElD,GACF,EAAQ,EAAe,CAAU,EAEjC,AAA0B,EAAc,SAAS,GAEjD,EAAQ,EAAM,mBAAoB,CAAQ,GAErC,EAAO,aAAa,GAAK,aAAe,QAAS,EAAQ,EAAe,OAAQ,OAAO,EACvF,EAAc,gBAAgB,MAAM,IAEzC,EAAQ,EAAe,EAAE,EAEzB,AAA2B,EAAc,SAAS,GAElD,EAAc,gBAAgB,MAAM,EACpC,EAAK,gBAAgB,kBAAkB,IAGzC,EAAK,gBAAgB,kBAAkB,EAIrC,IAAY,IAAA,GAAW,EAAK,gBAAgB,cAAc,EACzD,EAAQ,EAAM,eAAgB,CAAO,EAGtC,IAAY,IAAA,GAAW,EAAK,gBAAgB,cAAc,EACzD,EAAQ,EAAM,eAAgB,OAAO,CAAO,CAAC,CACpD,EAmBA,OAhBA,MAAa,CACX,EAAK,CACP,CAAC,EAGD,MAAgB,CACd,EAAW,EAAK,YAAY,cAAc,mBAAmB,GAAK,KAClE,EAAY,EAAK,YAAY,cAAc,oBAAoB,GAAK,KACpE,EAAK,CACP,CAAC,EAED,MAAgB,CACd,IAAK,IAAM,KAAW,EAAqB,OAAO,EAAG,EAAQ,EAC7D,EAAqB,MAAM,CAC7B,CAAC,EAEM,CAAE,WAAU,SAAQ,CAC7B"}
@@ -1,2 +1,2 @@
1
- const e=require(`./a11y-control.cjs`),t=require(`./field-control.cjs`),n=require(`./press-control.cjs`);var r=r=>{let i=t.createCheckableStateControl(r);return{a11y:e.createA11yControl(r.host,{checked:()=>r.role===`checkbox`&&i.indeterminate.value?`mixed`:i.checked.value?`true`:`false`,helperText:()=>i.assistive.value.text,helperTone:()=>i.assistive.value.isError?`error`:`default`,invalid:()=>i.assistive.value.isError,role:r.role}),control:i,press:n.createPressControl({disabled:()=>i.disabled.value,onPress:e=>{if(r.onPress){r.onPress(i,e);return}i.toggle(e)}})}};exports.createCheckableFieldControl=r;
1
+ const e=require(`./a11y-control.cjs`),t=require(`./field-control.cjs`),n=require(`./press-control.cjs`);let r=require(`@vielzeug/stateit`);var i=e=>{let n=(0,r.signal)(``),i=(0,r.signal)(!!e.checked.value),a=(0,r.signal)(!!e.indeterminate?.value),o=t.createAssistiveState({error:e.error,helper:e.helper});(0,r.watch)(e.checked,e=>{i.value=!!e},{immediate:!0}),e.indeterminate&&(0,r.watch)(e.indeterminate,e=>{a.value=!!e},{immediate:!0});let{base:s,triggerValidation:c}=t.createFieldControlBase(e,{toFormValue:e=>e,value:(0,r.computed)(()=>a.value?null:i.value?e.value.value??``:null)});(0,r.watch)(e.value,e=>{n.value=String(e??``)},{immediate:!0});let l=t=>({checked:i.value,originalEvent:t,value:e.value.value??``}),u=t=>{if(!s.disabled.value){if(e.group){a.value=!1,e.group.toggle(e.value.value??``,t),e.onToggle?.(l(t));return}e.clearIndeterminateFirst&&a.value||(i.value=!i.value),a.value=!1,e.onToggle?.(l(t))}};return{...s,assistive:o,checked:i,indeterminate:a,toggle:u,triggerValidation:c,value:n}},a=t=>{let r=i(t),a=e.createA11yControl({checked:()=>t.role===`checkbox`&&r.indeterminate.value?`mixed`:r.checked.value?`true`:`false`,helperText:()=>r.assistive.value.errorText||r.assistive.value.helperText,helperTone:()=>r.assistive.value.errorText?`error`:`default`,invalid:()=>!!r.assistive.value.errorText,role:t.role}),o=n.createPressControl({disabled:()=>r.disabled.value,onPress:e=>{if(t.onPress){t.onPress(r,e);return}r.toggle(e)}});return{...r,handleClick:o.handleClick,handleKeydown:o.handleKeydown,helperId:a.helperId,labelId:a.labelId}};exports.createCheckableFieldControl=a;
2
2
  //# sourceMappingURL=checkable-control.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"checkable-control.cjs","names":[],"sources":["../../src/controls/checkable-control.ts"],"sourcesContent":["import { createA11yControl, type A11yControlHandle } from './a11y-control';\nimport { createCheckableStateControl, type CheckableStateHandle, type CheckableStateOptions } from './field-control';\nimport { createPressControl, type PressControl } from './press-control';\n\nexport type CheckableFieldControlOptions = CheckableStateOptions & {\n host: HTMLElement;\n onPress?: (control: CheckableStateHandle, originalEvent: Event) => void;\n role: 'checkbox' | 'radio' | 'switch';\n};\n\nexport type CheckableFieldControlHandle = {\n a11y: A11yControlHandle;\n control: CheckableStateHandle;\n press: PressControl;\n};\n\nexport const createCheckableFieldControl = (options: CheckableFieldControlOptions): CheckableFieldControlHandle => {\n const control = createCheckableStateControl(options);\n const a11y = createA11yControl(options.host, {\n checked: () => {\n if (options.role === 'checkbox' && control.indeterminate.value) return 'mixed';\n\n return control.checked.value ? 'true' : 'false';\n },\n helperText: () => control.assistive.value.text,\n helperTone: () => (control.assistive.value.isError ? 'error' : 'default'),\n invalid: () => control.assistive.value.isError,\n role: options.role,\n });\n const press = createPressControl({\n disabled: () => control.disabled.value,\n onPress: (originalEvent) => {\n if (options.onPress) {\n options.onPress(control, originalEvent);\n\n return;\n }\n\n control.toggle(originalEvent);\n },\n });\n\n return { a11y, control, press };\n};\n"],"mappings":"wGAgBA,IAAa,EAA+B,GAAuE,CACjH,IAAM,EAAU,EAAA,4BAA4B,EAAQ,CAyBpD,MAAO,CAAE,KAxBI,EAAA,kBAAkB,EAAQ,KAAM,CAC3C,YACM,EAAQ,OAAS,YAAc,EAAQ,cAAc,MAAc,QAEhE,EAAQ,QAAQ,MAAQ,OAAS,QAE1C,eAAkB,EAAQ,UAAU,MAAM,KAC1C,eAAmB,EAAQ,UAAU,MAAM,QAAU,QAAU,UAC/D,YAAe,EAAQ,UAAU,MAAM,QACvC,KAAM,EAAQ,KACf,CAAC,CAca,UAAS,MAbV,EAAA,mBAAmB,CAC/B,aAAgB,EAAQ,SAAS,MACjC,QAAU,GAAkB,CAC1B,GAAI,EAAQ,QAAS,CACnB,EAAQ,QAAQ,EAAS,EAAc,CAEvC,OAGF,EAAQ,OAAO,EAAc,EAEhC,CAAC,CAE6B"}
1
+ {"version":3,"file":"checkable-control.cjs","names":[],"sources":["../../src/controls/checkable-control.ts"],"sourcesContent":["import { computed, signal, watch } from '@vielzeug/stateit';\n\nimport { createA11yControl } from './a11y-control';\nimport {\n createAssistiveState,\n createFieldControlBase,\n type CheckableChangePayload,\n type CheckableStateHandle,\n type CheckableStateOptions,\n} from './field-control';\nimport { createPressControl } from './press-control';\n\nexport type CheckableFieldControlOptions = CheckableStateOptions & {\n onPress?: (control: CheckableStateHandle, originalEvent: Event) => void;\n role: 'checkbox' | 'radio' | 'switch';\n};\n\nexport type CheckableFieldControlHandle = CheckableStateHandle & {\n handleClick: (event: MouseEvent) => boolean;\n handleKeydown: (event: KeyboardEvent) => boolean;\n helperId: string;\n labelId: string;\n};\n\n/** @internal */\nexport const createCheckableState = (options: CheckableStateOptions): CheckableStateHandle => {\n const value = signal('');\n const checked = signal(Boolean(options.checked.value));\n const indeterminate = signal(Boolean(options.indeterminate?.value));\n const assistive = createAssistiveState({ error: options.error, helper: options.helper });\n\n watch(\n options.checked,\n (next) => {\n checked.value = Boolean(next);\n },\n { immediate: true },\n );\n\n if (options.indeterminate) {\n watch(\n options.indeterminate,\n (next) => {\n indeterminate.value = Boolean(next);\n },\n { immediate: true },\n );\n }\n\n const { base, triggerValidation } = createFieldControlBase(options, {\n toFormValue: (nextValue: string | null) => nextValue,\n value: computed(() => {\n if (indeterminate.value) return null;\n\n return checked.value ? (options.value.value ?? '') : null;\n }),\n });\n\n watch(\n options.value,\n (next) => {\n value.value = String(next ?? '');\n },\n { immediate: true },\n );\n\n const createPayload = (event: Event): CheckableChangePayload => ({\n checked: checked.value,\n originalEvent: event,\n value: options.value.value ?? '',\n });\n\n const toggle = (event: Event): void => {\n if (base.disabled.value) return;\n\n if (options.group) {\n indeterminate.value = false;\n options.group.toggle(options.value.value ?? '', event);\n options.onToggle?.(createPayload(event));\n\n return;\n }\n\n if (options.clearIndeterminateFirst && indeterminate.value) {\n indeterminate.value = false;\n } else {\n checked.value = !checked.value;\n indeterminate.value = false;\n }\n\n options.onToggle?.(createPayload(event));\n };\n\n return {\n ...base,\n assistive,\n checked,\n indeterminate,\n toggle,\n triggerValidation,\n value,\n };\n};\n\nexport const createCheckableFieldControl = (options: CheckableFieldControlOptions): CheckableFieldControlHandle => {\n const control = createCheckableState(options);\n const a11y = createA11yControl({\n checked: () =>\n options.role === 'checkbox' && control.indeterminate.value ? 'mixed' : control.checked.value ? 'true' : 'false',\n helperText: () => control.assistive.value.errorText || control.assistive.value.helperText,\n helperTone: () => (control.assistive.value.errorText ? 'error' : 'default'),\n invalid: () => Boolean(control.assistive.value.errorText),\n role: options.role,\n });\n\n const press = createPressControl({\n disabled: () => control.disabled.value,\n onPress: (originalEvent) => {\n if (options.onPress) {\n options.onPress(control, originalEvent);\n\n return;\n }\n\n control.toggle(originalEvent);\n },\n });\n\n return {\n ...control,\n handleClick: press.handleClick,\n handleKeydown: press.handleKeydown,\n helperId: a11y.helperId,\n labelId: a11y.labelId,\n };\n};\n"],"mappings":"2IAyBA,IAAa,EAAwB,GAAyD,CAC5F,IAAM,GAAA,EAAA,EAAA,QAAe,EAAE,EACjB,GAAA,EAAA,EAAA,QAAiB,EAAQ,EAAQ,QAAQ,KAAM,EAC/C,GAAA,EAAA,EAAA,QAAuB,EAAQ,EAAQ,eAAe,KAAM,EAC5D,EAAY,EAAA,qBAAqB,CAAE,MAAO,EAAQ,MAAO,OAAQ,EAAQ,MAAO,CAAC,GAEvF,EAAA,EAAA,OACE,EAAQ,QACP,GAAS,CACR,EAAQ,MAAQ,EAAQ,CAC1B,EACA,CAAE,UAAW,EAAK,CACpB,EAEI,EAAQ,gBACV,EAAA,EAAA,OACE,EAAQ,cACP,GAAS,CACR,EAAc,MAAQ,EAAQ,CAChC,EACA,CAAE,UAAW,EAAK,CACpB,EAGF,GAAM,CAAE,OAAM,qBAAsB,EAAA,uBAAuB,EAAS,CAClE,YAAc,GAA6B,EAC3C,OAAA,EAAA,EAAA,cACM,EAAc,MAAc,KAEzB,EAAQ,MAAS,EAAQ,MAAM,OAAS,GAAM,IACtD,CACH,CAAC,GAED,EAAA,EAAA,OACE,EAAQ,MACP,GAAS,CACR,EAAM,MAAQ,OAAO,GAAQ,EAAE,CACjC,EACA,CAAE,UAAW,EAAK,CACpB,EAEA,IAAM,EAAiB,IAA0C,CAC/D,QAAS,EAAQ,MACjB,cAAe,EACf,MAAO,EAAQ,MAAM,OAAS,EAChC,GAEM,EAAU,GAAuB,CACjC,MAAK,SAAS,MAElB,IAAI,EAAQ,MAAO,CACjB,EAAc,MAAQ,GACtB,EAAQ,MAAM,OAAO,EAAQ,MAAM,OAAS,GAAI,CAAK,EACrD,EAAQ,WAAW,EAAc,CAAK,CAAC,EAEvC,MACF,CAEI,EAAQ,yBAA2B,EAAc,QAGnD,EAAQ,MAAQ,CAAC,EAAQ,OAFzB,EAAc,MAAQ,GAMxB,EAAQ,WAAW,EAAc,CAAK,CAAC,CATvC,CAUF,EAEA,MAAO,CACL,GAAG,EACH,YACA,UACA,gBACA,SACA,oBACA,OACF,CACF,EAEa,EAA+B,GAAuE,CACjH,IAAM,EAAU,EAAqB,CAAO,EACtC,EAAO,EAAA,kBAAkB,CAC7B,YACE,EAAQ,OAAS,YAAc,EAAQ,cAAc,MAAQ,QAAU,EAAQ,QAAQ,MAAQ,OAAS,QAC1G,eAAkB,EAAQ,UAAU,MAAM,WAAa,EAAQ,UAAU,MAAM,WAC/E,eAAmB,EAAQ,UAAU,MAAM,UAAY,QAAU,UACjE,YAAe,EAAQ,EAAQ,UAAU,MAAM,UAC/C,KAAM,EAAQ,IAChB,CAAC,EAEK,EAAQ,EAAA,mBAAmB,CAC/B,aAAgB,EAAQ,SAAS,MACjC,QAAU,GAAkB,CAC1B,GAAI,EAAQ,QAAS,CACnB,EAAQ,QAAQ,EAAS,CAAa,EAEtC,MACF,CAEA,EAAQ,OAAO,CAAa,CAC9B,CACF,CAAC,EAED,MAAO,CACL,GAAG,EACH,YAAa,EAAM,YACnB,cAAe,EAAM,cACrB,SAAU,EAAK,SACf,QAAS,EAAK,OAChB,CACF"}
@@ -1,15 +1,15 @@
1
- import { type A11yControlHandle } from './a11y-control';
2
1
  import { type CheckableStateHandle, type CheckableStateOptions } from './field-control';
3
- import { type PressControl } from './press-control';
4
2
  export type CheckableFieldControlOptions = CheckableStateOptions & {
5
- host: HTMLElement;
6
3
  onPress?: (control: CheckableStateHandle, originalEvent: Event) => void;
7
4
  role: 'checkbox' | 'radio' | 'switch';
8
5
  };
9
- export type CheckableFieldControlHandle = {
10
- a11y: A11yControlHandle;
11
- control: CheckableStateHandle;
12
- press: PressControl;
6
+ export type CheckableFieldControlHandle = CheckableStateHandle & {
7
+ handleClick: (event: MouseEvent) => boolean;
8
+ handleKeydown: (event: KeyboardEvent) => boolean;
9
+ helperId: string;
10
+ labelId: string;
13
11
  };
12
+ /** @internal */
13
+ export declare const createCheckableState: (options: CheckableStateOptions) => CheckableStateHandle;
14
14
  export declare const createCheckableFieldControl: (options: CheckableFieldControlOptions) => CheckableFieldControlHandle;
15
15
  //# sourceMappingURL=checkable-control.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"checkable-control.d.ts","sourceRoot":"","sources":["../../src/controls/checkable-control.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAA+B,KAAK,oBAAoB,EAAE,KAAK,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACrH,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAExE,MAAM,MAAM,4BAA4B,GAAG,qBAAqB,GAAG;IACjE,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,KAAK,KAAK,IAAI,CAAC;IACxE,IAAI,EAAE,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,IAAI,EAAE,iBAAiB,CAAC;IACxB,OAAO,EAAE,oBAAoB,CAAC;IAC9B,KAAK,EAAE,YAAY,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,2BAA2B,GAAI,SAAS,4BAA4B,KAAG,2BA2BnF,CAAC"}
1
+ {"version":3,"file":"checkable-control.d.ts","sourceRoot":"","sources":["../../src/controls/checkable-control.ts"],"names":[],"mappings":"AAGA,OAAO,EAIL,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC3B,MAAM,iBAAiB,CAAC;AAGzB,MAAM,MAAM,4BAA4B,GAAG,qBAAqB,GAAG;IACjE,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,KAAK,KAAK,IAAI,CAAC;IACxE,IAAI,EAAE,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG,oBAAoB,GAAG;IAC/D,WAAW,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC;IAC5C,aAAa,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,gBAAgB;AAChB,eAAO,MAAM,oBAAoB,GAAI,SAAS,qBAAqB,KAAG,oBA6ErE,CAAC;AAEF,eAAO,MAAM,2BAA2B,GAAI,SAAS,4BAA4B,KAAG,2BA+BnF,CAAC"}
@@ -1,2 +1,2 @@
1
- import{createA11yControl as e}from"./a11y-control.js";import{createCheckableStateControl as t}from"./field-control.js";import{createPressControl as n}from"./press-control.js";var r=r=>{let i=t(r);return{a11y:e(r.host,{checked:()=>r.role===`checkbox`&&i.indeterminate.value?`mixed`:i.checked.value?`true`:`false`,helperText:()=>i.assistive.value.text,helperTone:()=>i.assistive.value.isError?`error`:`default`,invalid:()=>i.assistive.value.isError,role:r.role}),control:i,press:n({disabled:()=>i.disabled.value,onPress:e=>{if(r.onPress){r.onPress(i,e);return}i.toggle(e)}})}};export{r as createCheckableFieldControl};
1
+ import{createA11yControl as e}from"./a11y-control.js";import{createAssistiveState as t,createFieldControlBase as n}from"./field-control.js";import{createPressControl as r}from"./press-control.js";import{computed as i,signal as a,watch as o}from"@vielzeug/stateit";var s=e=>{let r=a(``),s=a(!!e.checked.value),c=a(!!e.indeterminate?.value),l=t({error:e.error,helper:e.helper});o(e.checked,e=>{s.value=!!e},{immediate:!0}),e.indeterminate&&o(e.indeterminate,e=>{c.value=!!e},{immediate:!0});let{base:u,triggerValidation:d}=n(e,{toFormValue:e=>e,value:i(()=>c.value?null:s.value?e.value.value??``:null)});o(e.value,e=>{r.value=String(e??``)},{immediate:!0});let f=t=>({checked:s.value,originalEvent:t,value:e.value.value??``}),p=t=>{if(!u.disabled.value){if(e.group){c.value=!1,e.group.toggle(e.value.value??``,t),e.onToggle?.(f(t));return}e.clearIndeterminateFirst&&c.value||(s.value=!s.value),c.value=!1,e.onToggle?.(f(t))}};return{...u,assistive:l,checked:s,indeterminate:c,toggle:p,triggerValidation:d,value:r}},c=t=>{let n=s(t),i=e({checked:()=>t.role===`checkbox`&&n.indeterminate.value?`mixed`:n.checked.value?`true`:`false`,helperText:()=>n.assistive.value.errorText||n.assistive.value.helperText,helperTone:()=>n.assistive.value.errorText?`error`:`default`,invalid:()=>!!n.assistive.value.errorText,role:t.role}),a=r({disabled:()=>n.disabled.value,onPress:e=>{if(t.onPress){t.onPress(n,e);return}n.toggle(e)}});return{...n,handleClick:a.handleClick,handleKeydown:a.handleKeydown,helperId:i.helperId,labelId:i.labelId}};export{c as createCheckableFieldControl};
2
2
  //# sourceMappingURL=checkable-control.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"checkable-control.js","names":[],"sources":["../../src/controls/checkable-control.ts"],"sourcesContent":["import { createA11yControl, type A11yControlHandle } from './a11y-control';\nimport { createCheckableStateControl, type CheckableStateHandle, type CheckableStateOptions } from './field-control';\nimport { createPressControl, type PressControl } from './press-control';\n\nexport type CheckableFieldControlOptions = CheckableStateOptions & {\n host: HTMLElement;\n onPress?: (control: CheckableStateHandle, originalEvent: Event) => void;\n role: 'checkbox' | 'radio' | 'switch';\n};\n\nexport type CheckableFieldControlHandle = {\n a11y: A11yControlHandle;\n control: CheckableStateHandle;\n press: PressControl;\n};\n\nexport const createCheckableFieldControl = (options: CheckableFieldControlOptions): CheckableFieldControlHandle => {\n const control = createCheckableStateControl(options);\n const a11y = createA11yControl(options.host, {\n checked: () => {\n if (options.role === 'checkbox' && control.indeterminate.value) return 'mixed';\n\n return control.checked.value ? 'true' : 'false';\n },\n helperText: () => control.assistive.value.text,\n helperTone: () => (control.assistive.value.isError ? 'error' : 'default'),\n invalid: () => control.assistive.value.isError,\n role: options.role,\n });\n const press = createPressControl({\n disabled: () => control.disabled.value,\n onPress: (originalEvent) => {\n if (options.onPress) {\n options.onPress(control, originalEvent);\n\n return;\n }\n\n control.toggle(originalEvent);\n },\n });\n\n return { a11y, control, press };\n};\n"],"mappings":"+KAgBA,IAAa,EAA+B,GAAuE,CACjH,IAAM,EAAU,EAA4B,EAAQ,CAyBpD,MAAO,CAAE,KAxBI,EAAkB,EAAQ,KAAM,CAC3C,YACM,EAAQ,OAAS,YAAc,EAAQ,cAAc,MAAc,QAEhE,EAAQ,QAAQ,MAAQ,OAAS,QAE1C,eAAkB,EAAQ,UAAU,MAAM,KAC1C,eAAmB,EAAQ,UAAU,MAAM,QAAU,QAAU,UAC/D,YAAe,EAAQ,UAAU,MAAM,QACvC,KAAM,EAAQ,KACf,CAAC,CAca,UAAS,MAbV,EAAmB,CAC/B,aAAgB,EAAQ,SAAS,MACjC,QAAU,GAAkB,CAC1B,GAAI,EAAQ,QAAS,CACnB,EAAQ,QAAQ,EAAS,EAAc,CAEvC,OAGF,EAAQ,OAAO,EAAc,EAEhC,CAAC,CAE6B"}
1
+ {"version":3,"file":"checkable-control.js","names":[],"sources":["../../src/controls/checkable-control.ts"],"sourcesContent":["import { computed, signal, watch } from '@vielzeug/stateit';\n\nimport { createA11yControl } from './a11y-control';\nimport {\n createAssistiveState,\n createFieldControlBase,\n type CheckableChangePayload,\n type CheckableStateHandle,\n type CheckableStateOptions,\n} from './field-control';\nimport { createPressControl } from './press-control';\n\nexport type CheckableFieldControlOptions = CheckableStateOptions & {\n onPress?: (control: CheckableStateHandle, originalEvent: Event) => void;\n role: 'checkbox' | 'radio' | 'switch';\n};\n\nexport type CheckableFieldControlHandle = CheckableStateHandle & {\n handleClick: (event: MouseEvent) => boolean;\n handleKeydown: (event: KeyboardEvent) => boolean;\n helperId: string;\n labelId: string;\n};\n\n/** @internal */\nexport const createCheckableState = (options: CheckableStateOptions): CheckableStateHandle => {\n const value = signal('');\n const checked = signal(Boolean(options.checked.value));\n const indeterminate = signal(Boolean(options.indeterminate?.value));\n const assistive = createAssistiveState({ error: options.error, helper: options.helper });\n\n watch(\n options.checked,\n (next) => {\n checked.value = Boolean(next);\n },\n { immediate: true },\n );\n\n if (options.indeterminate) {\n watch(\n options.indeterminate,\n (next) => {\n indeterminate.value = Boolean(next);\n },\n { immediate: true },\n );\n }\n\n const { base, triggerValidation } = createFieldControlBase(options, {\n toFormValue: (nextValue: string | null) => nextValue,\n value: computed(() => {\n if (indeterminate.value) return null;\n\n return checked.value ? (options.value.value ?? '') : null;\n }),\n });\n\n watch(\n options.value,\n (next) => {\n value.value = String(next ?? '');\n },\n { immediate: true },\n );\n\n const createPayload = (event: Event): CheckableChangePayload => ({\n checked: checked.value,\n originalEvent: event,\n value: options.value.value ?? '',\n });\n\n const toggle = (event: Event): void => {\n if (base.disabled.value) return;\n\n if (options.group) {\n indeterminate.value = false;\n options.group.toggle(options.value.value ?? '', event);\n options.onToggle?.(createPayload(event));\n\n return;\n }\n\n if (options.clearIndeterminateFirst && indeterminate.value) {\n indeterminate.value = false;\n } else {\n checked.value = !checked.value;\n indeterminate.value = false;\n }\n\n options.onToggle?.(createPayload(event));\n };\n\n return {\n ...base,\n assistive,\n checked,\n indeterminate,\n toggle,\n triggerValidation,\n value,\n };\n};\n\nexport const createCheckableFieldControl = (options: CheckableFieldControlOptions): CheckableFieldControlHandle => {\n const control = createCheckableState(options);\n const a11y = createA11yControl({\n checked: () =>\n options.role === 'checkbox' && control.indeterminate.value ? 'mixed' : control.checked.value ? 'true' : 'false',\n helperText: () => control.assistive.value.errorText || control.assistive.value.helperText,\n helperTone: () => (control.assistive.value.errorText ? 'error' : 'default'),\n invalid: () => Boolean(control.assistive.value.errorText),\n role: options.role,\n });\n\n const press = createPressControl({\n disabled: () => control.disabled.value,\n onPress: (originalEvent) => {\n if (options.onPress) {\n options.onPress(control, originalEvent);\n\n return;\n }\n\n control.toggle(originalEvent);\n },\n });\n\n return {\n ...control,\n handleClick: press.handleClick,\n handleKeydown: press.handleKeydown,\n helperId: a11y.helperId,\n labelId: a11y.labelId,\n };\n};\n"],"mappings":"wQAyBA,IAAa,EAAwB,GAAyD,CAC5F,IAAM,EAAQ,EAAO,EAAE,EACjB,EAAU,EAAO,EAAQ,EAAQ,QAAQ,KAAM,EAC/C,EAAgB,EAAO,EAAQ,EAAQ,eAAe,KAAM,EAC5D,EAAY,EAAqB,CAAE,MAAO,EAAQ,MAAO,OAAQ,EAAQ,MAAO,CAAC,EAEvF,EACE,EAAQ,QACP,GAAS,CACR,EAAQ,MAAQ,EAAQ,CAC1B,EACA,CAAE,UAAW,EAAK,CACpB,EAEI,EAAQ,eACV,EACE,EAAQ,cACP,GAAS,CACR,EAAc,MAAQ,EAAQ,CAChC,EACA,CAAE,UAAW,EAAK,CACpB,EAGF,GAAM,CAAE,OAAM,qBAAsB,EAAuB,EAAS,CAClE,YAAc,GAA6B,EAC3C,MAAO,MACD,EAAc,MAAc,KAEzB,EAAQ,MAAS,EAAQ,MAAM,OAAS,GAAM,IACtD,CACH,CAAC,EAED,EACE,EAAQ,MACP,GAAS,CACR,EAAM,MAAQ,OAAO,GAAQ,EAAE,CACjC,EACA,CAAE,UAAW,EAAK,CACpB,EAEA,IAAM,EAAiB,IAA0C,CAC/D,QAAS,EAAQ,MACjB,cAAe,EACf,MAAO,EAAQ,MAAM,OAAS,EAChC,GAEM,EAAU,GAAuB,CACjC,MAAK,SAAS,MAElB,IAAI,EAAQ,MAAO,CACjB,EAAc,MAAQ,GACtB,EAAQ,MAAM,OAAO,EAAQ,MAAM,OAAS,GAAI,CAAK,EACrD,EAAQ,WAAW,EAAc,CAAK,CAAC,EAEvC,MACF,CAEI,EAAQ,yBAA2B,EAAc,QAGnD,EAAQ,MAAQ,CAAC,EAAQ,OAFzB,EAAc,MAAQ,GAMxB,EAAQ,WAAW,EAAc,CAAK,CAAC,CATvC,CAUF,EAEA,MAAO,CACL,GAAG,EACH,YACA,UACA,gBACA,SACA,oBACA,OACF,CACF,EAEa,EAA+B,GAAuE,CACjH,IAAM,EAAU,EAAqB,CAAO,EACtC,EAAO,EAAkB,CAC7B,YACE,EAAQ,OAAS,YAAc,EAAQ,cAAc,MAAQ,QAAU,EAAQ,QAAQ,MAAQ,OAAS,QAC1G,eAAkB,EAAQ,UAAU,MAAM,WAAa,EAAQ,UAAU,MAAM,WAC/E,eAAmB,EAAQ,UAAU,MAAM,UAAY,QAAU,UACjE,YAAe,EAAQ,EAAQ,UAAU,MAAM,UAC/C,KAAM,EAAQ,IAChB,CAAC,EAEK,EAAQ,EAAmB,CAC/B,aAAgB,EAAQ,SAAS,MACjC,QAAU,GAAkB,CAC1B,GAAI,EAAQ,QAAS,CACnB,EAAQ,QAAQ,EAAS,CAAa,EAEtC,MACF,CAEA,EAAQ,OAAO,CAAa,CAC9B,CACF,CAAC,EAED,MAAO,CACL,GAAG,EACH,YAAa,EAAM,YACnB,cAAe,EAAM,cACrB,SAAU,EAAK,SACf,QAAS,EAAK,OAChB,CACF"}
@@ -0,0 +1,2 @@
1
+ const e=require(`./field-control.cjs`);let t=require(`@vielzeug/stateit`);var n=e=>e?e.split(`,`).map(e=>e.trim()).filter(Boolean):[],r=r=>{let i=(0,t.signal)([]),a=(0,t.computed)(()=>!!r.multiple?.value),o=(0,t.computed)(()=>a.value?i.value.join(`,`):i.value[0]??``),s=e=>{let t=a.value?e:e.slice(0,1);return[...new Set(t.map(e=>String(e??``)).filter(Boolean))]},c=e=>{i.value=s(e)},l=()=>{c([])},u=e=>{i.value=i.value.filter(t=>t!==e)},d=e=>{if(a.value){if(i.value.includes(e))return;c([...i.value,e]);return}c([e])},f=e=>{if(a.value){if(i.value.includes(e)){u(e);return}c([...i.value,e]);return}c([e])},p=e=>{let t=n(typeof e==`string`?e:String(e??``));t.length===i.value.length&&t.every((e,t)=>e===i.value[t])||c(t)},{base:m,triggerValidation:h}=e.createFieldControlBase(r,{value:o}),g=e.createAssistiveState({error:r.error,helper:r.helper});return(0,t.watch)(r.value,e=>{p(e)},{immediate:!0}),r.multiple&&(0,t.watch)(r.multiple,()=>p(r.value.value)),{...m,assistive:g,clear:l,formValue:o,removeValue:u,selectedValues:i,selectValue:d,setValues:c,toggleValue:f,triggerValidation:h}};exports.createChoiceField=r;
2
+ //# sourceMappingURL=choice-field-control.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"choice-field-control.cjs","names":[],"sources":["../../src/controls/choice-field-control.ts"],"sourcesContent":["import { computed, signal, watch } from '@vielzeug/stateit';\n\nimport {\n createAssistiveState,\n createFieldControlBase,\n type ChoiceFieldHandle,\n type ChoiceFieldOptions,\n} from './field-control';\n\nconst parseChoiceFieldValues = (value: string | undefined): string[] => {\n if (!value) return [];\n\n return value\n .split(',')\n .map((entry) => entry.trim())\n .filter(Boolean);\n};\n\nexport const createChoiceField = (options: ChoiceFieldOptions): ChoiceFieldHandle => {\n const selectedValues = signal<string[]>([]);\n const isMultiple = computed(() => Boolean(options.multiple?.value));\n const formValue = computed(() =>\n isMultiple.value ? selectedValues.value.join(',') : (selectedValues.value[0] ?? ''),\n );\n\n const normalizeSelectedValues = (values: string[]): string[] => {\n const normalized = isMultiple.value ? values : values.slice(0, 1);\n\n return [...new Set(normalized.map((entry) => String(entry ?? '')).filter(Boolean))];\n };\n\n const setValues = (values: string[]): void => {\n selectedValues.value = normalizeSelectedValues(values);\n };\n\n const clear = (): void => {\n setValues([]);\n };\n\n const removeValue = (value: string): void => {\n selectedValues.value = selectedValues.value.filter((current) => current !== value);\n };\n\n const selectValue = (value: string): void => {\n if (isMultiple.value) {\n if (selectedValues.value.includes(value)) return;\n\n setValues([...selectedValues.value, value]);\n\n return;\n }\n\n setValues([value]);\n };\n\n const toggleValue = (value: string): void => {\n if (isMultiple.value) {\n if (selectedValues.value.includes(value)) {\n removeValue(value);\n\n return;\n }\n\n setValues([...selectedValues.value, value]);\n\n return;\n }\n\n setValues([value]);\n };\n\n const syncControlledValue = (nextValue: unknown): void => {\n const values = parseChoiceFieldValues(typeof nextValue === 'string' ? nextValue : String(nextValue ?? ''));\n\n if (\n values.length === selectedValues.value.length &&\n values.every((value, index) => value === selectedValues.value[index])\n ) {\n return;\n }\n\n setValues(values);\n };\n\n const { base, triggerValidation } = createFieldControlBase(options, { value: formValue });\n\n const assistive = createAssistiveState({\n error: options.error,\n helper: options.helper,\n });\n\n watch(\n options.value,\n (next) => {\n syncControlledValue(next);\n },\n { immediate: true },\n );\n\n if (options.multiple) {\n watch(options.multiple, () => syncControlledValue(options.value.value));\n }\n\n return {\n ...base,\n assistive,\n clear,\n formValue,\n removeValue,\n selectedValues,\n selectValue,\n setValues,\n toggleValue,\n triggerValidation,\n };\n};\n"],"mappings":"0EASA,IAAM,EAA0B,GACzB,EAEE,EACJ,MAAM,GAAG,EACT,IAAK,GAAU,EAAM,KAAK,CAAC,EAC3B,OAAO,OAAO,EALE,CAAC,EAQT,EAAqB,GAAmD,CACnF,IAAM,GAAA,EAAA,EAAA,QAAkC,CAAC,CAAC,EACpC,GAAA,EAAA,EAAA,cAA4B,EAAQ,EAAQ,UAAU,KAAM,EAC5D,GAAA,EAAA,EAAA,cACJ,EAAW,MAAQ,EAAe,MAAM,KAAK,GAAG,EAAK,EAAe,MAAM,IAAM,EAClF,EAEM,EAA2B,GAA+B,CAC9D,IAAM,EAAa,EAAW,MAAQ,EAAS,EAAO,MAAM,EAAG,CAAC,EAEhE,MAAO,CAAC,GAAG,IAAI,IAAI,EAAW,IAAK,GAAU,OAAO,GAAS,EAAE,CAAC,EAAE,OAAO,OAAO,CAAC,CAAC,CACpF,EAEM,EAAa,GAA2B,CAC5C,EAAe,MAAQ,EAAwB,CAAM,CACvD,EAEM,MAAoB,CACxB,EAAU,CAAC,CAAC,CACd,EAEM,EAAe,GAAwB,CAC3C,EAAe,MAAQ,EAAe,MAAM,OAAQ,GAAY,IAAY,CAAK,CACnF,EAEM,EAAe,GAAwB,CAC3C,GAAI,EAAW,MAAO,CACpB,GAAI,EAAe,MAAM,SAAS,CAAK,EAAG,OAE1C,EAAU,CAAC,GAAG,EAAe,MAAO,CAAK,CAAC,EAE1C,MACF,CAEA,EAAU,CAAC,CAAK,CAAC,CACnB,EAEM,EAAe,GAAwB,CAC3C,GAAI,EAAW,MAAO,CACpB,GAAI,EAAe,MAAM,SAAS,CAAK,EAAG,CACxC,EAAY,CAAK,EAEjB,MACF,CAEA,EAAU,CAAC,GAAG,EAAe,MAAO,CAAK,CAAC,EAE1C,MACF,CAEA,EAAU,CAAC,CAAK,CAAC,CACnB,EAEM,EAAuB,GAA6B,CACxD,IAAM,EAAS,EAAuB,OAAO,GAAc,SAAW,EAAY,OAAO,GAAa,EAAE,CAAC,EAGvG,EAAO,SAAW,EAAe,MAAM,QACvC,EAAO,OAAO,EAAO,IAAU,IAAU,EAAe,MAAM,EAAM,GAKtE,EAAU,CAAM,CAClB,EAEM,CAAE,OAAM,qBAAsB,EAAA,uBAAuB,EAAS,CAAE,MAAO,CAAU,CAAC,EAElF,EAAY,EAAA,qBAAqB,CACrC,MAAO,EAAQ,MACf,OAAQ,EAAQ,MAClB,CAAC,EAcD,OAZA,EAAA,EAAA,OACE,EAAQ,MACP,GAAS,CACR,EAAoB,CAAI,CAC1B,EACA,CAAE,UAAW,EAAK,CACpB,EAEI,EAAQ,WACV,EAAA,EAAA,OAAM,EAAQ,aAAgB,EAAoB,EAAQ,MAAM,KAAK,CAAC,EAGjE,CACL,GAAG,EACH,YACA,QACA,YACA,cACA,iBACA,cACA,YACA,cACA,mBACF,CACF"}
@@ -0,0 +1,3 @@
1
+ import { type ChoiceFieldHandle, type ChoiceFieldOptions } from './field-control';
2
+ export declare const createChoiceField: (options: ChoiceFieldOptions) => ChoiceFieldHandle;
3
+ //# sourceMappingURL=choice-field-control.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"choice-field-control.d.ts","sourceRoot":"","sources":["../../src/controls/choice-field-control.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACxB,MAAM,iBAAiB,CAAC;AAWzB,eAAO,MAAM,iBAAiB,GAAI,SAAS,kBAAkB,KAAG,iBAiG/D,CAAC"}
@@ -0,0 +1,2 @@
1
+ import{createAssistiveState as e,createFieldControlBase as t}from"./field-control.js";import{computed as n,signal as r,watch as i}from"@vielzeug/stateit";var a=e=>e?e.split(`,`).map(e=>e.trim()).filter(Boolean):[],o=o=>{let s=r([]),c=n(()=>!!o.multiple?.value),l=n(()=>c.value?s.value.join(`,`):s.value[0]??``),u=e=>{let t=c.value?e:e.slice(0,1);return[...new Set(t.map(e=>String(e??``)).filter(Boolean))]},d=e=>{s.value=u(e)},f=()=>{d([])},p=e=>{s.value=s.value.filter(t=>t!==e)},m=e=>{if(c.value){if(s.value.includes(e))return;d([...s.value,e]);return}d([e])},h=e=>{if(c.value){if(s.value.includes(e)){p(e);return}d([...s.value,e]);return}d([e])},g=e=>{let t=a(typeof e==`string`?e:String(e??``));t.length===s.value.length&&t.every((e,t)=>e===s.value[t])||d(t)},{base:_,triggerValidation:v}=t(o,{value:l}),y=e({error:o.error,helper:o.helper});return i(o.value,e=>{g(e)},{immediate:!0}),o.multiple&&i(o.multiple,()=>g(o.value.value)),{..._,assistive:y,clear:f,formValue:l,removeValue:p,selectedValues:s,selectValue:m,setValues:d,toggleValue:h,triggerValidation:v}};export{o as createChoiceField};
2
+ //# sourceMappingURL=choice-field-control.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"choice-field-control.js","names":[],"sources":["../../src/controls/choice-field-control.ts"],"sourcesContent":["import { computed, signal, watch } from '@vielzeug/stateit';\n\nimport {\n createAssistiveState,\n createFieldControlBase,\n type ChoiceFieldHandle,\n type ChoiceFieldOptions,\n} from './field-control';\n\nconst parseChoiceFieldValues = (value: string | undefined): string[] => {\n if (!value) return [];\n\n return value\n .split(',')\n .map((entry) => entry.trim())\n .filter(Boolean);\n};\n\nexport const createChoiceField = (options: ChoiceFieldOptions): ChoiceFieldHandle => {\n const selectedValues = signal<string[]>([]);\n const isMultiple = computed(() => Boolean(options.multiple?.value));\n const formValue = computed(() =>\n isMultiple.value ? selectedValues.value.join(',') : (selectedValues.value[0] ?? ''),\n );\n\n const normalizeSelectedValues = (values: string[]): string[] => {\n const normalized = isMultiple.value ? values : values.slice(0, 1);\n\n return [...new Set(normalized.map((entry) => String(entry ?? '')).filter(Boolean))];\n };\n\n const setValues = (values: string[]): void => {\n selectedValues.value = normalizeSelectedValues(values);\n };\n\n const clear = (): void => {\n setValues([]);\n };\n\n const removeValue = (value: string): void => {\n selectedValues.value = selectedValues.value.filter((current) => current !== value);\n };\n\n const selectValue = (value: string): void => {\n if (isMultiple.value) {\n if (selectedValues.value.includes(value)) return;\n\n setValues([...selectedValues.value, value]);\n\n return;\n }\n\n setValues([value]);\n };\n\n const toggleValue = (value: string): void => {\n if (isMultiple.value) {\n if (selectedValues.value.includes(value)) {\n removeValue(value);\n\n return;\n }\n\n setValues([...selectedValues.value, value]);\n\n return;\n }\n\n setValues([value]);\n };\n\n const syncControlledValue = (nextValue: unknown): void => {\n const values = parseChoiceFieldValues(typeof nextValue === 'string' ? nextValue : String(nextValue ?? ''));\n\n if (\n values.length === selectedValues.value.length &&\n values.every((value, index) => value === selectedValues.value[index])\n ) {\n return;\n }\n\n setValues(values);\n };\n\n const { base, triggerValidation } = createFieldControlBase(options, { value: formValue });\n\n const assistive = createAssistiveState({\n error: options.error,\n helper: options.helper,\n });\n\n watch(\n options.value,\n (next) => {\n syncControlledValue(next);\n },\n { immediate: true },\n );\n\n if (options.multiple) {\n watch(options.multiple, () => syncControlledValue(options.value.value));\n }\n\n return {\n ...base,\n assistive,\n clear,\n formValue,\n removeValue,\n selectedValues,\n selectValue,\n setValues,\n toggleValue,\n triggerValidation,\n };\n};\n"],"mappings":"0JASA,IAAM,EAA0B,GACzB,EAEE,EACJ,MAAM,GAAG,EACT,IAAK,GAAU,EAAM,KAAK,CAAC,EAC3B,OAAO,OAAO,EALE,CAAC,EAQT,EAAqB,GAAmD,CACnF,IAAM,EAAiB,EAAiB,CAAC,CAAC,EACpC,EAAa,MAAe,EAAQ,EAAQ,UAAU,KAAM,EAC5D,EAAY,MAChB,EAAW,MAAQ,EAAe,MAAM,KAAK,GAAG,EAAK,EAAe,MAAM,IAAM,EAClF,EAEM,EAA2B,GAA+B,CAC9D,IAAM,EAAa,EAAW,MAAQ,EAAS,EAAO,MAAM,EAAG,CAAC,EAEhE,MAAO,CAAC,GAAG,IAAI,IAAI,EAAW,IAAK,GAAU,OAAO,GAAS,EAAE,CAAC,EAAE,OAAO,OAAO,CAAC,CAAC,CACpF,EAEM,EAAa,GAA2B,CAC5C,EAAe,MAAQ,EAAwB,CAAM,CACvD,EAEM,MAAoB,CACxB,EAAU,CAAC,CAAC,CACd,EAEM,EAAe,GAAwB,CAC3C,EAAe,MAAQ,EAAe,MAAM,OAAQ,GAAY,IAAY,CAAK,CACnF,EAEM,EAAe,GAAwB,CAC3C,GAAI,EAAW,MAAO,CACpB,GAAI,EAAe,MAAM,SAAS,CAAK,EAAG,OAE1C,EAAU,CAAC,GAAG,EAAe,MAAO,CAAK,CAAC,EAE1C,MACF,CAEA,EAAU,CAAC,CAAK,CAAC,CACnB,EAEM,EAAe,GAAwB,CAC3C,GAAI,EAAW,MAAO,CACpB,GAAI,EAAe,MAAM,SAAS,CAAK,EAAG,CACxC,EAAY,CAAK,EAEjB,MACF,CAEA,EAAU,CAAC,GAAG,EAAe,MAAO,CAAK,CAAC,EAE1C,MACF,CAEA,EAAU,CAAC,CAAK,CAAC,CACnB,EAEM,EAAuB,GAA6B,CACxD,IAAM,EAAS,EAAuB,OAAO,GAAc,SAAW,EAAY,OAAO,GAAa,EAAE,CAAC,EAGvG,EAAO,SAAW,EAAe,MAAM,QACvC,EAAO,OAAO,EAAO,IAAU,IAAU,EAAe,MAAM,EAAM,GAKtE,EAAU,CAAM,CAClB,EAEM,CAAE,OAAM,qBAAsB,EAAuB,EAAS,CAAE,MAAO,CAAU,CAAC,EAElF,EAAY,EAAqB,CACrC,MAAO,EAAQ,MACf,OAAQ,EAAQ,MAClB,CAAC,EAcD,OAZA,EACE,EAAQ,MACP,GAAS,CACR,EAAoB,CAAI,CAC1B,EACA,CAAE,UAAW,EAAK,CACpB,EAEI,EAAQ,UACV,EAAM,EAAQ,aAAgB,EAAoB,EAAQ,MAAM,KAAK,CAAC,EAGjE,CACL,GAAG,EACH,YACA,QACA,YACA,cACA,iBACA,cACA,YACA,cACA,mBACF,CACF"}
@@ -1,2 +1,2 @@
1
- const e=require(`../runtime-lifecycle.cjs`),t=require(`../internal.cjs`),n=require(`../directives/spread.cjs`),r=require(`../form.cjs`),i=require(`./internal/control-state.cjs`);let a=require(`@vielzeug/stateit`);var o=(e,n)=>{let r=`${e}-${n&&n.trim()?n.trim():t.createId().replace(/^cft-/,``)}`,i=`label-${r}`;return{errorId:`error-${r}`,fieldId:r,helperId:`helper-${r}`,labelInsetId:i,labelOutsideId:`${i}-outside`}},s=n=>{let r=i.createControlState(n),a=o(n.prefix,n.name?.value),s=t.ref(),c=t.ref();return e.effect(()=>{let e=n.labelPlacement?.value??`inset`,t=n.label?.value??``;s.value&&(s.value.textContent=t,s.value.hidden=!t||e!==`inset`),c.value&&(c.value.textContent=t,c.value.hidden=!t||e!==`outside`)}),{disabled:r.disabled,errorId:a.errorId,fieldId:a.fieldId,helperId:a.helperId,labelInsetId:a.labelInsetId,labelInsetRef:s,labelOutsideId:a.labelOutsideId,labelOutsideRef:c,triggerValidation:(e,t)=>r.triggerValidation(e,t),validateOn:r.validateOn}},c=e=>({disabled:(0,a.computed)(()=>!!e.disabled?.value||!!e.context?.disabled?.value),validateOn:e.validateOn??e.context?.validateOn}),l=e=>(0,a.computed)(()=>{let t=e.value?.value??``,n=e.error?.value??``,r=e.helper?.value??``,i=!!n,a=!!r,o=n||r||``,s=e.maxLength?.value,c=Number(s),l=Number.isFinite(c)&&c>0?c:null,u=l!==null,d=u?`${t.length} / ${l}`:``,f=u?t.length/l:0;return{counterAtLimit:u?f>=1:!1,counterNearLimit:u?f>=.9&&f<1:!1,counterText:d,errorText:n,hasCounter:u,hasError:i,hasHelper:a,helperText:r,hidden:!o,isError:i,showHelper:!i&&a,text:o}}),u=e=>{if(e!==void 0)return(0,a.isSignal)(e)?e.value:typeof e==`function`?e():e},d=e=>()=>{let t=u(e);if(!(t==null||t===``))return String(t)},f=e=>()=>{let t=u(e);if(!(t==null||Number.isNaN(Number(t))||Number(t)<=0))return Number(t)},p=t=>{let i=(0,a.signal)(``),o=c(t),u=s({...t,...o});e.watch(t.value,e=>{i.value=String(e??``)},{immediate:!0});let p=r.defineField({disabled:u.disabled,value:i},{onReset:()=>{i.value=``,t.onReset?.()}}),h=l({error:t.error,helper:t.helper,maxLength:t.maxLength,value:i}),g=e=>{e?.preventDefault?.(),i.value=``,t.onInput?.(e??new Event(`input`),``),t.onChange?.(e??new Event(`change`),``),u.triggerValidation(p,`change`),t.elementRef?.value?.focus()};return t.elementRef&&e.onElement(t.elementRef,e=>{m({element:e,onBlur:t.onBlur,onChange:t.onChange,onInput:(e,n)=>{t.onInputExtra?.(e),t.onInput?.(e,n)},triggerValidation:e=>u.triggerValidation(p,e)})}),{assistive:h,attrs:n.spread({"?required":t.required,".disabled":t.disabled,".readOnly":t.readOnly,".type":t.type,".value":i,autocomplete:d(t.autocomplete),inputmode:d(t.inputmode),maxlength:f(t.maxLength),minlength:f(t.minLength),name:d(t.name),pattern:d(t.pattern),placeholder:d(t.placeholder),rows:f(t.rows)}),...u,clear:g,field:p,triggerValidation:e=>u.triggerValidation(p,e),value:i}},m=t=>{let{element:n,onBlur:r,onChange:i,onInput:a,triggerValidation:o}=t;a&&e.handle(n,`input`,e=>{a(e,n.value)}),e.handle(n,`change`,e=>{i?.(e,n.value),o?.(`change`)}),e.handle(n,`blur`,e=>{r?.(e),o?.(`blur`)})},h=e=>e?e.split(`,`).map(e=>e.trim()).filter(Boolean):[],g=t=>{let n=s({...c(t),label:t.label,labelPlacement:t.labelPlacement,name:t.name,prefix:t.prefix}),i=(0,a.signal)([]),o=(0,a.computed)(()=>!!t.multiple?.value),u=(0,a.computed)(()=>i.value.map(e=>t.getValue(e))),d=(0,a.computed)(()=>o.value?u.value.join(`,`):u.value[0]??``),f=e=>{let n=o.value?e:e.slice(0,1),r=[],i=new Set;for(let e of n){let n=t.getValue(e);i.has(n)||(i.add(n),r.push(e))}return r},p=e=>{i.value=f(e)},m=()=>{p([])},g=e=>{i.value=i.value.filter(n=>t.getValue(n)!==e)},_=e=>{if(o.value){let n=t.getValue(e);if(i.value.some(e=>t.getValue(e)===n))return;p([...i.value,e]);return}p([e])},v=e=>{if(o.value){let n=t.getValue(e);if(i.value.some(e=>t.getValue(e)===n)){g(n);return}p([...i.value,e]);return}p([e])},y=e=>{p(h(typeof e==`string`?e:String(e??``)).map(e=>t.mapControlledValue(e)))},b=r.defineField({disabled:n.disabled,value:d},{onReset:()=>{m(),t.onReset?.()}}),x=l({error:t.error,helper:t.helper});return e.watch(t.value,e=>{y(e)},{immediate:!0}),t.multiple&&e.watch(t.multiple,()=>y(t.value.value)),{...n,assistive:x,clear:m,field:b,formValue:d,isMultiple:o,isSelected:e=>i.value.some(n=>t.getValue(n)===e),removeValue:g,replaceSelectedItems:p,selectedItems:i,selectedValues:u,selectItem:_,toggleItem:v,triggerValidation:e=>n.triggerValidation(b,e)}},_=t=>{let n=(0,a.signal)(``),i=s(t),o=(0,a.signal)(!!t.checked.value),c=(0,a.signal)(!!t.indeterminate?.value),u=l({error:t.error,helper:t.helper});e.watch(t.checked,e=>{o.value=!!e},{immediate:!0}),t.indeterminate&&e.watch(t.indeterminate,e=>{c.value=!!e},{immediate:!0});let d=r.defineField({disabled:i.disabled,toFormValue:e=>e,value:(0,a.computed)(()=>o.value?t.value.value??``:null)},{onReset:()=>{o.value=!!t.checked.value,c.value=!!t.indeterminate?.value,t.onReset?.()}});e.watch(t.value,e=>{n.value=String(e??``)},{immediate:!0});let f=e=>({checked:o.value,fieldValue:t.value.value??``,originalEvent:e}),p=e=>{if(!i.disabled.value){if(t.group){c.value=!1,t.group.toggle(t.value.value??``,e),t.onToggle?.(f(e));return}t.clearIndeterminateFirst&&c.value||(o.value=!o.value),c.value=!1,t.onToggle?.(f(e))}};return{...i,assistive:u,checked:o,field:d,indeterminate:c,toggle:p,triggerValidation:e=>i.triggerValidation(d,e),value:n}};exports.createCheckableStateControl=_,exports.createChoiceFieldControl=g,exports.createTextFieldControl=p,exports.mountTextFieldLifecycle=m;
1
+ const e=require(`../runtime.cjs`),t=require(`../internal.cjs`),n=require(`../form.cjs`),r=require(`./internal/control-state.cjs`);let i=require(`@vielzeug/stateit`);var a=(e,n)=>{let r=`${e}-${n&&n.trim()?n.trim():t.createId().replace(/^cft-/,``)}`,i=`label-${r}`;return{errorId:`error-${r}`,fieldId:r,helperId:`helper-${r}`,labelInsetId:i,labelOutsideId:`${i}-outside`}},o=(e,t)=>{let i=r.createControlState(e),o=a(e.prefix,e.name?.value),s={disabled:i.disabled,errorId:o.errorId,fieldId:o.fieldId,helperId:o.helperId,labelInsetId:o.labelInsetId,labelOutsideId:o.labelOutsideId},c=n.defineField({...t,disabled:t.disabled??s.disabled});return{base:s,triggerValidation:e=>i.triggerValidation(c,e)}},s=e=>(0,i.computed)(()=>{let t=e.value?.value??``,n=e.error?.value??``,r=e.helper?.value??``,i=e.maxLength?.value,a=Number(i),o=Number.isFinite(a)&&a>0?a:null,s=o!==null,c=s?`${t.length} / ${o}`:``,l=s?t.length/o:0;return{counterAtLimit:s?l>=1:!1,counterNearLimit:s?l>=.9&&l<1:!1,counterText:c,errorText:n,hasCounter:s,helperText:r}}),c=t=>{let{element:n,onBlur:r,onChange:i,onInput:a,triggerValidation:o}=t,s=[];return a&&s.push(e.listen(n,`input`,e=>{e.stopPropagation(),a(e,n.value)})),s.push(e.listen(n,`change`,e=>{e.stopPropagation(),i?.(e,n.value),o?.(`change`)})),s.push(e.listen(n,`blur`,e=>{r?.(e),o?.(`blur`)})),()=>{for(let e of s)e()}};exports.createAssistiveState=s,exports.createFieldControlBase=o,exports.mountTextFieldLifecycle=c;
2
2
  //# sourceMappingURL=field-control.cjs.map