@12-apps/ui 6.46.1 → 6.48.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 (301) hide show
  1. package/components-catalog.md +1 -1
  2. package/dist/_internal/components/data-display/Avatar/Avatar.js +3 -3
  3. package/dist/_internal/components/data-display/Avatar/Avatar.view.js +2 -2
  4. package/dist/_internal/components/data-display/Badge/Badge.js +2 -2
  5. package/dist/_internal/components/data-display/CardKit/use-remove-confirm.js +1 -1
  6. package/dist/_internal/components/data-display/CardKit/use-row-confirm.js +1 -1
  7. package/dist/_internal/components/data-display/Chart/Chart.js +4 -4
  8. package/dist/_internal/components/data-display/Chart/SpecChart.js +7 -7
  9. package/dist/_internal/components/data-display/Chart/chart-context.js +2 -2
  10. package/dist/_internal/components/data-display/Chart/chart-renderers.js +3 -3
  11. package/dist/_internal/components/data-display/Chart/chart-spec.js +2 -2
  12. package/dist/_internal/components/data-display/DataViews/DataViewsGrid.js +32 -32
  13. package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +41 -41
  14. package/dist/_internal/components/data-display/DataViews/ManageViewsDialog.js +1 -1
  15. package/dist/_internal/components/data-display/DataViews/SaveViewModal.js +3 -3
  16. package/dist/_internal/components/data-display/DataViews/base-list-card-geometry.js +4 -4
  17. package/dist/_internal/components/data-display/DataViews/base-list-card-slots.js +3 -3
  18. package/dist/_internal/components/data-display/DataViews/base-list-card.js +7 -7
  19. package/dist/_internal/components/data-display/DataViews/data-views-category-pill.js +9 -9
  20. package/dist/_internal/components/data-display/DataViews/data-views-display-panel.js +1 -1
  21. package/dist/_internal/components/data-display/DataViews/data-views-filter-panel.js +15 -15
  22. package/dist/_internal/components/data-display/DataViews/data-views-grid-bodies.js +5 -5
  23. package/dist/_internal/components/data-display/DataViews/data-views-grid-parts.js +29 -29
  24. package/dist/_internal/components/data-display/DataViews/data-views-inline-bar.js +14 -14
  25. package/dist/_internal/components/data-display/DataViews/data-views-more-fields.js +12 -12
  26. package/dist/_internal/components/data-display/DataViews/data-views-more-filters.js +13 -13
  27. package/dist/_internal/components/data-display/DataViews/data-views-range-pill.js +2 -2
  28. package/dist/_internal/components/data-display/DataViews/data-views-scope-tabs.js +2 -2
  29. package/dist/_internal/components/data-display/DataViews/data-views-shell-toolbar.js +2 -2
  30. package/dist/_internal/components/data-display/DataViews/data-views-table-parts.js +5 -5
  31. package/dist/_internal/components/data-display/DataViews/data-views-toolbar.js +2 -2
  32. package/dist/_internal/components/data-display/DataViews/list-card-rails.js +2 -2
  33. package/dist/_internal/components/data-display/DataViews/use-data-views-state.js +2 -2
  34. package/dist/_internal/components/data-display/FleetMap/FleetBody.js +11 -11
  35. package/dist/_internal/components/data-display/FleetMap/FleetCanvas.js +8 -8
  36. package/dist/_internal/components/data-display/FleetMap/FleetMap.js +12 -12
  37. package/dist/_internal/components/data-display/FleetMap/FleetRoster.js +2 -2
  38. package/dist/_internal/components/data-display/HoverCard/HoverCard.js +3 -3
  39. package/dist/_internal/components/data-display/Lightbox/Lightbox.js +3 -3
  40. package/dist/_internal/components/data-display/MapPreview/MapLayers.js +2 -2
  41. package/dist/_internal/components/data-display/MapPreview/MapPreview.js +7 -7
  42. package/dist/_internal/components/data-display/Progress/Progress.js +2 -2
  43. package/dist/_internal/components/data-display/Sheet/Sheet.js +4 -4
  44. package/dist/_internal/components/data-display/Table/Table.js +3 -3
  45. package/dist/_internal/components/data-display/index.js +42 -42
  46. package/dist/_internal/components/feedback/StackedModal/StackedModal.js +3 -3
  47. package/dist/_internal/components/feedback/StackedModal/StackedModal.parts.js +2 -2
  48. package/dist/_internal/components/feedback/StackedModal/StackedModal.styles.js +1 -1
  49. package/dist/_internal/components/feedback/TutorialOverlay/TutorialOverlay.js +2 -2
  50. package/dist/_internal/components/feedback/index.js +8 -8
  51. package/dist/_internal/components/form/AddressAutocomplete/AddressAutocomplete.hooks.js +4 -4
  52. package/dist/_internal/components/form/AddressAutocomplete/AddressAutocomplete.js +7 -7
  53. package/dist/_internal/components/form/Autocomplete/Autocomplete.js +2 -2
  54. package/dist/_internal/components/form/Calendar/Calendar.hooks.js +2 -2
  55. package/dist/_internal/components/form/Calendar/Calendar.js +3 -3
  56. package/dist/_internal/components/form/CategorySelect/CategoryPanel.js +4 -4
  57. package/dist/_internal/components/form/CategorySelect/CategoryPanelList.js +3 -3
  58. package/dist/_internal/components/form/CategorySelect/CategoryRows.js +2 -2
  59. package/dist/_internal/components/form/CategorySelect/CategorySelect.js +8 -8
  60. package/dist/_internal/components/form/CepField/CepField.js +3 -3
  61. package/dist/_internal/components/form/CodeEditor/CodeEditor.js +2 -2
  62. package/dist/_internal/components/form/Command/Command.js +2 -2
  63. package/dist/_internal/components/form/DateRangePicker/DateRangePicker.js +5 -5
  64. package/dist/_internal/components/form/Input/Input.js +2 -2
  65. package/dist/_internal/components/form/NumberField/NumberField.js +3 -3
  66. package/dist/_internal/components/form/Select/Select.js +5 -2
  67. package/dist/_internal/components/form/Select/Select.metrics.js +5 -1
  68. package/dist/_internal/components/form/Select/Select.searchable.js +28 -0
  69. package/dist/_internal/components/form/Select/Select.searchable.js.map +1 -0
  70. package/dist/_internal/components/form/Select/Select.styles.js +25 -0
  71. package/dist/_internal/components/form/Select/Select.styles.js.map +1 -0
  72. package/dist/_internal/components/form/index.js +32 -29
  73. package/dist/_internal/components/form/total-form/Fields/CategoryField.js +9 -9
  74. package/dist/_internal/components/form/total-form/Fields/CepField.js +4 -4
  75. package/dist/_internal/components/form/total-form/Fields/SelectField.js +6 -3
  76. package/dist/_internal/components/form/total-form/Fields/TextField.js +3 -3
  77. package/dist/_internal/components/form/total-form/Fields/index.js +20 -18
  78. package/dist/_internal/components/index.js +88 -86
  79. package/dist/_internal/components/navigation/AppHeader/AppHeader.details.js +4 -4
  80. package/dist/_internal/components/navigation/SectionNav/SectionNav.bar.js +6 -6
  81. package/dist/_internal/components/navigation/SectionNav/SectionNav.js +8 -8
  82. package/dist/_internal/components/navigation/SectionNav/SectionNav.parts.js +3 -3
  83. package/dist/_internal/components/navigation/SectionNav/SectionNav.primary.js +4 -4
  84. package/dist/_internal/components/navigation/SectionNav/SectionNav.rail.js +4 -4
  85. package/dist/_internal/components/navigation/SectionNav/SectionNav.sheet.js +4 -4
  86. package/dist/_internal/components/navigation/index.js +12 -12
  87. package/dist/_internal/user-avatar/user-avatar.js +4 -4
  88. package/dist/charts.js +10 -10
  89. package/dist/{chunk-A64MQ7GW.js → chunk-2LSJTQIL.js} +2 -2
  90. package/dist/{chunk-EU76OQGR.js → chunk-2NYVMLFQ.js} +2 -2
  91. package/dist/{chunk-CJPP4OUK.js → chunk-2YKTB2IZ.js} +2 -2
  92. package/dist/{chunk-ISW5K72V.js → chunk-2ZRZTGWP.js} +5 -5
  93. package/dist/{chunk-LQRUTHJY.js → chunk-3CDU7DLD.js} +5 -5
  94. package/dist/{chunk-72FPUWD6.js → chunk-3IPQANXY.js} +2 -2
  95. package/dist/{chunk-442FSG7G.js → chunk-3QGMAVUF.js} +5 -3
  96. package/dist/chunk-3QGMAVUF.js.map +1 -0
  97. package/dist/{chunk-56QYSVLI.js → chunk-3WAAL3KN.js} +7 -7
  98. package/dist/{chunk-JO4UMHWR.js → chunk-43UFSKEK.js} +3 -3
  99. package/dist/{chunk-N2XQKTXX.js → chunk-5NFQKL7C.js} +5 -5
  100. package/dist/{chunk-PCHUIDMT.js → chunk-5OEC546C.js} +2 -2
  101. package/dist/{chunk-JBGCGYEC.js → chunk-6EJF3BUR.js} +4 -4
  102. package/dist/{chunk-77JL5XVD.js → chunk-6TZE77YJ.js} +30 -7
  103. package/dist/chunk-6TZE77YJ.js.map +1 -0
  104. package/dist/{chunk-RVOYCPKF.js → chunk-ACU7LEFG.js} +5 -5
  105. package/dist/{chunk-OARM5RX4.js → chunk-AQC67NQZ.js} +5 -5
  106. package/dist/chunk-AV6NNCRO.js +111 -0
  107. package/dist/chunk-AV6NNCRO.js.map +1 -0
  108. package/dist/{chunk-V54LG3QG.js → chunk-B3QWQG62.js} +2 -2
  109. package/dist/{chunk-J2JWWGMT.js → chunk-BPOVRMVS.js} +7 -7
  110. package/dist/{chunk-V4R6Q5ED.js → chunk-CGBUWNNQ.js} +11 -11
  111. package/dist/{chunk-ZCEXSYAJ.js → chunk-CGL7R37P.js} +4 -4
  112. package/dist/{chunk-GYZUJ7HH.js → chunk-CO4MSWTV.js} +5 -5
  113. package/dist/chunk-EISPWFYO.js +146 -0
  114. package/dist/chunk-EISPWFYO.js.map +1 -0
  115. package/dist/{chunk-PGPPN63I.js → chunk-EMEXXAQI.js} +2 -2
  116. package/dist/{chunk-2HPNN5XA.js → chunk-FIF4RQ4S.js} +2 -2
  117. package/dist/{chunk-T6HVNVFI.js → chunk-FQT4C5R4.js} +9 -9
  118. package/dist/{chunk-BWURMQWZ.js → chunk-FS7UVKEE.js} +4 -4
  119. package/dist/{chunk-LUPHXDEU.js → chunk-FVKBP3UX.js} +2 -2
  120. package/dist/{chunk-TPPFWETI.js → chunk-G6II7SVX.js} +7 -7
  121. package/dist/{chunk-LV2SZFXK.js → chunk-GMC3F43L.js} +7 -7
  122. package/dist/{chunk-R6SBP5M5.js → chunk-GOWBYHYW.js} +4 -4
  123. package/dist/{chunk-P3XEF26U.js → chunk-H7DVH6KD.js} +3 -3
  124. package/dist/{chunk-AA7QTFMB.js → chunk-HGRC635A.js} +2 -2
  125. package/dist/{chunk-TE3XYCX7.js → chunk-IHO2O44S.js} +5 -5
  126. package/dist/{chunk-VPH47OIV.js → chunk-IKZSQKOE.js} +2 -2
  127. package/dist/{chunk-IPI3OU2P.js → chunk-IV7G7NK3.js} +5 -5
  128. package/dist/{chunk-WYXNFH5Y.js → chunk-IYC7NPX7.js} +14 -2
  129. package/dist/{chunk-WYXNFH5Y.js.map → chunk-IYC7NPX7.js.map} +1 -1
  130. package/dist/{chunk-HC2AO3RT.js → chunk-J44PPGBF.js} +2 -2
  131. package/dist/{chunk-V2GHNHP6.js → chunk-JAHWFJCW.js} +4 -4
  132. package/dist/{chunk-HAFLKWWU.js → chunk-JQ6HDXKA.js} +2 -2
  133. package/dist/{chunk-SPZAEMGW.js → chunk-JWJ77IMK.js} +4 -4
  134. package/dist/{chunk-HYNDC3FP.js → chunk-JYLOCXMV.js} +5 -5
  135. package/dist/{chunk-QQUNZH3L.js → chunk-KESGVMHW.js} +3 -3
  136. package/dist/{chunk-JTWRI4WD.js → chunk-KN7C6R6L.js} +14 -14
  137. package/dist/{chunk-ILKNYENU.js → chunk-LB27LKG3.js} +4 -4
  138. package/dist/{chunk-IWYTOCCV.js → chunk-LHTEAPYG.js} +4 -4
  139. package/dist/{chunk-TPVSHO75.js → chunk-NLEO5YI4.js} +7 -7
  140. package/dist/{chunk-K45ML7M7.js → chunk-NU55QUMO.js} +2 -2
  141. package/dist/{chunk-KN3WYEH2.js → chunk-NYHZUVLC.js} +4 -4
  142. package/dist/{chunk-U2UT2NDH.js → chunk-OBID7SOG.js} +2 -2
  143. package/dist/{chunk-UUJ7J7NE.js → chunk-PP7CDKO4.js} +2 -2
  144. package/dist/{chunk-6L2FKTBO.js → chunk-PQS3IPMD.js} +10 -91
  145. package/dist/chunk-PQS3IPMD.js.map +1 -0
  146. package/dist/{chunk-6OQHZVK6.js → chunk-QJK7BNH3.js} +5 -5
  147. package/dist/{chunk-PARTZ7XI.js → chunk-R53ZOW4B.js} +2 -2
  148. package/dist/{chunk-L4G5BZFF.js → chunk-RJVUECN7.js} +2 -2
  149. package/dist/{chunk-BWXPO2SE.js → chunk-S22XIXLL.js} +3 -3
  150. package/dist/{chunk-QL7NPQOP.js → chunk-SAJ5H5VC.js} +2 -2
  151. package/dist/{chunk-6GAZAJXB.js → chunk-SDKOOVEX.js} +4 -4
  152. package/dist/{chunk-ETCS6OBJ.js → chunk-THCDUP6Q.js} +9 -9
  153. package/dist/{chunk-CMFJQH6A.js → chunk-UG636FEL.js} +4 -4
  154. package/dist/{chunk-NFA7STJA.js → chunk-UILH4OAZ.js} +5 -5
  155. package/dist/{chunk-X5F4FRH7.js → chunk-VNOXUWK7.js} +4 -4
  156. package/dist/{chunk-MD3ND6DT.js → chunk-VU63PDWW.js} +3 -3
  157. package/dist/{chunk-RBLBXJR7.js → chunk-WAD5VL6B.js} +7 -7
  158. package/dist/{chunk-4MGFUPQT.js → chunk-WC3W36AM.js} +7 -7
  159. package/dist/{chunk-Z3L2EGXW.js → chunk-WDAEYLT5.js} +2 -2
  160. package/dist/{chunk-BEX3FLHB.js → chunk-X3C3VTYS.js} +2 -2
  161. package/dist/{chunk-NFTFP6WO.js → chunk-XNTDEQEB.js} +5 -5
  162. package/dist/{chunk-TWVRPT7J.js → chunk-XXL4PM4M.js} +2 -2
  163. package/dist/{chunk-TNQDSTIA.js → chunk-Y6C4MYZE.js} +7 -7
  164. package/dist/{chunk-NRKAJHBB.js → chunk-YRACC6BB.js} +4 -4
  165. package/dist/{chunk-RSQYWGMU.js → chunk-YTIUFMRM.js} +5 -5
  166. package/dist/{chunk-FQ637IDM.js → chunk-YXU45AVO.js} +5 -5
  167. package/dist/{chunk-YDU2YPQA.js → chunk-ZVJSY2OV.js} +3 -3
  168. package/dist/data-display/Avatar.js +3 -3
  169. package/dist/data-display/Badge.js +2 -2
  170. package/dist/data-display/CardKit.js +10 -10
  171. package/dist/data-display/Chart.js +10 -10
  172. package/dist/data-display/DataViews.js +58 -58
  173. package/dist/data-display/FleetMap.js +12 -12
  174. package/dist/data-display/HoverCard.js +3 -3
  175. package/dist/data-display/Lightbox.js +3 -3
  176. package/dist/data-display/MapPreview.js +7 -7
  177. package/dist/data-display/Progress.js +2 -2
  178. package/dist/data-display/Sheet.js +4 -4
  179. package/dist/data-display/Table.js +3 -3
  180. package/dist/feedback/ConfirmAction.js +3 -3
  181. package/dist/feedback/StackedModal.js +3 -3
  182. package/dist/feedback/TutorialOverlay.js +2 -2
  183. package/dist/form/AddressAutocomplete.js +7 -7
  184. package/dist/form/Autocomplete.js +2 -2
  185. package/dist/form/Calendar.js +3 -3
  186. package/dist/form/CategorySelect.js +8 -8
  187. package/dist/form/CepField.js +3 -3
  188. package/dist/form/CodeEditor.js +2 -2
  189. package/dist/form/Command.js +2 -2
  190. package/dist/form/DateRangePicker.js +10 -10
  191. package/dist/form/Input.js +2 -2
  192. package/dist/form/NumberField.js +3 -3
  193. package/dist/form/Select.js +5 -2
  194. package/dist/form/total-form.js +20 -18
  195. package/dist/native/form/Select.js.map +1 -1
  196. package/dist/navigation/AppHeader.js +4 -4
  197. package/dist/navigation/SectionNav.js +8 -8
  198. package/dist/types/components/feedback/StackedModal/StackedModal.d.ts.map +1 -1
  199. package/dist/types/components/feedback/StackedModal/StackedModal.styles.d.ts +2 -1
  200. package/dist/types/components/feedback/StackedModal/StackedModal.styles.d.ts.map +1 -1
  201. package/dist/types/components/feedback/StackedModal/StackedModal.types.d.ts +8 -0
  202. package/dist/types/components/feedback/StackedModal/StackedModal.types.d.ts.map +1 -1
  203. package/dist/types/components/feedback/StackedModal/index.d.ts +1 -1
  204. package/dist/types/components/feedback/StackedModal/index.d.ts.map +1 -1
  205. package/dist/types/components/form/Select/Select.base.d.ts +15 -0
  206. package/dist/types/components/form/Select/Select.base.d.ts.map +1 -1
  207. package/dist/types/components/form/Select/Select.d.ts +5 -0
  208. package/dist/types/components/form/Select/Select.d.ts.map +1 -1
  209. package/dist/types/components/form/Select/Select.metrics.d.ts +20 -0
  210. package/dist/types/components/form/Select/Select.metrics.d.ts.map +1 -1
  211. package/dist/types/components/form/Select/Select.searchable.d.ts +23 -0
  212. package/dist/types/components/form/Select/Select.searchable.d.ts.map +1 -0
  213. package/dist/types/components/form/Select/Select.styles.d.ts +27 -0
  214. package/dist/types/components/form/Select/Select.styles.d.ts.map +1 -0
  215. package/dist/types-native/components/form/Select/Select.base.d.ts +15 -0
  216. package/dist/types-native/components/form/Select/Select.base.d.ts.map +1 -1
  217. package/dist/types-native/components/form/Select/Select.metrics.d.ts +20 -0
  218. package/dist/types-native/components/form/Select/Select.metrics.d.ts.map +1 -1
  219. package/dist/user-avatar.js +4 -4
  220. package/package.json +1 -1
  221. package/src/components/feedback/StackedModal/StackedModal.md +1 -0
  222. package/src/components/feedback/StackedModal/StackedModal.styles.ts +44 -8
  223. package/src/components/feedback/StackedModal/StackedModal.tsx +2 -1
  224. package/src/components/feedback/StackedModal/StackedModal.types.ts +9 -0
  225. package/src/components/feedback/StackedModal/index.ts +1 -1
  226. package/src/components/form/Select/Select.base.ts +15 -0
  227. package/src/components/form/Select/Select.md +31 -1
  228. package/src/components/form/Select/Select.metrics.ts +22 -0
  229. package/src/components/form/Select/Select.searchable.tsx +203 -0
  230. package/src/components/form/Select/Select.styles.tsx +195 -0
  231. package/src/components/form/Select/Select.tsx +20 -166
  232. package/dist/chunk-442FSG7G.js.map +0 -1
  233. package/dist/chunk-6L2FKTBO.js.map +0 -1
  234. package/dist/chunk-77JL5XVD.js.map +0 -1
  235. /package/dist/{chunk-A64MQ7GW.js.map → chunk-2LSJTQIL.js.map} +0 -0
  236. /package/dist/{chunk-EU76OQGR.js.map → chunk-2NYVMLFQ.js.map} +0 -0
  237. /package/dist/{chunk-CJPP4OUK.js.map → chunk-2YKTB2IZ.js.map} +0 -0
  238. /package/dist/{chunk-ISW5K72V.js.map → chunk-2ZRZTGWP.js.map} +0 -0
  239. /package/dist/{chunk-LQRUTHJY.js.map → chunk-3CDU7DLD.js.map} +0 -0
  240. /package/dist/{chunk-72FPUWD6.js.map → chunk-3IPQANXY.js.map} +0 -0
  241. /package/dist/{chunk-56QYSVLI.js.map → chunk-3WAAL3KN.js.map} +0 -0
  242. /package/dist/{chunk-JO4UMHWR.js.map → chunk-43UFSKEK.js.map} +0 -0
  243. /package/dist/{chunk-N2XQKTXX.js.map → chunk-5NFQKL7C.js.map} +0 -0
  244. /package/dist/{chunk-PCHUIDMT.js.map → chunk-5OEC546C.js.map} +0 -0
  245. /package/dist/{chunk-JBGCGYEC.js.map → chunk-6EJF3BUR.js.map} +0 -0
  246. /package/dist/{chunk-RVOYCPKF.js.map → chunk-ACU7LEFG.js.map} +0 -0
  247. /package/dist/{chunk-OARM5RX4.js.map → chunk-AQC67NQZ.js.map} +0 -0
  248. /package/dist/{chunk-V54LG3QG.js.map → chunk-B3QWQG62.js.map} +0 -0
  249. /package/dist/{chunk-J2JWWGMT.js.map → chunk-BPOVRMVS.js.map} +0 -0
  250. /package/dist/{chunk-V4R6Q5ED.js.map → chunk-CGBUWNNQ.js.map} +0 -0
  251. /package/dist/{chunk-ZCEXSYAJ.js.map → chunk-CGL7R37P.js.map} +0 -0
  252. /package/dist/{chunk-GYZUJ7HH.js.map → chunk-CO4MSWTV.js.map} +0 -0
  253. /package/dist/{chunk-PGPPN63I.js.map → chunk-EMEXXAQI.js.map} +0 -0
  254. /package/dist/{chunk-2HPNN5XA.js.map → chunk-FIF4RQ4S.js.map} +0 -0
  255. /package/dist/{chunk-T6HVNVFI.js.map → chunk-FQT4C5R4.js.map} +0 -0
  256. /package/dist/{chunk-BWURMQWZ.js.map → chunk-FS7UVKEE.js.map} +0 -0
  257. /package/dist/{chunk-LUPHXDEU.js.map → chunk-FVKBP3UX.js.map} +0 -0
  258. /package/dist/{chunk-TPPFWETI.js.map → chunk-G6II7SVX.js.map} +0 -0
  259. /package/dist/{chunk-LV2SZFXK.js.map → chunk-GMC3F43L.js.map} +0 -0
  260. /package/dist/{chunk-R6SBP5M5.js.map → chunk-GOWBYHYW.js.map} +0 -0
  261. /package/dist/{chunk-P3XEF26U.js.map → chunk-H7DVH6KD.js.map} +0 -0
  262. /package/dist/{chunk-AA7QTFMB.js.map → chunk-HGRC635A.js.map} +0 -0
  263. /package/dist/{chunk-TE3XYCX7.js.map → chunk-IHO2O44S.js.map} +0 -0
  264. /package/dist/{chunk-VPH47OIV.js.map → chunk-IKZSQKOE.js.map} +0 -0
  265. /package/dist/{chunk-IPI3OU2P.js.map → chunk-IV7G7NK3.js.map} +0 -0
  266. /package/dist/{chunk-HC2AO3RT.js.map → chunk-J44PPGBF.js.map} +0 -0
  267. /package/dist/{chunk-V2GHNHP6.js.map → chunk-JAHWFJCW.js.map} +0 -0
  268. /package/dist/{chunk-HAFLKWWU.js.map → chunk-JQ6HDXKA.js.map} +0 -0
  269. /package/dist/{chunk-SPZAEMGW.js.map → chunk-JWJ77IMK.js.map} +0 -0
  270. /package/dist/{chunk-HYNDC3FP.js.map → chunk-JYLOCXMV.js.map} +0 -0
  271. /package/dist/{chunk-QQUNZH3L.js.map → chunk-KESGVMHW.js.map} +0 -0
  272. /package/dist/{chunk-JTWRI4WD.js.map → chunk-KN7C6R6L.js.map} +0 -0
  273. /package/dist/{chunk-ILKNYENU.js.map → chunk-LB27LKG3.js.map} +0 -0
  274. /package/dist/{chunk-IWYTOCCV.js.map → chunk-LHTEAPYG.js.map} +0 -0
  275. /package/dist/{chunk-TPVSHO75.js.map → chunk-NLEO5YI4.js.map} +0 -0
  276. /package/dist/{chunk-K45ML7M7.js.map → chunk-NU55QUMO.js.map} +0 -0
  277. /package/dist/{chunk-KN3WYEH2.js.map → chunk-NYHZUVLC.js.map} +0 -0
  278. /package/dist/{chunk-U2UT2NDH.js.map → chunk-OBID7SOG.js.map} +0 -0
  279. /package/dist/{chunk-UUJ7J7NE.js.map → chunk-PP7CDKO4.js.map} +0 -0
  280. /package/dist/{chunk-6OQHZVK6.js.map → chunk-QJK7BNH3.js.map} +0 -0
  281. /package/dist/{chunk-PARTZ7XI.js.map → chunk-R53ZOW4B.js.map} +0 -0
  282. /package/dist/{chunk-L4G5BZFF.js.map → chunk-RJVUECN7.js.map} +0 -0
  283. /package/dist/{chunk-BWXPO2SE.js.map → chunk-S22XIXLL.js.map} +0 -0
  284. /package/dist/{chunk-QL7NPQOP.js.map → chunk-SAJ5H5VC.js.map} +0 -0
  285. /package/dist/{chunk-6GAZAJXB.js.map → chunk-SDKOOVEX.js.map} +0 -0
  286. /package/dist/{chunk-ETCS6OBJ.js.map → chunk-THCDUP6Q.js.map} +0 -0
  287. /package/dist/{chunk-CMFJQH6A.js.map → chunk-UG636FEL.js.map} +0 -0
  288. /package/dist/{chunk-NFA7STJA.js.map → chunk-UILH4OAZ.js.map} +0 -0
  289. /package/dist/{chunk-X5F4FRH7.js.map → chunk-VNOXUWK7.js.map} +0 -0
  290. /package/dist/{chunk-MD3ND6DT.js.map → chunk-VU63PDWW.js.map} +0 -0
  291. /package/dist/{chunk-RBLBXJR7.js.map → chunk-WAD5VL6B.js.map} +0 -0
  292. /package/dist/{chunk-4MGFUPQT.js.map → chunk-WC3W36AM.js.map} +0 -0
  293. /package/dist/{chunk-Z3L2EGXW.js.map → chunk-WDAEYLT5.js.map} +0 -0
  294. /package/dist/{chunk-BEX3FLHB.js.map → chunk-X3C3VTYS.js.map} +0 -0
  295. /package/dist/{chunk-NFTFP6WO.js.map → chunk-XNTDEQEB.js.map} +0 -0
  296. /package/dist/{chunk-TWVRPT7J.js.map → chunk-XXL4PM4M.js.map} +0 -0
  297. /package/dist/{chunk-TNQDSTIA.js.map → chunk-Y6C4MYZE.js.map} +0 -0
  298. /package/dist/{chunk-NRKAJHBB.js.map → chunk-YRACC6BB.js.map} +0 -0
  299. /package/dist/{chunk-RSQYWGMU.js.map → chunk-YTIUFMRM.js.map} +0 -0
  300. /package/dist/{chunk-FQ637IDM.js.map → chunk-YXU45AVO.js.map} +0 -0
  301. /package/dist/{chunk-YDU2YPQA.js.map → chunk-ZVJSY2OV.js.map} +0 -0
