@vielzeug/refine 26.10.7 → 26.10.9

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 (326) hide show
  1. package/README.md +6 -0
  2. package/dist/accordion-item.cjs +2 -2
  3. package/dist/accordion-item.cjs.map +1 -1
  4. package/dist/accordion-item.js +6 -6
  5. package/dist/accordion-item.js.map +1 -1
  6. package/dist/accordion.cjs +2 -2
  7. package/dist/accordion.cjs.map +1 -1
  8. package/dist/accordion.js +2 -2
  9. package/dist/accordion.js.map +1 -1
  10. package/dist/alert.cjs +2 -2
  11. package/dist/alert.cjs.map +1 -1
  12. package/dist/alert.js +2 -2
  13. package/dist/alert.js.map +1 -1
  14. package/dist/avatar.cjs +3 -3
  15. package/dist/avatar.cjs.map +1 -1
  16. package/dist/avatar.js +2 -2
  17. package/dist/avatar.js.map +1 -1
  18. package/dist/badge.cjs +2 -2
  19. package/dist/badge.cjs.map +1 -1
  20. package/dist/badge.js +2 -2
  21. package/dist/badge.js.map +1 -1
  22. package/dist/box.cjs +2 -2
  23. package/dist/box.cjs.map +1 -1
  24. package/dist/box.js +2 -2
  25. package/dist/box.js.map +1 -1
  26. package/dist/button-group.cjs +2 -2
  27. package/dist/button-group.cjs.map +1 -1
  28. package/dist/button-group.js +2 -2
  29. package/dist/button-group.js.map +1 -1
  30. package/dist/button.cjs +9 -9
  31. package/dist/button.cjs.map +1 -1
  32. package/dist/button.js +8 -8
  33. package/dist/button.js.map +1 -1
  34. package/dist/card.cjs +2 -2
  35. package/dist/card.cjs.map +1 -1
  36. package/dist/card.js +2 -2
  37. package/dist/card.js.map +1 -1
  38. package/dist/carousel.cjs +6 -6
  39. package/dist/carousel.cjs.map +1 -1
  40. package/dist/carousel.js +6 -6
  41. package/dist/carousel.js.map +1 -1
  42. package/dist/chat-message.cjs +4 -4
  43. package/dist/chat-message.cjs.map +1 -1
  44. package/dist/chat-message.js +4 -4
  45. package/dist/chat-message.js.map +1 -1
  46. package/dist/checkbox-group.cjs +1 -1
  47. package/dist/checkbox-group.cjs.map +1 -1
  48. package/dist/checkbox-group.js +1 -1
  49. package/dist/checkbox-group.js.map +1 -1
  50. package/dist/checkbox.cjs +1 -1
  51. package/dist/checkbox.cjs.map +1 -1
  52. package/dist/checkbox.js +1 -1
  53. package/dist/checkbox.js.map +1 -1
  54. package/dist/chip.cjs +8 -8
  55. package/dist/chip.cjs.map +1 -1
  56. package/dist/chip.js +8 -8
  57. package/dist/chip.js.map +1 -1
  58. package/dist/combobox.cjs +8 -8
  59. package/dist/combobox.cjs.map +1 -1
  60. package/dist/combobox.js +11 -11
  61. package/dist/combobox.js.map +1 -1
  62. package/dist/content/avatar/avatar.d.ts +2 -1
  63. package/dist/content/avatar/avatar.d.ts.map +1 -1
  64. package/dist/content/card/card.d.ts +6 -3
  65. package/dist/content/card/card.d.ts.map +1 -1
  66. package/dist/content/carousel/carousel.d.ts +5 -3
  67. package/dist/content/carousel/carousel.d.ts.map +1 -1
  68. package/dist/content/chat-message/chat-message.d.ts +2 -1
  69. package/dist/content/chat-message/chat-message.d.ts.map +1 -1
  70. package/dist/content/copy-command/copy-command.d.ts +1 -1
  71. package/dist/content/copy-command/copy-command.d.ts.map +1 -1
  72. package/dist/content/keyboard-key/keyboard-key.d.ts +2 -1
  73. package/dist/content/keyboard-key/keyboard-key.d.ts.map +1 -1
  74. package/dist/content/list/list.d.ts +2 -1
  75. package/dist/content/list/list.d.ts.map +1 -1
  76. package/dist/content/marquee/marquee.d.ts +3 -2
  77. package/dist/content/marquee/marquee.d.ts.map +1 -1
  78. package/dist/content/pagination/pagination.d.ts +1 -1
  79. package/dist/content/pagination/pagination.d.ts.map +1 -1
  80. package/dist/content/qr-code/qr-code.d.ts +0 -41
  81. package/dist/content/qr-code/qr-code.d.ts.map +1 -1
  82. package/dist/content/separator/separator.d.ts +1 -1
  83. package/dist/content/separator/separator.d.ts.map +1 -1
  84. package/dist/content/stepper/step.d.ts +1 -1
  85. package/dist/content/stepper/step.d.ts.map +1 -1
  86. package/dist/content/table/table.d.ts +2 -1
  87. package/dist/content/table/table.d.ts.map +1 -1
  88. package/dist/content/text/text.d.ts +13 -6
  89. package/dist/content/text/text.d.ts.map +1 -1
  90. package/dist/cookie-banner.cjs +1 -1
  91. package/dist/cookie-banner.cjs.map +1 -1
  92. package/dist/cookie-banner.js +1 -1
  93. package/dist/cookie-banner.js.map +1 -1
  94. package/dist/copy-command.cjs +6 -6
  95. package/dist/copy-command.cjs.map +1 -1
  96. package/dist/copy-command.js +7 -7
  97. package/dist/copy-command.js.map +1 -1
  98. package/dist/core/checkable.cjs +1 -1
  99. package/dist/core/checkable.cjs.map +1 -1
  100. package/dist/core/checkable.d.ts +6 -7
  101. package/dist/core/checkable.d.ts.map +1 -1
  102. package/dist/core/checkable.js +1 -1
  103. package/dist/core/checkable.js.map +1 -1
  104. package/dist/core/choice-field.cjs +1 -1
  105. package/dist/core/choice-field.cjs.map +1 -1
  106. package/dist/core/choice-field.d.ts +6 -6
  107. package/dist/core/choice-field.d.ts.map +1 -1
  108. package/dist/core/choice-field.js +1 -1
  109. package/dist/core/choice-field.js.map +1 -1
  110. package/dist/core/text-field.cjs +1 -1
  111. package/dist/core/text-field.cjs.map +1 -1
  112. package/dist/core/text-field.d.ts +8 -8
  113. package/dist/core/text-field.d.ts.map +1 -1
  114. package/dist/core/text-field.js +1 -1
  115. package/dist/core/text-field.js.map +1 -1
  116. package/dist/counter.cjs +2 -2
  117. package/dist/counter.cjs.map +1 -1
  118. package/dist/counter.js +2 -2
  119. package/dist/counter.js.map +1 -1
  120. package/dist/custom-elements.json +378 -241
  121. package/dist/datagrid.cjs +47 -47
  122. package/dist/datagrid.cjs.map +1 -1
  123. package/dist/datagrid.js +51 -51
  124. package/dist/datagrid.js.map +1 -1
  125. package/dist/date-picker.cjs +9 -9
  126. package/dist/date-picker.cjs.map +1 -1
  127. package/dist/date-picker.js +11 -11
  128. package/dist/date-picker.js.map +1 -1
  129. package/dist/dialog.cjs +3 -3
  130. package/dist/dialog.cjs.map +1 -1
  131. package/dist/dialog.js +3 -3
  132. package/dist/dialog.js.map +1 -1
  133. package/dist/disclosure/accordion/accordion.d.ts +4 -2
  134. package/dist/disclosure/accordion/accordion.d.ts.map +1 -1
  135. package/dist/disclosure/accordion-item/accordion-item.d.ts +1 -1
  136. package/dist/disclosure/accordion-item/accordion-item.d.ts.map +1 -1
  137. package/dist/disclosure/tab-item/tab-item.d.ts +1 -1
  138. package/dist/disclosure/tab-item/tab-item.d.ts.map +1 -1
  139. package/dist/disclosure/tabs/tabs.d.ts +1 -1
  140. package/dist/disclosure/tabs/tabs.d.ts.map +1 -1
  141. package/dist/drawer.cjs +4 -4
  142. package/dist/drawer.cjs.map +1 -1
  143. package/dist/drawer.js +2 -2
  144. package/dist/drawer.js.map +1 -1
  145. package/dist/feedback/alert/alert.d.ts +2 -1
  146. package/dist/feedback/alert/alert.d.ts.map +1 -1
  147. package/dist/feedback/badge/badge.d.ts +7 -4
  148. package/dist/feedback/badge/badge.d.ts.map +1 -1
  149. package/dist/feedback/chip/chip.d.ts +7 -5
  150. package/dist/feedback/chip/chip.d.ts.map +1 -1
  151. package/dist/grid-item.cjs +2 -2
  152. package/dist/grid-item.cjs.map +1 -1
  153. package/dist/grid-item.js +2 -2
  154. package/dist/grid-item.js.map +1 -1
  155. package/dist/grid.cjs +2 -2
  156. package/dist/grid.cjs.map +1 -1
  157. package/dist/grid.js +2 -2
  158. package/dist/grid.js.map +1 -1
  159. package/dist/input.cjs +7 -7
  160. package/dist/input.cjs.map +1 -1
  161. package/dist/input.js +8 -8
  162. package/dist/input.js.map +1 -1
  163. package/dist/inputs/button/button.d.ts +3 -2
  164. package/dist/inputs/button/button.d.ts.map +1 -1
  165. package/dist/inputs/button-group/button-group.d.ts +1 -37
  166. package/dist/inputs/button-group/button-group.d.ts.map +1 -1
  167. package/dist/inputs/combobox/combobox.types.d.ts +2 -2
  168. package/dist/inputs/combobox/combobox.types.d.ts.map +1 -1
  169. package/dist/inputs/counter/counter.d.ts +3 -2
  170. package/dist/inputs/counter/counter.d.ts.map +1 -1
  171. package/dist/inputs/datagrid/datagrid-model.cjs +1 -1
  172. package/dist/inputs/datagrid/datagrid-model.cjs.map +1 -1
  173. package/dist/inputs/datagrid/datagrid-model.d.ts +2 -1
  174. package/dist/inputs/datagrid/datagrid-model.d.ts.map +1 -1
  175. package/dist/inputs/datagrid/datagrid-model.js +1 -1
  176. package/dist/inputs/datagrid/datagrid-model.js.map +1 -1
  177. package/dist/inputs/datagrid/datagrid.d.ts +4 -2
  178. package/dist/inputs/datagrid/datagrid.d.ts.map +1 -1
  179. package/dist/inputs/date-picker/date-picker.d.ts +3 -2
  180. package/dist/inputs/date-picker/date-picker.d.ts.map +1 -1
  181. package/dist/inputs/input/input.d.ts +5 -3
  182. package/dist/inputs/input/input.d.ts.map +1 -1
  183. package/dist/inputs/message-composer/message-composer.d.ts +3 -2
  184. package/dist/inputs/message-composer/message-composer.d.ts.map +1 -1
  185. package/dist/inputs/number-input/number-input.d.ts +1 -1
  186. package/dist/inputs/number-input/number-input.d.ts.map +1 -1
  187. package/dist/inputs/otp-input/otp-input.d.ts +3 -2
  188. package/dist/inputs/otp-input/otp-input.d.ts.map +1 -1
  189. package/dist/inputs/query-bar/query-bar.d.ts.map +1 -1
  190. package/dist/inputs/select/select.d.ts +2 -2
  191. package/dist/inputs/select/select.d.ts.map +1 -1
  192. package/dist/inputs/textarea/textarea.d.ts +4 -3
  193. package/dist/inputs/textarea/textarea.d.ts.map +1 -1
  194. package/dist/inputs/time-picker/time-picker.d.ts +2 -2
  195. package/dist/inputs/time-picker/time-picker.d.ts.map +1 -1
  196. package/dist/keyboard-key.cjs +3 -3
  197. package/dist/keyboard-key.cjs.map +1 -1
  198. package/dist/keyboard-key.js +3 -3
  199. package/dist/keyboard-key.js.map +1 -1
  200. package/dist/layout/box/box.d.ts +6 -3
  201. package/dist/layout/box/box.d.ts.map +1 -1
  202. package/dist/layout/grid/grid.d.ts +11 -6
  203. package/dist/layout/grid/grid.d.ts.map +1 -1
  204. package/dist/layout/grid-item/grid-item.d.ts +8 -4
  205. package/dist/layout/grid-item/grid-item.d.ts.map +1 -1
  206. package/dist/layout/navbar/navbar.d.ts +4 -2
  207. package/dist/layout/navbar/navbar.d.ts.map +1 -1
  208. package/dist/layout/sidebar/sidebar.d.ts +2 -1
  209. package/dist/layout/sidebar/sidebar.d.ts.map +1 -1
  210. package/dist/list-item.cjs +1 -1
  211. package/dist/list-item.cjs.map +1 -1
  212. package/dist/list-item.js +1 -1
  213. package/dist/list-item.js.map +1 -1
  214. package/dist/list.cjs +2 -2
  215. package/dist/list.cjs.map +1 -1
  216. package/dist/list.js +2 -2
  217. package/dist/list.js.map +1 -1
  218. package/dist/marquee.cjs +3 -3
  219. package/dist/marquee.cjs.map +1 -1
  220. package/dist/marquee.js +3 -3
  221. package/dist/marquee.js.map +1 -1
  222. package/dist/menu.cjs +3 -3
  223. package/dist/menu.cjs.map +1 -1
  224. package/dist/menu.js +3 -3
  225. package/dist/menu.js.map +1 -1
  226. package/dist/message-composer.cjs +10 -10
  227. package/dist/message-composer.cjs.map +1 -1
  228. package/dist/message-composer.js +7 -7
  229. package/dist/message-composer.js.map +1 -1
  230. package/dist/navbar.cjs +10 -10
  231. package/dist/navbar.cjs.map +1 -1
  232. package/dist/navbar.js +13 -13
  233. package/dist/navbar.js.map +1 -1
  234. package/dist/number-input.cjs +3 -3
  235. package/dist/number-input.cjs.map +1 -1
  236. package/dist/number-input.js +4 -4
  237. package/dist/number-input.js.map +1 -1
  238. package/dist/otp-input.cjs +4 -4
  239. package/dist/otp-input.cjs.map +1 -1
  240. package/dist/otp-input.js +4 -4
  241. package/dist/otp-input.js.map +1 -1
  242. package/dist/overlay/dialog/dialog.d.ts +7 -4
  243. package/dist/overlay/dialog/dialog.d.ts.map +1 -1
  244. package/dist/overlay/drawer/drawer.d.ts +4 -2
  245. package/dist/overlay/drawer/drawer.d.ts.map +1 -1
  246. package/dist/overlay/menu/menu.d.ts +2 -1
  247. package/dist/overlay/menu/menu.d.ts.map +1 -1
  248. package/dist/pagination.cjs +9 -9
  249. package/dist/pagination.cjs.map +1 -1
  250. package/dist/pagination.js +9 -9
  251. package/dist/pagination.js.map +1 -1
  252. package/dist/qr-code.cjs +2 -2
  253. package/dist/qr-code.cjs.map +1 -1
  254. package/dist/qr-code.js +2 -2
  255. package/dist/qr-code.js.map +1 -1
  256. package/dist/query-bar.cjs +7 -7
  257. package/dist/query-bar.cjs.map +1 -1
  258. package/dist/query-bar.js +8 -8
  259. package/dist/query-bar.js.map +1 -1
  260. package/dist/radio-group.cjs +1 -1
  261. package/dist/radio-group.cjs.map +1 -1
  262. package/dist/radio-group.js +1 -1
  263. package/dist/radio-group.js.map +1 -1
  264. package/dist/refine.cjs +123 -123
  265. package/dist/refine.cjs.map +1 -1
  266. package/dist/refine.iife.js +123 -123
  267. package/dist/refine.iife.js.map +1 -1
  268. package/dist/refine.js +124 -124
  269. package/dist/refine.js.map +1 -1
  270. package/dist/select.cjs +13 -13
  271. package/dist/select.cjs.map +1 -1
  272. package/dist/select.js +15 -15
  273. package/dist/select.js.map +1 -1
  274. package/dist/separator.cjs +4 -4
  275. package/dist/separator.cjs.map +1 -1
  276. package/dist/separator.js +4 -4
  277. package/dist/separator.js.map +1 -1
  278. package/dist/shared/prop-bundles.cjs +1 -1
  279. package/dist/shared/prop-bundles.cjs.map +1 -1
  280. package/dist/shared/prop-bundles.d.ts +7 -8
  281. package/dist/shared/prop-bundles.d.ts.map +1 -1
  282. package/dist/shared/prop-bundles.js +1 -1
  283. package/dist/shared/prop-bundles.js.map +1 -1
  284. package/dist/shared/types.cjs +2 -0
  285. package/dist/shared/types.cjs.map +1 -0
  286. package/dist/shared/types.d.ts +27 -9
  287. package/dist/shared/types.d.ts.map +1 -1
  288. package/dist/shared/types.js +2 -0
  289. package/dist/shared/types.js.map +1 -0
  290. package/dist/sidebar.cjs +7 -7
  291. package/dist/sidebar.cjs.map +1 -1
  292. package/dist/sidebar.js +4 -4
  293. package/dist/sidebar.js.map +1 -1
  294. package/dist/step.cjs +10 -10
  295. package/dist/step.cjs.map +1 -1
  296. package/dist/step.js +10 -10
  297. package/dist/step.js.map +1 -1
  298. package/dist/tab-item.cjs +4 -4
  299. package/dist/tab-item.cjs.map +1 -1
  300. package/dist/tab-item.js +5 -5
  301. package/dist/tab-item.js.map +1 -1
  302. package/dist/table.cjs +2 -2
  303. package/dist/table.cjs.map +1 -1
  304. package/dist/table.js +2 -2
  305. package/dist/table.js.map +1 -1
  306. package/dist/tabs.cjs +2 -2
  307. package/dist/tabs.cjs.map +1 -1
  308. package/dist/tabs.js +4 -4
  309. package/dist/tabs.js.map +1 -1
  310. package/dist/text.cjs +2 -2
  311. package/dist/text.cjs.map +1 -1
  312. package/dist/text.js +2 -2
  313. package/dist/text.js.map +1 -1
  314. package/dist/textarea.cjs +7 -7
  315. package/dist/textarea.cjs.map +1 -1
  316. package/dist/textarea.js +7 -7
  317. package/dist/textarea.js.map +1 -1
  318. package/dist/time-picker.cjs +7 -7
  319. package/dist/time-picker.cjs.map +1 -1
  320. package/dist/time-picker.js +7 -7
  321. package/dist/time-picker.js.map +1 -1
  322. package/dist/tooltip.cjs +1 -1
  323. package/dist/tooltip.cjs.map +1 -1
  324. package/dist/tooltip.js +1 -1
  325. package/dist/tooltip.js.map +1 -1
  326. package/package.json +13 -13
