@ecoma-io/loom 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (495) hide show
  1. package/README.md +54 -57
  2. package/dist/blocks/AppHeader/AppHeader.js.map +1 -1
  3. package/dist/blocks/AppHeader/AppHeader.vue.d.ts +5 -6
  4. package/dist/blocks/AppHeader/AppHeader.vue.d.ts.map +1 -1
  5. package/dist/blocks/AppHeader/AppHeader.vue_vue_type_script_setup_true_lang.js +6 -7
  6. package/dist/blocks/AppHeader/AppHeader.vue_vue_type_script_setup_true_lang.js.map +1 -1
  7. package/dist/blocks/DashboardGrid/DashboardGrid.vue.d.ts +1 -1
  8. package/dist/blocks/DashboardGrid/DashboardGrid.vue.d.ts.map +1 -1
  9. package/dist/blocks/DesktopAppShell/DesktopAppShell.js +7 -0
  10. package/dist/blocks/DesktopAppShell/DesktopAppShell.js.map +1 -0
  11. package/dist/blocks/DesktopAppShell/DesktopAppShell.vue.d.ts +102 -0
  12. package/dist/blocks/DesktopAppShell/DesktopAppShell.vue.d.ts.map +1 -0
  13. package/dist/blocks/DesktopAppShell/DesktopAppShell.vue_vue_type_script_setup_true_lang.js +74 -0
  14. package/dist/blocks/DesktopAppShell/DesktopAppShell.vue_vue_type_script_setup_true_lang.js.map +1 -0
  15. package/dist/blocks/ErrorState/ErrorState.js +7 -0
  16. package/dist/blocks/ErrorState/ErrorState.js.map +1 -0
  17. package/dist/blocks/ErrorState/ErrorState.vue.d.ts +44 -0
  18. package/dist/blocks/ErrorState/ErrorState.vue.d.ts.map +1 -0
  19. package/dist/blocks/ErrorState/ErrorState.vue_vue_type_script_setup_true_lang.js +60 -0
  20. package/dist/blocks/ErrorState/ErrorState.vue_vue_type_script_setup_true_lang.js.map +1 -0
  21. package/dist/blocks/FormActions/FormActions.js +7 -0
  22. package/dist/blocks/FormActions/FormActions.js.map +1 -0
  23. package/dist/blocks/FormActions/FormActions.vue.d.ts +51 -0
  24. package/dist/blocks/FormActions/FormActions.vue.d.ts.map +1 -0
  25. package/dist/blocks/FormActions/FormActions.vue_vue_type_script_setup_true_lang.js +21 -0
  26. package/dist/blocks/FormActions/FormActions.vue_vue_type_script_setup_true_lang.js.map +1 -0
  27. package/dist/blocks/FormSection/FormSection.js +7 -0
  28. package/dist/blocks/FormSection/FormSection.js.map +1 -0
  29. package/dist/blocks/FormSection/FormSection.vue.d.ts +85 -0
  30. package/dist/blocks/FormSection/FormSection.vue.d.ts.map +1 -0
  31. package/dist/blocks/FormSection/FormSection.vue_vue_type_script_setup_true_lang.js +62 -0
  32. package/dist/blocks/FormSection/FormSection.vue_vue_type_script_setup_true_lang.js.map +1 -0
  33. package/dist/blocks/LoadingState/LoadingState.js +7 -0
  34. package/dist/blocks/LoadingState/LoadingState.js.map +1 -0
  35. package/dist/blocks/LoadingState/LoadingState.vue.d.ts +22 -0
  36. package/dist/blocks/LoadingState/LoadingState.vue.d.ts.map +1 -0
  37. package/dist/blocks/LoadingState/LoadingState.vue_vue_type_script_setup_true_lang.js +57 -0
  38. package/dist/blocks/LoadingState/LoadingState.vue_vue_type_script_setup_true_lang.js.map +1 -0
  39. package/dist/blocks/MetricCard/MetricCard.js +7 -0
  40. package/dist/blocks/MetricCard/MetricCard.js.map +1 -0
  41. package/dist/blocks/MetricCard/MetricCard.vue.d.ts +59 -0
  42. package/dist/blocks/MetricCard/MetricCard.vue.d.ts.map +1 -0
  43. package/dist/blocks/MetricCard/MetricCard.vue_vue_type_script_setup_true_lang.js +63 -0
  44. package/dist/blocks/MetricCard/MetricCard.vue_vue_type_script_setup_true_lang.js.map +1 -0
  45. package/dist/blocks/SidebarNav/SidebarNav.js.map +1 -1
  46. package/dist/blocks/SidebarNav/SidebarNav.vue_vue_type_script_setup_true_lang.js.map +1 -1
  47. package/dist/blocks/TitleBar/TitleBar.js.map +1 -1
  48. package/dist/blocks/TitleBar/TitleBar.vue.d.ts +37 -3
  49. package/dist/blocks/TitleBar/TitleBar.vue.d.ts.map +1 -1
  50. package/dist/blocks/TitleBar/TitleBar.vue_vue_type_script_setup_true_lang.js +14 -14
  51. package/dist/blocks/TitleBar/TitleBar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  52. package/dist/blocks/ToastStack/ToastStack.js.map +1 -1
  53. package/dist/blocks/ToastStack/ToastStack.vue.d.ts +20 -0
  54. package/dist/blocks/ToastStack/ToastStack.vue.d.ts.map +1 -1
  55. package/dist/blocks/ToastStack/ToastStack.vue_vue_type_script_setup_true_lang.js +16 -5
  56. package/dist/blocks/ToastStack/ToastStack.vue_vue_type_script_setup_true_lang.js.map +1 -1
  57. package/dist/composition/Center/Center.js +7 -0
  58. package/dist/composition/Center/Center.js.map +1 -0
  59. package/dist/composition/Center/Center.vue.d.ts +40 -0
  60. package/dist/composition/Center/Center.vue.d.ts.map +1 -0
  61. package/dist/composition/Center/Center.vue_vue_type_script_setup_true_lang.js +29 -0
  62. package/dist/composition/Center/Center.vue_vue_type_script_setup_true_lang.js.map +1 -0
  63. package/dist/composition/Frame/Frame.js +7 -0
  64. package/dist/composition/Frame/Frame.js.map +1 -0
  65. package/dist/composition/Frame/Frame.vue.d.ts +35 -0
  66. package/dist/composition/Frame/Frame.vue.d.ts.map +1 -0
  67. package/dist/composition/Frame/Frame.vue_vue_type_script_setup_true_lang.js +29 -0
  68. package/dist/composition/Frame/Frame.vue_vue_type_script_setup_true_lang.js.map +1 -0
  69. package/dist/composition/Grid/Grid.js +7 -0
  70. package/dist/composition/Grid/Grid.js.map +1 -0
  71. package/dist/composition/Grid/Grid.vue.d.ts +41 -0
  72. package/dist/composition/Grid/Grid.vue.d.ts.map +1 -0
  73. package/dist/composition/Grid/Grid.vue_vue_type_script_setup_true_lang.js +27 -0
  74. package/dist/composition/Grid/Grid.vue_vue_type_script_setup_true_lang.js.map +1 -0
  75. package/dist/composition/Inline/Inline.js +7 -0
  76. package/dist/composition/Inline/Inline.js.map +1 -0
  77. package/dist/composition/Inline/Inline.vue.d.ts +46 -0
  78. package/dist/composition/Inline/Inline.vue.d.ts.map +1 -0
  79. package/dist/composition/Inline/Inline.vue_vue_type_script_setup_true_lang.js +35 -0
  80. package/dist/composition/Inline/Inline.vue_vue_type_script_setup_true_lang.js.map +1 -0
  81. package/dist/composition/ScrollReel/ScrollReel.js +7 -0
  82. package/dist/composition/ScrollReel/ScrollReel.js.map +1 -0
  83. package/dist/composition/ScrollReel/ScrollReel.vue.d.ts +42 -0
  84. package/dist/composition/ScrollReel/ScrollReel.vue.d.ts.map +1 -0
  85. package/dist/composition/ScrollReel/ScrollReel.vue_vue_type_script_setup_true_lang.js +79 -0
  86. package/dist/composition/ScrollReel/ScrollReel.vue_vue_type_script_setup_true_lang.js.map +1 -0
  87. package/dist/composition/Sidebar/Sidebar.js +7 -0
  88. package/dist/composition/Sidebar/Sidebar.js.map +1 -0
  89. package/dist/composition/Sidebar/Sidebar.vue.d.ts +52 -0
  90. package/dist/composition/Sidebar/Sidebar.vue.d.ts.map +1 -0
  91. package/dist/composition/Sidebar/Sidebar.vue_vue_type_script_setup_true_lang.js +36 -0
  92. package/dist/composition/Sidebar/Sidebar.vue_vue_type_script_setup_true_lang.js.map +1 -0
  93. package/dist/composition/Split/Split.js +7 -0
  94. package/dist/composition/Split/Split.js.map +1 -0
  95. package/dist/composition/Split/Split.vue.d.ts +58 -0
  96. package/dist/composition/Split/Split.vue.d.ts.map +1 -0
  97. package/dist/composition/Split/Split.vue_vue_type_script_setup_true_lang.js +40 -0
  98. package/dist/composition/Split/Split.vue_vue_type_script_setup_true_lang.js.map +1 -0
  99. package/dist/composition/Stack/Stack.js +7 -0
  100. package/dist/composition/Stack/Stack.js.map +1 -0
  101. package/dist/composition/Stack/Stack.vue.d.ts +43 -0
  102. package/dist/composition/Stack/Stack.vue.d.ts.map +1 -0
  103. package/dist/composition/Stack/Stack.vue_vue_type_script_setup_true_lang.js +30 -0
  104. package/dist/composition/Stack/Stack.vue_vue_type_script_setup_true_lang.js.map +1 -0
  105. package/dist/index.d.ts +119 -11
  106. package/dist/index.d.ts.map +1 -1
  107. package/dist/index.js +83 -5
  108. package/dist/layouts/AppShell/AppShell.js +7 -0
  109. package/dist/layouts/AppShell/AppShell.js.map +1 -0
  110. package/dist/layouts/AppShell/AppShell.vue.d.ts +51 -0
  111. package/dist/layouts/AppShell/AppShell.vue.d.ts.map +1 -0
  112. package/dist/layouts/AppShell/AppShell.vue_vue_type_script_setup_true_lang.js +47 -0
  113. package/dist/layouts/AppShell/AppShell.vue_vue_type_script_setup_true_lang.js.map +1 -0
  114. package/dist/layouts/Centered/Centered.js +7 -0
  115. package/dist/layouts/Centered/Centered.js.map +1 -0
  116. package/dist/layouts/Centered/Centered.vue.d.ts +48 -0
  117. package/dist/layouts/Centered/Centered.vue.d.ts.map +1 -0
  118. package/dist/layouts/Centered/Centered.vue_vue_type_script_setup_true_lang.js +35 -0
  119. package/dist/layouts/Centered/Centered.vue_vue_type_script_setup_true_lang.js.map +1 -0
  120. package/dist/layouts/Dashboard/Dashboard.js +7 -0
  121. package/dist/layouts/Dashboard/Dashboard.js.map +1 -0
  122. package/dist/layouts/Dashboard/Dashboard.vue.d.ts +60 -0
  123. package/dist/layouts/Dashboard/Dashboard.vue.d.ts.map +1 -0
  124. package/dist/layouts/Dashboard/Dashboard.vue_vue_type_script_setup_true_lang.js +64 -0
  125. package/dist/layouts/Dashboard/Dashboard.vue_vue_type_script_setup_true_lang.js.map +1 -0
  126. package/dist/layouts/FormLayout/FormLayout.js +7 -0
  127. package/dist/layouts/FormLayout/FormLayout.js.map +1 -0
  128. package/dist/layouts/FormLayout/FormLayout.vue.d.ts +46 -0
  129. package/dist/layouts/FormLayout/FormLayout.vue.d.ts.map +1 -0
  130. package/dist/layouts/FormLayout/FormLayout.vue_vue_type_script_setup_true_lang.js +28 -0
  131. package/dist/layouts/FormLayout/FormLayout.vue_vue_type_script_setup_true_lang.js.map +1 -0
  132. package/dist/layouts/MasterDetail/MasterDetail.js +7 -0
  133. package/dist/layouts/MasterDetail/MasterDetail.js.map +1 -0
  134. package/dist/layouts/MasterDetail/MasterDetail.vue.d.ts +49 -0
  135. package/dist/layouts/MasterDetail/MasterDetail.vue.d.ts.map +1 -0
  136. package/dist/layouts/MasterDetail/MasterDetail.vue_vue_type_script_setup_true_lang.js +42 -0
  137. package/dist/layouts/MasterDetail/MasterDetail.vue_vue_type_script_setup_true_lang.js.map +1 -0
  138. package/dist/layouts/Reading/Reading.js +7 -0
  139. package/dist/layouts/Reading/Reading.js.map +1 -0
  140. package/dist/layouts/Reading/Reading.vue.d.ts +24 -0
  141. package/dist/layouts/Reading/Reading.vue.d.ts.map +1 -0
  142. package/dist/layouts/Reading/Reading.vue_vue_type_script_setup_true_lang.js +29 -0
  143. package/dist/layouts/Reading/Reading.vue_vue_type_script_setup_true_lang.js.map +1 -0
  144. package/dist/layouts/Settings/Settings.js +7 -0
  145. package/dist/layouts/Settings/Settings.js.map +1 -0
  146. package/dist/layouts/Settings/Settings.vue.d.ts +39 -0
  147. package/dist/layouts/Settings/Settings.vue.d.ts.map +1 -0
  148. package/dist/layouts/Settings/Settings.vue_vue_type_script_setup_true_lang.js +35 -0
  149. package/dist/layouts/Settings/Settings.vue_vue_type_script_setup_true_lang.js.map +1 -0
  150. package/dist/layouts/SplitLayout/SplitLayout.js +7 -0
  151. package/dist/layouts/SplitLayout/SplitLayout.js.map +1 -0
  152. package/dist/layouts/SplitLayout/SplitLayout.vue.d.ts +63 -0
  153. package/dist/layouts/SplitLayout/SplitLayout.vue.d.ts.map +1 -0
  154. package/dist/layouts/SplitLayout/SplitLayout.vue_vue_type_script_setup_true_lang.js +46 -0
  155. package/dist/layouts/SplitLayout/SplitLayout.vue_vue_type_script_setup_true_lang.js.map +1 -0
  156. package/dist/lib/ancestor-disabled.d.ts +35 -0
  157. package/dist/lib/ancestor-disabled.d.ts.map +1 -0
  158. package/dist/lib/ancestor-disabled.js +86 -0
  159. package/dist/lib/ancestor-disabled.js.map +1 -0
  160. package/dist/lib/cn.d.ts.map +1 -1
  161. package/dist/lib/cn.js +46 -1
  162. package/dist/lib/cn.js.map +1 -1
  163. package/dist/lib/count-labels.d.ts +78 -0
  164. package/dist/lib/count-labels.d.ts.map +1 -0
  165. package/dist/lib/count-labels.js +29 -0
  166. package/dist/lib/count-labels.js.map +1 -0
  167. package/dist/lib/date-labels.d.ts +278 -0
  168. package/dist/lib/date-labels.d.ts.map +1 -0
  169. package/dist/lib/date-labels.js +157 -0
  170. package/dist/lib/date-labels.js.map +1 -0
  171. package/dist/lib/field-context.d.ts +178 -0
  172. package/dist/lib/field-context.d.ts.map +1 -0
  173. package/dist/lib/field-context.js +106 -0
  174. package/dist/lib/field-context.js.map +1 -0
  175. package/dist/lib/label-registry.d.ts +75 -0
  176. package/dist/lib/label-registry.d.ts.map +1 -0
  177. package/dist/lib/labels.d.ts +116 -0
  178. package/dist/lib/labels.d.ts.map +1 -0
  179. package/dist/lib/labels.js +84 -0
  180. package/dist/lib/labels.js.map +1 -0
  181. package/dist/lib/theme.d.ts +68 -0
  182. package/dist/lib/theme.d.ts.map +1 -0
  183. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/CalendarDate.js +236 -0
  184. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/CalendarDate.js.map +1 -0
  185. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/calendars/GregorianCalendar.js +117 -0
  186. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/calendars/GregorianCalendar.js.map +1 -0
  187. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/conversion.js +142 -0
  188. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/conversion.js.map +1 -0
  189. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/manipulation.js +280 -0
  190. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/manipulation.js.map +1 -0
  191. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/queries.js +40 -0
  192. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/queries.js.map +1 -0
  193. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/string.js +69 -0
  194. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/string.js.map +1 -0
  195. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/utils.js +8 -0
  196. package/dist/node_modules/.pnpm/@internationalized_date@3.12.3/node_modules/@internationalized/date/dist/private/utils.js.map +1 -0
  197. package/dist/primitives/Accordion/Accordion.js +7 -0
  198. package/dist/primitives/Accordion/Accordion.js.map +1 -0
  199. package/dist/primitives/Accordion/Accordion.vue.d.ts +68 -0
  200. package/dist/primitives/Accordion/Accordion.vue.d.ts.map +1 -0
  201. package/dist/primitives/Accordion/Accordion.vue_vue_type_script_setup_true_lang.js +67 -0
  202. package/dist/primitives/Accordion/Accordion.vue_vue_type_script_setup_true_lang.js.map +1 -0
  203. package/dist/primitives/AlertDialog/AlertDialog.js +7 -0
  204. package/dist/primitives/AlertDialog/AlertDialog.js.map +1 -0
  205. package/dist/primitives/AlertDialog/AlertDialog.vue.d.ts +94 -0
  206. package/dist/primitives/AlertDialog/AlertDialog.vue.d.ts.map +1 -0
  207. package/dist/primitives/AlertDialog/AlertDialog.vue_vue_type_script_setup_true_lang.js +99 -0
  208. package/dist/primitives/AlertDialog/AlertDialog.vue_vue_type_script_setup_true_lang.js.map +1 -0
  209. package/dist/primitives/Avatar/Avatar.js +2 -2
  210. package/dist/primitives/Avatar/Avatar.js.map +1 -1
  211. package/dist/primitives/Avatar/Avatar.vue.d.ts +30 -3
  212. package/dist/primitives/Avatar/Avatar.vue.d.ts.map +1 -1
  213. package/dist/primitives/Avatar/Avatar.vue_vue_type_script_setup_true_lang.js +95 -14
  214. package/dist/primitives/Avatar/Avatar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  215. package/dist/primitives/AvatarGroup/AvatarGroup.js +7 -0
  216. package/dist/primitives/AvatarGroup/AvatarGroup.js.map +1 -0
  217. package/dist/primitives/AvatarGroup/AvatarGroup.vue.d.ts +104 -0
  218. package/dist/primitives/AvatarGroup/AvatarGroup.vue.d.ts.map +1 -0
  219. package/dist/primitives/AvatarGroup/AvatarGroup.vue_vue_type_script_setup_true_lang.js +139 -0
  220. package/dist/primitives/AvatarGroup/AvatarGroup.vue_vue_type_script_setup_true_lang.js.map +1 -0
  221. package/dist/primitives/Badge/Badge.js.map +1 -1
  222. package/dist/primitives/Badge/Badge.vue.d.ts +6 -6
  223. package/dist/primitives/Badge/Badge.vue.d.ts.map +1 -1
  224. package/dist/primitives/Badge/Badge.vue_vue_type_script_setup_true_lang.js +1 -1
  225. package/dist/primitives/Badge/Badge.vue_vue_type_script_setup_true_lang.js.map +1 -1
  226. package/dist/primitives/Breadcrumb/Breadcrumb.js +7 -0
  227. package/dist/primitives/Breadcrumb/Breadcrumb.js.map +1 -0
  228. package/dist/primitives/Breadcrumb/Breadcrumb.vue.d.ts +25 -0
  229. package/dist/primitives/Breadcrumb/Breadcrumb.vue.d.ts.map +1 -0
  230. package/dist/primitives/Breadcrumb/Breadcrumb.vue_vue_type_script_setup_true_lang.js +48 -0
  231. package/dist/primitives/Breadcrumb/Breadcrumb.vue_vue_type_script_setup_true_lang.js.map +1 -0
  232. package/dist/primitives/Button/Button.js +2 -2
  233. package/dist/primitives/Button/Button.js.map +1 -1
  234. package/dist/primitives/Button/Button.vue.d.ts +31 -8
  235. package/dist/primitives/Button/Button.vue.d.ts.map +1 -1
  236. package/dist/primitives/Button/Button.vue_vue_type_script_setup_true_lang.js +32 -16
  237. package/dist/primitives/Button/Button.vue_vue_type_script_setup_true_lang.js.map +1 -1
  238. package/dist/primitives/Checkbox/Checkbox.js.map +1 -1
  239. package/dist/primitives/Checkbox/Checkbox.vue.d.ts +18 -3
  240. package/dist/primitives/Checkbox/Checkbox.vue.d.ts.map +1 -1
  241. package/dist/primitives/Checkbox/Checkbox.vue_vue_type_script_setup_true_lang.js +46 -7
  242. package/dist/primitives/Checkbox/Checkbox.vue_vue_type_script_setup_true_lang.js.map +1 -1
  243. package/dist/primitives/Chip/Chip.js +7 -0
  244. package/dist/primitives/Chip/Chip.js.map +1 -0
  245. package/dist/primitives/Chip/Chip.vue.d.ts +79 -0
  246. package/dist/primitives/Chip/Chip.vue.d.ts.map +1 -0
  247. package/dist/primitives/Chip/Chip.vue_vue_type_script_setup_true_lang.js +139 -0
  248. package/dist/primitives/Chip/Chip.vue_vue_type_script_setup_true_lang.js.map +1 -0
  249. package/dist/primitives/ColorPicker/ColorPicker.js +7 -0
  250. package/dist/primitives/ColorPicker/ColorPicker.js.map +1 -0
  251. package/dist/primitives/ColorPicker/ColorPicker.vue.d.ts +125 -0
  252. package/dist/primitives/ColorPicker/ColorPicker.vue.d.ts.map +1 -0
  253. package/dist/primitives/ColorPicker/ColorPicker.vue_vue_type_script_setup_true_lang.js +301 -0
  254. package/dist/primitives/ColorPicker/ColorPicker.vue_vue_type_script_setup_true_lang.js.map +1 -0
  255. package/dist/primitives/Combobox/Combobox.js +7 -0
  256. package/dist/primitives/Combobox/Combobox.js.map +1 -0
  257. package/dist/primitives/Combobox/Combobox.vue.d.ts +205 -0
  258. package/dist/primitives/Combobox/Combobox.vue.d.ts.map +1 -0
  259. package/dist/primitives/Combobox/Combobox.vue_vue_type_script_setup_true_lang.js +345 -0
  260. package/dist/primitives/Combobox/Combobox.vue_vue_type_script_setup_true_lang.js.map +1 -0
  261. package/dist/primitives/ContextMenu/ContextMenu.js +7 -0
  262. package/dist/primitives/ContextMenu/ContextMenu.js.map +1 -0
  263. package/dist/primitives/ContextMenu/ContextMenu.vue.d.ts +55 -0
  264. package/dist/primitives/ContextMenu/ContextMenu.vue.d.ts.map +1 -0
  265. package/dist/primitives/ContextMenu/ContextMenu.vue_vue_type_script_setup_true_lang.js +82 -0
  266. package/dist/primitives/ContextMenu/ContextMenu.vue_vue_type_script_setup_true_lang.js.map +1 -0
  267. package/dist/primitives/DatePicker/DatePicker.js +7 -0
  268. package/dist/primitives/DatePicker/DatePicker.js.map +1 -0
  269. package/dist/primitives/DatePicker/DatePicker.vue.d.ts +102 -0
  270. package/dist/primitives/DatePicker/DatePicker.vue.d.ts.map +1 -0
  271. package/dist/primitives/DatePicker/DatePicker.vue_vue_type_script_setup_true_lang.js +292 -0
  272. package/dist/primitives/DatePicker/DatePicker.vue_vue_type_script_setup_true_lang.js.map +1 -0
  273. package/dist/primitives/DateRangePicker/DateRangePicker.js +7 -0
  274. package/dist/primitives/DateRangePicker/DateRangePicker.js.map +1 -0
  275. package/dist/primitives/DateRangePicker/DateRangePicker.vue.d.ts +173 -0
  276. package/dist/primitives/DateRangePicker/DateRangePicker.vue.d.ts.map +1 -0
  277. package/dist/primitives/DateRangePicker/DateRangePicker.vue_vue_type_script_setup_true_lang.js +412 -0
  278. package/dist/primitives/DateRangePicker/DateRangePicker.vue_vue_type_script_setup_true_lang.js.map +1 -0
  279. package/dist/primitives/DateTimePicker/DateTimePicker.js +7 -0
  280. package/dist/primitives/DateTimePicker/DateTimePicker.js.map +1 -0
  281. package/dist/primitives/DateTimePicker/DateTimePicker.vue.d.ts +113 -0
  282. package/dist/primitives/DateTimePicker/DateTimePicker.vue.d.ts.map +1 -0
  283. package/dist/primitives/DateTimePicker/DateTimePicker.vue_vue_type_script_setup_true_lang.js +358 -0
  284. package/dist/primitives/DateTimePicker/DateTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -0
  285. package/dist/primitives/DateTimeRangePicker/DateTimeRangePicker.js +7 -0
  286. package/dist/primitives/DateTimeRangePicker/DateTimeRangePicker.js.map +1 -0
  287. package/dist/primitives/DateTimeRangePicker/DateTimeRangePicker.vue.d.ts +181 -0
  288. package/dist/primitives/DateTimeRangePicker/DateTimeRangePicker.vue.d.ts.map +1 -0
  289. package/dist/primitives/DateTimeRangePicker/DateTimeRangePicker.vue_vue_type_script_setup_true_lang.js +562 -0
  290. package/dist/primitives/DateTimeRangePicker/DateTimeRangePicker.vue_vue_type_script_setup_true_lang.js.map +1 -0
  291. package/dist/primitives/Dialog/Dialog.js +2 -2
  292. package/dist/primitives/Dialog/Dialog.js.map +1 -1
  293. package/dist/primitives/Dialog/Dialog.vue.d.ts +39 -0
  294. package/dist/primitives/Dialog/Dialog.vue.d.ts.map +1 -1
  295. package/dist/primitives/Dialog/Dialog.vue_vue_type_script_setup_true_lang.js +14 -5
  296. package/dist/primitives/Dialog/Dialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
  297. package/dist/primitives/Drawer/Drawer.js +7 -0
  298. package/dist/primitives/Drawer/Drawer.js.map +1 -0
  299. package/dist/primitives/Drawer/Drawer.vue.d.ts +110 -0
  300. package/dist/primitives/Drawer/Drawer.vue.d.ts.map +1 -0
  301. package/dist/primitives/Drawer/Drawer.vue_vue_type_script_setup_true_lang.js +223 -0
  302. package/dist/primitives/Drawer/Drawer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  303. package/dist/primitives/DropdownMenu/DropdownMenu.js.map +1 -1
  304. package/dist/primitives/DropdownMenu/DropdownMenu.vue.d.ts.map +1 -1
  305. package/dist/primitives/DropdownMenu/DropdownMenu.vue_vue_type_script_setup_true_lang.js +2 -2
  306. package/dist/primitives/DropdownMenu/DropdownMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  307. package/dist/primitives/Editable/Editable.js +7 -0
  308. package/dist/primitives/Editable/Editable.js.map +1 -0
  309. package/dist/primitives/Editable/Editable.vue.d.ts +200 -0
  310. package/dist/primitives/Editable/Editable.vue.d.ts.map +1 -0
  311. package/dist/primitives/Editable/Editable.vue_vue_type_script_setup_true_lang.js +275 -0
  312. package/dist/primitives/Editable/Editable.vue_vue_type_script_setup_true_lang.js.map +1 -0
  313. package/dist/primitives/Field/Field.js.map +1 -1
  314. package/dist/primitives/Field/Field.vue.d.ts +32 -17
  315. package/dist/primitives/Field/Field.vue.d.ts.map +1 -1
  316. package/dist/primitives/Field/Field.vue_vue_type_script_setup_true_lang.js +51 -18
  317. package/dist/primitives/Field/Field.vue_vue_type_script_setup_true_lang.js.map +1 -1
  318. package/dist/primitives/Fieldset/Fieldset.js +7 -0
  319. package/dist/primitives/Fieldset/Fieldset.js.map +1 -0
  320. package/dist/primitives/Fieldset/Fieldset.vue.d.ts +91 -0
  321. package/dist/primitives/Fieldset/Fieldset.vue.d.ts.map +1 -0
  322. package/dist/primitives/Fieldset/Fieldset.vue_vue_type_script_setup_true_lang.js +138 -0
  323. package/dist/primitives/Fieldset/Fieldset.vue_vue_type_script_setup_true_lang.js.map +1 -0
  324. package/dist/primitives/FileUpload/FileUpload.js +7 -0
  325. package/dist/primitives/FileUpload/FileUpload.js.map +1 -0
  326. package/dist/primitives/FileUpload/FileUpload.vue.d.ts +132 -0
  327. package/dist/primitives/FileUpload/FileUpload.vue.d.ts.map +1 -0
  328. package/dist/primitives/FileUpload/FileUpload.vue_vue_type_script_setup_true_lang.js +359 -0
  329. package/dist/primitives/FileUpload/FileUpload.vue_vue_type_script_setup_true_lang.js.map +1 -0
  330. package/dist/primitives/HoverCard/HoverCard.js +7 -0
  331. package/dist/primitives/HoverCard/HoverCard.js.map +1 -0
  332. package/dist/primitives/HoverCard/HoverCard.vue.d.ts +68 -0
  333. package/dist/primitives/HoverCard/HoverCard.vue.d.ts.map +1 -0
  334. package/dist/primitives/HoverCard/HoverCard.vue_vue_type_script_setup_true_lang.js +62 -0
  335. package/dist/primitives/HoverCard/HoverCard.vue_vue_type_script_setup_true_lang.js.map +1 -0
  336. package/dist/primitives/IconButton/IconButton.js +7 -0
  337. package/dist/primitives/IconButton/IconButton.js.map +1 -0
  338. package/dist/primitives/IconButton/IconButton.vue.d.ts +45 -0
  339. package/dist/primitives/IconButton/IconButton.vue.d.ts.map +1 -0
  340. package/dist/primitives/IconButton/IconButton.vue_vue_type_script_setup_true_lang.js +58 -0
  341. package/dist/primitives/IconButton/IconButton.vue_vue_type_script_setup_true_lang.js.map +1 -0
  342. package/dist/primitives/Indicator/Indicator.js +7 -0
  343. package/dist/primitives/Indicator/Indicator.js.map +1 -0
  344. package/dist/primitives/Indicator/Indicator.vue.d.ts +144 -0
  345. package/dist/primitives/Indicator/Indicator.vue.d.ts.map +1 -0
  346. package/dist/primitives/Indicator/Indicator.vue_vue_type_script_setup_true_lang.js +198 -0
  347. package/dist/primitives/Indicator/Indicator.vue_vue_type_script_setup_true_lang.js.map +1 -0
  348. package/dist/primitives/Link/Link.js +7 -0
  349. package/dist/primitives/Link/Link.js.map +1 -0
  350. package/dist/primitives/Link/Link.vue.d.ts +46 -0
  351. package/dist/primitives/Link/Link.vue.d.ts.map +1 -0
  352. package/dist/primitives/Link/Link.vue_vue_type_script_setup_true_lang.js +85 -0
  353. package/dist/primitives/Link/Link.vue_vue_type_script_setup_true_lang.js.map +1 -0
  354. package/dist/primitives/Menubar/Menubar.js.map +1 -1
  355. package/dist/primitives/Menubar/Menubar.vue.d.ts.map +1 -1
  356. package/dist/primitives/Menubar/Menubar.vue_vue_type_script_setup_true_lang.js +1 -1
  357. package/dist/primitives/Menubar/Menubar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  358. package/dist/primitives/NumberField/NumberField.js +2 -2
  359. package/dist/primitives/NumberField/NumberField.js.map +1 -1
  360. package/dist/primitives/NumberField/NumberField.vue.d.ts +86 -25
  361. package/dist/primitives/NumberField/NumberField.vue.d.ts.map +1 -1
  362. package/dist/primitives/NumberField/NumberField.vue_vue_type_script_setup_true_lang.js +83 -39
  363. package/dist/primitives/NumberField/NumberField.vue_vue_type_script_setup_true_lang.js.map +1 -1
  364. package/dist/primitives/OtpInput/OtpInput.js +7 -0
  365. package/dist/primitives/OtpInput/OtpInput.js.map +1 -0
  366. package/dist/primitives/OtpInput/OtpInput.vue.d.ts +110 -0
  367. package/dist/primitives/OtpInput/OtpInput.vue.d.ts.map +1 -0
  368. package/dist/primitives/OtpInput/OtpInput.vue_vue_type_script_setup_true_lang.js +130 -0
  369. package/dist/primitives/OtpInput/OtpInput.vue_vue_type_script_setup_true_lang.js.map +1 -0
  370. package/dist/primitives/Pagination/Pagination.js +7 -0
  371. package/dist/primitives/Pagination/Pagination.js.map +1 -0
  372. package/dist/primitives/Pagination/Pagination.vue.d.ts +143 -0
  373. package/dist/primitives/Pagination/Pagination.vue.d.ts.map +1 -0
  374. package/dist/primitives/Pagination/Pagination.vue_vue_type_script_setup_true_lang.js +231 -0
  375. package/dist/primitives/Pagination/Pagination.vue_vue_type_script_setup_true_lang.js.map +1 -0
  376. package/dist/primitives/Progress/Progress.js +2 -2
  377. package/dist/primitives/Progress/Progress.js.map +1 -1
  378. package/dist/primitives/Progress/Progress.vue.d.ts +81 -15
  379. package/dist/primitives/Progress/Progress.vue.d.ts.map +1 -1
  380. package/dist/primitives/Progress/Progress.vue_vue_type_script_setup_true_lang.js +88 -22
  381. package/dist/primitives/Progress/Progress.vue_vue_type_script_setup_true_lang.js.map +1 -1
  382. package/dist/primitives/RadialProgress/RadialProgress.js +7 -0
  383. package/dist/primitives/RadialProgress/RadialProgress.js.map +1 -0
  384. package/dist/primitives/RadialProgress/RadialProgress.vue.d.ts +96 -0
  385. package/dist/primitives/RadialProgress/RadialProgress.vue.d.ts.map +1 -0
  386. package/dist/primitives/RadialProgress/RadialProgress.vue_vue_type_script_setup_true_lang.js +189 -0
  387. package/dist/primitives/RadialProgress/RadialProgress.vue_vue_type_script_setup_true_lang.js.map +1 -0
  388. package/dist/primitives/RadioGroup/RadioGroup.js.map +1 -1
  389. package/dist/primitives/RadioGroup/RadioGroup.vue.d.ts +7 -7
  390. package/dist/primitives/RadioGroup/RadioGroup.vue.d.ts.map +1 -1
  391. package/dist/primitives/RadioGroup/RadioGroup.vue_vue_type_script_setup_true_lang.js +26 -9
  392. package/dist/primitives/RadioGroup/RadioGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  393. package/dist/primitives/Rating/Rating.js +7 -0
  394. package/dist/primitives/Rating/Rating.js.map +1 -0
  395. package/dist/primitives/Rating/Rating.vue.d.ts +113 -0
  396. package/dist/primitives/Rating/Rating.vue.d.ts.map +1 -0
  397. package/dist/primitives/Rating/Rating.vue_vue_type_script_setup_true_lang.js +282 -0
  398. package/dist/primitives/Rating/Rating.vue_vue_type_script_setup_true_lang.js.map +1 -0
  399. package/dist/primitives/ScrollArea/ScrollArea.js +7 -0
  400. package/dist/primitives/ScrollArea/ScrollArea.js.map +1 -0
  401. package/dist/primitives/ScrollArea/ScrollArea.vue.d.ts +25 -0
  402. package/dist/primitives/ScrollArea/ScrollArea.vue.d.ts.map +1 -0
  403. package/dist/primitives/ScrollArea/ScrollArea.vue_vue_type_script_setup_true_lang.js +45 -0
  404. package/dist/primitives/ScrollArea/ScrollArea.vue_vue_type_script_setup_true_lang.js.map +1 -0
  405. package/dist/primitives/SegmentedControl/SegmentedControl.js.map +1 -1
  406. package/dist/primitives/SegmentedControl/SegmentedControl.vue.d.ts +5 -5
  407. package/dist/primitives/SegmentedControl/SegmentedControl.vue.d.ts.map +1 -1
  408. package/dist/primitives/SegmentedControl/SegmentedControl.vue_vue_type_script_setup_true_lang.js +51 -8
  409. package/dist/primitives/SegmentedControl/SegmentedControl.vue_vue_type_script_setup_true_lang.js.map +1 -1
  410. package/dist/primitives/Select/Select.js.map +1 -1
  411. package/dist/primitives/Select/Select.vue.d.ts +10 -10
  412. package/dist/primitives/Select/Select.vue.d.ts.map +1 -1
  413. package/dist/primitives/Select/Select.vue_vue_type_script_setup_true_lang.js +105 -52
  414. package/dist/primitives/Select/Select.vue_vue_type_script_setup_true_lang.js.map +1 -1
  415. package/dist/primitives/Skeleton/Skeleton.vue.d.ts +1 -1
  416. package/dist/primitives/Slider/Slider.js.map +1 -1
  417. package/dist/primitives/Slider/Slider.vue.d.ts +24 -4
  418. package/dist/primitives/Slider/Slider.vue.d.ts.map +1 -1
  419. package/dist/primitives/Slider/Slider.vue_vue_type_script_setup_true_lang.js +79 -9
  420. package/dist/primitives/Slider/Slider.vue_vue_type_script_setup_true_lang.js.map +1 -1
  421. package/dist/primitives/SpeedDial/SpeedDial.js +7 -0
  422. package/dist/primitives/SpeedDial/SpeedDial.js.map +1 -0
  423. package/dist/primitives/SpeedDial/SpeedDial.vue.d.ts +58 -0
  424. package/dist/primitives/SpeedDial/SpeedDial.vue.d.ts.map +1 -0
  425. package/dist/primitives/SpeedDial/SpeedDial.vue_vue_type_script_setup_true_lang.js +175 -0
  426. package/dist/primitives/SpeedDial/SpeedDial.vue_vue_type_script_setup_true_lang.js.map +1 -0
  427. package/dist/primitives/Stepper/Stepper.js +7 -0
  428. package/dist/primitives/Stepper/Stepper.js.map +1 -0
  429. package/dist/primitives/Stepper/Stepper.vue.d.ts +119 -0
  430. package/dist/primitives/Stepper/Stepper.vue.d.ts.map +1 -0
  431. package/dist/primitives/Stepper/Stepper.vue_vue_type_script_setup_true_lang.js +202 -0
  432. package/dist/primitives/Stepper/Stepper.vue_vue_type_script_setup_true_lang.js.map +1 -0
  433. package/dist/primitives/Switch/Switch.js.map +1 -1
  434. package/dist/primitives/Switch/Switch.vue.d.ts +13 -3
  435. package/dist/primitives/Switch/Switch.vue.d.ts.map +1 -1
  436. package/dist/primitives/Switch/Switch.vue_vue_type_script_setup_true_lang.js +34 -5
  437. package/dist/primitives/Switch/Switch.vue_vue_type_script_setup_true_lang.js.map +1 -1
  438. package/dist/primitives/Tabs/Tabs.js.map +1 -1
  439. package/dist/primitives/Tabs/Tabs.vue.d.ts.map +1 -1
  440. package/dist/primitives/Tabs/Tabs.vue_vue_type_script_setup_true_lang.js +1 -1
  441. package/dist/primitives/Tabs/Tabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
  442. package/dist/primitives/TagsInput/TagsInput.js +7 -0
  443. package/dist/primitives/TagsInput/TagsInput.js.map +1 -0
  444. package/dist/primitives/TagsInput/TagsInput.vue.d.ts +156 -0
  445. package/dist/primitives/TagsInput/TagsInput.vue.d.ts.map +1 -0
  446. package/dist/primitives/TagsInput/TagsInput.vue_vue_type_script_setup_true_lang.js +387 -0
  447. package/dist/primitives/TagsInput/TagsInput.vue_vue_type_script_setup_true_lang.js.map +1 -0
  448. package/dist/primitives/TextField/TextField.js +2 -2
  449. package/dist/primitives/TextField/TextField.js.map +1 -1
  450. package/dist/primitives/TextField/TextField.vue.d.ts +119 -10
  451. package/dist/primitives/TextField/TextField.vue.d.ts.map +1 -1
  452. package/dist/primitives/TextField/TextField.vue_vue_type_script_setup_true_lang.js +270 -21
  453. package/dist/primitives/TextField/TextField.vue_vue_type_script_setup_true_lang.js.map +1 -1
  454. package/dist/primitives/Textarea/Textarea.js +2 -2
  455. package/dist/primitives/Textarea/Textarea.js.map +1 -1
  456. package/dist/primitives/Textarea/Textarea.vue.d.ts +114 -14
  457. package/dist/primitives/Textarea/Textarea.vue.d.ts.map +1 -1
  458. package/dist/primitives/Textarea/Textarea.vue_vue_type_script_setup_true_lang.js +216 -20
  459. package/dist/primitives/Textarea/Textarea.vue_vue_type_script_setup_true_lang.js.map +1 -1
  460. package/dist/primitives/TimePicker/TimePicker.js +7 -0
  461. package/dist/primitives/TimePicker/TimePicker.js.map +1 -0
  462. package/dist/primitives/TimePicker/TimePicker.vue.d.ts +111 -0
  463. package/dist/primitives/TimePicker/TimePicker.vue.d.ts.map +1 -0
  464. package/dist/primitives/TimePicker/TimePicker.vue_vue_type_script_setup_true_lang.js +185 -0
  465. package/dist/primitives/TimePicker/TimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -0
  466. package/dist/primitives/Toast/Toast.js +2 -1
  467. package/dist/primitives/Toast/Toast.js.map +1 -1
  468. package/dist/primitives/Toast/Toast.vue.d.ts +29 -3
  469. package/dist/primitives/Toast/Toast.vue.d.ts.map +1 -1
  470. package/dist/primitives/Toast/Toast.vue_vue_type_script_setup_true_lang.js +17 -7
  471. package/dist/primitives/Toast/Toast.vue_vue_type_script_setup_true_lang.js.map +1 -1
  472. package/dist/primitives/Toast/ToastItem.js +2 -2
  473. package/dist/primitives/Toast/ToastItem.js.map +1 -1
  474. package/dist/primitives/Toast/ToastItem.vue.d.ts +69 -12
  475. package/dist/primitives/Toast/ToastItem.vue.d.ts.map +1 -1
  476. package/dist/primitives/Toast/ToastItem.vue_vue_type_script_setup_true_lang.js +23 -23
  477. package/dist/primitives/Toast/ToastItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  478. package/dist/primitives/Tooltip/Tooltip.vue.d.ts +1 -1
  479. package/dist/primitives/Tooltip/Tooltip.vue.d.ts.map +1 -1
  480. package/dist/primitives/WindowControls/WindowControls.js +2 -2
  481. package/dist/primitives/WindowControls/WindowControls.js.map +1 -1
  482. package/dist/primitives/WindowControls/WindowControls.vue.d.ts +66 -10
  483. package/dist/primitives/WindowControls/WindowControls.vue.d.ts.map +1 -1
  484. package/dist/primitives/WindowControls/WindowControls.vue_vue_type_script_setup_true_lang.js +23 -13
  485. package/dist/primitives/WindowControls/WindowControls.vue_vue_type_script_setup_true_lang.js.map +1 -1
  486. package/dist/styles/global.css +116 -17
  487. package/dist/styles/theme.contrast.test.ts +460 -0
  488. package/dist/styles/theme.css +239 -41
  489. package/dist/theme.js +171 -0
  490. package/dist/theme.js.map +1 -0
  491. package/package.json +14 -4
  492. package/dist/icons/BrandMark.d.ts +0 -18
  493. package/dist/icons/BrandMark.d.ts.map +0 -1
  494. package/dist/icons/BrandMark.js +0 -47
  495. package/dist/icons/BrandMark.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"SegmentedControl.js","names":[],"sources":["../../../src/primitives/SegmentedControl/SegmentedControl.vue"],"sourcesContent":["<script lang=\"ts\">\n/** One segment in a {@link SegmentedControl}. */\nexport interface SegmentedControlOption {\n /** Matched against `modelValue`. */\n value: string;\n /** Visible label, rendered inside the segment. */\n label: string;\n /** Disables this segment alone, leaving its neighbours pickable. */\n disabled?: boolean;\n /** Forwarded to the segment's DOM node — lets hosts keep stable test hooks. */\n testId?: string;\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { nextTick, onMounted, onUnmounted, reactive, ref, watch } from \"vue\";\nimport { RadioGroupRoot, RadioGroupItem } from \"reka-ui\";\nimport { cn } from \"../../lib/cn\";\nimport { optional } from \"../../lib/props\";\n\n/**\n * SegmentedControl — pick one of 2-5 mutually exclusive options, all visible\n * at once; one is always active. Built on Reka UI's RadioGroup (single\n * choice, roving tabindex — the group is one Tab stop, not N — with\n * arrow-key navigation). Styled with Loom tokens.\n */\nconst props = withDefaults(\n defineProps<{\n /** The selected option's `value`. */\n modelValue?: string;\n /** The segments to render, in order. */\n options: SegmentedControlOption[];\n /** Disables every segment at once, distinct from a single option's own `disabled`. */\n disabled?: boolean;\n /** `\"sm\"` is the compressed form for dense chrome — e.g. a status bar density level. */\n size?: \"default\" | \"sm\";\n }>(),\n { disabled: false, size: \"default\" },\n);\n\ndefineEmits<{ \"update:modelValue\": [value: string] }>();\n\n// Shared sliding indicator behind the checked segment. Measured off the live\n// DOM (offsetLeft/offsetWidth of the [data-state=checked] item), not derived\n// from index/width math, so \"sm\"/\"default\" sizing and variable-width labels\n// stay correct without per-size indicator code.\nconst indicatorEl = ref<HTMLElement | null>(null);\nconst indicatorStyle = reactive({ left: \"0px\", width: \"0px\", opacity: \"0\" });\n\nlet resizeObserver: ResizeObserver | undefined;\n\n// Re-targets onto the checked item itself (not the container) so a late\n// width settle on exactly that element — e.g. the `font-medium` weight swap\n// on data-[state=checked] reflowing after this function's own read — is\n// caught by the observer and re-measured, instead of going unnoticed because\n// the container's total box happened not to change.\nfunction updateIndicator() {\n const container = indicatorEl.value?.parentElement;\n const active = container?.querySelector<HTMLElement>('[role=\"radio\"][data-state=\"checked\"]');\n if (!active) {\n indicatorStyle.opacity = \"0\";\n resizeObserver?.disconnect();\n return;\n }\n indicatorStyle.left = `${active.offsetLeft}px`;\n indicatorStyle.width = `${active.offsetWidth}px`;\n indicatorStyle.opacity = \"1\";\n resizeObserver?.disconnect();\n resizeObserver?.observe(active);\n}\n\nonMounted(() => {\n resizeObserver = new ResizeObserver(updateIndicator);\n updateIndicator();\n});\nonUnmounted(() => resizeObserver?.disconnect());\n\nwatch(\n () => props.modelValue,\n () => nextTick(updateIndicator),\n);\nwatch(\n () => props.options,\n () => nextTick(updateIndicator),\n { deep: true },\n);\n</script>\n\n<template>\n <RadioGroupRoot\n v-bind=\"optional({ modelValue })\"\n :disabled=\"disabled\"\n orientation=\"horizontal\"\n class=\"relative inline-flex items-center gap-0.5 rounded-md border border-input bg-muted p-0.5\"\n @update:model-value=\"$emit('update:modelValue', String($event))\"\n >\n <span\n ref=\"indicatorEl\"\n aria-hidden=\"true\"\n class=\"pointer-events-none absolute inset-y-0.5 rounded-sm bg-card shadow-sm\"\n style=\"\n transition:\n left var(--duration-fast) var(--ease-spring),\n width var(--duration-fast) var(--ease-spring);\n \"\n :style=\"{\n left: indicatorStyle.left,\n width: indicatorStyle.width,\n opacity: indicatorStyle.opacity,\n }\"\n />\n <RadioGroupItem\n v-for=\"opt in options\"\n :key=\"opt.value\"\n :value=\"opt.value\"\n :disabled=\"opt.disabled ?? false\"\n v-bind=\"optional({ 'data-testid': opt.testId })\"\n style=\"\n transition:\n transform var(--duration-fast) var(--ease-spring),\n color var(--duration-fast) var(--ease-out);\n \"\n :class=\"\n cn(\n 'relative z-10 inline-flex items-center justify-center rounded-sm text-muted-foreground',\n size === 'sm' ? 'px-1.5 py-px text-[11px]' : 'px-3 py-1 text-sm',\n 'data-[state=checked]:font-medium data-[state=checked]:text-foreground',\n 'data-[state=unchecked]:hover:bg-subtle',\n 'active:scale-[0.97]',\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo',\n 'disabled:pointer-events-none disabled:opacity-50',\n )\n \"\n >\n {{ opt.label }}\n </RadioGroupItem>\n </RadioGroupRoot>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"SegmentedControl.js","names":[],"sources":["../../../src/primitives/SegmentedControl/SegmentedControl.vue"],"sourcesContent":["<script lang=\"ts\">\n/** One segment in a {@link SegmentedControl}. */\nexport interface SegmentedControlOption {\n /** Matched against `modelValue`. */\n value: string;\n /** Visible label, rendered inside the segment. */\n label: string;\n /** Disables this segment alone, leaving its neighbours pickable. */\n disabled?: boolean;\n /** Forwarded to the segment's DOM node — lets hosts keep stable test hooks. */\n testId?: string;\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { nextTick, onMounted, onUnmounted, reactive, ref, useTemplateRef, watch } from \"vue\";\nimport { RadioGroupRoot, RadioGroupItem } from \"reka-ui\";\nimport { cn } from \"../../lib/cn\";\nimport { optional } from \"../../lib/props\";\nimport { useSplitAttrs } from \"../../lib/attrs\";\nimport { useAncestorDisabled } from \"../../lib/ancestor-disabled\";\nimport { useFieldControl } from \"../../lib/field-context\";\n\n/**\n * SegmentedControl — pick one of 2-5 mutually exclusive options, all visible\n * at once; one is always active. Built on Reka UI's RadioGroup (single\n * choice, roving tabindex — the group is one Tab stop, not N — with\n * arrow-key navigation). Styled with Loom tokens.\n *\n * Inside a [Field](../Field/Field.vue) the row's description, `name`,\n * `required` and `invalid` reach the group through `useFieldControl()`.\n *\n * **A row's label does not name this group.** `<label for>` names a labelable\n * element and this renders a `div[role=\"radiogroup\"]`, so the row's label\n * resolves to the element and names nobody. Name it with a\n * [Fieldset](../Fieldset/Fieldset.vue)'s real `<legend>`, or with an\n * `aria-label`/`aria-labelledby` of its own — which is what every example\n * already does, because the control carries no label text.\n *\n * There is no `readonly`, and a row's is ignored rather than approximated: each\n * segment is a `<button role=\"radio\">` with no native read-only state to put it\n * in, and one segment is always active, so a read-only control here would be a\n * disabled one showing an answer.\n */\nconst props = withDefaults(\n defineProps<{\n /** The selected option's `value`. */\n modelValue?: string;\n /** The segments to render, in order. */\n options: SegmentedControlOption[];\n /** Disables every segment at once, distinct from a single option's own `disabled`. Unset defers to a wrapping Field. */\n disabled?: boolean | undefined;\n /** `\"sm\"` is the compressed form for dense chrome — e.g. a status bar density level. */\n size?: \"default\" | \"sm\";\n }>(),\n {\n // Not `false`: absent has to stay tellable from `false` for a Field above\n // to disable the control and for `:disabled=\"false\"` to overrule one that\n // does. Vue casts an absent Boolean prop with no declared default to\n // `false`, which would leave the context wired and inert.\n disabled: undefined,\n size: \"default\",\n },\n);\n\ndefineEmits<{ \"update:modelValue\": [value: string] }>();\n\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: groupAttrs } = useSplitAttrs();\n\n/**\n * The segments are real `<button>`s, so a `<fieldset disabled>` above this\n * control already makes each of them inert — but Reka's roving focus is what\n * decides where Tab lands, and it is driven by the group's own `disabled`,\n * which the fieldset never reaches. Measured on this branch: every segment went\n * `:disabled` while the `role=\"radiogroup\"` container kept `tabindex=\"0\"`, so\n * Tab still stopped on an unavailable control and left the reader nowhere. Its\n * own `disabled` prop sets that to `-1`.\n *\n * Reading the group state here rather than painting it with a CSS variant is\n * also what keeps the appearance honest, and this is the control where the\n * distinction bites: one option may carry `disabled` of its own, so \"a\n * `:disabled` button is inside this track\" and \"this track is unavailable\" are\n * different facts. Only the fieldset says the second.\n *\n * Read off the DOM rather than taken from the Field context, which publishes no\n * `disabled` on purpose — see `../../lib/ancestor-disabled.ts`.\n */\nconst root = useTemplateRef<{ $el?: Element }>(\"root\");\nconst groupDisabled = useAncestorDisabled(() => root.value?.$el);\n\n// One rendered node, so the split is only about `class` — a caller's class\n// needs a Tailwind-aware merge rather than Vue's concatenating fallthrough.\n//\n// `id` and `aria-describedby` arrive as fallthrough attrs rather than props, so\n// they are handed in as this caller's own values; `field.attrs` then spreads\n// **after** `groupAttrs`, and that position is the contract (see TextField.vue).\n//\n// `name`, `required` and `invalid` are omitted because this component has no\n// prop for any of them — the row's answer stands unopposed, and its `name`\n// reaches RadioGroupRoot's own prop, which mints the hidden input a `<form>`\n// submits. `readonly` is omitted for the reason the docblock gives.\n//\n// The resolved `required` then reaches the group through Reka's own prop rather\n// than the `aria-required` in `field.attrs`: RadioGroupRoot writes that\n// attribute itself, so leaving it to the bag is a race with a `false` — see\n// Checkbox.vue, where the merge order makes the same race a certainty.\nconst field = useFieldControl(() => ({\n id: attrs.id as string | undefined,\n describedBy: attrs[\"aria-describedby\"] as string | undefined,\n // The fieldset beats the prop in both directions, exactly as it does for the\n // segments themselves.\n disabled: groupDisabled.value ? true : props.disabled,\n}));\n\n// Shared sliding indicator behind the checked segment. Measured off the live\n// DOM (offsetLeft/offsetWidth of the [data-state=checked] item), not derived\n// from index/width math, so \"sm\"/\"default\" sizing and variable-width labels\n// stay correct without per-size indicator code.\nconst indicatorEl = ref<HTMLElement | null>(null);\nconst indicatorStyle = reactive({ left: \"0px\", width: \"0px\", opacity: \"0\" });\n\nlet resizeObserver: ResizeObserver | undefined;\n\n// Re-targets onto the checked item itself (not the container) so a late\n// width settle on exactly that element — e.g. the `font-medium` weight swap\n// on data-[state=checked] reflowing after this function's own read — is\n// caught by the observer and re-measured, instead of going unnoticed because\n// the container's total box happened not to change.\nfunction updateIndicator() {\n const container = indicatorEl.value?.parentElement;\n const active = container?.querySelector<HTMLElement>('[role=\"radio\"][data-state=\"checked\"]');\n if (!active) {\n indicatorStyle.opacity = \"0\";\n resizeObserver?.disconnect();\n return;\n }\n indicatorStyle.left = `${active.offsetLeft}px`;\n indicatorStyle.width = `${active.offsetWidth}px`;\n indicatorStyle.opacity = \"1\";\n resizeObserver?.disconnect();\n resizeObserver?.observe(active);\n}\n\nonMounted(() => {\n resizeObserver = new ResizeObserver(updateIndicator);\n updateIndicator();\n});\nonUnmounted(() => resizeObserver?.disconnect());\n\nwatch(\n () => props.modelValue,\n () => nextTick(updateIndicator),\n);\nwatch(\n () => props.options,\n () => nextTick(updateIndicator),\n { deep: true },\n);\n</script>\n\n<template>\n <RadioGroupRoot\n ref=\"root\"\n v-bind=\"{ ...optional({ modelValue }), ...groupAttrs, ...field.attrs }\"\n :disabled=\"field.disabled\"\n :required=\"field.required\"\n orientation=\"horizontal\"\n :class=\"\n cn(\n 'relative inline-flex items-center gap-0.5 rounded-md border border-input bg-muted p-0.5',\n // The one thing the *track* has left to say. Its fill is already\n // `bg-muted` — the well every other unavailable control drains to — so\n // the fill channel is spent before the state arrives, and the segments\n // inside carry the rest. The rim slackening from `input` to the lighter\n // `border` is what makes a wholly unavailable control tellable from an\n // available one at the group's own edge rather than only cell by cell.\n field.disabled && 'cursor-not-allowed border-border',\n attrs.class as string,\n )\n \"\n @update:model-value=\"$emit('update:modelValue', String($event))\"\n >\n <span\n ref=\"indicatorEl\"\n aria-hidden=\"true\"\n class=\"pointer-events-none absolute inset-y-0.5 rounded-sm bg-card shadow-sm\"\n style=\"\n transition:\n left var(--duration-fast) var(--ease-spring),\n width var(--duration-fast) var(--ease-spring);\n \"\n :style=\"{\n left: indicatorStyle.left,\n width: indicatorStyle.width,\n opacity: indicatorStyle.opacity,\n }\"\n />\n <RadioGroupItem\n v-for=\"opt in options\"\n :key=\"opt.value\"\n :value=\"opt.value\"\n :disabled=\"opt.disabled ?? false\"\n v-bind=\"optional({ 'data-testid': opt.testId })\"\n style=\"\n transition:\n transform var(--duration-fast) var(--ease-spring),\n color var(--duration-fast) var(--ease-out);\n \"\n :class=\"\n cn(\n // Named, not the bare `group`: a segmented control is dropped into\n // application chrome, and a bare `group-*` would also answer to any\n // ancestor a host happened to mark up as one.\n 'group/segment relative z-10 inline-flex items-center justify-center rounded-sm text-muted-foreground',\n size === 'sm' ? 'px-1.5 py-px text-[11px]' : 'px-3 py-1 text-sm',\n 'data-[state=checked]:font-medium data-[state=checked]:text-foreground',\n 'data-[state=unchecked]:hover:bg-subtle',\n 'active:scale-press',\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo',\n // No `opacity` here. A segment *is* its label — there is no glyph and\n // no fill of its own to dim — so `disabled:opacity-50` had nothing to\n // act on but the text, taking an unchecked segment to 1.96:1 and a\n // chosen one to 3.13:1 on its thumb.\n //\n // Unavailability is a fill instead, and it is the one step this\n // system already treats as meaningful: the cell drains up a rung of\n // the elevation rhythm, from the track's `bg-muted` to the page's own\n // `bg-background`, so it reads as a hole in the track rather than as\n // part of it. On a *chosen* segment that same fill covers the raised\n // white thumb, which is the whole signal — the value is still shown\n // and it is visibly no longer settable.\n 'disabled:pointer-events-none data-[disabled]:bg-background',\n )\n \"\n >\n <!-- The mute lives on this span rather than on the segment, and it has\n to. `data-[disabled]:` sorts *before* `data-[state=checked]:` in\n Tailwind's variant order, so a disabled segment that is also the\n chosen one would take `text-foreground` from the button — and a\n colour set on the button is only inherited here. Declared on the span\n it wins whatever the segment resolved to: 5.25:1 over the drained\n fill, against the 1.96:1 the dim used to leave. -->\n <span class=\"group-data-[disabled]/segment:text-muted-foreground\">{{ opt.label }}</span>\n </RadioGroupItem>\n </RadioGroupRoot>\n</template>\n"],"mappings":""}
