sygnal 5.4.0 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (316) hide show
  1. package/CHANGELOG.md +646 -0
  2. package/README.md +24 -9
  3. package/dist/astro/client.cjs.js +16 -9
  4. package/dist/astro/client.cjs.js.map +1 -1
  5. package/dist/astro/client.mjs +16 -9
  6. package/dist/astro/client.mjs.map +1 -1
  7. package/dist/astro/index.cjs.js +362 -91
  8. package/dist/astro/index.cjs.js.map +1 -1
  9. package/dist/astro/index.mjs +362 -92
  10. package/dist/astro/index.mjs.map +1 -1
  11. package/dist/astro/server.cjs.js +3396 -165
  12. package/dist/astro/server.cjs.js.map +1 -1
  13. package/dist/astro/server.mjs +3396 -165
  14. package/dist/astro/server.mjs.map +1 -1
  15. package/dist/devtools.cjs.js +1431 -0
  16. package/dist/devtools.cjs.js.map +1 -0
  17. package/dist/devtools.esm.js +1419 -0
  18. package/dist/devtools.esm.js.map +1 -0
  19. package/dist/diagnostics.cjs.js +3032 -296
  20. package/dist/diagnostics.cjs.js.map +1 -1
  21. package/dist/diagnostics.esm.js +3032 -296
  22. package/dist/diagnostics.esm.js.map +1 -1
  23. package/dist/element.cjs.js +230 -0
  24. package/dist/element.cjs.js.map +1 -0
  25. package/dist/element.esm.js +228 -0
  26. package/dist/element.esm.js.map +1 -0
  27. package/dist/guide/accessibility.md +257 -0
  28. package/dist/guide/adapters.md +221 -0
  29. package/dist/guide/behaviors.md +312 -0
  30. package/dist/guide/browser-sources.md +203 -0
  31. package/dist/guide/drag-and-drop.md +342 -0
  32. package/dist/guide/element-commands.md +306 -0
  33. package/dist/guide/error-boundaries.md +169 -0
  34. package/dist/guide/forms-reference.md +381 -0
  35. package/dist/guide/forms.md +250 -0
  36. package/dist/guide/http.md +299 -0
  37. package/dist/guide/inputs.md +173 -0
  38. package/dist/guide/persistence.md +245 -0
  39. package/dist/guide/recipes/carousel.md +155 -0
  40. package/dist/guide/recipes/charts.md +177 -0
  41. package/dist/guide/recipes/code-editor.md +135 -0
  42. package/dist/guide/recipes/data-grid.md +155 -0
  43. package/dist/guide/recipes/data-table.md +196 -0
  44. package/dist/guide/recipes/i18n.md +222 -0
  45. package/dist/guide/recipes/icons.md +115 -0
  46. package/dist/guide/recipes/overview.md +33 -0
  47. package/dist/guide/recipes/rich-text.md +154 -0
  48. package/dist/guide/resources.md +471 -0
  49. package/dist/guide/ssr.md +255 -0
  50. package/dist/guide/timers.md +178 -0
  51. package/dist/guide/ui/accordion.md +93 -0
  52. package/dist/guide/ui/combobox.md +144 -0
  53. package/dist/guide/ui/dialog.md +124 -0
  54. package/dist/guide/ui/disclosure.md +60 -0
  55. package/dist/guide/ui/menu.md +125 -0
  56. package/dist/guide/ui/overview.md +166 -0
  57. package/dist/guide/ui/popover.md +101 -0
  58. package/dist/guide/ui/select.md +114 -0
  59. package/dist/guide/ui/tabs.md +161 -0
  60. package/dist/guide/ui/toaster.md +152 -0
  61. package/dist/guide/ui/tooltip.md +103 -0
  62. package/dist/guide/undo.md +178 -0
  63. package/dist/guide/virtual-collections.md +183 -0
  64. package/dist/guide/web-components.md +179 -0
  65. package/dist/guide/widgets.md +217 -0
  66. package/dist/index.cjs.js +13178 -5769
  67. package/dist/index.cjs.js.map +1 -1
  68. package/dist/index.d.ts +2908 -276
  69. package/dist/index.esm.js +13149 -5779
  70. package/dist/index.esm.js.map +1 -1
  71. package/dist/jsx-dev-runtime.cjs.js +26 -334
  72. package/dist/jsx-dev-runtime.cjs.js.map +1 -1
  73. package/dist/jsx-dev-runtime.esm.js +19 -327
  74. package/dist/jsx-dev-runtime.esm.js.map +1 -1
  75. package/dist/jsx-runtime.cjs.js +26 -334
  76. package/dist/jsx-runtime.cjs.js.map +1 -1
  77. package/dist/jsx-runtime.esm.js +19 -327
  78. package/dist/jsx-runtime.esm.js.map +1 -1
  79. package/dist/jsx.cjs.js +10 -314
  80. package/dist/jsx.cjs.js.map +1 -1
  81. package/dist/jsx.esm.js +8 -315
  82. package/dist/jsx.esm.js.map +1 -1
  83. package/dist/react.cjs.js +117 -0
  84. package/dist/react.cjs.js.map +1 -0
  85. package/dist/react.esm.js +115 -0
  86. package/dist/react.esm.js.map +1 -0
  87. package/dist/shims/globalthis.cjs +20 -0
  88. package/dist/sygnal.min.js +1 -1
  89. package/dist/sygnal.min.js.map +1 -1
  90. package/dist/ui-combobox.cjs.js +169 -0
  91. package/dist/ui-combobox.cjs.js.map +1 -0
  92. package/dist/ui-combobox.esm.js +148 -0
  93. package/dist/ui-combobox.esm.js.map +1 -0
  94. package/dist/ui-menu.cjs.js +87 -0
  95. package/dist/ui-menu.cjs.js.map +1 -0
  96. package/dist/ui-menu.esm.js +66 -0
  97. package/dist/ui-menu.esm.js.map +1 -0
  98. package/dist/ui-select.cjs.js +104 -0
  99. package/dist/ui-select.cjs.js.map +1 -0
  100. package/dist/ui-select.esm.js +83 -0
  101. package/dist/ui-select.esm.js.map +1 -0
  102. package/dist/ui.cjs.js +738 -0
  103. package/dist/ui.cjs.js.map +1 -0
  104. package/dist/ui.esm.js +727 -0
  105. package/dist/ui.esm.js.map +1 -0
  106. package/dist/vike/ClientOnly.cjs.js +4 -14
  107. package/dist/vike/ClientOnly.cjs.js.map +1 -1
  108. package/dist/vike/ClientOnly.mjs +4 -14
  109. package/dist/vike/ClientOnly.mjs.map +1 -1
  110. package/dist/vike/{+config.js → config/+config.js} +9 -1
  111. package/dist/vike/config/+config.js.map +1 -0
  112. package/dist/vike/config/package.json +6 -0
  113. package/dist/vike/onRenderClient.cjs.js +165 -95
  114. package/dist/vike/onRenderClient.cjs.js.map +1 -1
  115. package/dist/vike/onRenderClient.mjs +165 -95
  116. package/dist/vike/onRenderClient.mjs.map +1 -1
  117. package/dist/vike/onRenderHtml.cjs.js +59 -24
  118. package/dist/vike/onRenderHtml.cjs.js.map +1 -1
  119. package/dist/vike/onRenderHtml.mjs +60 -25
  120. package/dist/vike/onRenderHtml.mjs.map +1 -1
  121. package/dist/vite/plugin.cjs.js +323 -88
  122. package/dist/vite/plugin.cjs.js.map +1 -1
  123. package/dist/vite/plugin.mjs +323 -89
  124. package/dist/vite/plugin.mjs.map +1 -1
  125. package/dist/zag.cjs.js +408 -0
  126. package/dist/zag.cjs.js.map +1 -0
  127. package/dist/zag.esm.js +405 -0
  128. package/dist/zag.esm.js.map +1 -0
  129. package/llms.txt +166 -103
  130. package/package.json +98 -14
  131. package/src/astro/client.ts +27 -16
  132. package/src/astro/index.d.ts +24 -0
  133. package/src/astro/index.ts +69 -3
  134. package/src/astro/server.ts +8 -2
  135. package/src/collection.ts +6 -93
  136. package/src/core/actions.ts +134 -0
  137. package/src/core/cell.ts +202 -0
  138. package/src/core/debug.ts +23 -0
  139. package/src/core/define.ts +242 -0
  140. package/src/core/hooks.ts +314 -0
  141. package/src/core/hosts/collection.ts +325 -0
  142. package/src/core/hosts/switchable.ts +146 -0
  143. package/src/core/instance.ts +592 -0
  144. package/src/core/markers/clientonly.ts +13 -0
  145. package/src/core/markers/lazy.ts +40 -0
  146. package/src/core/markers/portal.ts +96 -0
  147. package/src/core/markers/suspense.ts +41 -0
  148. package/src/core/markers/transition.ts +70 -0
  149. package/src/core/registry.ts +25 -0
  150. package/src/core/runtime.ts +573 -0
  151. package/src/core/statics.ts +104 -0
  152. package/src/core/teardown.ts +60 -0
  153. package/src/core/view.ts +37 -0
  154. package/src/cycle/dom/DocumentDOMSource.ts +13 -8
  155. package/src/cycle/dom/ElementFinder.ts +7 -9
  156. package/src/cycle/dom/EventDelegator.ts +174 -223
  157. package/src/cycle/dom/IsolateModule.ts +65 -35
  158. package/src/cycle/dom/MainDOMSource.ts +9 -2
  159. package/src/cycle/dom/PriorityQueue.ts +4 -2
  160. package/src/cycle/dom/SymbolTree.ts +18 -47
  161. package/src/cycle/dom/classNameModule.ts +9 -7
  162. package/src/cycle/dom/controlledInputModule.ts +23 -6
  163. package/src/cycle/dom/enrichEventStream.ts +25 -47
  164. package/src/cycle/dom/fragment.ts +7 -0
  165. package/src/cycle/dom/isolate.ts +30 -27
  166. package/src/cycle/dom/makeDOMDriver.ts +115 -56
  167. package/src/cycle/dom/mockDOMSource.ts +21 -1
  168. package/src/cycle/dom/modules.ts +16 -3
  169. package/src/cycle/dom/propsModule.ts +65 -0
  170. package/src/cycle/dom/selectModule.ts +22 -17
  171. package/src/cycle/dom/snabbdom.ts +1 -6
  172. package/src/cycle/dom/thunk.ts +3 -0
  173. package/src/cycle/dom/utils.ts +98 -0
  174. package/src/cycle/dom/viewTransition.ts +43 -0
  175. package/src/cycle/state/StateSource.ts +19 -3
  176. package/src/cycle/state/objIsEqual.ts +50 -0
  177. package/src/cycle/state/types.ts +0 -10
  178. package/src/defineComponent.ts +34 -0
  179. package/src/devtools.d.ts +151 -0
  180. package/src/devtools.ts +34 -0
  181. package/src/element.d.ts +59 -0
  182. package/src/element.ts +235 -0
  183. package/src/extra/backoff.ts +9 -0
  184. package/src/extra/behaviors.ts +169 -0
  185. package/src/extra/browserSignals.ts +23 -0
  186. package/src/extra/browserSources.ts +326 -0
  187. package/src/extra/command.ts +3 -3
  188. package/src/extra/controls.ts +47 -0
  189. package/src/extra/copyAsTest.ts +286 -0
  190. package/src/extra/devtools.ts +101 -31
  191. package/src/extra/devtoolsActions.ts +379 -0
  192. package/src/extra/devtoolsHook.ts +9 -0
  193. package/src/extra/devtoolsNext.ts +83 -0
  194. package/src/extra/diagnostics/checks/actionLog.ts +108 -0
  195. package/src/extra/diagnostics/checks/behaviors.ts +49 -0
  196. package/src/extra/diagnostics/checks/browserSources.ts +96 -0
  197. package/src/extra/diagnostics/checks/collections.ts +1 -1
  198. package/src/extra/diagnostics/checks/controls.ts +148 -0
  199. package/src/extra/diagnostics/checks/dataset.ts +57 -0
  200. package/src/extra/diagnostics/checks/dom.ts +20 -11
  201. package/src/extra/diagnostics/checks/elementCommands.ts +175 -0
  202. package/src/extra/diagnostics/checks/events.ts +17 -2
  203. package/src/extra/diagnostics/checks/fetch.ts +135 -0
  204. package/src/extra/diagnostics/checks/forms.ts +163 -0
  205. package/src/extra/diagnostics/checks/index.ts +97 -4
  206. package/src/extra/diagnostics/checks/inspect.ts +140 -32
  207. package/src/extra/diagnostics/checks/next.ts +417 -0
  208. package/src/extra/diagnostics/checks/persist.ts +54 -0
  209. package/src/extra/diagnostics/checks/props.ts +10 -5
  210. package/src/extra/diagnostics/checks/public.d.ts +98 -7
  211. package/src/extra/diagnostics/checks/replies.ts +128 -0
  212. package/src/extra/diagnostics/checks/router.ts +100 -0
  213. package/src/extra/diagnostics/checks/rxjsHints.ts +1 -1
  214. package/src/extra/diagnostics/checks/shared.ts +86 -2
  215. package/src/extra/diagnostics/checks/shorthand.ts +115 -0
  216. package/src/extra/diagnostics/checks/sortable.ts +129 -0
  217. package/src/extra/diagnostics/checks/state.ts +100 -7
  218. package/src/extra/diagnostics/checks/statics.ts +48 -0
  219. package/src/extra/diagnostics/checks/strict.ts +10 -67
  220. package/src/extra/diagnostics/checks/timers.ts +80 -0
  221. package/src/extra/diagnostics/checks/viewTransitions.ts +47 -0
  222. package/src/extra/diagnostics/checks/virtual.ts +73 -0
  223. package/src/extra/diagnostics/checks/widgets.ts +109 -0
  224. package/src/extra/diagnostics/checks/wiring.ts +66 -10
  225. package/src/extra/diagnostics/codes.ts +268 -23
  226. package/src/extra/diagnostics/index.ts +34 -9
  227. package/src/extra/diagnostics/legacy.ts +17 -0
  228. package/src/extra/driverFactories.ts +83 -19
  229. package/src/extra/elementCommands.ts +53 -0
  230. package/src/extra/fetchDriver.ts +519 -0
  231. package/src/extra/focusWithin.ts +27 -0
  232. package/src/extra/form.ts +268 -0
  233. package/src/extra/formHelpers.ts +139 -0
  234. package/src/extra/head.ts +106 -0
  235. package/src/extra/hmr.ts +2 -3
  236. package/src/extra/owned.ts +24 -0
  237. package/src/extra/pager.ts +50 -0
  238. package/src/extra/persist.ts +133 -0
  239. package/src/extra/pwa.ts +1 -1
  240. package/src/extra/queryCache.ts +107 -0
  241. package/src/extra/reducers.ts +1 -1
  242. package/src/extra/reduxDevtools.ts +92 -0
  243. package/src/extra/replies.ts +54 -0
  244. package/src/extra/router.ts +323 -0
  245. package/src/extra/run.ts +90 -217
  246. package/src/extra/selection.ts +76 -0
  247. package/src/extra/socketDriver.ts +265 -0
  248. package/src/extra/sortable.ts +377 -0
  249. package/src/extra/ssr.ts +427 -160
  250. package/src/extra/standardSchema.ts +27 -0
  251. package/src/extra/testing.ts +2433 -175
  252. package/src/extra/timers.ts +95 -0
  253. package/src/extra/undo.ts +261 -0
  254. package/src/extra/viewTransitions.ts +38 -0
  255. package/src/extra/virtual.ts +513 -0
  256. package/src/extra/widget.ts +201 -0
  257. package/src/index.d.ts +2631 -117
  258. package/src/index.ts +25 -4
  259. package/src/jsx-runtime.ts +15 -1
  260. package/src/jsx.ts +2 -1
  261. package/src/lazy.ts +50 -7
  262. package/src/portal.ts +3 -1
  263. package/src/pragma/index.ts +256 -133
  264. package/src/react-peers.d.ts +5 -0
  265. package/src/react.d.ts +43 -0
  266. package/src/react.ts +110 -0
  267. package/src/shared.ts +48 -0
  268. package/src/slot.ts +1 -1
  269. package/src/suspense.ts +3 -1
  270. package/src/switchable.ts +6 -121
  271. package/src/transition.ts +3 -1
  272. package/src/ui/accordion.ts +64 -0
  273. package/src/ui/dialog.ts +129 -0
  274. package/src/ui/disclosure.ts +35 -0
  275. package/src/ui/popover.ts +45 -0
  276. package/src/ui/shared.ts +94 -0
  277. package/src/ui/tabs.ts +82 -0
  278. package/src/ui/toaster.ts +198 -0
  279. package/src/ui/tooltip.ts +70 -0
  280. package/src/ui/zag/combobox.ts +115 -0
  281. package/src/ui/zag/menu.ts +40 -0
  282. package/src/ui/zag/select.ts +54 -0
  283. package/src/ui/zag/shared.ts +43 -0
  284. package/src/ui-combobox.d.ts +20 -0
  285. package/src/ui-combobox.ts +6 -0
  286. package/src/ui-menu.d.ts +30 -0
  287. package/src/ui-menu.ts +6 -0
  288. package/src/ui-select.d.ts +17 -0
  289. package/src/ui-select.ts +6 -0
  290. package/src/ui-zag-types.d.ts +42 -0
  291. package/src/ui.d.ts +208 -0
  292. package/src/ui.ts +15 -0
  293. package/src/vike/+config.ts +9 -1
  294. package/src/vike/ClientOnly.ts +1 -1
  295. package/src/vike/onRenderClient.ts +144 -96
  296. package/src/vike/onRenderHtml.ts +69 -26
  297. package/src/vike/types.ts +7 -1
  298. package/src/vite/globalthis-shim.ts +18 -0
  299. package/src/vite/globalthis.ts +56 -0
  300. package/src/vite/plugin.d.ts +22 -3
  301. package/src/vite/plugin.ts +222 -24
  302. package/src/zag.d.ts +64 -0
  303. package/src/zag.ts +238 -0
  304. package/dist/vike/+config.cjs.js +0 -66
  305. package/dist/vike/+config.cjs.js.map +0 -1
  306. package/dist/vike/+config.js.map +0 -1
  307. package/src/component.ts +0 -2301
  308. package/src/cycle/isolate/index.ts +0 -196
  309. package/src/cycle/run/index.ts +0 -151
  310. package/src/cycle/run/internals.ts +0 -143
  311. package/src/cycle/state/Collection.ts +0 -184
  312. package/src/cycle/state/index.ts +0 -5
  313. package/src/cycle/state/pickCombine.ts +0 -201
  314. package/src/cycle/state/pickMerge.ts +0 -122
  315. package/src/cycle/state/withState.ts +0 -47
  316. package/src/pragma/fn.ts +0 -55