package/dist/query-bar.js CHANGED
@@ -1,4 +1,4 @@
1
- import{dispatchNativeFieldEvent as e}from"./inputs/shared/native-field-event.js";import{reducedMotionMixin as t}from"./styles/mixins/accessibility.css.js";import{roundedVariantMixin as n}from"./styles/mixins/shape.css.js";import{colorThemeMixin as r}from"./styles/mixins/theme.css.js";import{setAriaReflection as i}from"./core/aria-reflection.js";import{lifecycleSignal as a}from"./core/ore.js";import{createListboxDropdown as o}from"./core/option-list.js";import{CHIP_TAG as s}from"./chip.js";import{INPUT_TAG as c}from"./input.js";import l from"./inputs/query-bar/query-bar.css.js";import{commitToken as u,hasQueryFilters as d,parseQuery as f,removeToken as p,suggestQuery as m,tokenValue as h}from"./inputs/query-bar/query-bar-grammar.js";import{computed as g,signal as _}from"@vielzeug/ripple";import{bind as v,createId as y,define as b,getHost as x,html as S,onCleanup as C,onElement as w,onMounted as T,prop as E,ref as D,useEmit as O,watchEffect as k}from"@vielzeug/ore";var A=36,j=`ore-query-bar`;b(j,{props:{clearable:E.bool(!1),disabled:E.bool(!1),error:E.string(),helper:E.string(),"hide-label":E.bool(!1),label:E.string(),placeholder:E.string(),rounded:E.string(),size:E.string(),state:E.data(),variant:E.string(),vocabulary:E.data()},setup(t){let n=x(),r=O(),s=k,c=a(C),l=y(`query-bar`),vocabulary=()=>t.vocabulary.value??[],emptyState=()=>({text:``,tokens:[]}),normalizeState=e=>{if(e==null)return emptyState();if(typeof e!=`object`||!Array.isArray(e.tokens))return null;let t=e;return{text:typeof t.text==`string`?t.text:``,tokens:t.tokens}},d=_(normalizeState(t.state.value)??emptyState()),h=_(d.value.text),b=g(()=>m(h.value,vocabulary())),E=g(()=>new Map(vocabulary().map(e=>[e.key,e]))),j=g(()=>{let e=f(h.value,vocabulary()).draft;return e!==null&&e.valuePrefix!==``&&b.value.length===0}),M=g(()=>{let e=f(h.value,vocabulary()).draft;return`No matching ${(e?E.value.get(e.key):void 0)?.label??e?.key??``} — searching as text`}),N=null,P=null,F=null,I=D(),L=o({getBoundary:()=>n,getFocusedOptionElement:()=>F?.querySelector(`[data-focused]`)??null,getItems:()=>b.value,getOptionId:e=>`${l}-opt-${e}`,getPanel:()=>F,getReference:()=>P,getTrigger:()=>N,isDisabled:()=>!!t.disabled.value,isItemDisabled:()=>!1,onClose:e=>r(`open-change`,{open:!1,reason:e}),onOpen:e=>r(`open-change`,{open:!0,reason:e}),positioning:{matchWidth:!1},restoreFocus:!1,signal:c}),{focusedIndex:R,isOpen:z}=L;v({attr:{open:()=>z.value?!0:void 0,size:t.size,variant:t.variant}}),Object.defineProperty(n,"state",{configurable:!0,enumerable:!0,get:()=>d.value,set:e=>{let t=normalizeState(e);t!==null&&t.tokens!==d.value.tokens&&(d.value=t,h.value=t.text)}});function emitChange(){e(n,`input`),e(n,`change`)}function commit(e){d.value=e,emitChange()}function mergeTokens(e,t){let n=e;for(let e of t){let t=n.findIndex(t=>t.key===e.key);n=t>=0?[...n.slice(0,t),e,...n.slice(t+1)]:[...n,e]}return n}function applyField(){let e=f(h.value,vocabulary());e.tokens.length>0&&(h.value=e.text),commit({text:e.text,tokens:mergeTokens(d.value.tokens,e.tokens)})}function handleInput(e){h.value=e.target.value,applyField(),canOpen()&&L.open(`keyboard`)}function pick(e){let t=/\s$/.test(h.value)||h.value.trim()===``?``:h.value.replace(/\S+\s*$/,``).trim();e.kind===`key`?(h.value=t?`${t} ${e.key}:`:`${e.key}:`,applyField()):(h.value=t,commit(u({text:t,tokens:d.value.tokens},e.key,e.value))),N?.focus()}function removeChip(e){e.stopPropagation();let t=e.detail?.value;t!==void 0&&(commit(p(d.value,t)),N?.focus())}function clearText(){h.value=``,commit({text:``,tokens:d.value.tokens}),N?.focus()}function handleKeydown(e){if(!t.disabled.value&&!L.handleKeydown(e))switch(e.key){case`Enter`:{let t=z.value?b.value[R.value]:void 0;t&&(e.preventDefault(),pick(t));break}case`Backspace`:if(h.value===``&&d.value.tokens.length>0){let e=d.value.tokens[d.value.tokens.length-1];e&&commit(p(d.value,e.key))}break;case`Tab`:L.close(`programmatic`)}}let canOpen=()=>b.value.length>0||j.value,openDropdown=()=>{canOpen()&&L.open(`focus`)};s(()=>{z.value&&!canOpen()&&L.close(`programmatic`)});function handleFocusOut(e){let t=e.relatedTarget;if(t instanceof Node&&n.shadowRoot?.contains(t))return;let r=f(h.value,vocabulary());if(r.draft){if(r.draft.valuePrefix===``){h.value=r.text;return}if(m(h.value,vocabulary()).length===0){let e=r.text?`${r.text} ${r.draft.key}:${r.draft.valuePrefix}`:`${r.draft.key}:${r.draft.valuePrefix}`;h.value=e,commit({text:e,tokens:d.value.tokens})}}}s(()=>{b.value,L.isOpen.value&&L.set(-1)}),s(()=>{z.value?(F&&`showPopover`in F&&!F.matches(`:popover-open`)&&F.showPopover(),L.updatePosition()):F&&`hidePopover`in F&&F.matches(`:popover-open`)&&F.hidePopover()}),w(I,e=>{P=e;let t=e.shadowRoot?.querySelector(`input`)??null;if(t)return N=t,t.setAttribute(`role`,`combobox`),t.setAttribute(`autocomplete`,`off`),t.setAttribute(`aria-autocomplete`,`list`),t.setAttribute(`aria-haspopup`,`listbox`),t.setAttribute(`spellcheck`,`false`),t.setAttribute(`aria-keyshortcuts`,`Backspace`),t.addEventListener(`input`,handleInput),t.addEventListener(`keydown`,handleKeydown),t.addEventListener(`focus`,openDropdown),t.addEventListener(`focusout`,handleFocusOut),()=>{N=null,P=null,t.removeEventListener(`input`,handleInput),t.removeEventListener(`keydown`,handleKeydown),t.removeEventListener(`focus`,openDropdown),t.removeEventListener(`focusout`,handleFocusOut)}}),T(()=>{let e=n.shadowRoot?.querySelector(`[role="listbox"]`);N&&i(N,`ariaControlsElements`,e?[e]:[])}),s(()=>{if(!I.value||!N)return;N.setAttribute(`aria-expanded`,String(z.value));let e=n.shadowRoot?.querySelector(`[role="listbox"]`);i(N,`ariaControlsElements`,e?[e]:[]);let r=L.ariaActiveDescendant.value,a=r?[...F?.querySelectorAll(`[role="option"]`)??[]].find(e=>e.id===r):null;i(N,`ariaActiveDescendantElement`,a?.id===r?[a]:[]),t.disabled.value?N.setAttribute(`aria-disabled`,`true`):N.removeAttribute(`aria-disabled`),t.error.value?N.setAttribute(`aria-invalid`,`true`):N.removeAttribute(`aria-invalid`)}),s(()=>{I.value&&N&&N.value!==h.value&&(N.value=h.value)}),C(()=>{L[Symbol.dispose]()});let hideLabel=()=>t[`hide-label`].value,inputLabel=()=>hideLabel()?``:t.label.value??``,inputAriaLabel=()=>hideLabel()?t.label.value??``:null,pillLabel=e=>{let t=E.value.get(e.key),n=t?.options.find(t=>t.value===e.value);return t&&n?`${t.label}: ${n.label}`:`${t?.key??e.key}: ${n?.label??e.value}`},optionMeta=e=>{let t=E.value.get(e.key);return e.kind===`key`?`${e.key}:`:t?.label??e.key};return S`
1
+ import{dispatchNativeFieldEvent as e}from"./inputs/shared/native-field-event.js";import{reducedMotionMixin as t}from"./styles/mixins/accessibility.css.js";import{roundedVariantMixin as n}from"./styles/mixins/shape.css.js";import{colorThemeMixin as r}from"./styles/mixins/theme.css.js";import{setAriaReflection as i}from"./core/aria-reflection.js";import{lifecycleSignal as a}from"./core/ore.js";import{createListboxDropdown as o}from"./core/option-list.js";import{COMPONENT_SIZES as s,ROUNDED_SIZES as c}from"./shared/types.js";import{CHIP_TAG as l}from"./chip.js";import{INPUT_TAG as u}from"./input.js";import d from"./inputs/query-bar/query-bar.css.js";import{commitToken as f,hasQueryFilters as p,parseQuery as m,removeToken as h,suggestQuery as g,tokenValue as _}from"./inputs/query-bar/query-bar-grammar.js";import{computed as v,signal as y}from"@vielzeug/ripple";import{bind as b,createId as x,define as S,getHost as C,html as w,onCleanup as T,onElement as E,onMounted as D,prop as O,ref as k,useEmit as A,watchEffect as j}from"@vielzeug/ore";var M=36,N=[`flat`,`solid`,`bordered`,`outline`,`ghost`],P=`ore-query-bar`;S(P,{props:{clearable:O.bool(!1),disabled:O.bool(!1),error:O.string(),helper:O.string(),"hide-label":O.bool(!1),label:O.string(),placeholder:O.string(),rounded:O.oneOf(c),size:O.oneOf(s),state:O.data(),variant:O.oneOf(N),vocabulary:O.data()},setup(t){let n=C(),r=A(),s=j,c=a(T),l=x(`query-bar`),vocabulary=()=>t.vocabulary.value??[],emptyState=()=>({text:``,tokens:[]}),normalizeState=e=>{if(e==null)return emptyState();if(typeof e!=`object`||!Array.isArray(e.tokens))return null;let t=e;return{text:typeof t.text==`string`?t.text:``,tokens:t.tokens}},u=y(normalizeState(t.state.value)??emptyState()),d=y(u.value.text),p=v(()=>g(d.value,vocabulary())),_=v(()=>new Map(vocabulary().map(e=>[e.key,e]))),S=v(()=>{let e=m(d.value,vocabulary()).draft;return e!==null&&e.valuePrefix!==``&&p.value.length===0}),O=v(()=>{let e=m(d.value,vocabulary()).draft;return`No matching ${(e?_.value.get(e.key):void 0)?.label??e?.key??``} — searching as text`}),N=null,P=null,F=null,I=k(),L=o({getBoundary:()=>n,getFocusedOptionElement:()=>F?.querySelector(`[data-focused]`)??null,getItems:()=>p.value,getOptionId:e=>`${l}-opt-${e}`,getPanel:()=>F,getReference:()=>P,getTrigger:()=>N,isDisabled:()=>!!t.disabled.value,isItemDisabled:()=>!1,onClose:e=>r(`open-change`,{open:!1,reason:e}),onOpen:e=>r(`open-change`,{open:!0,reason:e}),positioning:{matchWidth:!1},restoreFocus:!1,signal:c}),{focusedIndex:R,isOpen:z}=L;b({attr:{open:()=>z.value?!0:void 0,size:t.size,variant:t.variant}}),Object.defineProperty(n,"state",{configurable:!0,enumerable:!0,get:()=>u.value,set:e=>{let t=normalizeState(e);t!==null&&t.tokens!==u.value.tokens&&(u.value=t,d.value=t.text)}});function emitChange(){e(n,`input`),e(n,`change`)}function commit(e){u.value=e,emitChange()}function mergeTokens(e,t){let n=e;for(let e of t){let t=n.findIndex(t=>t.key===e.key);n=t>=0?[...n.slice(0,t),e,...n.slice(t+1)]:[...n,e]}return n}function applyField(){let e=m(d.value,vocabulary());e.tokens.length>0&&(d.value=e.text),commit({text:e.text,tokens:mergeTokens(u.value.tokens,e.tokens)})}function handleInput(e){d.value=e.target.value,applyField(),canOpen()&&L.open(`keyboard`)}function pick(e){let t=/\s$/.test(d.value)||d.value.trim()===``?``:d.value.replace(/\S+\s*$/,``).trim();e.kind===`key`?(d.value=t?`${t} ${e.key}:`:`${e.key}:`,applyField()):(d.value=t,commit(f({text:t,tokens:u.value.tokens},e.key,e.value))),N?.focus()}function removeChip(e){e.stopPropagation();let t=e.detail?.value;t!==void 0&&(commit(h(u.value,t)),N?.focus())}function clearText(){d.value=``,commit({text:``,tokens:u.value.tokens}),N?.focus()}function handleKeydown(e){if(!t.disabled.value&&!L.handleKeydown(e))switch(e.key){case`Enter`:{let t=z.value?p.value[R.value]:void 0;t&&(e.preventDefault(),pick(t));break}case`Backspace`:if(d.value===``&&u.value.tokens.length>0){let e=u.value.tokens[u.value.tokens.length-1];e&&commit(h(u.value,e.key))}break;case`Tab`:L.close(`programmatic`)}}let canOpen=()=>p.value.length>0||S.value,openDropdown=()=>{canOpen()&&L.open(`focus`)};s(()=>{z.value&&!canOpen()&&L.close(`programmatic`)});function handleFocusOut(e){let t=e.relatedTarget;if(t instanceof Node&&n.shadowRoot?.contains(t))return;let r=m(d.value,vocabulary());if(r.draft){if(r.draft.valuePrefix===``){d.value=r.text;return}if(g(d.value,vocabulary()).length===0){let e=r.text?`${r.text} ${r.draft.key}:${r.draft.valuePrefix}`:`${r.draft.key}:${r.draft.valuePrefix}`;d.value=e,commit({text:e,tokens:u.value.tokens})}}}s(()=>{p.value,L.isOpen.value&&L.set(-1)}),s(()=>{z.value?(F&&`showPopover`in F&&!F.matches(`:popover-open`)&&F.showPopover(),L.updatePosition()):F&&`hidePopover`in F&&F.matches(`:popover-open`)&&F.hidePopover()}),E(I,e=>{P=e;let t=e.shadowRoot?.querySelector(`input`)??null;if(t)return N=t,t.setAttribute(`role`,`combobox`),t.setAttribute(`autocomplete`,`off`),t.setAttribute(`aria-autocomplete`,`list`),t.setAttribute(`aria-haspopup`,`listbox`),t.setAttribute(`spellcheck`,`false`),t.setAttribute(`aria-keyshortcuts`,`Backspace`),t.addEventListener(`input`,handleInput),t.addEventListener(`keydown`,handleKeydown),t.addEventListener(`focus`,openDropdown),t.addEventListener(`focusout`,handleFocusOut),()=>{N=null,P=null,t.removeEventListener(`input`,handleInput),t.removeEventListener(`keydown`,handleKeydown),t.removeEventListener(`focus`,openDropdown),t.removeEventListener(`focusout`,handleFocusOut)}}),D(()=>{let e=n.shadowRoot?.querySelector(`[role="listbox"]`);N&&i(N,`ariaControlsElements`,e?[e]:[])}),s(()=>{if(!I.value||!N)return;N.setAttribute(`aria-expanded`,String(z.value));let e=n.shadowRoot?.querySelector(`[role="listbox"]`);i(N,`ariaControlsElements`,e?[e]:[]);let r=L.ariaActiveDescendant.value,a=r?[...F?.querySelectorAll(`[role="option"]`)??[]].find(e=>e.id===r):null;i(N,`ariaActiveDescendantElement`,a?.id===r?[a]:[]),t.disabled.value?N.setAttribute(`aria-disabled`,`true`):N.removeAttribute(`aria-disabled`),t.error.value?N.setAttribute(`aria-invalid`,`true`):N.removeAttribute(`aria-invalid`)}),s(()=>{I.value&&N&&N.value!==d.value&&(N.value=d.value)}),T(()=>{L[Symbol.dispose]()});let hideLabel=()=>t[`hide-label`].value,inputLabel=()=>hideLabel()?``:t.label.value??``,inputAriaLabel=()=>hideLabel()?t.label.value??``:null,pillLabel=e=>{let t=_.value.get(e.key),n=t?.options.find(t=>t.value===e.value);return t&&n?`${t.label}: ${n.label}`:`${t?.key??e.key}: ${n?.label??e.value}`},optionMeta=e=>{let t=_.value.get(e.key);return e.kind===`key`?`${e.key}:`:t?.label??e.key};return w`
2
2
  <ore-input
3
3
  class="trigger"
4
4
  ref=${I}
@@ -16,7 +16,7 @@ import{dispatchNativeFieldEvent as e}from"./inputs/shared/native-field-event.js"
16
16
  <div class="prefix" slot="prefix">
17
17
  <ore-icon name="search" size="16" aria-hidden="true"></ore-icon>
18
18
  <span class="pills">
19
- ${()=>d.value.tokens.map(e=>S`
19
+ ${()=>u.value.tokens.map(e=>w`
20
20
  <ore-chip
21
21
  value=${e.key}
22
22
  label=${pillLabel(e)}
@@ -36,7 +36,7 @@ import{dispatchNativeFieldEvent as e}from"./inputs/shared/native-field-event.js"
36
36
  type="button"
37
37
  aria-label="Clear"
38
38
  tabindex="-1"
39
- ?hidden="${()=>!t.clearable.value||h.value===``}"
39
+ ?hidden="${()=>!t.clearable.value||d.value===``}"
40
40
  @click="${clearText}">
41
41
  <ore-icon name="x" size="12" stroke-width="2.5" aria-hidden="true"></ore-icon>
42
42
  </button>
@@ -52,10 +52,10 @@ import{dispatchNativeFieldEvent as e}from"./inputs/shared/native-field-event.js"
52
52
  <div
53
53
  role="listbox"
54
54
  id="${()=>`${l}-listbox`}"
55
- style="${()=>z.value&&canOpen()?`height:${(j.value?1:b.value.length)*A}px;`:``}"
55
+ style="${()=>z.value&&canOpen()?`height:${(S.value?1:p.value.length)*M}px;`:``}"
56
56
  aria-label="${()=>t.label.value||t.placeholder.value||`Suggestions`}">
57
- ${()=>z.value&&j.value?S`<div class="no-match" role="option" aria-selected="false" aria-disabled="true">${M.value}</div>`:``}
58
- ${()=>z.value&&b.value.length>0?b.value.map((e,t)=>S`
57
+ ${()=>z.value&&S.value?w`<div class="no-match" role="option" aria-selected="false" aria-disabled="true">${O.value}</div>`:``}
58
+ ${()=>z.value&&p.value.length>0?p.value.map((e,t)=>w`
59
59
  <div
60
60
  class="option"
61
61
  role="option"
@@ -63,7 +63,7 @@ import{dispatchNativeFieldEvent as e}from"./inputs/shared/native-field-event.js"
63
63
  data-option-index="${t}"
64
64
  aria-selected="false"
65
65
  aria-disabled="false"
66
- style="${`position:absolute;top:0;left:0;right:0;transform:translateY(${t*A}px);`}"
66
+ style="${`position:absolute;top:0;left:0;right:0;transform:translateY(${t*M}px);`}"
67
67
  ?data-focused=${()=>R.value===t}
68
68
  @pointermove="${()=>L.set(t)}"
69
69
  @click="${()=>pick(e)}">
@@ -73,5 +73,5 @@ import{dispatchNativeFieldEvent as e}from"./inputs/shared/native-field-event.js"
73
73
  `):``}
74
74
  </div>
75
75
  </div>
76
- `},shadow:{delegatesFocus:!0},styles:[r,t,n,l]});export{s as CHIP_TAG,c as INPUT_TAG,j as QUERY_BAR_TAG,u as commitToken,d as hasQueryFilters,f as parseQuery,p as removeToken,m as suggestQuery,h as tokenValue};
76
+ `},shadow:{delegatesFocus:!0},styles:[r,t,n,d]});export{l as CHIP_TAG,u as INPUT_TAG,P as QUERY_BAR_TAG,f as commitToken,p as hasQueryFilters,m as parseQuery,h as removeToken,g as suggestQuery,_ as tokenValue};
77
77
  //# sourceMappingURL=query-bar.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"query-bar.js","names":[],"sources":["../src/inputs/query-bar/query-bar.ts"],"sourcesContent":["import {\n bind,\n createId,\n define,\n getHost,\n html,\n onCleanup,\n onElement,\n onMounted,\n prop,\n ref,\n useEmit,\n watchEffect,\n} from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\nimport { createListboxDropdown, lifecycleSignal, setAriaReflection } from '../../core';\nimport { colorThemeMixin, reducedMotionMixin, roundedVariantMixin } from '../../styles';\nimport type { AddEventListeners, ComponentSize, RoundedSize } from '../../types';\nimport { dispatchNativeFieldEvent } from '../shared/native-field-event';\nimport componentStyles from './query-bar.css?inline';\nimport type { OreQueryBarEvents, OreQueryBarProps } from './query-bar.types';\nimport {\n commitToken,\n parseQuery,\n type QueryState,\n type QuerySuggestion,\n type QueryToken,\n type QueryTokenDef,\n removeToken,\n suggestQuery,\n} from './query-bar-grammar';\n\nexport { CHIP_TAG } from '../../feedback/chip/chip';\nexport { INPUT_TAG } from '../input/input';\nexport type { OreQueryBarEvents, OreQueryBarProps } from './query-bar.types';\nexport * from './query-bar-grammar';\n\n/** Fixed row height of one suggestion; the dropdown positions rows against it. */\nconst OPTION_ROW_HEIGHT = 36;\n\n/**\n * A search field that accepts free text and `key:value` tokens together, in the\n * grammar GitHub's pull-request search made familiar. Committed tokens render as\n * removable pills inside the field; a suggestion dropdown lists the vocabulary's\n * keys and matching values while typing, so phones never need to type a colon.\n *\n * The bar is state-driven: `vocabulary` defines the token keys and their accepted\n * values, `state` carries `{ text, tokens }`, and every edit emits `input` +\n * `change` with the new state readable from the element's `state` property. Omit\n * `state` for uncontrolled use. External `state` writes whose `tokens` array is\n * identical to the current one are treated as echoes — only token changes are\n * adopted — so text-only round-trips never wipe the field's live draft.\n *\n * The dropdown opens while the field holds focus (and reopens on typing after\n * Escape) and overlays the page from the top layer. Picking a key suggestion\n * starts composing `key:`; picking a value commits its pill. Typing a complete\n * `key:value` commits immediately. Backspace on an empty field removes the last\n * pill. A draft whose value matches nothing shows a \"searching as text\" row\n * instead of closing; on blur, a bare `key:` fragment reverts and a dead draft\n * degrades into the searched text, so the field never carries silent residue.\n *\n * @element ore-query-bar\n *\n * @attr {string} label - Accessible name for the entry field\n * @attr {string} placeholder - Field placeholder, typically the surface's search hint\n * @attr {string} error - Inline error under the field\n * @attr {string} helper - Helper text under the field\n * @attr {boolean} hide-label - Hide the visible label while keeping its accessible name\n * @attr {boolean} clearable - Show a clear (×) button; it clears the free text only\n * @attr {boolean} disabled - Disable the whole bar\n * @attr {string} size - Field size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Field radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} variant - Field variant: 'flat' | 'solid' | 'bordered' | 'outline' | 'ghost'\n *\n * @prop {QueryState} state - The controlled query state; write a new object to apply external changes\n * @prop {QueryTokenDef[]} vocabulary - The token vocabulary\n *\n * @fires input - The query changed; read the new state from the `state` property\n * @fires change - Same as `input`\n * @fires open-change - The suggestion dropdown opened or closed. detail: { open, reason }\n *\n * @part wrapper - The ore-input field host\n * @part dropdown - The suggestion dropdown container\n * @cssprop --query-bar-min-width - Minimum host width (default 12rem)\n * @cssprop --query-bar-icon-size - Leading search icon size (default 16px)\n * @cssprop --query-bar-option-height - Suggestion row height (default 36px)\n * @cssprop --query-bar-dropdown-min-width - Dropdown panel minimum width (default 16rem)\n * @cssprop --query-bar-dropdown-max-width - Dropdown panel maximum width (default 28rem, viewport-capped)\n * @cssprop --chip-* - Pill styling (see ore-chip)\n * @cssprop --combobox-dropdown-* - Dropdown panel and option styling (see ore-combobox)\n *\n * @example\n * ```html\n * <ore-query-bar id=\"bar\" label=\"Search issues\" placeholder=\"Title, author or label…\" clearable>\n * </ore-query-bar>\n * <script>\n * bar.vocabulary = [\n * { key: 'author', label: 'Author', options: [{ label: 'Alice', value: 'alice' }] },\n * ];\n * </script>\n * ```\n */\nexport const QUERY_BAR_TAG = 'ore-query-bar' as const;\ndefine<OreQueryBarProps>(QUERY_BAR_TAG, {\n props: {\n clearable: prop.bool(false),\n disabled: prop.bool(false),\n error: prop.string(),\n helper: prop.string(),\n 'hide-label': prop.bool(false),\n label: prop.string(),\n placeholder: prop.string(),\n rounded: prop.string<RoundedSize>(),\n size: prop.string<ComponentSize>(),\n state: prop.data<QueryState>(),\n variant: prop.string<'flat' | 'solid' | 'bordered' | 'outline' | 'ghost'>(),\n vocabulary: prop.data<QueryTokenDef[]>(),\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreQueryBarEvents>();\n const watch = watchEffect;\n const abortSignal = lifecycleSignal(onCleanup);\n const barId = createId('query-bar');\n\n const vocabulary = (): QueryTokenDef[] => props.vocabulary.value ?? [];\n const emptyState = (): QueryState => ({ text: '', tokens: [] });\n const normalizeState = (value: unknown): QueryState | null => {\n if (value == null) return emptyState();\n if (typeof value !== 'object' || !Array.isArray((value as QueryState).tokens)) return null;\n const state = value as QueryState;\n return { text: typeof state.text === 'string' ? state.text : '', tokens: state.tokens };\n };\n\n /**\n * The working state: the initial `state` prop plus every commit this bar emits\n * before the consumer round-trips it. Gestures must read from here, never from\n * the prop directly: props lag a render behind, so two quick pill removals\n * would otherwise each compute from the same stale snapshot and the second\n * would resurrect the first pill.\n */\n const working = signal<QueryState>(normalizeState(props.state.value) ?? emptyState());\n /** What the field shows: the live draft (free text plus an unfinished token). */\n const field = signal(working.value.text);\n\n const suggestions = computed<QuerySuggestion[]>(() => suggestQuery(field.value, vocabulary()));\n const defBy = computed(() => new Map(vocabulary().map((def) => [def.key, def])));\n\n /**\n * True while the draft names a known key whose prefix matches no option. The\n * dropdown then shows a \"searching as text\" row instead of closing, so the\n * degradation is never silent — and blur makes the state honest (below).\n */\n const noMatch = computed(() => {\n const draft = parseQuery(field.value, vocabulary()).draft;\n return draft !== null && draft.valuePrefix !== '' && suggestions.value.length === 0;\n });\n\n const noMatchLabel = computed(() => {\n const draft = parseQuery(field.value, vocabulary()).draft;\n const def = draft ? defBy.value.get(draft.key) : undefined;\n return `No matching ${def?.label ?? draft?.key ?? ''} — searching as text`;\n });\n\n // Element refs the listbox dropdown needs; resolved as the template renders.\n let inputEl: HTMLInputElement | null = null;\n let fieldEl: HTMLElement | null = null;\n let dropdownEl: HTMLElement | null = null;\n const inputRef = ref<HTMLElement>();\n\n const optionList = createListboxDropdown<QuerySuggestion>({\n getBoundary: () => el,\n getFocusedOptionElement: () => dropdownEl?.querySelector<HTMLElement>('[data-focused]') ?? null,\n getItems: () => suggestions.value,\n getOptionId: (index) => `${barId}-opt-${index}`,\n getPanel: () => dropdownEl,\n getReference: () => fieldEl,\n getTrigger: () => inputEl,\n isDisabled: () => Boolean(props.disabled.value),\n isItemDisabled: () => false,\n onClose: (reason) => emit('open-change', { open: false, reason }),\n onOpen: (reason) => emit('open-change', { open: true, reason }),\n // The reference is the whole (often full-row) field: matching its width would\n // stretch the panel across the page. The dropdown sizes to its content within\n // its own min/max bounds instead, like a menu.\n positioning: { matchWidth: false },\n restoreFocus: false,\n signal: abortSignal,\n });\n const { focusedIndex, isOpen } = optionList;\n\n bind({\n attr: {\n open: () => (isOpen.value ? true : undefined),\n size: props.size,\n variant: props.variant,\n },\n });\n\n // Expose the working state as a native-like `.state` property on the host: the\n // live external channel, replacing the prop-installed property exactly as\n // ore-combobox replaces its own `value`. Writes whose `tokens` array matches\n // the working one are consumer echoes (v-model round-trips) and keep the\n // field's live draft; a changed tokens array is an external write — a deep-link\n // preset, a mode switch — and is adopted, field included.\n Object.defineProperty(el, 'state', {\n configurable: true,\n enumerable: true,\n get: () => working.value,\n set: (value: unknown) => {\n const next = normalizeState(value);\n if (next === null || next.tokens === working.value.tokens) return;\n working.value = next;\n field.value = next.text;\n },\n });\n\n // ── State commits ────────────────────────────────────────────────────────\n\n function emitChange(): void {\n dispatchNativeFieldEvent(el, 'input');\n dispatchNativeFieldEvent(el, 'change');\n }\n\n /** Applies the next state locally and announces it; the consumer reads `el.state`. */\n function commit(next: QueryState): void {\n working.value = next;\n emitChange();\n }\n\n /** Folds parsed tokens into the working set, replacing per key and keeping slots. */\n function mergeTokens(base: QueryToken[], parsed: readonly QueryToken[]): QueryToken[] {\n let tokens = base;\n for (const token of parsed) {\n const slot = tokens.findIndex((candidate) => candidate.key === token.key);\n tokens = slot >= 0 ? [...tokens.slice(0, slot), token, ...tokens.slice(slot + 1)] : [...tokens, token];\n }\n return tokens;\n }\n\n /** Parses the field, folds any complete tokens into the working state, and commits. */\n function applyField(): void {\n const parsed = parseQuery(field.value, vocabulary());\n if (parsed.tokens.length > 0) field.value = parsed.text;\n commit({ text: parsed.text, tokens: mergeTokens(working.value.tokens, parsed.tokens) });\n }\n\n function handleInput(event: Event): void {\n field.value = (event.target as HTMLInputElement).value;\n applyField();\n // Typing is the strongest composing signal: the dropdown must come back after\n // Escape without a blur/refocus cycle, or the bar reads as broken.\n if (canOpen()) optionList.open('keyboard');\n }\n\n function pick(suggestion: QuerySuggestion): void {\n // The word being typed is selector intent: whichever suggestion is picked consumes\n // it, so it never leaks into the free text as a stray search term. A field ending\n // in whitespace has no active word; a `key:…` draft is consumed like any word.\n const rest =\n /\\s$/.test(field.value) || field.value.trim() === '' ? '' : field.value.replace(/\\S+\\s*$/, '').trim();\n if (suggestion.kind === 'key') {\n // Start composing: replace the word being typed with the token key.\n field.value = rest ? `${rest} ${suggestion.key}:` : `${suggestion.key}:`;\n applyField();\n } else {\n field.value = rest;\n commit(commitToken({ text: rest, tokens: working.value.tokens }, suggestion.key, suggestion.value));\n }\n inputEl?.focus();\n }\n\n function removeChip(event: Event): void {\n event.stopPropagation();\n const key = (event as CustomEvent<{ value?: string }>).detail?.value;\n if (key === undefined) return;\n commit(removeToken(working.value, key));\n // Keep the compose flow: without this, focus falls to the host and the next\n // keystroke goes nowhere.\n inputEl?.focus();\n }\n\n /** The field's own clear button: clears the free text, never the pills. */\n function clearText(): void {\n field.value = '';\n commit({ text: '', tokens: working.value.tokens });\n inputEl?.focus();\n }\n\n function handleKeydown(e: KeyboardEvent): void {\n if (props.disabled.value) return;\n\n // While open, the listbox owns arrows, Home/End, and Escape.\n if (optionList.handleKeydown(e)) return;\n\n switch (e.key) {\n case 'Enter': {\n const active = isOpen.value ? suggestions.value[focusedIndex.value] : undefined;\n if (active) {\n e.preventDefault();\n pick(active);\n }\n break;\n }\n case 'Backspace':\n // The GitHub-style touch: backspace on an empty field drops the last pill.\n if (field.value === '' && working.value.tokens.length > 0) {\n const last = working.value.tokens[working.value.tokens.length - 1];\n if (last) commit(removeToken(working.value, last.key));\n }\n break;\n case 'Tab':\n optionList.close('programmatic');\n break;\n default:\n break;\n }\n }\n\n // The dropdown is open exactly while the field holds focus and has something to\n // show — suggestions, or the no-match row for an unresolvable draft; Escape,\n // outside pointers, and Tab dismiss it through the machinery.\n const canOpen = (): boolean => suggestions.value.length > 0 || noMatch.value;\n const openDropdown = (): void => {\n if (canOpen()) optionList.open('focus');\n };\n watch(() => {\n if (isOpen.value && !canOpen()) optionList.close('programmatic');\n });\n\n /**\n * Blur makes the field honest about dead drafts. A bare `key:` fragment is dead\n * syntax — revert it, leaving no residue. A draft that matches nothing was\n * already announced as \"searching as text\" — degrade it into the text so what\n * the field shows is what is searched. Live compositions (a draft with matching\n * suggestions) survive blur, so an interrupted pick resumes on refocus.\n */\n function handleFocusOut(event: FocusEvent): void {\n const next = event.relatedTarget;\n if (next instanceof Node && el.shadowRoot?.contains(next)) return;\n\n const parsed = parseQuery(field.value, vocabulary());\n if (!parsed.draft) return;\n if (parsed.draft.valuePrefix === '') {\n field.value = parsed.text;\n return;\n }\n if (suggestQuery(field.value, vocabulary()).length === 0) {\n const degraded = parsed.text\n ? `${parsed.text} ${parsed.draft.key}:${parsed.draft.valuePrefix}`\n : `${parsed.draft.key}:${parsed.draft.valuePrefix}`;\n field.value = degraded;\n commit({ text: degraded, tokens: working.value.tokens });\n }\n }\n\n // New suggestions start from no highlight; arrows move it, Enter commits it.\n watch(() => {\n void suggestions.value;\n if (optionList.isOpen.value) optionList.set(-1);\n });\n\n // The dropdown is popover=manual: without showPopover the UA stylesheet keeps it\n // display:none, so the panel must enter the top layer exactly when it opens.\n watch(() => {\n if (isOpen.value) {\n if (dropdownEl && 'showPopover' in dropdownEl && !dropdownEl.matches(':popover-open')) {\n dropdownEl.showPopover();\n }\n optionList.updatePosition();\n } else if (dropdownEl && 'hidePopover' in dropdownEl && dropdownEl.matches(':popover-open')) {\n dropdownEl.hidePopover();\n }\n });\n\n // Once ore-input is in the DOM, grab its inner <input> from its shadow root and\n // attach the query-bar's ARIA and event handlers imperatively (the combobox\n // pattern: the focused element must carry the combobox semantics itself).\n onElement(inputRef, (bitInputEl) => {\n fieldEl = bitInputEl;\n\n const rawInput = bitInputEl.shadowRoot?.querySelector<HTMLInputElement>('input') ?? null;\n if (!rawInput) return;\n\n inputEl = rawInput;\n\n rawInput.setAttribute('role', 'combobox');\n rawInput.setAttribute('autocomplete', 'off');\n rawInput.setAttribute('aria-autocomplete', 'list');\n rawInput.setAttribute('aria-haspopup', 'listbox');\n rawInput.setAttribute('spellcheck', 'false');\n // Backspace on the empty field drops the last pill: the only discoverability\n // of that shortcut for assistive tech.\n rawInput.setAttribute('aria-keyshortcuts', 'Backspace');\n\n rawInput.addEventListener('input', handleInput as EventListener);\n rawInput.addEventListener('keydown', handleKeydown as EventListener);\n rawInput.addEventListener('focus', openDropdown);\n rawInput.addEventListener('focusout', handleFocusOut as EventListener);\n\n return () => {\n inputEl = null;\n fieldEl = null;\n rawInput.removeEventListener('input', handleInput as EventListener);\n rawInput.removeEventListener('keydown', handleKeydown as EventListener);\n rawInput.removeEventListener('focus', openDropdown);\n rawInput.removeEventListener('focusout', handleFocusOut as EventListener);\n };\n });\n\n onMounted(() => {\n const listbox = el.shadowRoot?.querySelector<HTMLElement>('[role=\"listbox\"]');\n if (inputEl) setAriaReflection(inputEl, 'ariaControlsElements', listbox ? [listbox] : []);\n });\n\n // Reactively sync combobox-specific ARIA the field does not manage itself.\n watch(() => {\n if (!inputRef.value || !inputEl) return;\n\n inputEl.setAttribute('aria-expanded', String(isOpen.value));\n\n const listbox = el.shadowRoot?.querySelector<HTMLElement>('[role=\"listbox\"]');\n setAriaReflection(inputEl, 'ariaControlsElements', listbox ? [listbox] : []);\n const activeId = optionList.ariaActiveDescendant.value;\n const activeOption = activeId\n ? [...(dropdownEl?.querySelectorAll<HTMLElement>('[role=\"option\"]') ?? [])].find(\n (option) => option.id === activeId,\n )\n : null;\n setAriaReflection(inputEl, 'ariaActiveDescendantElement', activeOption?.id === activeId ? [activeOption] : []);\n\n if (props.disabled.value) inputEl.setAttribute('aria-disabled', 'true');\n else inputEl.removeAttribute('aria-disabled');\n\n if (props.error.value) inputEl.setAttribute('aria-invalid', 'true');\n else inputEl.removeAttribute('aria-invalid');\n });\n\n // Reactively sync the field signal into the raw input value.\n watch(() => {\n if (!inputRef.value || !inputEl) return;\n if (inputEl.value !== field.value) inputEl.value = field.value;\n });\n\n onCleanup(() => {\n optionList[Symbol.dispose]();\n });\n\n // When hide-label is set, suppress the visible label passed to ore-input (no inset\n // label renders, avoiding extra field height) but expose the label text as\n // aria-label on the input so the bar retains its accessible name.\n const hideLabel = () => props['hide-label'].value;\n const inputLabel = () => (hideLabel() ? '' : (props.label.value ?? ''));\n const inputAriaLabel = () => (hideLabel() ? (props.label.value ?? '') : null);\n\n /** Pill copy: `Author: Alice`, degrading to the raw key/value outside the vocabulary. */\n const pillLabel = (token: QueryToken): string => {\n const def = defBy.value.get(token.key);\n const option = def?.options.find((candidate) => candidate.value === token.value);\n if (def && option) return `${def.label}: ${option.label}`;\n return `${def?.key ?? token.key}: ${option?.label ?? token.value}`;\n };\n\n /** The muted second column: the token key for value rows, the `key:` syntax for key rows. */\n const optionMeta = (suggestion: QuerySuggestion): string => {\n const def = defBy.value.get(suggestion.key);\n return suggestion.kind === 'key' ? `${suggestion.key}:` : (def?.label ?? suggestion.key);\n };\n\n return html`\n <ore-input\n class=\"trigger\"\n ref=${inputRef}\n label=\"${inputLabel}\"\n aria-label=\"${inputAriaLabel}\"\n placeholder=\"${() => props.placeholder.value ?? ''}\"\n label-placement=\"inset\"\n variant=\"${() => props.variant.value ?? 'bordered'}\"\n size=\"${() => props.size.value ?? ''}\"\n rounded=\"${() => props.rounded.value ?? 'md'}\"\n helper=\"${() => props.helper.value ?? ''}\"\n error=\"${() => props.error.value ?? ''}\"\n ?disabled=\"${() => Boolean(props.disabled.value)}\"\n part=\"wrapper\">\n <div class=\"prefix\" slot=\"prefix\">\n <ore-icon name=\"search\" size=\"16\" aria-hidden=\"true\"></ore-icon>\n <span class=\"pills\">\n ${() =>\n working.value.tokens.map(\n (token) => html`\n <ore-chip\n value=${token.key}\n label=${pillLabel(token)}\n mode=\"removable\"\n variant=\"flat\"\n size=\"sm\"\n @remove=${removeChip}>\n ${pillLabel(token)}\n </ore-chip>\n `,\n )}\n </span>\n </div>\n <span class=\"suffix\" slot=\"suffix\">\n <button\n class=\"clear-btn\"\n part=\"clear-btn\"\n type=\"button\"\n aria-label=\"Clear\"\n tabindex=\"-1\"\n ?hidden=\"${() => !props.clearable.value || field.value === ''}\"\n @click=\"${clearText}\">\n <ore-icon name=\"x\" size=\"12\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n </button>\n </span>\n </ore-input>\n <div\n class=\"dropdown\"\n part=\"dropdown\"\n id=\"${() => `${barId}-dropdown`}\"\n popover=\"manual\"\n ?data-open=${() => isOpen.value}\n ref=${(node: HTMLElement | null) => {\n dropdownEl = node;\n }}>\n <div\n role=\"listbox\"\n id=\"${() => `${barId}-listbox`}\"\n style=\"${() => (isOpen.value && canOpen() ? `height:${(noMatch.value ? 1 : suggestions.value.length) * OPTION_ROW_HEIGHT}px;` : '')}\"\n aria-label=\"${() => props.label.value || props.placeholder.value || 'Suggestions'}\">\n ${() =>\n isOpen.value && noMatch.value\n ? html`<div class=\"no-match\" role=\"option\" aria-selected=\"false\" aria-disabled=\"true\">${noMatchLabel.value}</div>`\n : ''}\n ${() =>\n isOpen.value && suggestions.value.length > 0\n ? suggestions.value.map(\n (suggestion, index) => html`\n <div\n class=\"option\"\n role=\"option\"\n id=\"${`${barId}-opt-${index}`}\"\n data-option-index=\"${index}\"\n aria-selected=\"false\"\n aria-disabled=\"false\"\n style=\"${`position:absolute;top:0;left:0;right:0;transform:translateY(${index * OPTION_ROW_HEIGHT}px);`}\"\n ?data-focused=${() => focusedIndex.value === index}\n @pointermove=\"${() => optionList.set(index)}\"\n @click=\"${() => pick(suggestion)}\">\n <span class=\"option-label\">${suggestion.label}</span>\n <span class=\"option-meta\">${optionMeta(suggestion)}</span>\n </div>\n `,\n )\n : ''}\n </div>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [colorThemeMixin, reducedMotionMixin, roundedVariantMixin, componentStyles],\n}) as unknown as AddEventListeners<OreQueryBarEvents>;\n"],"mappings":"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"}
1
+ {"version":3,"file":"query-bar.js","names":[],"sources":["../src/inputs/query-bar/query-bar.ts"],"sourcesContent":["import {\n bind,\n createId,\n define,\n getHost,\n html,\n onCleanup,\n onElement,\n onMounted,\n prop,\n ref,\n useEmit,\n watchEffect,\n} from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\nimport { createListboxDropdown, lifecycleSignal, setAriaReflection } from '../../core';\nimport { colorThemeMixin, reducedMotionMixin, roundedVariantMixin } from '../../styles';\nimport { type AddEventListeners, COMPONENT_SIZES, ROUNDED_SIZES } from '../../types';\nimport { dispatchNativeFieldEvent } from '../shared/native-field-event';\nimport componentStyles from './query-bar.css?inline';\nimport type { OreQueryBarEvents, OreQueryBarProps } from './query-bar.types';\nimport {\n commitToken,\n parseQuery,\n type QueryState,\n type QuerySuggestion,\n type QueryToken,\n type QueryTokenDef,\n removeToken,\n suggestQuery,\n} from './query-bar-grammar';\n\nexport { CHIP_TAG } from '../../feedback/chip/chip';\nexport { INPUT_TAG } from '../input/input';\nexport type { OreQueryBarEvents, OreQueryBarProps } from './query-bar.types';\nexport * from './query-bar-grammar';\n\n/** Fixed row height of one suggestion; the dropdown positions rows against it. */\nconst OPTION_ROW_HEIGHT = 36;\nconst QUERY_BAR_VARIANTS = ['flat', 'solid', 'bordered', 'outline', 'ghost'] as const;\n\n/**\n * A search field that accepts free text and `key:value` tokens together, in the\n * grammar GitHub's pull-request search made familiar. Committed tokens render as\n * removable pills inside the field; a suggestion dropdown lists the vocabulary's\n * keys and matching values while typing, so phones never need to type a colon.\n *\n * The bar is state-driven: `vocabulary` defines the token keys and their accepted\n * values, `state` carries `{ text, tokens }`, and every edit emits `input` +\n * `change` with the new state readable from the element's `state` property. Omit\n * `state` for uncontrolled use. External `state` writes whose `tokens` array is\n * identical to the current one are treated as echoes — only token changes are\n * adopted — so text-only round-trips never wipe the field's live draft.\n *\n * The dropdown opens while the field holds focus (and reopens on typing after\n * Escape) and overlays the page from the top layer. Picking a key suggestion\n * starts composing `key:`; picking a value commits its pill. Typing a complete\n * `key:value` commits immediately. Backspace on an empty field removes the last\n * pill. A draft whose value matches nothing shows a \"searching as text\" row\n * instead of closing; on blur, a bare `key:` fragment reverts and a dead draft\n * degrades into the searched text, so the field never carries silent residue.\n *\n * @element ore-query-bar\n *\n * @attr {string} label - Accessible name for the entry field\n * @attr {string} placeholder - Field placeholder, typically the surface's search hint\n * @attr {string} error - Inline error under the field\n * @attr {string} helper - Helper text under the field\n * @attr {boolean} hide-label - Hide the visible label while keeping its accessible name\n * @attr {boolean} clearable - Show a clear (×) button; it clears the free text only\n * @attr {boolean} disabled - Disable the whole bar\n * @attr {string} size - Field size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Field radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} variant - Field variant: 'flat' | 'solid' | 'bordered' | 'outline' | 'ghost'\n *\n * @prop {QueryState} state - The controlled query state; write a new object to apply external changes\n * @prop {QueryTokenDef[]} vocabulary - The token vocabulary\n *\n * @fires input - The query changed; read the new state from the `state` property\n * @fires change - Same as `input`\n * @fires open-change - The suggestion dropdown opened or closed. detail: { open, reason }\n *\n * @part wrapper - The ore-input field host\n * @part dropdown - The suggestion dropdown container\n * @cssprop --query-bar-min-width - Minimum host width (default 12rem)\n * @cssprop --query-bar-icon-size - Leading search icon size (default 16px)\n * @cssprop --query-bar-option-height - Suggestion row height (default 36px)\n * @cssprop --query-bar-dropdown-min-width - Dropdown panel minimum width (default 16rem)\n * @cssprop --query-bar-dropdown-max-width - Dropdown panel maximum width (default 28rem, viewport-capped)\n * @cssprop --chip-* - Pill styling (see ore-chip)\n * @cssprop --combobox-dropdown-* - Dropdown panel and option styling (see ore-combobox)\n *\n * @example\n * ```html\n * <ore-query-bar id=\"bar\" label=\"Search issues\" placeholder=\"Title, author or label…\" clearable>\n * </ore-query-bar>\n * <script>\n * bar.vocabulary = [\n * { key: 'author', label: 'Author', options: [{ label: 'Alice', value: 'alice' }] },\n * ];\n * </script>\n * ```\n */\nexport const QUERY_BAR_TAG = 'ore-query-bar' as const;\ndefine<OreQueryBarProps>(QUERY_BAR_TAG, {\n props: {\n clearable: prop.bool(false),\n disabled: prop.bool(false),\n error: prop.string(),\n helper: prop.string(),\n 'hide-label': prop.bool(false),\n label: prop.string(),\n placeholder: prop.string(),\n rounded: prop.oneOf(ROUNDED_SIZES),\n size: prop.oneOf(COMPONENT_SIZES),\n state: prop.data<QueryState>(),\n variant: prop.oneOf(QUERY_BAR_VARIANTS),\n vocabulary: prop.data<QueryTokenDef[]>(),\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreQueryBarEvents>();\n const watch = watchEffect;\n const abortSignal = lifecycleSignal(onCleanup);\n const barId = createId('query-bar');\n\n const vocabulary = (): QueryTokenDef[] => props.vocabulary.value ?? [];\n const emptyState = (): QueryState => ({ text: '', tokens: [] });\n const normalizeState = (value: unknown): QueryState | null => {\n if (value == null) return emptyState();\n if (typeof value !== 'object' || !Array.isArray((value as QueryState).tokens)) return null;\n const state = value as QueryState;\n return { text: typeof state.text === 'string' ? state.text : '', tokens: state.tokens };\n };\n\n /**\n * The working state: the initial `state` prop plus every commit this bar emits\n * before the consumer round-trips it. Gestures must read from here, never from\n * the prop directly: props lag a render behind, so two quick pill removals\n * would otherwise each compute from the same stale snapshot and the second\n * would resurrect the first pill.\n */\n const working = signal<QueryState>(normalizeState(props.state.value) ?? emptyState());\n /** What the field shows: the live draft (free text plus an unfinished token). */\n const field = signal(working.value.text);\n\n const suggestions = computed<QuerySuggestion[]>(() => suggestQuery(field.value, vocabulary()));\n const defBy = computed(() => new Map(vocabulary().map((def) => [def.key, def])));\n\n /**\n * True while the draft names a known key whose prefix matches no option. The\n * dropdown then shows a \"searching as text\" row instead of closing, so the\n * degradation is never silent — and blur makes the state honest (below).\n */\n const noMatch = computed(() => {\n const draft = parseQuery(field.value, vocabulary()).draft;\n return draft !== null && draft.valuePrefix !== '' && suggestions.value.length === 0;\n });\n\n const noMatchLabel = computed(() => {\n const draft = parseQuery(field.value, vocabulary()).draft;\n const def = draft ? defBy.value.get(draft.key) : undefined;\n return `No matching ${def?.label ?? draft?.key ?? ''} — searching as text`;\n });\n\n // Element refs the listbox dropdown needs; resolved as the template renders.\n let inputEl: HTMLInputElement | null = null;\n let fieldEl: HTMLElement | null = null;\n let dropdownEl: HTMLElement | null = null;\n const inputRef = ref<HTMLElement>();\n\n const optionList = createListboxDropdown<QuerySuggestion>({\n getBoundary: () => el,\n getFocusedOptionElement: () => dropdownEl?.querySelector<HTMLElement>('[data-focused]') ?? null,\n getItems: () => suggestions.value,\n getOptionId: (index) => `${barId}-opt-${index}`,\n getPanel: () => dropdownEl,\n getReference: () => fieldEl,\n getTrigger: () => inputEl,\n isDisabled: () => Boolean(props.disabled.value),\n isItemDisabled: () => false,\n onClose: (reason) => emit('open-change', { open: false, reason }),\n onOpen: (reason) => emit('open-change', { open: true, reason }),\n // The reference is the whole (often full-row) field: matching its width would\n // stretch the panel across the page. The dropdown sizes to its content within\n // its own min/max bounds instead, like a menu.\n positioning: { matchWidth: false },\n restoreFocus: false,\n signal: abortSignal,\n });\n const { focusedIndex, isOpen } = optionList;\n\n bind({\n attr: {\n open: () => (isOpen.value ? true : undefined),\n size: props.size,\n variant: props.variant,\n },\n });\n\n // Expose the working state as a native-like `.state` property on the host: the\n // live external channel, replacing the prop-installed property exactly as\n // ore-combobox replaces its own `value`. Writes whose `tokens` array matches\n // the working one are consumer echoes (v-model round-trips) and keep the\n // field's live draft; a changed tokens array is an external write — a deep-link\n // preset, a mode switch — and is adopted, field included.\n Object.defineProperty(el, 'state', {\n configurable: true,\n enumerable: true,\n get: () => working.value,\n set: (value: unknown) => {\n const next = normalizeState(value);\n if (next === null || next.tokens === working.value.tokens) return;\n working.value = next;\n field.value = next.text;\n },\n });\n\n // ── State commits ────────────────────────────────────────────────────────\n\n function emitChange(): void {\n dispatchNativeFieldEvent(el, 'input');\n dispatchNativeFieldEvent(el, 'change');\n }\n\n /** Applies the next state locally and announces it; the consumer reads `el.state`. */\n function commit(next: QueryState): void {\n working.value = next;\n emitChange();\n }\n\n /** Folds parsed tokens into the working set, replacing per key and keeping slots. */\n function mergeTokens(base: QueryToken[], parsed: readonly QueryToken[]): QueryToken[] {\n let tokens = base;\n for (const token of parsed) {\n const slot = tokens.findIndex((candidate) => candidate.key === token.key);\n tokens = slot >= 0 ? [...tokens.slice(0, slot), token, ...tokens.slice(slot + 1)] : [...tokens, token];\n }\n return tokens;\n }\n\n /** Parses the field, folds any complete tokens into the working state, and commits. */\n function applyField(): void {\n const parsed = parseQuery(field.value, vocabulary());\n if (parsed.tokens.length > 0) field.value = parsed.text;\n commit({ text: parsed.text, tokens: mergeTokens(working.value.tokens, parsed.tokens) });\n }\n\n function handleInput(event: Event): void {\n field.value = (event.target as HTMLInputElement).value;\n applyField();\n // Typing is the strongest composing signal: the dropdown must come back after\n // Escape without a blur/refocus cycle, or the bar reads as broken.\n if (canOpen()) optionList.open('keyboard');\n }\n\n function pick(suggestion: QuerySuggestion): void {\n // The word being typed is selector intent: whichever suggestion is picked consumes\n // it, so it never leaks into the free text as a stray search term. A field ending\n // in whitespace has no active word; a `key:…` draft is consumed like any word.\n const rest =\n /\\s$/.test(field.value) || field.value.trim() === '' ? '' : field.value.replace(/\\S+\\s*$/, '').trim();\n if (suggestion.kind === 'key') {\n // Start composing: replace the word being typed with the token key.\n field.value = rest ? `${rest} ${suggestion.key}:` : `${suggestion.key}:`;\n applyField();\n } else {\n field.value = rest;\n commit(commitToken({ text: rest, tokens: working.value.tokens }, suggestion.key, suggestion.value));\n }\n inputEl?.focus();\n }\n\n function removeChip(event: Event): void {\n event.stopPropagation();\n const key = (event as CustomEvent<{ value?: string }>).detail?.value;\n if (key === undefined) return;\n commit(removeToken(working.value, key));\n // Keep the compose flow: without this, focus falls to the host and the next\n // keystroke goes nowhere.\n inputEl?.focus();\n }\n\n /** The field's own clear button: clears the free text, never the pills. */\n function clearText(): void {\n field.value = '';\n commit({ text: '', tokens: working.value.tokens });\n inputEl?.focus();\n }\n\n function handleKeydown(e: KeyboardEvent): void {\n if (props.disabled.value) return;\n\n // While open, the listbox owns arrows, Home/End, and Escape.\n if (optionList.handleKeydown(e)) return;\n\n switch (e.key) {\n case 'Enter': {\n const active = isOpen.value ? suggestions.value[focusedIndex.value] : undefined;\n if (active) {\n e.preventDefault();\n pick(active);\n }\n break;\n }\n case 'Backspace':\n // The GitHub-style touch: backspace on an empty field drops the last pill.\n if (field.value === '' && working.value.tokens.length > 0) {\n const last = working.value.tokens[working.value.tokens.length - 1];\n if (last) commit(removeToken(working.value, last.key));\n }\n break;\n case 'Tab':\n optionList.close('programmatic');\n break;\n default:\n break;\n }\n }\n\n // The dropdown is open exactly while the field holds focus and has something to\n // show — suggestions, or the no-match row for an unresolvable draft; Escape,\n // outside pointers, and Tab dismiss it through the machinery.\n const canOpen = (): boolean => suggestions.value.length > 0 || noMatch.value;\n const openDropdown = (): void => {\n if (canOpen()) optionList.open('focus');\n };\n watch(() => {\n if (isOpen.value && !canOpen()) optionList.close('programmatic');\n });\n\n /**\n * Blur makes the field honest about dead drafts. A bare `key:` fragment is dead\n * syntax — revert it, leaving no residue. A draft that matches nothing was\n * already announced as \"searching as text\" — degrade it into the text so what\n * the field shows is what is searched. Live compositions (a draft with matching\n * suggestions) survive blur, so an interrupted pick resumes on refocus.\n */\n function handleFocusOut(event: FocusEvent): void {\n const next = event.relatedTarget;\n if (next instanceof Node && el.shadowRoot?.contains(next)) return;\n\n const parsed = parseQuery(field.value, vocabulary());\n if (!parsed.draft) return;\n if (parsed.draft.valuePrefix === '') {\n field.value = parsed.text;\n return;\n }\n if (suggestQuery(field.value, vocabulary()).length === 0) {\n const degraded = parsed.text\n ? `${parsed.text} ${parsed.draft.key}:${parsed.draft.valuePrefix}`\n : `${parsed.draft.key}:${parsed.draft.valuePrefix}`;\n field.value = degraded;\n commit({ text: degraded, tokens: working.value.tokens });\n }\n }\n\n // New suggestions start from no highlight; arrows move it, Enter commits it.\n watch(() => {\n void suggestions.value;\n if (optionList.isOpen.value) optionList.set(-1);\n });\n\n // The dropdown is popover=manual: without showPopover the UA stylesheet keeps it\n // display:none, so the panel must enter the top layer exactly when it opens.\n watch(() => {\n if (isOpen.value) {\n if (dropdownEl && 'showPopover' in dropdownEl && !dropdownEl.matches(':popover-open')) {\n dropdownEl.showPopover();\n }\n optionList.updatePosition();\n } else if (dropdownEl && 'hidePopover' in dropdownEl && dropdownEl.matches(':popover-open')) {\n dropdownEl.hidePopover();\n }\n });\n\n // Once ore-input is in the DOM, grab its inner <input> from its shadow root and\n // attach the query-bar's ARIA and event handlers imperatively (the combobox\n // pattern: the focused element must carry the combobox semantics itself).\n onElement(inputRef, (bitInputEl) => {\n fieldEl = bitInputEl;\n\n const rawInput = bitInputEl.shadowRoot?.querySelector<HTMLInputElement>('input') ?? null;\n if (!rawInput) return;\n\n inputEl = rawInput;\n\n rawInput.setAttribute('role', 'combobox');\n rawInput.setAttribute('autocomplete', 'off');\n rawInput.setAttribute('aria-autocomplete', 'list');\n rawInput.setAttribute('aria-haspopup', 'listbox');\n rawInput.setAttribute('spellcheck', 'false');\n // Backspace on the empty field drops the last pill: the only discoverability\n // of that shortcut for assistive tech.\n rawInput.setAttribute('aria-keyshortcuts', 'Backspace');\n\n rawInput.addEventListener('input', handleInput as EventListener);\n rawInput.addEventListener('keydown', handleKeydown as EventListener);\n rawInput.addEventListener('focus', openDropdown);\n rawInput.addEventListener('focusout', handleFocusOut as EventListener);\n\n return () => {\n inputEl = null;\n fieldEl = null;\n rawInput.removeEventListener('input', handleInput as EventListener);\n rawInput.removeEventListener('keydown', handleKeydown as EventListener);\n rawInput.removeEventListener('focus', openDropdown);\n rawInput.removeEventListener('focusout', handleFocusOut as EventListener);\n };\n });\n\n onMounted(() => {\n const listbox = el.shadowRoot?.querySelector<HTMLElement>('[role=\"listbox\"]');\n if (inputEl) setAriaReflection(inputEl, 'ariaControlsElements', listbox ? [listbox] : []);\n });\n\n // Reactively sync combobox-specific ARIA the field does not manage itself.\n watch(() => {\n if (!inputRef.value || !inputEl) return;\n\n inputEl.setAttribute('aria-expanded', String(isOpen.value));\n\n const listbox = el.shadowRoot?.querySelector<HTMLElement>('[role=\"listbox\"]');\n setAriaReflection(inputEl, 'ariaControlsElements', listbox ? [listbox] : []);\n const activeId = optionList.ariaActiveDescendant.value;\n const activeOption = activeId\n ? [...(dropdownEl?.querySelectorAll<HTMLElement>('[role=\"option\"]') ?? [])].find(\n (option) => option.id === activeId,\n )\n : null;\n setAriaReflection(inputEl, 'ariaActiveDescendantElement', activeOption?.id === activeId ? [activeOption] : []);\n\n if (props.disabled.value) inputEl.setAttribute('aria-disabled', 'true');\n else inputEl.removeAttribute('aria-disabled');\n\n if (props.error.value) inputEl.setAttribute('aria-invalid', 'true');\n else inputEl.removeAttribute('aria-invalid');\n });\n\n // Reactively sync the field signal into the raw input value.\n watch(() => {\n if (!inputRef.value || !inputEl) return;\n if (inputEl.value !== field.value) inputEl.value = field.value;\n });\n\n onCleanup(() => {\n optionList[Symbol.dispose]();\n });\n\n // When hide-label is set, suppress the visible label passed to ore-input (no inset\n // label renders, avoiding extra field height) but expose the label text as\n // aria-label on the input so the bar retains its accessible name.\n const hideLabel = () => props['hide-label'].value;\n const inputLabel = () => (hideLabel() ? '' : (props.label.value ?? ''));\n const inputAriaLabel = () => (hideLabel() ? (props.label.value ?? '') : null);\n\n /** Pill copy: `Author: Alice`, degrading to the raw key/value outside the vocabulary. */\n const pillLabel = (token: QueryToken): string => {\n const def = defBy.value.get(token.key);\n const option = def?.options.find((candidate) => candidate.value === token.value);\n if (def && option) return `${def.label}: ${option.label}`;\n return `${def?.key ?? token.key}: ${option?.label ?? token.value}`;\n };\n\n /** The muted second column: the token key for value rows, the `key:` syntax for key rows. */\n const optionMeta = (suggestion: QuerySuggestion): string => {\n const def = defBy.value.get(suggestion.key);\n return suggestion.kind === 'key' ? `${suggestion.key}:` : (def?.label ?? suggestion.key);\n };\n\n return html`\n <ore-input\n class=\"trigger\"\n ref=${inputRef}\n label=\"${inputLabel}\"\n aria-label=\"${inputAriaLabel}\"\n placeholder=\"${() => props.placeholder.value ?? ''}\"\n label-placement=\"inset\"\n variant=\"${() => props.variant.value ?? 'bordered'}\"\n size=\"${() => props.size.value ?? ''}\"\n rounded=\"${() => props.rounded.value ?? 'md'}\"\n helper=\"${() => props.helper.value ?? ''}\"\n error=\"${() => props.error.value ?? ''}\"\n ?disabled=\"${() => Boolean(props.disabled.value)}\"\n part=\"wrapper\">\n <div class=\"prefix\" slot=\"prefix\">\n <ore-icon name=\"search\" size=\"16\" aria-hidden=\"true\"></ore-icon>\n <span class=\"pills\">\n ${() =>\n working.value.tokens.map(\n (token) => html`\n <ore-chip\n value=${token.key}\n label=${pillLabel(token)}\n mode=\"removable\"\n variant=\"flat\"\n size=\"sm\"\n @remove=${removeChip}>\n ${pillLabel(token)}\n </ore-chip>\n `,\n )}\n </span>\n </div>\n <span class=\"suffix\" slot=\"suffix\">\n <button\n class=\"clear-btn\"\n part=\"clear-btn\"\n type=\"button\"\n aria-label=\"Clear\"\n tabindex=\"-1\"\n ?hidden=\"${() => !props.clearable.value || field.value === ''}\"\n @click=\"${clearText}\">\n <ore-icon name=\"x\" size=\"12\" stroke-width=\"2.5\" aria-hidden=\"true\"></ore-icon>\n </button>\n </span>\n </ore-input>\n <div\n class=\"dropdown\"\n part=\"dropdown\"\n id=\"${() => `${barId}-dropdown`}\"\n popover=\"manual\"\n ?data-open=${() => isOpen.value}\n ref=${(node: HTMLElement | null) => {\n dropdownEl = node;\n }}>\n <div\n role=\"listbox\"\n id=\"${() => `${barId}-listbox`}\"\n style=\"${() => (isOpen.value && canOpen() ? `height:${(noMatch.value ? 1 : suggestions.value.length) * OPTION_ROW_HEIGHT}px;` : '')}\"\n aria-label=\"${() => props.label.value || props.placeholder.value || 'Suggestions'}\">\n ${() =>\n isOpen.value && noMatch.value\n ? html`<div class=\"no-match\" role=\"option\" aria-selected=\"false\" aria-disabled=\"true\">${noMatchLabel.value}</div>`\n : ''}\n ${() =>\n isOpen.value && suggestions.value.length > 0\n ? suggestions.value.map(\n (suggestion, index) => html`\n <div\n class=\"option\"\n role=\"option\"\n id=\"${`${barId}-opt-${index}`}\"\n data-option-index=\"${index}\"\n aria-selected=\"false\"\n aria-disabled=\"false\"\n style=\"${`position:absolute;top:0;left:0;right:0;transform:translateY(${index * OPTION_ROW_HEIGHT}px);`}\"\n ?data-focused=${() => focusedIndex.value === index}\n @pointermove=\"${() => optionList.set(index)}\"\n @click=\"${() => pick(suggestion)}\">\n <span class=\"option-label\">${suggestion.label}</span>\n <span class=\"option-meta\">${optionMeta(suggestion)}</span>\n </div>\n `,\n )\n : ''}\n </div>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [colorThemeMixin, reducedMotionMixin, roundedVariantMixin, componentStyles],\n}) as unknown as AddEventListeners<OreQueryBarEvents>;\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./styles/mixins/states.css.cjs"),t=require("./core/choice-field.cjs"),n=require("./core/light-dom.cjs"),r=require("./core/ore.cjs"),i=require("./core/nav.cjs"),a=require("./shared/prop-bundles.cjs"),o=require("./inputs/radio-group/radio-group.css.cjs");let s=require("@vielzeug/ore");var c=(0,s.createContext)(`OreRadioGroup`),l=`ore-radio-group`;(0,s.define)(l,{formAssociated:!0,props:{...a.themableBundle,...a.sizableBundle,...a.disablableBundle,error:s.prop.string(),helper:s.prop.string(),label:s.prop.string(),name:s.prop.string(),orientation:s.prop.oneOf([`horizontal`,`vertical`],`vertical`),required:s.prop.bool(!1),value:{...s.prop.string(),reflect:!1}},setup(e){let a=(0,s.getHost)(),o=(0,s.useEmit)(),l=(0,s.useSlots)(),u=s.watchEffect,d=t.createChoiceField({disabled:e.disabled,error:e.error,helper:e.helper,label:e.label,prefix:`radio-group`,required:e.required,signal:r.lifecycleSignal(s.onCleanup),value:e.value});d.attachFormField((0,s.useField)({disabled:d.disabled,onReset:d.reset,toFormValue:e=>e,validationMessage:d.validationMessage,validity:d.validity,value:d.formValue}));let f=d.selectedValue,p=e.disabled;(0,s.bind)({attr:{size:e.size,value:()=>f.value||null}});let getSlottedRadios=()=>n.getLightChildrenByTag(a,`ore-radio`),getEnabledRadios=()=>p.value?[]:getSlottedRadios().filter(e=>!e.hasAttribute(`disabled`)),getLabelForValue=e=>n.getChoiceLabel(getSlottedRadios(),e),selectRadio=(e,t)=>{d.setValues(e?[e]:[]);let n=e?[getLabelForValue(e)]:[];o(`change`,{labels:n,originalEvent:t,values:e?[e]:[]}),d.triggerValidation(`blur`)};(0,s.provide)(c,{color:e.color,disabled:p,name:e.name,select:selectRadio,size:e.size,value:f}),u(()=>{l.elements().value,f.value;let t=getSlottedRadios();for(let n of t){let t=n.getAttribute(`value`)??``;n.toggleAttribute(`checked`,t===f.value),e.name.value?n.setAttribute(`name`,e.name.value):n.removeAttribute(`name`),e.color.value?n.setAttribute(`color`,e.color.value):n.removeAttribute(`color`),e.size.value?n.setAttribute(`size`,e.size.value):n.removeAttribute(`size`),n.toggleAttribute(`disabled`,p.value)}}),u(()=>{l.elements().value;let e=getSlottedRadios(),t=!1;for(let n of e){let e=n.getAttribute(`value`)===f.value;n.setAttribute(`tabindex`,e&&!p.value?`0`:`-1`),e&&!p.value&&(t=!0)}if(!t&&e.length>0){let t=e.find(e=>!e.hasAttribute(`disabled`));t&&t.setAttribute(`tabindex`,`0`)}});let m=i.createListControl({getItems:getEnabledRadios,keys:{next:[`ArrowDown`,`ArrowRight`],prev:[`ArrowUp`,`ArrowLeft`]},loop:!0,onNavigate:({event:e,item:t})=>{t.focus(),t.tagName===`ORE-RADIO`&&selectRadio(t.getAttribute(`value`)??``,e)},signal:r.lifecycleSignal(s.onCleanup)});(0,s.bind)({on:{change:e=>{e.target!==a&&(e.stopPropagation(),selectRadio(e.target.getAttribute(`value`)??``,e))},keydown:e=>{let t=getEnabledRadios();if(!t.length)return;let n=t.indexOf(document.activeElement);n!==-1&&(m.set(n),m.handleKeydown(e))}}});let h=(0,s.createId)(`radio-group-legend`);return s.html`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./styles/mixins/states.css.cjs"),t=require("./core/choice-field.cjs"),n=require("./core/light-dom.cjs"),r=require("./core/ore.cjs"),i=require("./core/nav.cjs"),a=require("./shared/prop-bundles.cjs"),o=require("./inputs/radio-group/radio-group.css.cjs");let s=require("@vielzeug/ore");var c=(0,s.createContext)(`OreRadioGroup`),l=`ore-radio-group`;(0,s.define)(l,{formAssociated:!0,props:{...a.themableBundle,...a.sizableBundle,...a.disablableBundle,error:s.prop.string(),helper:s.prop.string(),label:s.prop.string(),name:s.prop.string(),orientation:s.prop.oneOf([`horizontal`,`vertical`],`vertical`),required:s.prop.bool(!1),value:{...s.prop.string(),reflect:!1}},setup(e){let a=(0,s.getHost)(),o=(0,s.useEmit)(),l=(0,s.useSlots)(),u=s.watchEffect,d=t.createChoiceField({disabled:e.disabled,error:e.error,helper:e.helper,label:e.label,prefix:`radio-group`,required:e.required,signal:r.lifecycleSignal(s.onCleanup),value:e.value});d.attachFormField((0,s.useField)({disabled:d.disabled,onReset:d.reset,toFormValue:e=>e,validity:d.validity,value:d.formValue}));let f=d.selectedValue,p=e.disabled;(0,s.bind)({attr:{size:e.size,value:()=>f.value||null}});let getSlottedRadios=()=>n.getLightChildrenByTag(a,`ore-radio`),getEnabledRadios=()=>p.value?[]:getSlottedRadios().filter(e=>!e.hasAttribute(`disabled`)),getLabelForValue=e=>n.getChoiceLabel(getSlottedRadios(),e),selectRadio=(e,t)=>{d.setValues(e?[e]:[]);let n=e?[getLabelForValue(e)]:[];o(`change`,{labels:n,originalEvent:t,values:e?[e]:[]}),d.triggerValidation(`blur`)};(0,s.provide)(c,{color:e.color,disabled:p,name:e.name,select:selectRadio,size:e.size,value:f}),u(()=>{l.elements().value,f.value;let t=getSlottedRadios();for(let n of t){let t=n.getAttribute(`value`)??``;n.toggleAttribute(`checked`,t===f.value),e.name.value?n.setAttribute(`name`,e.name.value):n.removeAttribute(`name`),e.color.value?n.setAttribute(`color`,e.color.value):n.removeAttribute(`color`),e.size.value?n.setAttribute(`size`,e.size.value):n.removeAttribute(`size`),n.toggleAttribute(`disabled`,p.value)}}),u(()=>{l.elements().value;let e=getSlottedRadios(),t=!1;for(let n of e){let e=n.getAttribute(`value`)===f.value;n.setAttribute(`tabindex`,e&&!p.value?`0`:`-1`),e&&!p.value&&(t=!0)}if(!t&&e.length>0){let t=e.find(e=>!e.hasAttribute(`disabled`));t&&t.setAttribute(`tabindex`,`0`)}});let m=i.createListControl({getItems:getEnabledRadios,keys:{next:[`ArrowDown`,`ArrowRight`],prev:[`ArrowUp`,`ArrowLeft`]},loop:!0,onNavigate:({event:e,item:t})=>{t.focus(),t.tagName===`ORE-RADIO`&&selectRadio(t.getAttribute(`value`)??``,e)},signal:r.lifecycleSignal(s.onCleanup)});(0,s.bind)({on:{change:e=>{e.target!==a&&(e.stopPropagation(),selectRadio(e.target.getAttribute(`value`)??``,e))},keydown:e=>{let t=getEnabledRadios();if(!t.length)return;let n=t.indexOf(document.activeElement);n!==-1&&(m.set(n),m.handleKeydown(e))}}});let h=(0,s.createId)(`radio-group-legend`);return s.html`
2
2
  <fieldset
3
3
  role="radiogroup"
4
4
  aria-required="${()=>String(!!e.required.value)}"
@@ -1 +1 @@
1
- {"version":3,"file":"radio-group.cjs","names":[],"sources":["../src/inputs/radio-group/radio-group.ts"],"sourcesContent":["import {\n bind,\n createContext,\n createId,\n define,\n getHost,\n html,\n onCleanup,\n prop,\n provide,\n useEmit,\n useField,\n useSlots,\n watchEffect,\n when,\n} from '@vielzeug/ore';\nimport type { Readable } from '@vielzeug/ripple';\nimport {\n type ChoiceChangeDetail,\n createChoiceField,\n createListControl,\n getChoiceLabel,\n getLightChildrenByTag,\n lifecycleSignal,\n} from '../../core';\nimport { disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { disabledStateMixin } from '../../styles';\nimport type { ComponentSize, ThemeColor } from '../../types';\nimport componentStyles from './radio-group.css?inline';\n\n/** Radio group component properties */\nexport type OreRadioGroupProps = {\n /** Theme color tint */\n color?: ThemeColor;\n /** Disabled state */\n disabled?: boolean;\n /** Error message text */\n error?: string;\n /** Helper text displayed below the items */\n helper?: string;\n /** Group label text */\n label?: string;\n /** Form field name */\n name?: string;\n /** Layout orientation */\n orientation?: 'horizontal' | 'vertical';\n /** Required field */\n required?: boolean;\n /** Items size preset */\n size?: ComponentSize;\n /** Initial selected value */\n value?: string;\n};\n\nexport type RadioGroupContext = {\n color: Readable<ThemeColor | undefined>;\n disabled: Readable<boolean>;\n name: Readable<string | undefined>;\n select: (value: string, originalEvent?: Event) => void;\n size: Readable<ComponentSize | undefined>;\n value: Readable<string | undefined>;\n};\n\nexport const RADIO_GROUP_CTX = createContext<RadioGroupContext | undefined>('OreRadioGroup');\n\n/** Events emitted by the radio-group component */\nexport type OreRadioGroupEvents = {\n /** Emitted when the selection changes */\n change: ChoiceChangeDetail;\n};\n\n/**\n * A group of radio buttons that allows users to select a single option from a set.\n * Supports keyboard navigation (arrows) and automatic value management.\n *\n * @element ore-radio-group\n *\n * @attr {string} value - Selected value\n * @attr {string} name - Form field name\n * @attr {string} label - Group label\n * @attr {string} orientation - Layout: 'vertical' | 'horizontal'\n * @attr {boolean} required - Required field\n *\n * @fires change - Emitted when a radio is selected. detail: { values: string[], labels: string[], originalEvent?: Event }\n *\n * @slot - Place `ore-radio` elements here\n *\n * @cssprop --radio-group-direction - Flex direction of the items list ('row' | 'column')\n * @cssprop --radio-group-gap - Gap between radio items\n * @part items - Items container.\n * @example\n * ```html\n * <ore-radio-group name=\"plan\" label=\"Choose a plan\" value=\"free\" required>\n * <ore-radio value=\"free\">Free</ore-radio>\n * <ore-radio value=\"pro\">Pro</ore-radio>\n * <ore-radio value=\"enterprise\">Enterprise</ore-radio>\n * </ore-radio-group>\n * <ore-radio-group name=\"direction\" orientation=\"horizontal\" color=\"primary\">\n * <ore-radio value=\"left\">Left</ore-radio>\n * <ore-radio value=\"right\">Right</ore-radio>\n * </ore-radio-group>\n * ```\n */\nexport const RADIO_GROUP_TAG = 'ore-radio-group' as const;\ndefine<OreRadioGroupProps>(RADIO_GROUP_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n error: prop.string(),\n helper: prop.string(),\n label: prop.string(),\n name: prop.string(),\n orientation: prop.oneOf(['horizontal', 'vertical'] as const, 'vertical'),\n required: prop.bool(false),\n // Not auto-reflected (`reflect: false`): the derived, interaction-updated selection\n // (`selectedValue`) is the single writer for this attribute, via `bind()` below; letting\n // `prop.string()`'s own default reflection also write the raw incoming value would leave\n // two effects racing to set the same attribute from different sources.\n value: { ...prop.string(), reflect: false },\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreRadioGroupEvents>();\n const slots = useSlots();\n const watch = watchEffect;\n\n const choice = createChoiceField({\n disabled: props.disabled,\n error: props.error,\n helper: props.helper,\n label: props.label,\n prefix: 'radio-group',\n required: props.required,\n signal: lifecycleSignal(onCleanup),\n value: props.value,\n });\n\n choice.attachFormField(\n useField<string>({\n disabled: choice.disabled,\n onReset: choice.reset,\n toFormValue: (v) => v,\n validationMessage: choice.validationMessage,\n validity: choice.validity,\n value: choice.formValue,\n }),\n );\n\n const selectedValue = choice.selectedValue;\n const isDisabled = props.disabled;\n\n bind({\n attr: {\n size: props.size,\n value: () => selectedValue.value || null,\n },\n });\n\n const getSlottedRadios = (): HTMLElement[] => getLightChildrenByTag(el, 'ore-radio');\n\n const getEnabledRadios = (): HTMLElement[] =>\n isDisabled.value ? [] : getSlottedRadios().filter((radio) => !radio.hasAttribute('disabled'));\n\n const getLabelForValue = (value: string): string => getChoiceLabel(getSlottedRadios(), value);\n\n const selectRadio = (val: string, originalEvent?: Event): void => {\n choice.setValues(val ? [val] : []);\n\n const labels = val ? [getLabelForValue(val)] : [];\n const values = val ? [val] : [];\n\n emit('change', { labels, originalEvent, values });\n choice.triggerValidation('blur');\n };\n\n provide(RADIO_GROUP_CTX, {\n color: props.color as Readable<ThemeColor | undefined>,\n disabled: isDisabled,\n name: props.name,\n select: selectRadio,\n size: props.size as Readable<ComponentSize | undefined>,\n value: selectedValue,\n });\n\n // Sync name/color/size/disabled/checked onto slotted ore-radio children.\n watch(() => {\n void slots.elements().value;\n void selectedValue.value;\n\n const radios = getSlottedRadios();\n\n for (const radio of radios) {\n const val = radio.getAttribute('value') ?? '';\n\n radio.toggleAttribute('checked', val === selectedValue.value);\n\n if (props.name.value) radio.setAttribute('name', props.name.value);\n else radio.removeAttribute('name');\n\n if (props.color.value) radio.setAttribute('color', props.color.value);\n else radio.removeAttribute('color');\n\n if (props.size.value) radio.setAttribute('size', props.size.value);\n else radio.removeAttribute('size');\n\n radio.toggleAttribute('disabled', isDisabled.value);\n }\n });\n\n // Roving tabindex: only the selected (or first) radio is tabbable.\n watch(() => {\n void slots.elements().value;\n\n const radios = getSlottedRadios();\n let hasFocusable = false;\n\n for (const radio of radios) {\n const isSelected = radio.getAttribute('value') === selectedValue.value;\n\n radio.setAttribute('tabindex', isSelected && !isDisabled.value ? '0' : '-1');\n\n if (isSelected && !isDisabled.value) hasFocusable = true;\n }\n\n if (!hasFocusable && radios.length > 0) {\n const first = radios.find((r) => !r.hasAttribute('disabled'));\n\n if (first) first.setAttribute('tabindex', '0');\n }\n });\n\n const listControl = createListControl<HTMLElement>({\n getItems: getEnabledRadios,\n keys: { next: ['ArrowDown', 'ArrowRight'], prev: ['ArrowUp', 'ArrowLeft'] },\n loop: true,\n onNavigate: ({ event, item }) => {\n item.focus();\n\n if (item.tagName === 'ORE-RADIO') {\n selectRadio(item.getAttribute('value') ?? '', event);\n }\n },\n signal: lifecycleSignal(onCleanup),\n });\n\n bind({\n on: {\n change: (e: Event) => {\n if (e.target === el) return;\n\n e.stopPropagation();\n selectRadio((e.target as HTMLElement).getAttribute('value') ?? '', e);\n },\n keydown: (e: KeyboardEvent) => {\n const radios = getEnabledRadios();\n\n if (!radios.length) return;\n\n const focused = radios.indexOf(document.activeElement as HTMLElement);\n\n if (focused === -1) return;\n\n listControl.set(focused);\n listControl.handleKeydown(e);\n },\n },\n });\n\n const legendId = createId('radio-group-legend');\n\n return html`\n <fieldset\n role=\"radiogroup\"\n aria-required=\"${() => String(Boolean(props.required.value))}\"\n aria-invalid=\"${choice.ariaInvalid}\"\n aria-errormessage=\"${choice.ariaErrorMessage}\"\n aria-describedby=\"${choice.ariaDescribedBy}\">\n <legend id=\"${legendId}\" ?hidden=${() => !props.label.value}>\n ${props.label}${when(\n () => Boolean(props.required.value),\n () => html`\n <span aria-hidden=\"true\">*</span>\n `,\n )}\n </legend>\n <div class=\"radio-group-items\" part=\"items\">\n <slot></slot>\n </div>\n <div\n class=\"helper-text\"\n part=\"helper\"\n id=\"${choice.assistiveId}\"\n role=\"${() => (choice.errorText.value ? 'alert' : null)}\"\n aria-live=\"polite\"\n ?hidden=\"${() => !choice.errorText.value && !choice.helperText.value}\">\n ${() => choice.errorText.value || choice.helperText.value}\n </div>\n </fieldset>\n `;\n },\n styles: [disabledStateMixin, componentStyles],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"radio-group.cjs","names":[],"sources":["../src/inputs/radio-group/radio-group.ts"],"sourcesContent":["import {\n bind,\n createContext,\n createId,\n define,\n getHost,\n html,\n onCleanup,\n prop,\n provide,\n useEmit,\n useField,\n useSlots,\n watchEffect,\n when,\n} from '@vielzeug/ore';\nimport type { Readable } from '@vielzeug/ripple';\nimport {\n type ChoiceChangeDetail,\n createChoiceField,\n createListControl,\n getChoiceLabel,\n getLightChildrenByTag,\n lifecycleSignal,\n} from '../../core';\nimport { disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { disabledStateMixin } from '../../styles';\nimport type { ComponentSize, ThemeColor } from '../../types';\nimport componentStyles from './radio-group.css?inline';\n\n/** Radio group component properties */\nexport type OreRadioGroupProps = {\n /** Theme color tint */\n color?: ThemeColor;\n /** Disabled state */\n disabled?: boolean;\n /** Error message text */\n error?: string;\n /** Helper text displayed below the items */\n helper?: string;\n /** Group label text */\n label?: string;\n /** Form field name */\n name?: string;\n /** Layout orientation */\n orientation?: 'horizontal' | 'vertical';\n /** Required field */\n required?: boolean;\n /** Items size preset */\n size?: ComponentSize;\n /** Initial selected value */\n value?: string;\n};\n\nexport type RadioGroupContext = {\n color: Readable<ThemeColor | undefined>;\n disabled: Readable<boolean>;\n name: Readable<string | undefined>;\n select: (value: string, originalEvent?: Event) => void;\n size: Readable<ComponentSize | undefined>;\n value: Readable<string | undefined>;\n};\n\nexport const RADIO_GROUP_CTX = createContext<RadioGroupContext | undefined>('OreRadioGroup');\n\n/** Events emitted by the radio-group component */\nexport type OreRadioGroupEvents = {\n /** Emitted when the selection changes */\n change: ChoiceChangeDetail;\n};\n\n/**\n * A group of radio buttons that allows users to select a single option from a set.\n * Supports keyboard navigation (arrows) and automatic value management.\n *\n * @element ore-radio-group\n *\n * @attr {string} value - Selected value\n * @attr {string} name - Form field name\n * @attr {string} label - Group label\n * @attr {string} orientation - Layout: 'vertical' | 'horizontal'\n * @attr {boolean} required - Required field\n *\n * @fires change - Emitted when a radio is selected. detail: { values: string[], labels: string[], originalEvent?: Event }\n *\n * @slot - Place `ore-radio` elements here\n *\n * @cssprop --radio-group-direction - Flex direction of the items list ('row' | 'column')\n * @cssprop --radio-group-gap - Gap between radio items\n * @part items - Items container.\n * @example\n * ```html\n * <ore-radio-group name=\"plan\" label=\"Choose a plan\" value=\"free\" required>\n * <ore-radio value=\"free\">Free</ore-radio>\n * <ore-radio value=\"pro\">Pro</ore-radio>\n * <ore-radio value=\"enterprise\">Enterprise</ore-radio>\n * </ore-radio-group>\n * <ore-radio-group name=\"direction\" orientation=\"horizontal\" color=\"primary\">\n * <ore-radio value=\"left\">Left</ore-radio>\n * <ore-radio value=\"right\">Right</ore-radio>\n * </ore-radio-group>\n * ```\n */\nexport const RADIO_GROUP_TAG = 'ore-radio-group' as const;\ndefine<OreRadioGroupProps>(RADIO_GROUP_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n error: prop.string(),\n helper: prop.string(),\n label: prop.string(),\n name: prop.string(),\n orientation: prop.oneOf(['horizontal', 'vertical'] as const, 'vertical'),\n required: prop.bool(false),\n // Not auto-reflected (`reflect: false`): the derived, interaction-updated selection\n // (`selectedValue`) is the single writer for this attribute, via `bind()` below; letting\n // `prop.string()`'s own default reflection also write the raw incoming value would leave\n // two effects racing to set the same attribute from different sources.\n value: { ...prop.string(), reflect: false },\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreRadioGroupEvents>();\n const slots = useSlots();\n const watch = watchEffect;\n\n const choice = createChoiceField({\n disabled: props.disabled,\n error: props.error,\n helper: props.helper,\n label: props.label,\n prefix: 'radio-group',\n required: props.required,\n signal: lifecycleSignal(onCleanup),\n value: props.value,\n });\n\n choice.attachFormField(\n useField<string>({\n disabled: choice.disabled,\n onReset: choice.reset,\n toFormValue: (v) => v,\n validity: choice.validity,\n value: choice.formValue,\n }),\n );\n\n const selectedValue = choice.selectedValue;\n const isDisabled = props.disabled;\n\n bind({\n attr: {\n size: props.size,\n value: () => selectedValue.value || null,\n },\n });\n\n const getSlottedRadios = (): HTMLElement[] => getLightChildrenByTag(el, 'ore-radio');\n\n const getEnabledRadios = (): HTMLElement[] =>\n isDisabled.value ? [] : getSlottedRadios().filter((radio) => !radio.hasAttribute('disabled'));\n\n const getLabelForValue = (value: string): string => getChoiceLabel(getSlottedRadios(), value);\n\n const selectRadio = (val: string, originalEvent?: Event): void => {\n choice.setValues(val ? [val] : []);\n\n const labels = val ? [getLabelForValue(val)] : [];\n const values = val ? [val] : [];\n\n emit('change', { labels, originalEvent, values });\n choice.triggerValidation('blur');\n };\n\n provide(RADIO_GROUP_CTX, {\n color: props.color as Readable<ThemeColor | undefined>,\n disabled: isDisabled,\n name: props.name,\n select: selectRadio,\n size: props.size as Readable<ComponentSize | undefined>,\n value: selectedValue,\n });\n\n // Sync name/color/size/disabled/checked onto slotted ore-radio children.\n watch(() => {\n void slots.elements().value;\n void selectedValue.value;\n\n const radios = getSlottedRadios();\n\n for (const radio of radios) {\n const val = radio.getAttribute('value') ?? '';\n\n radio.toggleAttribute('checked', val === selectedValue.value);\n\n if (props.name.value) radio.setAttribute('name', props.name.value);\n else radio.removeAttribute('name');\n\n if (props.color.value) radio.setAttribute('color', props.color.value);\n else radio.removeAttribute('color');\n\n if (props.size.value) radio.setAttribute('size', props.size.value);\n else radio.removeAttribute('size');\n\n radio.toggleAttribute('disabled', isDisabled.value);\n }\n });\n\n // Roving tabindex: only the selected (or first) radio is tabbable.\n watch(() => {\n void slots.elements().value;\n\n const radios = getSlottedRadios();\n let hasFocusable = false;\n\n for (const radio of radios) {\n const isSelected = radio.getAttribute('value') === selectedValue.value;\n\n radio.setAttribute('tabindex', isSelected && !isDisabled.value ? '0' : '-1');\n\n if (isSelected && !isDisabled.value) hasFocusable = true;\n }\n\n if (!hasFocusable && radios.length > 0) {\n const first = radios.find((r) => !r.hasAttribute('disabled'));\n\n if (first) first.setAttribute('tabindex', '0');\n }\n });\n\n const listControl = createListControl<HTMLElement>({\n getItems: getEnabledRadios,\n keys: { next: ['ArrowDown', 'ArrowRight'], prev: ['ArrowUp', 'ArrowLeft'] },\n loop: true,\n onNavigate: ({ event, item }) => {\n item.focus();\n\n if (item.tagName === 'ORE-RADIO') {\n selectRadio(item.getAttribute('value') ?? '', event);\n }\n },\n signal: lifecycleSignal(onCleanup),\n });\n\n bind({\n on: {\n change: (e: Event) => {\n if (e.target === el) return;\n\n e.stopPropagation();\n selectRadio((e.target as HTMLElement).getAttribute('value') ?? '', e);\n },\n keydown: (e: KeyboardEvent) => {\n const radios = getEnabledRadios();\n\n if (!radios.length) return;\n\n const focused = radios.indexOf(document.activeElement as HTMLElement);\n\n if (focused === -1) return;\n\n listControl.set(focused);\n listControl.handleKeydown(e);\n },\n },\n });\n\n const legendId = createId('radio-group-legend');\n\n return html`\n <fieldset\n role=\"radiogroup\"\n aria-required=\"${() => String(Boolean(props.required.value))}\"\n aria-invalid=\"${choice.ariaInvalid}\"\n aria-errormessage=\"${choice.ariaErrorMessage}\"\n aria-describedby=\"${choice.ariaDescribedBy}\">\n <legend id=\"${legendId}\" ?hidden=${() => !props.label.value}>\n ${props.label}${when(\n () => Boolean(props.required.value),\n () => html`\n <span aria-hidden=\"true\">*</span>\n `,\n )}\n </legend>\n <div class=\"radio-group-items\" part=\"items\">\n <slot></slot>\n </div>\n <div\n class=\"helper-text\"\n part=\"helper\"\n id=\"${choice.assistiveId}\"\n role=\"${() => (choice.errorText.value ? 'alert' : null)}\"\n aria-live=\"polite\"\n ?hidden=\"${() => !choice.errorText.value && !choice.helperText.value}\">\n ${() => choice.errorText.value || choice.helperText.value}\n </div>\n </fieldset>\n `;\n },\n styles: [disabledStateMixin, componentStyles],\n});\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import{disabledStateMixin as e}from"./styles/mixins/states.css.js";import{createChoiceField as t}from"./core/choice-field.js";import{getChoiceLabel as n,getLightChildrenByTag as r}from"./core/light-dom.js";import{lifecycleSignal as i}from"./core/ore.js";import{createListControl as a}from"./core/nav.js";import{disablableBundle as o,sizableBundle as s,themableBundle as c}from"./shared/prop-bundles.js";import l from"./inputs/radio-group/radio-group.css.js";import{bind as u,createContext as d,createId as f,define as p,getHost as m,html as h,onCleanup as g,prop as _,provide as v,useEmit as y,useField as b,useSlots as x,watchEffect as S,when as C}from"@vielzeug/ore";var w=d(`OreRadioGroup`),T=`ore-radio-group`;p(T,{formAssociated:!0,props:{...c,...s,...o,error:_.string(),helper:_.string(),label:_.string(),name:_.string(),orientation:_.oneOf([`horizontal`,`vertical`],`vertical`),required:_.bool(!1),value:{..._.string(),reflect:!1}},setup(e){let o=m(),s=y(),c=x(),l=S,d=t({disabled:e.disabled,error:e.error,helper:e.helper,label:e.label,prefix:`radio-group`,required:e.required,signal:i(g),value:e.value});d.attachFormField(b({disabled:d.disabled,onReset:d.reset,toFormValue:e=>e,validationMessage:d.validationMessage,validity:d.validity,value:d.formValue}));let p=d.selectedValue,_=e.disabled;u({attr:{size:e.size,value:()=>p.value||null}});let getSlottedRadios=()=>r(o,`ore-radio`),getEnabledRadios=()=>_.value?[]:getSlottedRadios().filter(e=>!e.hasAttribute(`disabled`)),getLabelForValue=e=>n(getSlottedRadios(),e),selectRadio=(e,t)=>{d.setValues(e?[e]:[]);let n=e?[getLabelForValue(e)]:[];s(`change`,{labels:n,originalEvent:t,values:e?[e]:[]}),d.triggerValidation(`blur`)};v(w,{color:e.color,disabled:_,name:e.name,select:selectRadio,size:e.size,value:p}),l(()=>{c.elements().value,p.value;let t=getSlottedRadios();for(let n of t){let t=n.getAttribute(`value`)??``;n.toggleAttribute(`checked`,t===p.value),e.name.value?n.setAttribute(`name`,e.name.value):n.removeAttribute(`name`),e.color.value?n.setAttribute(`color`,e.color.value):n.removeAttribute(`color`),e.size.value?n.setAttribute(`size`,e.size.value):n.removeAttribute(`size`),n.toggleAttribute(`disabled`,_.value)}}),l(()=>{c.elements().value;let e=getSlottedRadios(),t=!1;for(let n of e){let e=n.getAttribute(`value`)===p.value;n.setAttribute(`tabindex`,e&&!_.value?`0`:`-1`),e&&!_.value&&(t=!0)}if(!t&&e.length>0){let t=e.find(e=>!e.hasAttribute(`disabled`));t&&t.setAttribute(`tabindex`,`0`)}});let T=a({getItems:getEnabledRadios,keys:{next:[`ArrowDown`,`ArrowRight`],prev:[`ArrowUp`,`ArrowLeft`]},loop:!0,onNavigate:({event:e,item:t})=>{t.focus(),t.tagName===`ORE-RADIO`&&selectRadio(t.getAttribute(`value`)??``,e)},signal:i(g)});u({on:{change:e=>{e.target!==o&&(e.stopPropagation(),selectRadio(e.target.getAttribute(`value`)??``,e))},keydown:e=>{let t=getEnabledRadios();if(!t.length)return;let n=t.indexOf(document.activeElement);n!==-1&&(T.set(n),T.handleKeydown(e))}}});let E=f(`radio-group-legend`);return h`
1
+ import{disabledStateMixin as e}from"./styles/mixins/states.css.js";import{createChoiceField as t}from"./core/choice-field.js";import{getChoiceLabel as n,getLightChildrenByTag as r}from"./core/light-dom.js";import{lifecycleSignal as i}from"./core/ore.js";import{createListControl as a}from"./core/nav.js";import{disablableBundle as o,sizableBundle as s,themableBundle as c}from"./shared/prop-bundles.js";import l from"./inputs/radio-group/radio-group.css.js";import{bind as u,createContext as d,createId as f,define as p,getHost as m,html as h,onCleanup as g,prop as _,provide as v,useEmit as y,useField as b,useSlots as x,watchEffect as S,when as C}from"@vielzeug/ore";var w=d(`OreRadioGroup`),T=`ore-radio-group`;p(T,{formAssociated:!0,props:{...c,...s,...o,error:_.string(),helper:_.string(),label:_.string(),name:_.string(),orientation:_.oneOf([`horizontal`,`vertical`],`vertical`),required:_.bool(!1),value:{..._.string(),reflect:!1}},setup(e){let o=m(),s=y(),c=x(),l=S,d=t({disabled:e.disabled,error:e.error,helper:e.helper,label:e.label,prefix:`radio-group`,required:e.required,signal:i(g),value:e.value});d.attachFormField(b({disabled:d.disabled,onReset:d.reset,toFormValue:e=>e,validity:d.validity,value:d.formValue}));let p=d.selectedValue,_=e.disabled;u({attr:{size:e.size,value:()=>p.value||null}});let getSlottedRadios=()=>r(o,`ore-radio`),getEnabledRadios=()=>_.value?[]:getSlottedRadios().filter(e=>!e.hasAttribute(`disabled`)),getLabelForValue=e=>n(getSlottedRadios(),e),selectRadio=(e,t)=>{d.setValues(e?[e]:[]);let n=e?[getLabelForValue(e)]:[];s(`change`,{labels:n,originalEvent:t,values:e?[e]:[]}),d.triggerValidation(`blur`)};v(w,{color:e.color,disabled:_,name:e.name,select:selectRadio,size:e.size,value:p}),l(()=>{c.elements().value,p.value;let t=getSlottedRadios();for(let n of t){let t=n.getAttribute(`value`)??``;n.toggleAttribute(`checked`,t===p.value),e.name.value?n.setAttribute(`name`,e.name.value):n.removeAttribute(`name`),e.color.value?n.setAttribute(`color`,e.color.value):n.removeAttribute(`color`),e.size.value?n.setAttribute(`size`,e.size.value):n.removeAttribute(`size`),n.toggleAttribute(`disabled`,_.value)}}),l(()=>{c.elements().value;let e=getSlottedRadios(),t=!1;for(let n of e){let e=n.getAttribute(`value`)===p.value;n.setAttribute(`tabindex`,e&&!_.value?`0`:`-1`),e&&!_.value&&(t=!0)}if(!t&&e.length>0){let t=e.find(e=>!e.hasAttribute(`disabled`));t&&t.setAttribute(`tabindex`,`0`)}});let T=a({getItems:getEnabledRadios,keys:{next:[`ArrowDown`,`ArrowRight`],prev:[`ArrowUp`,`ArrowLeft`]},loop:!0,onNavigate:({event:e,item:t})=>{t.focus(),t.tagName===`ORE-RADIO`&&selectRadio(t.getAttribute(`value`)??``,e)},signal:i(g)});u({on:{change:e=>{e.target!==o&&(e.stopPropagation(),selectRadio(e.target.getAttribute(`value`)??``,e))},keydown:e=>{let t=getEnabledRadios();if(!t.length)return;let n=t.indexOf(document.activeElement);n!==-1&&(T.set(n),T.handleKeydown(e))}}});let E=f(`radio-group-legend`);return h`
2
2
  <fieldset
3
3
  role="radiogroup"
4
4
  aria-required="${()=>String(!!e.required.value)}"
@@ -1 +1 @@
1
- {"version":3,"file":"radio-group.js","names":[],"sources":["../src/inputs/radio-group/radio-group.ts"],"sourcesContent":["import {\n bind,\n createContext,\n createId,\n define,\n getHost,\n html,\n onCleanup,\n prop,\n provide,\n useEmit,\n useField,\n useSlots,\n watchEffect,\n when,\n} from '@vielzeug/ore';\nimport type { Readable } from '@vielzeug/ripple';\nimport {\n type ChoiceChangeDetail,\n createChoiceField,\n createListControl,\n getChoiceLabel,\n getLightChildrenByTag,\n lifecycleSignal,\n} from '../../core';\nimport { disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { disabledStateMixin } from '../../styles';\nimport type { ComponentSize, ThemeColor } from '../../types';\nimport componentStyles from './radio-group.css?inline';\n\n/** Radio group component properties */\nexport type OreRadioGroupProps = {\n /** Theme color tint */\n color?: ThemeColor;\n /** Disabled state */\n disabled?: boolean;\n /** Error message text */\n error?: string;\n /** Helper text displayed below the items */\n helper?: string;\n /** Group label text */\n label?: string;\n /** Form field name */\n name?: string;\n /** Layout orientation */\n orientation?: 'horizontal' | 'vertical';\n /** Required field */\n required?: boolean;\n /** Items size preset */\n size?: ComponentSize;\n /** Initial selected value */\n value?: string;\n};\n\nexport type RadioGroupContext = {\n color: Readable<ThemeColor | undefined>;\n disabled: Readable<boolean>;\n name: Readable<string | undefined>;\n select: (value: string, originalEvent?: Event) => void;\n size: Readable<ComponentSize | undefined>;\n value: Readable<string | undefined>;\n};\n\nexport const RADIO_GROUP_CTX = createContext<RadioGroupContext | undefined>('OreRadioGroup');\n\n/** Events emitted by the radio-group component */\nexport type OreRadioGroupEvents = {\n /** Emitted when the selection changes */\n change: ChoiceChangeDetail;\n};\n\n/**\n * A group of radio buttons that allows users to select a single option from a set.\n * Supports keyboard navigation (arrows) and automatic value management.\n *\n * @element ore-radio-group\n *\n * @attr {string} value - Selected value\n * @attr {string} name - Form field name\n * @attr {string} label - Group label\n * @attr {string} orientation - Layout: 'vertical' | 'horizontal'\n * @attr {boolean} required - Required field\n *\n * @fires change - Emitted when a radio is selected. detail: { values: string[], labels: string[], originalEvent?: Event }\n *\n * @slot - Place `ore-radio` elements here\n *\n * @cssprop --radio-group-direction - Flex direction of the items list ('row' | 'column')\n * @cssprop --radio-group-gap - Gap between radio items\n * @part items - Items container.\n * @example\n * ```html\n * <ore-radio-group name=\"plan\" label=\"Choose a plan\" value=\"free\" required>\n * <ore-radio value=\"free\">Free</ore-radio>\n * <ore-radio value=\"pro\">Pro</ore-radio>\n * <ore-radio value=\"enterprise\">Enterprise</ore-radio>\n * </ore-radio-group>\n * <ore-radio-group name=\"direction\" orientation=\"horizontal\" color=\"primary\">\n * <ore-radio value=\"left\">Left</ore-radio>\n * <ore-radio value=\"right\">Right</ore-radio>\n * </ore-radio-group>\n * ```\n */\nexport const RADIO_GROUP_TAG = 'ore-radio-group' as const;\ndefine<OreRadioGroupProps>(RADIO_GROUP_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n error: prop.string(),\n helper: prop.string(),\n label: prop.string(),\n name: prop.string(),\n orientation: prop.oneOf(['horizontal', 'vertical'] as const, 'vertical'),\n required: prop.bool(false),\n // Not auto-reflected (`reflect: false`): the derived, interaction-updated selection\n // (`selectedValue`) is the single writer for this attribute, via `bind()` below; letting\n // `prop.string()`'s own default reflection also write the raw incoming value would leave\n // two effects racing to set the same attribute from different sources.\n value: { ...prop.string(), reflect: false },\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreRadioGroupEvents>();\n const slots = useSlots();\n const watch = watchEffect;\n\n const choice = createChoiceField({\n disabled: props.disabled,\n error: props.error,\n helper: props.helper,\n label: props.label,\n prefix: 'radio-group',\n required: props.required,\n signal: lifecycleSignal(onCleanup),\n value: props.value,\n });\n\n choice.attachFormField(\n useField<string>({\n disabled: choice.disabled,\n onReset: choice.reset,\n toFormValue: (v) => v,\n validationMessage: choice.validationMessage,\n validity: choice.validity,\n value: choice.formValue,\n }),\n );\n\n const selectedValue = choice.selectedValue;\n const isDisabled = props.disabled;\n\n bind({\n attr: {\n size: props.size,\n value: () => selectedValue.value || null,\n },\n });\n\n const getSlottedRadios = (): HTMLElement[] => getLightChildrenByTag(el, 'ore-radio');\n\n const getEnabledRadios = (): HTMLElement[] =>\n isDisabled.value ? [] : getSlottedRadios().filter((radio) => !radio.hasAttribute('disabled'));\n\n const getLabelForValue = (value: string): string => getChoiceLabel(getSlottedRadios(), value);\n\n const selectRadio = (val: string, originalEvent?: Event): void => {\n choice.setValues(val ? [val] : []);\n\n const labels = val ? [getLabelForValue(val)] : [];\n const values = val ? [val] : [];\n\n emit('change', { labels, originalEvent, values });\n choice.triggerValidation('blur');\n };\n\n provide(RADIO_GROUP_CTX, {\n color: props.color as Readable<ThemeColor | undefined>,\n disabled: isDisabled,\n name: props.name,\n select: selectRadio,\n size: props.size as Readable<ComponentSize | undefined>,\n value: selectedValue,\n });\n\n // Sync name/color/size/disabled/checked onto slotted ore-radio children.\n watch(() => {\n void slots.elements().value;\n void selectedValue.value;\n\n const radios = getSlottedRadios();\n\n for (const radio of radios) {\n const val = radio.getAttribute('value') ?? '';\n\n radio.toggleAttribute('checked', val === selectedValue.value);\n\n if (props.name.value) radio.setAttribute('name', props.name.value);\n else radio.removeAttribute('name');\n\n if (props.color.value) radio.setAttribute('color', props.color.value);\n else radio.removeAttribute('color');\n\n if (props.size.value) radio.setAttribute('size', props.size.value);\n else radio.removeAttribute('size');\n\n radio.toggleAttribute('disabled', isDisabled.value);\n }\n });\n\n // Roving tabindex: only the selected (or first) radio is tabbable.\n watch(() => {\n void slots.elements().value;\n\n const radios = getSlottedRadios();\n let hasFocusable = false;\n\n for (const radio of radios) {\n const isSelected = radio.getAttribute('value') === selectedValue.value;\n\n radio.setAttribute('tabindex', isSelected && !isDisabled.value ? '0' : '-1');\n\n if (isSelected && !isDisabled.value) hasFocusable = true;\n }\n\n if (!hasFocusable && radios.length > 0) {\n const first = radios.find((r) => !r.hasAttribute('disabled'));\n\n if (first) first.setAttribute('tabindex', '0');\n }\n });\n\n const listControl = createListControl<HTMLElement>({\n getItems: getEnabledRadios,\n keys: { next: ['ArrowDown', 'ArrowRight'], prev: ['ArrowUp', 'ArrowLeft'] },\n loop: true,\n onNavigate: ({ event, item }) => {\n item.focus();\n\n if (item.tagName === 'ORE-RADIO') {\n selectRadio(item.getAttribute('value') ?? '', event);\n }\n },\n signal: lifecycleSignal(onCleanup),\n });\n\n bind({\n on: {\n change: (e: Event) => {\n if (e.target === el) return;\n\n e.stopPropagation();\n selectRadio((e.target as HTMLElement).getAttribute('value') ?? '', e);\n },\n keydown: (e: KeyboardEvent) => {\n const radios = getEnabledRadios();\n\n if (!radios.length) return;\n\n const focused = radios.indexOf(document.activeElement as HTMLElement);\n\n if (focused === -1) return;\n\n listControl.set(focused);\n listControl.handleKeydown(e);\n },\n },\n });\n\n const legendId = createId('radio-group-legend');\n\n return html`\n <fieldset\n role=\"radiogroup\"\n aria-required=\"${() => String(Boolean(props.required.value))}\"\n aria-invalid=\"${choice.ariaInvalid}\"\n aria-errormessage=\"${choice.ariaErrorMessage}\"\n aria-describedby=\"${choice.ariaDescribedBy}\">\n <legend id=\"${legendId}\" ?hidden=${() => !props.label.value}>\n ${props.label}${when(\n () => Boolean(props.required.value),\n () => html`\n <span aria-hidden=\"true\">*</span>\n `,\n )}\n </legend>\n <div class=\"radio-group-items\" part=\"items\">\n <slot></slot>\n </div>\n <div\n class=\"helper-text\"\n part=\"helper\"\n id=\"${choice.assistiveId}\"\n role=\"${() => (choice.errorText.value ? 'alert' : null)}\"\n aria-live=\"polite\"\n ?hidden=\"${() => !choice.errorText.value && !choice.helperText.value}\">\n ${() => choice.errorText.value || choice.helperText.value}\n </div>\n </fieldset>\n `;\n },\n styles: [disabledStateMixin, componentStyles],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"radio-group.js","names":[],"sources":["../src/inputs/radio-group/radio-group.ts"],"sourcesContent":["import {\n bind,\n createContext,\n createId,\n define,\n getHost,\n html,\n onCleanup,\n prop,\n provide,\n useEmit,\n useField,\n useSlots,\n watchEffect,\n when,\n} from '@vielzeug/ore';\nimport type { Readable } from '@vielzeug/ripple';\nimport {\n type ChoiceChangeDetail,\n createChoiceField,\n createListControl,\n getChoiceLabel,\n getLightChildrenByTag,\n lifecycleSignal,\n} from '../../core';\nimport { disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { disabledStateMixin } from '../../styles';\nimport type { ComponentSize, ThemeColor } from '../../types';\nimport componentStyles from './radio-group.css?inline';\n\n/** Radio group component properties */\nexport type OreRadioGroupProps = {\n /** Theme color tint */\n color?: ThemeColor;\n /** Disabled state */\n disabled?: boolean;\n /** Error message text */\n error?: string;\n /** Helper text displayed below the items */\n helper?: string;\n /** Group label text */\n label?: string;\n /** Form field name */\n name?: string;\n /** Layout orientation */\n orientation?: 'horizontal' | 'vertical';\n /** Required field */\n required?: boolean;\n /** Items size preset */\n size?: ComponentSize;\n /** Initial selected value */\n value?: string;\n};\n\nexport type RadioGroupContext = {\n color: Readable<ThemeColor | undefined>;\n disabled: Readable<boolean>;\n name: Readable<string | undefined>;\n select: (value: string, originalEvent?: Event) => void;\n size: Readable<ComponentSize | undefined>;\n value: Readable<string | undefined>;\n};\n\nexport const RADIO_GROUP_CTX = createContext<RadioGroupContext | undefined>('OreRadioGroup');\n\n/** Events emitted by the radio-group component */\nexport type OreRadioGroupEvents = {\n /** Emitted when the selection changes */\n change: ChoiceChangeDetail;\n};\n\n/**\n * A group of radio buttons that allows users to select a single option from a set.\n * Supports keyboard navigation (arrows) and automatic value management.\n *\n * @element ore-radio-group\n *\n * @attr {string} value - Selected value\n * @attr {string} name - Form field name\n * @attr {string} label - Group label\n * @attr {string} orientation - Layout: 'vertical' | 'horizontal'\n * @attr {boolean} required - Required field\n *\n * @fires change - Emitted when a radio is selected. detail: { values: string[], labels: string[], originalEvent?: Event }\n *\n * @slot - Place `ore-radio` elements here\n *\n * @cssprop --radio-group-direction - Flex direction of the items list ('row' | 'column')\n * @cssprop --radio-group-gap - Gap between radio items\n * @part items - Items container.\n * @example\n * ```html\n * <ore-radio-group name=\"plan\" label=\"Choose a plan\" value=\"free\" required>\n * <ore-radio value=\"free\">Free</ore-radio>\n * <ore-radio value=\"pro\">Pro</ore-radio>\n * <ore-radio value=\"enterprise\">Enterprise</ore-radio>\n * </ore-radio-group>\n * <ore-radio-group name=\"direction\" orientation=\"horizontal\" color=\"primary\">\n * <ore-radio value=\"left\">Left</ore-radio>\n * <ore-radio value=\"right\">Right</ore-radio>\n * </ore-radio-group>\n * ```\n */\nexport const RADIO_GROUP_TAG = 'ore-radio-group' as const;\ndefine<OreRadioGroupProps>(RADIO_GROUP_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n error: prop.string(),\n helper: prop.string(),\n label: prop.string(),\n name: prop.string(),\n orientation: prop.oneOf(['horizontal', 'vertical'] as const, 'vertical'),\n required: prop.bool(false),\n // Not auto-reflected (`reflect: false`): the derived, interaction-updated selection\n // (`selectedValue`) is the single writer for this attribute, via `bind()` below; letting\n // `prop.string()`'s own default reflection also write the raw incoming value would leave\n // two effects racing to set the same attribute from different sources.\n value: { ...prop.string(), reflect: false },\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreRadioGroupEvents>();\n const slots = useSlots();\n const watch = watchEffect;\n\n const choice = createChoiceField({\n disabled: props.disabled,\n error: props.error,\n helper: props.helper,\n label: props.label,\n prefix: 'radio-group',\n required: props.required,\n signal: lifecycleSignal(onCleanup),\n value: props.value,\n });\n\n choice.attachFormField(\n useField<string>({\n disabled: choice.disabled,\n onReset: choice.reset,\n toFormValue: (v) => v,\n validity: choice.validity,\n value: choice.formValue,\n }),\n );\n\n const selectedValue = choice.selectedValue;\n const isDisabled = props.disabled;\n\n bind({\n attr: {\n size: props.size,\n value: () => selectedValue.value || null,\n },\n });\n\n const getSlottedRadios = (): HTMLElement[] => getLightChildrenByTag(el, 'ore-radio');\n\n const getEnabledRadios = (): HTMLElement[] =>\n isDisabled.value ? [] : getSlottedRadios().filter((radio) => !radio.hasAttribute('disabled'));\n\n const getLabelForValue = (value: string): string => getChoiceLabel(getSlottedRadios(), value);\n\n const selectRadio = (val: string, originalEvent?: Event): void => {\n choice.setValues(val ? [val] : []);\n\n const labels = val ? [getLabelForValue(val)] : [];\n const values = val ? [val] : [];\n\n emit('change', { labels, originalEvent, values });\n choice.triggerValidation('blur');\n };\n\n provide(RADIO_GROUP_CTX, {\n color: props.color as Readable<ThemeColor | undefined>,\n disabled: isDisabled,\n name: props.name,\n select: selectRadio,\n size: props.size as Readable<ComponentSize | undefined>,\n value: selectedValue,\n });\n\n // Sync name/color/size/disabled/checked onto slotted ore-radio children.\n watch(() => {\n void slots.elements().value;\n void selectedValue.value;\n\n const radios = getSlottedRadios();\n\n for (const radio of radios) {\n const val = radio.getAttribute('value') ?? '';\n\n radio.toggleAttribute('checked', val === selectedValue.value);\n\n if (props.name.value) radio.setAttribute('name', props.name.value);\n else radio.removeAttribute('name');\n\n if (props.color.value) radio.setAttribute('color', props.color.value);\n else radio.removeAttribute('color');\n\n if (props.size.value) radio.setAttribute('size', props.size.value);\n else radio.removeAttribute('size');\n\n radio.toggleAttribute('disabled', isDisabled.value);\n }\n });\n\n // Roving tabindex: only the selected (or first) radio is tabbable.\n watch(() => {\n void slots.elements().value;\n\n const radios = getSlottedRadios();\n let hasFocusable = false;\n\n for (const radio of radios) {\n const isSelected = radio.getAttribute('value') === selectedValue.value;\n\n radio.setAttribute('tabindex', isSelected && !isDisabled.value ? '0' : '-1');\n\n if (isSelected && !isDisabled.value) hasFocusable = true;\n }\n\n if (!hasFocusable && radios.length > 0) {\n const first = radios.find((r) => !r.hasAttribute('disabled'));\n\n if (first) first.setAttribute('tabindex', '0');\n }\n });\n\n const listControl = createListControl<HTMLElement>({\n getItems: getEnabledRadios,\n keys: { next: ['ArrowDown', 'ArrowRight'], prev: ['ArrowUp', 'ArrowLeft'] },\n loop: true,\n onNavigate: ({ event, item }) => {\n item.focus();\n\n if (item.tagName === 'ORE-RADIO') {\n selectRadio(item.getAttribute('value') ?? '', event);\n }\n },\n signal: lifecycleSignal(onCleanup),\n });\n\n bind({\n on: {\n change: (e: Event) => {\n if (e.target === el) return;\n\n e.stopPropagation();\n selectRadio((e.target as HTMLElement).getAttribute('value') ?? '', e);\n },\n keydown: (e: KeyboardEvent) => {\n const radios = getEnabledRadios();\n\n if (!radios.length) return;\n\n const focused = radios.indexOf(document.activeElement as HTMLElement);\n\n if (focused === -1) return;\n\n listControl.set(focused);\n listControl.handleKeydown(e);\n },\n },\n });\n\n const legendId = createId('radio-group-legend');\n\n return html`\n <fieldset\n role=\"radiogroup\"\n aria-required=\"${() => String(Boolean(props.required.value))}\"\n aria-invalid=\"${choice.ariaInvalid}\"\n aria-errormessage=\"${choice.ariaErrorMessage}\"\n aria-describedby=\"${choice.ariaDescribedBy}\">\n <legend id=\"${legendId}\" ?hidden=${() => !props.label.value}>\n ${props.label}${when(\n () => Boolean(props.required.value),\n () => html`\n <span aria-hidden=\"true\">*</span>\n `,\n )}\n </legend>\n <div class=\"radio-group-items\" part=\"items\">\n <slot></slot>\n </div>\n <div\n class=\"helper-text\"\n part=\"helper\"\n id=\"${choice.assistiveId}\"\n role=\"${() => (choice.errorText.value ? 'alert' : null)}\"\n aria-live=\"polite\"\n ?hidden=\"${() => !choice.errorText.value && !choice.helperText.value}\">\n ${() => choice.errorText.value || choice.helperText.value}\n </div>\n </fieldset>\n `;\n },\n styles: [disabledStateMixin, componentStyles],\n});\n"],"mappings":"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"}