@@ -16,8 +16,8 @@ declare const __VLS_export: import("vue").DefineComponent<{
16
16
  modelValue?: string;
17
17
  /** The segments to render, in order. */
18
18
  options: SegmentedControlOption[];
19
- /** Disables every segment at once, distinct from a single option's own `disabled`. */
20
- disabled?: boolean;
19
+ /** Disables every segment at once, distinct from a single option's own `disabled`. Unset defers to a wrapping Field. */
20
+ disabled?: boolean | undefined;
21
21
  /** `"sm"` is the compressed form for dense chrome — e.g. a status bar density level. */
22
22
  size?: "default" | "sm";
23
23
  }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
@@ -27,14 +27,14 @@ declare const __VLS_export: import("vue").DefineComponent<{
27
27
  modelValue?: string;
28
28
  /** The segments to render, in order. */
29
29
  options: SegmentedControlOption[];
30
- /** Disables every segment at once, distinct from a single option's own `disabled`. */
31
- disabled?: boolean;
30
+ /** Disables every segment at once, distinct from a single option's own `disabled`. Unset defers to a wrapping Field. */
31
+ disabled?: boolean | undefined;
32
32
  /** `"sm"` is the compressed form for dense chrome — e.g. a status bar density level. */
33
33
  size?: "default" | "sm";
34
34
  }> & Readonly<{
35
35
  "onUpdate:modelValue"?: (value: string) => any;
36
36
  }>, {
37
37
  size: "default" | "sm";
38
- disabled: boolean;
38
+ disabled: boolean | undefined;
39
39
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
40
40
  //# sourceMappingURL=SegmentedControl.vue.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SegmentedControl.vue.d.ts","sourceRoot":"","sources":["../../../src/primitives/SegmentedControl/SegmentedControl.vue"],"names":[],"mappings":"AAmJA,iDAAiD;AACjD,MAAM,WAAW,sBAAsB;IACrC,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;wBACoB,OAAO,YAAY;AAAxC,wBAAyC;AACzC,QAAA,MAAM,YAAY;IAQd,qCAAqC;iBACxB,MAAM;IACnB,wCAAwC;aAC/B,sBAAsB,EAAE;IACjC,sFAAsF;eAC3E,OAAO;IAClB,wFAAwF;WACjF,SAAS,GAAG,IAAI;;;;IAPvB,qCAAqC;iBACxB,MAAM;IACnB,wCAAwC;aAC/B,sBAAsB,EAAE;IACjC,sFAAsF;eAC3E,OAAO;IAClB,wFAAwF;WACjF,SAAS,GAAG,IAAI;;;;UAAhB,SAAS,GAAG,IAAI;cAFZ,OAAO;6EAwMlB,CAAC"}
1
+ {"version":3,"file":"SegmentedControl.vue.d.ts","sourceRoot":"","sources":["../../../src/primitives/SegmentedControl/SegmentedControl.vue"],"names":[],"mappings":"AAmQA,iDAAiD;AACjD,MAAM,WAAW,sBAAsB;IACrC,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;wBACoB,OAAO,YAAY;AAAxC,wBAAyC;AACzC,QAAA,MAAM,YAAY;IAuBd,qCAAqC;iBACxB,MAAM;IACnB,wCAAwC;aAC/B,sBAAsB,EAAE;IACjC,wHAAwH;eAC7G,OAAO,GAAG,SAAS;IAC9B,wFAAwF;WACjF,SAAS,GAAG,IAAI;;;;IAPvB,qCAAqC;iBACxB,MAAM;IACnB,wCAAwC;aAC/B,sBAAsB,EAAE;IACjC,wHAAwH;eAC7G,OAAO,GAAG,SAAS;IAC9B,wFAAwF;WACjF,SAAS,GAAG,IAAI;;;;UAAhB,SAAS,GAAG,IAAI;cAFZ,OAAO,GAAG,SAAS;6EAiU9B,CAAC"}
@@ -1,22 +1,53 @@
1
1
  import { cn } from "../../lib/cn.js";
2
2
  import { optional } from "../../lib/props.js";
3
- import { Fragment, createBlock, createElementBlock, createElementVNode, createTextVNode, defineComponent, mergeProps, nextTick, normalizeStyle, onMounted, onUnmounted, openBlock, reactive, ref, renderList, toDisplayString, unref, watch, withCtx } from "vue";
3
+ import { useSplitAttrs } from "../../lib/attrs.js";
4
+ import { useFieldControl } from "../../lib/field-context.js";
5
+ import { useAncestorDisabled } from "../../lib/ancestor-disabled.js";
6
+ import { Fragment, createBlock, createElementBlock, createElementVNode, defineComponent, mergeProps, nextTick, normalizeStyle, onMounted, onUnmounted, openBlock, reactive, ref, renderList, toDisplayString, unref, useTemplateRef, watch, withCtx } from "vue";
4
7
  import { RadioGroupItem, RadioGroupRoot } from "reka-ui";
5
8
  //#region src/primitives/SegmentedControl/SegmentedControl.vue?vue&type=script&setup=true&lang.ts
9
+ var _hoisted_1 = { class: "group-data-[disabled]/segment:text-muted-foreground" };
6
10
  var SegmentedControl_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
11
+ inheritAttrs: false,
7
12
  __name: "SegmentedControl",
8
13
  props: {
9
14
  modelValue: {},
10
15
  options: {},
11
16
  disabled: {
12
17
  type: Boolean,
13
- default: false
18
+ default: void 0
14
19
  },
15
20
  size: { default: "default" }
16
21
  },
17
22
  emits: ["update:modelValue"],
18
23
  setup(__props) {
19
24
  const props = __props;
25
+ const { attrs, rest: groupAttrs } = useSplitAttrs();
26
+ /**
27
+ * The segments are real `<button>`s, so a `<fieldset disabled>` above this
28
+ * control already makes each of them inert — but Reka's roving focus is what
29
+ * decides where Tab lands, and it is driven by the group's own `disabled`,
30
+ * which the fieldset never reaches. Measured on this branch: every segment went
31
+ * `:disabled` while the `role="radiogroup"` container kept `tabindex="0"`, so
32
+ * Tab still stopped on an unavailable control and left the reader nowhere. Its
33
+ * own `disabled` prop sets that to `-1`.
34
+ *
35
+ * Reading the group state here rather than painting it with a CSS variant is
36
+ * also what keeps the appearance honest, and this is the control where the
37
+ * distinction bites: one option may carry `disabled` of its own, so "a
38
+ * `:disabled` button is inside this track" and "this track is unavailable" are
39
+ * different facts. Only the fieldset says the second.
40
+ *
41
+ * Read off the DOM rather than taken from the Field context, which publishes no
42
+ * `disabled` on purpose — see `../../lib/ancestor-disabled.ts`.
43
+ */
44
+ const root = useTemplateRef("root");
45
+ const groupDisabled = useAncestorDisabled(() => root.value?.$el);
46
+ const field = useFieldControl(() => ({
47
+ id: attrs.id,
48
+ describedBy: attrs["aria-describedby"],
49
+ disabled: groupDisabled.value ? true : props.disabled
50
+ }));
20
51
  const indicatorEl = ref(null);
21
52
  const indicatorStyle = reactive({
22
53
  left: "0px",
@@ -45,10 +76,18 @@ var SegmentedControl_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
45
76
  watch(() => props.modelValue, () => nextTick(updateIndicator));
46
77
  watch(() => props.options, () => nextTick(updateIndicator), { deep: true });
47
78
  return (_ctx, _cache) => {
48
- return openBlock(), createBlock(unref(RadioGroupRoot), mergeProps(unref(optional)({ modelValue: __props.modelValue }), {
49
- disabled: __props.disabled,
79
+ return openBlock(), createBlock(unref(RadioGroupRoot), mergeProps({
80
+ ref_key: "root",
81
+ ref: root
82
+ }, {
83
+ ...unref(optional)({ modelValue: __props.modelValue }),
84
+ ...unref(groupAttrs),
85
+ ...unref(field).attrs
86
+ }, {
87
+ disabled: unref(field).disabled,
88
+ required: unref(field).required,
50
89
  orientation: "horizontal",
51
- class: "relative inline-flex items-center gap-0.5 rounded-md border border-input bg-muted p-0.5",
90
+ class: unref(cn)("relative inline-flex items-center gap-0.5 rounded-md border border-input bg-muted p-0.5", unref(field).disabled && "cursor-not-allowed border-border", unref(attrs).class),
52
91
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => _ctx.$emit("update:modelValue", String($event)))
53
92
  }), {
54
93
  default: withCtx(() => [createElementVNode("span", {
@@ -68,9 +107,9 @@ var SegmentedControl_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
68
107
  disabled: opt.disabled ?? false
69
108
  }, { ref_for: true }, unref(optional)({ "data-testid": opt.testId }), {
70
109
  style: { "transition": "transform var(--duration-fast) var(--ease-spring),\n color var(--duration-fast) var(--ease-out)" },
71
- class: unref(cn)("relative z-10 inline-flex items-center justify-center rounded-sm text-muted-foreground", __props.size === "sm" ? "px-1.5 py-px text-[11px]" : "px-3 py-1 text-sm", "data-[state=checked]:font-medium data-[state=checked]:text-foreground", "data-[state=unchecked]:hover:bg-subtle", "active:scale-[0.97]", "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo", "disabled:pointer-events-none disabled:opacity-50")
110
+ class: unref(cn)("group/segment relative z-10 inline-flex items-center justify-center rounded-sm text-muted-foreground", __props.size === "sm" ? "px-1.5 py-px text-[11px]" : "px-3 py-1 text-sm", "data-[state=checked]:font-medium data-[state=checked]:text-foreground", "data-[state=unchecked]:hover:bg-subtle", "active:scale-press", "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo", "disabled:pointer-events-none data-[disabled]:bg-background")
72
111
  }), {
73
- default: withCtx(() => [createTextVNode(toDisplayString(opt.label), 1)]),
112
+ default: withCtx(() => [createElementVNode("span", _hoisted_1, toDisplayString(opt.label), 1)]),
74
113
  _: 2
75
114
  }, 1040, [
76
115
  "value",
@@ -79,7 +118,11 @@ var SegmentedControl_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
79
118
  ]);
80
119
  }), 128))]),
81
120
  _: 1
82
- }, 16, ["disabled"]);
121
+ }, 16, [
122
+ "disabled",
123
+ "required",
124
+ "class"
125
+ ]);
83
126
  };
