@proef/common-ui 0.0.0-stage → 2.2.1
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/dist/esm/assets/imagem-6ee08a37d9.png +0 -0
- package/dist/esm/assets/imagem-6fcae1b87b.png +0 -0
- package/dist/esm/index.js +324 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/legacy/assets/svgs/proef-footer-logo.svg.js +5 -0
- package/dist/esm/legacy/assets/svgs/proef-footer-logo.svg.js.map +1 -0
- package/dist/esm/legacy/components/atoms/Acronym/Acronym.css +43 -0
- package/dist/esm/legacy/components/atoms/Acronym/Acronym.js +31 -0
- package/dist/esm/legacy/components/atoms/Acronym/Acronym.js.map +1 -0
- package/dist/esm/legacy/components/atoms/BreadCrumb/BreadCrumb.css +36 -0
- package/dist/esm/legacy/components/atoms/BreadCrumb/BreadCrumb.js +57 -0
- package/dist/esm/legacy/components/atoms/BreadCrumb/BreadCrumb.js.map +1 -0
- package/dist/esm/legacy/components/atoms/Button/variants/ActionButton.css +218 -0
- package/dist/esm/legacy/components/atoms/Button/variants/ActionButton.js +50 -0
- package/dist/esm/legacy/components/atoms/Button/variants/ActionButton.js.map +1 -0
- package/dist/esm/legacy/components/atoms/Button/variants/FilterButton.css +56 -0
- package/dist/esm/legacy/components/atoms/Button/variants/FilterButton.js +34 -0
- package/dist/esm/legacy/components/atoms/Button/variants/FilterButton.js.map +1 -0
- package/dist/esm/legacy/components/atoms/Button/variants/IconButton.css +74 -0
- package/dist/esm/legacy/components/atoms/Button/variants/IconButton.js +29 -0
- package/dist/esm/legacy/components/atoms/Button/variants/IconButton.js.map +1 -0
- package/dist/esm/legacy/components/atoms/Button/variants/MainButton.css +99 -0
- package/dist/esm/legacy/components/atoms/Button/variants/MainButton.js +36 -0
- package/dist/esm/legacy/components/atoms/Button/variants/MainButton.js.map +1 -0
- package/dist/esm/legacy/components/atoms/Button/variants/TabButton.css +63 -0
- package/dist/esm/legacy/components/atoms/Button/variants/TabButton.js +21 -0
- package/dist/esm/legacy/components/atoms/Button/variants/TabButton.js.map +1 -0
- package/dist/esm/legacy/components/atoms/Field/Field.css +171 -0
- package/dist/esm/legacy/components/atoms/Field/Field.js +70 -0
- package/dist/esm/legacy/components/atoms/Field/Field.js.map +1 -0
- package/dist/esm/legacy/components/atoms/IconText/IconText.css +10 -0
- package/dist/esm/legacy/components/atoms/IconText/IconText.js +25 -0
- package/dist/esm/legacy/components/atoms/IconText/IconText.js.map +1 -0
- package/dist/esm/legacy/components/atoms/Icone/Icone.js +24 -0
- package/dist/esm/legacy/components/atoms/Icone/Icone.js.map +1 -0
- package/dist/esm/legacy/components/atoms/Input/Input.css +12 -0
- package/dist/esm/legacy/components/atoms/Input/Input.js +28 -0
- package/dist/esm/legacy/components/atoms/Input/Input.js.map +1 -0
- package/dist/esm/legacy/components/atoms/InputData/InputData.js +25 -0
- package/dist/esm/legacy/components/atoms/InputData/InputData.js.map +1 -0
- package/dist/esm/legacy/components/atoms/Label/Label.css +192 -0
- package/dist/esm/legacy/components/atoms/Label/Label.js +13 -0
- package/dist/esm/legacy/components/atoms/Label/Label.js.map +1 -0
- package/dist/esm/legacy/components/atoms/MultiTagPickerTag/MultiTagPickerTag.css +40 -0
- package/dist/esm/legacy/components/atoms/MultiTagPickerTag/MultiTagPickerTag.js +21 -0
- package/dist/esm/legacy/components/atoms/MultiTagPickerTag/MultiTagPickerTag.js.map +1 -0
- package/dist/esm/legacy/components/atoms/Select/Select.css +16 -0
- package/dist/esm/legacy/components/atoms/Select/Select.js +27 -0
- package/dist/esm/legacy/components/atoms/Select/Select.js.map +1 -0
- package/dist/esm/legacy/components/atoms/Stack/Stack.js +20 -0
- package/dist/esm/legacy/components/atoms/Stack/Stack.js.map +1 -0
- package/dist/esm/legacy/components/atoms/Switch/CustomSwitch.css +36 -0
- package/dist/esm/legacy/components/atoms/Switch/CustomSwitch.js +29 -0
- package/dist/esm/legacy/components/atoms/Switch/CustomSwitch.js.map +1 -0
- package/dist/esm/legacy/components/charts/Charts.js +349 -0
- package/dist/esm/legacy/components/charts/Charts.js.map +1 -0
- package/dist/esm/legacy/components/layout/AppLauncher/AppLauncher.js +100 -0
- package/dist/esm/legacy/components/layout/AppLauncher/AppLauncher.js.map +1 -0
- package/dist/esm/legacy/components/layout/Error/Error.css +20 -0
- package/dist/esm/legacy/components/layout/Error/Error.js +12 -0
- package/dist/esm/legacy/components/layout/Error/Error.js.map +1 -0
- package/dist/esm/legacy/components/layout/Footer/Footer.css +42 -0
- package/dist/esm/legacy/components/layout/Footer/Footer.js +23 -0
- package/dist/esm/legacy/components/layout/Footer/Footer.js.map +1 -0
- package/dist/esm/legacy/components/layout/Header/Header.css +66 -0
- package/dist/esm/legacy/components/layout/Header/Header.js +37 -0
- package/dist/esm/legacy/components/layout/Header/Header.js.map +1 -0
- package/dist/esm/legacy/components/layout/Layout/Layout.js +31 -0
- package/dist/esm/legacy/components/layout/Layout/Layout.js.map +1 -0
- package/dist/esm/legacy/components/layout/Sidebar/Sidebar.js +38 -0
- package/dist/esm/legacy/components/layout/Sidebar/Sidebar.js.map +1 -0
- package/dist/esm/legacy/components/layout/Spinner/Spinner.css +10 -0
- package/dist/esm/legacy/components/layout/Spinner/Spinner.js +19 -0
- package/dist/esm/legacy/components/layout/Spinner/Spinner.js.map +1 -0
- package/dist/esm/legacy/components/layout/TopBar/TopBar.js +34 -0
- package/dist/esm/legacy/components/layout/TopBar/TopBar.js.map +1 -0
- package/dist/esm/legacy/components/layout/TopNavLayout/TopNavLayout.js +82 -0
- package/dist/esm/legacy/components/layout/TopNavLayout/TopNavLayout.js.map +1 -0
- package/dist/esm/legacy/components/molecules/BarraValor/BarraValor.js +25 -0
- package/dist/esm/legacy/components/molecules/BarraValor/BarraValor.js.map +1 -0
- package/dist/esm/legacy/components/molecules/ColumnPicker/ColumnPicker.js +246 -0
- package/dist/esm/legacy/components/molecules/ColumnPicker/ColumnPicker.js.map +1 -0
- package/dist/esm/legacy/components/molecules/ConfirmModal/ConfirmModal.css +3 -0
- package/dist/esm/legacy/components/molecules/ConfirmModal/ConfirmModal.js +33 -0
- package/dist/esm/legacy/components/molecules/ConfirmModal/ConfirmModal.js.map +1 -0
- package/dist/esm/legacy/components/molecules/DataTable/DataTable.js +1259 -0
- package/dist/esm/legacy/components/molecules/DataTable/DataTable.js.map +1 -0
- package/dist/esm/legacy/components/molecules/FileDropzone/FileDropzone.js +68 -0
- package/dist/esm/legacy/components/molecules/FileDropzone/FileDropzone.js.map +1 -0
- package/dist/esm/legacy/components/molecules/LanguageSwitcher/LanguageSwitcher.js +96 -0
- package/dist/esm/legacy/components/molecules/LanguageSwitcher/LanguageSwitcher.js.map +1 -0
- package/dist/esm/legacy/components/molecules/Modal/Modal.css +54 -0
- package/dist/esm/legacy/components/molecules/Modal/Modal.js +64 -0
- package/dist/esm/legacy/components/molecules/Modal/Modal.js.map +1 -0
- package/dist/esm/legacy/components/molecules/MultiTagPicker/MultiTagPicker.css +97 -0
- package/dist/esm/legacy/components/molecules/MultiTagPicker/MultiTagPicker.js +113 -0
- package/dist/esm/legacy/components/molecules/MultiTagPicker/MultiTagPicker.js.map +1 -0
- package/dist/esm/legacy/components/molecules/PhotoAvatar/PhotoAvatar.js +114 -0
- package/dist/esm/legacy/components/molecules/PhotoAvatar/PhotoAvatar.js.map +1 -0
- package/dist/esm/legacy/components/molecules/SeletorPesquisa/SeletorPesquisa.js +116 -0
- package/dist/esm/legacy/components/molecules/SeletorPesquisa/SeletorPesquisa.js.map +1 -0
- package/dist/esm/legacy/components/molecules/Sidebar/Sidebar.css +69 -0
- package/dist/esm/legacy/components/molecules/Sidebar/Sidebar.js +62 -0
- package/dist/esm/legacy/components/molecules/Sidebar/Sidebar.js.map +1 -0
- package/dist/esm/legacy/components/molecules/UserAvatar/UserAvatar.js +23 -0
- package/dist/esm/legacy/components/molecules/UserAvatar/UserAvatar.js.map +1 -0
- package/dist/esm/legacy/components/organisms/GanttChart/GanttChart.js +162 -0
- package/dist/esm/legacy/components/organisms/GanttChart/GanttChart.js.map +1 -0
- package/dist/esm/legacy/components/organisms/Kanban/Kanban.js +88 -0
- package/dist/esm/legacy/components/organisms/Kanban/Kanban.js.map +1 -0
- package/dist/esm/legacy/components/organisms/LazyLoader/LazyLoader.js +87 -0
- package/dist/esm/legacy/components/organisms/LazyLoader/LazyLoader.js.map +1 -0
- package/dist/esm/legacy/components/organisms/MapaPontos/MapaPontos.js +427 -0
- package/dist/esm/legacy/components/organisms/MapaPontos/MapaPontos.js.map +1 -0
- package/dist/esm/legacy/components/organisms/PainelFiltros/PainelFiltros.js +218 -0
- package/dist/esm/legacy/components/organisms/PainelFiltros/PainelFiltros.js.map +1 -0
- package/dist/esm/legacy/components/organisms/PesquisaRapida/PesquisaRapida.js +147 -0
- package/dist/esm/legacy/components/organisms/PesquisaRapida/PesquisaRapida.js.map +1 -0
- package/dist/esm/legacy/components/organisms/Profile/Profile.css +26 -0
- package/dist/esm/legacy/components/organisms/Profile/Profile.js +26 -0
- package/dist/esm/legacy/components/organisms/Profile/Profile.js.map +1 -0
- package/dist/esm/legacy/components/organisms/RoleGuard/RoleGuard.js +79 -0
- package/dist/esm/legacy/components/organisms/RoleGuard/RoleGuard.js.map +1 -0
- package/dist/esm/legacy/components/organisms/Selector/Selector.css +87 -0
- package/dist/esm/legacy/components/organisms/Selector/Selector.js +181 -0
- package/dist/esm/legacy/components/organisms/Selector/Selector.js.map +1 -0
- package/dist/esm/legacy/components/organisms/StatusMatrix/StatusMatrix.js +115 -0
- package/dist/esm/legacy/components/organisms/StatusMatrix/StatusMatrix.js.map +1 -0
- package/dist/esm/legacy/components/ui/Avisos.js +33 -0
- package/dist/esm/legacy/components/ui/Avisos.js.map +1 -0
- package/dist/esm/legacy/components/ui/BarraAcoes.js +19 -0
- package/dist/esm/legacy/components/ui/BarraAcoes.js.map +1 -0
- package/dist/esm/legacy/components/ui/CabecalhoPagina.js +19 -0
- package/dist/esm/legacy/components/ui/CabecalhoPagina.js.map +1 -0
- package/dist/esm/legacy/components/ui/CaixaPesquisa.js +9 -0
- package/dist/esm/legacy/components/ui/CaixaPesquisa.js.map +1 -0
- package/dist/esm/legacy/components/ui/Confirmacao.js +34 -0
- package/dist/esm/legacy/components/ui/Confirmacao.js.map +1 -0
- package/dist/esm/legacy/components/ui/Escolha.js +41 -0
- package/dist/esm/legacy/components/ui/Escolha.js.map +1 -0
- package/dist/esm/legacy/components/ui/FaixaAviso.js +19 -0
- package/dist/esm/legacy/components/ui/FaixaAviso.js.map +1 -0
- package/dist/esm/legacy/components/ui/MenuAcoes.js +116 -0
- package/dist/esm/legacy/components/ui/MenuAcoes.js.map +1 -0
- package/dist/esm/legacy/components/ui/Passos.js +32 -0
- package/dist/esm/legacy/components/ui/Passos.js.map +1 -0
- package/dist/esm/legacy/components/ui/Separadores.js +17 -0
- package/dist/esm/legacy/components/ui/Separadores.js.map +1 -0
- package/dist/esm/legacy/components/ui/TextoAuto.js +33 -0
- package/dist/esm/legacy/components/ui/TextoAuto.js.map +1 -0
- package/dist/esm/legacy/components/ui/Ui.js +263 -0
- package/dist/esm/legacy/components/ui/Ui.js.map +1 -0
- package/dist/esm/legacy/components/ui/painelFlutuante.js +13 -0
- package/dist/esm/legacy/components/ui/painelFlutuante.js.map +1 -0
- package/dist/esm/legacy/constants/Colors.js +33 -0
- package/dist/esm/legacy/constants/Colors.js.map +1 -0
- package/dist/esm/legacy/constants/FontWeight.js +35 -0
- package/dist/esm/legacy/constants/FontWeight.js.map +1 -0
- package/dist/esm/legacy/contexts/apiContext.js +25 -0
- package/dist/esm/legacy/contexts/apiContext.js.map +1 -0
- package/dist/esm/legacy/contexts/authContext.js +85 -0
- package/dist/esm/legacy/contexts/authContext.js.map +1 -0
- package/dist/esm/legacy/contexts/socketContext.js +34 -0
- package/dist/esm/legacy/contexts/socketContext.js.map +1 -0
- package/dist/esm/legacy/hooks/useApi.js +62 -0
- package/dist/esm/legacy/hooks/useApi.js.map +1 -0
- package/dist/esm/legacy/pages/Error/ErrorPage.css +18 -0
- package/dist/esm/legacy/pages/Error/ErrorPage.js +50 -0
- package/dist/esm/legacy/pages/Error/ErrorPage.js.map +1 -0
- package/dist/esm/legacy/pages/Loading/Loading.css +46 -0
- package/dist/esm/legacy/pages/Loading/Loading.js +9 -0
- package/dist/esm/legacy/pages/Loading/Loading.js.map +1 -0
- package/dist/esm/legacy/pages/Login/LoginScreen.js +46 -0
- package/dist/esm/legacy/pages/Login/LoginScreen.js.map +1 -0
- package/dist/esm/legacy/pages/NotFound/NotFound.css +21 -0
- package/dist/esm/legacy/pages/NotFound/NotFound.js +24 -0
- package/dist/esm/legacy/pages/NotFound/NotFound.js.map +1 -0
- package/dist/esm/legacy/styles/themes/ButtonThemes.js +28 -0
- package/dist/esm/legacy/styles/themes/ButtonThemes.js.map +1 -0
- package/dist/esm/legacy/styles/utils/utils.js +7 -0
- package/dist/esm/legacy/styles/utils/utils.js.map +1 -0
- package/dist/esm/legacy/utils/stringUtils.js +35 -0
- package/dist/esm/legacy/utils/stringUtils.js.map +1 -0
- package/dist/esm/v1/capabilities/documents/QRScanning/scanQRCodes.js +157 -0
- package/dist/esm/v1/capabilities/documents/QRScanning/scanQRCodes.js.map +1 -0
- package/dist/esm/v1/capabilities/overlay/useFloatingPanel.js +52 -0
- package/dist/esm/v1/capabilities/overlay/useFloatingPanel.js.map +1 -0
- package/dist/esm/v1/capabilities/theme/useIsDark.js +15 -0
- package/dist/esm/v1/capabilities/theme/useIsDark.js.map +1 -0
- package/dist/esm/v1/capabilities/theme/useTheme.js +66 -0
- package/dist/esm/v1/capabilities/theme/useTheme.js.map +1 -0
- package/dist/esm/v1/components/data/Pagination/Pagination.js +66 -0
- package/dist/esm/v1/components/data/Pagination/Pagination.js.map +1 -0
- package/dist/esm/v1/components/documents/DocumentDropzone/DocumentDropzone.js +307 -0
- package/dist/esm/v1/components/documents/DocumentDropzone/DocumentDropzone.js.map +1 -0
- package/dist/esm/v1/components/feedback/Toast/Toast.js +105 -0
- package/dist/esm/v1/components/feedback/Toast/Toast.js.map +1 -0
- package/dist/esm/v1/components/forms/FormField/FormField.js +59 -0
- package/dist/esm/v1/components/forms/FormField/FormField.js.map +1 -0
- package/dist/esm/v1/components/forms/FormGrid/FormGrid.js +20 -0
- package/dist/esm/v1/components/forms/FormGrid/FormGrid.js.map +1 -0
- package/dist/esm/v1/components/layout/AppShell/AppShell.js +89 -0
- package/dist/esm/v1/components/layout/AppShell/AppShell.js.map +1 -0
- package/dist/esm/v1/components/layout/Page/Page.js +16 -0
- package/dist/esm/v1/components/layout/Page/Page.js.map +1 -0
- package/dist/esm/v1/components/layout/PageHeader/PageHeader.js +26 -0
- package/dist/esm/v1/components/layout/PageHeader/PageHeader.js.map +1 -0
- package/dist/esm/v1/components/layout/SideNav/SideNav.js +287 -0
- package/dist/esm/v1/components/layout/SideNav/SideNav.js.map +1 -0
- package/dist/esm/v1/components/layout/navTrail.js +19 -0
- package/dist/esm/v1/components/layout/navTrail.js.map +1 -0
- package/dist/esm/v1/components/lists/ListFinder/ListFinder.js +271 -0
- package/dist/esm/v1/components/lists/ListFinder/ListFinder.js.map +1 -0
- package/dist/esm/v1/components/lists/ListFinder/labels.js +18 -0
- package/dist/esm/v1/components/lists/ListFinder/labels.js.map +1 -0
- package/dist/esm/v1/components/overlays/ConfirmDialog/ConfirmDialog.js +95 -0
- package/dist/esm/v1/components/overlays/ConfirmDialog/ConfirmDialog.js.map +1 -0
- package/dist/esm/v1/components/overlays/Dialog/Dialog.js +141 -0
- package/dist/esm/v1/components/overlays/Dialog/Dialog.js.map +1 -0
- package/dist/esm/v1/components/overlays/Tooltip/Tooltip.js +98 -0
- package/dist/esm/v1/components/overlays/Tooltip/Tooltip.js.map +1 -0
- package/dist/esm/v1/components/overlays/Tooltip/TooltipLayer.js +84 -0
- package/dist/esm/v1/components/overlays/Tooltip/TooltipLayer.js.map +1 -0
- package/dist/esm/v1/components/overlays/Tooltip/TooltipPanel.js +33 -0
- package/dist/esm/v1/components/overlays/Tooltip/TooltipPanel.js.map +1 -0
- package/dist/esm/v1/components/overlays/topLayer.js +28 -0
- package/dist/esm/v1/components/overlays/topLayer.js.map +1 -0
- package/dist/esm/v1/components/tables/PaginatedTable/PaginatedTable.js +50 -0
- package/dist/esm/v1/components/tables/PaginatedTable/PaginatedTable.js.map +1 -0
- package/dist/esm/v1/components/tables/Table/ColumnFilter.js +292 -0
- package/dist/esm/v1/components/tables/Table/ColumnFilter.js.map +1 -0
- package/dist/esm/v1/components/tables/Table/OverlayScrollbar.js +129 -0
- package/dist/esm/v1/components/tables/Table/OverlayScrollbar.js.map +1 -0
- package/dist/esm/v1/components/tables/Table/Table.js +1410 -0
- package/dist/esm/v1/components/tables/Table/Table.js.map +1 -0
- package/dist/esm/v1/components/tables/Table/labels.js +44 -0
- package/dist/esm/v1/components/tables/Table/labels.js.map +1 -0
- package/dist/esm/v1/foundations/icons/icons.js +227 -0
- package/dist/esm/v1/foundations/icons/icons.js.map +1 -0
- package/dist/esm/v1/primitives/buttons/Button/Button.js +41 -0
- package/dist/esm/v1/primitives/buttons/Button/Button.js.map +1 -0
- package/dist/esm/v1/primitives/buttons/SegmentedControl/SegmentedControl.js +65 -0
- package/dist/esm/v1/primitives/buttons/SegmentedControl/SegmentedControl.js.map +1 -0
- package/dist/esm/v1/primitives/buttons/SegmentedControl/segmentedStyles.js +10 -0
- package/dist/esm/v1/primitives/buttons/SegmentedControl/segmentedStyles.js.map +1 -0
- package/dist/esm/v1/primitives/display/Avatar/Avatar.js +120 -0
- package/dist/esm/v1/primitives/display/Avatar/Avatar.js.map +1 -0
- package/dist/esm/v1/primitives/display/Badge/Badge.js +23 -0
- package/dist/esm/v1/primitives/display/Badge/Badge.js.map +1 -0
- package/dist/esm/v1/primitives/display/Card/Card.js +22 -0
- package/dist/esm/v1/primitives/display/Card/Card.js.map +1 -0
- package/dist/esm/v1/primitives/display/FilterChips/FilterChips.js +45 -0
- package/dist/esm/v1/primitives/display/FilterChips/FilterChips.js.map +1 -0
- package/dist/esm/v1/primitives/display/Kpi/Kpi.js +103 -0
- package/dist/esm/v1/primitives/display/Kpi/Kpi.js.map +1 -0
- package/dist/esm/v1/primitives/display/Notice/Notice.js +71 -0
- package/dist/esm/v1/primitives/display/Notice/Notice.js.map +1 -0
- package/dist/esm/v1/primitives/display/Person/Person.js +14 -0
- package/dist/esm/v1/primitives/display/Person/Person.js.map +1 -0
- package/dist/esm/v1/primitives/display/RichText/RichText.js +12 -0
- package/dist/esm/v1/primitives/display/RichText/RichText.js.map +1 -0
- package/dist/esm/v1/primitives/display/RichText/utils.js +56 -0
- package/dist/esm/v1/primitives/display/RichText/utils.js.map +1 -0
- package/dist/esm/v1/primitives/documents/PdfPreview/PdfPreview.js +137 -0
- package/dist/esm/v1/primitives/documents/PdfPreview/PdfPreview.js.map +1 -0
- package/dist/esm/v1/primitives/documents/PdfPreview/pdfjs.js +26 -0
- package/dist/esm/v1/primitives/documents/PdfPreview/pdfjs.js.map +1 -0
- package/dist/esm/v1/primitives/forms/Checkbox/Checkbox.js +37 -0
- package/dist/esm/v1/primitives/forms/Checkbox/Checkbox.js.map +1 -0
- package/dist/esm/v1/primitives/forms/DateInput/DateInput.js +150 -0
- package/dist/esm/v1/primitives/forms/DateInput/DateInput.js.map +1 -0
- package/dist/esm/v1/primitives/forms/LookupInput/LookupInput.js +37 -0
- package/dist/esm/v1/primitives/forms/LookupInput/LookupInput.js.map +1 -0
- package/dist/esm/v1/primitives/forms/RichTextEditor/RichTextEditor.js +253 -0
- package/dist/esm/v1/primitives/forms/RichTextEditor/RichTextEditor.js.map +1 -0
- package/dist/esm/v1/primitives/forms/SearchInput/SearchInput.js +43 -0
- package/dist/esm/v1/primitives/forms/SearchInput/SearchInput.js.map +1 -0
- package/dist/esm/v1/primitives/forms/SelectInput/SelectInput.js +207 -0
- package/dist/esm/v1/primitives/forms/SelectInput/SelectInput.js.map +1 -0
- package/dist/esm/v1/primitives/forms/TextArea/TextArea.js +75 -0
- package/dist/esm/v1/primitives/forms/TextArea/TextArea.js.map +1 -0
- package/dist/esm/v1/primitives/forms/TextInput/TextInput.js +21 -0
- package/dist/esm/v1/primitives/forms/TextInput/TextInput.js.map +1 -0
- package/dist/esm/v1/primitives/forms/field.js +14 -0
- package/dist/esm/v1/primitives/forms/field.js.map +1 -0
- package/dist/esm/v1/primitives/lists/ListItem/ListItem.js +73 -0
- package/dist/esm/v1/primitives/lists/ListItem/ListItem.js.map +1 -0
- package/dist/esm/v1/primitives/navigation/Tabs/Tabs.js +96 -0
- package/dist/esm/v1/primitives/navigation/Tabs/Tabs.js.map +1 -0
- package/dist/style.components.css +3 -0
- package/dist/style.css +2 -0
- package/dist/style.layered.css +2 -0
- package/dist/tailwind.css +24 -0
- package/dist/theme-boot.js +1 -0
- package/dist/theme.css +265 -0
- package/dist/tokens.css +121 -0
- package/dist/types/index.d.ts +14 -0
- package/dist/types/legacy/components/atoms/Acronym/Acronym.d.ts +11 -0
- package/dist/types/legacy/components/atoms/BreadCrumb/BreadCrumb.d.ts +9 -0
- package/dist/types/legacy/components/atoms/Button/variants/ActionButton.d.ts +14 -0
- package/dist/types/legacy/components/atoms/Button/variants/FilterButton.d.ts +12 -0
- package/dist/types/legacy/components/atoms/Button/variants/IconButton.d.ts +22 -0
- package/dist/types/legacy/components/atoms/Button/variants/MainButton.d.ts +17 -0
- package/dist/types/legacy/components/atoms/Button/variants/TabButton.d.ts +14 -0
- package/dist/types/legacy/components/atoms/Field/Field.d.ts +15 -0
- package/dist/types/legacy/components/atoms/IconText/IconText.d.ts +12 -0
- package/dist/types/legacy/components/atoms/Icone/Icone.d.ts +31 -0
- package/dist/types/legacy/components/atoms/Input/Input.d.ts +13 -0
- package/dist/types/legacy/components/atoms/InputData/InputData.d.ts +38 -0
- package/dist/types/legacy/components/atoms/Label/Label.d.ts +11 -0
- package/dist/types/legacy/components/atoms/MultiTagPickerTag/MultiTagPickerTag.d.ts +10 -0
- package/dist/types/legacy/components/atoms/SearchSelect/SearchSelect.d.ts +15 -0
- package/dist/types/legacy/components/atoms/Select/Select.d.ts +16 -0
- package/dist/types/legacy/components/atoms/Stack/Stack.d.ts +9 -0
- package/dist/types/legacy/components/atoms/Switch/CustomSwitch.d.ts +12 -0
- package/dist/types/legacy/components/charts/Charts.d.ts +149 -0
- package/dist/types/legacy/components/layout/AppLauncher/AppLauncher.d.ts +35 -0
- package/dist/types/legacy/components/layout/Error/Error.d.ts +8 -0
- package/dist/types/legacy/components/layout/Footer/Footer.d.ts +11 -0
- package/dist/types/legacy/components/layout/Header/Header.d.ts +16 -0
- package/dist/types/legacy/components/layout/Layout/Layout.d.ts +35 -0
- package/dist/types/legacy/components/layout/Sidebar/Sidebar.d.ts +56 -0
- package/dist/types/legacy/components/layout/Spinner/Spinner.d.ts +5 -0
- package/dist/types/legacy/components/layout/TopBar/TopBar.d.ts +10 -0
- package/dist/types/legacy/components/layout/TopNavLayout/TopNavLayout.d.ts +43 -0
- package/dist/types/legacy/components/molecules/BarraValor/BarraValor.d.ts +28 -0
- package/dist/types/legacy/components/molecules/ColumnPicker/ColumnPicker.d.ts +116 -0
- package/dist/types/legacy/components/molecules/ConfirmModal/ConfirmModal.d.ts +13 -0
- package/dist/types/legacy/components/molecules/DataTable/DataTable.d.ts +344 -0
- package/dist/types/legacy/components/molecules/FileDropzone/FileDropzone.d.ts +25 -0
- package/dist/types/legacy/components/molecules/LanguageSwitcher/LanguageSwitcher.d.ts +33 -0
- package/dist/types/legacy/components/molecules/Modal/Modal.d.ts +22 -0
- package/dist/types/legacy/components/molecules/MultiTagPicker/MultiTagPicker.d.ts +25 -0
- package/dist/types/legacy/components/molecules/PhotoAvatar/PhotoAvatar.d.ts +34 -0
- package/dist/types/legacy/components/molecules/SeletorPesquisa/SeletorPesquisa.d.ts +48 -0
- package/dist/types/legacy/components/molecules/Sidebar/Sidebar.d.ts +12 -0
- package/dist/types/legacy/components/molecules/UserAvatar/UserAvatar.d.ts +19 -0
- package/dist/types/legacy/components/organisms/GanttChart/GanttChart.d.ts +62 -0
- package/dist/types/legacy/components/organisms/Kanban/Kanban.d.ts +44 -0
- package/dist/types/legacy/components/organisms/LazyLoader/LazyLoader.d.ts +16 -0
- package/dist/types/legacy/components/organisms/MapaPontos/MapaPontos.d.ts +206 -0
- package/dist/types/legacy/components/organisms/PainelFiltros/PainelFiltros.d.ts +69 -0
- package/dist/types/legacy/components/organisms/PesquisaRapida/PesquisaRapida.d.ts +53 -0
- package/dist/types/legacy/components/organisms/Profile/Profile.d.ts +12 -0
- package/dist/types/legacy/components/organisms/RoleGuard/RoleGuard.d.ts +37 -0
- package/dist/types/legacy/components/organisms/Selector/Selector.d.ts +20 -0
- package/dist/types/legacy/components/organisms/StatusMatrix/StatusMatrix.d.ts +54 -0
- package/dist/types/legacy/components/ui/Avisos.d.ts +33 -0
- package/dist/types/legacy/components/ui/BarraAcoes.d.ts +19 -0
- package/dist/types/legacy/components/ui/CabecalhoPagina.d.ts +23 -0
- package/dist/types/legacy/components/ui/CaixaPesquisa.d.ts +14 -0
- package/dist/types/legacy/components/ui/Confirmacao.d.ts +24 -0
- package/dist/types/legacy/components/ui/Escolha.d.ts +35 -0
- package/dist/types/legacy/components/ui/FaixaAviso.d.ts +19 -0
- package/dist/types/legacy/components/ui/MenuAcoes.d.ts +31 -0
- package/dist/types/legacy/components/ui/Passos.d.ts +31 -0
- package/dist/types/legacy/components/ui/Separadores.d.ts +19 -0
- package/dist/types/legacy/components/ui/TextoAuto.d.ts +23 -0
- package/dist/types/legacy/components/ui/Ui.d.ts +181 -0
- package/dist/types/legacy/components/ui/painelFlutuante.d.ts +16 -0
- package/dist/types/legacy/constants/Colors.d.ts +28 -0
- package/dist/types/legacy/constants/FontWeight.d.ts +9 -0
- package/dist/types/legacy/contexts/apiContext.d.ts +10 -0
- package/dist/types/legacy/contexts/authContext.d.ts +31 -0
- package/dist/types/legacy/contexts/socketContext.d.ts +16 -0
- package/dist/types/legacy/exports/assets.d.ts +0 -0
- package/dist/types/legacy/exports/atoms.d.ts +19 -0
- package/dist/types/legacy/exports/charts.d.ts +2 -0
- package/dist/types/legacy/exports/constants.d.ts +0 -0
- package/dist/types/legacy/exports/contexts.d.ts +3 -0
- package/dist/types/legacy/exports/hooks.d.ts +4 -0
- package/dist/types/legacy/exports/layout.d.ts +14 -0
- package/dist/types/legacy/exports/molecules.d.ts +21 -0
- package/dist/types/legacy/exports/organisms.d.ts +17 -0
- package/dist/types/legacy/exports/pages.d.ts +5 -0
- package/dist/types/legacy/exports/styles.d.ts +2 -0
- package/dist/types/legacy/exports/types.d.ts +7 -0
- package/dist/types/legacy/exports/ui.d.ts +24 -0
- package/dist/types/legacy/exports/utils.d.ts +1 -0
- package/dist/types/legacy/hooks/useApi.d.ts +19 -0
- package/dist/types/legacy/pages/Error/ErrorPage.d.ts +16 -0
- package/dist/types/legacy/pages/Loading/Loading.d.ts +8 -0
- package/dist/types/legacy/pages/Login/LoginScreen.d.ts +42 -0
- package/dist/types/legacy/pages/NotFound/NotFound.d.ts +8 -0
- package/dist/types/legacy/styles/themes/ButtonThemes.d.ts +6 -0
- package/dist/types/legacy/styles/utils/utils.d.ts +2 -0
- package/dist/types/legacy/types/Fetcher.d.ts +5 -0
- package/dist/types/legacy/types/LoggedUser.d.ts +10 -0
- package/dist/types/legacy/types/SelectableElement.d.ts +6 -0
- package/dist/types/legacy/types/SidebarMenu.d.ts +12 -0
- package/dist/types/legacy/types/themes/AcronymThemes.d.ts +4 -0
- package/dist/types/legacy/types/themes/ButtonThemes.d.ts +21 -0
- package/dist/types/legacy/types/themes/CustomSwitchThemes.d.ts +4 -0
- package/dist/types/legacy/types/themes/IconTextThemes.d.ts +6 -0
- package/dist/types/legacy/utils/keycloak.d.ts +0 -0
- package/dist/types/legacy/utils/stringUtils.d.ts +6 -0
- package/dist/types/v1/capabilities/documents/QRScanning/scanQRCodes.d.ts +25 -0
- package/dist/types/v1/capabilities/overlay/useFloatingPanel.d.ts +20 -0
- package/dist/types/v1/capabilities/theme/useIsDark.d.ts +10 -0
- package/dist/types/v1/capabilities/theme/useTheme.d.ts +29 -0
- package/dist/types/v1/components/data/Pagination/Pagination.d.ts +33 -0
- package/dist/types/v1/components/documents/DocumentDropzone/DocumentDropzone.d.ts +60 -0
- package/dist/types/v1/components/feedback/Toast/Toast.d.ts +51 -0
- package/dist/types/v1/components/forms/FormField/FormField.d.ts +44 -0
- package/dist/types/v1/components/forms/FormGrid/FormGrid.d.ts +23 -0
- package/dist/types/v1/components/layout/AppShell/AppShell.d.ts +35 -0
- package/dist/types/v1/components/layout/Page/Page.d.ts +23 -0
- package/dist/types/v1/components/layout/PageHeader/PageHeader.d.ts +35 -0
- package/dist/types/v1/components/layout/SideNav/SideNav.d.ts +92 -0
- package/dist/types/v1/components/layout/navTrail.d.ts +15 -0
- package/dist/types/v1/components/lists/ListFinder/ListFinder.d.ts +86 -0
- package/dist/types/v1/components/lists/ListFinder/labels.d.ts +24 -0
- package/dist/types/v1/components/overlays/ConfirmDialog/ConfirmDialog.d.ts +59 -0
- package/dist/types/v1/components/overlays/Dialog/Dialog.d.ts +66 -0
- package/dist/types/v1/components/overlays/Tooltip/Tooltip.d.ts +34 -0
- package/dist/types/v1/components/overlays/Tooltip/TooltipLayer.d.ts +18 -0
- package/dist/types/v1/components/overlays/Tooltip/TooltipPanel.d.ts +23 -0
- package/dist/types/v1/components/overlays/topLayer.d.ts +23 -0
- package/dist/types/v1/components/tables/PaginatedTable/PaginatedTable.d.ts +41 -0
- package/dist/types/v1/components/tables/Table/ColumnFilter.d.ts +48 -0
- package/dist/types/v1/components/tables/Table/OverlayScrollbar.d.ts +34 -0
- package/dist/types/v1/components/tables/Table/Table.d.ts +250 -0
- package/dist/types/v1/components/tables/Table/labels.d.ts +54 -0
- package/dist/types/v1/foundations/icons/icons.d.ts +81 -0
- package/dist/types/v1/index.d.ts +86 -0
- package/dist/types/v1/primitives/buttons/Button/Button.d.ts +35 -0
- package/dist/types/v1/primitives/buttons/SegmentedControl/SegmentedControl.d.ts +28 -0
- package/dist/types/v1/primitives/buttons/SegmentedControl/segmentedStyles.d.ts +16 -0
- package/dist/types/v1/primitives/display/Avatar/Avatar.d.ts +30 -0
- package/dist/types/v1/primitives/display/Badge/Badge.d.ts +25 -0
- package/dist/types/v1/primitives/display/Card/Card.d.ts +22 -0
- package/dist/types/v1/primitives/display/FilterChips/FilterChips.d.ts +33 -0
- package/dist/types/v1/primitives/display/Kpi/Kpi.d.ts +68 -0
- package/dist/types/v1/primitives/display/Notice/Notice.d.ts +29 -0
- package/dist/types/v1/primitives/display/Person/Person.d.ts +15 -0
- package/dist/types/v1/primitives/display/RichText/RichText.d.ts +17 -0
- package/dist/types/v1/primitives/display/RichText/utils.d.ts +22 -0
- package/dist/types/v1/primitives/documents/PdfPreview/PdfPreview.d.ts +17 -0
- package/dist/types/v1/primitives/documents/PdfPreview/pdfjs.d.ts +11 -0
- package/dist/types/v1/primitives/forms/Checkbox/Checkbox.d.ts +25 -0
- package/dist/types/v1/primitives/forms/DateInput/DateInput.d.ts +43 -0
- package/dist/types/v1/primitives/forms/LookupInput/LookupInput.d.ts +28 -0
- package/dist/types/v1/primitives/forms/RichTextEditor/RichTextEditor.d.ts +64 -0
- package/dist/types/v1/primitives/forms/SearchInput/SearchInput.d.ts +23 -0
- package/dist/types/v1/primitives/forms/SelectInput/SelectInput.d.ts +70 -0
- package/dist/types/v1/primitives/forms/TextArea/TextArea.d.ts +40 -0
- package/dist/types/v1/primitives/forms/TextInput/TextInput.d.ts +16 -0
- package/dist/types/v1/primitives/forms/field.d.ts +22 -0
- package/dist/types/v1/primitives/lists/ListItem/ListItem.d.ts +67 -0
- package/dist/types/v1/primitives/navigation/Tabs/Tabs.d.ts +58 -0
- package/package.json +125 -6
- package/README.md +0 -3
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useMemo, useEffect } from "react";
|
|
3
|
+
import { ChevronLeftIcon, SearchIcon } from "../../../foundations/icons/icons.js";
|
|
4
|
+
import ListItem, { LINHA_ESBATIDA } from "../../../primitives/lists/ListItem/ListItem.js";
|
|
5
|
+
import Checkbox from "../../../primitives/forms/Checkbox/Checkbox.js";
|
|
6
|
+
import { OverlayScrollbar } from "../../tables/Table/OverlayScrollbar.js";
|
|
7
|
+
import { DEFAULT_LIST_FINDER_LABELS } from "./labels.js";
|
|
8
|
+
const semAcentos = (s) => s.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase();
|
|
9
|
+
function termosDaPesquisa(texto) {
|
|
10
|
+
const porEspacos = texto.trim().split(/\s+/).filter(Boolean);
|
|
11
|
+
if (porEspacos.length > 1 && porEspacos.every((t) => /^\d{6,}$/.test(t))) return porEspacos;
|
|
12
|
+
return texto.split(/[\n,;\t]+/).map((t) => t.trim()).filter(Boolean);
|
|
13
|
+
}
|
|
14
|
+
function numerosPagina(atual, total) {
|
|
15
|
+
if (total <= 5) return Array.from({ length: total }, (_, i) => i + 1);
|
|
16
|
+
if (atual <= 2) return [1, 2, 3, "…", total];
|
|
17
|
+
if (atual >= total - 1) return [1, "…", total - 2, total - 1, total];
|
|
18
|
+
return [1, "…", atual, "…", total];
|
|
19
|
+
}
|
|
20
|
+
function LinhaEsqueleto({ marcavel, largura }) {
|
|
21
|
+
return /* @__PURE__ */ jsxs("div", { className: `flex items-start gap-1.5 px-3 py-3 animate-pulse motion-reduce:animate-none ${LINHA_ESBATIDA}`, children: [
|
|
22
|
+
marcavel && /* @__PURE__ */ jsx("span", { className: "flex w-7 shrink-0 justify-center", children: /* @__PURE__ */ jsx("span", { className: "mt-0.5 h-4 w-4 border border-slate-200 bg-slate-100" }) }),
|
|
23
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-1.5", children: [
|
|
24
|
+
/* @__PURE__ */ jsx("div", { className: "h-3 w-20 bg-slate-200" }),
|
|
25
|
+
/* @__PURE__ */ jsx("div", { className: `h-2.5 ${largura} bg-slate-200` }),
|
|
26
|
+
/* @__PURE__ */ jsx("div", { className: "h-1.5 w-1/3 bg-slate-100" })
|
|
27
|
+
] })
|
|
28
|
+
] });
|
|
29
|
+
}
|
|
30
|
+
function ListFinder({
|
|
31
|
+
items,
|
|
32
|
+
itemKey,
|
|
33
|
+
itemContent,
|
|
34
|
+
activeKey,
|
|
35
|
+
onItemClick,
|
|
36
|
+
selectedKeys,
|
|
37
|
+
onSelectionChange,
|
|
38
|
+
filters,
|
|
39
|
+
onBack,
|
|
40
|
+
searchable = true,
|
|
41
|
+
search: pesquisaDeFora,
|
|
42
|
+
onSearchChange,
|
|
43
|
+
searchText,
|
|
44
|
+
mode = "pages",
|
|
45
|
+
onLoadMore,
|
|
46
|
+
total,
|
|
47
|
+
page,
|
|
48
|
+
onPageChange,
|
|
49
|
+
pageSize = 50,
|
|
50
|
+
loading = false,
|
|
51
|
+
labels,
|
|
52
|
+
footerExtra,
|
|
53
|
+
bordered = true,
|
|
54
|
+
className = ""
|
|
55
|
+
}) {
|
|
56
|
+
const L = { ...DEFAULT_LIST_FINDER_LABELS, ...labels };
|
|
57
|
+
const [pesquisaPropria, setPesquisaPropria] = useState("");
|
|
58
|
+
const pesquisa = searchable ? pesquisaDeFora ?? pesquisaPropria : "";
|
|
59
|
+
const pesquisar = (s) => {
|
|
60
|
+
setPesquisaPropria(s);
|
|
61
|
+
onSearchChange?.(s);
|
|
62
|
+
};
|
|
63
|
+
const colar = (e) => {
|
|
64
|
+
const texto = e.clipboardData.getData("text");
|
|
65
|
+
if (!/\r?\n/.test(texto.trim())) return;
|
|
66
|
+
e.preventDefault();
|
|
67
|
+
const lista = texto.split(/\r?\n/).map((t) => t.trim()).filter(Boolean).join(", ");
|
|
68
|
+
const el = e.currentTarget;
|
|
69
|
+
pesquisar(el.value.slice(0, el.selectionStart ?? el.value.length) + lista + el.value.slice(el.selectionEnd ?? el.value.length));
|
|
70
|
+
};
|
|
71
|
+
const termos = useMemo(() => termosDaPesquisa(pesquisa).map(semAcentos), [pesquisa]);
|
|
72
|
+
const filtradas = useMemo(() => {
|
|
73
|
+
if (!searchText || !termos.length) return items;
|
|
74
|
+
return items.filter((it) => {
|
|
75
|
+
const texto = semAcentos(searchText(it));
|
|
76
|
+
return termos.some((t) => texto.includes(t));
|
|
77
|
+
});
|
|
78
|
+
}, [items, termos, searchText]);
|
|
79
|
+
const peloServidor = total !== void 0;
|
|
80
|
+
const aRolar = mode === "scroll";
|
|
81
|
+
const [paginaPropria, setPaginaPropria] = useState(1);
|
|
82
|
+
const totalLinhas = peloServidor ? total : filtradas.length;
|
|
83
|
+
const totalPaginas = Math.max(1, Math.ceil(totalLinhas / pageSize));
|
|
84
|
+
const pagina = Math.min(peloServidor ? page ?? 1 : paginaPropria, totalPaginas);
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
if (!peloServidor) setPaginaPropria(1);
|
|
87
|
+
}, [pesquisa, peloServidor]);
|
|
88
|
+
const irPara = (p) => {
|
|
89
|
+
if (peloServidor) onPageChange?.(p);
|
|
90
|
+
else setPaginaPropria(p);
|
|
91
|
+
};
|
|
92
|
+
const [lotes, setLotes] = useState(1);
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
setLotes(1);
|
|
95
|
+
}, [pesquisa]);
|
|
96
|
+
const visiveis = peloServidor ? filtradas : aRolar ? filtradas.slice(0, lotes * pageSize) : filtradas.slice((pagina - 1) * pageSize, pagina * pageSize);
|
|
97
|
+
const haMais = aRolar && (peloServidor ? !!onLoadMore && items.length < totalLinhas : visiveis.length < filtradas.length);
|
|
98
|
+
const [caixa, setCaixa] = useState(null);
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
caixa?.scrollTo?.({ top: 0 });
|
|
101
|
+
}, [pagina, caixa]);
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
if (aRolar) caixa?.scrollTo?.({ top: 0 });
|
|
104
|
+
}, [pesquisa, aRolar, caixa]);
|
|
105
|
+
const [fim, setFim] = useState(null);
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
if (!fim || !caixa || !haMais || typeof IntersectionObserver === "undefined") return;
|
|
108
|
+
const io = new IntersectionObserver(([e]) => {
|
|
109
|
+
if (!e?.isIntersecting) return;
|
|
110
|
+
if (peloServidor) {
|
|
111
|
+
if (!loading) onLoadMore?.();
|
|
112
|
+
} else setLotes((n) => n + 1);
|
|
113
|
+
}, { root: caixa, rootMargin: "300px" });
|
|
114
|
+
io.observe(fim);
|
|
115
|
+
return () => io.disconnect();
|
|
116
|
+
}, [fim, caixa, haMais, peloServidor, loading, onLoadMore, visiveis.length]);
|
|
117
|
+
const marcadas = selectedKeys ?? /* @__PURE__ */ new Set();
|
|
118
|
+
const marcaveis = !!onSelectionChange;
|
|
119
|
+
const nMarcadasVisiveis = visiveis.filter((it) => marcadas.has(itemKey(it))).length;
|
|
120
|
+
const todasMarcadas = visiveis.length > 0 && nMarcadasVisiveis === visiveis.length;
|
|
121
|
+
const marcar = (key, sim) => {
|
|
122
|
+
const n = new Set(marcadas);
|
|
123
|
+
if (sim) n.add(key);
|
|
124
|
+
else n.delete(key);
|
|
125
|
+
onSelectionChange?.(n);
|
|
126
|
+
};
|
|
127
|
+
const marcarVisiveis = () => {
|
|
128
|
+
const n = new Set(marcadas);
|
|
129
|
+
for (const it of visiveis) {
|
|
130
|
+
if (todasMarcadas) n.delete(itemKey(it));
|
|
131
|
+
else n.add(itemKey(it));
|
|
132
|
+
}
|
|
133
|
+
onSelectionChange?.(n);
|
|
134
|
+
};
|
|
135
|
+
const aCarregar = loading && visiveis.length === 0;
|
|
136
|
+
const esqueleto = /* @__PURE__ */ jsx("span", { className: "inline-block h-2 w-20 rounded-sm bg-slate-200 animate-pulse motion-reduce:animate-none", "aria-hidden": true });
|
|
137
|
+
return /* @__PURE__ */ jsxs("div", { className: `v1-reset flex h-full min-h-0 flex-col bg-white text-control text-slate-800 ${bordered ? "border border-slate-200" : ""} ${className}`, children: [
|
|
138
|
+
(searchable || onBack || filters) && /* @__PURE__ */ jsxs("div", { className: "space-y-2 border-b border-slate-100 px-3 py-2", children: [
|
|
139
|
+
(onBack || filters) && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
140
|
+
onBack && /* @__PURE__ */ jsx(
|
|
141
|
+
"button",
|
|
142
|
+
{
|
|
143
|
+
type: "button",
|
|
144
|
+
onClick: onBack,
|
|
145
|
+
"aria-label": L.back,
|
|
146
|
+
title: L.back,
|
|
147
|
+
className: "-ml-1 flex h-7 w-6 shrink-0 items-center justify-center rounded text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-700",
|
|
148
|
+
children: /* @__PURE__ */ jsx(ChevronLeftIcon, { size: 14 })
|
|
149
|
+
}
|
|
150
|
+
),
|
|
151
|
+
/* @__PURE__ */ jsx("div", { className: "flex min-w-0 flex-1 items-center gap-1.5", children: filters })
|
|
152
|
+
] }),
|
|
153
|
+
searchable && /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
154
|
+
/* @__PURE__ */ jsx(SearchIcon, { size: 11, className: "pointer-events-none absolute top-1/2 left-2 -translate-y-1/2 text-slate-400" }),
|
|
155
|
+
/* @__PURE__ */ jsx(
|
|
156
|
+
"input",
|
|
157
|
+
{
|
|
158
|
+
type: "search",
|
|
159
|
+
value: pesquisa,
|
|
160
|
+
onChange: (e) => pesquisar(e.target.value),
|
|
161
|
+
onPaste: colar,
|
|
162
|
+
placeholder: L.searchPlaceholder,
|
|
163
|
+
"aria-label": L.search,
|
|
164
|
+
className: "block w-full min-w-0 border border-slate-200 bg-white py-1.5 pr-2 pl-6 text-micro text-slate-700 outline-none transition-colors placeholder:text-slate-400 focus:border-proef-blue"
|
|
165
|
+
}
|
|
166
|
+
)
|
|
167
|
+
] })
|
|
168
|
+
] }),
|
|
169
|
+
marcaveis && visiveis.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 border-b border-slate-100 bg-slate-50 px-3 py-1.5 text-[10px] text-slate-500", children: [
|
|
170
|
+
/* @__PURE__ */ jsx("span", { className: "flex w-7 shrink-0 justify-center", children: /* @__PURE__ */ jsx(
|
|
171
|
+
Checkbox,
|
|
172
|
+
{
|
|
173
|
+
checked: todasMarcadas,
|
|
174
|
+
indeterminate: nMarcadasVisiveis > 0 && !todasMarcadas,
|
|
175
|
+
onChange: marcarVisiveis,
|
|
176
|
+
"aria-label": L.selectVisible(visiveis.length)
|
|
177
|
+
}
|
|
178
|
+
) }),
|
|
179
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, children: nMarcadasVisiveis > 0 ? L.selectedCount(nMarcadasVisiveis, visiveis.length) : L.selectVisible(visiveis.length) }),
|
|
180
|
+
marcadas.size > 0 && /* @__PURE__ */ jsx(
|
|
181
|
+
"button",
|
|
182
|
+
{
|
|
183
|
+
type: "button",
|
|
184
|
+
onClick: () => onSelectionChange?.(/* @__PURE__ */ new Set()),
|
|
185
|
+
className: "ml-auto text-proef-blue hover:underline",
|
|
186
|
+
children: L.clearSelection
|
|
187
|
+
}
|
|
188
|
+
)
|
|
189
|
+
] }),
|
|
190
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex min-h-0 flex-1 flex-col", children: [
|
|
191
|
+
/* @__PURE__ */ jsxs("div", { ref: setCaixa, className: "relative min-h-0 flex-1 overflow-y-auto scrollbar-none", children: [
|
|
192
|
+
aCarregar ? (
|
|
193
|
+
// A forma das linhas já diz que vem ali a lista. Mais do que cabem,
|
|
194
|
+
// cortadas pela caixa: chega ao fundo em qualquer altura.
|
|
195
|
+
/* @__PURE__ */ jsxs("div", { role: "status", "aria-busy": "true", className: "h-full overflow-hidden", children: [
|
|
196
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: L.loading }),
|
|
197
|
+
["w-11/12", "w-3/4", "w-5/6", "w-2/3", "w-4/5", "w-7/12"].flatMap((l) => [l, l, l, l]).map((largura, i) => /* @__PURE__ */ jsx(LinhaEsqueleto, { marcavel: marcaveis, largura }, i))
|
|
198
|
+
] })
|
|
199
|
+
) : visiveis.length === 0 ? /* @__PURE__ */ jsx("p", { className: "m-0 px-3 py-4 text-center text-[10px] text-slate-400", children: L.empty }) : /* @__PURE__ */ jsx("ul", { className: "m-0 list-none p-0", children: visiveis.map((it) => {
|
|
200
|
+
const key = itemKey(it);
|
|
201
|
+
return /* @__PURE__ */ jsx(
|
|
202
|
+
ListItem,
|
|
203
|
+
{
|
|
204
|
+
...itemContent(it),
|
|
205
|
+
active: activeKey === key,
|
|
206
|
+
onClick: onItemClick ? () => onItemClick(it) : void 0,
|
|
207
|
+
checked: marcadas.has(key),
|
|
208
|
+
onCheckedChange: marcaveis ? (sim) => marcar(key, sim) : void 0,
|
|
209
|
+
checkboxLabel: L.checkItem(key),
|
|
210
|
+
highlight: termos
|
|
211
|
+
},
|
|
212
|
+
key
|
|
213
|
+
);
|
|
214
|
+
}) }),
|
|
215
|
+
!aCarregar && haMais && /* @__PURE__ */ jsxs("div", { ref: setFim, role: "status", "aria-busy": "true", children: [
|
|
216
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: L.loading }),
|
|
217
|
+
["w-3/4", "w-5/6", "w-2/3"].map((largura, i) => /* @__PURE__ */ jsx(LinhaEsqueleto, { marcavel: marcaveis, largura }, i))
|
|
218
|
+
] })
|
|
219
|
+
] }),
|
|
220
|
+
/* @__PURE__ */ jsx(OverlayScrollbar, { alvo: caixa, borda: 0 })
|
|
221
|
+
] }),
|
|
222
|
+
/* @__PURE__ */ jsxs("div", { className: `flex shrink-0 items-center gap-2 border-t border-slate-100 bg-slate-50 px-3 text-micro text-slate-400 ${aRolar ? "h-8 justify-center" : "h-9 justify-between"}`, children: [
|
|
223
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 whitespace-nowrap", children: [
|
|
224
|
+
aCarregar ? esqueleto : aRolar ? (
|
|
225
|
+
// A rolar: quantas já se mostram, de quantas há.
|
|
226
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
227
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-slate-500 tabular-nums", children: visiveis.length.toLocaleString("pt-PT") }),
|
|
228
|
+
" / ",
|
|
229
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-slate-500 tabular-nums", children: totalLinhas.toLocaleString("pt-PT") }),
|
|
230
|
+
" ",
|
|
231
|
+
L.itemsNoun(totalLinhas)
|
|
232
|
+
] })
|
|
233
|
+
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
234
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-slate-500 tabular-nums", children: totalLinhas.toLocaleString("pt-PT") }),
|
|
235
|
+
" ",
|
|
236
|
+
L.itemsNoun(totalLinhas)
|
|
237
|
+
] }),
|
|
238
|
+
footerExtra,
|
|
239
|
+
loading && !aCarregar && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "animate-pulse motion-reduce:animate-none", children: "…" })
|
|
240
|
+
] }),
|
|
241
|
+
!aRolar && !aCarregar && totalPaginas > 1 && /* @__PURE__ */ jsxs("nav", { "aria-label": L.pagination, className: "flex items-center gap-0.5", children: [
|
|
242
|
+
/* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
|
|
243
|
+
L.page,
|
|
244
|
+
" ",
|
|
245
|
+
pagina,
|
|
246
|
+
" / ",
|
|
247
|
+
totalPaginas
|
|
248
|
+
] }),
|
|
249
|
+
numerosPagina(pagina, totalPaginas).map((p, i) => p === "…" ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "flex h-6 min-w-3 items-center justify-center text-slate-300", children: "…" }, `r${i}`) : /* @__PURE__ */ jsxs(
|
|
250
|
+
"button",
|
|
251
|
+
{
|
|
252
|
+
type: "button",
|
|
253
|
+
onClick: () => irPara(p),
|
|
254
|
+
"aria-current": p === pagina ? "page" : void 0,
|
|
255
|
+
className: `grid h-6 min-w-5 place-items-center px-1 tabular-nums transition-colors ${p === pagina ? "cursor-default font-semibold text-slate-800" : "text-slate-400 hover:text-slate-700"}`,
|
|
256
|
+
children: [
|
|
257
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "invisible col-start-1 row-start-1 font-semibold", children: p.toLocaleString("pt-PT") }),
|
|
258
|
+
/* @__PURE__ */ jsx("span", { className: "col-start-1 row-start-1", children: p.toLocaleString("pt-PT") })
|
|
259
|
+
]
|
|
260
|
+
},
|
|
261
|
+
p
|
|
262
|
+
))
|
|
263
|
+
] })
|
|
264
|
+
] })
|
|
265
|
+
] });
|
|
266
|
+
}
|
|
267
|
+
export {
|
|
268
|
+
ListFinder as default,
|
|
269
|
+
termosDaPesquisa
|
|
270
|
+
};
|
|
271
|
+
//# sourceMappingURL=ListFinder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ListFinder.js","sources":["../../../../../../src/v1/components/lists/ListFinder/ListFinder.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useState } from 'react'\r\nimport { ChevronLeftIcon, SearchIcon } from '../../../foundations/icons/icons'\r\nimport ListItem, { LINHA_ESBATIDA, type ListItemContent } from '../../../primitives/lists/ListItem/ListItem'\r\nimport Checkbox from '../../../primitives/forms/Checkbox/Checkbox'\r\nimport { OverlayScrollbar } from '../../tables/Table/OverlayScrollbar'\r\nimport { DEFAULT_LIST_FINDER_LABELS, type ListFinderLabels } from './labels'\r\n\r\nexport interface ListFinderProps<T> {\r\n /** As linhas: todas, ou só a página atual quando o servidor pagina (com `total`). */\r\n items: T[]\r\n /** Uma chave única por linha (ex: o id). */\r\n itemKey: (item: T) => string\r\n /** O que cada linha mostra: as partes do [ListItem](?path=/docs/v1-primitives-lists-listitem--docs). */\r\n itemContent: (item: T) => ListItemContent\r\n /** A linha aberta (fica realçada). */\r\n activeKey?: string | null\r\n /** Ao clicar numa linha: normalmente, abri-la ao lado. */\r\n onItemClick?: (item: T) => void\r\n /** As marcadas. Só há caixas de marcar com `onSelectionChange`. */\r\n selectedKeys?: ReadonlySet<string>\r\n onSelectionChange?: (keys: Set<string>) => void\r\n /** Filtros ao lado do voltar, por cima da pesquisa (ex: um ou dois selects, no traço fino da pesquisa). */\r\n filters?: React.ReactNode\r\n /** Com isto aparece um ‹ à esquerda, para fechar ou esconder a lista. */\r\n onBack?: () => void\r\n /** Com a caixa de pesquisa (o normal). Sem ela, a lista mostra tudo o que recebe. */\r\n searchable?: boolean\r\n /** O texto da pesquisa. Sem ele, a pesquisa guarda o seu. */\r\n search?: string\r\n onSearchChange?: (search: string) => void\r\n /**\r\n * O texto onde a pesquisa procura, em cada linha. Com isto, a lista filtra-se\r\n * sozinha (sem acentos nem maiúsculas); sem isto, quem filtra é a app (ex: o\r\n * servidor, com `onSearchChange`). Uma lista colada (uma por linha, ou\r\n * separadas por vírgulas) mostra as que tiverem qualquer uma delas.\r\n */\r\n searchText?: (item: T) => string\r\n /**\r\n * Como se chega ao resto da lista:\r\n * - `'pages'` (o normal): páginas numeradas no rodapé;\r\n * - `'scroll'`: uma lista só, que vai mostrando mais `pageSize` linhas ao\r\n * chegar ao fundo. Com o servidor a paginar, `items` são as que já vieram e\r\n * pede-se o lote seguinte com `onLoadMore`.\r\n */\r\n mode?: 'pages' | 'scroll'\r\n /** Com `mode=\"scroll\"` e o servidor a paginar: buscar o lote seguinte (junta-o a `items`). */\r\n onLoadMore?: () => void\r\n /** O servidor pagina: quantas linhas há lá ao todo. `items` é só a página atual (ou, a rolar, as que já vieram). */\r\n total?: number\r\n /** A página atual (1, 2, ...), quando o servidor pagina. */\r\n page?: number\r\n onPageChange?: (page: number) => void\r\n /** Quantas linhas por página. Com o servidor a paginar, quantas ele manda. */\r\n pageSize?: number\r\n /** A carregar: sem linhas ainda, mostra o esqueleto delas. A rolar, com linhas, é o lote seguinte a chegar. */\r\n loading?: boolean\r\n labels?: Partial<ListFinderLabels>\r\n /** No rodapé, a seguir à contagem: algo pequeno da app (ex: um ícone de ajuda com as regras da lista). */\r\n footerExtra?: React.ReactNode\r\n /** Com a moldura à volta (o normal). Sem ela, para ir dentro de um painel que já tem a sua. */\r\n bordered?: boolean\r\n className?: string\r\n}\r\n\r\nconst semAcentos = (s: string) => s.normalize('NFD').replace(/[̀-ͯ]/g, '').toLowerCase()\r\n\r\n/**\r\n * Parte o texto da pesquisa nos termos a procurar: vírgula, ponto e vírgula,\r\n * tab e mudança de linha. O espaço só separa quando tudo o que lá está são\r\n * números de 6 ou mais dígitos (uma coluna colada de uma folha de cálculo);\r\n * fora disso \"vila real\" é uma coisa só, e não \"vila\" ou \"real\".\r\n */\r\nexport function termosDaPesquisa(texto: string): string[] {\r\n const porEspacos = texto.trim().split(/\\s+/).filter(Boolean)\r\n if (porEspacos.length > 1 && porEspacos.every(t => /^\\d{6,}$/.test(t))) return porEspacos\r\n return texto.split(/[\\n,;\\t]+/).map(t => t.trim()).filter(Boolean)\r\n}\r\n\r\n/** Os números das páginas numa coluna estreita: no máximo cinco lugares. */\r\nfunction numerosPagina(atual: number, total: number): (number | '…')[] {\r\n if (total <= 5) return Array.from({ length: total }, (_, i) => i + 1)\r\n if (atual <= 2) return [1, 2, 3, '…', total]\r\n if (atual >= total - 1) return [1, '…', total - 2, total - 1, total]\r\n return [1, '…', atual, '…', total]\r\n}\r\n\r\n/** Uma linha a carregar: a forma das linhas já diz que vem ali a lista. */\r\nfunction LinhaEsqueleto({ marcavel, largura }: { marcavel: boolean; largura: string }) {\r\n return (\r\n <div className={`flex items-start gap-1.5 px-3 py-3 animate-pulse motion-reduce:animate-none ${LINHA_ESBATIDA}`}>\r\n {marcavel && <span className=\"flex w-7 shrink-0 justify-center\"><span className=\"mt-0.5 h-4 w-4 border border-slate-200 bg-slate-100\" /></span>}\r\n <div className=\"min-w-0 flex-1 space-y-1.5\">\r\n <div className=\"h-3 w-20 bg-slate-200\" />\r\n <div className={`h-2.5 ${largura} bg-slate-200`} />\r\n <div className=\"h-1.5 w-1/3 bg-slate-100\" />\r\n </div>\r\n </div>\r\n )\r\n}\r\n\r\n/**\r\n * Uma lista para encontrar e escolher: filtros e pesquisa em cima, as linhas\r\n * ([ListItem](?path=/docs/v1-primitives-lists-listitem--docs)) a rolar no meio e\r\n * as páginas (ou a contagem, a rolar) em baixo. Pensada para a coluna ao lado do que se abre (a lista à\r\n * esquerda, o detalhe da linha escolhida à direita).\r\n *\r\n * Enche a altura do pai. O topo, a barra de \"selecionar todos\" e o rodapé\r\n * ficam sempre no sítio: só as linhas rolam.\r\n *\r\n * - **Pesquisa**: com `searchText` filtra sozinha; sem ele, a app filtra\r\n * (`search`/`onSearchChange`).\r\n * - **Páginas**: pagina sozinha (`pageSize`), ou é o servidor (`total`, `page`,\r\n * `onPageChange`).\r\n * - **A rolar** (`mode=\"scroll\"`): sem páginas, vai mostrando mais ao descer;\r\n * com o servidor, `items` são as que já vieram e `onLoadMore` pede mais.\r\n * - **Realce**: o que se procurou realça-se no código e no título das linhas.\r\n * - **Marcar vários**: com `onSelectionChange`. O \"selecionar todos\" só marca\r\n * as linhas à vista, nunca as que não se veem.\r\n */\r\nexport default function ListFinder<T>({\r\n items, itemKey, itemContent, activeKey, onItemClick, selectedKeys, onSelectionChange, filters, onBack,\r\n searchable = true, search: pesquisaDeFora, onSearchChange, searchText, mode = 'pages', onLoadMore, total, page, onPageChange, pageSize = 50, loading = false,\r\n labels, footerExtra, bordered = true, className = '',\r\n}: ListFinderProps<T>) {\r\n const L = { ...DEFAULT_LIST_FINDER_LABELS, ...labels }\r\n const [pesquisaPropria, setPesquisaPropria] = useState('')\r\n const pesquisa = searchable ? (pesquisaDeFora ?? pesquisaPropria) : ''\r\n const pesquisar = (s: string) => { setPesquisaPropria(s); onSearchChange?.(s) }\r\n // Uma caixa de uma linha deita fora as quebras de linha: uma coluna colada\r\n // de uma folha de cálculo chegava como um número só, colado. Passam a vírgulas.\r\n const colar = (e: React.ClipboardEvent<HTMLInputElement>) => {\r\n const texto = e.clipboardData.getData('text')\r\n if (!/\\r?\\n/.test(texto.trim())) return\r\n e.preventDefault()\r\n const lista = texto.split(/\\r?\\n/).map(t => t.trim()).filter(Boolean).join(', ')\r\n const el = e.currentTarget\r\n pesquisar(el.value.slice(0, el.selectionStart ?? el.value.length) + lista + el.value.slice(el.selectionEnd ?? el.value.length))\r\n }\r\n\r\n // Os mesmos termos filtram (com `searchText`) e realçam-se nas linhas.\r\n const termos = useMemo(() => termosDaPesquisa(pesquisa).map(semAcentos), [pesquisa])\r\n const filtradas = useMemo(() => {\r\n if (!searchText || !termos.length) return items\r\n return items.filter(it => {\r\n const texto = semAcentos(searchText(it))\r\n return termos.some(t => texto.includes(t))\r\n })\r\n }, [items, termos, searchText])\r\n\r\n // Paginação: do servidor (com `total`), ou feita aqui.\r\n const peloServidor = total !== undefined\r\n const aRolar = mode === 'scroll'\r\n const [paginaPropria, setPaginaPropria] = useState(1)\r\n const totalLinhas = peloServidor ? total : filtradas.length\r\n const totalPaginas = Math.max(1, Math.ceil(totalLinhas / pageSize))\r\n const pagina = Math.min(peloServidor ? (page ?? 1) : paginaPropria, totalPaginas)\r\n // Uma pesquisa nova volta à primeira página: a terceira de antes já não é a mesma lista.\r\n useEffect(() => { if (!peloServidor) setPaginaPropria(1) }, [pesquisa, peloServidor])\r\n const irPara = (p: number) => { if (peloServidor) onPageChange?.(p); else setPaginaPropria(p) }\r\n // A rolar sem servidor: quantos lotes já se mostram.\r\n const [lotes, setLotes] = useState(1)\r\n useEffect(() => { setLotes(1) }, [pesquisa])\r\n const visiveis = peloServidor ? filtradas\r\n : aRolar ? filtradas.slice(0, lotes * pageSize)\r\n : filtradas.slice((pagina - 1) * pageSize, pagina * pageSize)\r\n const haMais = aRolar && (peloServidor ? !!onLoadMore && items.length < totalLinhas : visiveis.length < filtradas.length)\r\n\r\n // Ao mudar de página, ou de pesquisa a rolar, a lista volta ao topo.\r\n const [caixa, setCaixa] = useState<HTMLDivElement | null>(null)\r\n useEffect(() => { caixa?.scrollTo?.({ top: 0 }) }, [pagina, caixa])\r\n useEffect(() => { if (aRolar) caixa?.scrollTo?.({ top: 0 }) }, [pesquisa, aRolar, caixa])\r\n\r\n // A rolar: a linha-sentinela no fundo, ao chegar a 300px da vista, pede o\r\n // lote seguinte. Volta a observar a cada lote que chega: se continuar à\r\n // vista (uma janela alta), pede logo outro.\r\n const [fim, setFim] = useState<HTMLDivElement | null>(null)\r\n useEffect(() => {\r\n if (!fim || !caixa || !haMais || typeof IntersectionObserver === 'undefined') return\r\n const io = new IntersectionObserver(([e]) => {\r\n if (!e?.isIntersecting) return\r\n if (peloServidor) { if (!loading) onLoadMore?.() } else setLotes(n => n + 1)\r\n }, { root: caixa, rootMargin: '300px' })\r\n io.observe(fim)\r\n return () => io.disconnect()\r\n }, [fim, caixa, haMais, peloServidor, loading, onLoadMore, visiveis.length])\r\n\r\n const marcadas = selectedKeys ?? new Set<string>()\r\n const marcaveis = !!onSelectionChange\r\n const nMarcadasVisiveis = visiveis.filter(it => marcadas.has(itemKey(it))).length\r\n const todasMarcadas = visiveis.length > 0 && nMarcadasVisiveis === visiveis.length\r\n const marcar = (key: string, sim: boolean) => {\r\n const n = new Set(marcadas)\r\n if (sim) n.add(key); else n.delete(key)\r\n onSelectionChange?.(n)\r\n }\r\n const marcarVisiveis = () => {\r\n const n = new Set(marcadas)\r\n for (const it of visiveis) { if (todasMarcadas) n.delete(itemKey(it)); else n.add(itemKey(it)) }\r\n onSelectionChange?.(n)\r\n }\r\n\r\n const aCarregar = loading && visiveis.length === 0\r\n const esqueleto = <span className=\"inline-block h-2 w-20 rounded-sm bg-slate-200 animate-pulse motion-reduce:animate-none\" aria-hidden />\r\n\r\n return (\r\n <div className={`v1-reset flex h-full min-h-0 flex-col bg-white text-control text-slate-800 ${bordered ? 'border border-slate-200' : ''} ${className}`}>\r\n {/* Sem pesquisa, filtros nem voltar, não há cabeça: as linhas começam no topo. */}\r\n {(searchable || onBack || filters) && (\r\n <div className=\"space-y-2 border-b border-slate-100 px-3 py-2\">\r\n {(onBack || filters) && (\r\n <div className=\"flex items-center gap-1.5\">\r\n {onBack && (\r\n <button type=\"button\" onClick={onBack} aria-label={L.back} title={L.back}\r\n className=\"-ml-1 flex h-7 w-6 shrink-0 items-center justify-center rounded text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-700\">\r\n <ChevronLeftIcon size={14} />\r\n </button>\r\n )}\r\n <div className=\"flex min-w-0 flex-1 items-center gap-1.5\">{filters}</div>\r\n </div>\r\n )}\r\n {searchable && (\r\n <div className=\"relative\">\r\n {/* Caixa direita e fina, no tamanho do texto das linhas: a lista é\r\n uma coluna estreita, e a pesquisa não deve pesar mais do que ela. */}\r\n <SearchIcon size={11} className=\"pointer-events-none absolute top-1/2 left-2 -translate-y-1/2 text-slate-400\" />\r\n <input\r\n type=\"search\"\r\n value={pesquisa}\r\n onChange={e => pesquisar(e.target.value)}\r\n onPaste={colar}\r\n placeholder={L.searchPlaceholder}\r\n aria-label={L.search}\r\n className=\"block w-full min-w-0 border border-slate-200 bg-white py-1.5 pr-2 pl-6 text-micro text-slate-700 outline-none transition-colors placeholder:text-slate-400 focus:border-proef-blue\"\r\n />\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n\r\n {/* Fora da área que rola: é a cabeça da lista, e é a descer a lista que\r\n se decide marcá-la toda. */}\r\n {marcaveis && visiveis.length > 0 && (\r\n <div className=\"flex items-center gap-1.5 border-b border-slate-100 bg-slate-50 px-3 py-1.5 text-[10px] text-slate-500\">\r\n {/* Na coluna de 28px das linhas, para as caixas ficarem umas por baixo das outras. */}\r\n <span className=\"flex w-7 shrink-0 justify-center\">\r\n <Checkbox\r\n checked={todasMarcadas}\r\n indeterminate={nMarcadasVisiveis > 0 && !todasMarcadas}\r\n onChange={marcarVisiveis}\r\n aria-label={L.selectVisible(visiveis.length)}\r\n />\r\n </span>\r\n <span aria-hidden>{nMarcadasVisiveis > 0 ? L.selectedCount(nMarcadasVisiveis, visiveis.length) : L.selectVisible(visiveis.length)}</span>\r\n {marcadas.size > 0 && (\r\n <button type=\"button\" onClick={() => onSelectionChange?.(new Set())}\r\n className=\"ml-auto text-proef-blue hover:underline\">\r\n {L.clearSelection}\r\n </button>\r\n )}\r\n </div>\r\n )}\r\n\r\n <div className=\"relative flex min-h-0 flex-1 flex-col\">\r\n {/* `relative`: o texto só para leitores de ecrã (`sr-only`, posição\r\n absoluta) do fundo da lista tem de ficar preso a esta caixa. Sem isso\r\n ficava no fim das linhas, fora do corte do scroll, e esticava a\r\n página — dava para rolar até um branco sem nada. */}\r\n <div ref={setCaixa} className=\"relative min-h-0 flex-1 overflow-y-auto scrollbar-none\">\r\n {aCarregar ? (\r\n // A forma das linhas já diz que vem ali a lista. Mais do que cabem,\r\n // cortadas pela caixa: chega ao fundo em qualquer altura.\r\n <div role=\"status\" aria-busy=\"true\" className=\"h-full overflow-hidden\">\r\n <span className=\"sr-only\">{L.loading}</span>\r\n {['w-11/12', 'w-3/4', 'w-5/6', 'w-2/3', 'w-4/5', 'w-7/12'].flatMap(l => [l, l, l, l]).map((largura, i) => (\r\n <LinhaEsqueleto key={i} marcavel={marcaveis} largura={largura} />\r\n ))}\r\n </div>\r\n ) : visiveis.length === 0 ? (\r\n <p className=\"m-0 px-3 py-4 text-center text-[10px] text-slate-400\">{L.empty}</p>\r\n ) : (\r\n <ul className=\"m-0 list-none p-0\">\r\n {visiveis.map(it => {\r\n const key = itemKey(it)\r\n return (\r\n <ListItem\r\n key={key}\r\n {...itemContent(it)}\r\n active={activeKey === key}\r\n onClick={onItemClick ? () => onItemClick(it) : undefined}\r\n checked={marcadas.has(key)}\r\n onCheckedChange={marcaveis ? sim => marcar(key, sim) : undefined}\r\n checkboxLabel={L.checkItem(key)}\r\n highlight={termos}\r\n />\r\n )\r\n })}\r\n </ul>\r\n )}\r\n {/* A rolar: o lote seguinte a chegar, e a sentinela que o pede. */}\r\n {!aCarregar && haMais && (\r\n <div ref={setFim} role=\"status\" aria-busy=\"true\">\r\n <span className=\"sr-only\">{L.loading}</span>\r\n {['w-3/4', 'w-5/6', 'w-2/3'].map((largura, i) => <LinhaEsqueleto key={i} marcavel={marcaveis} largura={largura} />)}\r\n </div>\r\n )}\r\n </div>\r\n <OverlayScrollbar alvo={caixa} borda={0} />\r\n </div>\r\n\r\n {/* Sempre à vista e com a mesma altura, carregada ou não: aparecer do\r\n nada fazia saltar o fundo do painel. */}\r\n <div className={`flex shrink-0 items-center gap-2 border-t border-slate-100 bg-slate-50 px-3 text-micro text-slate-400 ${aRolar ? 'h-8 justify-center' : 'h-9 justify-between'}`}>\r\n <span className=\"flex items-center gap-1 whitespace-nowrap\">\r\n {aCarregar ? esqueleto : aRolar ? (\r\n // A rolar: quantas já se mostram, de quantas há.\r\n <><span className=\"font-medium text-slate-500 tabular-nums\">{visiveis.length.toLocaleString('pt-PT')}</span> / <span className=\"font-medium text-slate-500 tabular-nums\">{totalLinhas.toLocaleString('pt-PT')}</span> {L.itemsNoun(totalLinhas)}</>\r\n ) : <><span className=\"font-medium text-slate-500 tabular-nums\">{totalLinhas.toLocaleString('pt-PT')}</span> {L.itemsNoun(totalLinhas)}</>}\r\n {footerExtra}\r\n {/* Com linhas e a pedir outra vez (ex: outra página, ou a atualizar): um \"…\" a pulsar. */}\r\n {loading && !aCarregar && <span aria-hidden className=\"animate-pulse motion-reduce:animate-none\">…</span>}\r\n </span>\r\n {!aRolar && !aCarregar && totalPaginas > 1 && (\r\n <nav aria-label={L.pagination} className=\"flex items-center gap-0.5\">\r\n <span className=\"sr-only\">{L.page} {pagina} / {totalPaginas}</span>\r\n {numerosPagina(pagina, totalPaginas).map((p, i) => p === '…' ? (\r\n <span key={`r${i}`} aria-hidden className=\"flex h-6 min-w-3 items-center justify-center text-slate-300\">…</span>\r\n ) : (\r\n <button\r\n key={p}\r\n type=\"button\"\r\n onClick={() => irPara(p)}\r\n aria-current={p === pagina ? 'page' : undefined}\r\n className={`grid h-6 min-w-5 place-items-center px-1 tabular-nums transition-colors ${\r\n p === pagina ? 'cursor-default font-semibold text-slate-800' : 'text-slate-400 hover:text-slate-700'}`}\r\n >\r\n {/* Sem caixa nem fundo: a página atual é só o número mais forte.\r\n A cópia invisível a negrito guarda a largura, para os números\r\n não se mexerem ao trocar de página. */}\r\n <span aria-hidden className=\"invisible col-start-1 row-start-1 font-semibold\">{p.toLocaleString('pt-PT')}</span>\r\n <span className=\"col-start-1 row-start-1\">{p.toLocaleString('pt-PT')}</span>\r\n </button>\r\n ))}\r\n </nav>\r\n )}\r\n </div>\r\n </div>\r\n )\r\n}\r\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const DEFAULT_LIST_FINDER_LABELS = {
|
|
2
|
+
searchPlaceholder: "Pesquisar",
|
|
3
|
+
search: "Pesquisar",
|
|
4
|
+
back: "Fechar a lista",
|
|
5
|
+
itemsNoun: (count) => count === 1 ? "item" : "itens",
|
|
6
|
+
selectVisible: (count) => `Selecionar ${count === 1 ? "o" : `os ${count}`} à vista`,
|
|
7
|
+
selectedCount: (selected, visible) => `${selected} de ${visible} marcados`,
|
|
8
|
+
clearSelection: "Limpar",
|
|
9
|
+
checkItem: (key) => `Marcar ${key}`,
|
|
10
|
+
empty: "Sem resultados",
|
|
11
|
+
loading: "A carregar",
|
|
12
|
+
pagination: "Páginas",
|
|
13
|
+
page: "Página"
|
|
14
|
+
};
|
|
15
|
+
export {
|
|
16
|
+
DEFAULT_LIST_FINDER_LABELS
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=labels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"labels.js","sources":["../../../../../../src/v1/components/lists/ListFinder/labels.ts"],"sourcesContent":["/** Os textos do ListFinder. A app troca os que quiser pela prop `labels`. */\r\nexport interface ListFinderLabels {\r\n /** Dentro da caixa de pesquisa. */\r\n searchPlaceholder: string\r\n /** O nome da caixa de pesquisa, para leitores de ecrã. */\r\n search: string\r\n /** O botão de voltar (só com `onBack`). */\r\n back: string\r\n /** O nome do que a lista tem, no singular ou plural (ex: \"1 ordem\", \"20 ordens\"). */\r\n itemsNoun: (count: number) => string\r\n /** A caixa de cima, sem nenhuma marcada. */\r\n selectVisible: (count: number) => string\r\n /** A caixa de cima, com algumas marcadas. */\r\n selectedCount: (selected: number, visible: number) => string\r\n clearSelection: string\r\n /** A caixa de marcar de cada linha (ex: \"Marcar P-020000\"). */\r\n checkItem: (key: string) => string\r\n /** Sem nada para mostrar. */\r\n empty: string\r\n loading: string\r\n pagination: string\r\n page: string\r\n}\r\n\r\nexport const DEFAULT_LIST_FINDER_LABELS: ListFinderLabels = {\r\n searchPlaceholder: 'Pesquisar',\r\n search: 'Pesquisar',\r\n back: 'Fechar a lista',\r\n itemsNoun: (count) => (count === 1 ? 'item' : 'itens'),\r\n selectVisible: (count) => `Selecionar ${count === 1 ? 'o' : `os ${count}`} à vista`,\r\n selectedCount: (selected, visible) => `${selected} de ${visible} marcados`,\r\n clearSelection: 'Limpar',\r\n checkItem: (key) => `Marcar ${key}`,\r\n empty: 'Sem resultados',\r\n loading: 'A carregar',\r\n pagination: 'Páginas',\r\n page: 'Página',\r\n}\r\n"],"names":[],"mappings":"AAwBO,MAAM,6BAA+C;AAAA,EAC1D,mBAAmB;AAAA,EACnB,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,WAAW,CAAC,UAAW,UAAU,IAAI,SAAS;AAAA,EAC9C,eAAe,CAAC,UAAU,cAAc,UAAU,IAAI,MAAM,MAAM,KAAK,EAAE;AAAA,EACzE,eAAe,CAAC,UAAU,YAAY,GAAG,QAAQ,OAAO,OAAO;AAAA,EAC/D,gBAAgB;AAAA,EAChB,WAAW,CAAC,QAAQ,UAAU,GAAG;AAAA,EACjC,OAAO;AAAA,EACP,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,MAAM;AACR;"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useRef, useEffect, useState, useCallback, useContext, createContext } from "react";
|
|
3
|
+
import Dialog from "../Dialog/Dialog.js";
|
|
4
|
+
import Button from "../../../primitives/buttons/Button/Button.js";
|
|
5
|
+
import { WarningIcon } from "../../../foundations/icons/icons.js";
|
|
6
|
+
function ConfirmDialog({
|
|
7
|
+
open,
|
|
8
|
+
title,
|
|
9
|
+
message,
|
|
10
|
+
detail,
|
|
11
|
+
tone = "default",
|
|
12
|
+
confirmLabel = "Confirmar",
|
|
13
|
+
cancelLabel = "Cancelar",
|
|
14
|
+
closeLabel = "Fechar",
|
|
15
|
+
loading = false,
|
|
16
|
+
secondaryAction,
|
|
17
|
+
onConfirm,
|
|
18
|
+
onCancel
|
|
19
|
+
}) {
|
|
20
|
+
const danger = tone === "danger";
|
|
21
|
+
const confirmRef = useRef(null);
|
|
22
|
+
const cancelRef = useRef(null);
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (open) (danger ? cancelRef : confirmRef).current?.focus();
|
|
25
|
+
}, [open, danger]);
|
|
26
|
+
return /* @__PURE__ */ jsx(
|
|
27
|
+
Dialog,
|
|
28
|
+
{
|
|
29
|
+
open,
|
|
30
|
+
onClose: () => !loading && onCancel(),
|
|
31
|
+
title,
|
|
32
|
+
size: "sm",
|
|
33
|
+
closeLabel,
|
|
34
|
+
footer: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
35
|
+
/* @__PURE__ */ jsx(Button, { ref: confirmRef, variant: danger ? "danger" : "primary", loading, onClick: onConfirm, children: confirmLabel }),
|
|
36
|
+
secondaryAction && /* @__PURE__ */ jsx(Button, { variant: "secondary", disabled: loading, onClick: secondaryAction.onClick, children: secondaryAction.label }),
|
|
37
|
+
/* @__PURE__ */ jsx(Button, { ref: cancelRef, variant: "secondary", disabled: loading, onClick: onCancel, children: cancelLabel })
|
|
38
|
+
] }),
|
|
39
|
+
children: (message || detail) && /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
40
|
+
danger && /* @__PURE__ */ jsx("span", { className: "flex h-9 w-9 flex-none items-center justify-center rounded-full bg-incumprido-bg text-incumprido", children: /* @__PURE__ */ jsx(WarningIcon, { size: 18 }) }),
|
|
41
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 self-center", children: [
|
|
42
|
+
message && /* @__PURE__ */ jsx("div", { className: "m-0 text-control leading-relaxed text-foreground", children: message }),
|
|
43
|
+
detail && /* @__PURE__ */ jsx("div", { className: "m-0 mt-1 text-caption leading-relaxed text-muted-foreground", children: detail })
|
|
44
|
+
] })
|
|
45
|
+
] })
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
const ConfirmContext = createContext(null);
|
|
50
|
+
function ConfirmProvider({ children, confirmLabel, cancelLabel, closeLabel }) {
|
|
51
|
+
const [pending, setPending] = useState(null);
|
|
52
|
+
const resolver = useRef(null);
|
|
53
|
+
const confirm = useCallback((options) => {
|
|
54
|
+
resolver.current?.(false);
|
|
55
|
+
setPending(options);
|
|
56
|
+
return new Promise((resolve) => {
|
|
57
|
+
resolver.current = resolve;
|
|
58
|
+
});
|
|
59
|
+
}, []);
|
|
60
|
+
const answer = (ok) => {
|
|
61
|
+
resolver.current?.(ok);
|
|
62
|
+
resolver.current = null;
|
|
63
|
+
setPending(null);
|
|
64
|
+
};
|
|
65
|
+
return /* @__PURE__ */ jsxs(ConfirmContext.Provider, { value: confirm, children: [
|
|
66
|
+
children,
|
|
67
|
+
/* @__PURE__ */ jsx(
|
|
68
|
+
ConfirmDialog,
|
|
69
|
+
{
|
|
70
|
+
open: pending !== null,
|
|
71
|
+
title: pending?.title ?? "",
|
|
72
|
+
message: pending?.message,
|
|
73
|
+
detail: pending?.detail,
|
|
74
|
+
tone: pending?.tone,
|
|
75
|
+
secondaryAction: pending?.secondaryAction,
|
|
76
|
+
confirmLabel: pending?.confirmLabel ?? confirmLabel,
|
|
77
|
+
cancelLabel: pending?.cancelLabel ?? cancelLabel,
|
|
78
|
+
closeLabel: pending?.closeLabel ?? closeLabel,
|
|
79
|
+
onConfirm: () => answer(true),
|
|
80
|
+
onCancel: () => answer(false)
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
] });
|
|
84
|
+
}
|
|
85
|
+
function useConfirm() {
|
|
86
|
+
const confirm = useContext(ConfirmContext);
|
|
87
|
+
if (!confirm) throw new Error("useConfirm: falta o <ConfirmProvider> à volta da app");
|
|
88
|
+
return confirm;
|
|
89
|
+
}
|
|
90
|
+
export {
|
|
91
|
+
ConfirmProvider,
|
|
92
|
+
ConfirmDialog as default,
|
|
93
|
+
useConfirm
|
|
94
|
+
};
|
|
95
|
+
//# sourceMappingURL=ConfirmDialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfirmDialog.js","sources":["../../../../../../src/v1/components/overlays/ConfirmDialog/ConfirmDialog.tsx"],"sourcesContent":["import React, { createContext, useCallback, useContext, useEffect, useRef, useState } from 'react'\r\nimport Dialog from '../Dialog/Dialog'\r\nimport Button from '../../../primitives/buttons/Button/Button'\r\nimport { WarningIcon } from '../../../foundations/icons/icons'\r\n\r\nexport interface ConfirmDialogProps {\r\n open: boolean\r\n /** Curto: a ação ou a pergunta (ex: \"Apagar despesa\"). */\r\n title: React.ReactNode\r\n /** A pergunta ou o que vai acontecer (ex: \"Tem a certeza que pretende apagar esta despesa?\"). */\r\n message?: React.ReactNode\r\n /** Consequência que a pessoa não adivinha sozinha (ex: \"Não se pode desfazer.\"). Em letra mais pequena. */\r\n detail?: React.ReactNode\r\n /** `danger`: apaga ou não se pode desfazer. O botão fica vermelho e aparece o sinal de atenção. */\r\n tone?: 'default' | 'danger'\r\n /** Por omissão: \"Confirmar\". */\r\n confirmLabel?: string\r\n /** Por omissão: \"Cancelar\". */\r\n cancelLabel?: string\r\n /** Nome do botão ×, para leitores de ecrã. Por omissão: \"Fechar\". */\r\n closeLabel?: string\r\n /** A confirmar (ex: à espera do servidor): o botão mostra a roda e a janela não fecha. */\r\n loading?: boolean\r\n /** Uma segunda saída (ex: \"Desativar\" em vez de apagar). Não fecha a janela sozinha. */\r\n secondaryAction?: { label: string; onClick: () => void }\r\n onConfirm: () => void\r\n /** Cancelar, ×, Esc ou clique fora. */\r\n onCancel: () => void\r\n}\r\n\r\n/**\r\n * Pergunta de sim/não antes de uma ação (ex: apagar, enviar, fechar sem\r\n * guardar). Substitui o `window.confirm` do browser, que mostra o endereço do\r\n * servidor, não diz que registo é e só tem \"OK\".\r\n *\r\n * Com `tone=\"danger\"` o foco começa em Cancelar: um Enter por engano não apaga\r\n * nada. Nos outros casos começa em Confirmar.\r\n *\r\n * Para não ter de guardar o estado em cada ecrã, usar `useConfirm()` (com o\r\n * `ConfirmProvider` à volta da app).\r\n */\r\nexport default function ConfirmDialog({\r\n open,\r\n title,\r\n message,\r\n detail,\r\n tone = 'default',\r\n confirmLabel = 'Confirmar',\r\n cancelLabel = 'Cancelar',\r\n closeLabel = 'Fechar',\r\n loading = false,\r\n secondaryAction,\r\n onConfirm,\r\n onCancel,\r\n}: ConfirmDialogProps) {\r\n const danger = tone === 'danger'\r\n const confirmRef = useRef<HTMLButtonElement>(null)\r\n const cancelRef = useRef<HTMLButtonElement>(null)\r\n\r\n // Depois de a janela abrir (o efeito do Dialog corre antes deste): o browser\r\n // poria o foco no ×, o primeiro botão da janela.\r\n useEffect(() => {\r\n if (open) (danger ? cancelRef : confirmRef).current?.focus()\r\n }, [open, danger])\r\n\r\n return (\r\n <Dialog\r\n open={open}\r\n onClose={() => !loading && onCancel()}\r\n title={title}\r\n size=\"sm\"\r\n closeLabel={closeLabel}\r\n footer={\r\n <>\r\n <Button ref={confirmRef} variant={danger ? 'danger' : 'primary'} loading={loading} onClick={onConfirm}>\r\n {confirmLabel}\r\n </Button>\r\n {secondaryAction && (\r\n <Button variant=\"secondary\" disabled={loading} onClick={secondaryAction.onClick}>\r\n {secondaryAction.label}\r\n </Button>\r\n )}\r\n <Button ref={cancelRef} variant=\"secondary\" disabled={loading} onClick={onCancel}>\r\n {cancelLabel}\r\n </Button>\r\n </>\r\n }\r\n >\r\n {/* Sem texto não há corpo: o sinal de atenção sozinho ficava a flutuar. */}\r\n {(message || detail) && (\r\n <div className=\"flex items-start gap-3\">\r\n {danger && (\r\n <span className=\"flex h-9 w-9 flex-none items-center justify-center rounded-full bg-incumprido-bg text-incumprido\">\r\n <WarningIcon size={18} />\r\n </span>\r\n )}\r\n <div className=\"min-w-0 flex-1 self-center\">\r\n {message && <div className=\"m-0 text-control leading-relaxed text-foreground\">{message}</div>}\r\n {detail && <div className=\"m-0 mt-1 text-caption leading-relaxed text-muted-foreground\">{detail}</div>}\r\n </div>\r\n </div>\r\n )}\r\n </Dialog>\r\n )\r\n}\r\n\r\nexport type ConfirmOptions = Omit<ConfirmDialogProps, 'open' | 'onConfirm' | 'onCancel' | 'loading'>\r\n\r\nconst ConfirmContext = createContext<((options: ConfirmOptions) => Promise<boolean>) | null>(null)\r\n\r\nexport interface ConfirmProviderProps {\r\n children: React.ReactNode\r\n /** Textos por omissão dos botões, para a app os traduzir. */\r\n confirmLabel?: string\r\n cancelLabel?: string\r\n closeLabel?: string\r\n}\r\n\r\n/**\r\n * Dá o `useConfirm()` a toda a app. Monta-se uma vez, à volta da app.\r\n */\r\nexport function ConfirmProvider({ children, confirmLabel, cancelLabel, closeLabel }: ConfirmProviderProps) {\r\n const [pending, setPending] = useState<ConfirmOptions | null>(null)\r\n const resolver = useRef<((ok: boolean) => void) | null>(null)\r\n\r\n const confirm = useCallback((options: ConfirmOptions) => {\r\n // Uma pergunta nova responde \"não\" à anterior que ainda estivesse aberta.\r\n resolver.current?.(false)\r\n setPending(options)\r\n return new Promise<boolean>((resolve) => {\r\n resolver.current = resolve\r\n })\r\n }, [])\r\n\r\n const answer = (ok: boolean) => {\r\n resolver.current?.(ok)\r\n resolver.current = null\r\n setPending(null)\r\n }\r\n\r\n return (\r\n <ConfirmContext.Provider value={confirm}>\r\n {children}\r\n <ConfirmDialog\r\n open={pending !== null}\r\n title={pending?.title ?? ''}\r\n message={pending?.message}\r\n detail={pending?.detail}\r\n tone={pending?.tone}\r\n secondaryAction={pending?.secondaryAction}\r\n confirmLabel={pending?.confirmLabel ?? confirmLabel}\r\n cancelLabel={pending?.cancelLabel ?? cancelLabel}\r\n closeLabel={pending?.closeLabel ?? closeLabel}\r\n onConfirm={() => answer(true)}\r\n onCancel={() => answer(false)}\r\n />\r\n </ConfirmContext.Provider>\r\n )\r\n}\r\n\r\n/**\r\n * Pergunta e espera pela resposta: `true` se confirmou, `false` se cancelou.\r\n *\r\n * const confirm = useConfirm()\r\n * if (await confirm({ title: 'Apagar despesa', message: 'Tem a certeza?', tone: 'danger', confirmLabel: 'Apagar' })) apagar()\r\n */\r\nexport function useConfirm() {\r\n const confirm = useContext(ConfirmContext)\r\n if (!confirm) throw new Error('useConfirm: falta o <ConfirmProvider> à volta da app')\r\n return confirm\r\n}\r\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useRef, useId, useContext, useEffect, createContext } from "react";
|
|
3
|
+
import { createPortal } from "react-dom";
|
|
4
|
+
const DialogContainerContext = createContext(null);
|
|
5
|
+
const DialogDepthContext = createContext(0);
|
|
6
|
+
const useDialogContainer = () => useContext(DialogContainerContext);
|
|
7
|
+
const WIDTHS = { sm: "max-w-dialog-sm", md: "max-w-dialog-md", lg: "max-w-dialog-lg", xl: "max-w-dialog-xl" };
|
|
8
|
+
const abertas = [];
|
|
9
|
+
const silenciados = /* @__PURE__ */ new Set();
|
|
10
|
+
const doTopo = () => abertas[abertas.length - 1];
|
|
11
|
+
function silenciar() {
|
|
12
|
+
for (const el of silenciados) el.removeAttribute("inert");
|
|
13
|
+
silenciados.clear();
|
|
14
|
+
const topo = doTopo();
|
|
15
|
+
if (!topo) return;
|
|
16
|
+
for (const el of Array.from(document.body.children)) {
|
|
17
|
+
if (el === topo.root || el.hasAttribute("inert")) continue;
|
|
18
|
+
el.setAttribute("inert", "");
|
|
19
|
+
silenciados.add(el);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function empilhar(aberta) {
|
|
23
|
+
const acima = abertas.findIndex((a) => a.depth > aberta.depth);
|
|
24
|
+
if (acima === -1) abertas.push(aberta);
|
|
25
|
+
else abertas.splice(acima, 0, aberta);
|
|
26
|
+
}
|
|
27
|
+
function Dialog({
|
|
28
|
+
open,
|
|
29
|
+
onClose,
|
|
30
|
+
title,
|
|
31
|
+
subtitle,
|
|
32
|
+
footer,
|
|
33
|
+
size = "md",
|
|
34
|
+
height = "auto",
|
|
35
|
+
closeOnBackdrop = true,
|
|
36
|
+
closeLabel = "Fechar",
|
|
37
|
+
flush = false,
|
|
38
|
+
children
|
|
39
|
+
}) {
|
|
40
|
+
const [root, setRoot] = useState(null);
|
|
41
|
+
const janela = useRef(null);
|
|
42
|
+
const fundo = useRef(null);
|
|
43
|
+
const titleId = useId();
|
|
44
|
+
const depth = useContext(DialogDepthContext);
|
|
45
|
+
const fechar = useRef(onClose);
|
|
46
|
+
fechar.current = onClose;
|
|
47
|
+
const pressedBackdrop = useRef(false);
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (!open || !root) return;
|
|
50
|
+
const anterior = document.activeElement;
|
|
51
|
+
const aberta = { root, janela: janela.current, depth };
|
|
52
|
+
empilhar(aberta);
|
|
53
|
+
silenciar();
|
|
54
|
+
const topo = doTopo();
|
|
55
|
+
const dentro = topo.janela?.contains(document.activeElement);
|
|
56
|
+
if (!dentro) topo.janela?.focus();
|
|
57
|
+
const onKeyDown = (e) => {
|
|
58
|
+
if (e.key !== "Escape" || e.defaultPrevented) return;
|
|
59
|
+
if (doTopo() !== aberta) return;
|
|
60
|
+
fechar.current();
|
|
61
|
+
};
|
|
62
|
+
document.addEventListener("keydown", onKeyDown);
|
|
63
|
+
return () => {
|
|
64
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
65
|
+
abertas.splice(abertas.indexOf(aberta), 1);
|
|
66
|
+
silenciar();
|
|
67
|
+
const voltar = anterior && !anterior.closest("[inert]");
|
|
68
|
+
if (voltar) anterior.focus();
|
|
69
|
+
else doTopo()?.janela?.focus();
|
|
70
|
+
};
|
|
71
|
+
}, [open, root, depth]);
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
if (!open) return;
|
|
74
|
+
const html = document.documentElement;
|
|
75
|
+
const before = html.style.overflow;
|
|
76
|
+
html.style.overflow = "hidden";
|
|
77
|
+
return () => {
|
|
78
|
+
html.style.overflow = before;
|
|
79
|
+
};
|
|
80
|
+
}, [open]);
|
|
81
|
+
const noFundo = (e) => e.target === fundo.current || e.target === e.currentTarget;
|
|
82
|
+
return createPortal(
|
|
83
|
+
/* @__PURE__ */ jsxs(
|
|
84
|
+
"div",
|
|
85
|
+
{
|
|
86
|
+
ref: setRoot,
|
|
87
|
+
hidden: !open,
|
|
88
|
+
onPointerDown: (e) => {
|
|
89
|
+
pressedBackdrop.current = noFundo(e);
|
|
90
|
+
},
|
|
91
|
+
onClick: (e) => {
|
|
92
|
+
if (closeOnBackdrop && pressedBackdrop.current && noFundo(e)) onClose();
|
|
93
|
+
},
|
|
94
|
+
className: `fixed inset-0 z-[200] items-center justify-center p-dialog-margin ${open ? "flex" : "hidden"}`,
|
|
95
|
+
children: [
|
|
96
|
+
/* @__PURE__ */ jsx("div", { ref: fundo, className: "absolute inset-0 bg-black/40 motion-safe:animate-backdrop-in" }),
|
|
97
|
+
/* @__PURE__ */ jsxs(
|
|
98
|
+
"div",
|
|
99
|
+
{
|
|
100
|
+
ref: janela,
|
|
101
|
+
role: "dialog",
|
|
102
|
+
"aria-modal": "true",
|
|
103
|
+
"aria-labelledby": titleId,
|
|
104
|
+
tabIndex: -1,
|
|
105
|
+
className: `relative flex max-h-full w-full ${WIDTHS[size]} flex-col overflow-hidden rounded-2xl bg-card text-foreground shadow-modal outline-none motion-safe:animate-dialog-in ${height === "full" ? "h-full" : ""}`,
|
|
106
|
+
children: [
|
|
107
|
+
/* @__PURE__ */ jsxs("header", { className: "flex flex-none items-center justify-between gap-3 bg-gradient-to-br from-primary to-primary-strong px-5 py-3.5", children: [
|
|
108
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
109
|
+
/* @__PURE__ */ jsx("h2", { id: titleId, className: "m-0 truncate text-title font-bold text-primary-foreground", children: title }),
|
|
110
|
+
subtitle && /* @__PURE__ */ jsx("p", { className: "m-0 mt-0.5 truncate text-caption text-primary-foreground/75", children: subtitle })
|
|
111
|
+
] }),
|
|
112
|
+
/* @__PURE__ */ jsx(
|
|
113
|
+
"button",
|
|
114
|
+
{
|
|
115
|
+
type: "button",
|
|
116
|
+
"aria-label": closeLabel,
|
|
117
|
+
title: closeLabel,
|
|
118
|
+
onClick: onClose,
|
|
119
|
+
className: "flex h-7 w-7 flex-none cursor-pointer items-center justify-center rounded-md border border-primary-foreground/25 bg-primary-foreground/15 text-base leading-none text-primary-foreground transition-colors hover:bg-primary-foreground/25 focus-visible:ring-2 focus-visible:ring-primary-foreground/60 focus-visible:outline-none",
|
|
120
|
+
children: "×"
|
|
121
|
+
}
|
|
122
|
+
)
|
|
123
|
+
] }),
|
|
124
|
+
/* @__PURE__ */ jsx(DialogContainerContext.Provider, { value: root, children: /* @__PURE__ */ jsxs(DialogDepthContext.Provider, { value: depth + 1, children: [
|
|
125
|
+
/* @__PURE__ */ jsx("div", { className: flush ? "flex min-h-0 flex-1 flex-col overflow-hidden bg-canvas" : "min-h-0 flex-1 overflow-y-auto bg-canvas px-5 py-4", children }),
|
|
126
|
+
footer && /* @__PURE__ */ jsx("footer", { className: "flex flex-none flex-wrap justify-end gap-2 border-t border-border bg-muted/40 px-5 py-[18px]", children: footer })
|
|
127
|
+
] }) })
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
)
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
),
|
|
134
|
+
document.body
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
export {
|
|
138
|
+
Dialog as default,
|
|
139
|
+
useDialogContainer
|
|
140
|
+
};
|
|
141
|
+
//# sourceMappingURL=Dialog.js.map
|