@@ -0,0 +1,203 @@
1
+ import Autocomplete from '@mui/material/Autocomplete/index.js';
2
+ import type { AutocompleteRenderInputParams } from '@mui/material/Autocomplete/index.js';
3
+ import type { SelectChangeEvent } from '@mui/material/Select/index.js';
4
+ import { useTheme } from '@mui/material/styles/index.js';
5
+ import type { Theme } from '@mui/material/styles/index.js';
6
+ import TextField from '@mui/material/TextField/index.js';
7
+ import React from 'react';
8
+
9
+ import { SEARCHABLE_MIN_OPTIONS, SELECT_SEARCH } from './Select.metrics';
10
+ import { formControlSize, SelectFieldControl } from './Select.styles';
11
+ import type { SelectOption, SelectProps } from './Select.types';
12
+
13
+ import { splitTestId } from '../../../platform/test-id';
14
+ import { asFieldSize } from '../../../tokens/field-height';
15
+ import { stackedOverlayZIndex } from '../../../tokens/layers';
16
+ import { rem } from '../../../tokens/relative';
17
+
18
+ /**
19
+ * THE SELECT, PAST FIVE OPTIONS: a search box over a list of bounded height.
20
+ *
21
+ * Same engine as `CreatableSelect` — MUI `Autocomplete` — so every searchable
22
+ * dropdown in the library types, filters and scrolls the same way. What it
23
+ * keeps from `Select` is the whole CONTRACT, so a call site cannot tell which
24
+ * one it got until it opens it:
25
+ *
26
+ * - the field chrome ({@link SelectFieldControl}: variant, size, glow, pulse);
27
+ * - the floating label, placeholder, helper text and error;
28
+ * - `onChange(event)` with `event.target.value` — the option's value, a number
29
+ * staying a number, exactly what MUI's `Select` hands its handlers;
30
+ * - disabled options, and the `-select` / `-option-<value>` test ids.
31
+ *
32
+ * It cannot be cleared (a `Select` has no "none" either — its placeholder is
33
+ * disabled), and it never accepts text that is not an option.
34
+ */
35
+
36
+ /** Whether `props` should render as a search box. */
37
+ export function shouldSearch(props: SelectProps): boolean {
38
+ if (props.multiple || props.renderValue) return false;
39
+ if (props.searchable !== undefined) return props.searchable;
40
+ return props.options.length >= SEARCHABLE_MIN_OPTIONS;
41
+ }
42
+
43
+ /**
44
+ * The change MUI's `Select` would have emitted: handlers read
45
+ * `event.target.value` (and sometimes `.name`), so that is what they get.
46
+ */
47
+ function selectChange(value: SelectOption['value'], name: string | undefined): SelectChangeEvent<unknown> {
48
+ return { target: { value, name: name ?? '' } } as unknown as SelectChangeEvent<unknown>;
49
+ }
50
+
51
+ function renderOption(
52
+ props: React.HTMLAttributes<HTMLLIElement>,
53
+ option: SelectOption,
54
+ optionTestId: (value: SelectOption['value']) => string,
55
+ ): React.JSX.Element {
56
+ const { key, ...rest } = props as typeof props & { key?: React.Key };
57
+ return (
58
+ <li key={key ?? option.value} {...rest} data-testid={optionTestId(option.value)}>
59
+ {option.label}
60
+ </li>
61
+ );
62
+ }
63
+
64
+ interface FieldProps {
65
+ params: AutocompleteRenderInputParams;
66
+ field: Pick<SelectProps, 'label' | 'placeholder' | 'helperText' | 'error' | 'name' | 'required' | 'autoFocus' | 'onBlur' | 'onFocus'>;
67
+ ariaLabel: string | undefined;
68
+ disabled: boolean | undefined;
69
+ triggerTestId: string;
70
+ }
71
+
72
+ function renderField({ params, field, ariaLabel, disabled, triggerTestId }: FieldProps): React.JSX.Element {
73
+ return (
74
+ <TextField
75
+ {...params}
76
+ label={field.label}
77
+ placeholder={field.placeholder}
78
+ helperText={field.helperText}
79
+ error={field.error}
80
+ name={field.name}
81
+ required={field.required}
82
+ autoFocus={field.autoFocus}
83
+ onBlur={field.onBlur as React.FocusEventHandler<HTMLInputElement | HTMLTextAreaElement> | undefined}
84
+ onFocus={field.onFocus as React.FocusEventHandler<HTMLInputElement | HTMLTextAreaElement> | undefined}
85
+ // The menu drew its placeholder under a shrunk label (`displayEmpty`);
86
+ // a floating label left down would hide it until focus.
87
+ slotProps={field.placeholder ? { inputLabel: { shrink: true } } : undefined}
88
+ inputProps={{
89
+ ...params.inputProps,
90
+ 'aria-label': ariaLabel,
91
+ // The menu's display div carried `aria-disabled`; the input keeps it.
92
+ 'aria-disabled': disabled ? true : undefined,
93
+ 'data-testid': triggerTestId,
94
+ }}
95
+ />
96
+ );
97
+ }
98
+
99
+ /**
100
+ * The option the field shows, KEPT STABLE while it is the same one.
101
+ *
102
+ * Consumers build `options` inline (`xs.map(...)`), so a fresh `find` returns a
103
+ * new object on every parent render, which MUI reads as a changed value and
104
+ * answers by resetting the typed text — a refetch mid-search wiped the query.
105
+ * Uncontrolled use (`defaultValue`, no `value`) keeps its own state, as MUI's
106
+ * Select did.
107
+ */
108
+ function useSelectedOption(
109
+ options: SelectOption[],
110
+ value: unknown,
111
+ defaultValue: unknown,
112
+ ): [SelectOption | null, (next: SelectOption) => void] {
113
+ const [own, setOwn] = React.useState<unknown>(defaultValue ?? '');
114
+ const current = value === undefined ? own : value;
115
+ const match = options.find((option) => String(option.value) === String(current ?? '')) ?? null;
116
+ const key = match === null ? null : `${String(match.value)}\u0000${match.label}\u0000${match.disabled === true}`;
117
+ // Keyed on the option's identity, not the object `find` just returned.
118
+ const stable = React.useMemo(() => match, [key]);
119
+ return [stable, (next) => setOwn(next.value)];
120
+ }
121
+
122
+ /**
123
+ * A field that does not fill its row sizes to its longest option, the way the
124
+ * menu sized to its selected text: MUI's Autocomplete input is `width: 0`, so
125
+ * without this a `fullWidth={false}` select collapsed to its arrow.
126
+ */
127
+ function intrinsicWidth(
128
+ theme: Theme,
129
+ options: SelectOption[],
130
+ fullWidth: boolean,
131
+ ): React.CSSProperties | undefined {
132
+ if (fullWidth) return undefined;
133
+ const longest = options.reduce((max, option) => Math.max(max, option.label.length), 0);
134
+ // The label in `ch`, plus the field's inline padding and the arrow's slot.
135
+ return { minWidth: `calc(${longest}ch + ${rem(theme, SELECT_SEARCH.fieldChrome)})` };
136
+ }
137
+
138
+ export const SearchableSelect = React.forwardRef<HTMLDivElement, SelectProps>((props, ref) => {
139
+ const { variant, options, fullWidth = true, size, error, glow, pulse, value, defaultValue } = props;
140
+ const { onChange, disabled, name, noOptionsText, sx, className, style, id } = props;
141
+ const { testId: dataTestId } = splitTestId(props as unknown as Record<string, unknown>);
142
+ const [selected, setOwn] = useSelectedOption(options, value, defaultValue);
143
+ const theme = useTheme();
144
+ const optionTestId = (optionValue: SelectOption['value']): string =>
145
+ dataTestId ? `${dataTestId}-option-${optionValue}` : `option-${optionValue}`;
146
+
147
+ return (
148
+ <SelectFieldControl
149
+ fullWidth={fullWidth}
150
+ size={formControlSize(size)}
151
+ error={error}
152
+ customVariant={variant}
153
+ fieldSize={asFieldSize(size)}
154
+ glow={glow}
155
+ pulse={pulse}
156
+ ref={ref}
157
+ sx={sx}
158
+ className={className}
159
+ style={{ ...intrinsicWidth(theme, options, fullWidth), ...style }}
160
+ data-testid={dataTestId}
161
+ >
162
+ <Autocomplete<SelectOption, false, true, false>
163
+ id={id}
164
+ value={selected as SelectOption}
165
+ options={options}
166
+ disabled={disabled}
167
+ disableClearable
168
+ autoHighlight
169
+ handleHomeEndKeys
170
+ size={formControlSize(size)}
171
+ noOptionsText={noOptionsText ?? null}
172
+ getOptionLabel={(option) => option.label}
173
+ // Two people may share a name; the value is what tells them apart.
174
+ getOptionKey={(option) => String(option.value)}
175
+ getOptionDisabled={(option) => option.disabled === true}
176
+ isOptionEqualToValue={(option, current) => String(option.value) === String(current.value)}
177
+ onChange={(_event, next) => {
178
+ setOwn(next);
179
+ onChange?.(selectChange(next.value, name), null);
180
+ }}
181
+ renderOption={(optionProps, option) => renderOption(optionProps, option, optionTestId)}
182
+ slotProps={{
183
+ // Above stacked sheets and dialogs, as `CreatableSelect` does.
184
+ popper: { sx: { zIndex: stackedOverlayZIndex } },
185
+ // THE bounded height: MUI's own default is 40vh, which on a tall
186
+ // screen is the whole page again.
187
+ listbox: { sx: (theme) => ({ maxHeight: rem(theme, SELECT_SEARCH.listMaxHeight) }) },
188
+ }}
189
+ renderInput={(params) =>
190
+ renderField({
191
+ params,
192
+ field: props,
193
+ ariaLabel: props['aria-label'],
194
+ disabled,
195
+ triggerTestId: dataTestId ? `${dataTestId}-select` : 'select',
196
+ })
197
+ }
198
+ />
199
+ </SelectFieldControl>
200
+ );
201
+ });
202
+
203
+ SearchableSelect.displayName = 'SearchableSelect';
@@ -0,0 +1,195 @@
1
+ import FormControl, { type FormControlProps } from '@mui/material/FormControl/index.js';
2
+ import { alpha, type CSSObject, keyframes, styled, type Theme } from '@mui/material/styles/index.js';
3
+ import React from 'react';
4
+
5
+ import {
6
+ SELECT_BORDER,
7
+ SELECT_GLASS,
8
+ SELECT_GLOW,
9
+ SELECT_GRADIENT,
10
+ SELECT_PULSE,
11
+ selectInputSize,
12
+ } from './Select.metrics';
13
+ import type { SelectProps } from './Select.types';
14
+
15
+ import { fieldEdge } from '../../../tokens/field-edge';
16
+ import { FIELD_BORDER_WIDTH, fieldControlStyles, fieldHeight } from '../../../tokens/field-height';
17
+ import type { SizeValue } from '../../../tokens/vocabulary';
18
+ import { fieldRadius } from '../../../tokens/field-radius';
19
+ import { absoluteInk } from '../../../tokens/ink';
20
+ import { rem } from '../../../tokens/relative';
21
+
22
+ /**
23
+ * THE FIELD CHROME BOTH WEB SELECTS WEAR — the menu `Select` and the searchable
24
+ * one it becomes past {@link SEARCHABLE_MIN_OPTIONS} options. Shared so the two
25
+ * cannot drift: a form whose short select and long select were drawn by two
26
+ * copies of these rules would show it the first time one of them changed.
27
+ */
28
+
29
+ // Define pulse animation
30
+ const pulseAnimation = (theme: Theme) => keyframes`
31
+ 0% {
32
+ box-shadow: 0 0 0 0 currentColor;
33
+ opacity: 1;
34
+ }
35
+ 70% {
36
+ box-shadow: 0 0 0 ${rem(theme, SELECT_PULSE.spread)} currentColor;
37
+ opacity: 0;
38
+ }
39
+ 100% {
40
+ box-shadow: 0 0 0 0 currentColor;
41
+ opacity: 0;
42
+ }
43
+ `;
44
+
45
+ /** Glow ring on the outlined input, keyed off the `glow` prop. */
46
+ const glowStyles = (theme: Theme): CSSObject => ({
47
+ '& .MuiOutlinedInput-root': {
48
+ boxShadow: `0 0 ${rem(theme, SELECT_GLOW.rest.blur)} ${alpha(theme.palette.primary.main, SELECT_GLOW.rest.alpha)}`,
49
+ '&.Mui-focused': {
50
+ boxShadow: `0 0 ${rem(theme, SELECT_GLOW.focused.blur)} ${alpha(theme.palette.primary.main, SELECT_GLOW.focused.alpha)}`,
51
+ },
52
+ },
53
+ });
54
+
55
+ /** Pulsing halo behind the control, keyed off the `pulse` prop. */
56
+ const pulseStyles = (theme: Theme, size: SizeValue): CSSObject => ({
57
+ '&::after': {
58
+ content: '""',
59
+ position: 'absolute',
60
+ top: '50%',
61
+ left: '0',
62
+ right: '0',
63
+ height: fieldHeight(theme, size),
64
+ transform: 'translateY(-50%)',
65
+ borderRadius: fieldRadius(theme),
66
+ backgroundColor: theme.palette.primary.main,
67
+ opacity: SELECT_PULSE.opacity,
68
+ animation: `${pulseAnimation(theme)} ${SELECT_PULSE.ms / 1000}s infinite`,
69
+ pointerEvents: 'none',
70
+ zIndex: -1,
71
+ },
72
+ });
73
+
74
+ /** `glass` variant: translucent, blurred background. */
75
+ const glassVariant = (theme: Theme): CSSObject => ({
76
+ backgroundColor: alpha(theme.palette.background.paper, SELECT_GLASS.background.rest),
77
+ backdropFilter: `blur(${rem(theme, SELECT_GLASS.blur)})`,
78
+ // `SELECT_BORDER.rest` is the field hairline.
79
+ border: `${FIELD_BORDER_WIDTH}px solid ${fieldEdge(theme)}`,
80
+ '& fieldset': { border: 'none' },
81
+ '&:hover': {
82
+ backgroundColor: alpha(theme.palette.background.paper, SELECT_GLASS.background.hover),
83
+ borderColor: alpha(theme.palette.primary.main, SELECT_GLASS.hoverBorderAlpha),
84
+ },
85
+ '&.Mui-focused': {
86
+ backgroundColor: alpha(theme.palette.background.paper, SELECT_GLASS.background.focused),
87
+ borderColor: theme.palette.primary.main,
88
+ boxShadow: `0 0 0 ${rem(theme, SELECT_GLASS.focusRing.width)} ${alpha(theme.palette.primary.main, SELECT_GLASS.focusRing.alpha)}`,
89
+ },
90
+ });
91
+
92
+ /** `gradient` variant: gradient fill with a masked gradient border. */
93
+ const gradientFill = (theme: Theme, strength: number): string =>
94
+ `linear-gradient(${SELECT_GRADIENT.angleDeg}deg, ${alpha(theme.palette.primary.main, strength)}, ${alpha(theme.palette.secondary.main, strength)})`;
95
+
96
+ const gradientVariant = (theme: Theme): CSSObject => ({
97
+ background: gradientFill(theme, SELECT_GRADIENT.fill.rest),
98
+ border: `${rem(theme, SELECT_GRADIENT.borderWidth)} solid transparent`,
99
+ backgroundOrigin: 'border-box',
100
+ backgroundClip: 'padding-box, border-box',
101
+ position: 'relative',
102
+ '& fieldset': { border: 'none' },
103
+ '&::before': {
104
+ content: '""',
105
+ position: 'absolute',
106
+ top: 0,
107
+ left: 0,
108
+ right: 0,
109
+ bottom: 0,
110
+ borderRadius: 'inherit',
111
+ background: `linear-gradient(${SELECT_GRADIENT.angleDeg}deg, ${theme.palette.primary.main}, ${theme.palette.secondary.main})`,
112
+ mask: `linear-gradient(${absoluteInk(theme).white} 0 0) content-box, linear-gradient(${absoluteInk(theme).white} 0 0)`,
113
+ maskComposite: 'exclude',
114
+ padding: rem(theme, SELECT_GRADIENT.borderWidth),
115
+ zIndex: -1,
116
+ },
117
+ '&:hover': {
118
+ background: gradientFill(theme, SELECT_GRADIENT.fill.hover),
119
+ },
120
+ '&.Mui-focused': {
121
+ background: gradientFill(theme, SELECT_GRADIENT.fill.focused),
122
+ '&::before': {
123
+ background: `linear-gradient(${SELECT_GRADIENT.angleDeg}deg, ${theme.palette.primary.dark}, ${theme.palette.secondary.dark})`,
124
+ },
125
+ },
126
+ });
127
+
128
+ /** `default` variant: standard outlined borders with hover/focus/error states. */
129
+ const defaultVariant = (theme: Theme): CSSObject => ({
130
+ '& fieldset': { borderColor: fieldEdge(theme) },
131
+ '&:hover fieldset': { borderColor: theme.palette.primary.main },
132
+ '&.Mui-focused fieldset': { borderColor: theme.palette.primary.main, borderWidth: rem(theme, SELECT_BORDER.focused) },
133
+ '&.Mui-error fieldset': { borderColor: theme.palette.error.main },
134
+ });
135
+
136
+ /** Pick the variant style block for the outlined input. */
137
+ const variantStyles = (theme: Theme, variant: SelectProps['variant']): CSSObject => {
138
+ if (variant === 'glass') return glassVariant(theme);
139
+ if (variant === 'gradient') return gradientVariant(theme);
140
+ return defaultVariant(theme);
141
+ };
142
+
143
+ const StyledFormControl = styled(FormControl, {
144
+ shouldForwardProp: (prop) =>
145
+ prop !== 'customVariant' && prop !== 'fieldSize' && prop !== 'glow' && prop !== 'pulse',
146
+ })<{
147
+ customVariant?: SelectProps['variant'];
148
+ fieldSize: SizeValue;
149
+ glow?: boolean;
150
+ pulse?: boolean;
151
+ }>(({ theme, customVariant, fieldSize, glow, pulse }) => ({
152
+ position: 'relative',
153
+ // The theme's field height for this size — the height `Input` draws for it.
154
+ ...fieldControlStyles(theme, fieldSize),
155
+ ...(glow ? glowStyles(theme) : {}),
156
+ ...(pulse ? pulseStyles(theme, fieldSize) : {}),
157
+ '& .MuiOutlinedInput-root': {
158
+ transition: 'all 0.3s ease',
159
+ borderRadius: fieldRadius(theme),
160
+ ...variantStyles(theme, customVariant),
161
+ },
162
+ }));
163
+
164
+ /** What {@link SelectFieldControl} takes: a FormControl, plus the four look switches. */
165
+ export interface SelectFieldControlProps extends FormControlProps {
166
+ customVariant?: SelectProps['variant'];
167
+ fieldSize: SizeValue;
168
+ glow?: boolean;
169
+ pulse?: boolean;
170
+ 'data-testid'?: string;
171
+ }
172
+
173
+ /**
174
+ * The styled FormControl, behind a component with a NAMED type: a `styled()`
175
+ * export's inferred type reaches into `@mui/system`'s pnpm path, which the
176
+ * declaration build refuses to write (TS2742).
177
+ */
178
+ export const SelectFieldControl = React.forwardRef<HTMLDivElement, SelectFieldControlProps>(
179
+ (props, ref) => <StyledFormControl ref={ref} {...props} />,
180
+ );
181
+
182
+ SelectFieldControl.displayName = 'SelectFieldControl';
183
+
184
+ /**
185
+ * The house scale as a FormControl size.
186
+ *
187
+ * Not `muiSize`: that collapses five onto MUI's three, and a FormControl takes
188
+ * only two. This component's scale is already narrowed to `sm | md`, so the map
189
+ * is exact rather than lossy.
190
+ */
191
+ export const formControlSize = (size: SelectProps['size']): 'small' | 'medium' | undefined => {
192
+ if (size === undefined) return undefined;
193
+ return selectInputSize(size) === 'sm' ? 'small' : 'medium';
194
+ };
195
+
@@ -1,163 +1,15 @@
1
- import FormControl from '@mui/material/FormControl/index.js';
2
1
  import FormHelperText from '@mui/material/FormHelperText/index.js';