84
127
  }
85
128
  });
@@ -1 +1 @@
1
- {"version":3,"file":"SegmentedControl.vue_vue_type_script_setup_true_lang.js","names":["$emit"],"sources":["../../../src/primitives/SegmentedControl/SegmentedControl.vue"],"sourcesContent":["<script lang=\"ts\">\n/** One segment in a {@link SegmentedControl}. */\nexport interface SegmentedControlOption {\n /** Matched against `modelValue`. */\n value: string;\n /** Visible label, rendered inside the segment. */\n label: string;\n /** Disables this segment alone, leaving its neighbours pickable. */\n disabled?: boolean;\n /** Forwarded to the segment's DOM node — lets hosts keep stable test hooks. */\n testId?: string;\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { nextTick, onMounted, onUnmounted, reactive, ref, watch } from \"vue\";\nimport { RadioGroupRoot, RadioGroupItem } from \"reka-ui\";\nimport { cn } from \"../../lib/cn\";\nimport { optional } from \"../../lib/props\";\n\n/**\n * SegmentedControl — pick one of 2-5 mutually exclusive options, all visible\n * at once; one is always active. Built on Reka UI's RadioGroup (single\n * choice, roving tabindex — the group is one Tab stop, not N — with\n * arrow-key navigation). Styled with Loom tokens.\n */\nconst props = withDefaults(\n defineProps<{\n /** The selected option's `value`. */\n modelValue?: string;\n /** The segments to render, in order. */\n options: SegmentedControlOption[];\n /** Disables every segment at once, distinct from a single option's own `disabled`. */\n disabled?: boolean;\n /** `\"sm\"` is the compressed form for dense chrome — e.g. a status bar density level. */\n size?: \"default\" | \"sm\";\n }>(),\n { disabled: false, size: \"default\" },\n);\n\ndefineEmits<{ \"update:modelValue\": [value: string] }>();\n\n// Shared sliding indicator behind the checked segment. Measured off the live\n// DOM (offsetLeft/offsetWidth of the [data-state=checked] item), not derived\n// from index/width math, so \"sm\"/\"default\" sizing and variable-width labels\n// stay correct without per-size indicator code.\nconst indicatorEl = ref<HTMLElement | null>(null);\nconst indicatorStyle = reactive({ left: \"0px\", width: \"0px\", opacity: \"0\" });\n\nlet resizeObserver: ResizeObserver | undefined;\n\n// Re-targets onto the checked item itself (not the container) so a late\n// width settle on exactly that element — e.g. the `font-medium` weight swap\n// on data-[state=checked] reflowing after this function's own read — is\n// caught by the observer and re-measured, instead of going unnoticed because\n// the container's total box happened not to change.\nfunction updateIndicator() {\n const container = indicatorEl.value?.parentElement;\n const active = container?.querySelector<HTMLElement>('[role=\"radio\"][data-state=\"checked\"]');\n if (!active) {\n indicatorStyle.opacity = \"0\";\n resizeObserver?.disconnect();\n return;\n }\n indicatorStyle.left = `${active.offsetLeft}px`;\n indicatorStyle.width = `${active.offsetWidth}px`;\n indicatorStyle.opacity = \"1\";\n resizeObserver?.disconnect();\n resizeObserver?.observe(active);\n}\n\nonMounted(() => {\n resizeObserver = new ResizeObserver(updateIndicator);\n updateIndicator();\n});\nonUnmounted(() => resizeObserver?.disconnect());\n\nwatch(\n () => props.modelValue,\n () => nextTick(updateIndicator),\n);\nwatch(\n () => props.options,\n () => nextTick(updateIndicator),\n { deep: true },\n);\n</script>\n\n<template>\n <RadioGroupRoot\n v-bind=\"optional({ modelValue })\"\n :disabled=\"disabled\"\n orientation=\"horizontal\"\n class=\"relative inline-flex items-center gap-0.5 rounded-md border border-input bg-muted p-0.5\"\n @update:model-value=\"$emit('update:modelValue', String($event))\"\n >\n <span\n ref=\"indicatorEl\"\n aria-hidden=\"true\"\n class=\"pointer-events-none absolute inset-y-0.5 rounded-sm bg-card shadow-sm\"\n style=\"\n transition:\n left var(--duration-fast) var(--ease-spring),\n width var(--duration-fast) var(--ease-spring);\n \"\n :style=\"{\n left: indicatorStyle.left,\n width: indicatorStyle.width,\n opacity: indicatorStyle.opacity,\n }\"\n />\n <RadioGroupItem\n v-for=\"opt in options\"\n :key=\"opt.value\"\n :value=\"opt.value\"\n :disabled=\"opt.disabled ?? false\"\n v-bind=\"optional({ 'data-testid': opt.testId })\"\n style=\"\n transition:\n transform var(--duration-fast) var(--ease-spring),\n color var(--duration-fast) var(--ease-out);\n \"\n :class=\"\n cn(\n 'relative z-10 inline-flex items-center justify-center rounded-sm text-muted-foreground',\n size === 'sm' ? 'px-1.5 py-px text-[11px]' : 'px-3 py-1 text-sm',\n 'data-[state=checked]:font-medium data-[state=checked]:text-foreground',\n 'data-[state=unchecked]:hover:bg-subtle',\n 'active:scale-[0.97]',\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo',\n 'disabled:pointer-events-none disabled:opacity-50',\n )\n \"\n >\n {{ opt.label }}\n </RadioGroupItem>\n </RadioGroupRoot>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;EA0BA,MAAM,QAAQ;EAoBd,MAAM,cAAc,IAAwB,IAAI;EAChD,MAAM,iBAAiB,SAAS;GAAE,MAAM;GAAO,OAAO;GAAO,SAAS;EAAI,CAAC;EAE3E,IAAI;EAOJ,SAAS,kBAAkB;GAEzB,MAAM,UADY,YAAY,OAAO,cAAA,EACX,cAA2B,0CAAsC;GAC3F,IAAI,CAAC,QAAQ;IACX,eAAe,UAAU;IACzB,gBAAgB,WAAW;IAC3B;GACF;GACA,eAAe,OAAO,GAAG,OAAO,WAAW;GAC3C,eAAe,QAAQ,GAAG,OAAO,YAAY;GAC7C,eAAe,UAAU;GACzB,gBAAgB,WAAW;GAC3B,gBAAgB,QAAQ,MAAM;EAChC;EAEA,gBAAgB;GACd,iBAAiB,IAAI,eAAe,eAAe;GACnD,gBAAgB;EAClB,CAAC;EACD,kBAAkB,gBAAgB,WAAW,CAAC;EAE9C,YACQ,MAAM,kBACN,SAAS,eAAe,CAChC;EACA,YACQ,MAAM,eACN,SAAS,eAAe,GAC9B,EAAE,MAAM,KAAK,CACf;;GAIE,OAAA,UAAA,GAAA,YA+CiB,MAAA,cAAA,GA/CjB,WACU,MA8CO,QAAA,CA9CC,CAAA,EAAA,YAAG,QAAA,WAAU,CAAA,GAAA;IAC5B,UAAU,QAAA;IACX,aAAY;IACZ,OAAM;IACL,uBAAkB,OAAA,OAAA,OAAA,MAAA,WAAEA,KAAAA,MAAK,qBAAsB,OAAO,MAAM,CAAA;;IAE7D,SAAA,cAcE,CAdF,mBAcE,QAAA;KAbI,SAAA;KAAJ,KAAI;KACJ,eAAY;KACZ,OAAM;KACN,OAIC,eAAA,CAJD,EAAA,cAAA,yGAAA,GAIC;MACuB,MAAA,eAAe;MAAqB,OAAA,eAAe;MAAwB,SAAA,eAAe;;IAMpH,GAAA,MAAA,CAAA,IAAA,UAAA,IAAA,GAAA,mBAwBiB,UAAA,MAAA,WAvBD,QAAA,UAAP,QAAG;KADZ,OAAA,UAAA,GAAA,YAwBiB,MAAA,cAAA,GAxBjB,WAwBiB;MAtBd,KAAK,IAAI;MACT,OAAO,IAAI;MACX,UAAU,IAAI,YAAQ;KACf,GAAA,EAAA,SAAA,KAAA,GAAA,MAAA,QAAA,CAAQ,CAAA,EAAA,eAAkB,IAAI,OAAM,CAAA,GAAA;MAC5C,OAAA,EAAA,cAAA,2GAAA;MAKC,OAAgB,MAAA,EAAA,CAAE,CAAA,0FAAgH,QAAA,SAAI,OAAA,6BAAA,qBAAA,yEAAA,0CAAA,uBAAA,+GAAA,kDAAA;;MAYvI,SAAA,cAAe,CAAZ,gBAAA,gBAAA,IAAI,KAAK,GAAA,CAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"SegmentedControl.vue_vue_type_script_setup_true_lang.js","names":["$emit"],"sources":["../../../src/primitives/SegmentedControl/SegmentedControl.vue"],"sourcesContent":["<script lang=\"ts\">\n/** One segment in a {@link SegmentedControl}. */\nexport interface SegmentedControlOption {\n /** Matched against `modelValue`. */\n value: string;\n /** Visible label, rendered inside the segment. */\n label: string;\n /** Disables this segment alone, leaving its neighbours pickable. */\n disabled?: boolean;\n /** Forwarded to the segment's DOM node — lets hosts keep stable test hooks. */\n testId?: string;\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { nextTick, onMounted, onUnmounted, reactive, ref, useTemplateRef, watch } from \"vue\";\nimport { RadioGroupRoot, RadioGroupItem } from \"reka-ui\";\nimport { cn } from \"../../lib/cn\";\nimport { optional } from \"../../lib/props\";\nimport { useSplitAttrs } from \"../../lib/attrs\";\nimport { useAncestorDisabled } from \"../../lib/ancestor-disabled\";\nimport { useFieldControl } from \"../../lib/field-context\";\n\n/**\n * SegmentedControl — pick one of 2-5 mutually exclusive options, all visible\n * at once; one is always active. Built on Reka UI's RadioGroup (single\n * choice, roving tabindex — the group is one Tab stop, not N — with\n * arrow-key navigation). Styled with Loom tokens.\n *\n * Inside a [Field](../Field/Field.vue) the row's description, `name`,\n * `required` and `invalid` reach the group through `useFieldControl()`.\n *\n * **A row's label does not name this group.** `<label for>` names a labelable\n * element and this renders a `div[role=\"radiogroup\"]`, so the row's label\n * resolves to the element and names nobody. Name it with a\n * [Fieldset](../Fieldset/Fieldset.vue)'s real `<legend>`, or with an\n * `aria-label`/`aria-labelledby` of its own — which is what every example\n * already does, because the control carries no label text.\n *\n * There is no `readonly`, and a row's is ignored rather than approximated: each\n * segment is a `<button role=\"radio\">` with no native read-only state to put it\n * in, and one segment is always active, so a read-only control here would be a\n * disabled one showing an answer.\n */\nconst props = withDefaults(\n defineProps<{\n /** The selected option's `value`. */\n modelValue?: string;\n /** The segments to render, in order. */\n options: SegmentedControlOption[];\n /** Disables every segment at once, distinct from a single option's own `disabled`. Unset defers to a wrapping Field. */\n disabled?: boolean | undefined;\n /** `\"sm\"` is the compressed form for dense chrome — e.g. a status bar density level. */\n size?: \"default\" | \"sm\";\n }>(),\n {\n // Not `false`: absent has to stay tellable from `false` for a Field above\n // to disable the control and for `:disabled=\"false\"` to overrule one that\n // does. Vue casts an absent Boolean prop with no declared default to\n // `false`, which would leave the context wired and inert.\n disabled: undefined,\n size: \"default\",\n },\n);\n\ndefineEmits<{ \"update:modelValue\": [value: string] }>();\n\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: groupAttrs } = useSplitAttrs();\n\n/**\n * The segments are real `<button>`s, so a `<fieldset disabled>` above this\n * control already makes each of them inert — but Reka's roving focus is what\n * decides where Tab lands, and it is driven by the group's own `disabled`,\n * which the fieldset never reaches. Measured on this branch: every segment went\n * `:disabled` while the `role=\"radiogroup\"` container kept `tabindex=\"0\"`, so\n * Tab still stopped on an unavailable control and left the reader nowhere. Its\n * own `disabled` prop sets that to `-1`.\n *\n * Reading the group state here rather than painting it with a CSS variant is\n * also what keeps the appearance honest, and this is the control where the\n * distinction bites: one option may carry `disabled` of its own, so \"a\n * `:disabled` button is inside this track\" and \"this track is unavailable\" are\n * different facts. Only the fieldset says the second.\n *\n * Read off the DOM rather than taken from the Field context, which publishes no\n * `disabled` on purpose — see `../../lib/ancestor-disabled.ts`.\n */\nconst root = useTemplateRef<{ $el?: Element }>(\"root\");\nconst groupDisabled = useAncestorDisabled(() => root.value?.$el);\n\n// One rendered node, so the split is only about `class` — a caller's class\n// needs a Tailwind-aware merge rather than Vue's concatenating fallthrough.\n//\n// `id` and `aria-describedby` arrive as fallthrough attrs rather than props, so\n// they are handed in as this caller's own values; `field.attrs` then spreads\n// **after** `groupAttrs`, and that position is the contract (see TextField.vue).\n//\n// `name`, `required` and `invalid` are omitted because this component has no\n// prop for any of them — the row's answer stands unopposed, and its `name`\n// reaches RadioGroupRoot's own prop, which mints the hidden input a `<form>`\n// submits. `readonly` is omitted for the reason the docblock gives.\n//\n// The resolved `required` then reaches the group through Reka's own prop rather\n// than the `aria-required` in `field.attrs`: RadioGroupRoot writes that\n// attribute itself, so leaving it to the bag is a race with a `false` — see\n// Checkbox.vue, where the merge order makes the same race a certainty.\nconst field = useFieldControl(() => ({\n id: attrs.id as string | undefined,\n describedBy: attrs[\"aria-describedby\"] as string | undefined,\n // The fieldset beats the prop in both directions, exactly as it does for the\n // segments themselves.\n disabled: groupDisabled.value ? true : props.disabled,\n}));\n\n// Shared sliding indicator behind the checked segment. Measured off the live\n// DOM (offsetLeft/offsetWidth of the [data-state=checked] item), not derived\n// from index/width math, so \"sm\"/\"default\" sizing and variable-width labels\n// stay correct without per-size indicator code.\nconst indicatorEl = ref<HTMLElement | null>(null);\nconst indicatorStyle = reactive({ left: \"0px\", width: \"0px\", opacity: \"0\" });\n\nlet resizeObserver: ResizeObserver | undefined;\n\n// Re-targets onto the checked item itself (not the container) so a late\n// width settle on exactly that element — e.g. the `font-medium` weight swap\n// on data-[state=checked] reflowing after this function's own read — is\n// caught by the observer and re-measured, instead of going unnoticed because\n// the container's total box happened not to change.\nfunction updateIndicator() {\n const container = indicatorEl.value?.parentElement;\n const active = container?.querySelector<HTMLElement>('[role=\"radio\"][data-state=\"checked\"]');\n if (!active) {\n indicatorStyle.opacity = \"0\";\n resizeObserver?.disconnect();\n return;\n }\n indicatorStyle.left = `${active.offsetLeft}px`;\n indicatorStyle.width = `${active.offsetWidth}px`;\n indicatorStyle.opacity = \"1\";\n resizeObserver?.disconnect();\n resizeObserver?.observe(active);\n}\n\nonMounted(() => {\n resizeObserver = new ResizeObserver(updateIndicator);\n updateIndicator();\n});\nonUnmounted(() => resizeObserver?.disconnect());\n\nwatch(\n () => props.modelValue,\n () => nextTick(updateIndicator),\n);\nwatch(\n () => props.options,\n () => nextTick(updateIndicator),\n { deep: true },\n);\n</script>\n\n<template>\n <RadioGroupRoot\n ref=\"root\"\n v-bind=\"{ ...optional({ modelValue }), ...groupAttrs, ...field.attrs }\"\n :disabled=\"field.disabled\"\n :required=\"field.required\"\n orientation=\"horizontal\"\n :class=\"\n cn(\n 'relative inline-flex items-center gap-0.5 rounded-md border border-input bg-muted p-0.5',\n // The one thing the *track* has left to say. Its fill is already\n // `bg-muted` — the well every other unavailable control drains to — so\n // the fill channel is spent before the state arrives, and the segments\n // inside carry the rest. The rim slackening from `input` to the lighter\n // `border` is what makes a wholly unavailable control tellable from an\n // available one at the group's own edge rather than only cell by cell.\n field.disabled && 'cursor-not-allowed border-border',\n attrs.class as string,\n )\n \"\n @update:model-value=\"$emit('update:modelValue', String($event))\"\n >\n <span\n ref=\"indicatorEl\"\n aria-hidden=\"true\"\n class=\"pointer-events-none absolute inset-y-0.5 rounded-sm bg-card shadow-sm\"\n style=\"\n transition:\n left var(--duration-fast) var(--ease-spring),\n width var(--duration-fast) var(--ease-spring);\n \"\n :style=\"{\n left: indicatorStyle.left,\n width: indicatorStyle.width,\n opacity: indicatorStyle.opacity,\n }\"\n />\n <RadioGroupItem\n v-for=\"opt in options\"\n :key=\"opt.value\"\n :value=\"opt.value\"\n :disabled=\"opt.disabled ?? false\"\n v-bind=\"optional({ 'data-testid': opt.testId })\"\n style=\"\n transition:\n transform var(--duration-fast) var(--ease-spring),\n color var(--duration-fast) var(--ease-out);\n \"\n :class=\"\n cn(\n // Named, not the bare `group`: a segmented control is dropped into\n // application chrome, and a bare `group-*` would also answer to any\n // ancestor a host happened to mark up as one.\n 'group/segment relative z-10 inline-flex items-center justify-center rounded-sm text-muted-foreground',\n size === 'sm' ? 'px-1.5 py-px text-[11px]' : 'px-3 py-1 text-sm',\n 'data-[state=checked]:font-medium data-[state=checked]:text-foreground',\n 'data-[state=unchecked]:hover:bg-subtle',\n 'active:scale-press',\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:shadow-halo',\n // No `opacity` here. A segment *is* its label — there is no glyph and\n // no fill of its own to dim — so `disabled:opacity-50` had nothing to\n // act on but the text, taking an unchecked segment to 1.96:1 and a\n // chosen one to 3.13:1 on its thumb.\n //\n // Unavailability is a fill instead, and it is the one step this\n // system already treats as meaningful: the cell drains up a rung of\n // the elevation rhythm, from the track's `bg-muted` to the page's own\n // `bg-background`, so it reads as a hole in the track rather than as\n // part of it. On a *chosen* segment that same fill covers the raised\n // white thumb, which is the whole signal — the value is still shown\n // and it is visibly no longer settable.\n 'disabled:pointer-events-none data-[disabled]:bg-background',\n )\n \"\n >\n <!-- The mute lives on this span rather than on the segment, and it has\n to. `data-[disabled]:` sorts *before* `data-[state=checked]:` in\n Tailwind's variant order, so a disabled segment that is also the\n chosen one would take `text-foreground` from the button — and a\n colour set on the button is only inherited here. Declared on the span\n it wins whatever the segment resolved to: 5.25:1 over the drained\n fill, against the 1.96:1 the dim used to leave. -->\n <span class=\"group-data-[disabled]/segment:text-muted-foreground\">{{ opt.label }}</span>\n </RadioGroupItem>\n </RadioGroupRoot>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;EA4CA,MAAM,QAAQ;EAwBd,MAAM,EAAE,OAAO,MAAM,eAAe,cAAc;;;;;;;;;;;;;;;;;;;EAoBlD,MAAM,OAAO,eAAkC,MAAM;EACrD,MAAM,gBAAgB,0BAA0B,KAAK,OAAO,GAAG;EAkB/D,MAAM,QAAQ,uBAAuB;GACnC,IAAI,MAAM;GACV,aAAa,MAAM;GAGnB,UAAU,cAAc,QAAQ,OAAO,MAAM;EAC/C,EAAE;EAMF,MAAM,cAAc,IAAwB,IAAI;EAChD,MAAM,iBAAiB,SAAS;GAAE,MAAM;GAAO,OAAO;GAAO,SAAS;EAAI,CAAC;EAE3E,IAAI;EAOJ,SAAS,kBAAkB;GAEzB,MAAM,UADY,YAAY,OAAO,cAAA,EACX,cAA2B,0CAAsC;GAC3F,IAAI,CAAC,QAAQ;IACX,eAAe,UAAU;IACzB,gBAAgB,WAAW;IAC3B;GACF;GACA,eAAe,OAAO,GAAG,OAAO,WAAW;GAC3C,eAAe,QAAQ,GAAG,OAAO,YAAY;GAC7C,eAAe,UAAU;GACzB,gBAAgB,WAAW;GAC3B,gBAAgB,QAAQ,MAAM;EAChC;EAEA,gBAAgB;GACd,iBAAiB,IAAI,eAAe,eAAe;GACnD,gBAAgB;EAClB,CAAC;EACD,kBAAkB,gBAAgB,WAAW,CAAC;EAE9C,YACQ,MAAM,kBACN,SAAS,eAAe,CAChC;EACA,YACQ,MAAM,eACN,SAAS,eAAe,GAC9B,EAAE,MAAM,KAAK,CACf;;GAIE,OAAA,UAAA,GAAA,YAmFiB,MAAA,cAAA,GAnFjB,WAmFiB;IAlFX,SAAA;IAAJ,KAAI;GACS,GAAA;IAAA,GAAA,MAAA,QAAA,CAAQ,CAAA,EAAA,YAAG,QAAA,WAAU,CAAA;IAAA,GAAQ,MAAA,UAAA;IAAU,GAAK,MAAA,KAAA,CAAK,CAAC;GAAK,GAAA;IACnE,UAAU,MAAA,KAAA,CAAK,CAAC;IAChB,UAAU,MAAA,KAAA,CAAK,CAAC;IACjB,aAAY;IACX,OAAc,MAAA,EAAA,CAAE,CAAA,2FAAwkB,MAAA,KAAA,CAAK,CAAC,YAAQ,oCAAgD,MAAA,KAAA,CAAK,CAAC,KAAA;IAa5pB,uBAAkB,OAAA,OAAA,OAAA,MAAA,WAAEA,KAAAA,MAAK,qBAAsB,OAAO,MAAM,CAAA;;IAE7D,SAAA,cAcE,CAdF,mBAcE,QAAA;KAbI,SAAA;KAAJ,KAAI;KACJ,eAAY;KACZ,OAAM;KACN,OAIC,eAAA,CAJD,EAAA,cAAA,yGAAA,GAIC;MACuB,MAAA,eAAe;MAAqB,OAAA,eAAe;MAAwB,SAAA,eAAe;;IAMpH,GAAA,MAAA,CAAA,IAAA,UAAA,IAAA,GAAA,mBA8CiB,UAAA,MAAA,WA7CD,QAAA,UAAP,QAAG;KADZ,OAAA,UAAA,GAAA,YA8CiB,MAAA,cAAA,GA9CjB,WA8CiB;MA5Cd,KAAK,IAAI;MACT,OAAO,IAAI;MACX,UAAU,IAAI,YAAQ;KACf,GAAA,EAAA,SAAA,KAAA,GAAA,MAAA,QAAA,CAAQ,CAAA,EAAA,eAAkB,IAAI,OAAM,CAAA,GAAA;MAC5C,OAAA,EAAA,cAAA,2GAAA;MAKC,OAAgB,MAAA,EAAA,CAAE,CAAA,wGAAoV,QAAA,SAAI,OAAA,6BAAA,qBAAA,yEAAA,0CAAA,sBAAA,+GAAA,4DAAA;;MAkC3W,SAAA,cAAwF,CAAxF,mBAAwF,QAAxF,YAAwF,gBAAnB,IAAI,KAAK,GAAA,CAAA,CAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"Select.js","names":[],"sources":["../../../src/primitives/Select/Select.vue"],"sourcesContent":["<script lang=\"ts\">\nimport { cva } from \"class-variance-authority\";\n\n/** One row of the list. `value` is what the model carries; `label` is what a reader sees. */\nexport interface SelectOption {\n /** The value bound to `v-model` when this row is chosen. Unique within the list. */\n value: string;\n /** The text shown on the row, and on the trigger once it is chosen. */\n label: string;\n /** Present but unchoosable — visible, skipped by the keyboard, unclickable. */\n disabled?: boolean;\n}\n\n/**\n * The trigger's height scale. It matches the text input scale exactly, so a\n * form row mixing a Select beside a text field never comes out uneven — which\n * is why reaching past `size` for an `h-*` class is always the wrong fix.\n */\nexport type SelectSize = \"sm\" | \"md\" | \"lg\";\n\nexport const selectVariants = cva(\n [\n \"group inline-flex w-full items-center justify-between gap-2 rounded-md border border-input bg-background text-foreground\",\n \"transition-[color,background-color,box-shadow] duration-fast ease-out hover:bg-subtle\",\n // Rim-lit at rest; the ring blooms on focus.\n \"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\",\n \"disabled:cursor-not-allowed disabled:opacity-50 data-[placeholder]:text-muted-foreground\",\n ],\n {\n // `satisfies` keeps the two halves honest: the union above is the name a\n // consumer imports and the documentation prints, the map below is the\n // classes. Adding a member to one and not the other stops compiling.\n variants: {\n size: {\n sm: \"h-8 px-2.5 text-xs\",\n md: \"h-9 px-3 text-sm\",\n lg: \"h-11 px-4 text-base\",\n } satisfies Record<SelectSize, string>,\n },\n defaultVariants: { size: \"md\" },\n },\n);\n</script>\n\n<script setup lang=\"ts\">\nimport {\n SelectRoot,\n SelectTrigger,\n SelectValue,\n SelectIcon,\n SelectPortal,\n SelectContent,\n SelectViewport,\n SelectItem,\n SelectItemText,\n SelectItemIndicator,\n} from \"reka-ui\";\nimport { Check, ChevronDown } from \"@lucide/vue\";\nimport { cn } from \"../../lib/cn\";\nimport { listStaggerDelay } from \"../../lib/motion\";\nimport { useSplitAttrs } from \"../../lib/attrs\";\n\n/**\n * Select — pick one value out of a closed list, through a compact trigger and\n * a popover listbox. It suits roughly three to fifteen rows where one value is\n * always chosen: a language, a resolution, a quality preset.\n *\n * Below that, two to five options a reader should see all of at once are\n * better shown than hidden. Above it, a list long enough to need searching\n * wants a combobox, which is a different control rather than a longer version\n * of this one.\n *\n * Built on Reka UI's Select, which supplies the listbox semantics: arrow-key\n * navigation, first-character typeahead, Escape and outside-click to close, and\n * the `role=\"combobox\"` trigger wired to the listbox by `aria-expanded` and\n * `aria-controls`. The active row is tracked by moving real focus onto it, not\n * by `aria-activedescendant`.\n */\nwithDefaults(\n defineProps<{\n /** The chosen option's `value`. Leave it unset to show the placeholder. */\n modelValue?: string;\n /** The rows, in the order they are shown. */\n options: SelectOption[];\n /** Shown on the trigger while nothing is chosen. It is not an option. */\n placeholder?: string;\n /** Unavailable: dims the trigger and refuses to open. */\n disabled?: boolean;\n /** Error state: paints the destructive border and ring, and sets `aria-invalid`. */\n invalid?: boolean;\n /** Trigger height. It shares the text input scale so mixed form rows stay aligned. */\n size?: SelectSize;\n }>(),\n { disabled: false, invalid: false, size: \"md\" },\n);\n\ndefineEmits<{\n /** The chosen option's `value`. Fires once per choice; the list closes with it. */\n \"update:modelValue\": [value: string];\n}>();\n\n// The root renders no DOM node at all, so fallthrough attributes would be\n// dropped on the floor rather than landing anywhere. They go to the trigger,\n// which is the interactive element they describe.\n//\n// `class` is pulled out of that spread and merged through `cn()` instead.\n// Spreading it alongside the trigger's own `:class` only concatenates the two\n// lists — Vue's merge is generic, not Tailwind-aware — so a caller's `w-28`\n// silently loses to the trigger's own `w-full` depending on which utility\n// Tailwind happened to emit last.\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: triggerAttrs } = useSplitAttrs();\n</script>\n\n<template>\n <SelectRoot\n :model-value=\"modelValue ?? ''\"\n :disabled=\"disabled\"\n @update:model-value=\"$emit('update:modelValue', String($event))\"\n >\n <SelectTrigger\n v-bind=\"triggerAttrs\"\n :aria-invalid=\"invalid || undefined\"\n :data-invalid=\"invalid || undefined\"\n :class=\"\n cn(\n selectVariants({ size }),\n !invalid && 'focus-visible:shadow-halo',\n invalid && 'border-destructive focus-visible:outline-destructive',\n attrs.class as string,\n )\n \"\n >\n <SelectValue :placeholder=\"placeholder ?? ''\" />\n <SelectIcon class=\"shrink-0 text-muted-foreground\">\n <ChevronDown\n class=\"h-4 w-4 transition-transform duration-fast ease-out group-data-[state=open]:rotate-180\"\n />\n </SelectIcon>\n </SelectTrigger>\n\n <SelectPortal>\n <SelectContent\n position=\"popper\"\n :side-offset=\"6\"\n :class=\"\n cn(\n 'z-50 min-w-[var(--reka-select-trigger-width)] overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md',\n // Scoped to the open state, never unconditional. Reka keeps the\n // closed content mounted while it waits for an animationend that a\n // mount-only animation never fires again — an invisible overlay\n // eating clicks. Scoping it makes the closed element compute\n // `animation-name: none`, which is the immediate-unmount branch.\n 'data-[state=open]:animate-fade-rise',\n )\n \"\n >\n <SelectViewport class=\"p-1\">\n <!-- The rows reveal one step after another, from the shared stagger\n vocabulary rather than a per-template delay of its own. -->\n <SelectItem\n v-for=\"(option, index) in options\"\n :key=\"option.value\"\n :value=\"option.value\"\n :disabled=\"option.disabled ?? false\"\n :style=\"{ animationDelay: listStaggerDelay(index) }\"\n :class=\"\n cn(\n 'relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-3 py-1.5 pr-8 text-sm text-foreground outline-none',\n 'transition-colors duration-fast ease-out',\n 'animate-fade-rise',\n 'data-[highlighted]:bg-subtle',\n 'data-[state=checked]:bg-primary-muted data-[state=checked]:text-primary',\n 'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',\n )\n \"\n >\n <SelectItemText>{{ option.label }}</SelectItemText>\n <SelectItemIndicator class=\"absolute right-2 inline-flex items-center\">\n <Check class=\"h-4 w-4\" />\n </SelectItemIndicator>\n </SelectItem>\n </SelectViewport>\n </SelectContent>\n </SelectPortal>\n </SelectRoot>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"Select.js","names":[],"sources":["../../../src/primitives/Select/Select.vue"],"sourcesContent":["<script lang=\"ts\">\nimport { cva } from \"class-variance-authority\";\n\n/** One row of the list. `value` is what the model carries; `label` is what a reader sees. */\nexport interface SelectOption {\n /** The value bound to `v-model` when this row is chosen. Unique within the list. */\n value: string;\n /** The text shown on the row, and on the trigger once it is chosen. */\n label: string;\n /** Present but unchoosable — visible, skipped by the keyboard, unclickable. */\n disabled?: boolean;\n}\n\n/**\n * The trigger's height scale. It matches the text input scale exactly, so a\n * form row mixing a Select beside a text field never comes out uneven — which\n * is why reaching past `size` for an `h-*` class is always the wrong fix.\n */\nexport type SelectSize = \"sm\" | \"md\" | \"lg\";\n\nexport const selectVariants = cva(\n [\n \"group inline-flex w-full items-center justify-between gap-2 rounded-md border border-input bg-background text-foreground\",\n \"transition-[color,background-color,box-shadow] duration-fast ease-out hover:bg-subtle\",\n // Rim-lit at rest; the ring blooms on focus.\n \"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\",\n // No `opacity` here, and that is the point. The trigger is the node that\n // carries the chosen label, and what a reader needs from an unavailable\n // Select is exactly that: what it is set to. `disabled:opacity-50`\n // composited `text-foreground` down to 3.06:1 on this fill — halving the\n // alpha more than halves the contrast. Unavailability is painted in\n // measured colours instead: the fill drains to the neutral well and the\n // label lands on `--color-muted-foreground`, 4.68:1 over it.\n //\n // Both survive their neighbours on this element. `hover:` sorts *before*\n // `disabled:` in Tailwind's variant order, so the disabled fill wins over\n // `hover:bg-subtle` rather than flickering under a pointer; and\n // `data-[placeholder]:text-muted-foreground` names the same colour, so the\n // two colour rules agree whatever the sort puts last.\n //\n // The third channel — the rim slackening from `input` to `border` — is\n // **not** here, and cannot be: a `disabled:` variant outranks a plain\n // `border-destructive` on specificity, so a Select that was both in error\n // and unavailable would lose its destructive rim to it. It is written as a\n // plain conditional in the template, where `cn()` can order the two.\n \"disabled:cursor-not-allowed disabled:bg-muted disabled:text-muted-foreground\",\n \"data-[placeholder]:text-muted-foreground\",\n ],\n {\n // `satisfies` keeps the two halves honest: the union above is the name a\n // consumer imports and the documentation prints, the map below is the\n // classes. Adding a member to one and not the other stops compiling.\n variants: {\n size: {\n sm: \"h-8 px-2.5 text-xs\",\n md: \"h-9 px-3 text-sm\",\n lg: \"h-11 px-4 text-base\",\n } satisfies Record<SelectSize, string>,\n },\n defaultVariants: { size: \"md\" },\n },\n);\n</script>\n\n<script setup lang=\"ts\">\nimport {\n SelectRoot,\n SelectTrigger,\n SelectValue,\n SelectIcon,\n SelectPortal,\n SelectContent,\n SelectViewport,\n SelectItem,\n SelectItemText,\n SelectItemIndicator,\n} from \"reka-ui\";\nimport { computed } from \"vue\";\nimport { Check, ChevronDown } from \"@lucide/vue\";\nimport { cn } from \"../../lib/cn\";\nimport { listStaggerDelay } from \"../../lib/motion\";\nimport { useSplitAttrs } from \"../../lib/attrs\";\nimport { useFieldControl } from \"../../lib/field-context\";\n\n/**\n * Select — pick one value out of a closed list, through a compact trigger and\n * a popover listbox. It suits roughly three to fifteen rows where one value is\n * always chosen: a language, a resolution, a quality preset.\n *\n * Below that, two to five options a reader should see all of at once are\n * better shown than hidden. Above it, a list long enough to need searching\n * wants a combobox, which is a different control rather than a longer version\n * of this one.\n *\n * Built on Reka UI's Select, which supplies the listbox semantics: arrow-key\n * navigation, first-character typeahead, Escape and outside-click to close, and\n * the `role=\"combobox\"` trigger wired to the listbox by `aria-expanded` and\n * `aria-controls`. The active row is tracked by moving real focus onto it, not\n * by `aria-activedescendant`.\n *\n * Inside a [Field](../Field/Field.vue) it wires itself: the row's id, the id of\n * its hint or error line, `required`, `invalid`, `disabled` and the name the\n * chosen value is submitted under all arrive through `useFieldControl()`, so\n * `<Field label=\"Language\" error=\"…\"><Select … /></Field>` needs no attributes\n * at the call site. Both booleans below still win over the row when they are\n * set, in both directions — which is why they default to `undefined` rather\n * than `false`.\n *\n * A row's `readonly` is deliberately ignored. A read-only value is one a reader\n * may see and copy but not change, and a closed list has nothing to show that\n * the trigger is not already showing — so a read-only Select is a disabled\n * Select that lies about being reachable. Rows holding a value nobody may edit\n * want a disabled Select, or no control at all.\n *\n * The consequence is that the library's three resting appearances collapse to\n * two here. A TextField rests available, on show, or unavailable; this control\n * has no middle state, so the lifted `subtle` fill never appears on it and the\n * trigger goes straight from `background` to the drained fill, muted label and\n * slackened rim of the disabled row.\n */\nconst props = withDefaults(\n defineProps<{\n /** The chosen option's `value`. Leave it unset to show the placeholder. */\n modelValue?: string;\n /** The rows, in the order they are shown. */\n options: SelectOption[];\n /** Shown on the trigger while nothing is chosen. It is not an option. */\n placeholder?: string;\n /** Unavailable: dims the trigger and refuses to open. Unset defers to a wrapping Field. */\n disabled?: boolean | undefined;\n /** Error state: paints the destructive border and ring, and sets `aria-invalid`. Unset defers to a wrapping Field's `error`. */\n invalid?: boolean | undefined;\n /** Trigger height. It shares the text input scale so mixed form rows stay aligned. */\n size?: SelectSize;\n }>(),\n {\n // Not `false`, for either. `false` is a caller saying \"this control is fine\n // / enabled even though its row is not\"; absent is a caller saying nothing,\n // and only `undefined` survives to mean that past Vue's\n // absent-Boolean-casts-to-false rule — see TextField.vue, which carries the\n // full reasoning.\n disabled: undefined,\n invalid: undefined,\n size: \"md\",\n },\n);\n\ndefineEmits<{\n /** The chosen option's `value`. Fires once per choice; the list closes with it. */\n \"update:modelValue\": [value: string];\n}>();\n\n// The root renders no DOM node at all, so fallthrough attributes would be\n// dropped on the floor rather than landing anywhere. They go to the trigger,\n// which is the interactive element they describe.\n//\n// `class` is pulled out of that spread and merged through `cn()` instead.\n// Spreading it alongside the trigger's own `:class` only concatenates the two\n// lists — Vue's merge is generic, not Tailwind-aware — so a caller's `w-28`\n// silently loses to the trigger's own `w-full` depending on which utility\n// Tailwind happened to emit last.\ndefineOptions({ inheritAttrs: false });\nconst { attrs, rest: triggerAttrs } = useSplitAttrs();\n\n// `id` and `aria-describedby` reach this control as fallthrough attrs rather\n// than props, so they are read off `attrs` and handed in as this caller's own\n// values — a caller who sets either still beats the row, and the row's\n// description is merged into theirs rather than replacing it. `name`,\n// `readonly` and `required` are absent from this object because there is no\n// prop to oppose the row with; the row's answer stands unopposed, which is\n// what is wanted.\nconst field = useFieldControl(() => ({\n id: attrs.id as string | undefined,\n describedBy: attrs[\"aria-describedby\"] as string | undefined,\n disabled: props.disabled,\n invalid: props.invalid,\n}));\n\n// Two of the resolved keys do not travel with the bag, and both are Reka\n// facts rather than preferences.\n//\n// `aria-required` cannot be delivered this way at all: Reka's `Slot` merges an\n// as-child chain as `mergeProps(attrs, child.props)`, so the trigger's own\n// declaration — `aria-required` off the root's `required` prop — beats anything\n// arriving from outside, and a value spread here would be dropped silently.\n// The root's prop below is the only lever, and it is bound from the same\n// resolved value.\n//\n// `name` would be the `name` of a `<button type=\"button\">`, which no form\n// submission has ever included; the hidden input at the end of the template\n// carries the value instead.\nconst triggerFieldAttrs = computed(() => {\n // Removed from a copy rather than listed positively, so a key added to the\n // resolved bag later reaches this trigger without anyone remembering to come\n // back here.\n const aria: Record<string, unknown> = { ...field.attrs };\n delete aria.name;\n delete aria[\"aria-required\"];\n return aria;\n});\n</script>\n\n<template>\n <SelectRoot\n :model-value=\"modelValue ?? ''\"\n :disabled=\"field.disabled\"\n :required=\"field.required\"\n @update:model-value=\"$emit('update:modelValue', String($event))\"\n >\n <SelectTrigger\n v-bind=\"{ ...triggerAttrs, ...triggerFieldAttrs }\"\n :data-invalid=\"field.invalid || undefined\"\n :class=\"\n cn(\n selectVariants({ size }),\n !field.invalid && 'focus-visible:shadow-halo',\n // The border half of the disabled treatment, and it lives here rather\n // than beside the fill in the variant map for the reason written\n // there. Read as a pair with the line below: `cn()` resolves a border\n // colour by whichever class it saw last, so an unavailable trigger\n // that is also in error still shows the destructive rim.\n field.disabled && 'border-border',\n field.invalid && 'border-destructive focus-visible:outline-destructive',\n attrs.class as string,\n )\n \"\n >\n <SelectValue :placeholder=\"placeholder ?? ''\" />\n <SelectIcon class=\"shrink-0 text-muted-foreground\">\n <ChevronDown\n class=\"h-4 w-4 transition-transform duration-fast ease-out group-data-[state=open]:rotate-180\"\n />\n </SelectIcon>\n </SelectTrigger>\n\n <SelectPortal>\n <SelectContent\n position=\"popper\"\n :side-offset=\"6\"\n :class=\"\n cn(\n 'z-50 min-w-[var(--reka-select-trigger-width)] overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md',\n // Scoped to the open state, never unconditional. Reka keeps the\n // closed content mounted while it waits for an animationend that a\n // mount-only animation never fires again — an invisible overlay\n // eating clicks. Scoping it makes the closed element compute\n // `animation-name: none`, which is the immediate-unmount branch.\n 'data-[state=open]:animate-fade-rise',\n )\n \"\n >\n <SelectViewport class=\"p-1\">\n <!-- The rows reveal one step after another, from the shared stagger\n vocabulary rather than a per-template delay of its own. -->\n <SelectItem\n v-for=\"(option, index) in options\"\n :key=\"option.value\"\n :value=\"option.value\"\n :disabled=\"option.disabled ?? false\"\n :style=\"{ animationDelay: listStaggerDelay(index) }\"\n :class=\"\n cn(\n 'relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-3 py-1.5 pr-8 text-sm text-foreground outline-none',\n 'transition-colors duration-fast ease-out',\n 'animate-fade-rise',\n 'data-[highlighted]:bg-subtle',\n 'data-[state=checked]:bg-primary-muted data-[state=checked]:text-primary',\n // Inert, but still readable: a row a reader cannot pick is\n // still a row they have to read to understand why the list is\n // shaped the way it is. `data-[disabled]:opacity-50` took the\n // label to 3.13:1 on the popover; the colour on the text node\n // below leaves it at 5.76:1 and still visibly lighter than the\n // rows around it.\n 'data-[disabled]:pointer-events-none',\n )\n \"\n >\n <!-- The mute lives here rather than on the row, and it has to.\n `data-[disabled]:` sorts *before* `data-[state=checked]:` in\n Tailwind's variant order, so a disabled row that is also the\n chosen one would take `text-primary` from the container and a\n container colour is only inherited. Declared on the text node\n it wins whatever the row resolved to. -->\n <SelectItemText :class=\"option.disabled && 'text-muted-foreground'\">{{\n option.label\n }}</SelectItemText>\n <SelectItemIndicator class=\"absolute right-2 inline-flex items-center\">\n <Check class=\"h-4 w-4\" />\n </SelectItemIndicator>\n </SelectItem>\n </SelectViewport>\n </SelectContent>\n </SelectPortal>\n\n <!-- What a surrounding `<form>` reads, and only once a row has given this\n control a name. Reka can render a hidden native `<select>` from the\n root's own `name` instead, and two of its behaviours are wrong here: a\n native select always resolves to one of its options, so it would post\n the first row while the placeholder was still showing, and `required`\n on a visually-hidden control arms browser validation the library\n deliberately never arms — a submission blocked with \"an invalid form\n control is not focusable\" and no bubble anyone can see. A hidden input\n posts the model and nothing else. -->\n <input\n v-if=\"field.name\"\n type=\"hidden\"\n :name=\"field.name\"\n :value=\"modelValue ?? ''\"\n :disabled=\"field.disabled\"\n />\n </SelectRoot>\n</template>\n"],"mappings":""}
@@ -25,10 +25,10 @@ declare const __VLS_export: import("vue").DefineComponent<{
25
25
  options: SelectOption[];
26
26
  /** Shown on the trigger while nothing is chosen. It is not an option. */
27
27
  placeholder?: string;
28
- /** Unavailable: dims the trigger and refuses to open. */
29
- disabled?: boolean;
30
- /** Error state: paints the destructive border and ring, and sets `aria-invalid`. */
31
- invalid?: boolean;
28
+ /** Unavailable: dims the trigger and refuses to open. Unset defers to a wrapping Field. */
29
+ disabled?: boolean | undefined;
30
+ /** Error state: paints the destructive border and ring, and sets `aria-invalid`. Unset defers to a wrapping Field's `error`. */
31
+ invalid?: boolean | undefined;
32
32
  /** Trigger height. It shares the text input scale so mixed form rows stay aligned. */
33
33
  size?: SelectSize;
34
34
  }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
