@12-apps/ui 6.46.1 → 6.47.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.
- package/components-catalog.md +1 -1
- package/dist/_internal/components/data-display/Avatar/Avatar.js +3 -3
- package/dist/_internal/components/data-display/Avatar/Avatar.view.js +2 -2
- package/dist/_internal/components/data-display/Badge/Badge.js +2 -2
- package/dist/_internal/components/data-display/CardKit/use-remove-confirm.js +1 -1
- package/dist/_internal/components/data-display/CardKit/use-row-confirm.js +1 -1
- package/dist/_internal/components/data-display/Chart/Chart.js +4 -4
- package/dist/_internal/components/data-display/Chart/SpecChart.js +7 -7
- package/dist/_internal/components/data-display/Chart/chart-context.js +2 -2
- package/dist/_internal/components/data-display/Chart/chart-renderers.js +3 -3
- package/dist/_internal/components/data-display/Chart/chart-spec.js +2 -2
- package/dist/_internal/components/data-display/DataViews/DataViewsGrid.js +29 -29
- package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +38 -38
- package/dist/_internal/components/data-display/DataViews/ManageViewsDialog.js +1 -1
- package/dist/_internal/components/data-display/DataViews/SaveViewModal.js +3 -3
- package/dist/_internal/components/data-display/DataViews/base-list-card-geometry.js +4 -4
- package/dist/_internal/components/data-display/DataViews/base-list-card-slots.js +3 -3
- package/dist/_internal/components/data-display/DataViews/base-list-card.js +7 -7
- package/dist/_internal/components/data-display/DataViews/data-views-category-pill.js +9 -9
- package/dist/_internal/components/data-display/DataViews/data-views-display-panel.js +1 -1
- package/dist/_internal/components/data-display/DataViews/data-views-filter-panel.js +12 -12
- package/dist/_internal/components/data-display/DataViews/data-views-grid-bodies.js +5 -5
- package/dist/_internal/components/data-display/DataViews/data-views-grid-parts.js +26 -26
- package/dist/_internal/components/data-display/DataViews/data-views-inline-bar.js +14 -14
- package/dist/_internal/components/data-display/DataViews/data-views-more-fields.js +12 -12
- package/dist/_internal/components/data-display/DataViews/data-views-more-filters.js +13 -13
- package/dist/_internal/components/data-display/DataViews/data-views-range-pill.js +2 -2
- package/dist/_internal/components/data-display/DataViews/data-views-scope-tabs.js +2 -2
- package/dist/_internal/components/data-display/DataViews/data-views-shell-toolbar.js +2 -2
- package/dist/_internal/components/data-display/DataViews/data-views-table-parts.js +5 -5
- package/dist/_internal/components/data-display/DataViews/data-views-toolbar.js +2 -2
- package/dist/_internal/components/data-display/DataViews/list-card-rails.js +2 -2
- package/dist/_internal/components/data-display/DataViews/use-data-views-state.js +2 -2
- package/dist/_internal/components/data-display/FleetMap/FleetBody.js +11 -11
- package/dist/_internal/components/data-display/FleetMap/FleetCanvas.js +8 -8
- package/dist/_internal/components/data-display/FleetMap/FleetMap.js +12 -12
- package/dist/_internal/components/data-display/FleetMap/FleetRoster.js +2 -2
- package/dist/_internal/components/data-display/HoverCard/HoverCard.js +3 -3
- package/dist/_internal/components/data-display/Lightbox/Lightbox.js +3 -3
- package/dist/_internal/components/data-display/MapPreview/MapLayers.js +2 -2
- package/dist/_internal/components/data-display/MapPreview/MapPreview.js +7 -7
- package/dist/_internal/components/data-display/Progress/Progress.js +2 -2
- package/dist/_internal/components/data-display/Sheet/Sheet.js +4 -4
- package/dist/_internal/components/data-display/Table/Table.js +3 -3
- package/dist/_internal/components/data-display/index.js +42 -42
- package/dist/_internal/components/feedback/TutorialOverlay/TutorialOverlay.js +2 -2
- package/dist/_internal/components/feedback/index.js +5 -5
- package/dist/_internal/components/form/AddressAutocomplete/AddressAutocomplete.hooks.js +4 -4
- package/dist/_internal/components/form/AddressAutocomplete/AddressAutocomplete.js +7 -7
- package/dist/_internal/components/form/Autocomplete/Autocomplete.js +2 -2
- package/dist/_internal/components/form/Calendar/Calendar.hooks.js +2 -2
- package/dist/_internal/components/form/Calendar/Calendar.js +3 -3
- package/dist/_internal/components/form/CategorySelect/CategoryPanel.js +4 -4
- package/dist/_internal/components/form/CategorySelect/CategoryPanelList.js +3 -3
- package/dist/_internal/components/form/CategorySelect/CategoryRows.js +2 -2
- package/dist/_internal/components/form/CategorySelect/CategorySelect.js +8 -8
- package/dist/_internal/components/form/CepField/CepField.js +3 -3
- package/dist/_internal/components/form/CodeEditor/CodeEditor.js +2 -2
- package/dist/_internal/components/form/Command/Command.js +2 -2
- package/dist/_internal/components/form/DateRangePicker/DateRangePicker.js +5 -5
- package/dist/_internal/components/form/Input/Input.js +2 -2
- package/dist/_internal/components/form/NumberField/NumberField.js +3 -3
- package/dist/_internal/components/form/Select/Select.js +5 -2
- package/dist/_internal/components/form/Select/Select.metrics.js +5 -1
- package/dist/_internal/components/form/Select/Select.searchable.js +28 -0
- package/dist/_internal/components/form/Select/Select.searchable.js.map +1 -0
- package/dist/_internal/components/form/Select/Select.styles.js +25 -0
- package/dist/_internal/components/form/Select/Select.styles.js.map +1 -0
- package/dist/_internal/components/form/index.js +32 -29
- package/dist/_internal/components/form/total-form/Fields/CategoryField.js +9 -9
- package/dist/_internal/components/form/total-form/Fields/CepField.js +4 -4
- package/dist/_internal/components/form/total-form/Fields/SelectField.js +6 -3
- package/dist/_internal/components/form/total-form/Fields/TextField.js +3 -3
- package/dist/_internal/components/form/total-form/Fields/index.js +20 -18
- package/dist/_internal/components/index.js +85 -83
- package/dist/_internal/components/navigation/AppHeader/AppHeader.details.js +4 -4
- package/dist/_internal/components/navigation/SectionNav/SectionNav.bar.js +6 -6
- package/dist/_internal/components/navigation/SectionNav/SectionNav.js +8 -8
- package/dist/_internal/components/navigation/SectionNav/SectionNav.parts.js +3 -3
- package/dist/_internal/components/navigation/SectionNav/SectionNav.primary.js +4 -4
- package/dist/_internal/components/navigation/SectionNav/SectionNav.rail.js +4 -4
- package/dist/_internal/components/navigation/SectionNav/SectionNav.sheet.js +4 -4
- package/dist/_internal/components/navigation/index.js +12 -12
- package/dist/_internal/user-avatar/user-avatar.js +4 -4
- package/dist/charts.js +10 -10
- package/dist/{chunk-A64MQ7GW.js → chunk-2LSJTQIL.js} +2 -2
- package/dist/{chunk-EU76OQGR.js → chunk-2NYVMLFQ.js} +2 -2
- package/dist/{chunk-CJPP4OUK.js → chunk-2YKTB2IZ.js} +2 -2
- package/dist/{chunk-ISW5K72V.js → chunk-2ZRZTGWP.js} +5 -5
- package/dist/{chunk-LQRUTHJY.js → chunk-3CDU7DLD.js} +5 -5
- package/dist/{chunk-72FPUWD6.js → chunk-3IPQANXY.js} +2 -2
- package/dist/{chunk-56QYSVLI.js → chunk-3WAAL3KN.js} +7 -7
- package/dist/{chunk-JO4UMHWR.js → chunk-43UFSKEK.js} +3 -3
- package/dist/{chunk-N2XQKTXX.js → chunk-5NFQKL7C.js} +5 -5
- package/dist/{chunk-PCHUIDMT.js → chunk-5OEC546C.js} +2 -2
- package/dist/{chunk-JBGCGYEC.js → chunk-6EJF3BUR.js} +4 -4
- package/dist/{chunk-P3XEF26U.js → chunk-A5ODDTGU.js} +3 -3
- package/dist/{chunk-RVOYCPKF.js → chunk-ACU7LEFG.js} +5 -5
- package/dist/{chunk-OARM5RX4.js → chunk-AQC67NQZ.js} +5 -5
- package/dist/{chunk-QQUNZH3L.js → chunk-AS2PWQIU.js} +3 -3
- package/dist/chunk-AV6NNCRO.js +111 -0
- package/dist/chunk-AV6NNCRO.js.map +1 -0
- package/dist/{chunk-V54LG3QG.js → chunk-B3QWQG62.js} +2 -2
- package/dist/{chunk-J2JWWGMT.js → chunk-BPOVRMVS.js} +7 -7
- package/dist/{chunk-V4R6Q5ED.js → chunk-CGBUWNNQ.js} +11 -11
- package/dist/{chunk-ZCEXSYAJ.js → chunk-CGL7R37P.js} +4 -4
- package/dist/{chunk-GYZUJ7HH.js → chunk-CO4MSWTV.js} +5 -5
- package/dist/chunk-EISPWFYO.js +146 -0
- package/dist/chunk-EISPWFYO.js.map +1 -0
- package/dist/{chunk-PGPPN63I.js → chunk-EMEXXAQI.js} +2 -2
- package/dist/{chunk-2HPNN5XA.js → chunk-FIF4RQ4S.js} +2 -2
- package/dist/{chunk-T6HVNVFI.js → chunk-FQT4C5R4.js} +9 -9
- package/dist/{chunk-BWURMQWZ.js → chunk-FS7UVKEE.js} +4 -4
- package/dist/{chunk-LUPHXDEU.js → chunk-FVKBP3UX.js} +2 -2
- package/dist/{chunk-TPPFWETI.js → chunk-G6II7SVX.js} +7 -7
- package/dist/{chunk-LV2SZFXK.js → chunk-GMC3F43L.js} +7 -7
- package/dist/{chunk-R6SBP5M5.js → chunk-GOWBYHYW.js} +4 -4
- package/dist/{chunk-AA7QTFMB.js → chunk-HGRC635A.js} +2 -2
- package/dist/{chunk-TE3XYCX7.js → chunk-IHO2O44S.js} +5 -5
- package/dist/{chunk-VPH47OIV.js → chunk-IKZSQKOE.js} +2 -2
- package/dist/{chunk-IPI3OU2P.js → chunk-IV7G7NK3.js} +5 -5
- package/dist/{chunk-JTWRI4WD.js → chunk-IX3U3XPP.js} +14 -14
- package/dist/{chunk-WYXNFH5Y.js → chunk-IYC7NPX7.js} +14 -2
- package/dist/{chunk-WYXNFH5Y.js.map → chunk-IYC7NPX7.js.map} +1 -1
- package/dist/{chunk-HC2AO3RT.js → chunk-J44PPGBF.js} +2 -2
- package/dist/{chunk-V2GHNHP6.js → chunk-JAHWFJCW.js} +4 -4
- package/dist/{chunk-HAFLKWWU.js → chunk-JQ6HDXKA.js} +2 -2
- package/dist/{chunk-SPZAEMGW.js → chunk-JWJ77IMK.js} +4 -4
- package/dist/{chunk-HYNDC3FP.js → chunk-JYLOCXMV.js} +5 -5
- package/dist/{chunk-ILKNYENU.js → chunk-LB27LKG3.js} +4 -4
- package/dist/{chunk-IWYTOCCV.js → chunk-LHTEAPYG.js} +4 -4
- package/dist/{chunk-TPVSHO75.js → chunk-NLEO5YI4.js} +7 -7
- package/dist/{chunk-K45ML7M7.js → chunk-NU55QUMO.js} +2 -2
- package/dist/{chunk-KN3WYEH2.js → chunk-NYHZUVLC.js} +4 -4
- package/dist/{chunk-U2UT2NDH.js → chunk-OBID7SOG.js} +2 -2
- package/dist/{chunk-UUJ7J7NE.js → chunk-PP7CDKO4.js} +2 -2
- package/dist/{chunk-6L2FKTBO.js → chunk-PQS3IPMD.js} +10 -91
- package/dist/chunk-PQS3IPMD.js.map +1 -0
- package/dist/{chunk-PARTZ7XI.js → chunk-R53ZOW4B.js} +2 -2
- package/dist/{chunk-BWXPO2SE.js → chunk-S22XIXLL.js} +3 -3
- package/dist/{chunk-QL7NPQOP.js → chunk-SAJ5H5VC.js} +2 -2
- package/dist/{chunk-6GAZAJXB.js → chunk-SDKOOVEX.js} +4 -4
- package/dist/{chunk-ETCS6OBJ.js → chunk-THCDUP6Q.js} +9 -9
- package/dist/{chunk-CMFJQH6A.js → chunk-UG636FEL.js} +4 -4
- package/dist/{chunk-NFA7STJA.js → chunk-UILH4OAZ.js} +5 -5
- package/dist/{chunk-X5F4FRH7.js → chunk-VNOXUWK7.js} +4 -4
- package/dist/{chunk-MD3ND6DT.js → chunk-VU63PDWW.js} +3 -3
- package/dist/{chunk-RBLBXJR7.js → chunk-WAD5VL6B.js} +7 -7
- package/dist/{chunk-4MGFUPQT.js → chunk-WC3W36AM.js} +7 -7
- package/dist/{chunk-Z3L2EGXW.js → chunk-WDAEYLT5.js} +2 -2
- package/dist/{chunk-BEX3FLHB.js → chunk-X3C3VTYS.js} +2 -2
- package/dist/{chunk-NFTFP6WO.js → chunk-XNTDEQEB.js} +5 -5
- package/dist/{chunk-TWVRPT7J.js → chunk-XXL4PM4M.js} +2 -2
- package/dist/{chunk-6OQHZVK6.js → chunk-XXNLBO4Q.js} +3 -3
- package/dist/{chunk-TNQDSTIA.js → chunk-Y6C4MYZE.js} +7 -7
- package/dist/{chunk-NRKAJHBB.js → chunk-YRACC6BB.js} +4 -4
- package/dist/{chunk-RSQYWGMU.js → chunk-YTIUFMRM.js} +5 -5
- package/dist/{chunk-FQ637IDM.js → chunk-YXU45AVO.js} +5 -5
- package/dist/{chunk-YDU2YPQA.js → chunk-ZVJSY2OV.js} +3 -3
- package/dist/data-display/Avatar.js +3 -3
- package/dist/data-display/Badge.js +2 -2
- package/dist/data-display/CardKit.js +10 -10
- package/dist/data-display/Chart.js +10 -10
- package/dist/data-display/DataViews.js +55 -55
- package/dist/data-display/FleetMap.js +12 -12
- package/dist/data-display/HoverCard.js +3 -3
- package/dist/data-display/Lightbox.js +3 -3
- package/dist/data-display/MapPreview.js +7 -7
- package/dist/data-display/Progress.js +2 -2
- package/dist/data-display/Sheet.js +4 -4
- package/dist/data-display/Table.js +3 -3
- package/dist/feedback/ConfirmAction.js +3 -3
- package/dist/feedback/TutorialOverlay.js +2 -2
- package/dist/form/AddressAutocomplete.js +7 -7
- package/dist/form/Autocomplete.js +2 -2
- package/dist/form/Calendar.js +3 -3
- package/dist/form/CategorySelect.js +8 -8
- package/dist/form/CepField.js +3 -3
- package/dist/form/CodeEditor.js +2 -2
- package/dist/form/Command.js +2 -2
- package/dist/form/DateRangePicker.js +10 -10
- package/dist/form/Input.js +2 -2
- package/dist/form/NumberField.js +3 -3
- package/dist/form/Select.js +5 -2
- package/dist/form/total-form.js +20 -18
- package/dist/native/form/Select.js.map +1 -1
- package/dist/navigation/AppHeader.js +4 -4
- package/dist/navigation/SectionNav.js +8 -8
- package/dist/types/components/form/Select/Select.base.d.ts +15 -0
- package/dist/types/components/form/Select/Select.base.d.ts.map +1 -1
- package/dist/types/components/form/Select/Select.d.ts +5 -0
- package/dist/types/components/form/Select/Select.d.ts.map +1 -1
- package/dist/types/components/form/Select/Select.metrics.d.ts +20 -0
- package/dist/types/components/form/Select/Select.metrics.d.ts.map +1 -1
- package/dist/types/components/form/Select/Select.searchable.d.ts +23 -0
- package/dist/types/components/form/Select/Select.searchable.d.ts.map +1 -0
- package/dist/types/components/form/Select/Select.styles.d.ts +27 -0
- package/dist/types/components/form/Select/Select.styles.d.ts.map +1 -0
- package/dist/types-native/components/form/Select/Select.base.d.ts +15 -0
- package/dist/types-native/components/form/Select/Select.base.d.ts.map +1 -1
- package/dist/types-native/components/form/Select/Select.metrics.d.ts +20 -0
- package/dist/types-native/components/form/Select/Select.metrics.d.ts.map +1 -1
- package/dist/user-avatar.js +4 -4
- package/package.json +1 -1
- package/src/components/form/Select/Select.base.ts +15 -0
- package/src/components/form/Select/Select.md +31 -1
- package/src/components/form/Select/Select.metrics.ts +22 -0
- package/src/components/form/Select/Select.searchable.tsx +203 -0
- package/src/components/form/Select/Select.styles.tsx +195 -0
- package/src/components/form/Select/Select.tsx +20 -166
- package/dist/chunk-6L2FKTBO.js.map +0 -1
- /package/dist/{chunk-A64MQ7GW.js.map → chunk-2LSJTQIL.js.map} +0 -0
- /package/dist/{chunk-EU76OQGR.js.map → chunk-2NYVMLFQ.js.map} +0 -0
- /package/dist/{chunk-CJPP4OUK.js.map → chunk-2YKTB2IZ.js.map} +0 -0
- /package/dist/{chunk-ISW5K72V.js.map → chunk-2ZRZTGWP.js.map} +0 -0
- /package/dist/{chunk-LQRUTHJY.js.map → chunk-3CDU7DLD.js.map} +0 -0
- /package/dist/{chunk-72FPUWD6.js.map → chunk-3IPQANXY.js.map} +0 -0
- /package/dist/{chunk-56QYSVLI.js.map → chunk-3WAAL3KN.js.map} +0 -0
- /package/dist/{chunk-JO4UMHWR.js.map → chunk-43UFSKEK.js.map} +0 -0
- /package/dist/{chunk-N2XQKTXX.js.map → chunk-5NFQKL7C.js.map} +0 -0
- /package/dist/{chunk-PCHUIDMT.js.map → chunk-5OEC546C.js.map} +0 -0
- /package/dist/{chunk-JBGCGYEC.js.map → chunk-6EJF3BUR.js.map} +0 -0
- /package/dist/{chunk-P3XEF26U.js.map → chunk-A5ODDTGU.js.map} +0 -0
- /package/dist/{chunk-RVOYCPKF.js.map → chunk-ACU7LEFG.js.map} +0 -0
- /package/dist/{chunk-OARM5RX4.js.map → chunk-AQC67NQZ.js.map} +0 -0
- /package/dist/{chunk-QQUNZH3L.js.map → chunk-AS2PWQIU.js.map} +0 -0
- /package/dist/{chunk-V54LG3QG.js.map → chunk-B3QWQG62.js.map} +0 -0
- /package/dist/{chunk-J2JWWGMT.js.map → chunk-BPOVRMVS.js.map} +0 -0
- /package/dist/{chunk-V4R6Q5ED.js.map → chunk-CGBUWNNQ.js.map} +0 -0
- /package/dist/{chunk-ZCEXSYAJ.js.map → chunk-CGL7R37P.js.map} +0 -0
- /package/dist/{chunk-GYZUJ7HH.js.map → chunk-CO4MSWTV.js.map} +0 -0
- /package/dist/{chunk-PGPPN63I.js.map → chunk-EMEXXAQI.js.map} +0 -0
- /package/dist/{chunk-2HPNN5XA.js.map → chunk-FIF4RQ4S.js.map} +0 -0
- /package/dist/{chunk-T6HVNVFI.js.map → chunk-FQT4C5R4.js.map} +0 -0
- /package/dist/{chunk-BWURMQWZ.js.map → chunk-FS7UVKEE.js.map} +0 -0
- /package/dist/{chunk-LUPHXDEU.js.map → chunk-FVKBP3UX.js.map} +0 -0
- /package/dist/{chunk-TPPFWETI.js.map → chunk-G6II7SVX.js.map} +0 -0
- /package/dist/{chunk-LV2SZFXK.js.map → chunk-GMC3F43L.js.map} +0 -0
- /package/dist/{chunk-R6SBP5M5.js.map → chunk-GOWBYHYW.js.map} +0 -0
- /package/dist/{chunk-AA7QTFMB.js.map → chunk-HGRC635A.js.map} +0 -0
- /package/dist/{chunk-TE3XYCX7.js.map → chunk-IHO2O44S.js.map} +0 -0
- /package/dist/{chunk-VPH47OIV.js.map → chunk-IKZSQKOE.js.map} +0 -0
- /package/dist/{chunk-IPI3OU2P.js.map → chunk-IV7G7NK3.js.map} +0 -0
- /package/dist/{chunk-JTWRI4WD.js.map → chunk-IX3U3XPP.js.map} +0 -0
- /package/dist/{chunk-HC2AO3RT.js.map → chunk-J44PPGBF.js.map} +0 -0
- /package/dist/{chunk-V2GHNHP6.js.map → chunk-JAHWFJCW.js.map} +0 -0
- /package/dist/{chunk-HAFLKWWU.js.map → chunk-JQ6HDXKA.js.map} +0 -0
- /package/dist/{chunk-SPZAEMGW.js.map → chunk-JWJ77IMK.js.map} +0 -0
- /package/dist/{chunk-HYNDC3FP.js.map → chunk-JYLOCXMV.js.map} +0 -0
- /package/dist/{chunk-ILKNYENU.js.map → chunk-LB27LKG3.js.map} +0 -0
- /package/dist/{chunk-IWYTOCCV.js.map → chunk-LHTEAPYG.js.map} +0 -0
- /package/dist/{chunk-TPVSHO75.js.map → chunk-NLEO5YI4.js.map} +0 -0
- /package/dist/{chunk-K45ML7M7.js.map → chunk-NU55QUMO.js.map} +0 -0
- /package/dist/{chunk-KN3WYEH2.js.map → chunk-NYHZUVLC.js.map} +0 -0
- /package/dist/{chunk-U2UT2NDH.js.map → chunk-OBID7SOG.js.map} +0 -0
- /package/dist/{chunk-UUJ7J7NE.js.map → chunk-PP7CDKO4.js.map} +0 -0
- /package/dist/{chunk-PARTZ7XI.js.map → chunk-R53ZOW4B.js.map} +0 -0
- /package/dist/{chunk-BWXPO2SE.js.map → chunk-S22XIXLL.js.map} +0 -0
- /package/dist/{chunk-QL7NPQOP.js.map → chunk-SAJ5H5VC.js.map} +0 -0
- /package/dist/{chunk-6GAZAJXB.js.map → chunk-SDKOOVEX.js.map} +0 -0
- /package/dist/{chunk-ETCS6OBJ.js.map → chunk-THCDUP6Q.js.map} +0 -0
- /package/dist/{chunk-CMFJQH6A.js.map → chunk-UG636FEL.js.map} +0 -0
- /package/dist/{chunk-NFA7STJA.js.map → chunk-UILH4OAZ.js.map} +0 -0
- /package/dist/{chunk-X5F4FRH7.js.map → chunk-VNOXUWK7.js.map} +0 -0
- /package/dist/{chunk-MD3ND6DT.js.map → chunk-VU63PDWW.js.map} +0 -0
- /package/dist/{chunk-RBLBXJR7.js.map → chunk-WAD5VL6B.js.map} +0 -0
- /package/dist/{chunk-4MGFUPQT.js.map → chunk-WC3W36AM.js.map} +0 -0
- /package/dist/{chunk-Z3L2EGXW.js.map → chunk-WDAEYLT5.js.map} +0 -0
- /package/dist/{chunk-BEX3FLHB.js.map → chunk-X3C3VTYS.js.map} +0 -0
- /package/dist/{chunk-NFTFP6WO.js.map → chunk-XNTDEQEB.js.map} +0 -0
- /package/dist/{chunk-TWVRPT7J.js.map → chunk-XXL4PM4M.js.map} +0 -0
- /package/dist/{chunk-6OQHZVK6.js.map → chunk-XXNLBO4Q.js.map} +0 -0
- /package/dist/{chunk-TNQDSTIA.js.map → chunk-Y6C4MYZE.js.map} +0 -0
- /package/dist/{chunk-NRKAJHBB.js.map → chunk-YRACC6BB.js.map} +0 -0
- /package/dist/{chunk-RSQYWGMU.js.map → chunk-YTIUFMRM.js.map} +0 -0
- /package/dist/{chunk-FQ637IDM.js.map → chunk-YXU45AVO.js.map} +0 -0
- /package/dist/{chunk-YDU2YPQA.js.map → chunk-ZVJSY2OV.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.base.d.ts","sourceRoot":"","sources":["../../../../../src/components/form/Select/Select.base.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAE5D;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,OAAO,GAAG,UAAU,CAAC;AAE7D,2FAA2F;AAC3F,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,CAAC;AAE1C,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB;;OAEG;IACH,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"Select.base.d.ts","sourceRoot":"","sources":["../../../../../src/components/form/Select/Select.base.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAE5D;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,OAAO,GAAG,UAAU,CAAC;AAE7D,2FAA2F;AAC3F,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,CAAC;AAE1C,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB;;OAEG;IACH,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB"}
|
|
@@ -69,4 +69,24 @@ export declare const selectedWashAlpha: (theme: UiTheme) => number;
|
|
|
69
69
|
* would come to disagree about what an outlined field looks like.
|
|
70
70
|
*/
|
|
71
71
|
export { INPUT_BORDER as SELECT_BORDER, INPUT_GLASS as SELECT_GLASS, INPUT_GLOW as SELECT_GLOW, INPUT_GRADIENT as SELECT_GRADIENT, INPUT_PULSE as SELECT_PULSE, } from '../Input/Input.metrics';
|
|
72
|
+
/**
|
|
73
|
+
* WHEN A `Select` BECOMES A SEARCH BOX, AND HOW TALL ITS LIST MAY GROW.
|
|
74
|
+
*
|
|
75
|
+
* Past five options a menu stops being scannable at a glance and starts being
|
|
76
|
+
* scrolled — and MUI's menu grows to the viewport's height to show them all, so
|
|
77
|
+
* a staff picker covered the whole screen. From six options on the field turns
|
|
78
|
+
* into the searchable dropdown (`CreatableSelect`'s engine, MUI `Autocomplete`)
|
|
79
|
+
* and its list stops at {@link SELECT_SEARCH.listMaxHeight}: about six rows,
|
|
80
|
+
* the seventh cut in half so the list reads as scrollable.
|
|
81
|
+
*/
|
|
82
|
+
export declare const SEARCHABLE_MIN_OPTIONS = 6;
|
|
83
|
+
export declare const SELECT_SEARCH: {
|
|
84
|
+
/** px — six 40px rows and half of the seventh. */
|
|
85
|
+
readonly listMaxHeight: 260;
|
|
86
|
+
/**
|
|
87
|
+
* px — what a field that does not fill its row adds to its longest label:
|
|
88
|
+
* the input's inline padding and the arrow's slot.
|
|
89
|
+
*/
|
|
90
|
+
readonly fieldChrome: 72;
|
|
91
|
+
};
|
|
72
92
|
//# sourceMappingURL=Select.metrics.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.metrics.d.ts","sourceRoot":"","sources":["../../../../../src/components/form/Select/Select.metrics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAE5D;;;;;;;;;GASG;AAEH,2EAA2E;AAC3E,eAAO,MAAM,eAAe,GAAI,SAAS,aAAa,KAAG,YACX,CAAC;AAE/C;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,SAAS,GAAG,SAAS,KAAG,IAAI,GAAG,IACxC,CAAC;AAE9B;;;;GAIG;AACH,eAAO,MAAM,WAAW;;;;;CAKd,CAAC;AAEX,uEAAuE;AACvE,eAAO,MAAM,eAAe,QAC4C,CAAC;AAEzE,2EAA2E;AAC3E,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAE5C;;;;;;GAMG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;IAOtB,8DAA8D;;CAEtD,CAAC;AAEX,uEAAuE;AACvE,eAAO,MAAM,eAAe,wGAAuB,CAAC;AAEpD,4DAA4D;AAC5D,eAAO,MAAM,iBAAiB,GAAI,OAAO,OAAO,KAAG,MACuC,CAAC;AAE3F;;;;;GAKG;AACH,OAAO,EACL,YAAY,IAAI,aAAa,EAC7B,WAAW,IAAI,YAAY,EAC3B,UAAU,IAAI,WAAW,EACzB,cAAc,IAAI,eAAe,EACjC,WAAW,IAAI,YAAY,GAC5B,MAAM,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"Select.metrics.d.ts","sourceRoot":"","sources":["../../../../../src/components/form/Select/Select.metrics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAE5D;;;;;;;;;GASG;AAEH,2EAA2E;AAC3E,eAAO,MAAM,eAAe,GAAI,SAAS,aAAa,KAAG,YACX,CAAC;AAE/C;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,SAAS,GAAG,SAAS,KAAG,IAAI,GAAG,IACxC,CAAC;AAE9B;;;;GAIG;AACH,eAAO,MAAM,WAAW;;;;;CAKd,CAAC;AAEX,uEAAuE;AACvE,eAAO,MAAM,eAAe,QAC4C,CAAC;AAEzE,2EAA2E;AAC3E,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAE5C;;;;;;GAMG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;IAOtB,8DAA8D;;CAEtD,CAAC;AAEX,uEAAuE;AACvE,eAAO,MAAM,eAAe,wGAAuB,CAAC;AAEpD,4DAA4D;AAC5D,eAAO,MAAM,iBAAiB,GAAI,OAAO,OAAO,KAAG,MACuC,CAAC;AAE3F;;;;;GAKG;AACH,OAAO,EACL,YAAY,IAAI,aAAa,EAC7B,WAAW,IAAI,YAAY,EAC3B,UAAU,IAAI,WAAW,EACzB,cAAc,IAAI,eAAe,EACjC,WAAW,IAAI,YAAY,GAC5B,MAAM,wBAAwB,CAAC;AAEhC;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC,eAAO,MAAM,aAAa;IACxB,kDAAkD;;IAElD;;;OAGG;;CAEK,CAAC"}
|
package/dist/user-avatar.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
UserAvatar,
|
|
3
3
|
UserMenu
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-PP7CDKO4.js";
|
|
5
5
|
import "./chunk-UDQSIRAP.js";
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-EMEXXAQI.js";
|
|
7
|
+
import "./chunk-Y6C4MYZE.js";
|
|
8
|
+
import "./chunk-MTEQEPNY.js";
|
|
8
9
|
import "./chunk-6ZZGK5DT.js";
|
|
9
10
|
import "./chunk-3ZVUNSFF.js";
|
|
10
|
-
import "./chunk-MTEQEPNY.js";
|
|
11
11
|
import "./chunk-VUHLNYAE.js";
|
|
12
12
|
import "./chunk-2GSIEDGN.js";
|
|
13
13
|
import "./chunk-OP5JR5Q5.js";
|
package/package.json
CHANGED
|
@@ -75,4 +75,19 @@ export interface SelectBaseProps {
|
|
|
75
75
|
disabled?: boolean;
|
|
76
76
|
testID?: string;
|
|
77
77
|
dataTestId?: string;
|
|
78
|
+
/**
|
|
79
|
+
* Draw the field as a search box that filters the options as you type,
|
|
80
|
+
* with a list of bounded height.
|
|
81
|
+
*
|
|
82
|
+
* Left unset, it follows the option count: a list longer than
|
|
83
|
+
* five options searches (`SEARCHABLE_MIN_OPTIONS`), a shorter one opens
|
|
84
|
+
* as a plain menu. `multiple` and `renderValue` always keep the menu.
|
|
85
|
+
*/
|
|
86
|
+
searchable?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* What the searchable list says when nothing matches the typed text. The
|
|
89
|
+
* host's sentence: this library ships no copy. Unset, the empty list shows
|
|
90
|
+
* no message.
|
|
91
|
+
*/
|
|
92
|
+
noOptionsText?: string;
|
|
78
93
|
}
|
|
@@ -50,6 +50,36 @@ function MyComponent() {
|
|
|
50
50
|
- `glow`: Whether to show glow effect on hover/focus
|
|
51
51
|
- `pulse`: Whether to show pulse animation
|
|
52
52
|
- `fullWidth`: Whether select should take full width of container
|
|
53
|
+
- `searchable`: Force the search box on (`true`) or the menu on (`false`); unset, it follows the option count (see below)
|
|
54
|
+
- `noOptionsText`: The host's sentence the search box shows when nothing matches the typed text
|
|
55
|
+
|
|
56
|
+
## Six options or more: a search box
|
|
57
|
+
|
|
58
|
+
Up to **five** options the select opens a menu. From **six** on it becomes the
|
|
59
|
+
searchable dropdown — the same engine as `CreatableSelect` (MUI `Autocomplete`):
|
|
60
|
+
the field is a text box that filters the options as you type, and the list
|
|
61
|
+
stops at `SELECT_SEARCH.listMaxHeight` (about six rows) and scrolls, instead of
|
|
62
|
+
growing to the height of the viewport.
|
|
63
|
+
|
|
64
|
+
The props stay the same: `options`, `value`/`defaultValue`, `label`,
|
|
65
|
+
`placeholder`, `helperText`, `error`, `name`, `required`, disabled options,
|
|
66
|
+
variants and sizes. `onChange` still receives `{ target: { value, name } }` with
|
|
67
|
+
the option's value in its own type. The test ids keep their spelling.
|
|
68
|
+
|
|
69
|
+
**What does change — and breaks tests written against the menu:**
|
|
70
|
+
|
|
71
|
+
- `{dataTestId}-select` (and `role="combobox"`) is now the search `<input>`,
|
|
72
|
+
not the menu's display `<div>`. The selected label is its VALUE, not its
|
|
73
|
+
text: assert with `toHaveValue('Garçom')` / `input.value`, not `toHaveText`.
|
|
74
|
+
- `onChange`'s event is a plain `{ target }` object (no `preventDefault`), and
|
|
75
|
+
its second argument is `null` rather than the clicked `MenuItem`.
|
|
76
|
+
- Opening it with a click or `mouseDown` on the combobox still works; typing
|
|
77
|
+
filters only while the input has real focus.
|
|
78
|
+
|
|
79
|
+
- `searchable` overrides the count either way.
|
|
80
|
+
- `multiple` and `renderValue` always keep the menu: a search box holds one value.
|
|
81
|
+
- Pass `noOptionsText` — the library ships no copy, so unset means an empty list
|
|
82
|
+
says nothing.
|
|
53
83
|
|
|
54
84
|
## Visual Variants
|
|
55
85
|
|
|
@@ -138,7 +168,7 @@ The Select component includes `data-testid` attributes for reliable testing:
|
|
|
138
168
|
| Test ID | Element | Description |
|
|
139
169
|
|---------|---------|-------------|
|
|
140
170
|
| `{dataTestId}` | FormControl | Root FormControl wrapper element |
|
|
141
|
-
| `{dataTestId}-select` | Select element | The MUI Select component |
|
|
171
|
+
| `{dataTestId}-select` | Select element | The MUI Select component (the search `<input>` from six options on) |
|
|
142
172
|
| `{dataTestId}-option-{value}` | Menu items | Individual option elements (one per option) |
|
|
143
173
|
|
|
144
174
|
**Default Test IDs (when no dataTestId prop provided):**
|
|
@@ -88,3 +88,25 @@ export {
|
|
|
88
88
|
INPUT_GRADIENT as SELECT_GRADIENT,
|
|
89
89
|
INPUT_PULSE as SELECT_PULSE,
|
|
90
90
|
} from '../Input/Input.metrics';
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* WHEN A `Select` BECOMES A SEARCH BOX, AND HOW TALL ITS LIST MAY GROW.
|
|
94
|
+
*
|
|
95
|
+
* Past five options a menu stops being scannable at a glance and starts being
|
|
96
|
+
* scrolled — and MUI's menu grows to the viewport's height to show them all, so
|
|
97
|
+
* a staff picker covered the whole screen. From six options on the field turns
|
|
98
|
+
* into the searchable dropdown (`CreatableSelect`'s engine, MUI `Autocomplete`)
|
|
99
|
+
* and its list stops at {@link SELECT_SEARCH.listMaxHeight}: about six rows,
|
|
100
|
+
* the seventh cut in half so the list reads as scrollable.
|
|
101
|
+
*/
|
|
102
|
+
export const SEARCHABLE_MIN_OPTIONS = 6;
|
|
103
|
+
|
|
104
|
+
export const SELECT_SEARCH = {
|
|
105
|
+
/** px — six 40px rows and half of the seventh. */
|
|
106
|
+
listMaxHeight: 260,
|
|
107
|
+
/**
|
|
108
|
+
* px — what a field that does not fill its row adds to its longest label:
|
|
109
|
+
* the input's inline padding and the arrow's slot.
|
|
110
|
+
*/
|
|
111
|
+
fieldChrome: 72,
|
|
112
|
+
} as const;
|
|
@@ -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
|
+
|