3
2
  import InputLabel from '@mui/material/InputLabel/index.js';
4
3
  import MenuItem from '@mui/material/MenuItem/index.js';
5
4
  import MuiSelect from '@mui/material/Select/index.js';
6
- import { alpha, type CSSObject, keyframes, styled, type Theme } from '@mui/material/styles/index.js';
7
5
  import React from 'react';
8
6
 
9
- import {
10
- SELECT_BORDER,
11
- SELECT_GLASS,
12
- SELECT_GLOW,
13
- SELECT_GRADIENT,
14
- SELECT_PULSE,
15
- selectInputSize,
16
- } from './Select.metrics';
7
+ import { SearchableSelect, shouldSearch } from './Select.searchable';
8
+ import { formControlSize, SelectFieldControl } from './Select.styles';
17
9
  import type { SelectProps } from './Select.types';
18
10
 
19
11
  import { splitTestId } from '../../../platform/test-id';
20
- import { fieldEdge } from '../../../tokens/field-edge';
21
- import { asFieldSize, FIELD_BORDER_WIDTH, fieldControlStyles, fieldHeight } from '../../../tokens/field-height';
22
- import type { SizeValue } from '../../../tokens/vocabulary';
23
- import { fieldRadius } from '../../../tokens/field-radius';
24
- import { absoluteInk } from '../../../tokens/ink';
25
- import { rem } from '../../../tokens/relative';
26
-
27
- // Define pulse animation
28
- const pulseAnimation = (theme: Theme) => keyframes`
29
- 0% {
30
- box-shadow: 0 0 0 0 currentColor;
31
- opacity: 1;
32
- }
33
- 70% {
34
- box-shadow: 0 0 0 ${rem(theme, SELECT_PULSE.spread)} currentColor;
35
- opacity: 0;
36
- }
37
- 100% {
38
- box-shadow: 0 0 0 0 currentColor;
39
- opacity: 0;
40
- }
41
- `;
42
-
43
- /** Glow ring on the outlined input, keyed off the `glow` prop. */
44
- const glowStyles = (theme: Theme): CSSObject => ({
45
- '& .MuiOutlinedInput-root': {
46
- boxShadow: `0 0 ${rem(theme, SELECT_GLOW.rest.blur)} ${alpha(theme.palette.primary.main, SELECT_GLOW.rest.alpha)}`,
47
- '&.Mui-focused': {
48
- boxShadow: `0 0 ${rem(theme, SELECT_GLOW.focused.blur)} ${alpha(theme.palette.primary.main, SELECT_GLOW.focused.alpha)}`,
49
- },
50
- },
51
- });
52
-
53
- /** Pulsing halo behind the control, keyed off the `pulse` prop. */
54
- const pulseStyles = (theme: Theme, size: SizeValue): CSSObject => ({
55
- '&::after': {
56
- content: '""',
57
- position: 'absolute',
58
- top: '50%',
59
- left: '0',
60
- right: '0',
61
- height: fieldHeight(theme, size),
62
- transform: 'translateY(-50%)',
63
- borderRadius: fieldRadius(theme),
64
- backgroundColor: theme.palette.primary.main,
65
- opacity: SELECT_PULSE.opacity,
66
- animation: `${pulseAnimation(theme)} ${SELECT_PULSE.ms / 1000}s infinite`,
67
- pointerEvents: 'none',
68
- zIndex: -1,
69
- },
70
- });
71
-
72
- /** `glass` variant: translucent, blurred background. */
73
- const glassVariant = (theme: Theme): CSSObject => ({
74
- backgroundColor: alpha(theme.palette.background.paper, SELECT_GLASS.background.rest),
75
- backdropFilter: `blur(${rem(theme, SELECT_GLASS.blur)})`,
76
- // `SELECT_BORDER.rest` is the field hairline.
77
- border: `${FIELD_BORDER_WIDTH}px solid ${fieldEdge(theme)}`,
78
- '& fieldset': { border: 'none' },
79
- '&:hover': {
80
- backgroundColor: alpha(theme.palette.background.paper, SELECT_GLASS.background.hover),
81
- borderColor: alpha(theme.palette.primary.main, SELECT_GLASS.hoverBorderAlpha),
82
- },
83
- '&.Mui-focused': {
84
- backgroundColor: alpha(theme.palette.background.paper, SELECT_GLASS.background.focused),
85
- borderColor: theme.palette.primary.main,
86
- boxShadow: `0 0 0 ${rem(theme, SELECT_GLASS.focusRing.width)} ${alpha(theme.palette.primary.main, SELECT_GLASS.focusRing.alpha)}`,
87
- },
88
- });
89
-
90
- /** `gradient` variant: gradient fill with a masked gradient border. */
91
- const gradientFill = (theme: Theme, strength: number): string =>
92
- `linear-gradient(${SELECT_GRADIENT.angleDeg}deg, ${alpha(theme.palette.primary.main, strength)}, ${alpha(theme.palette.secondary.main, strength)})`;
93
-
94
- const gradientVariant = (theme: Theme): CSSObject => ({
95
- background: gradientFill(theme, SELECT_GRADIENT.fill.rest),
96
- border: `${rem(theme, SELECT_GRADIENT.borderWidth)} solid transparent`,
97
- backgroundOrigin: 'border-box',
98
- backgroundClip: 'padding-box, border-box',
99
- position: 'relative',
100
- '& fieldset': { border: 'none' },
101
- '&::before': {
102
- content: '""',
103
- position: 'absolute',
104
- top: 0,
105
- left: 0,
106
- right: 0,
107
- bottom: 0,
108
- borderRadius: 'inherit',
109
- background: `linear-gradient(${SELECT_GRADIENT.angleDeg}deg, ${theme.palette.primary.main}, ${theme.palette.secondary.main})`,
110
- mask: `linear-gradient(${absoluteInk(theme).white} 0 0) content-box, linear-gradient(${absoluteInk(theme).white} 0 0)`,
111
- maskComposite: 'exclude',
112
- padding: rem(theme, SELECT_GRADIENT.borderWidth),
113
- zIndex: -1,
114
- },
115
- '&:hover': {
116
- background: gradientFill(theme, SELECT_GRADIENT.fill.hover),
117
- },
118
- '&.Mui-focused': {
119
- background: gradientFill(theme, SELECT_GRADIENT.fill.focused),
120
- '&::before': {
121
- background: `linear-gradient(${SELECT_GRADIENT.angleDeg}deg, ${theme.palette.primary.dark}, ${theme.palette.secondary.dark})`,
122
- },
123
- },
124
- });
125
-
126
- /** `default` variant: standard outlined borders with hover/focus/error states. */
127
- const defaultVariant = (theme: Theme): CSSObject => ({
128
- '& fieldset': { borderColor: fieldEdge(theme) },
129
- '&:hover fieldset': { borderColor: theme.palette.primary.main },
130
- '&.Mui-focused fieldset': { borderColor: theme.palette.primary.main, borderWidth: rem(theme, SELECT_BORDER.focused) },
131
- '&.Mui-error fieldset': { borderColor: theme.palette.error.main },
132
- });
133
-
134
- /** Pick the variant style block for the outlined input. */
135
- const variantStyles = (theme: Theme, variant: SelectProps['variant']): CSSObject => {
136
- if (variant === 'glass') return glassVariant(theme);
137
- if (variant === 'gradient') return gradientVariant(theme);
138
- return defaultVariant(theme);
139
- };
140
-
141
- const StyledFormControl = styled(FormControl, {
142
- shouldForwardProp: (prop) =>
143
- prop !== 'customVariant' && prop !== 'fieldSize' && prop !== 'glow' && prop !== 'pulse',
144
- })<{
145
- customVariant?: SelectProps['variant'];
146
- fieldSize: SizeValue;
147
- glow?: boolean;
148
- pulse?: boolean;
149
- }>(({ theme, customVariant, fieldSize, glow, pulse }) => ({
150
- position: 'relative',
151
- // The theme's field height for this size — the height `Input` draws for it.
152
- ...fieldControlStyles(theme, fieldSize),
153
- ...(glow ? glowStyles(theme) : {}),
154
- ...(pulse ? pulseStyles(theme, fieldSize) : {}),
155
- '& .MuiOutlinedInput-root': {
156
- transition: 'all 0.3s ease',
157
- borderRadius: fieldRadius(theme),
158
- ...variantStyles(theme, customVariant),
159
- },
160
- }));
12
+ import { asFieldSize } from '../../../tokens/field-height';
161
13
 