@@ -40,17 +40,17 @@ declare const __VLS_export: import("vue").DefineComponent<{
40
40
  options: SelectOption[];
41
41
  /** Shown on the trigger while nothing is chosen. It is not an option. */
42
42
  placeholder?: string;
43
- /** Unavailable: dims the trigger and refuses to open. */
44
- disabled?: boolean;
45
- /** Error state: paints the destructive border and ring, and sets `aria-invalid`. */
46
- invalid?: boolean;
43
+ /** Unavailable: dims the trigger and refuses to open. Unset defers to a wrapping Field. */
44
+ disabled?: boolean | undefined;
45
+ /** Error state: paints the destructive border and ring, and sets `aria-invalid`. Unset defers to a wrapping Field's `error`. */
46
+ invalid?: boolean | undefined;
47
47
  /** Trigger height. It shares the text input scale so mixed form rows stay aligned. */
48
48
  size?: SelectSize;
49
49
  }> & Readonly<{
50
50
  "onUpdate:modelValue"?: (value: string) => any;
51
51
  }>, {
52
52
  size: SelectSize;
53
- disabled: boolean;
54
- invalid: boolean;
53
+ disabled: boolean | undefined;
54
+ invalid: boolean | undefined;
55
55
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
56
56
  //# sourceMappingURL=Select.vue.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Select.vue.d.ts","sourceRoot":"","sources":["../../../src/primitives/Select/Select.vue"],"names":[],"mappings":"AAkNA,6FAA6F;AAC7F,MAAM,WAAW,YAAY;IAC3B,oFAAoF;IACpF,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE5C,eAAO,MAAM,cAAc;;8EAqB1B,CAAC;wBACmB,OAAO,YAAY;AAAxC,wBAAyC;AACzC,QAAA,MAAM,YAAY;IAkBd,2EAA2E;iBAC9D,MAAM;IACnB,6CAA6C;aACpC,YAAY,EAAE;IACvB,yEAAyE;kBAC3D,MAAM;IACpB,yDAAyD;eAC9C,OAAO;IAClB,oFAAoF;cAC1E,OAAO;IACjB,sFAAsF;WAC/E,UAAU;;;;IAXjB,2EAA2E;iBAC9D,MAAM;IACnB,6CAA6C;aACpC,YAAY,EAAE;IACvB,yEAAyE;kBAC3D,MAAM;IACpB,yDAAyD;eAC9C,OAAO;IAClB,oFAAoF;cAC1E,OAAO;IACjB,sFAAsF;WAC/E,UAAU;;;;UAAV,UAAU;cAJN,OAAO;aAER,OAAO;6EAyUjB,CAAC"}
1
+ {"version":3,"file":"Select.vue.d.ts","sourceRoot":"","sources":["../../../src/primitives/Select/Select.vue"],"names":[],"mappings":"AAiVA,6FAA6F;AAC7F,MAAM,WAAW,YAAY;IAC3B,oFAAoF;IACpF,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE5C,eAAO,MAAM,cAAc;;8EAyC1B,CAAC;wBACmB,OAAO,YAAY;AAAxC,wBAAyC;AACzC,QAAA,MAAM,YAAY;IAsCd,2EAA2E;iBAC9D,MAAM;IACnB,6CAA6C;aACpC,YAAY,EAAE;IACvB,yEAAyE;kBAC3D,MAAM;IACpB,2FAA2F;eAChF,OAAO,GAAG,SAAS;IAC9B,gIAAgI;cACtH,OAAO,GAAG,SAAS;IAC7B,sFAAsF;WAC/E,UAAU;;;;IAXjB,2EAA2E;iBAC9D,MAAM;IACnB,6CAA6C;aACpC,YAAY,EAAE;IACvB,yEAAyE;kBAC3D,MAAM;IACpB,2FAA2F;eAChF,OAAO,GAAG,SAAS;IAC9B,gIAAgI;cACtH,OAAO,GAAG,SAAS;IAC7B,sFAAsF;WAC/E,UAAU;;;;UAAV,UAAU;cAJN,OAAO,GAAG,SAAS;aAEpB,OAAO,GAAG,SAAS;6EAsa7B,CAAC"}
@@ -1,8 +1,9 @@
1
1
  import { cn } from "../../lib/cn.js";
2
2
  import { listStaggerDelay } from "../../lib/motion.js";
3
3
  import { useSplitAttrs } from "../../lib/attrs.js";
4
+ import { useFieldControl } from "../../lib/field-context.js";
4
5
  import { Check, ChevronDown } from "@lucide/vue";
5
- import { Fragment, createBlock, createElementBlock, createTextVNode, createVNode, defineComponent, mergeProps, normalizeClass, normalizeStyle, openBlock, renderList, toDisplayString, unref, withCtx } from "vue";
6
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createTextVNode, createVNode, defineComponent, mergeProps, normalizeClass, normalizeStyle, openBlock, renderList, toDisplayString, unref, withCtx } from "vue";
6
7
  import { SelectContent, SelectIcon, SelectItem, SelectItemIndicator, SelectItemText, SelectPortal, SelectRoot, SelectTrigger, SelectValue, SelectViewport } from "reka-ui";
