@12-apps/ui 6.73.0 → 6.74.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/NATIVE.md +1 -1
- package/dist/_internal/components/data-display/AsyncStateContainer/AsyncStateContainer.js +6 -6
- package/dist/_internal/components/data-display/Avatar/Avatar.js +4 -4
- package/dist/_internal/components/data-display/Avatar/Avatar.view.js +2 -2
- package/dist/_internal/components/data-display/CardKit/use-remove-confirm.js +5 -5
- package/dist/_internal/components/data-display/CardKit/use-row-confirm.js +5 -5
- package/dist/_internal/components/data-display/Carousel/Carousel.js +2 -2
- package/dist/_internal/components/data-display/Chart/Chart.js +3 -3
- package/dist/_internal/components/data-display/Chart/SpecChart.js +6 -6
- package/dist/_internal/components/data-display/Chart/chart-renderers.js +2 -2
- package/dist/_internal/components/data-display/Chart/chart-spec.js +2 -2
- package/dist/_internal/components/data-display/DataGrid/DataGrid.js +2 -2
- package/dist/_internal/components/data-display/DataViews/DataViewsGrid.js +38 -38
- package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +59 -57
- package/dist/_internal/components/data-display/DataViews/DeleteViewDialog.js +3 -3
- package/dist/_internal/components/data-display/DataViews/ManageViewsDialog.js +7 -7
- package/dist/_internal/components/data-display/DataViews/SaveViewModal.js +7 -5
- package/dist/_internal/components/data-display/DataViews/base-card.js +3 -3
- package/dist/_internal/components/data-display/DataViews/base-list-card-geometry.js +3 -3
- package/dist/_internal/components/data-display/DataViews/base-list-card-layout.js +3 -3
- package/dist/_internal/components/data-display/DataViews/base-list-card-slots.js +2 -2
- 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-filter-panel.js +12 -12
- package/dist/_internal/components/data-display/DataViews/data-views-grid-bodies.js +6 -6
- package/dist/_internal/components/data-display/DataViews/data-views-grid-parts.js +33 -33
- package/dist/_internal/components/data-display/DataViews/data-views-inline-bar.js +16 -16
- package/dist/_internal/components/data-display/DataViews/data-views-more-fields.js +13 -13
- package/dist/_internal/components/data-display/DataViews/data-views-more-filters.js +14 -14
- package/dist/_internal/components/data-display/DataViews/data-views-range-pill.js +2 -2
- package/dist/_internal/components/data-display/DataViews/data-views-shell-toolbar.js +5 -5
- package/dist/_internal/components/data-display/DataViews/data-views-table-parts.js +14 -12
- package/dist/_internal/components/data-display/DataViews/data-views-toolbar.js +4 -4
- 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 +4 -4
- package/dist/_internal/components/data-display/EmptyState/EmptyState.js +2 -2
- package/dist/_internal/components/data-display/FleetMap/FleetBody.js +10 -10
- package/dist/_internal/components/data-display/FleetMap/FleetCanvas.js +6 -6
- package/dist/_internal/components/data-display/FleetMap/FleetMap.js +14 -14
- package/dist/_internal/components/data-display/FleetMap/FleetRoster.js +3 -3
- package/dist/_internal/components/data-display/HoverCard/HoverCard.js +2 -2
- package/dist/_internal/components/data-display/InteractiveTooltip/InteractiveTooltip.js +2 -2
- package/dist/_internal/components/data-display/LazyImage/LazyImage.js +3 -3
- package/dist/_internal/components/data-display/Lightbox/Lightbox.js +6 -6
- package/dist/_internal/components/data-display/LoadingState/LoadingState.js +3 -3
- package/dist/_internal/components/data-display/MapPreview/MapLayers.js +3 -3
- package/dist/_internal/components/data-display/MapPreview/MapPreview.js +5 -5
- package/dist/_internal/components/data-display/Progress/Progress.js +2 -2
- package/dist/_internal/components/data-display/SectionOnboarding/SectionOnboarding.js +3 -3
- package/dist/_internal/components/data-display/Sheet/Sheet.hooks.js +2 -2
- package/dist/_internal/components/data-display/Sheet/Sheet.js +4 -4
- package/dist/_internal/components/data-display/StatCard/StatCard.js +3 -3
- package/dist/_internal/components/data-display/Table/Table.js +2 -2
- package/dist/_internal/components/data-display/index.js +56 -56
- package/dist/_internal/components/feedback/ConfirmAction/ConfirmAction.js +2 -2
- package/dist/_internal/components/feedback/ConfirmAction/ConfirmButton.js +3 -3
- package/dist/_internal/components/feedback/ConfirmAction/with-confirmation.js +2 -2
- package/dist/_internal/components/feedback/Dialog/Dialog.js +2 -2
- package/dist/_internal/components/feedback/TutorialOverlay/TutorialOverlay.js +2 -2
- package/dist/_internal/components/feedback/index.js +11 -11
- package/dist/_internal/components/form/AddressAutocomplete/AddressAutocomplete.hooks.js +4 -4
- package/dist/_internal/components/form/AddressAutocomplete/AddressAutocomplete.js +8 -8
- package/dist/_internal/components/form/AddressAutocomplete/AddressAutocompleteField.js +2 -2
- package/dist/_internal/components/form/Autocomplete/Autocomplete.js +1 -1
- package/dist/_internal/components/form/Calendar/Calendar.hooks.js +2 -2
- package/dist/_internal/components/form/Calendar/Calendar.js +6 -6
- package/dist/_internal/components/form/Calendar/CalendarDayCell.js +2 -2
- package/dist/_internal/components/form/Calendar/CalendarMonth.js +3 -3
- package/dist/_internal/components/form/CategorySelect/CategoryPanel.js +3 -3
- package/dist/_internal/components/form/CategorySelect/CategorySelect.js +7 -7
- package/dist/_internal/components/form/CepField/CepField.js +5 -4
- 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 +9 -9
- package/dist/_internal/components/form/Input/Input.factory.js +23 -0
- package/dist/_internal/components/form/Input/Input.factory.js.map +1 -0
- package/dist/_internal/components/form/Input/Input.js +4 -2
- package/dist/_internal/components/form/Input/outlined/text-field-slim-outlined.js +10 -0
- package/dist/_internal/components/form/Input/outlined/text-field-slim-outlined.js.map +1 -0
- package/dist/_internal/components/form/Input/text-field-slim.factory.js +10 -0
- package/dist/_internal/components/form/Input/text-field-slim.factory.js.map +1 -0
- package/dist/_internal/components/form/Input/text-field-slim.js +2 -1
- package/dist/_internal/components/form/NumberField/NumberField.js +5 -3
- package/dist/_internal/components/form/PickerSheet/PickerSheet.js +2 -2
- package/dist/_internal/components/form/index.js +44 -40
- package/dist/_internal/components/form/total-form/Fields/CategoryField.js +8 -8
- package/dist/_internal/components/form/total-form/Fields/CepField.js +6 -5
- package/dist/_internal/components/form/total-form/Fields/TextField.js +5 -3
- package/dist/_internal/components/form/total-form/Fields/index.js +21 -17
- package/dist/_internal/components/index.js +164 -160
- package/dist/_internal/components/layout/Card/Card.js +2 -2
- package/dist/_internal/components/layout/ScrollArea/ScrollArea.js +3 -3
- package/dist/_internal/components/layout/SettingCard/SettingCard.js +4 -4
- package/dist/_internal/components/layout/SettingCard/SettingCard.summary.js +3 -3
- package/dist/_internal/components/layout/SettingCard/SettingGroup.js +5 -5
- package/dist/_internal/components/layout/SettingCard/SettingSwitch.js +4 -4
- package/dist/_internal/components/layout/SettingCard/SettingToggle.js +5 -5
- package/dist/_internal/components/layout/SettingsLayout/SettingsLayout.js +5 -5
- package/dist/_internal/components/layout/SettingsLayout/SettingsPanel.js +2 -2
- package/dist/_internal/components/layout/Skeleton/Skeleton.js +2 -2
- package/dist/_internal/components/layout/index.js +17 -17
- package/dist/_internal/components/navigation/AppHeader/AppHeader.details.js +7 -7
- package/dist/_internal/components/navigation/NavigationMenu/NavigationMegaSection.js +3 -3
- package/dist/_internal/components/navigation/NavigationMenu/NavigationMenu.js +5 -5
- package/dist/_internal/components/navigation/NavigationMenu/NavigationMenuItem.js +2 -2
- package/dist/_internal/components/navigation/NavigationMenu/NavigationStandardBody.js +3 -3
- package/dist/_internal/components/navigation/SectionNav/SectionNav.bar.js +6 -4
- package/dist/_internal/components/navigation/SectionNav/SectionNav.js +3 -3
- package/dist/_internal/components/navigation/SectionNav/SectionNav.primary.js +9 -3
- package/dist/_internal/components/navigation/index.js +39 -39
- package/dist/_internal/components/utility/InfiniteScroll/InfiniteScroll.js +2 -2
- package/dist/_internal/components/utility/InstallPrompt/InstallPrompt.js +2 -2
- package/dist/_internal/components/utility/index.js +8 -8
- package/dist/_internal/pt-BR.data-display.js +2 -2
- package/dist/_internal/social-login-button/social-login-button.js +3 -3
- package/dist/_internal/user-avatar/user-avatar.js +7 -7
- package/dist/charts.js +11 -11
- package/dist/{chunk-NQP72RTD.js → chunk-27F2VXS4.js} +2 -2
- package/dist/{chunk-GMJBWOIU.js → chunk-2ILXXBMG.js} +5 -5
- package/dist/{chunk-LVATGJZO.js → chunk-2K2Q7VGV.js} +2 -2
- package/dist/{chunk-ISW5K72V.js → chunk-2ZRZTGWP.js} +5 -5
- package/dist/{chunk-BM3MKZL2.js → chunk-3BDMYTH6.js} +2 -2
- package/dist/{chunk-Q7BGMLCX.js → chunk-3FDSXSEP.js} +3 -3
- package/dist/{chunk-5WJFCQFN.js → chunk-3O2OJW4O.js} +4 -4
- package/dist/{chunk-L4FWEI2P.js → chunk-3V3Z4EML.js} +5 -5
- package/dist/{chunk-CE74DKHT.js → chunk-44PBCQ7E.js} +7 -7
- package/dist/{chunk-U5YOOHR6.js → chunk-4QGPRORO.js} +2 -2
- package/dist/{chunk-W2RXXF7K.js → chunk-4XBAEKQQ.js} +4 -4
- package/dist/{chunk-LYVTJLCF.js → chunk-56JF5PZK.js} +4 -4
- package/dist/{chunk-QBY3TWV3.js → chunk-5HFB4WFE.js} +3 -3
- package/dist/{chunk-3DPPDGOF.js → chunk-62SXUU5U.js} +5 -5
- package/dist/{chunk-QADTI63U.js → chunk-6ATXOJVQ.js} +4 -4
- package/dist/chunk-6GYUR63Q.js +14 -0
- package/dist/chunk-6GYUR63Q.js.map +1 -0
- package/dist/{chunk-F3AYISXT.js → chunk-6PU3JYVY.js} +4 -4
- package/dist/{chunk-WVIJFS5Y.js → chunk-725H45MT.js} +7 -7
- package/dist/{chunk-XP522FFM.js → chunk-7JKDB5J5.js} +5 -5
- package/dist/{chunk-V45JGJ3W.js → chunk-7K23NEZO.js} +8 -8
- package/dist/{chunk-EOQ6EKTS.js → chunk-7XSCEHGA.js} +7 -7
- package/dist/{chunk-7VUXSNVZ.js → chunk-A4B27HYU.js} +2 -2
- package/dist/{chunk-ADSA76T7.js → chunk-AG3DY5TH.js} +2 -2
- package/dist/{chunk-G5ORAVSP.js → chunk-AJ5LXKLQ.js} +8 -8
- package/dist/{chunk-HI7JPDD6.js → chunk-AMLHEKSV.js} +5 -5
- package/dist/{chunk-XZILNBAU.js → chunk-ARVLS57B.js} +6 -6
- package/dist/{chunk-ZEH6MGP5.js → chunk-BEHM2VLH.js} +9 -9
- package/dist/{chunk-EBMWYRXW.js → chunk-BEYLI32I.js} +2 -2
- package/dist/{chunk-YKKHNYEW.js → chunk-BF3SGOWT.js} +3 -3
- package/dist/{chunk-MA6SUE7F.js → chunk-BGGVYKVZ.js} +4 -4
- package/dist/{chunk-YNIOCELQ.js → chunk-BJONUBQL.js} +3 -3
- package/dist/{chunk-E5GYHN4X.js → chunk-CAX3NFFE.js} +3 -3
- package/dist/{chunk-LIN4A2BW.js → chunk-CSD6SWBZ.js} +5 -5
- package/dist/{chunk-QK63RXLG.js → chunk-CYH5QQUP.js} +8 -8
- package/dist/{chunk-CJGSQL77.js → chunk-CZV6NVCA.js} +4 -4
- package/dist/{chunk-755VS7NA.js → chunk-DOWVAC4U.js} +3 -3
- package/dist/{chunk-PIP7XII2.js → chunk-E54XIRY2.js} +5 -5
- package/dist/{chunk-SL6454K7.js → chunk-EEB66IVH.js} +26 -32
- package/dist/chunk-EEB66IVH.js.map +1 -0
- package/dist/{chunk-NJMAFII4.js → chunk-F5IXDEWJ.js} +2 -2
- package/dist/{chunk-U57NFQYE.js → chunk-FIOBPQL2.js} +4 -4
- package/dist/{chunk-6VUVSYP4.js → chunk-FR2RJXHS.js} +2 -2
- package/dist/{chunk-FWPQUYND.js → chunk-FS55MQ4Q.js} +2 -2
- package/dist/{chunk-UXVB423Q.js → chunk-FVL6U72V.js} +6 -6
- package/dist/{chunk-2ZHF5VE4.js → chunk-FXECKKPW.js} +32 -29
- package/dist/chunk-FXECKKPW.js.map +1 -0
- package/dist/{chunk-LWZ2K225.js → chunk-FXZUVZON.js} +6 -6
- package/dist/{chunk-RGR6YKK5.js → chunk-GBKIGUNP.js} +2 -2
- package/dist/{chunk-YBAK2WN5.js → chunk-HBHBRRSW.js} +7 -7
- package/dist/{chunk-HNFZLXZI.js → chunk-HBP2OU4Q.js} +5 -5
- package/dist/{chunk-V6OC2PSQ.js → chunk-HCLAVPGG.js} +2 -2
- package/dist/{chunk-4MKVGSHX.js → chunk-HN3PZTUK.js} +5 -5
- package/dist/{chunk-ZOUWHGV3.js → chunk-HOJL2GKW.js} +7 -7
- package/dist/{chunk-JVOEVTCZ.js → chunk-HQCZT6TO.js} +5 -5
- package/dist/{chunk-PCM4VEPO.js → chunk-HSIUVFXE.js} +7 -7
- package/dist/{chunk-L5R2FB4T.js → chunk-HVGQH54G.js} +2 -2
- package/dist/{chunk-7SPFK73H.js → chunk-IHLOP4LG.js} +7 -7
- package/dist/{chunk-RQF4NXDC.js → chunk-IWJTLCTF.js} +2 -2
- package/dist/{chunk-IICBAAL7.js → chunk-IZ7JTG3Z.js} +4 -4
- package/dist/{chunk-2QB4WIU5.js → chunk-J5QNJERV.js} +10 -10
- package/dist/{chunk-6OLERKNC.js → chunk-JA3WJPXH.js} +2 -2
- package/dist/{chunk-5ZOJLYD2.js → chunk-JE6RZ5L6.js} +4 -4
- package/dist/{chunk-GICG3XJK.js → chunk-JGLPSBZE.js} +4 -4
- package/dist/{chunk-J2RUDZVJ.js → chunk-KARMRTTM.js} +7 -7
- package/dist/{chunk-RIAZPGHT.js → chunk-KKVM723A.js} +4 -4
- package/dist/{chunk-3DFWHF6O.js → chunk-KLEKSTZI.js} +6 -6
- package/dist/{chunk-6QOJEZDH.js → chunk-KZ5I5WCH.js} +4 -4
- package/dist/{chunk-CDYQKIBL.js → chunk-LABIUXDM.js} +2 -2
- package/dist/chunk-LZRVUOMU.js +12 -0
- package/dist/chunk-LZRVUOMU.js.map +1 -0
- package/dist/{chunk-ZAPP32GD.js → chunk-M7HYNXCU.js} +2 -2
- package/dist/{chunk-QVEQOUQY.js → chunk-MA6ENJDP.js} +3 -3
- package/dist/{chunk-D34PZJH3.js → chunk-MBMZNSBP.js} +2 -2
- package/dist/{chunk-EQK3K65G.js → chunk-MK7KZY2Y.js} +2 -2
- package/dist/chunk-MK7KZY2Y.js.map +1 -0
- package/dist/{chunk-Z2J4MRTF.js → chunk-MKNW4FRR.js} +4 -4
- package/dist/{chunk-RCZ4KL2H.js → chunk-NIENIKZ5.js} +2 -2
- package/dist/{chunk-6QRN4JK7.js → chunk-NKBCUR4V.js} +2 -2
- package/dist/{chunk-2B3NX5HJ.js → chunk-NPSARV2I.js} +6 -6
- package/dist/{chunk-YPAH2NWN.js → chunk-NQ6P7O7C.js} +2 -2
- package/dist/{chunk-EWVJJ32N.js → chunk-OKYYHBGS.js} +6 -6
- package/dist/{chunk-WQ32YFM5.js → chunk-P7VAMJFJ.js} +5 -5
- package/dist/{chunk-KYPHR4TT.js → chunk-QWSYHENP.js} +2 -2
- package/dist/chunk-RHVJ3L4U.js +14 -0
- package/dist/chunk-RHVJ3L4U.js.map +1 -0
- package/dist/{chunk-SE5WHKCB.js → chunk-RPKUZDRY.js} +6 -6
- package/dist/{chunk-V6SRBQMN.js → chunk-S4JXSC4D.js} +5 -5
- package/dist/{chunk-TIM4PXWN.js → chunk-SB2SEGR6.js} +3 -3
- package/dist/{chunk-7PTE6HBW.js → chunk-SUXT6QAY.js} +2 -2
- package/dist/{chunk-DAT4XWYX.js → chunk-TRYYYWV3.js} +14 -14
- package/dist/{chunk-65NYUQXD.js → chunk-TSID4257.js} +9 -9
- package/dist/{chunk-KPEKD5SG.js → chunk-UKUGSU3Y.js} +11 -3
- package/dist/{chunk-KPEKD5SG.js.map → chunk-UKUGSU3Y.js.map} +1 -1
- package/dist/{chunk-23LPXHR2.js → chunk-URSYEHPU.js} +11 -5
- package/dist/chunk-URSYEHPU.js.map +1 -0
- package/dist/{chunk-DWFUT45A.js → chunk-VEBNL5MG.js} +3 -3
- package/dist/{chunk-LVXGCXKB.js → chunk-VMTOLAZ5.js} +7 -7
- package/dist/{chunk-BRBQNPM2.js → chunk-VQSBZPKO.js} +3 -3
- package/dist/{chunk-ZEVFMQAQ.js → chunk-VWVA74JY.js} +2 -2
- package/dist/{chunk-RX2XP7V5.js → chunk-WHUJAGPV.js} +4 -4
- package/dist/{chunk-YULI2EBC.js → chunk-XICRCPEQ.js} +4 -4
- package/dist/{chunk-Q4WTVAJ5.js → chunk-XLCVMRSO.js} +2 -2
- package/dist/{chunk-ZIHSCBMN.js → chunk-Z5V5E3JW.js} +10 -10
- package/dist/{chunk-7KAZ3B5B.js → chunk-Z5W4QPEC.js} +4 -4
- package/dist/{chunk-G3JFESKD.js → chunk-Z5WUSI47.js} +6 -6
- package/dist/chunk-ZLMKGVB2.js +21 -0
- package/dist/chunk-ZLMKGVB2.js.map +1 -0
- package/dist/{chunk-JPYNGWV4.js → chunk-ZOLUUX4B.js} +2 -2
- package/dist/{chunk-4W6AQFMO.js → chunk-ZVWQ5TF4.js} +3 -3
- package/dist/data-display/AsyncStateContainer.js +6 -6
- package/dist/data-display/Avatar.js +4 -4
- package/dist/data-display/CardKit.js +13 -13
- package/dist/data-display/Carousel.js +2 -2
- package/dist/data-display/Chart.js +11 -11
- package/dist/data-display/DataGrid.js +2 -2
- package/dist/data-display/DataViews.js +72 -70
- package/dist/data-display/EmptyState.js +2 -2
- package/dist/data-display/FleetMap.js +14 -14
- package/dist/data-display/HoverCard.js +2 -2
- package/dist/data-display/InteractiveTooltip.js +2 -2
- package/dist/data-display/LazyImage.js +3 -3
- package/dist/data-display/Lightbox.js +6 -6
- package/dist/data-display/LoadingState.js +3 -3
- package/dist/data-display/MapPreview.js +5 -5
- package/dist/data-display/Progress.js +2 -2
- package/dist/data-display/SectionOnboarding.js +3 -3
- package/dist/data-display/Sheet.js +4 -4
- package/dist/data-display/StatCard.js +3 -3
- package/dist/data-display/Table.js +2 -2
- package/dist/feedback/ConfirmAction.js +7 -7
- package/dist/feedback/Dialog.js +2 -2
- package/dist/feedback/TutorialOverlay.js +2 -2
- package/dist/form/AddressAutocomplete.js +8 -8
- package/dist/form/Autocomplete.js +1 -1
- package/dist/form/Calendar.js +6 -6
- package/dist/form/CategorySelect.js +7 -7
- package/dist/form/CepField.js +5 -4
- package/dist/form/CodeEditor.js +2 -2
- package/dist/form/Command.js +2 -2
- package/dist/form/DateRangePicker.js +9 -9
- package/dist/form/Input/outlined.js +27 -0
- package/dist/form/Input/outlined.js.map +1 -0
- package/dist/form/Input.js +4 -2
- package/dist/form/NumberField.js +5 -3
- package/dist/form/PickerSheet.js +2 -2
- package/dist/form/total-form.js +21 -17
- package/dist/layout/Card.js +2 -2
- package/dist/layout/ContentToolbar.js +3 -3
- package/dist/layout/ScrollArea.js +3 -3
- package/dist/layout/SettingCard.js +7 -7
- package/dist/layout/SettingsLayout.js +5 -5
- package/dist/layout/Skeleton.js +2 -2
- package/dist/locales.js +6 -6
- package/dist/navigation/AppHeader.js +9 -9
- package/dist/navigation/NavigationMenu.js +5 -5
- package/dist/navigation/SectionNav.js +3 -3
- package/dist/pt-BR.js +6 -6
- package/dist/social-login-button.js +3 -3
- package/dist/types/components/form/CepField/CepField.d.ts.map +1 -1
- package/dist/types/components/form/Input/Input.d.ts +9 -3
- package/dist/types/components/form/Input/Input.d.ts.map +1 -1
- package/dist/types/components/form/Input/Input.factory.d.ts +13 -0
- package/dist/types/components/form/Input/Input.factory.d.ts.map +1 -0
- package/dist/types/components/form/Input/outlined/index.d.ts +24 -0
- package/dist/types/components/form/Input/outlined/index.d.ts.map +1 -0
- package/dist/types/components/form/Input/outlined/text-field-slim-outlined.d.ts +10 -0
- package/dist/types/components/form/Input/outlined/text-field-slim-outlined.d.ts.map +1 -0
- package/dist/types/components/form/Input/text-field-slim.d.ts +8 -40
- package/dist/types/components/form/Input/text-field-slim.d.ts.map +1 -1
- package/dist/types/components/form/Input/text-field-slim.factory.d.ts +61 -0
- package/dist/types/components/form/Input/text-field-slim.factory.d.ts.map +1 -0
- package/dist/types/components/navigation/SectionNav/SectionNav.bar.d.ts +2 -0
- package/dist/types/components/navigation/SectionNav/SectionNav.bar.d.ts.map +1 -1
- package/dist/types/components/navigation/SectionNav/SectionNav.primary.d.ts +9 -0
- package/dist/types/components/navigation/SectionNav/SectionNav.primary.d.ts.map +1 -1
- package/dist/user-avatar.js +7 -7
- package/dist/utility/InfiniteScroll.js +2 -2
- package/dist/utility/InstallPrompt.js +2 -2
- package/package.json +5 -1
- package/src/components/form/CepField/CepField.tsx +3 -1
- package/src/components/form/Input/Input.factory.tsx +221 -0
- package/src/components/form/Input/Input.md +20 -0
- package/src/components/form/Input/Input.tsx +9 -196
- package/src/components/form/Input/outlined/index.ts +27 -0
- package/src/components/form/Input/outlined/text-field-slim-outlined.tsx +13 -0
- package/src/components/form/Input/text-field-slim.factory.tsx +248 -0
- package/src/components/form/Input/text-field-slim.tsx +9 -209
- package/src/components/navigation/SectionNav/SectionNav.bar.tsx +9 -3
- package/src/components/navigation/SectionNav/SectionNav.md +1 -1
- package/src/components/navigation/SectionNav/SectionNav.primary.tsx +14 -1
- package/dist/chunk-23LPXHR2.js.map +0 -1
- package/dist/chunk-2ZHF5VE4.js.map +0 -1
- package/dist/chunk-EQK3K65G.js.map +0 -1
- package/dist/chunk-SL6454K7.js.map +0 -1
- /package/dist/{chunk-NQP72RTD.js.map → chunk-27F2VXS4.js.map} +0 -0
- /package/dist/{chunk-GMJBWOIU.js.map → chunk-2ILXXBMG.js.map} +0 -0
- /package/dist/{chunk-LVATGJZO.js.map → chunk-2K2Q7VGV.js.map} +0 -0
- /package/dist/{chunk-ISW5K72V.js.map → chunk-2ZRZTGWP.js.map} +0 -0
- /package/dist/{chunk-BM3MKZL2.js.map → chunk-3BDMYTH6.js.map} +0 -0
- /package/dist/{chunk-Q7BGMLCX.js.map → chunk-3FDSXSEP.js.map} +0 -0
- /package/dist/{chunk-5WJFCQFN.js.map → chunk-3O2OJW4O.js.map} +0 -0
- /package/dist/{chunk-L4FWEI2P.js.map → chunk-3V3Z4EML.js.map} +0 -0
- /package/dist/{chunk-CE74DKHT.js.map → chunk-44PBCQ7E.js.map} +0 -0
- /package/dist/{chunk-U5YOOHR6.js.map → chunk-4QGPRORO.js.map} +0 -0
- /package/dist/{chunk-W2RXXF7K.js.map → chunk-4XBAEKQQ.js.map} +0 -0
- /package/dist/{chunk-LYVTJLCF.js.map → chunk-56JF5PZK.js.map} +0 -0
- /package/dist/{chunk-QBY3TWV3.js.map → chunk-5HFB4WFE.js.map} +0 -0
- /package/dist/{chunk-3DPPDGOF.js.map → chunk-62SXUU5U.js.map} +0 -0
- /package/dist/{chunk-QADTI63U.js.map → chunk-6ATXOJVQ.js.map} +0 -0
- /package/dist/{chunk-F3AYISXT.js.map → chunk-6PU3JYVY.js.map} +0 -0
- /package/dist/{chunk-WVIJFS5Y.js.map → chunk-725H45MT.js.map} +0 -0
- /package/dist/{chunk-XP522FFM.js.map → chunk-7JKDB5J5.js.map} +0 -0
- /package/dist/{chunk-V45JGJ3W.js.map → chunk-7K23NEZO.js.map} +0 -0
- /package/dist/{chunk-EOQ6EKTS.js.map → chunk-7XSCEHGA.js.map} +0 -0
- /package/dist/{chunk-7VUXSNVZ.js.map → chunk-A4B27HYU.js.map} +0 -0
- /package/dist/{chunk-ADSA76T7.js.map → chunk-AG3DY5TH.js.map} +0 -0
- /package/dist/{chunk-G5ORAVSP.js.map → chunk-AJ5LXKLQ.js.map} +0 -0
- /package/dist/{chunk-HI7JPDD6.js.map → chunk-AMLHEKSV.js.map} +0 -0
- /package/dist/{chunk-XZILNBAU.js.map → chunk-ARVLS57B.js.map} +0 -0
- /package/dist/{chunk-ZEH6MGP5.js.map → chunk-BEHM2VLH.js.map} +0 -0
- /package/dist/{chunk-EBMWYRXW.js.map → chunk-BEYLI32I.js.map} +0 -0
- /package/dist/{chunk-YKKHNYEW.js.map → chunk-BF3SGOWT.js.map} +0 -0
- /package/dist/{chunk-MA6SUE7F.js.map → chunk-BGGVYKVZ.js.map} +0 -0
- /package/dist/{chunk-YNIOCELQ.js.map → chunk-BJONUBQL.js.map} +0 -0
- /package/dist/{chunk-E5GYHN4X.js.map → chunk-CAX3NFFE.js.map} +0 -0
- /package/dist/{chunk-LIN4A2BW.js.map → chunk-CSD6SWBZ.js.map} +0 -0
- /package/dist/{chunk-QK63RXLG.js.map → chunk-CYH5QQUP.js.map} +0 -0
- /package/dist/{chunk-CJGSQL77.js.map → chunk-CZV6NVCA.js.map} +0 -0
- /package/dist/{chunk-755VS7NA.js.map → chunk-DOWVAC4U.js.map} +0 -0
- /package/dist/{chunk-PIP7XII2.js.map → chunk-E54XIRY2.js.map} +0 -0
- /package/dist/{chunk-NJMAFII4.js.map → chunk-F5IXDEWJ.js.map} +0 -0
- /package/dist/{chunk-U57NFQYE.js.map → chunk-FIOBPQL2.js.map} +0 -0
- /package/dist/{chunk-6VUVSYP4.js.map → chunk-FR2RJXHS.js.map} +0 -0
- /package/dist/{chunk-FWPQUYND.js.map → chunk-FS55MQ4Q.js.map} +0 -0
- /package/dist/{chunk-UXVB423Q.js.map → chunk-FVL6U72V.js.map} +0 -0
- /package/dist/{chunk-LWZ2K225.js.map → chunk-FXZUVZON.js.map} +0 -0
- /package/dist/{chunk-RGR6YKK5.js.map → chunk-GBKIGUNP.js.map} +0 -0
- /package/dist/{chunk-YBAK2WN5.js.map → chunk-HBHBRRSW.js.map} +0 -0
- /package/dist/{chunk-HNFZLXZI.js.map → chunk-HBP2OU4Q.js.map} +0 -0
- /package/dist/{chunk-V6OC2PSQ.js.map → chunk-HCLAVPGG.js.map} +0 -0
- /package/dist/{chunk-4MKVGSHX.js.map → chunk-HN3PZTUK.js.map} +0 -0
- /package/dist/{chunk-ZOUWHGV3.js.map → chunk-HOJL2GKW.js.map} +0 -0
- /package/dist/{chunk-JVOEVTCZ.js.map → chunk-HQCZT6TO.js.map} +0 -0
- /package/dist/{chunk-PCM4VEPO.js.map → chunk-HSIUVFXE.js.map} +0 -0
- /package/dist/{chunk-L5R2FB4T.js.map → chunk-HVGQH54G.js.map} +0 -0
- /package/dist/{chunk-7SPFK73H.js.map → chunk-IHLOP4LG.js.map} +0 -0
- /package/dist/{chunk-RQF4NXDC.js.map → chunk-IWJTLCTF.js.map} +0 -0
- /package/dist/{chunk-IICBAAL7.js.map → chunk-IZ7JTG3Z.js.map} +0 -0
- /package/dist/{chunk-2QB4WIU5.js.map → chunk-J5QNJERV.js.map} +0 -0
- /package/dist/{chunk-6OLERKNC.js.map → chunk-JA3WJPXH.js.map} +0 -0
- /package/dist/{chunk-5ZOJLYD2.js.map → chunk-JE6RZ5L6.js.map} +0 -0
- /package/dist/{chunk-GICG3XJK.js.map → chunk-JGLPSBZE.js.map} +0 -0
- /package/dist/{chunk-J2RUDZVJ.js.map → chunk-KARMRTTM.js.map} +0 -0
- /package/dist/{chunk-RIAZPGHT.js.map → chunk-KKVM723A.js.map} +0 -0
- /package/dist/{chunk-3DFWHF6O.js.map → chunk-KLEKSTZI.js.map} +0 -0
- /package/dist/{chunk-6QOJEZDH.js.map → chunk-KZ5I5WCH.js.map} +0 -0
- /package/dist/{chunk-CDYQKIBL.js.map → chunk-LABIUXDM.js.map} +0 -0
- /package/dist/{chunk-ZAPP32GD.js.map → chunk-M7HYNXCU.js.map} +0 -0
- /package/dist/{chunk-QVEQOUQY.js.map → chunk-MA6ENJDP.js.map} +0 -0
- /package/dist/{chunk-D34PZJH3.js.map → chunk-MBMZNSBP.js.map} +0 -0
- /package/dist/{chunk-Z2J4MRTF.js.map → chunk-MKNW4FRR.js.map} +0 -0
- /package/dist/{chunk-RCZ4KL2H.js.map → chunk-NIENIKZ5.js.map} +0 -0
- /package/dist/{chunk-6QRN4JK7.js.map → chunk-NKBCUR4V.js.map} +0 -0
- /package/dist/{chunk-2B3NX5HJ.js.map → chunk-NPSARV2I.js.map} +0 -0
- /package/dist/{chunk-YPAH2NWN.js.map → chunk-NQ6P7O7C.js.map} +0 -0
- /package/dist/{chunk-EWVJJ32N.js.map → chunk-OKYYHBGS.js.map} +0 -0
- /package/dist/{chunk-WQ32YFM5.js.map → chunk-P7VAMJFJ.js.map} +0 -0
- /package/dist/{chunk-KYPHR4TT.js.map → chunk-QWSYHENP.js.map} +0 -0
- /package/dist/{chunk-SE5WHKCB.js.map → chunk-RPKUZDRY.js.map} +0 -0
- /package/dist/{chunk-V6SRBQMN.js.map → chunk-S4JXSC4D.js.map} +0 -0
- /package/dist/{chunk-TIM4PXWN.js.map → chunk-SB2SEGR6.js.map} +0 -0
- /package/dist/{chunk-7PTE6HBW.js.map → chunk-SUXT6QAY.js.map} +0 -0
- /package/dist/{chunk-DAT4XWYX.js.map → chunk-TRYYYWV3.js.map} +0 -0
- /package/dist/{chunk-65NYUQXD.js.map → chunk-TSID4257.js.map} +0 -0
- /package/dist/{chunk-DWFUT45A.js.map → chunk-VEBNL5MG.js.map} +0 -0
- /package/dist/{chunk-LVXGCXKB.js.map → chunk-VMTOLAZ5.js.map} +0 -0
- /package/dist/{chunk-BRBQNPM2.js.map → chunk-VQSBZPKO.js.map} +0 -0
- /package/dist/{chunk-ZEVFMQAQ.js.map → chunk-VWVA74JY.js.map} +0 -0
- /package/dist/{chunk-RX2XP7V5.js.map → chunk-WHUJAGPV.js.map} +0 -0
- /package/dist/{chunk-YULI2EBC.js.map → chunk-XICRCPEQ.js.map} +0 -0
- /package/dist/{chunk-Q4WTVAJ5.js.map → chunk-XLCVMRSO.js.map} +0 -0
- /package/dist/{chunk-ZIHSCBMN.js.map → chunk-Z5V5E3JW.js.map} +0 -0
- /package/dist/{chunk-7KAZ3B5B.js.map → chunk-Z5W4QPEC.js.map} +0 -0
- /package/dist/{chunk-G3JFESKD.js.map → chunk-Z5WUSI47.js.map} +0 -0
- /package/dist/{chunk-JPYNGWV4.js.map → chunk-ZOLUUX4B.js.map} +0 -0
- /package/dist/{chunk-4W6AQFMO.js.map → chunk-ZVWQ5TF4.js.map} +0 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `TextFieldSlim`'s body, with the input implementation left to the caller
|
|
5
|
+
* (FUT-1054). Why the field exists at all, and what it transcribes from MUI's
|
|
6
|
+
* `TextField`, is in `text-field-slim.tsx`.
|
|
7
|
+
*/
|
|
8
|
+
import FormControl from '@mui/material/FormControl/index.js';
|
|
9
|
+
import FormHelperText from '@mui/material/FormHelperText/index.js';
|
|
10
|
+
import InputLabel from '@mui/material/InputLabel/index.js';
|
|
11
|
+
import { styled } from '@mui/material/styles/index.js';
|
|
12
|
+
import type { FilledInputProps } from '@mui/material/FilledInput/index.js';
|
|
13
|
+
import type { FormControlProps } from '@mui/material/FormControl/index.js';
|
|
14
|
+
import type { FormHelperTextProps } from '@mui/material/FormHelperText/index.js';
|
|
15
|
+
import type { InputProps as MuiInputProps } from '@mui/material/Input/index.js';
|
|
16
|
+
import type { InputBaseComponentProps } from '@mui/material/InputBase/index.js';
|
|
17
|
+
import type { InputLabelProps } from '@mui/material/InputLabel/index.js';
|
|
18
|
+
import type { OutlinedInputProps } from '@mui/material/OutlinedInput/index.js';
|
|
19
|
+
import React from 'react';
|
|
20
|
+
|
|
21
|
+
import { withDefaults } from '../../../utils/withDefaults';
|
|
22
|
+
|
|
23
|
+
/** MUI's three input variants, by the name `TextField` gives them. */
|
|
24
|
+
export type MuiFieldVariant = 'standard' | 'filled' | 'outlined';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Which input renders a variant. The generic `TextFieldSlim` maps all three;
|
|
28
|
+
* a pinned field maps the one it renders, so the other two are never imported
|
|
29
|
+
* (FUT-1054).
|
|
30
|
+
*/
|
|
31
|
+
export type InputForVariant = (variant: MuiFieldVariant) => React.ElementType;
|
|
32
|
+
|
|
33
|
+
/** What `createTextFieldSlim` returns, and what `createInput` composes. */
|
|
34
|
+
export type TextFieldSlimComponent = React.ForwardRefExoticComponent<
|
|
35
|
+
TextFieldSlimProps & React.RefAttributes<HTMLDivElement>
|
|
36
|
+
>;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* `MuiTextField-root`, by hand.
|
|
40
|
+
*
|
|
41
|
+
* `@mui/material` does not re-export `textFieldClasses` from its root barrel,
|
|
42
|
+
* and the deep path that does would import `TextField` — the whole thing this
|
|
43
|
+
* file exists to avoid. So the class name is written out, and the parity test
|
|
44
|
+
* asserts it against a REAL `TextField`'s root rather than against itself.
|
|
45
|
+
*
|
|
46
|
+
* It has to be there at all because it is part of MUI's public surface: two of
|
|
47
|
+
* this package's own suites reach for `.closest('.MuiTextField-root')`, and a
|
|
48
|
+
* consumer's stylesheet may too.
|
|
49
|
+
*/
|
|
50
|
+
const TEXT_FIELD_ROOT_CLASS = 'MuiTextField-root';
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Named `MuiTextField` so a theme's `components.MuiTextField.styleOverrides`
|
|
54
|
+
* keeps applying. Nothing in this repo sets one today; a consumer's theme is
|
|
55
|
+
* not this package's to break.
|
|
56
|
+
*/
|
|
57
|
+
const TextFieldSlimRoot = styled(FormControl, {
|
|
58
|
+
name: 'MuiTextField',
|
|
59
|
+
slot: 'Root',
|
|
60
|
+
overridesResolver: (_props, styles) => styles.root,
|
|
61
|
+
})({});
|
|
62
|
+
|
|
63
|
+
export interface TextFieldSlimProps
|
|
64
|
+
extends Omit<FormControlProps, 'onChange' | 'onBlur' | 'onFocus' | 'defaultValue'> {
|
|
65
|
+
autoComplete?: string;
|
|
66
|
+
autoFocus?: boolean;
|
|
67
|
+
defaultValue?: unknown;
|
|
68
|
+
helperText?: React.ReactNode;
|
|
69
|
+
label?: React.ReactNode;
|
|
70
|
+
maxRows?: number | string;
|
|
71
|
+
minRows?: number | string;
|
|
72
|
+
multiline?: boolean;
|
|
73
|
+
name?: string;
|
|
74
|
+
placeholder?: string;
|
|
75
|
+
rows?: number | string;
|
|
76
|
+
type?: React.InputHTMLAttributes<HTMLInputElement>['type'];
|
|
77
|
+
value?: unknown;
|
|
78
|
+
inputRef?: React.Ref<unknown>;
|
|
79
|
+
onBlur?: React.FocusEventHandler<HTMLInputElement | HTMLTextAreaElement>;
|
|
80
|
+
onChange?: React.ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement>;
|
|
81
|
+
onFocus?: React.FocusEventHandler<HTMLInputElement | HTMLTextAreaElement>;
|
|
82
|
+
/** Props for the rendered input variant. */
|
|
83
|
+
InputProps?: Partial<MuiInputProps & FilledInputProps & OutlinedInputProps>;
|
|
84
|
+
/**
|
|
85
|
+
* Props for the `<input>` itself — where an `aria-label` has to ride.
|
|
86
|
+
*
|
|
87
|
+
* MUI's own type, because it is deliberately open: a caller puts `data-*`
|
|
88
|
+
* and `aria-*` here precisely because the root would swallow them, and
|
|
89
|
+
* `InputHTMLAttributes` alone rejects both.
|
|
90
|
+
*/
|
|
91
|
+
inputProps?: InputBaseComponentProps;
|
|
92
|
+
InputLabelProps?: Partial<InputLabelProps>;
|
|
93
|
+
FormHelperTextProps?: Partial<FormHelperTextProps>;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* `TextField`'s own defaults, as a table.
|
|
98
|
+
*
|
|
99
|
+
* One `= default` per destructured prop is one branch per prop, and eight of
|
|
100
|
+
* them put this component over the complexity bar before it rendered anything —
|
|
101
|
+
* which is the same reason `AppHeader` keeps its defaults in a table. The values
|
|
102
|
+
* are `TextField`'s, unchanged; the parity test would fail if any drifted.
|
|
103
|
+
*/
|
|
104
|
+
const DEFAULTS: Partial<TextFieldSlimProps> = {
|
|
105
|
+
autoFocus: false,
|
|
106
|
+
color: 'primary',
|
|
107
|
+
disabled: false,
|
|
108
|
+
error: false,
|
|
109
|
+
fullWidth: false,
|
|
110
|
+
multiline: false,
|
|
111
|
+
required: false,
|
|
112
|
+
variant: 'outlined',
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/** The two ids a labelled, described field needs, and the input's own. */
|
|
116
|
+
function idsOf(props: TextFieldSlimProps, generated: string): {
|
|
117
|
+
id: string;
|
|
118
|
+
helperTextId: string | undefined;
|
|
119
|
+
inputLabelId: string | undefined;
|
|
120
|
+
} {
|
|
121
|
+
const id = props.id ?? generated;
|
|
122
|
+
return {
|
|
123
|
+
id,
|
|
124
|
+
helperTextId: props.helperText && id ? `${id}-helper-text` : undefined,
|
|
125
|
+
inputLabelId: props.label && id ? `${id}-label` : undefined,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* What only the OUTLINED variant needs: it draws its own notch around the
|
|
131
|
+
* label, so it has to be told the label and whether the caller pinned it shrunk
|
|
132
|
+
* (FUT-729's `shrink` case).
|
|
133
|
+
*/
|
|
134
|
+
function outlinedPropsOf(props: TextFieldSlimProps): Record<string, unknown> {
|
|
135
|
+
if (props.variant !== 'outlined') return {};
|
|
136
|
+
const shrink = props.InputLabelProps?.shrink;
|
|
137
|
+
return { label: props.label, ...(shrink === undefined ? {} : { notched: shrink }) };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
interface FieldIds {
|
|
141
|
+
id: string;
|
|
142
|
+
helperTextId: string | undefined;
|
|
143
|
+
inputLabelId: string | undefined;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Everything the input (or this component) consumes by name.
|
|
148
|
+
*
|
|
149
|
+
* A key LIST rather than the omit-by-destructuring idiom, which would name
|
|
150
|
+
* twenty-four bindings only to leave every one of them unused — twenty-four
|
|
151
|
+
* lint warnings, in a package that allows none.
|
|
152
|
+
*
|
|
153
|
+
* `fullWidth`, `disabled`, `error`, `required`, `color` and `variant` are
|
|
154
|
+
* deliberately absent: `TextField` hands those to the root, and `fullWidth` to
|
|
155
|
+
* both.
|
|
156
|
+
*/
|
|
157
|
+
const CONSUMED_BY_FIELD: ReadonlySet<string> = new Set([
|
|
158
|
+
'autoComplete', 'autoFocus', 'children', 'className', 'defaultValue',
|
|
159
|
+
'FormHelperTextProps', 'helperText', 'id', 'InputLabelProps', 'inputProps',
|
|
160
|
+
'InputProps', 'inputRef', 'label', 'maxRows', 'minRows', 'multiline', 'name',
|
|
161
|
+
'onBlur', 'onChange', 'onFocus', 'placeholder', 'rows', 'type', 'value',
|
|
162
|
+
]);
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* What the ROOT `FormControl` gets: the props `TextField` hands it by name,
|
|
166
|
+
* plus everything it did not recognise.
|
|
167
|
+
*
|
|
168
|
+
* That second half is `TextField`'s behaviour and not a choice made here: an
|
|
169
|
+
* unrecognised HTML attribute lands on the root `div`, which is why `Input` has
|
|
170
|
+
* to route `aria-label` through `inputProps`. The parity test pins it.
|
|
171
|
+
*/
|
|
172
|
+
function rootPropsOf(props: TextFieldSlimProps): Record<string, unknown> {
|
|
173
|
+
return Object.fromEntries(
|
|
174
|
+
Object.entries(props).filter(([key]) => !CONSUMED_BY_FIELD.has(key)),
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** What the INPUT gets, by name, exactly as `TextField` names them. */
|
|
179
|
+
function fieldPropsOf(props: TextFieldSlimProps, ids: FieldIds): Record<string, unknown> {
|
|
180
|
+
return {
|
|
181
|
+
'aria-describedby': ids.helperTextId,
|
|
182
|
+
autoComplete: props.autoComplete,
|
|
183
|
+
autoFocus: props.autoFocus,
|
|
184
|
+
defaultValue: props.defaultValue,
|
|
185
|
+
fullWidth: props.fullWidth,
|
|
186
|
+
multiline: props.multiline,
|
|
187
|
+
name: props.name,
|
|
188
|
+
rows: props.rows,
|
|
189
|
+
maxRows: props.maxRows,
|
|
190
|
+
minRows: props.minRows,
|
|
191
|
+
type: props.type,
|
|
192
|
+
value: props.value,
|
|
193
|
+
id: ids.id,
|
|
194
|
+
inputRef: props.inputRef,
|
|
195
|
+
onBlur: props.onBlur,
|
|
196
|
+
onChange: props.onChange,
|
|
197
|
+
onFocus: props.onFocus,
|
|
198
|
+
placeholder: props.placeholder,
|
|
199
|
+
inputProps: props.inputProps,
|
|
200
|
+
...outlinedPropsOf(props),
|
|
201
|
+
...props.InputProps,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* The field, with the input implementation chosen by `inputFor`.
|
|
207
|
+
*
|
|
208
|
+
* A factory rather than a component so the variant table lives in the CALLER's
|
|
209
|
+
* module: this module imports none of `Input`, `FilledInput` or
|
|
210
|
+
* `OutlinedInput`, so what `inputFor` returns is the only input a caller's
|
|
211
|
+
* bundle keeps. The caller's own module-scope `createTextFieldSlim(...)` call
|
|
212
|
+
* is kept by the bundler, and with it every module its argument reaches
|
|
213
|
+
* (FUT-3402), so that argument must name only the variants it serves.
|
|
214
|
+
*/
|
|
215
|
+
export function createTextFieldSlim(inputFor: InputForVariant): TextFieldSlimComponent {
|
|
216
|
+
return React.forwardRef<HTMLDivElement, TextFieldSlimProps>(
|
|
217
|
+
function TextFieldSlim(rawProps, ref) {
|
|
218
|
+
const props = withDefaults(rawProps, DEFAULTS);
|
|
219
|
+
// `TextField` uses `@mui/utils`'s `useId`, which is React's with a fallback
|
|
220
|
+
// for React 17. The peer here is React 19, so React's own is the same thing
|
|
221
|
+
// without the dependency. The override still wins, exactly as it did — and
|
|
222
|
+
// it is read from the RAW props, before `withDefaults` could supply one.
|
|
223
|
+
const ids = idsOf(rawProps, React.useId());
|
|
224
|
+
const InputComponent = inputFor(props.variant ?? 'outlined');
|
|
225
|
+
const { label, helperText } = props;
|
|
226
|
+
|
|
227
|
+
return (
|
|
228
|
+
<TextFieldSlimRoot
|
|
229
|
+
className={[TEXT_FIELD_ROOT_CLASS, props.className].filter(Boolean).join(' ')}
|
|
230
|
+
ref={ref}
|
|
231
|
+
{...rootPropsOf(props)}
|
|
232
|
+
>
|
|
233
|
+
{label !== null && label !== undefined && label !== '' ? (
|
|
234
|
+
<InputLabel htmlFor={ids.id} id={ids.inputLabelId} {...props.InputLabelProps}>
|
|
235
|
+
{label}
|
|
236
|
+
</InputLabel>
|
|
237
|
+
) : null}
|
|
238
|
+
<InputComponent {...fieldPropsOf(props, ids)} />
|
|
239
|
+
{helperText ? (
|
|
240
|
+
<FormHelperText id={ids.helperTextId} {...props.FormHelperTextProps}>
|
|
241
|
+
{helperText}
|
|
242
|
+
</FormHelperText>
|
|
243
|
+
) : null}
|
|
244
|
+
</TextFieldSlimRoot>
|
|
245
|
+
);
|
|
246
|
+
},
|
|
247
|
+
);
|
|
248
|
+
}
|
|
@@ -33,22 +33,13 @@
|
|
|
33
33
|
* dev-only warning about `children` that only the select branch could emit.
|
|
34
34
|
*/
|
|
35
35
|
import FilledInput from '@mui/material/FilledInput/index.js';
|
|
36
|
-
import FormControl from '@mui/material/FormControl/index.js';
|
|
37
|
-
import FormHelperText from '@mui/material/FormHelperText/index.js';
|
|
38
36
|
import StandardInput from '@mui/material/Input/index.js';
|
|
39
|
-
import InputLabel from '@mui/material/InputLabel/index.js';
|
|
40
37
|
import OutlinedInput from '@mui/material/OutlinedInput/index.js';
|
|
41
|
-
import { styled } from '@mui/material/styles/index.js';
|
|
42
|
-
import type { FilledInputProps } from '@mui/material/FilledInput/index.js';
|
|
43
|
-
import type { FormControlProps } from '@mui/material/FormControl/index.js';
|
|
44
|
-
import type { FormHelperTextProps } from '@mui/material/FormHelperText/index.js';
|
|
45
|
-
import type { InputProps as MuiInputProps } from '@mui/material/Input/index.js';
|
|
46
|
-
import type { InputBaseComponentProps } from '@mui/material/InputBase/index.js';
|
|
47
|
-
import type { InputLabelProps } from '@mui/material/InputLabel/index.js';
|
|
48
|
-
import type { OutlinedInputProps } from '@mui/material/OutlinedInput/index.js';
|
|
49
|
-
import React from 'react';
|
|
50
38
|
|
|
51
|
-
import {
|
|
39
|
+
import { createTextFieldSlim } from './text-field-slim.factory';
|
|
40
|
+
import type { TextFieldSlimComponent } from './text-field-slim.factory';
|
|
41
|
+
|
|
42
|
+
export type { TextFieldSlimProps } from './text-field-slim.factory';
|
|
52
43
|
|
|
53
44
|
const VARIANT_COMPONENT = {
|
|
54
45
|
standard: StandardInput,
|
|
@@ -57,201 +48,10 @@ const VARIANT_COMPONENT = {
|
|
|
57
48
|
} as const;
|
|
58
49
|
|
|
59
50
|
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* and the deep path that does would import `TextField` — the whole thing this
|
|
64
|
-
* file exists to avoid. So the class name is written out, and the parity test
|
|
65
|
-
* asserts it against a REAL `TextField`'s root rather than against itself.
|
|
66
|
-
*
|
|
67
|
-
* It has to be there at all because it is part of MUI's public surface: two of
|
|
68
|
-
* this package's own suites reach for `.closest('.MuiTextField-root')`, and a
|
|
69
|
-
* consumer's stylesheet may too.
|
|
70
|
-
*/
|
|
71
|
-
const TEXT_FIELD_ROOT_CLASS = 'MuiTextField-root';
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Named `MuiTextField` so a theme's `components.MuiTextField.styleOverrides`
|
|
75
|
-
* keeps applying. Nothing in this repo sets one today; a consumer's theme is
|
|
76
|
-
* not this package's to break.
|
|
77
|
-
*/
|
|
78
|
-
const TextFieldSlimRoot = styled(FormControl, {
|
|
79
|
-
name: 'MuiTextField',
|
|
80
|
-
slot: 'Root',
|
|
81
|
-
overridesResolver: (_props, styles) => styles.root,
|
|
82
|
-
})({});
|
|
83
|
-
|
|
84
|
-
export interface TextFieldSlimProps
|
|
85
|
-
extends Omit<FormControlProps, 'onChange' | 'onBlur' | 'onFocus' | 'defaultValue'> {
|
|
86
|
-
autoComplete?: string;
|
|
87
|
-
autoFocus?: boolean;
|
|
88
|
-
defaultValue?: unknown;
|
|
89
|
-
helperText?: React.ReactNode;
|
|
90
|
-
label?: React.ReactNode;
|
|
91
|
-
maxRows?: number | string;
|
|
92
|
-
minRows?: number | string;
|
|
93
|
-
multiline?: boolean;
|
|
94
|
-
name?: string;
|
|
95
|
-
placeholder?: string;
|
|
96
|
-
rows?: number | string;
|
|
97
|
-
type?: React.InputHTMLAttributes<HTMLInputElement>['type'];
|
|
98
|
-
value?: unknown;
|
|
99
|
-
inputRef?: React.Ref<unknown>;
|
|
100
|
-
onBlur?: React.FocusEventHandler<HTMLInputElement | HTMLTextAreaElement>;
|
|
101
|
-
onChange?: React.ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement>;
|
|
102
|
-
onFocus?: React.FocusEventHandler<HTMLInputElement | HTMLTextAreaElement>;
|
|
103
|
-
/** Props for the rendered input variant. */
|
|
104
|
-
InputProps?: Partial<MuiInputProps & FilledInputProps & OutlinedInputProps>;
|
|
105
|
-
/**
|
|
106
|
-
* Props for the `<input>` itself — where an `aria-label` has to ride.
|
|
107
|
-
*
|
|
108
|
-
* MUI's own type, because it is deliberately open: a caller puts `data-*`
|
|
109
|
-
* and `aria-*` here precisely because the root would swallow them, and
|
|
110
|
-
* `InputHTMLAttributes` alone rejects both.
|
|
111
|
-
*/
|
|
112
|
-
inputProps?: InputBaseComponentProps;
|
|
113
|
-
InputLabelProps?: Partial<InputLabelProps>;
|
|
114
|
-
FormHelperTextProps?: Partial<FormHelperTextProps>;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* `TextField`'s own defaults, as a table.
|
|
119
|
-
*
|
|
120
|
-
* One `= default` per destructured prop is one branch per prop, and eight of
|
|
121
|
-
* them put this component over the complexity bar before it rendered anything —
|
|
122
|
-
* which is the same reason `AppHeader` keeps its defaults in a table. The values
|
|
123
|
-
* are `TextField`'s, unchanged; the parity test would fail if any drifted.
|
|
124
|
-
*/
|
|
125
|
-
const DEFAULTS: Partial<TextFieldSlimProps> = {
|
|
126
|
-
autoFocus: false,
|
|
127
|
-
color: 'primary',
|
|
128
|
-
disabled: false,
|
|
129
|
-
error: false,
|
|
130
|
-
fullWidth: false,
|
|
131
|
-
multiline: false,
|
|
132
|
-
required: false,
|
|
133
|
-
variant: 'outlined',
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
/** The two ids a labelled, described field needs, and the input's own. */
|
|
137
|
-
function idsOf(props: TextFieldSlimProps, generated: string): {
|
|
138
|
-
id: string;
|
|
139
|
-
helperTextId: string | undefined;
|
|
140
|
-
inputLabelId: string | undefined;
|
|
141
|
-
} {
|
|
142
|
-
const id = props.id ?? generated;
|
|
143
|
-
return {
|
|
144
|
-
id,
|
|
145
|
-
helperTextId: props.helperText && id ? `${id}-helper-text` : undefined,
|
|
146
|
-
inputLabelId: props.label && id ? `${id}-label` : undefined,
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* What only the OUTLINED variant needs: it draws its own notch around the
|
|
152
|
-
* label, so it has to be told the label and whether the caller pinned it shrunk
|
|
153
|
-
* (FUT-729's `shrink` case).
|
|
154
|
-
*/
|
|
155
|
-
function outlinedPropsOf(props: TextFieldSlimProps): Record<string, unknown> {
|
|
156
|
-
if (props.variant !== 'outlined') return {};
|
|
157
|
-
const shrink = props.InputLabelProps?.shrink;
|
|
158
|
-
return { label: props.label, ...(shrink === undefined ? {} : { notched: shrink }) };
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
interface FieldIds {
|
|
162
|
-
id: string;
|
|
163
|
-
helperTextId: string | undefined;
|
|
164
|
-
inputLabelId: string | undefined;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Everything the input (or this component) consumes by name.
|
|
169
|
-
*
|
|
170
|
-
* A key LIST rather than the omit-by-destructuring idiom, which would name
|
|
171
|
-
* twenty-four bindings only to leave every one of them unused — twenty-four
|
|
172
|
-
* lint warnings, in a package that allows none.
|
|
173
|
-
*
|
|
174
|
-
* `fullWidth`, `disabled`, `error`, `required`, `color` and `variant` are
|
|
175
|
-
* deliberately absent: `TextField` hands those to the root, and `fullWidth` to
|
|
176
|
-
* both.
|
|
177
|
-
*/
|
|
178
|
-
const CONSUMED_BY_FIELD: ReadonlySet<string> = new Set([
|
|
179
|
-
'autoComplete', 'autoFocus', 'children', 'className', 'defaultValue',
|
|
180
|
-
'FormHelperTextProps', 'helperText', 'id', 'InputLabelProps', 'inputProps',
|
|
181
|
-
'InputProps', 'inputRef', 'label', 'maxRows', 'minRows', 'multiline', 'name',
|
|
182
|
-
'onBlur', 'onChange', 'onFocus', 'placeholder', 'rows', 'type', 'value',
|
|
183
|
-
]);
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* What the ROOT `FormControl` gets: the props `TextField` hands it by name,
|
|
187
|
-
* plus everything it did not recognise.
|
|
188
|
-
*
|
|
189
|
-
* That second half is `TextField`'s behaviour and not a choice made here: an
|
|
190
|
-
* unrecognised HTML attribute lands on the root `div`, which is why `Input` has
|
|
191
|
-
* to route `aria-label` through `inputProps`. The parity test pins it.
|
|
51
|
+
* The generic field: any of MUI's three variants, chosen at runtime. A field
|
|
52
|
+
* that only ever renders outlined uses `./outlined` instead, which never
|
|
53
|
+
* imports the other two (FUT-1054).
|
|
192
54
|
*/
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
Object.entries(props).filter(([key]) => !CONSUMED_BY_FIELD.has(key)),
|
|
196
|
-
);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/** What the INPUT gets, by name, exactly as `TextField` names them. */
|
|
200
|
-
function fieldPropsOf(props: TextFieldSlimProps, ids: FieldIds): Record<string, unknown> {
|
|
201
|
-
return {
|
|
202
|
-
'aria-describedby': ids.helperTextId,
|
|
203
|
-
autoComplete: props.autoComplete,
|
|
204
|
-
autoFocus: props.autoFocus,
|
|
205
|
-
defaultValue: props.defaultValue,
|
|
206
|
-
fullWidth: props.fullWidth,
|
|
207
|
-
multiline: props.multiline,
|
|
208
|
-
name: props.name,
|
|
209
|
-
rows: props.rows,
|
|
210
|
-
maxRows: props.maxRows,
|
|
211
|
-
minRows: props.minRows,
|
|
212
|
-
type: props.type,
|
|
213
|
-
value: props.value,
|
|
214
|
-
id: ids.id,
|
|
215
|
-
inputRef: props.inputRef,
|
|
216
|
-
onBlur: props.onBlur,
|
|
217
|
-
onChange: props.onChange,
|
|
218
|
-
onFocus: props.onFocus,
|
|
219
|
-
placeholder: props.placeholder,
|
|
220
|
-
inputProps: props.inputProps,
|
|
221
|
-
...outlinedPropsOf(props),
|
|
222
|
-
...props.InputProps,
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
export const TextFieldSlim = React.forwardRef<HTMLDivElement, TextFieldSlimProps>(
|
|
227
|
-
function TextFieldSlim(rawProps, ref) {
|
|
228
|
-
const props = withDefaults(rawProps, DEFAULTS);
|
|
229
|
-
// `TextField` uses `@mui/utils`'s `useId`, which is React's with a fallback
|
|
230
|
-
// for React 17. The peer here is React 19, so React's own is the same thing
|
|
231
|
-
// without the dependency. The override still wins, exactly as it did — and
|
|
232
|
-
// it is read from the RAW props, before `withDefaults` could supply one.
|
|
233
|
-
const ids = idsOf(rawProps, React.useId());
|
|
234
|
-
const InputComponent = VARIANT_COMPONENT[props.variant ?? 'outlined'];
|
|
235
|
-
const { label, helperText } = props;
|
|
236
|
-
|
|
237
|
-
return (
|
|
238
|
-
<TextFieldSlimRoot
|
|
239
|
-
className={[TEXT_FIELD_ROOT_CLASS, props.className].filter(Boolean).join(' ')}
|
|
240
|
-
ref={ref}
|
|
241
|
-
{...rootPropsOf(props)}
|
|
242
|
-
>
|
|
243
|
-
{label !== null && label !== undefined && label !== '' ? (
|
|
244
|
-
<InputLabel htmlFor={ids.id} id={ids.inputLabelId} {...props.InputLabelProps}>
|
|
245
|
-
{label}
|
|
246
|
-
</InputLabel>
|
|
247
|
-
) : null}
|
|
248
|
-
<InputComponent {...fieldPropsOf(props, ids)} />
|
|
249
|
-
{helperText ? (
|
|
250
|
-
<FormHelperText id={ids.helperTextId} {...props.FormHelperTextProps}>
|
|
251
|
-
{helperText}
|
|
252
|
-
</FormHelperText>
|
|
253
|
-
) : null}
|
|
254
|
-
</TextFieldSlimRoot>
|
|
255
|
-
);
|
|
256
|
-
},
|
|
55
|
+
export const TextFieldSlim: TextFieldSlimComponent = createTextFieldSlim(
|
|
56
|
+
(variant) => VARIANT_COMPONENT[variant],
|
|
257
57
|
);
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
destinationControl,
|
|
19
19
|
focusRing,
|
|
20
20
|
} from './SectionNav.parts';
|
|
21
|
-
import { RaisedActionButton } from './SectionNav.primary';
|
|
21
|
+
import { raisedLift, RaisedActionButton } from './SectionNav.primary';
|
|
22
22
|
import { SectionNavSheet } from './SectionNav.sheet';
|
|
23
23
|
import type { SectionNavAction, SectionNavBadge, SectionNavDestination, SectionNavMenu, SectionNavProps } from './SectionNav.types';
|
|
24
24
|
|
|
@@ -45,6 +45,12 @@ export function sectionNavBarInset(theme: Parameters<typeof rem>[0], options: Se
|
|
|
45
45
|
return `calc(${barHeight(theme, options.compact === true)} + env(safe-area-inset-bottom))`;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
/** Where the bar's sheets stop: clear of the raised button's {@link raisedLift}, which drew over their last row (FUT-3399). */
|
|
49
|
+
export function sectionNavSheetOffset(theme: Parameters<typeof rem>[0], raised: boolean, options: SectionNavBarOptions = {}): string {
|
|
50
|
+
const inset = sectionNavBarInset(theme, options);
|
|
51
|
+
return raised ? `calc(${inset} + ${rem(theme, raisedLift(options.compact === true))})` : inset;
|
|
52
|
+
}
|
|
53
|
+
|
|
48
54
|
/**
|
|
49
55
|
* One slot: icon over label, a count on the icon.
|
|
50
56
|
*
|
|
@@ -373,7 +379,7 @@ export function SectionNavBar({
|
|
|
373
379
|
linkComponent={linkComponent}
|
|
374
380
|
copy={copy}
|
|
375
381
|
testId={`${dataTestId}-primary-sheet`}
|
|
376
|
-
bottomOffset={
|
|
382
|
+
bottomOffset={sectionNavSheetOffset(theme, primary !== undefined, { compact })}
|
|
377
383
|
/>
|
|
378
384
|
) : null}
|
|
379
385
|
{more ? (
|
|
@@ -384,7 +390,7 @@ export function SectionNavBar({
|
|
|
384
390
|
linkComponent={linkComponent}
|
|
385
391
|
copy={copy}
|
|
386
392
|
testId={`${dataTestId}-more-sheet`}
|
|
387
|
-
bottomOffset={
|
|
393
|
+
bottomOffset={sectionNavSheetOffset(theme, primary !== undefined, { compact })}
|
|
388
394
|
/>
|
|
389
395
|
) : null}
|
|
390
396
|
</>
|
|
@@ -19,7 +19,7 @@ action, the sheets, and the rail's sections.
|
|
|
19
19
|
|
|
20
20
|
| `layout` | draws | menus |
|
|
21
21
|
|---|---|---|
|
|
22
|
-
| `bar` | a bottom row: the destinations, `more` last, `primary` raised in the middle | open as bottom sheets over the page, stopping above the bar |
|
|
22
|
+
| `bar` | a bottom row: the destinations, `more` last, `primary` raised in the middle | open as bottom sheets over the page, stopping above the bar — and above the raised `primary` when there is one, so it never draws over a sheet |
|
|
23
23
|
| `rail` | a vertical list: `back`, `heading`, a `primary` menu as one button, the destinations, then `more` | `primary` opens as a menu anchored to its button (named by `title`); `more` is listed under its `title` |
|
|
24
24
|
|
|
25
25
|
Which layout to use is the HOST's call. A bar beside a sidebar is two
|
|
@@ -156,6 +156,19 @@ function RaisedCaption({ shown, label, inert }: { shown: boolean; label: string;
|
|
|
156
156
|
);
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
+
/**
|
|
160
|
+
* How far the round button stands out of the bar's top edge, in design px — what
|
|
161
|
+
* the bar's sheets must clear so the button never draws over one (FUT-3399).
|
|
162
|
+
* The compact bar's smaller button stands out less.
|
|
163
|
+
*/
|
|
164
|
+
export const RAISED_LIFT = 18;
|
|
165
|
+
export const RAISED_LIFT_COMPACT = 12;
|
|
166
|
+
|
|
167
|
+
/** The lift of the round button on a bar of this form. */
|
|
168
|
+
export function raisedLift(compact: boolean): number {
|
|
169
|
+
return compact ? RAISED_LIFT_COMPACT : RAISED_LIFT;
|
|
170
|
+
}
|
|
171
|
+
|
|
159
172
|
/** The round button: lifted half out of the bar, its icon turning while what it opened is open. */
|
|
160
173
|
function raisedSx(theme: Theme, expanded: boolean, compact: boolean): SxProps<Theme> {
|
|
161
174
|
const size = rem(theme, compact ? 40 : 52);
|
|
@@ -167,7 +180,7 @@ function raisedSx(theme: Theme, expanded: boolean, compact: boolean): SxProps<Th
|
|
|
167
180
|
width: size,
|
|
168
181
|
height: size,
|
|
169
182
|
// Lifted half out of the bar: the one control that is not a place.
|
|
170
|
-
marginTop: rem(theme, compact
|
|
183
|
+
marginTop: rem(theme, -raisedLift(compact)),
|
|
171
184
|
borderRadius: '50%',
|
|
172
185
|
display: 'flex',
|
|
173
186
|
alignItems: 'center',
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/navigation/SectionNav/SectionNav.bar.tsx"],"sourcesContent":["import Typography from '@mui/material/Typography/index.js';\nimport { alpha, useTheme, type SxProps, type Theme } from '@mui/material/styles/index.js';\nimport { useState, type ElementType, type ReactNode } from 'react';\n\nimport type { SectionNavCopy } from '../../../copy';\nimport { stackedOverlayZIndex } from '../../../tokens/layers';\nimport { rem } from '../../../tokens/scales';\n\nimport { barSlots, destinationState, isMenu, menuActive, menuCount, type BarSlot } from './SectionNav.helpers';\nimport {\n Box,\n CONTROL_RESET,\n CountedIcon,\n NOT_LIVE,\n SlotIcon,\n controlProps,\n useMounted,\n destinationControl,\n focusRing,\n} from './SectionNav.parts';\nimport { RaisedActionButton } from './SectionNav.primary';\nimport { SectionNavSheet } from './SectionNav.sheet';\nimport type { SectionNavAction, SectionNavBadge, SectionNavDestination, SectionNavMenu, SectionNavProps } from './SectionNav.types';\n\n/** Which of the bar's two menus is open, if any. */\ntype OpenMenu = 'primary' | 'more' | null;\n\n/**\n * The bar's height above the safe area — tall enough for an icon over a label;\n * a compact bar holds the icon alone.\n */\nconst barHeight = (theme: Parameters<typeof rem>[0], compact = false): string => rem(theme, compact ? 48 : 60);\n\n/** How the bar is drawn — `compact` is `SectionNavProps.compact`. */\nexport interface SectionNavBarOptions {\n compact?: boolean;\n}\n\n/**\n * The bar's full height on screen, the safe area included — where its sheets\n * stop, and what a host reserves at the foot of its content so nothing it\n * floats (a toast, a receipt) lands under the bar.\n */\nexport function sectionNavBarInset(theme: Parameters<typeof rem>[0], options: SectionNavBarOptions = {}): string {\n return `calc(${barHeight(theme, options.compact === true)} + env(safe-area-inset-bottom))`;\n}\n\n/**\n * One slot: icon over label, a count on the icon.\n *\n * `current` is the page the viewer is on and is what `aria-current` reports —\n * a link's claim only; an action slot that is ON says so with `aria-pressed`,\n * which arrives in `control`. `lit` is only how the slot looks, and goes out\n * while a sheet is open so the bar shows where the thumb is. Opening a sheet\n * is `aria-expanded`'s to say.\n *\n * A destination is a link or an action; the \"more\" slot is a button that\n * opens its sheet. Either way the whole slot is the target, so a thumb landing\n * on the label lands on the control. A `disabled` slot is a disabled button,\n * dimmed — the act is still where the hand expects it. A `loading` or\n * `dimmed` slot is drawn the same and stays focusable (`aria-disabled`).\n */\nfunction Slot({\n label,\n icon,\n count,\n current,\n lit,\n copy,\n testId,\n control,\n expanded,\n loading = false,\n compact = false,\n}: {\n label: string;\n icon: ReactNode;\n count: SectionNavBadge | undefined;\n current: boolean;\n lit: boolean;\n copy: SectionNavCopy;\n testId: string;\n control: Record<string, unknown>;\n expanded?: boolean;\n loading?: boolean;\n /** Icon only: the label stays the slot's name, out of sight, and its tooltip. */\n compact?: boolean;\n}): React.JSX.Element {\n const theme = useTheme();\n const animate = useMounted();\n return (\n <Box\n {...control}\n title={compact ? label : undefined}\n aria-current={current ? 'page' : undefined}\n aria-expanded={expanded}\n aria-busy={loading || undefined}\n data-lit={lit ? 'true' : undefined}\n data-testid={testId}\n sx={slotSx(theme, lit, compact)}\n >\n <CountedIcon\n icon={\n <Box component=\"span\" data-slot-pill=\"\" sx={pillSx(theme)}>\n <SlotIcon icon={icon} loading={loading} />\n </Box>\n }\n count={count}\n label={copy.badge}\n attentionLabel={copy.attention}\n testId={`${testId}-badge`}\n />\n <Typography\n component=\"span\"\n variant=\"caption\"\n sx={{\n maxWidth: '100%',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n lineHeight: 1.3,\n fontWeight: lit ? 700 : 600,\n color: lit ? 'text.primary' : 'inherit',\n ...labelFoldSx(theme, compact, animate),\n }}\n >\n {label}\n </Typography>\n </Box>\n );\n}\n\n/**\n * The label folding away in a compact bar: it shrinks to no height and fades\n * while the bar shrinks, rather than leaving in one frame. Never `display:\n * none` — it is still the slot's accessible name. With reduced motion it\n * simply goes.\n */\nfunction labelFoldSx(theme: Theme, compact: boolean, animate: boolean): Record<string, unknown> {\n return {\n maxHeight: compact ? 0 : rem(theme, 24),\n opacity: compact ? 0 : 1,\n transition: animate\n ? theme.transitions.create(['max-height', 'opacity'], { duration: theme.transitions.duration.shorter })\n : 'none',\n '@media (prefers-reduced-motion: reduce)': { transition: 'none' },\n };\n}\n\n/** The pill behind a slot's icon — tinted while the slot is lit. */\nfunction pillSx(theme: Theme): SxProps<Theme> {\n return {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n px: 1.75,\n py: 0.25,\n borderRadius: rem(theme, 999),\n transition: theme.transitions.create('background-color', { duration: theme.transitions.duration.shorter }),\n };\n}\n\n/** A slot's look: icon over label, a pill behind the lit icon, dimmed when disabled. */\nfunction slotSx(theme: Theme, lit: boolean, compact: boolean): SxProps<Theme> {\n return {\n ...CONTROL_RESET,\n ...focusRing(theme),\n flex: 1,\n minWidth: 0,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: compact ? 0 : 0.25,\n position: 'relative',\n color: lit ? 'primary.main' : 'text.secondary',\n // The current slot is marked by more than its colour: a tinted pill behind\n // its icon and a bolder label, so the state survives a colour-blind reading.\n '&[data-lit=\"true\"] [data-slot-pill]': { bgcolor: alpha(theme.palette.primary.main, 0.14) },\n '& svg': { fontSize: rem(theme, 22) },\n [NOT_LIVE]: { color: 'text.disabled' },\n } as SxProps<Theme>;\n}\n\n/** What every slot kind is handed: the bar's open state and how to change it. */\ninterface SlotContext {\n open: OpenMenu;\n toggle: (menu: Exclude<OpenMenu, null>) => void;\n close: () => void;\n linkComponent: ElementType | undefined;\n copy: SectionNavCopy;\n dataTestId: string;\n compact: boolean;\n}\n\n/** The raised button: an action runs on tap; a menu opens its sheet. */\nfunction PrimarySlot({\n primary,\n context,\n}: {\n primary: SectionNavMenu | SectionNavAction;\n context: SlotContext;\n}): React.JSX.Element {\n const testId = primary.dataTestId ?? `${context.dataTestId}-primary`;\n if (!isMenu(primary)) {\n return (\n <RaisedActionButton\n label={primary.label}\n icon={primary.icon}\n captioned\n compact={context.compact}\n disabled={primary.disabled}\n loading={primary.loading}\n dataTestId={testId}\n onClick={() => {\n context.close();\n primary.onSelect();\n }}\n />\n );\n }\n return (\n <RaisedActionButton\n label={primary.label}\n icon={primary.icon}\n open={context.open === 'primary'}\n closeLabel={context.copy.close}\n compact={context.compact}\n disabled={primary.disabled}\n dataTestId={testId}\n onClick={() => context.toggle('primary')}\n />\n );\n}\n\n/** The \"more\" slot: a button that opens its sheet, carrying its entries' counts. */\nfunction MoreSlot({ more, context }: { more: SectionNavMenu; context: SlotContext }): React.JSX.Element {\n const { open } = context;\n return (\n <Slot\n label={more.label}\n icon={more.icon}\n count={menuCount(more)}\n current={false}\n lit={open === 'more' || (open === null && menuActive(more))}\n expanded={open === 'more'}\n copy={context.copy}\n testId={more.dataTestId ?? `${context.dataTestId}-more`}\n compact={context.compact}\n control={controlProps({\n href: undefined,\n linkComponent: context.linkComponent,\n inert: more.disabled === true,\n onClick: () => context.toggle('more'),\n })}\n />\n );\n}\n\n/** A destination: a link, or an action slot (a toggle when it carries `active`). */\nfunction DestinationSlot({\n destination,\n context,\n}: {\n destination: SectionNavDestination;\n context: SlotContext;\n}): React.JSX.Element {\n const { current, lit } = destinationState(destination);\n return (\n <Slot\n label={destination.label}\n icon={destination.icon}\n count={destination.badge}\n current={current}\n lit={context.open === null && lit}\n copy={context.copy}\n testId={destination.dataTestId ?? `${context.dataTestId}-dest-${destination.id}`}\n loading={destination.loading === true}\n compact={context.compact}\n control={destinationControl(destination, context.linkComponent, () => {\n context.close();\n destination.onSelect?.();\n })}\n />\n );\n}\n\n/** One slot of the bar, whichever kind it is. */\nfunction BarSlotView({\n slot,\n primary,\n more,\n context,\n}: {\n slot: BarSlot;\n primary: SectionNavMenu | SectionNavAction | undefined;\n more: SectionNavMenu | undefined;\n context: SlotContext;\n}): React.JSX.Element | null {\n if (slot.kind === 'primary') return primary ? <PrimarySlot primary={primary} context={context} /> : null;\n if (slot.kind === 'more') return more ? <MoreSlot more={more} context={context} /> : null;\n return <DestinationSlot destination={slot.destination} context={context} />;\n}\n\n/** The bar's own box: docked, a hairline on top, raised over the backdrop only while its sheet is open. */\nfunction barSx(theme: Theme, sheetOpen: boolean, compact: boolean, animate: boolean): SxProps<Theme> {\n return {\n flex: 'none',\n display: 'flex',\n alignItems: 'stretch',\n boxSizing: 'border-box',\n height: sectionNavBarInset(theme, { compact }),\n // Folding to icons and back is a change of height the eye follows;\n // with reduced motion it simply happens.\n transition: animate ? theme.transitions.create('height', { duration: theme.transitions.duration.shorter }) : 'none',\n '@media (prefers-reduced-motion: reduce)': { transition: 'none' },\n paddingBottom: 'env(safe-area-inset-bottom)',\n borderTop: `1px solid ${theme.palette.divider}`,\n bgcolor: 'background.paper',\n // Above the backdrop ONLY while one of its own sheets is open, so the\n // primary button can close what it opened. Raised all the time it\n // would sit over every dialog the page opens, and on a small phone a\n // dialog's own footer is exactly where the bar is. `stackedOverlayZIndex`,\n // not `zIndex.modal + 1`: a host lifting a bottom Drawer clear of a\n // stacked sheet catches this bar's OWN sheets too.\n position: 'relative',\n zIndex: sheetOpen ? stackedOverlayZIndex(theme) + 1 : 'auto',\n } as SxProps<Theme>;\n}\n\n/** The phone layout: a bottom bar, with its menus as bottom sheets. */\nexport function SectionNavBar({\n label,\n destinations,\n primary,\n more,\n linkComponent,\n copy,\n dataTestId,\n compact = false,\n}: Required<Pick<SectionNavProps, 'label' | 'destinations' | 'copy' | 'dataTestId'>> &\n Pick<SectionNavProps, 'primary' | 'more' | 'compact'> & { linkComponent: ElementType | undefined }): React.JSX.Element {\n const sheetMenu = isMenu(primary) ? primary : undefined;\n const theme = useTheme();\n const animate = useMounted();\n const [open, setOpen] = useState<OpenMenu>(null);\n const toggle = (menu: Exclude<OpenMenu, null>): void => setOpen((current) => (current === menu ? null : menu));\n const close = (): void => setOpen(null);\n\n return (\n <>\n <Box\n component=\"nav\"\n aria-label={label}\n data-testid={dataTestId}\n sx={barSx(theme, open !== null, compact, animate)}\n >\n {barSlots(destinations, more !== undefined, primary !== undefined).map((slot) => (\n <BarSlotView\n key={slot.kind === 'destination' ? `dest-${slot.destination.id}` : `menu-${slot.kind}`}\n slot={slot}\n primary={primary}\n more={more}\n context={{ open, toggle, close, linkComponent, copy, dataTestId, compact }}\n />\n ))}\n </Box>\n {sheetMenu ? (\n <SectionNavSheet\n menu={sheetMenu}\n open={open === 'primary'}\n onClose={close}\n linkComponent={linkComponent}\n copy={copy}\n testId={`${dataTestId}-primary-sheet`}\n bottomOffset={sectionNavBarInset(theme, { compact })}\n />\n ) : null}\n {more ? (\n <SectionNavSheet\n menu={more}\n open={open === 'more'}\n onClose={close}\n linkComponent={linkComponent}\n copy={copy}\n testId={`${dataTestId}-more-sheet`}\n bottomOffset={sectionNavBarInset(theme, { compact })}\n />\n ) : null}\n </>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/form/Input/Input.tsx"],"sourcesContent":["import CircularProgress from '@mui/material/CircularProgress/index.js';\nimport InputAdornment from '@mui/material/InputAdornment/index.js';\nimport { styled, useTheme } from '@mui/material/styles/index.js';\nimport React from 'react';\n\nimport { INPUT_LOADING } from './Input.metrics';\nimport { TextFieldSlim } from './text-field-slim';\n\nimport {\n filledStyles,\n floatingLabelStyles,\n glowStyles,\n inputBaseStyles,\n inputRadiusStyles,\n muiVariantFor,\n outlinedStyles,\n pulseStyles,\n SIZE_MAP,\n} from './Input.styles';\nimport type { InputProps } from './Input.types';\nimport { splitTestId } from '../../../platform/test-id';\nimport { fieldControlStyles } from '../../../tokens/field-height';\nimport { rem } from '../../../tokens/relative';\nimport type { SizeValue } from '../../../tokens/vocabulary';\n\n/**\n * `TextFieldSlim`, not `TextField` — see `text-field-slim.tsx`. MUI's own\n * `TextField` imports `Select` unconditionally, and through it `Menu`,\n * `Popover`, `Modal` and seven more component modules, so every screen with one\n * text box shipped a dropdown it can never render. Same composition, same DOM,\n * same prop routing; the select branch is the only thing missing.\n */\nconst StyledTextField = styled(TextFieldSlim, {\n shouldForwardProp: (prop) =>\n !['customVariant', 'fieldSize', 'floating', 'glow', 'pulse', 'loading'].includes(prop as string),\n})<{\n customVariant?: InputProps['variant'];\n fieldSize: SizeValue;\n floating?: boolean;\n glow?: boolean;\n pulse?: boolean;\n loading?: boolean;\n}>(({ theme, customVariant, fieldSize, floating, glow, pulse, loading }) => ({\n position: 'relative',\n // The theme's field height for this size (outlined family, one line).\n ...fieldControlStyles(theme, fieldSize),\n opacity: loading ? INPUT_LOADING.opacity : 1,\n\n ...(glow ? glowStyles(theme) : {}),\n ...(pulse ? pulseStyles(theme, fieldSize) : {}),\n ...(floating ? floatingLabelStyles(theme) : {}),\n\n '& .MuiInputBase-root': {\n transition: 'all 0.3s ease',\n ...inputRadiusStyles(theme, customVariant),\n ...inputBaseStyles(theme, customVariant),\n },\n\n '& .MuiOutlinedInput-root': outlinedStyles(theme),\n '& .MuiFilledInput-root': filledStyles(theme),\n}));\n\n/** Only one adornment shows at a time: the spinner replaces the caller's while loading. */\nconst EndAdornment: React.FC<{ loading: boolean; endAdornment?: React.ReactNode }> = ({\n loading,\n endAdornment,\n}) => {\n const theme = useTheme();\n if (loading) {\n return (\n <InputAdornment position=\"end\">\n <CircularProgress size={rem(theme, INPUT_LOADING.spinnerSize)} />\n </InputAdornment>\n );\n }\n\n if (!endAdornment) return null;\n\n return <InputAdornment position=\"end\">{endAdornment}</InputAdornment>;\n};\n\n/** While loading the field is inert: no clicks, and disabled to assistive tech. */\nconst interactionProps = (\n loading: boolean,\n onClick: InputProps['onClick'],\n disabled?: boolean,\n) => ({\n disabled: loading || disabled,\n onClick: loading ? undefined : onClick,\n});\n\n/**\n * The ARIA that describes the field has to sit on the `<input>`: the text\n * field puts every attribute it does not recognise on its root `FormControl`,\n * a `<div>` with no role, where a screen reader never reads it.\n *\n * `aria-label` has ridden `inputProps` since FUT-755. `aria-describedby` and\n * `aria-busy` fell through to the div until FUT-2619, so CepField's input\n * pointed at nothing while its lookup status lived in a live region beside it.\n *\n * `inputProps` are spread onto the `<input>` AFTER the `aria-describedby` MUI\n * writes for helper text, so a caller's ids REPLACE the helper text's: MUI's\n * `TextField` on its own keeps only one of the two. This joins both, helper\n * text first. The helper id is MUI's `<id>-helper-text` (the parity test pins\n * that spelling), which is why the field's id is fixed here rather than left\n * to the text field.\n */\nfunction inputAriaOf(a: {\n id: string;\n helperText: React.ReactNode;\n label?: string;\n describedBy?: string;\n busy?: InputProps['aria-busy'];\n}): Record<string, unknown> {\n const describedBy = [a.helperText ? `${a.id}-helper-text` : undefined, a.describedBy]\n .filter(Boolean)\n .join(' ');\n return {\n ...(a.label === undefined ? {} : { 'aria-label': a.label }),\n ...(a.describedBy === undefined ? {} : { 'aria-describedby': describedBy }),\n ...(a.busy === undefined ? {} : { 'aria-busy': a.busy }),\n };\n}\n\nexport const Input = React.forwardRef<HTMLInputElement, InputProps>(\n (\n {\n variant = 'outlined',\n size = 'md',\n label,\n error,\n helperText,\n startAdornment,\n endAdornment,\n fullWidth = true,\n floating = false,\n glow = false,\n pulse = false,\n loading = false,\n onClick,\n onFocus,\n onBlur,\n 'aria-label': ariaLabel,\n 'aria-describedby': ariaDescribedBy,\n 'aria-busy': ariaBusy,\n inputProps,\n ...rest\n },\n ref,\n ) => {\n const { testId: dataTestId, rest: props } = splitTestId(rest);\n const generatedId = React.useId();\n const id = props.id ?? generatedId;\n return (\n <StyledTextField\n ref={ref}\n variant={muiVariantFor(variant)}\n customVariant={variant}\n fieldSize={size}\n floating={floating}\n glow={glow}\n pulse={pulse}\n loading={loading}\n label={label}\n error={error}\n helperText={helperText}\n fullWidth={fullWidth}\n {...interactionProps(loading, onClick, props.disabled)}\n onFocus={onFocus}\n onBlur={onBlur}\n /*\n * `aria-label` has to ride `inputProps` to reach the `<input>` (FUT-755).\n * Spread with the rest it lands on the FormControl DIV that the text\n * field renders as its root, which carries no role — so the field kept\n * no accessible name, and a source grep saying \"this input is labelled\"\n * disagreed with the DOM. The reports search box and the block-title\n * inputs were both named in source and anonymous to a screen reader.\n * `aria-describedby` and `aria-busy` are the same case: `inputAriaOf`.\n */\n inputProps={{\n 'data-testid': dataTestId,\n ...inputProps,\n ...inputAriaOf({ id, helperText, label: ariaLabel, describedBy: ariaDescribedBy, busy: ariaBusy }),\n }}\n InputProps={{\n startAdornment: startAdornment && (\n <InputAdornment position=\"start\">{startAdornment}</InputAdornment>\n ),\n endAdornment: <EndAdornment loading={loading} endAdornment={endAdornment} />,\n }}\n {...SIZE_MAP[size]}\n {...props}\n id={id}\n />\n );\n },\n);\n\nInput.displayName = 'Input';\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/form/CepField/CepField.tsx"],"sourcesContent":["'use client';\n\nimport type { CepFieldCopy } from \"../../../copy\";\nimport React, { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { cepDigits, formatCep, isValidCep } from '@12-apps/forms-core';\n\nimport { FormControl, FormLabel, FormMessage } from '../Form';\nimport { Input } from '../Input';\nimport type { CepAddress, CepFieldProps, CepLookupStatus } from './CepField.types';\n\n/** Everything {@link useCepLookup} needs, so the hook signature stays flat. */\ninterface LookupOptions {\n digits: string;\n complete: boolean;\n disabled: boolean;\n debounceMs: number;\n onLookup?: (cep: string) => Promise<CepAddress | null>;\n onResolved?: (address: CepAddress) => void;\n onNotFound?: () => void;\n}\n\n/**\n * Debounced, race-safe CEP resolution.\n *\n * Two guards earn their keep here: a monotonic sequence id, bumped\n * synchronously on every new query, so a slow response for a since-edited CEP\n * can never land; and a \"last queried\" marker, so re-rendering (or the caller\n * re-masking the same value) never re-hits the provider.\n */\nfunction useCepLookup({\n digits,\n complete,\n disabled,\n debounceMs,\n onLookup,\n onResolved,\n onNotFound,\n}: LookupOptions): CepLookupStatus {\n const [status, setStatus] = useState<CepLookupStatus>('idle');\n const lastQueriedRef = useRef('');\n const seqRef = useRef(0);\n // Latest callbacks, read at call time — keeps them out of the effect deps so\n // an inline arrow from the caller doesn't re-trigger the lookup every render.\n const lookupRef = useRef(onLookup);\n const resolvedRef = useRef(onResolved);\n const notFoundRef = useRef(onNotFound);\n lookupRef.current = onLookup;\n resolvedRef.current = onResolved;\n notFoundRef.current = onNotFound;\n\n useEffect(() => {\n if (!complete || disabled || !lookupRef.current) {\n // Editing away from a complete CEP drops any stale status and forgets the\n // last query, so re-typing the same CEP resolves again.\n seqRef.current += 1;\n setStatus('idle');\n lastQueriedRef.current = '';\n return;\n }\n if (lastQueriedRef.current === digits) return;\n\n const mySeq = (seqRef.current += 1);\n const handle = setTimeout(() => {\n lastQueriedRef.current = digits;\n setStatus('loading');\n void (async () => {\n // A failing lookup is treated exactly like \"not found\" — the user types\n // the address instead. Never surfaced as a crash. Going through\n // `Promise.resolve().then` rather than calling directly covers the two\n // failure modes an `await … .catch()` misses: a lookup that throws\n // SYNCHRONOUSLY, and one that returns something other than a promise.\n const address = await Promise.resolve()\n .then(() => lookupRef.current?.(digits))\n .catch(() => null);\n if (seqRef.current !== mySeq) return;\n setStatus(address ? 'found' : 'notfound');\n // A miss is reported too, so a caller that filled from a PREVIOUS CEP\n // can undo it rather than leaving that address under this CEP.\n if (address) resolvedRef.current?.(address);\n else notFoundRef.current?.();\n })();\n }, debounceMs);\n\n return () => clearTimeout(handle);\n }, [digits, complete, disabled, debounceMs]);\n\n return status;\n}\n\n/**\n * The lookup outcome as a live region, so screen readers announce it without\n * stealing focus. Silent while idle, and while the caller is showing its own\n * validation error (which would otherwise stack two messages).\n */\nfunction CepStatus({\n status,\n testId,\n suppressed,\n copy,\n}: {\n status: CepLookupStatus;\n testId: string;\n suppressed: boolean;\n copy: CepFieldCopy;\n}): React.ReactElement {\n const visible = !suppressed && status !== 'idle';\n return (\n <span id={`${testId}-status`} role=\"status\" aria-live=\"polite\">\n {visible && (\n <FormMessage error={status === 'notfound'} dataTestId={`${testId}-${status}`}>\n {copy[status as Exclude<CepLookupStatus, 'idle'>]}\n </FormMessage>\n )}\n </span>\n );\n}\n\n/**\n * A CEP input that fills the rest of the address in.\n *\n * The pattern every Brazilian form has used for twenty years: type eight\n * digits, and logradouro/bairro/cidade/UF arrive on their own. This is the\n * reusable half — masking, validation, debouncing, race-safety and status —\n * with the actual lookup injected via `onLookup`, so the same component serves\n * a supplier form, a store-location form or a delivery checkout without\n * knowing anything about providers or auth.\n *\n * Resolution is best-effort by design. A provider outage, an unknown CEP or a\n * timeout leaves the field exactly as usable as a plain text input — the user\n * types the address themselves. Autofill never blocks.\n *\n * @example\n * ```tsx\n * <CepField\n * value={cep}\n * onChange={setCep}\n * onLookup={(c) => fetch(`/api/…/lookup/cep/${c}`).then((r) => r.json()).then((b) => b.data)}\n * onResolved={(a) => { setStreet(a.street ?? ''); setCity(a.city ?? ''); }}\n * />\n * ```\n */\nexport function CepField({\n value,\n onChange,\n onLookup,\n onResolved,\n onNotFound,\n label = 'CEP',\n placeholder = '00000-000',\n error,\n disabled = false,\n debounceMs = 500,\n name = 'postalCode',\n dataTestId,\n copy,\n}: CepFieldProps): React.ReactElement {\n const testId = dataTestId ?? `cep-field-${name}`;\n\n const status = useCepLookup({\n digits: cepDigits(value),\n complete: isValidCep(value),\n disabled,\n debounceMs,\n onLookup,\n onResolved,\n onNotFound,\n });\n\n const handleChange = useCallback(\n (event: React.ChangeEvent<HTMLInputElement>) => onChange(formatCep(event.target.value)),\n [onChange],\n );\n\n return (\n <FormControl fullWidth>\n {label && (\n <FormLabel htmlFor={name} error={Boolean(error)}>\n {label}\n </FormLabel>\n )}\n <Input\n id={name}\n name={name}\n type=\"text\"\n inputMode=\"numeric\"\n autoComplete=\"postal-code\"\n placeholder={placeholder}\n value={value}\n error={Boolean(error)}\n disabled={disabled}\n loading={status === 'loading'}\n onChange={handleChange}\n data-testid={testId}\n aria-describedby={`${testId}-status`}\n aria-busy={status === 'loading'}\n />\n {error && (\n <FormMessage error dataTestId={`${testId}-message`}>\n {error}\n </FormMessage>\n )}\n <CepStatus status={status} testId={testId} suppressed={Boolean(error)} copy={copy} />\n </FormControl>\n );\n}\n\nexport default CepField;\n"],"mappings":";;;;;;;;;;AAGA,SAAgB,aAAa,WAAW,QAAQ,gBAAgB;AAEhE,SAAS,WAAW,WAAW,kBAAkB;AAyGzC,cAiEJ,YAjEI;AAhFR,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAmC;AACjC,QAAM,CAAC,QAAQ,SAAS,IAAI,SAA0B,MAAM;AAC5D,QAAM,iBAAiB,OAAO,EAAE;AAChC,QAAM,SAAS,OAAO,CAAC;AAGvB,QAAM,YAAY,OAAO,QAAQ;AACjC,QAAM,cAAc,OAAO,UAAU;AACrC,QAAM,cAAc,OAAO,UAAU;AACrC,YAAU,UAAU;AACpB,cAAY,UAAU;AACtB,cAAY,UAAU;AAEtB,YAAU,MAAM;AACd,QAAI,CAAC,YAAY,YAAY,CAAC,UAAU,SAAS;AAG/C,aAAO,WAAW;AAClB,gBAAU,MAAM;AAChB,qBAAe,UAAU;AACzB;AAAA,IACF;AACA,QAAI,eAAe,YAAY,OAAQ;AAEvC,UAAM,QAAS,OAAO,WAAW;AACjC,UAAM,SAAS,WAAW,MAAM;AAC9B,qBAAe,UAAU;AACzB,gBAAU,SAAS;AACnB,YAAM,YAAY;AAMhB,cAAM,UAAU,MAAM,QAAQ,QAAQ,EACnC,KAAK,MAAM,UAAU,UAAU,MAAM,CAAC,EACtC,MAAM,MAAM,IAAI;AACnB,YAAI,OAAO,YAAY,MAAO;AAC9B,kBAAU,UAAU,UAAU,UAAU;AAGxC,YAAI,QAAS,aAAY,UAAU,OAAO;AAAA,YACrC,aAAY,UAAU;AAAA,MAC7B,GAAG;AAAA,IACL,GAAG,UAAU;AAEb,WAAO,MAAM,aAAa,MAAM;AAAA,EAClC,GAAG,CAAC,QAAQ,UAAU,UAAU,UAAU,CAAC;AAE3C,SAAO;AACT;AAOA,SAAS,UAAU;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKuB;AACrB,QAAM,UAAU,CAAC,cAAc,WAAW;AAC1C,SACE,oBAAC,UAAK,IAAI,GAAG,MAAM,WAAW,MAAK,UAAS,aAAU,UACnD,qBACC,oBAAC,eAAY,OAAO,WAAW,YAAY,YAAY,GAAG,MAAM,IAAI,MAAM,IACvE,eAAK,MAA0C,GAClD,GAEJ;AAEJ;AA0BO,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR,cAAc;AAAA,EACd;AAAA,EACA,WAAW;AAAA,EACX,aAAa;AAAA,EACb,OAAO;AAAA,EACP;AAAA,EACA;AACF,GAAsC;AACpC,QAAM,SAAS,cAAc,aAAa,IAAI;AAE9C,QAAM,SAAS,aAAa;AAAA,IAC1B,QAAQ,UAAU,KAAK;AAAA,IACvB,UAAU,WAAW,KAAK;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,eAAe;AAAA,IACnB,CAAC,UAA+C,SAAS,UAAU,MAAM,OAAO,KAAK,CAAC;AAAA,IACtF,CAAC,QAAQ;AAAA,EACX;AAEA,SACE,qBAAC,eAAY,WAAS,MACnB;AAAA,aACC,oBAAC,aAAU,SAAS,MAAM,OAAO,QAAQ,KAAK,GAC3C,iBACH;AAAA,IAEF;AAAA,MAAC;AAAA;AAAA,QACC,IAAI;AAAA,QACJ;AAAA,QACA,MAAK;AAAA,QACL,WAAU;AAAA,QACV,cAAa;AAAA,QACb;AAAA,QACA;AAAA,QACA,OAAO,QAAQ,KAAK;AAAA,QACpB;AAAA,QACA,SAAS,WAAW;AAAA,QACpB,UAAU;AAAA,QACV,eAAa;AAAA,QACb,oBAAkB,GAAG,MAAM;AAAA,QAC3B,aAAW,WAAW;AAAA;AAAA,IACxB;AAAA,IACC,SACC,oBAAC,eAAY,OAAK,MAAC,YAAY,GAAG,MAAM,YACrC,iBACH;AAAA,IAEF,oBAAC,aAAU,QAAgB,QAAgB,YAAY,QAAQ,KAAK,GAAG,MAAY;AAAA,KACrF;AAEJ;AAEA,IAAO,mBAAQ;","names":[]}
|