@@ -0,0 +1,169 @@
1
+ 'use strict';
2
+
3
+ var combobox = require('@zag-js/combobox');
4
+ var zag = require('sygnal/zag');
5
+ var sygnal = require('sygnal');
6
+
7
+ function _interopNamespaceDefault(e) {
8
+ var n = Object.create(null);
9
+ if (e) {
10
+ Object.keys(e).forEach(function (k) {
11
+ if (k !== 'default') {
12
+ var d = Object.getOwnPropertyDescriptor(e, k);
13
+ Object.defineProperty(n, k, d.get ? d : {
14
+ enumerable: true,
15
+ get: function () { return e[k]; }
16
+ });
17
+ }
18
+ });
19
+ }
20
+ n.default = e;
21
+ return Object.freeze(n);
22
+ }
23
+
24
+ var combobox__namespace = /*#__PURE__*/_interopNamespaceDefault(combobox);
25
+
26
+ /*
27
+ * PLAN-5 2-Z: helpers the Zag-based parts (Menu, Select, Combobox) share. '../../zag' becomes the
28
+ * external 'sygnal/zag' and '../../index' the external 'sygnal' in the 'sygnal/ui/menu', 'sygnal/ui/select' and 'sygnal/ui/combobox' builds.
29
+ */
30
+ /** G-413: the naming props a part applies to its control (not the host) */
31
+ const NAMING = ['aria-label', 'aria-labelledby', 'aria-describedby'];
32
+ /**
33
+ * A control's (or listbox's) Zag props named from the part's props: without a label element, no
34
+ * aria-labelledby to it; the props' aria-label / aria-labelledby (/ aria-describedby) win
35
+ */
36
+ const named = (bag, p, describe) => {
37
+ const a = bag.attrs;
38
+ if (p.label == null)
39
+ delete a['aria-labelledby'];
40
+ for (const k of NAMING)
41
+ if (p[k] != null && (describe || k != 'aria-describedby'))
42
+ a[k] = p[k];
43
+ if (p['aria-labelledby'] != null)
44
+ delete a['aria-label'];
45
+ return bag;
46
+ };
47
+ /** An item as the parts take it: a string, or { value, label?, disabled? } (Menu also { separator: true }) */
48
+ const norm = (items) => (items || []).map((i) => (i && typeof i == 'object'
49
+ ? { ...i, value: String(i.value ?? ''), label: i.label ?? String(i.value ?? '') }
50
+ : { value: String(i), label: String(i) }));
51
+ /** A Select / Combobox value prop as Zag's string[] (undefined: uncontrolled; null or '': none) */
52
+ const arr = (v) => v === undefined ? undefined : v == null || v === '' ? [] : Array.isArray(v) ? v.map(String) : [String(v)];
53
+ /** The listbox collection options for Zag's collection() */
54
+ const collectionOf = (z, items) => z.collection({ items, itemToValue: (i) => i.value, itemToString: (i) => i.label, isItemDisabled: (i) => !!i.disabled });
55
+ /** value-change's detail: the value (single) or the values (multiple) */
56
+ const valueOut = (d, x) => (x.multiple ? d.value : d.value[0] ?? null);
57
+ /** Item rows of a listbox (Select, Combobox): text + a ✓ indicator Zag hides when unselected */
58
+ const options = (h, api) => api.collection.items.map((item) => h('div', { key: item.value, ...api.getItemProps({ item }) }, h('span', api.getItemTextProps({ item }), item.label), h('span', api.getItemIndicatorProps({ item }), '✓')));
59
+
60
+ /*
61
+ * PLAN-5 2-Z (U-1): Combobox, a Zag combobox machine (WAI-ARIA editable combobox with a listbox
62
+ * popup) as a widget tag.
63
+ *
64
+ * <Combobox className="city" label="City" items={CITIES} value={state.city} placeholder="Type a city" />
65
+ * intent: CITY: DOM.select('.city').events('value-change').detail() // 'Paris'
66
+ *
67
+ * Renders a label, the input (role="combobox", aria-autocomplete="list", aria-activedescendant
68
+ * on the highlighted option), a trigger button, and the listbox in a positioner. The items are
69
+ * filtered as the user types: by default the labels that contain the text (case-insensitive);
70
+ * `filter={(item, text) => boolean}` replaces the test, `filter={false}` leaves it to the app (it
71
+ * passes the `items` to show, from `input-change`). The filter text resets when the list closes.
72
+ * Keyboard is Zag's: ArrowDown / ArrowUp open and move, Enter selects, Escape closes, Home / End
73
+ * in the input move the caret. Styling hooks: `data-scope="combobox"` + `data-part` (root, label,
74
+ * control, input, trigger, positioner, content, item, item-text, item-indicator), `data-state`,
75
+ * `data-highlighted`.
76
+ *
77
+ * Forms (G-411): with `name`, hidden inputs submit the value (one per value when `multiple`);
78
+ * the visible input, which shows the label, has no name. `form` goes on the hidden inputs (G-434).
79
+ * With `allowCustomValue` (single), the selected value is submitted unless the user typed since
80
+ * the last selection; then the typed text (an item's exact label submits that item's value; G-435,
81
+ * G-468).
82
+ *
83
+ * Props: `label`, `items` (strings or { value, label?, disabled? }), `value` (controlled: a
84
+ * string, an array when `multiple`, null for none), `defaultValue`, `placeholder`, `filter`, and
85
+ * Zag's combobox props (`multiple`, `name`, `form`, `disabled`, `readOnly`, `required`,
86
+ * `invalid`, `allowCustomValue`, `openOnClick`, `inputBehavior`, `selectionBehavior`,
87
+ * `closeOnSelect`, `loopFocus`, `positioning`, `open`, `id`). Events: `value-change` (the value,
88
+ * or the values when multiple), `input-change` (the text the user typed), `open-change` (boolean).
89
+ * Commands: `open`, `close`, `clear`, `focus` (the input).
90
+ */
91
+ const shown = (all, f, q) => {
92
+ if (f === false || !q)
93
+ return all;
94
+ const l = q.toLowerCase();
95
+ return all.filter((i) => (typeof f == 'function' ? f(i, q) : String(i.label).toLowerCase().includes(l)));
96
+ };
97
+ // the filter text: what the user typed; '' when the list closes
98
+ const setText = (x, q) => { if (x.q !== q)
99
+ x.q = q, x.refresh(); };
100
+ // G-411: forms get the value, not the label the input shows: the visible input has no name; one
101
+ // hidden input per value (a single combobox: one, '' when empty) carries `name`.
102
+ // G-435 / G-468: a single combobox with `allowCustomValue` submits the selected value unless the
103
+ // user typed since the last selection (`x.t`: set by input-change, cleared by a selection, a value
104
+ // change or a new controlled value that isn't empty: G-494); then the value of an item whose label the text is, else the
105
+ // text itself. So `selectionBehavior` 'preserve' / 'clear', items relabelled after a pick and a
106
+ // `defaultValue` before the items load all submit the value.
107
+ const submitted = (api, x) => {
108
+ const v = api.value[0] ?? '';
109
+ if (!x.custom || !x.t)
110
+ return v;
111
+ const q = api.inputValue;
112
+ return x.items.find((i) => i.label === q)?.value ?? q;
113
+ };
114
+ const hidden = (api, p, x) => {
115
+ if (p.name == null)
116
+ return null;
117
+ const vs = x.multiple ? api.value : [submitted(api, x)];
118
+ // G-434: `form` as an attribute (HTMLInputElement.form is a read-only property)
119
+ const attrs = p.form == null ? undefined : { form: p.form };
120
+ return vs.map((value, i) => sygnal.createElement('input', { key: 'h' + i, type: 'hidden', name: p.name, attrs, disabled: !!p.disabled, value }));
121
+ };
122
+ const Combobox = /*#__PURE__*/ zag.fromZag(combobox__namespace, (api, p, x) => {
123
+ const input = named(api.getInputProps(), p, 1);
124
+ delete input.attrs.name;
125
+ delete input.attrs.form;
126
+ return sygnal.createElement('div', api.getRootProps(), p.label != null && sygnal.createElement('label', api.getLabelProps(), p.label), sygnal.createElement('div', api.getControlProps(), sygnal.createElement('input', { ...input, placeholder: p.placeholder }), sygnal.createElement('button', api.getTriggerProps(), '▾')), sygnal.createElement('div', api.getPositionerProps(), sygnal.createElement('div', named(api.getContentProps(), p), options(sygnal.createElement, api))), hidden(api, p, x));
127
+ }, {
128
+ name: 'Combobox',
129
+ $own: 1,
130
+ ownProps: [...NAMING, 'name'],
131
+ props: ({ items, label, placeholder, value, defaultValue, filter, 'aria-label': _l, 'aria-labelledby': _b, 'aria-describedby': _d, ...p }, x) => {
132
+ x.multiple = !!p.multiple;
133
+ x.custom = !!p.allowCustomValue;
134
+ x.items = norm(items);
135
+ // G-468: a new controlled value ends the typing. G-494: not an empty one (an app that clears
136
+ // its value on input-change: the typed text is still what is submitted)
137
+ const v = arr(value), k = v && JSON.stringify(v);
138
+ if (k !== x.v)
139
+ x.v = k, v?.length && (x.t = 0);
140
+ return {
141
+ ...p,
142
+ collection: collectionOf(combobox__namespace, shown(x.items, filter, x.q || '')),
143
+ value: v,
144
+ defaultValue: arr(defaultValue),
145
+ // typing only (not the label a selection writes): the filter text, and input-change
146
+ // G-414: the app's own callbacks (p.onInputValueChange / p.onOpenChange) run first
147
+ onInputValueChange: (d) => { p.onInputValueChange?.(d); if (d.reason == 'input-change')
148
+ x.t = 1, setText(x, d.inputValue), x.dispatch('input-change', d.inputValue); },
149
+ onSelect: (d) => { x.t = 0; p.onSelect?.(d); },
150
+ onValueChange: (d) => { x.t = 0; p.onValueChange?.(d); },
151
+ onOpenChange: (d) => { p.onOpenChange?.(d); d.open || setText(x, ''); },
152
+ };
153
+ },
154
+ events: {
155
+ 'value-change': ['onValueChange', valueOut],
156
+ 'input-change': null,
157
+ 'open-change': ['onOpenChange', (d) => d.open],
158
+ },
159
+ commands: {
160
+ open: (api) => api.setOpen(true),
161
+ close: (api) => api.setOpen(false),
162
+ clear: (api) => api.clearValue(),
163
+ focus: (api) => api.focus(),
164
+ },
165
+ fallback: (p, hh) => hh('div', null, p.label != null && hh('label', null, p.label), hh('input', { placeholder: p.placeholder, disabled: true })),
166
+ });
167
+
168
+ exports.Combobox = Combobox;
169
+ //# sourceMappingURL=ui-combobox.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-combobox.cjs.js","sources":["../src/ui/zag/shared.ts","../src/ui/zag/combobox.ts"],"sourcesContent":["/*\n * PLAN-5 2-Z: helpers the Zag-based parts (Menu, Select, Combobox) share. '../../zag' becomes the\n * external 'sygnal/zag' and '../../index' the external 'sygnal' in the 'sygnal/ui/menu', 'sygnal/ui/select' and 'sygnal/ui/combobox' builds.\n */\n\n/** G-413: the naming props a part applies to its control (not the host) */\nexport const NAMING = ['aria-label', 'aria-labelledby', 'aria-describedby']\n\n/**\n * A control's (or listbox's) Zag props named from the part's props: without a label element, no\n * aria-labelledby to it; the props' aria-label / aria-labelledby (/ aria-describedby) win\n */\nexport const named = (bag: any, p: any, describe?: any) => {\n const a = bag.attrs\n if (p.label == null) delete a['aria-labelledby']\n for (const k of NAMING) if (p[k] != null && (describe || k != 'aria-describedby')) a[k] = p[k]\n if (p['aria-labelledby'] != null) delete a['aria-label']\n return bag\n}\n\n/** An item as the parts take it: a string, or { value, label?, disabled? } (Menu also { separator: true }) */\nexport const norm = (items: any): any[] =>\n (items || []).map((i: any) => (i && typeof i == 'object'\n ? {...i, value: String(i.value ?? ''), label: i.label ?? String(i.value ?? '')}\n : {value: String(i), label: String(i)}))\n\n/** A Select / Combobox value prop as Zag's string[] (undefined: uncontrolled; null or '': none) */\nexport const arr = (v: any): any =>\n v === undefined ? undefined : v == null || v === '' ? [] : Array.isArray(v) ? v.map(String) : [String(v)]\n\n/** The listbox collection options for Zag's collection() */\nexport const collectionOf = (z: any, items: any[]) =>\n z.collection({items, itemToValue: (i: any) => i.value, itemToString: (i: any) => i.label, isItemDisabled: (i: any) => !!i.disabled})\n\n/** value-change's detail: the value (single) or the values (multiple) */\nexport const valueOut = (d: any, x: any) => (x.multiple ? d.value : d.value[0] ?? null)\n\n/** Item rows of a listbox (Select, Combobox): text + a ✓ indicator Zag hides when unselected */\nexport const options = (h: any, api: any) =>\n api.collection.items.map((item: any) =>\n h('div', {key: item.value, ...api.getItemProps({item})},\n h('span', api.getItemTextProps({item}), item.label),\n h('span', api.getItemIndicatorProps({item}), '✓')))\n","/*\n * PLAN-5 2-Z (U-1): Combobox, a Zag combobox machine (WAI-ARIA editable combobox with a listbox\n * popup) as a widget tag.\n *\n * <Combobox className=\"city\" label=\"City\" items={CITIES} value={state.city} placeholder=\"Type a city\" />\n * intent: CITY: DOM.select('.city').events('value-change').detail() // 'Paris'\n *\n * Renders a label, the input (role=\"combobox\", aria-autocomplete=\"list\", aria-activedescendant\n * on the highlighted option), a trigger button, and the listbox in a positioner. The items are\n * filtered as the user types: by default the labels that contain the text (case-insensitive);\n * `filter={(item, text) => boolean}` replaces the test, `filter={false}` leaves it to the app (it\n * passes the `items` to show, from `input-change`). The filter text resets when the list closes.\n * Keyboard is Zag's: ArrowDown / ArrowUp open and move, Enter selects, Escape closes, Home / End\n * in the input move the caret. Styling hooks: `data-scope=\"combobox\"` + `data-part` (root, label,\n * control, input, trigger, positioner, content, item, item-text, item-indicator), `data-state`,\n * `data-highlighted`.\n *\n * Forms (G-411): with `name`, hidden inputs submit the value (one per value when `multiple`);\n * the visible input, which shows the label, has no name. `form` goes on the hidden inputs (G-434).\n * With `allowCustomValue` (single), the selected value is submitted unless the user typed since\n * the last selection; then the typed text (an item's exact label submits that item's value; G-435,\n * G-468).\n *\n * Props: `label`, `items` (strings or { value, label?, disabled? }), `value` (controlled: a\n * string, an array when `multiple`, null for none), `defaultValue`, `placeholder`, `filter`, and\n * Zag's combobox props (`multiple`, `name`, `form`, `disabled`, `readOnly`, `required`,\n * `invalid`, `allowCustomValue`, `openOnClick`, `inputBehavior`, `selectionBehavior`,\n * `closeOnSelect`, `loopFocus`, `positioning`, `open`, `id`). Events: `value-change` (the value,\n * or the values when multiple), `input-change` (the text the user typed), `open-change` (boolean).\n * Commands: `open`, `close`, `clear`, `focus` (the input).\n */\nimport * as combobox from '@zag-js/combobox'\nimport {fromZag} from '../../zag'\nimport {createElement as h} from '../../index'\nimport {NAMING, arr, collectionOf, named, norm, options, valueOut} from './shared'\n\nconst shown = (all: any[], f: any, q: string) => {\n if (f === false || !q) return all\n const l = q.toLowerCase()\n return all.filter((i) => (typeof f == 'function' ? f(i, q) : String(i.label).toLowerCase().includes(l)))\n}\n\n// the filter text: what the user typed; '' when the list closes\nconst setText = (x: any, q: string) => { if (x.q !== q) x.q = q, x.refresh() }\n\n// G-411: forms get the value, not the label the input shows: the visible input has no name; one\n// hidden input per value (a single combobox: one, '' when empty) carries `name`.\n// G-435 / G-468: a single combobox with `allowCustomValue` submits the selected value unless the\n// user typed since the last selection (`x.t`: set by input-change, cleared by a selection, a value\n// change or a new controlled value that isn't empty: G-494); then the value of an item whose label the text is, else the\n// text itself. So `selectionBehavior` 'preserve' / 'clear', items relabelled after a pick and a\n// `defaultValue` before the items load all submit the value.\nconst submitted = (api: any, x: any): string => {\n const v = api.value[0] ?? ''\n if (!x.custom || !x.t) return v\n const q = api.inputValue\n return x.items.find((i: any) => i.label === q)?.value ?? q\n}\nconst hidden = (api: any, p: any, x: any) => {\n if (p.name == null) return null\n const vs = x.multiple ? api.value : [submitted(api, x)]\n // G-434: `form` as an attribute (HTMLInputElement.form is a read-only property)\n const attrs = p.form == null ? undefined : {form: p.form}\n return vs.map((value: string, i: number) => h('input', {key: 'h' + i, type: 'hidden', name: p.name, attrs, disabled: !!p.disabled, value}))\n}\n\nexport const Combobox: any = /*#__PURE__*/ fromZag(combobox, (api: any, p: any, x: any) => {\n const input = named(api.getInputProps(), p, 1)\n delete input.attrs.name\n delete input.attrs.form\n return h('div', api.getRootProps(),\n p.label != null && h('label', api.getLabelProps(), p.label),\n h('div', api.getControlProps(),\n h('input', {...input, placeholder: p.placeholder}),\n h('button', api.getTriggerProps(), '▾')),\n h('div', api.getPositionerProps(), h('div', named(api.getContentProps(), p), options(h, api))),\n hidden(api, p, x))\n}, {\n name: 'Combobox',\n $own: 1,\n ownProps: [...NAMING, 'name'],\n props: ({items, label, placeholder, value, defaultValue, filter, 'aria-label': _l, 'aria-labelledby': _b, 'aria-describedby': _d, ...p}: any, x: any) => {\n x.multiple = !!p.multiple\n x.custom = !!p.allowCustomValue\n x.items = norm(items)\n // G-468: a new controlled value ends the typing. G-494: not an empty one (an app that clears\n // its value on input-change: the typed text is still what is submitted)\n const v = arr(value), k = v && JSON.stringify(v)\n if (k !== x.v) x.v = k, v?.length && (x.t = 0)\n return {\n ...p,\n collection: collectionOf(combobox, shown(x.items, filter, x.q || '')),\n value: v,\n defaultValue: arr(defaultValue),\n // typing only (not the label a selection writes): the filter text, and input-change\n // G-414: the app's own callbacks (p.onInputValueChange / p.onOpenChange) run first\n onInputValueChange: (d: any) => { p.onInputValueChange?.(d); if (d.reason == 'input-change') x.t = 1, setText(x, d.inputValue), x.dispatch('input-change', d.inputValue) },\n onSelect: (d: any) => { x.t = 0; p.onSelect?.(d) },\n onValueChange: (d: any) => { x.t = 0; p.onValueChange?.(d) },\n onOpenChange: (d: any) => { p.onOpenChange?.(d); d.open || setText(x, '') },\n }\n },\n events: {\n 'value-change': ['onValueChange', valueOut],\n 'input-change': null,\n 'open-change': ['onOpenChange', (d: any) => d.open],\n },\n commands: {\n open: (api: any) => api.setOpen(true),\n close: (api: any) => api.setOpen(false),\n clear: (api: any) => api.clearValue(),\n focus: (api: any) => api.focus(),\n },\n fallback: (p: any, hh: any) => hh('div', null, p.label != null && hh('label', null, p.label), hh('input', {placeholder: p.placeholder, disabled: true})),\n})\n"],"names":["h","fromZag","combobox"],"mappings":"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"}
@@ -0,0 +1,148 @@
1
+ import * as combobox from '@zag-js/combobox';
2
+ import { fromZag } from 'sygnal/zag';
3
+ import { createElement } from 'sygnal';
4
+
5
+ /*
6
+ * PLAN-5 2-Z: helpers the Zag-based parts (Menu, Select, Combobox) share. '../../zag' becomes the
7
+ * external 'sygnal/zag' and '../../index' the external 'sygnal' in the 'sygnal/ui/menu', 'sygnal/ui/select' and 'sygnal/ui/combobox' builds.
8
+ */
9
+ /** G-413: the naming props a part applies to its control (not the host) */
10
+ const NAMING = ['aria-label', 'aria-labelledby', 'aria-describedby'];
11
+ /**
12
+ * A control's (or listbox's) Zag props named from the part's props: without a label element, no
13
+ * aria-labelledby to it; the props' aria-label / aria-labelledby (/ aria-describedby) win
14
+ */
15
+ const named = (bag, p, describe) => {
16
+ const a = bag.attrs;
17
+ if (p.label == null)
18
+ delete a['aria-labelledby'];
19
+ for (const k of NAMING)
20
+ if (p[k] != null && (describe || k != 'aria-describedby'))
21
+ a[k] = p[k];
22
+ if (p['aria-labelledby'] != null)
23
+ delete a['aria-label'];
24
+ return bag;
25
+ };
26
+ /** An item as the parts take it: a string, or { value, label?, disabled? } (Menu also { separator: true }) */
27
+ const norm = (items) => (items || []).map((i) => (i && typeof i == 'object'
28
+ ? { ...i, value: String(i.value ?? ''), label: i.label ?? String(i.value ?? '') }
29
+ : { value: String(i), label: String(i) }));
30
+ /** A Select / Combobox value prop as Zag's string[] (undefined: uncontrolled; null or '': none) */
31
+ const arr = (v) => v === undefined ? undefined : v == null || v === '' ? [] : Array.isArray(v) ? v.map(String) : [String(v)];
32
+ /** The listbox collection options for Zag's collection() */
33
+ const collectionOf = (z, items) => z.collection({ items, itemToValue: (i) => i.value, itemToString: (i) => i.label, isItemDisabled: (i) => !!i.disabled });
34
+ /** value-change's detail: the value (single) or the values (multiple) */
35
+ const valueOut = (d, x) => (x.multiple ? d.value : d.value[0] ?? null);
36
+ /** Item rows of a listbox (Select, Combobox): text + a ✓ indicator Zag hides when unselected */
37
+ const options = (h, api) => api.collection.items.map((item) => h('div', { key: item.value, ...api.getItemProps({ item }) }, h('span', api.getItemTextProps({ item }), item.label), h('span', api.getItemIndicatorProps({ item }), '✓')));
38
+
39
+ /*
40
+ * PLAN-5 2-Z (U-1): Combobox, a Zag combobox machine (WAI-ARIA editable combobox with a listbox
41
+ * popup) as a widget tag.
42
+ *
43
+ * <Combobox className="city" label="City" items={CITIES} value={state.city} placeholder="Type a city" />
44
+ * intent: CITY: DOM.select('.city').events('value-change').detail() // 'Paris'
45
+ *
46
+ * Renders a label, the input (role="combobox", aria-autocomplete="list", aria-activedescendant
47
+ * on the highlighted option), a trigger button, and the listbox in a positioner. The items are
48
+ * filtered as the user types: by default the labels that contain the text (case-insensitive);
49
+ * `filter={(item, text) => boolean}` replaces the test, `filter={false}` leaves it to the app (it
50
+ * passes the `items` to show, from `input-change`). The filter text resets when the list closes.
51
+ * Keyboard is Zag's: ArrowDown / ArrowUp open and move, Enter selects, Escape closes, Home / End
52
+ * in the input move the caret. Styling hooks: `data-scope="combobox"` + `data-part` (root, label,
53
+ * control, input, trigger, positioner, content, item, item-text, item-indicator), `data-state`,
54
+ * `data-highlighted`.
55
+ *
56
+ * Forms (G-411): with `name`, hidden inputs submit the value (one per value when `multiple`);
57
+ * the visible input, which shows the label, has no name. `form` goes on the hidden inputs (G-434).
58
+ * With `allowCustomValue` (single), the selected value is submitted unless the user typed since
59
+ * the last selection; then the typed text (an item's exact label submits that item's value; G-435,
60
+ * G-468).
61
+ *
62
+ * Props: `label`, `items` (strings or { value, label?, disabled? }), `value` (controlled: a
63
+ * string, an array when `multiple`, null for none), `defaultValue`, `placeholder`, `filter`, and
64
+ * Zag's combobox props (`multiple`, `name`, `form`, `disabled`, `readOnly`, `required`,
65
+ * `invalid`, `allowCustomValue`, `openOnClick`, `inputBehavior`, `selectionBehavior`,
66
+ * `closeOnSelect`, `loopFocus`, `positioning`, `open`, `id`). Events: `value-change` (the value,
67
+ * or the values when multiple), `input-change` (the text the user typed), `open-change` (boolean).
68
+ * Commands: `open`, `close`, `clear`, `focus` (the input).
69
+ */
70
+ const shown = (all, f, q) => {
71
+ if (f === false || !q)
72
+ return all;
73
+ const l = q.toLowerCase();
74
+ return all.filter((i) => (typeof f == 'function' ? f(i, q) : String(i.label).toLowerCase().includes(l)));
75
+ };
76
+ // the filter text: what the user typed; '' when the list closes
77
+ const setText = (x, q) => { if (x.q !== q)
78
+ x.q = q, x.refresh(); };
79
+ // G-411: forms get the value, not the label the input shows: the visible input has no name; one
80
+ // hidden input per value (a single combobox: one, '' when empty) carries `name`.
81
+ // G-435 / G-468: a single combobox with `allowCustomValue` submits the selected value unless the
82
+ // user typed since the last selection (`x.t`: set by input-change, cleared by a selection, a value
83
+ // change or a new controlled value that isn't empty: G-494); then the value of an item whose label the text is, else the
84
+ // text itself. So `selectionBehavior` 'preserve' / 'clear', items relabelled after a pick and a
85
+ // `defaultValue` before the items load all submit the value.
86
+ const submitted = (api, x) => {
87
+ const v = api.value[0] ?? '';
88
+ if (!x.custom || !x.t)
89
+ return v;
90
+ const q = api.inputValue;
91
+ return x.items.find((i) => i.label === q)?.value ?? q;
92
+ };
93
+ const hidden = (api, p, x) => {
94
+ if (p.name == null)
95
+ return null;
96
+ const vs = x.multiple ? api.value : [submitted(api, x)];
97
+ // G-434: `form` as an attribute (HTMLInputElement.form is a read-only property)
98
+ const attrs = p.form == null ? undefined : { form: p.form };
99
+ return vs.map((value, i) => createElement('input', { key: 'h' + i, type: 'hidden', name: p.name, attrs, disabled: !!p.disabled, value }));
100
+ };
101
+ const Combobox = /*#__PURE__*/ fromZag(combobox, (api, p, x) => {
102
+ const input = named(api.getInputProps(), p, 1);
103
+ delete input.attrs.name;
104
+ delete input.attrs.form;
105
+ return createElement('div', api.getRootProps(), p.label != null && createElement('label', api.getLabelProps(), p.label), createElement('div', api.getControlProps(), createElement('input', { ...input, placeholder: p.placeholder }), createElement('button', api.getTriggerProps(), '▾')), createElement('div', api.getPositionerProps(), createElement('div', named(api.getContentProps(), p), options(createElement, api))), hidden(api, p, x));
106
+ }, {
107
+ name: 'Combobox',
108
+ $own: 1,
109
+ ownProps: [...NAMING, 'name'],
110
+ props: ({ items, label, placeholder, value, defaultValue, filter, 'aria-label': _l, 'aria-labelledby': _b, 'aria-describedby': _d, ...p }, x) => {
111
+ x.multiple = !!p.multiple;
112
+ x.custom = !!p.allowCustomValue;
113
+ x.items = norm(items);
114
+ // G-468: a new controlled value ends the typing. G-494: not an empty one (an app that clears
115
+ // its value on input-change: the typed text is still what is submitted)
116
+ const v = arr(value), k = v && JSON.stringify(v);
117
+ if (k !== x.v)
118
+ x.v = k, v?.length && (x.t = 0);
119
+ return {
120
+ ...p,
121
+ collection: collectionOf(combobox, shown(x.items, filter, x.q || '')),
122
+ value: v,
123
+ defaultValue: arr(defaultValue),
124
+ // typing only (not the label a selection writes): the filter text, and input-change
125
+ // G-414: the app's own callbacks (p.onInputValueChange / p.onOpenChange) run first
126
+ onInputValueChange: (d) => { p.onInputValueChange?.(d); if (d.reason == 'input-change')
127
+ x.t = 1, setText(x, d.inputValue), x.dispatch('input-change', d.inputValue); },
128
+ onSelect: (d) => { x.t = 0; p.onSelect?.(d); },
129
+ onValueChange: (d) => { x.t = 0; p.onValueChange?.(d); },
130
+ onOpenChange: (d) => { p.onOpenChange?.(d); d.open || setText(x, ''); },
131
+ };
132
+ },
133
+ events: {
134
+ 'value-change': ['onValueChange', valueOut],
135
+ 'input-change': null,
136
+ 'open-change': ['onOpenChange', (d) => d.open],
137
+ },
138
+ commands: {
139
+ open: (api) => api.setOpen(true),
140
+ close: (api) => api.setOpen(false),
141
+ clear: (api) => api.clearValue(),
142
+ focus: (api) => api.focus(),
143
+ },
144
+ fallback: (p, hh) => hh('div', null, p.label != null && hh('label', null, p.label), hh('input', { placeholder: p.placeholder, disabled: true })),
145
+ });
146
+
147
+ export { Combobox };
148
+ //# sourceMappingURL=ui-combobox.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-combobox.esm.js","sources":["../src/ui/zag/shared.ts","../src/ui/zag/combobox.ts"],"sourcesContent":["/*\n * PLAN-5 2-Z: helpers the Zag-based parts (Menu, Select, Combobox) share. '../../zag' becomes the\n * external 'sygnal/zag' and '../../index' the external 'sygnal' in the 'sygnal/ui/menu', 'sygnal/ui/select' and 'sygnal/ui/combobox' builds.\n */\n\n/** G-413: the naming props a part applies to its control (not the host) */\nexport const NAMING = ['aria-label', 'aria-labelledby', 'aria-describedby']\n\n/**\n * A control's (or listbox's) Zag props named from the part's props: without a label element, no\n * aria-labelledby to it; the props' aria-label / aria-labelledby (/ aria-describedby) win\n */\nexport const named = (bag: any, p: any, describe?: any) => {\n const a = bag.attrs\n if (p.label == null) delete a['aria-labelledby']\n for (const k of NAMING) if (p[k] != null && (describe || k != 'aria-describedby')) a[k] = p[k]\n if (p['aria-labelledby'] != null) delete a['aria-label']\n return bag\n}\n\n/** An item as the parts take it: a string, or { value, label?, disabled? } (Menu also { separator: true }) */\nexport const norm = (items: any): any[] =>\n (items || []).map((i: any) => (i && typeof i == 'object'\n ? {...i, value: String(i.value ?? ''), label: i.label ?? String(i.value ?? '')}\n : {value: String(i), label: String(i)}))\n\n/** A Select / Combobox value prop as Zag's string[] (undefined: uncontrolled; null or '': none) */\nexport const arr = (v: any): any =>\n v === undefined ? undefined : v == null || v === '' ? [] : Array.isArray(v) ? v.map(String) : [String(v)]\n\n/** The listbox collection options for Zag's collection() */\nexport const collectionOf = (z: any, items: any[]) =>\n z.collection({items, itemToValue: (i: any) => i.value, itemToString: (i: any) => i.label, isItemDisabled: (i: any) => !!i.disabled})\n\n/** value-change's detail: the value (single) or the values (multiple) */\nexport const valueOut = (d: any, x: any) => (x.multiple ? d.value : d.value[0] ?? null)\n\n/** Item rows of a listbox (Select, Combobox): text + a ✓ indicator Zag hides when unselected */\nexport const options = (h: any, api: any) =>\n api.collection.items.map((item: any) =>\n h('div', {key: item.value, ...api.getItemProps({item})},\n h('span', api.getItemTextProps({item}), item.label),\n h('span', api.getItemIndicatorProps({item}), '✓')))\n","/*\n * PLAN-5 2-Z (U-1): Combobox, a Zag combobox machine (WAI-ARIA editable combobox with a listbox\n * popup) as a widget tag.\n *\n * <Combobox className=\"city\" label=\"City\" items={CITIES} value={state.city} placeholder=\"Type a city\" />\n * intent: CITY: DOM.select('.city').events('value-change').detail() // 'Paris'\n *\n * Renders a label, the input (role=\"combobox\", aria-autocomplete=\"list\", aria-activedescendant\n * on the highlighted option), a trigger button, and the listbox in a positioner. The items are\n * filtered as the user types: by default the labels that contain the text (case-insensitive);\n * `filter={(item, text) => boolean}` replaces the test, `filter={false}` leaves it to the app (it\n * passes the `items` to show, from `input-change`). The filter text resets when the list closes.\n * Keyboard is Zag's: ArrowDown / ArrowUp open and move, Enter selects, Escape closes, Home / End\n * in the input move the caret. Styling hooks: `data-scope=\"combobox\"` + `data-part` (root, label,\n * control, input, trigger, positioner, content, item, item-text, item-indicator), `data-state`,\n * `data-highlighted`.\n *\n * Forms (G-411): with `name`, hidden inputs submit the value (one per value when `multiple`);\n * the visible input, which shows the label, has no name. `form` goes on the hidden inputs (G-434).\n * With `allowCustomValue` (single), the selected value is submitted unless the user typed since\n * the last selection; then the typed text (an item's exact label submits that item's value; G-435,\n * G-468).\n *\n * Props: `label`, `items` (strings or { value, label?, disabled? }), `value` (controlled: a\n * string, an array when `multiple`, null for none), `defaultValue`, `placeholder`, `filter`, and\n * Zag's combobox props (`multiple`, `name`, `form`, `disabled`, `readOnly`, `required`,\n * `invalid`, `allowCustomValue`, `openOnClick`, `inputBehavior`, `selectionBehavior`,\n * `closeOnSelect`, `loopFocus`, `positioning`, `open`, `id`). Events: `value-change` (the value,\n * or the values when multiple), `input-change` (the text the user typed), `open-change` (boolean).\n * Commands: `open`, `close`, `clear`, `focus` (the input).\n */\nimport * as combobox from '@zag-js/combobox'\nimport {fromZag} from '../../zag'\nimport {createElement as h} from '../../index'\nimport {NAMING, arr, collectionOf, named, norm, options, valueOut} from './shared'\n\nconst shown = (all: any[], f: any, q: string) => {\n if (f === false || !q) return all\n const l = q.toLowerCase()\n return all.filter((i) => (typeof f == 'function' ? f(i, q) : String(i.label).toLowerCase().includes(l)))\n}\n\n// the filter text: what the user typed; '' when the list closes\nconst setText = (x: any, q: string) => { if (x.q !== q) x.q = q, x.refresh() }\n\n// G-411: forms get the value, not the label the input shows: the visible input has no name; one\n// hidden input per value (a single combobox: one, '' when empty) carries `name`.\n// G-435 / G-468: a single combobox with `allowCustomValue` submits the selected value unless the\n// user typed since the last selection (`x.t`: set by input-change, cleared by a selection, a value\n// change or a new controlled value that isn't empty: G-494); then the value of an item whose label the text is, else the\n// text itself. So `selectionBehavior` 'preserve' / 'clear', items relabelled after a pick and a\n// `defaultValue` before the items load all submit the value.\nconst submitted = (api: any, x: any): string => {\n const v = api.value[0] ?? ''\n if (!x.custom || !x.t) return v\n const q = api.inputValue\n return x.items.find((i: any) => i.label === q)?.value ?? q\n}\nconst hidden = (api: any, p: any, x: any) => {\n if (p.name == null) return null\n const vs = x.multiple ? api.value : [submitted(api, x)]\n // G-434: `form` as an attribute (HTMLInputElement.form is a read-only property)\n const attrs = p.form == null ? undefined : {form: p.form}\n return vs.map((value: string, i: number) => h('input', {key: 'h' + i, type: 'hidden', name: p.name, attrs, disabled: !!p.disabled, value}))\n}\n\nexport const Combobox: any = /*#__PURE__*/ fromZag(combobox, (api: any, p: any, x: any) => {\n const input = named(api.getInputProps(), p, 1)\n delete input.attrs.name\n delete input.attrs.form\n return h('div', api.getRootProps(),\n p.label != null && h('label', api.getLabelProps(), p.label),\n h('div', api.getControlProps(),\n h('input', {...input, placeholder: p.placeholder}),\n h('button', api.getTriggerProps(), '▾')),\n h('div', api.getPositionerProps(), h('div', named(api.getContentProps(), p), options(h, api))),\n hidden(api, p, x))\n}, {\n name: 'Combobox',\n $own: 1,\n ownProps: [...NAMING, 'name'],\n props: ({items, label, placeholder, value, defaultValue, filter, 'aria-label': _l, 'aria-labelledby': _b, 'aria-describedby': _d, ...p}: any, x: any) => {\n x.multiple = !!p.multiple\n x.custom = !!p.allowCustomValue\n x.items = norm(items)\n // G-468: a new controlled value ends the typing. G-494: not an empty one (an app that clears\n // its value on input-change: the typed text is still what is submitted)\n const v = arr(value), k = v && JSON.stringify(v)\n if (k !== x.v) x.v = k, v?.length && (x.t = 0)\n return {\n ...p,\n collection: collectionOf(combobox, shown(x.items, filter, x.q || '')),\n value: v,\n defaultValue: arr(defaultValue),\n // typing only (not the label a selection writes): the filter text, and input-change\n // G-414: the app's own callbacks (p.onInputValueChange / p.onOpenChange) run first\n onInputValueChange: (d: any) => { p.onInputValueChange?.(d); if (d.reason == 'input-change') x.t = 1, setText(x, d.inputValue), x.dispatch('input-change', d.inputValue) },\n onSelect: (d: any) => { x.t = 0; p.onSelect?.(d) },\n onValueChange: (d: any) => { x.t = 0; p.onValueChange?.(d) },\n onOpenChange: (d: any) => { p.onOpenChange?.(d); d.open || setText(x, '') },\n }\n },\n events: {\n 'value-change': ['onValueChange', valueOut],\n 'input-change': null,\n 'open-change': ['onOpenChange', (d: any) => d.open],\n },\n commands: {\n open: (api: any) => api.setOpen(true),\n close: (api: any) => api.setOpen(false),\n clear: (api: any) => api.clearValue(),\n focus: (api: any) => api.focus(),\n },\n fallback: (p: any, hh: any) => hh('div', null, p.label != null && hh('label', null, p.label), hh('input', {placeholder: p.placeholder, disabled: true})),\n})\n"],"names":["h"],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ 'use strict';
2
+
3
+ var menu = require('@zag-js/menu');
4
+ var zag = require('sygnal/zag');
5
+ var sygnal = require('sygnal');
6
+
7
+ function _interopNamespaceDefault(e) {
8
+ var n = Object.create(null);
9
+ if (e) {
10
+ Object.keys(e).forEach(function (k) {
11
+ if (k !== 'default') {
12
+ var d = Object.getOwnPropertyDescriptor(e, k);
13
+ Object.defineProperty(n, k, d.get ? d : {
14
+ enumerable: true,
15
+ get: function () { return e[k]; }
16
+ });
17
+ }
18
+ });
19
+ }
20
+ n.default = e;
21
+ return Object.freeze(n);
22
+ }
23
+
24
+ var menu__namespace = /*#__PURE__*/_interopNamespaceDefault(menu);
25
+
26
+ /*
27
+ * PLAN-5 2-Z: helpers the Zag-based parts (Menu, Select, Combobox) share. '../../zag' becomes the
28
+ * external 'sygnal/zag' and '../../index' the external 'sygnal' in the 'sygnal/ui/menu', 'sygnal/ui/select' and 'sygnal/ui/combobox' builds.
29
+ */
30
+ /** G-413: the naming props a part applies to its control (not the host) */
31
+ const NAMING = ['aria-label', 'aria-labelledby', 'aria-describedby'];
32
+ /**
33
+ * A control's (or listbox's) Zag props named from the part's props: without a label element, no
34
+ * aria-labelledby to it; the props' aria-label / aria-labelledby (/ aria-describedby) win
35
+ */
36
+ const named = (bag, p, describe) => {
37
+ const a = bag.attrs;
38
+ if (p.label == null)
39
+ delete a['aria-labelledby'];
40
+ for (const k of NAMING)
41
+ if (p[k] != null && (describe || k != 'aria-describedby'))
42
+ a[k] = p[k];
43
+ if (p['aria-labelledby'] != null)
44
+ delete a['aria-label'];
45
+ return bag;
46
+ };
47
+ /** An item as the parts take it: a string, or { value, label?, disabled? } (Menu also { separator: true }) */
48
+ const norm = (items) => (items || []).map((i) => (i && typeof i == 'object'
49
+ ? { ...i, value: String(i.value ?? ''), label: i.label ?? String(i.value ?? '') }
50
+ : { value: String(i), label: String(i) }));
51
+
52
+ /*
53
+ * PLAN-5 2-Z (U-1): Menu, a Zag menu machine (WAI-ARIA menu button) as a widget tag.
54
+ *
55
+ * <Menu className="actions" label="Actions" items={[{ value: 'edit', label: 'Edit' }, { value: 'delete', label: 'Delete', disabled: true }]} />
56
+ * intent: PICK: DOM.select('.actions').events('select').detail() // 'edit'
57
+ * model: OPEN_ACTIONS: { ELEMENT: { open: '.actions' } }
58
+ *
59
+ * Renders a trigger button (its text: `label`) and the menu (role="menu", items role="menuitem")
60
+ * in a positioner. Keyboard, focus and typeahead are Zag's: Enter / Space / ArrowDown open it on
61
+ * the first item (ArrowUp on the last), the arrows move, Home / End, typing jumps to an item,
62
+ * Enter / click selects and closes, Escape / Tab / a click outside closes; the focus returns to
63
+ * the trigger. Styling hooks: Zag's `data-scope="menu"` + `data-part` (trigger, positioner,
64
+ * content, item, separator), `data-state`, `data-highlighted`, `data-disabled`.
65
+ *
66
+ * Props: `label`, `items` (strings, or { value, label?, disabled? }, or { separator: true }), and
67
+ * Zag's menu props (`open` controlled, `defaultOpen`, `closeOnSelect`, `loopFocus`, `typeahead`,
68
+ * `positioning`, `dir`, `id`). Events: `select` (the item's value), `open-change` (boolean).
69
+ * Commands: `open`, `close`.
70
+ */
71
+ const Menu = /*#__PURE__*/ zag.fromZag(menu__namespace, (api, p) => [
72
+ sygnal.createElement('button', named(api.getTriggerProps(), { ...p, label: 1 }, 1), p.label),
73
+ sygnal.createElement('div', api.getPositionerProps(), sygnal.createElement('div', api.getContentProps(), norm(p.items).map((i) => (i.separator
74
+ ? sygnal.createElement('hr', api.getSeparatorProps())
75
+ : sygnal.createElement('div', { key: i.value, ...api.getItemProps({ value: i.value, disabled: !!i.disabled }) }, i.label))))),
76
+ ], {
77
+ name: 'Menu',
78
+ $own: 1,
79
+ ownProps: NAMING,
80
+ props: ({ items, label, 'aria-label': _l, 'aria-labelledby': _b, 'aria-describedby': _d, ...p }) => p,
81
+ events: { select: ['onSelect', (d) => d.value], 'open-change': ['onOpenChange', (d) => d.open] },
82
+ commands: { open: (api) => api.setOpen(true), close: (api) => api.setOpen(false) },
83
+ fallback: (p, hh) => hh('button', { type: 'button', 'aria-haspopup': 'menu', 'aria-expanded': false }, p.label),
84
+ });
85
+
86
+ exports.Menu = Menu;
87
+ //# sourceMappingURL=ui-menu.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-menu.cjs.js","sources":["../src/ui/zag/shared.ts","../src/ui/zag/menu.ts"],"sourcesContent":["/*\n * PLAN-5 2-Z: helpers the Zag-based parts (Menu, Select, Combobox) share. '../../zag' becomes the\n * external 'sygnal/zag' and '../../index' the external 'sygnal' in the 'sygnal/ui/menu', 'sygnal/ui/select' and 'sygnal/ui/combobox' builds.\n */\n\n/** G-413: the naming props a part applies to its control (not the host) */\nexport const NAMING = ['aria-label', 'aria-labelledby', 'aria-describedby']\n\n/**\n * A control's (or listbox's) Zag props named from the part's props: without a label element, no\n * aria-labelledby to it; the props' aria-label / aria-labelledby (/ aria-describedby) win\n */\nexport const named = (bag: any, p: any, describe?: any) => {\n const a = bag.attrs\n if (p.label == null) delete a['aria-labelledby']\n for (const k of NAMING) if (p[k] != null && (describe || k != 'aria-describedby')) a[k] = p[k]\n if (p['aria-labelledby'] != null) delete a['aria-label']\n return bag\n}\n\n/** An item as the parts take it: a string, or { value, label?, disabled? } (Menu also { separator: true }) */\nexport const norm = (items: any): any[] =>\n (items || []).map((i: any) => (i && typeof i == 'object'\n ? {...i, value: String(i.value ?? ''), label: i.label ?? String(i.value ?? '')}\n : {value: String(i), label: String(i)}))\n\n/** A Select / Combobox value prop as Zag's string[] (undefined: uncontrolled; null or '': none) */\nexport const arr = (v: any): any =>\n v === undefined ? undefined : v == null || v === '' ? [] : Array.isArray(v) ? v.map(String) : [String(v)]\n\n/** The listbox collection options for Zag's collection() */\nexport const collectionOf = (z: any, items: any[]) =>\n z.collection({items, itemToValue: (i: any) => i.value, itemToString: (i: any) => i.label, isItemDisabled: (i: any) => !!i.disabled})\n\n/** value-change's detail: the value (single) or the values (multiple) */\nexport const valueOut = (d: any, x: any) => (x.multiple ? d.value : d.value[0] ?? null)\n\n/** Item rows of a listbox (Select, Combobox): text + a ✓ indicator Zag hides when unselected */\nexport const options = (h: any, api: any) =>\n api.collection.items.map((item: any) =>\n h('div', {key: item.value, ...api.getItemProps({item})},\n h('span', api.getItemTextProps({item}), item.label),\n h('span', api.getItemIndicatorProps({item}), '✓')))\n","/*\n * PLAN-5 2-Z (U-1): Menu, a Zag menu machine (WAI-ARIA menu button) as a widget tag.\n *\n * <Menu className=\"actions\" label=\"Actions\" items={[{ value: 'edit', label: 'Edit' }, { value: 'delete', label: 'Delete', disabled: true }]} />\n * intent: PICK: DOM.select('.actions').events('select').detail() // 'edit'\n * model: OPEN_ACTIONS: { ELEMENT: { open: '.actions' } }\n *\n * Renders a trigger button (its text: `label`) and the menu (role=\"menu\", items role=\"menuitem\")\n * in a positioner. Keyboard, focus and typeahead are Zag's: Enter / Space / ArrowDown open it on\n * the first item (ArrowUp on the last), the arrows move, Home / End, typing jumps to an item,\n * Enter / click selects and closes, Escape / Tab / a click outside closes; the focus returns to\n * the trigger. Styling hooks: Zag's `data-scope=\"menu\"` + `data-part` (trigger, positioner,\n * content, item, separator), `data-state`, `data-highlighted`, `data-disabled`.\n *\n * Props: `label`, `items` (strings, or { value, label?, disabled? }, or { separator: true }), and\n * Zag's menu props (`open` controlled, `defaultOpen`, `closeOnSelect`, `loopFocus`, `typeahead`,\n * `positioning`, `dir`, `id`). Events: `select` (the item's value), `open-change` (boolean).\n * Commands: `open`, `close`.\n */\nimport * as menu from '@zag-js/menu'\nimport {fromZag} from '../../zag'\nimport {createElement as h} from '../../index'\nimport {NAMING, named, norm} from './shared'\n\nexport const Menu: any = /*#__PURE__*/ fromZag(menu, (api: any, p: any) => [\n h('button', named(api.getTriggerProps(), {...p, label: 1}, 1), p.label),\n h('div', api.getPositionerProps(),\n h('div', api.getContentProps(),\n norm(p.items).map((i: any) => (i.separator\n ? h('hr', api.getSeparatorProps())\n : h('div', {key: i.value, ...api.getItemProps({value: i.value, disabled: !!i.disabled})}, i.label))))),\n], {\n name: 'Menu',\n $own: 1,\n ownProps: NAMING,\n props: ({items, label, 'aria-label': _l, 'aria-labelledby': _b, 'aria-describedby': _d, ...p}: any) => p,\n events: {select: ['onSelect', (d: any) => d.value], 'open-change': ['onOpenChange', (d: any) => d.open]},\n commands: {open: (api: any) => api.setOpen(true), close: (api: any) => api.setOpen(false)},\n fallback: (p: any, hh: any) => hh('button', {type: 'button', 'aria-haspopup': 'menu', 'aria-expanded': false}, p.label),\n})\n"],"names":["fromZag","menu","h"],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ import * as menu from '@zag-js/menu';
2
+ import { fromZag } from 'sygnal/zag';
3
+ import { createElement } from 'sygnal';
4
+
5
+ /*
6
+ * PLAN-5 2-Z: helpers the Zag-based parts (Menu, Select, Combobox) share. '../../zag' becomes the
7
+ * external 'sygnal/zag' and '../../index' the external 'sygnal' in the 'sygnal/ui/menu', 'sygnal/ui/select' and 'sygnal/ui/combobox' builds.
8
+ */
9
+ /** G-413: the naming props a part applies to its control (not the host) */
10
+ const NAMING = ['aria-label', 'aria-labelledby', 'aria-describedby'];
11
+ /**
12
+ * A control's (or listbox's) Zag props named from the part's props: without a label element, no
13
+ * aria-labelledby to it; the props' aria-label / aria-labelledby (/ aria-describedby) win
14
+ */
15
+ const named = (bag, p, describe) => {
16
+ const a = bag.attrs;
17
+ if (p.label == null)
18
+ delete a['aria-labelledby'];
19
+ for (const k of NAMING)
20
+ if (p[k] != null && (describe || k != 'aria-describedby'))
21
+ a[k] = p[k];
22
+ if (p['aria-labelledby'] != null)
23
+ delete a['aria-label'];
24
+ return bag;
25
+ };
26
+ /** An item as the parts take it: a string, or { value, label?, disabled? } (Menu also { separator: true }) */
27
+ const norm = (items) => (items || []).map((i) => (i && typeof i == 'object'
28
+ ? { ...i, value: String(i.value ?? ''), label: i.label ?? String(i.value ?? '') }
29
+ : { value: String(i), label: String(i) }));
30
+
31
+ /*
32
+ * PLAN-5 2-Z (U-1): Menu, a Zag menu machine (WAI-ARIA menu button) as a widget tag.
33
+ *
34
+ * <Menu className="actions" label="Actions" items={[{ value: 'edit', label: 'Edit' }, { value: 'delete', label: 'Delete', disabled: true }]} />
35
+ * intent: PICK: DOM.select('.actions').events('select').detail() // 'edit'
36
+ * model: OPEN_ACTIONS: { ELEMENT: { open: '.actions' } }
37
+ *
38
+ * Renders a trigger button (its text: `label`) and the menu (role="menu", items role="menuitem")
39
+ * in a positioner. Keyboard, focus and typeahead are Zag's: Enter / Space / ArrowDown open it on
40
+ * the first item (ArrowUp on the last), the arrows move, Home / End, typing jumps to an item,
41
+ * Enter / click selects and closes, Escape / Tab / a click outside closes; the focus returns to
42
+ * the trigger. Styling hooks: Zag's `data-scope="menu"` + `data-part` (trigger, positioner,
43
+ * content, item, separator), `data-state`, `data-highlighted`, `data-disabled`.
44
+ *
45
+ * Props: `label`, `items` (strings, or { value, label?, disabled? }, or { separator: true }), and
46
+ * Zag's menu props (`open` controlled, `defaultOpen`, `closeOnSelect`, `loopFocus`, `typeahead`,
47
+ * `positioning`, `dir`, `id`). Events: `select` (the item's value), `open-change` (boolean).
48
+ * Commands: `open`, `close`.
49
+ */
50
+ const Menu = /*#__PURE__*/ fromZag(menu, (api, p) => [
51
+ createElement('button', named(api.getTriggerProps(), { ...p, label: 1 }, 1), p.label),
52
+ createElement('div', api.getPositionerProps(), createElement('div', api.getContentProps(), norm(p.items).map((i) => (i.separator
53
+ ? createElement('hr', api.getSeparatorProps())
54
+ : createElement('div', { key: i.value, ...api.getItemProps({ value: i.value, disabled: !!i.disabled }) }, i.label))))),
55
+ ], {
56
+ name: 'Menu',
57
+ $own: 1,
58
+ ownProps: NAMING,
59
+ props: ({ items, label, 'aria-label': _l, 'aria-labelledby': _b, 'aria-describedby': _d, ...p }) => p,
60
+ events: { select: ['onSelect', (d) => d.value], 'open-change': ['onOpenChange', (d) => d.open] },
61
+ commands: { open: (api) => api.setOpen(true), close: (api) => api.setOpen(false) },
62
+ fallback: (p, hh) => hh('button', { type: 'button', 'aria-haspopup': 'menu', 'aria-expanded': false }, p.label),
63
+ });
64
+
65
+ export { Menu };
66
+ //# sourceMappingURL=ui-menu.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-menu.esm.js","sources":["../src/ui/zag/shared.ts","../src/ui/zag/menu.ts"],"sourcesContent":["/*\n * PLAN-5 2-Z: helpers the Zag-based parts (Menu, Select, Combobox) share. '../../zag' becomes the\n * external 'sygnal/zag' and '../../index' the external 'sygnal' in the 'sygnal/ui/menu', 'sygnal/ui/select' and 'sygnal/ui/combobox' builds.\n */\n\n/** G-413: the naming props a part applies to its control (not the host) */\nexport const NAMING = ['aria-label', 'aria-labelledby', 'aria-describedby']\n\n/**\n * A control's (or listbox's) Zag props named from the part's props: without a label element, no\n * aria-labelledby to it; the props' aria-label / aria-labelledby (/ aria-describedby) win\n */\nexport const named = (bag: any, p: any, describe?: any) => {\n const a = bag.attrs\n if (p.label == null) delete a['aria-labelledby']\n for (const k of NAMING) if (p[k] != null && (describe || k != 'aria-describedby')) a[k] = p[k]\n if (p['aria-labelledby'] != null) delete a['aria-label']\n return bag\n}\n\n/** An item as the parts take it: a string, or { value, label?, disabled? } (Menu also { separator: true }) */\nexport const norm = (items: any): any[] =>\n (items || []).map((i: any) => (i && typeof i == 'object'\n ? {...i, value: String(i.value ?? ''), label: i.label ?? String(i.value ?? '')}\n : {value: String(i), label: String(i)}))\n\n/** A Select / Combobox value prop as Zag's string[] (undefined: uncontrolled; null or '': none) */\nexport const arr = (v: any): any =>\n v === undefined ? undefined : v == null || v === '' ? [] : Array.isArray(v) ? v.map(String) : [String(v)]\n\n/** The listbox collection options for Zag's collection() */\nexport const collectionOf = (z: any, items: any[]) =>\n z.collection({items, itemToValue: (i: any) => i.value, itemToString: (i: any) => i.label, isItemDisabled: (i: any) => !!i.disabled})\n\n/** value-change's detail: the value (single) or the values (multiple) */\nexport const valueOut = (d: any, x: any) => (x.multiple ? d.value : d.value[0] ?? null)\n\n/** Item rows of a listbox (Select, Combobox): text + a ✓ indicator Zag hides when unselected */\nexport const options = (h: any, api: any) =>\n api.collection.items.map((item: any) =>\n h('div', {key: item.value, ...api.getItemProps({item})},\n h('span', api.getItemTextProps({item}), item.label),\n h('span', api.getItemIndicatorProps({item}), '✓')))\n","/*\n * PLAN-5 2-Z (U-1): Menu, a Zag menu machine (WAI-ARIA menu button) as a widget tag.\n *\n * <Menu className=\"actions\" label=\"Actions\" items={[{ value: 'edit', label: 'Edit' }, { value: 'delete', label: 'Delete', disabled: true }]} />\n * intent: PICK: DOM.select('.actions').events('select').detail() // 'edit'\n * model: OPEN_ACTIONS: { ELEMENT: { open: '.actions' } }\n *\n * Renders a trigger button (its text: `label`) and the menu (role=\"menu\", items role=\"menuitem\")\n * in a positioner. Keyboard, focus and typeahead are Zag's: Enter / Space / ArrowDown open it on\n * the first item (ArrowUp on the last), the arrows move, Home / End, typing jumps to an item,\n * Enter / click selects and closes, Escape / Tab / a click outside closes; the focus returns to\n * the trigger. Styling hooks: Zag's `data-scope=\"menu\"` + `data-part` (trigger, positioner,\n * content, item, separator), `data-state`, `data-highlighted`, `data-disabled`.\n *\n * Props: `label`, `items` (strings, or { value, label?, disabled? }, or { separator: true }), and\n * Zag's menu props (`open` controlled, `defaultOpen`, `closeOnSelect`, `loopFocus`, `typeahead`,\n * `positioning`, `dir`, `id`). Events: `select` (the item's value), `open-change` (boolean).\n * Commands: `open`, `close`.\n */\nimport * as menu from '@zag-js/menu'\nimport {fromZag} from '../../zag'\nimport {createElement as h} from '../../index'\nimport {NAMING, named, norm} from './shared'\n\nexport const Menu: any = /*#__PURE__*/ fromZag(menu, (api: any, p: any) => [\n h('button', named(api.getTriggerProps(), {...p, label: 1}, 1), p.label),\n h('div', api.getPositionerProps(),\n h('div', api.getContentProps(),\n norm(p.items).map((i: any) => (i.separator\n ? h('hr', api.getSeparatorProps())\n : h('div', {key: i.value, ...api.getItemProps({value: i.value, disabled: !!i.disabled})}, i.label))))),\n], {\n name: 'Menu',\n $own: 1,\n ownProps: NAMING,\n props: ({items, label, 'aria-label': _l, 'aria-labelledby': _b, 'aria-describedby': _d, ...p}: any) => p,\n events: {select: ['onSelect', (d: any) => d.value], 'open-change': ['onOpenChange', (d: any) => d.open]},\n commands: {open: (api: any) => api.setOpen(true), close: (api: any) => api.setOpen(false)},\n fallback: (p: any, hh: any) => hh('button', {type: 'button', 'aria-haspopup': 'menu', 'aria-expanded': false}, p.label),\n})\n"],"names":["h"],"mappings":"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"}