7
8
  import { cva } from "class-variance-authority";
8
9
  //#region src/primitives/Select/Select.vue?vue&type=script&setup=true&lang.ts
@@ -21,12 +22,38 @@ import { cva } from "class-variance-authority";
21
22
  * the `role="combobox"` trigger wired to the listbox by `aria-expanded` and
22
23
  * `aria-controls`. The active row is tracked by moving real focus onto it, not
23
24
  * by `aria-activedescendant`.
25
+ *
26
+ * Inside a [Field](../Field/Field.vue) it wires itself: the row's id, the id of
27
+ * its hint or error line, `required`, `invalid`, `disabled` and the name the
28
+ * chosen value is submitted under all arrive through `useFieldControl()`, so
29
+ * `<Field label="Language" error="…"><Select … /></Field>` needs no attributes
30
+ * at the call site. Both booleans below still win over the row when they are
31
+ * set, in both directions — which is why they default to `undefined` rather
32
+ * than `false`.
33
+ *
34
+ * A row's `readonly` is deliberately ignored. A read-only value is one a reader
35
+ * may see and copy but not change, and a closed list has nothing to show that
36
+ * the trigger is not already showing — so a read-only Select is a disabled
37
+ * Select that lies about being reachable. Rows holding a value nobody may edit
38
+ * want a disabled Select, or no control at all.
39
+ *
40
+ * The consequence is that the library's three resting appearances collapse to
41
+ * two here. A TextField rests available, on show, or unavailable; this control
42
+ * has no middle state, so the lifted `subtle` fill never appears on it and the
43
+ * trigger goes straight from `background` to the drained fill, muted label and
44
+ * slackened rim of the disabled row.
24
45
  */