162
14
  /**
163
15
  * Build the placeholder item plus one MenuItem per option. Returns a flat ARRAY
@@ -191,19 +43,7 @@ function renderMenuItems(
191
43
  return items;
192
44
  }
193
45
 
194
- /**
195
- * The house scale as a FormControl size.
196
- *
197
- * Not `muiSize`: that collapses five onto MUI's three, and a FormControl takes
198
- * only two. This component's scale is already narrowed to `sm | md`, so the map
199
- * is exact rather than lossy.
200
- */
201
- const formControlSize = (size: SelectProps['size']): 'small' | 'medium' | undefined => {
202
- if (size === undefined) return undefined;
203
- return selectInputSize(size) === 'sm' ? 'small' : 'medium';
204
- };
205
-
206
- export const Select = React.forwardRef<HTMLDivElement, SelectProps>(
46
+ const MenuSelect = React.forwardRef<HTMLDivElement, SelectProps>(
207
47
  (
208
48
  {
209
49
  // `variant`/`size`/`glow`/`pulse` intentionally have no defaults: undefined
@@ -231,7 +71,7 @@ export const Select = React.forwardRef<HTMLDivElement, SelectProps>(
231
71
  const selectId = React.useId();
232
72
 
233
73
  return (
234
- <StyledFormControl
74
+ <SelectFieldControl
235
75
  fullWidth={fullWidth}
236
76
  size={formControlSize(size)}
237
77
  error={error}
@@ -281,9 +121,23 @@ export const Select = React.forwardRef<HTMLDivElement, SelectProps>(
281
121
  {helperText}
282
122
  </FormHelperText>
283
123
  )}
284
- </StyledFormControl>
124
+ </SelectFieldControl>
285
125
  );
286
126
  },
287
127
  );
288
128
 
129
+ MenuSelect.displayName = 'MenuSelect';
130
+
131
+ /**
132
+ * The house select. Up to five options it opens a menu; from six on it is a
133
+ * search box over a list of bounded height (`Select.searchable.tsx`), with the
134
+ * same props, events and test ids either way. `searchable` overrides the count.
135
+ */
136
+ export const Select = React.forwardRef<HTMLDivElement, SelectProps>((props, ref) => {
137
+ if (shouldSearch(props)) return <SearchableSelect {...props} ref={ref} />;
138
+ // The searchable path's own props: nothing for MUI's Select to receive.
139
+ const { searchable: _searchable, noOptionsText: _noOptionsText, ...menuProps } = props;
140
+ return <MenuSelect {...menuProps} ref={ref} />;
141
+ });
142
+
289
143
  Select.displayName = 'Select';
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/feedback/StackedModal/StackedModal.tsx"],"sourcesContent":["import Dialog from '@mui/material/Dialog/index.js';\nimport Slide from '@mui/material/Slide/index.js';\nimport { styled } from '@mui/material/styles/index.js';\nimport type { TransitionProps } from '@mui/material/transitions/index.js';\nimport type { FC } from 'react';\nimport React, { forwardRef, useId } from 'react';\nimport { usePanelChrome } from './StackedModal.hooks';\nimport { modalAriaIds, ModalPanelContents, resolveModalContent } from './StackedModal.parts';\nimport type { PanelStyleProps } from './StackedModal.styles';\nimport { dialogRootStyles, STYLE_ONLY_PROPS } from './StackedModal.styles';\nimport type { StackedModalProps } from './StackedModal.types';\n\nconst StyledDialog = styled(Dialog, {\n shouldForwardProp: (prop) => !STYLE_ONLY_PROPS.includes(prop as string),\n})<PanelStyleProps>(({ theme, ...props }) => dialogRootStyles(theme, props));\n\n/** Panels slide in from the right on every device. */\nconst SlideTransition = forwardRef<HTMLDivElement, TransitionProps>(\n function SlideTransition(props, ref) {\n return (\n <Slide direction=\"left\" ref={ref} {...props}>\n {props.children as React.ReactElement}\n </Slide>\n );\n },\n);\n\nconst DEFAULTS: Partial<StackedModalProps> = {\n open: false,\n glass: false,\n navigationTitle: '',\n closeOnClickOutside: true,\n closeOnEsc: true,\n loading: false,\n loadingText: 'Loading...',\n maxWidth: false,\n disableBackdrop: false,\n disableFocusTrap: false,\n keepMounted: false,\n rtl: false,\n};\n\n/**\n * Fills in the defaults for props the caller left `undefined`. A table plus one\n * loop, rather than a default per destructured prop — each of those is a branch,\n * and fifteen of them put the component over the complexity bar on their own.\n */\nconst withDefaults = (props: StackedModalProps): StackedModalProps => {\n const resolved = { ...props };\n for (const [key, value] of Object.entries(DEFAULTS)) {\n const prop = key as keyof StackedModalProps;\n if (resolved[prop] === undefined) {\n Object.assign(resolved, { [prop]: value });\n }\n }\n return resolved;\n};\n\n/** The modal's props once defaults are applied and its stack identity is settled. */\ntype ResolvedProps = StackedModalProps & { modalId: string };\n\nconst StackedModalPanel: FC<ResolvedProps> = (props) => {\n const {\n open, onClose, glass, navigationTitle, backLabel, hideClose, children, actions, modalId,\n closeOnClickOutside, closeOnEsc, loading, loadingText, fullScreen, maxWidth, disableBackdrop,\n disableFocusTrap, keepMounted, rtl, dataTestId,\n 'aria-labelledby': ariaLabelledBy, 'aria-describedby': ariaDescribedBy, ...otherProps\n } = props;\n\n const {\n dialogRef, modalRole, isAnimating, showSkeleton, zIndex, isMobile, canGoBack,\n handleBack, handleClose,\n } = usePanelChrome({\n open, modalId, loading, closeOnEsc, closeOnClickOutside, disableFocusTrap, onClose,\n });\n\n // Don't render if in background (performance optimization)\n if (modalRole === 'background' && !keepMounted) return null;\n\n const { content, modalActions, headerActions, hasMobileActions } = resolveModalContent(\n children,\n actions,\n isMobile,\n );\n const { titleId, descId } = modalAriaIds(modalId, ariaLabelledBy, ariaDescribedBy);\n\n return (\n <StyledDialog\n ref={dialogRef}\n open={Boolean(open)}\n onClose={handleClose}\n fullScreen={fullScreen ?? isMobile}\n modalRole={modalRole}\n isAnimating={isAnimating}\n glass={glass}\n rtl={rtl}\n customMaxWidth={maxWidth}\n TransitionComponent={SlideTransition}\n maxWidth={maxWidth}\n disableEscapeKeyDown={!closeOnEsc}\n hideBackdrop={disableBackdrop}\n keepMounted={keepMounted}\n aria-labelledby={titleId}\n aria-describedby={descId}\n data-testid={dataTestId}\n sx={{ zIndex }}\n {...otherProps}\n >\n <ModalPanelContents\n backLabel={backLabel}\n showSkeleton={showSkeleton}\n loadingText={loadingText}\n titleId={titleId}\n descId={descId}\n navigationTitle={navigationTitle}\n hideClose={hideClose}\n canGoBack={canGoBack}\n onBack={handleBack}\n onClose={onClose}\n headerActions={headerActions}\n content={content}\n modalActions={modalActions}\n hasMobileActions={hasMobileActions}\n rtl={rtl}\n dataTestId={dataTestId}\n />\n </StyledDialog>\n );\n};\n\nexport const StackedModal: FC<StackedModalProps> = (props) => {\n // A modal with no caller-supplied id still needs a STABLE one — it keys this\n // panel's entry in the stack, so a value that changed per render (as a\n // `Math.random()` default does) would re-register it on every pass.\n const fallbackId = useId();\n const resolved = withDefaults(props);\n return <StackedModalPanel {...resolved} modalId={resolved.modalId ?? fallbackId} />;\n};\n\n// Re-exported so `./StackedModal` stays the single public entry point for the\n// component and its stack primitives, as the barrel and existing imports expect.\nexport {\n ModalStackProvider,\n ModalStackProvider as StackedModalProvider,\n useModalStack,\n useModalStack as useStackedModal,\n} from './modal-stack';\nexport { StackedModalActions, StackedModalContent } from './StackedModal.parts';\n"],"mappings":";;;;;;;;;;;;;;AAAA,OAAO,YAAY;AACnB,OAAO,WAAW;AAClB,SAAS,cAAc;AAGvB,SAAgB,YAAY,aAAa;AAenC;AARN,IAAM,eAAe,OAAO,QAAQ;AAAA,EAClC,mBAAmB,CAAC,SAAS,CAAC,iBAAiB,SAAS,IAAc;AACxE,CAAC,EAAmB,CAAC,EAAE,OAAO,GAAG,MAAM,MAAM,iBAAiB,OAAO,KAAK,CAAC;AAG3E,IAAM,kBAAkB;AAAA,EACtB,SAASA,iBAAgB,OAAO,KAAK;AACnC,WACE,oBAAC,SAAM,WAAU,QAAO,KAAW,GAAG,OACnC,gBAAM,UACT;AAAA,EAEJ;AACF;AAEA,IAAM,WAAuC;AAAA,EAC3C,MAAM;AAAA,EACN,OAAO;AAAA,EACP,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,aAAa;AAAA,EACb,UAAU;AAAA,EACV,iBAAiB;AAAA,EACjB,kBAAkB;AAAA,EAClB,aAAa;AAAA,EACb,KAAK;AACP;AAOA,IAAM,eAAe,CAAC,UAAgD;AACpE,QAAM,WAAW,EAAE,GAAG,MAAM;AAC5B,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,GAAG;AACnD,UAAM,OAAO;AACb,QAAI,SAAS,IAAI,MAAM,QAAW;AAChC,aAAO,OAAO,UAAU,EAAE,CAAC,IAAI,GAAG,MAAM,CAAC;AAAA,IAC3C;AAAA,EACF;AACA,SAAO;AACT;AAKA,IAAM,oBAAuC,CAAC,UAAU;AACtD,QAAM;AAAA,IACJ;AAAA,IAAM;AAAA,IAAS;AAAA,IAAO;AAAA,IAAiB;AAAA,IAAW;AAAA,IAAW;AAAA,IAAU;AAAA,IAAS;AAAA,IAChF;AAAA,IAAqB;AAAA,IAAY;AAAA,IAAS;AAAA,IAAa;AAAA,IAAY;AAAA,IAAU;AAAA,IAC7E;AAAA,IAAkB;AAAA,IAAa;AAAA,IAAK;AAAA,IACpC,mBAAmB;AAAA,IAAgB,oBAAoB;AAAA,IAAiB,GAAG;AAAA,EAC7E,IAAI;AAEJ,QAAM;AAAA,IACJ;AAAA,IAAW;AAAA,IAAW;AAAA,IAAa;AAAA,IAAc;AAAA,IAAQ;AAAA,IAAU;AAAA,IACnE;AAAA,IAAY;AAAA,EACd,IAAI,eAAe;AAAA,IACjB;AAAA,IAAM;AAAA,IAAS;AAAA,IAAS;AAAA,IAAY;AAAA,IAAqB;AAAA,IAAkB;AAAA,EAC7E,CAAC;AAGD,MAAI,cAAc,gBAAgB,CAAC,YAAa,QAAO;AAEvD,QAAM,EAAE,SAAS,cAAc,eAAe,iBAAiB,IAAI;AAAA,IACjE;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,EAAE,SAAS,OAAO,IAAI,aAAa,SAAS,gBAAgB,eAAe;AAEjF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,MAAM,QAAQ,IAAI;AAAA,MAClB,SAAS;AAAA,MACT,YAAY,cAAc;AAAA,MAC1B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,gBAAgB;AAAA,MAChB,qBAAqB;AAAA,MACrB;AAAA,MACA,sBAAsB,CAAC;AAAA,MACvB,cAAc;AAAA,MACd;AAAA,MACA,mBAAiB;AAAA,MACjB,oBAAkB;AAAA,MAClB,eAAa;AAAA,MACb,IAAI,EAAE,OAAO;AAAA,MACZ,GAAG;AAAA,MAEJ;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,QAAQ;AAAA,UACR;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA,MACF;AAAA;AAAA,EACF;AAEJ;AAEO,IAAM,eAAsC,CAAC,UAAU;AAI5D,QAAM,aAAa,MAAM;AACzB,QAAM,WAAW,aAAa,KAAK;AACnC,SAAO,oBAAC,qBAAmB,GAAG,UAAU,SAAS,SAAS,WAAW,YAAY;AACnF;","names":["SlideTransition"]}