46
+ var _hoisted_1 = [
47
+ "name",
48
+ "value",
49
+ "disabled"
50
+ ];
25
51
  var selectVariants = cva([
26
52
  "group inline-flex w-full items-center justify-between gap-2 rounded-md border border-input bg-background text-foreground",
27
53
  "transition-[color,background-color,box-shadow] duration-fast ease-out hover:bg-subtle",
28
54
  "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring",
29
- "disabled:cursor-not-allowed disabled:opacity-50 data-[placeholder]:text-muted-foreground"
55
+ "disabled:cursor-not-allowed disabled:bg-muted disabled:text-muted-foreground",
56
+ "data-[placeholder]:text-muted-foreground"
30
57
  ], {
31
58
  variants: { size: {
32
59
  sm: "h-8 px-2.5 text-xs",
@@ -44,75 +71,101 @@ var Select_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCom
44
71
  placeholder: {},
45
72
  disabled: {
46
73
  type: Boolean,
47
- default: false
74
+ default: void 0
48
75
  },
49
76
  invalid: {
50
77
  type: Boolean,
51
- default: false
78
+ default: void 0
52
79
  },
53
80
  size: { default: "md" }
54
81
  },
55
82
  emits: ["update:modelValue"],
56
83
  setup(__props) {
84
+ const props = __props;
57
85
  const { attrs, rest: triggerAttrs } = useSplitAttrs();
86
+ const field = useFieldControl(() => ({
87
+ id: attrs.id,
88
+ describedBy: attrs["aria-describedby"],
89
+ disabled: props.disabled,
90
+ invalid: props.invalid
91
+ }));
92
+ const triggerFieldAttrs = computed(() => {
93
+ const aria = { ...field.attrs };
94
+ delete aria.name;
95
+ delete aria["aria-required"];
96
+ return aria;
97
+ });
58
98
  return (_ctx, _cache) => {
59
99
  return openBlock(), createBlock(unref(SelectRoot), {
60
100
  "model-value": __props.modelValue ?? "",
61
- disabled: __props.disabled,
101
+ disabled: unref(field).disabled,
102
+ required: unref(field).required,
62
103
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => _ctx.$emit("update:modelValue", String($event)))
63
104
  }, {
64
- default: withCtx(() => [createVNode(unref(SelectTrigger), mergeProps(unref(triggerAttrs), {
65
- "aria-invalid": __props.invalid || void 0,
66
- "data-invalid": __props.invalid || void 0,
67
- class: unref(cn)(unref(selectVariants)({ size: __props.size }), !__props.invalid && "focus-visible:shadow-halo", __props.invalid && "border-destructive focus-visible:outline-destructive", unref(attrs).class)
68
- }), {
69
- default: withCtx(() => [createVNode(unref(SelectValue), { placeholder: __props.placeholder ?? "" }, null, 8, ["placeholder"]), createVNode(unref(SelectIcon), { class: "shrink-0 text-muted-foreground" }, {
70
- default: withCtx(() => [createVNode(unref(ChevronDown), { class: "h-4 w-4 transition-transform duration-fast ease-out group-data-[state=open]:rotate-180" })]),
71
- _: 1
72
- })]),
73
- _: 1
74
- }, 16, [
75
- "aria-invalid",
76
- "data-invalid",
77
- "class"
78
- ]), createVNode(unref(SelectPortal), null, {
79
- default: withCtx(() => [createVNode(unref(SelectContent), {
80
- position: "popper",
81
- "side-offset": 6,
82
- class: normalizeClass(unref(cn)("z-50 min-w-[var(--reka-select-trigger-width)] overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md", "data-[state=open]:animate-fade-rise"))
105
+ default: withCtx(() => [
106
+ createVNode(unref(SelectTrigger), mergeProps({
107
+ ...unref(triggerAttrs),
108
+ ...triggerFieldAttrs.value
83
109
  }, {
84
- default: withCtx(() => [createVNode(unref(SelectViewport), { class: "p-1" }, {
85
- default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.options, (option, index) => {
86
- return openBlock(), createBlock(unref(SelectItem), {
87
- key: option.value,
88
- value: option.value,
89
- disabled: option.disabled ?? false,
90
- style: normalizeStyle({ animationDelay: unref(listStaggerDelay)(index) }),
91
- class: normalizeClass(unref(cn)("relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-3 py-1.5 pr-8 text-sm text-foreground outline-none", "transition-colors duration-fast ease-out", "animate-fade-rise", "data-[highlighted]:bg-subtle", "data-[state=checked]:bg-primary-muted data-[state=checked]:text-primary", "data-[disabled]:pointer-events-none data-[disabled]:opacity-50"))
92
- }, {
93
- default: withCtx(() => [createVNode(unref(SelectItemText), null, {
94
- default: withCtx(() => [createTextVNode(toDisplayString(option.label), 1)]),
95
- _: 2
96
- }, 1024), createVNode(unref(SelectItemIndicator), { class: "absolute right-2 inline-flex items-center" }, {
97
- default: withCtx(() => [createVNode(unref(Check), { class: "h-4 w-4" })]),
98
- _: 1
99
- })]),
100
- _: 2
101
- }, 1032, [
102
- "value",
103
- "disabled",
104
- "style",
105
- "class"
106
- ]);
107
- }), 128))]),
110
+ "data-invalid": unref(field).invalid || void 0,
111
+ class: unref(cn)(unref(selectVariants)({ size: __props.size }), !unref(field).invalid && "focus-visible:shadow-halo", unref(field).disabled && "border-border", unref(field).invalid && "border-destructive focus-visible:outline-destructive", unref(attrs).class)
112
+ }), {
113
+ default: withCtx(() => [createVNode(unref(SelectValue), { placeholder: __props.placeholder ?? "" }, null, 8, ["placeholder"]), createVNode(unref(SelectIcon), { class: "shrink-0 text-muted-foreground" }, {
114
+ default: withCtx(() => [createVNode(unref(ChevronDown), { class: "h-4 w-4 transition-transform duration-fast ease-out group-data-[state=open]:rotate-180" })]),
108
115
  _: 1
109
116
  })]),
110
117
  _: 1
111
- }, 8, ["class"])]),
112
- _: 1
113
- })]),
118
+ }, 16, ["data-invalid", "class"]),
119
+ createVNode(unref(SelectPortal), null, {
120
+ default: withCtx(() => [createVNode(unref(SelectContent), {
121
+ position: "popper",
122
+ "side-offset": 6,
123
+ class: normalizeClass(unref(cn)("z-50 min-w-[var(--reka-select-trigger-width)] overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md", "data-[state=open]:animate-fade-rise"))
124
+ }, {
125
+ default: withCtx(() => [createVNode(unref(SelectViewport), { class: "p-1" }, {
126
+ default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.options, (option, index) => {
127
+ return openBlock(), createBlock(unref(SelectItem), {
128
+ key: option.value,
129
+ value: option.value,
130
+ disabled: option.disabled ?? false,
131
+ style: normalizeStyle({ animationDelay: unref(listStaggerDelay)(index) }),
132
+ class: normalizeClass(unref(cn)("relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-3 py-1.5 pr-8 text-sm text-foreground outline-none", "transition-colors duration-fast ease-out", "animate-fade-rise", "data-[highlighted]:bg-subtle", "data-[state=checked]:bg-primary-muted data-[state=checked]:text-primary", "data-[disabled]:pointer-events-none"))
133
+ }, {
134
+ default: withCtx(() => [createVNode(unref(SelectItemText), { class: normalizeClass(option.disabled && "text-muted-foreground") }, {
135
+ default: withCtx(() => [createTextVNode(toDisplayString(option.label), 1)]),
136
+ _: 2
137
+ }, 1032, ["class"]), createVNode(unref(SelectItemIndicator), { class: "absolute right-2 inline-flex items-center" }, {
138
+ default: withCtx(() => [createVNode(unref(Check), { class: "h-4 w-4" })]),
139
+ _: 1
140
+ })]),
141
+ _: 2
142
+ }, 1032, [
143
+ "value",
144
+ "disabled",
145
+ "style",
146
+ "class"
147
+ ]);
148
+ }), 128))]),
149
+ _: 1
150
+ })]),
151
+ _: 1
152
+ }, 8, ["class"])]),
153
+ _: 1
154
+ }),
155
+ unref(field).name ? (openBlock(), createElementBlock("input", {
156
+ key: 0,
157
+ type: "hidden",
158
+ name: unref(field).name,
159
+ value: __props.modelValue ?? "",
160
+ disabled: unref(field).disabled
161
+ }, null, 8, _hoisted_1)) : createCommentVNode("", true)
162
+ ]),
114
163
  _: 1
115
- }, 8, ["model-value", "disabled"]);
164
+ }, 8, [
165
+ "model-value",
166
+ "disabled",
167
+ "required"
168
+ ]);
116
169
  };
117
170
  }
118
171
  });