@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,37 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useRef, useImperativeHandle, useEffect } from "react";
|
|
3
|
+
import { CheckIcon } from "../../../foundations/icons/icons.js";
|
|
4
|
+
import { useField } from "../field.js";
|
|
5
|
+
const Checkbox = forwardRef(function Checkbox2({ invalid, indeterminate = false, className = "", id, required, ...props }, ref) {
|
|
6
|
+
const field = useField();
|
|
7
|
+
const caixa = useRef(null);
|
|
8
|
+
useImperativeHandle(ref, () => caixa.current);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
if (caixa.current) caixa.current.indeterminate = indeterminate;
|
|
11
|
+
});
|
|
12
|
+
return /* @__PURE__ */ jsxs("span", { className: `relative inline-flex size-4 shrink-0 ${className}`, children: [
|
|
13
|
+
/* @__PURE__ */ jsx(
|
|
14
|
+
"input",
|
|
15
|
+
{
|
|
16
|
+
ref: caixa,
|
|
17
|
+
type: "checkbox",
|
|
18
|
+
id: id ?? field.id,
|
|
19
|
+
required: required ?? field.required,
|
|
20
|
+
"aria-invalid": invalid || void 0,
|
|
21
|
+
className: "peer absolute inset-0 m-0 size-full cursor-pointer appearance-none rounded-sm border border-muted-foreground/40 bg-card outline-none transition-[background-color,border-color,box-shadow] duration-150 checked:border-primary checked:bg-primary indeterminate:border-primary indeterminate:bg-primary focus-visible:ring-3 focus-visible:ring-primary/20 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/15 disabled:cursor-not-allowed disabled:bg-muted disabled:checked:border-border disabled:checked:bg-muted disabled:indeterminate:border-border disabled:indeterminate:bg-muted",
|
|
22
|
+
...props
|
|
23
|
+
}
|
|
24
|
+
),
|
|
25
|
+
indeterminate ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "pointer-events-none absolute inset-0 m-auto h-0.5 w-2 rounded-full bg-primary-foreground peer-disabled:bg-muted-foreground" }) : /* @__PURE__ */ jsx(
|
|
26
|
+
CheckIcon,
|
|
27
|
+
{
|
|
28
|
+
size: 12,
|
|
29
|
+
className: "pointer-events-none absolute inset-0 m-auto hidden text-primary-foreground peer-checked:block peer-disabled:text-muted-foreground"
|
|
30
|
+
}
|
|
31
|
+
)
|
|
32
|
+
] });
|
|
33
|
+
});
|
|
34
|
+
export {
|
|
35
|
+
Checkbox as default
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=Checkbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Checkbox.js","sources":["../../../../../../src/v1/primitives/forms/Checkbox/Checkbox.tsx"],"sourcesContent":["import React, { forwardRef, useEffect, useImperativeHandle, useRef } from 'react'\r\nimport { CheckIcon } from '../../../foundations/icons/icons'\r\nimport { useField } from '../field'\r\n\r\nexport interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type'> {\r\n /** Marca a caixa a vermelho (ex: aceitar os termos, por marcar ao submeter). */\r\n invalid?: boolean\r\n /**\r\n * Meio marcada: um traço em vez do visto (ex: \"selecionar todos\" com só\r\n * algumas marcadas). Só o aspeto: ao clicar, o browser tira-o e a caixa passa\r\n * a marcada ou desmarcada pelo `onChange`, como sempre. Para leitores de ecrã é\r\n * \"parcialmente marcada\".\r\n */\r\n indeterminate?: boolean\r\n}\r\n\r\n/**\r\n * Caixa de marcar.\r\n *\r\n * Dentro de um [FormField](?path=/docs/v1-components-forms-formfield--docs) fica\r\n * ligada à etiqueta automaticamente. Fora dele, dar-lhe um `aria-label` ou\r\n * envolvê-la num `<label>`: sozinha não tem nome para os leitores de ecrã.\r\n *\r\n * **Aceita os atributos HTML do [<input type=\"checkbox\">](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input/checkbox)**, com o mesmo comportamento: `checked`/`defaultChecked`, `onChange`, `required`, `disabled`, `name`, `value`, `ref`, ...\r\n * Só os próprios do V1 aparecem na tabela abaixo.\r\n * Diferenças: o `className` aplica-se à caixa à volta; o `type` é sempre `checkbox`.\r\n */\r\nconst Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(function Checkbox({ invalid, indeterminate = false, className = '', id, required, ...props }, ref) {\r\n const field = useField()\r\n // O meio-marcado não é atributo HTML, só propriedade do elemento: vai pela ref.\r\n const caixa = useRef<HTMLInputElement>(null)\r\n useImperativeHandle(ref, () => caixa.current!)\r\n // A cada render, e não só quando a prop muda: um clique tira-o no browser, e\r\n // se a app o mantiver, tem de voltar.\r\n useEffect(() => { if (caixa.current) caixa.current.indeterminate = indeterminate })\r\n return (\r\n <span className={`relative inline-flex size-4 shrink-0 ${className}`}>\r\n <input\r\n ref={caixa}\r\n type=\"checkbox\"\r\n id={id ?? field.id}\r\n required={required ?? field.required}\r\n aria-invalid={invalid || undefined}\r\n className={\r\n 'peer absolute inset-0 m-0 size-full cursor-pointer appearance-none rounded-sm border border-muted-foreground/40 bg-card outline-none ' +\r\n 'transition-[background-color,border-color,box-shadow] duration-150 ' +\r\n 'checked:border-primary checked:bg-primary indeterminate:border-primary indeterminate:bg-primary ' +\r\n 'focus-visible:ring-3 focus-visible:ring-primary/20 ' +\r\n 'aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/15 ' +\r\n 'disabled:cursor-not-allowed disabled:bg-muted disabled:checked:border-border disabled:checked:bg-muted disabled:indeterminate:border-border disabled:indeterminate:bg-muted'\r\n }\r\n {...props}\r\n />\r\n {indeterminate ? (\r\n <span aria-hidden className=\"pointer-events-none absolute inset-0 m-auto h-0.5 w-2 rounded-full bg-primary-foreground peer-disabled:bg-muted-foreground\" />\r\n ) : (\r\n <CheckIcon\r\n size={12}\r\n className=\"pointer-events-none absolute inset-0 m-auto hidden text-primary-foreground peer-checked:block peer-disabled:text-muted-foreground\"\r\n />\r\n )}\r\n </span>\r\n )\r\n})\r\n\r\nexport default Checkbox\r\n"],"names":["Checkbox"],"mappings":";;;;AA2BA,MAAM,WAAW,WAA4C,SAASA,UAAS,EAAE,SAAS,gBAAgB,OAAO,YAAY,IAAI,IAAI,UAAU,GAAG,MAAA,GAAS,KAAK;AAC9J,QAAM,QAAQ,SAAA;AAEd,QAAM,QAAQ,OAAyB,IAAI;AAC3C,sBAAoB,KAAK,MAAM,MAAM,OAAQ;AAG7C,YAAU,MAAM;AAAE,QAAI,MAAM,QAAS,OAAM,QAAQ,gBAAgB;AAAA,EAAc,CAAC;AAClF,SACE,qBAAC,QAAA,EAAK,WAAW,wCAAwC,SAAS,IAChE,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAK;AAAA,QACL,MAAK;AAAA,QACL,IAAI,MAAM,MAAM;AAAA,QAChB,UAAU,YAAY,MAAM;AAAA,QAC5B,gBAAc,WAAW;AAAA,QACzB,WACE;AAAA,QAOD,GAAG;AAAA,MAAA;AAAA,IAAA;AAAA,IAEL,gBACC,oBAAC,QAAA,EAAK,eAAW,MAAC,WAAU,8HAA6H,IAEzJ;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAM;AAAA,QACN,WAAU;AAAA,MAAA;AAAA,IAAA;AAAA,EACZ,GAEJ;AAEJ,CAAC;"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useRef, useEffect } from "react";
|
|
3
|
+
import { useField, fieldClasses, readOnlyClasses } from "../field.js";
|
|
4
|
+
const isoToBr = (iso) => {
|
|
5
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})/.exec(iso ?? "");
|
|
6
|
+
return m ? `${m[3]}/${m[2]}/${m[1]}` : "";
|
|
7
|
+
};
|
|
8
|
+
const brToIso = (br) => {
|
|
9
|
+
const m = /^(\d{2})\/(\d{2})\/(\d{4})$/.exec(br.trim());
|
|
10
|
+
if (!m) return "";
|
|
11
|
+
const [, dd, mm, yyyy] = m;
|
|
12
|
+
const d = /* @__PURE__ */ new Date(`${yyyy}-${mm}-${dd}T00:00:00`);
|
|
13
|
+
if (Number.isNaN(d.getTime()) || d.getDate() !== Number(dd) || d.getMonth() + 1 !== Number(mm)) return "";
|
|
14
|
+
return `${yyyy}-${mm}-${dd}`;
|
|
15
|
+
};
|
|
16
|
+
const mask = (raw) => {
|
|
17
|
+
const d = raw.replace(/\D/g, "").slice(0, 8);
|
|
18
|
+
if (d.length <= 2) return d;
|
|
19
|
+
if (d.length <= 4) return `${d.slice(0, 2)}/${d.slice(2)}`;
|
|
20
|
+
return `${d.slice(0, 2)}/${d.slice(2, 4)}/${d.slice(4)}`;
|
|
21
|
+
};
|
|
22
|
+
function CalendarIcon() {
|
|
23
|
+
return /* @__PURE__ */ jsxs("svg", { "aria-hidden": true, viewBox: "0 0 24 24", width: 13, height: 13, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
24
|
+
/* @__PURE__ */ jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2" }),
|
|
25
|
+
/* @__PURE__ */ jsx("path", { d: "M16 2v4M8 2v4M3 10h18" })
|
|
26
|
+
] });
|
|
27
|
+
}
|
|
28
|
+
function DateInput({
|
|
29
|
+
value,
|
|
30
|
+
defaultValue,
|
|
31
|
+
onChange,
|
|
32
|
+
onBlur,
|
|
33
|
+
onKeyDown,
|
|
34
|
+
min,
|
|
35
|
+
max,
|
|
36
|
+
disabled,
|
|
37
|
+
readOnly,
|
|
38
|
+
required,
|
|
39
|
+
autoFocus,
|
|
40
|
+
id,
|
|
41
|
+
invalid,
|
|
42
|
+
placeholder = "dd/mm/aaaa",
|
|
43
|
+
"aria-label": ariaLabel,
|
|
44
|
+
calendarLabel = "Abrir calendário",
|
|
45
|
+
className = ""
|
|
46
|
+
}) {
|
|
47
|
+
const field = useField();
|
|
48
|
+
const controlled = value !== void 0;
|
|
49
|
+
const [iso, setIso] = useState(value ?? defaultValue ?? "");
|
|
50
|
+
const [text, setText] = useState(isoToBr(value ?? defaultValue ?? ""));
|
|
51
|
+
const nativeRef = useRef(null);
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
if (!controlled) return;
|
|
54
|
+
const outside = value ?? "";
|
|
55
|
+
if (outside === brToIso(text)) return;
|
|
56
|
+
setIso(outside);
|
|
57
|
+
setText(isoToBr(outside));
|
|
58
|
+
}, [value, controlled]);
|
|
59
|
+
const onBlurRef = useRef(onBlur);
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
onBlurRef.current = onBlur;
|
|
62
|
+
});
|
|
63
|
+
const pendingCommit = useRef(false);
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (!pendingCommit.current) return;
|
|
66
|
+
pendingCommit.current = false;
|
|
67
|
+
onBlurRef.current?.();
|
|
68
|
+
}, [value]);
|
|
69
|
+
const emit = (next) => {
|
|
70
|
+
setIso(next);
|
|
71
|
+
onChange?.(next);
|
|
72
|
+
};
|
|
73
|
+
const type = (raw) => {
|
|
74
|
+
const masked = mask(raw);
|
|
75
|
+
setText(masked);
|
|
76
|
+
if (masked === "") return emit("");
|
|
77
|
+
const next = brToIso(masked);
|
|
78
|
+
if (next) emit(next);
|
|
79
|
+
};
|
|
80
|
+
const leave = () => {
|
|
81
|
+
if (text !== "" && !brToIso(text)) setText(isoToBr(iso));
|
|
82
|
+
onBlur?.();
|
|
83
|
+
};
|
|
84
|
+
const openCalendar = () => {
|
|
85
|
+
const el = nativeRef.current;
|
|
86
|
+
if (!el || disabled || readOnly) return;
|
|
87
|
+
if (typeof el.showPicker === "function") el.showPicker();
|
|
88
|
+
else el.click();
|
|
89
|
+
};
|
|
90
|
+
return /* @__PURE__ */ jsxs("span", { className: `relative inline-flex w-full items-center ${className}`, children: [
|
|
91
|
+
/* @__PURE__ */ jsx(
|
|
92
|
+
"input",
|
|
93
|
+
{
|
|
94
|
+
id: id ?? field.id,
|
|
95
|
+
type: "text",
|
|
96
|
+
inputMode: "numeric",
|
|
97
|
+
autoComplete: "off",
|
|
98
|
+
"aria-label": ariaLabel,
|
|
99
|
+
"aria-invalid": invalid || void 0,
|
|
100
|
+
placeholder,
|
|
101
|
+
value: text,
|
|
102
|
+
onChange: (e) => type(e.target.value),
|
|
103
|
+
onBlur: leave,
|
|
104
|
+
onKeyDown,
|
|
105
|
+
autoFocus,
|
|
106
|
+
disabled,
|
|
107
|
+
readOnly,
|
|
108
|
+
required: required ?? field.required,
|
|
109
|
+
className: `h-control ${fieldClasses} ${readOnlyClasses} pr-8 tabular-nums`
|
|
110
|
+
}
|
|
111
|
+
),
|
|
112
|
+
!disabled && !readOnly && /* @__PURE__ */ jsx(
|
|
113
|
+
"button",
|
|
114
|
+
{
|
|
115
|
+
type: "button",
|
|
116
|
+
tabIndex: -1,
|
|
117
|
+
onClick: openCalendar,
|
|
118
|
+
"aria-label": calendarLabel,
|
|
119
|
+
"data-tip": calendarLabel,
|
|
120
|
+
className: "absolute right-1.5 flex h-6 w-6 cursor-pointer items-center justify-center rounded border-0 bg-transparent p-0 text-muted-foreground hover:text-foreground",
|
|
121
|
+
children: /* @__PURE__ */ jsx(CalendarIcon, {})
|
|
122
|
+
}
|
|
123
|
+
),
|
|
124
|
+
/* @__PURE__ */ jsx(
|
|
125
|
+
"input",
|
|
126
|
+
{
|
|
127
|
+
ref: nativeRef,
|
|
128
|
+
type: "date",
|
|
129
|
+
tabIndex: -1,
|
|
130
|
+
"aria-hidden": true,
|
|
131
|
+
value: iso,
|
|
132
|
+
min,
|
|
133
|
+
max,
|
|
134
|
+
onChange: (e) => {
|
|
135
|
+
const v = e.target.value;
|
|
136
|
+
setText(isoToBr(v));
|
|
137
|
+
emit(v);
|
|
138
|
+
if (controlled) pendingCommit.current = true;
|
|
139
|
+
else onBlurRef.current?.();
|
|
140
|
+
},
|
|
141
|
+
className: "sr-only absolute right-1.5 bottom-0 h-0 w-0 border-0 p-0"
|
|
142
|
+
}
|
|
143
|
+
)
|
|
144
|
+
] });
|
|
145
|
+
}
|
|
146
|
+
export {
|
|
147
|
+
DateInput,
|
|
148
|
+
DateInput as default
|
|
149
|
+
};
|
|
150
|
+
//# sourceMappingURL=DateInput.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DateInput.js","sources":["../../../../../../src/v1/primitives/forms/DateInput/DateInput.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react'\r\nimport { fieldClasses, readOnlyClasses, useField } from '../field'\r\n\r\nexport interface DateInputProps {\r\n /** Data em ISO (`aaaa-mm-dd`) ou `''` (vazio). Controlado. */\r\n value?: string\r\n /** Valor inicial, sem controlar (ISO). */\r\n defaultValue?: string\r\n /** Recebe só datas completas e válidas, em ISO; `''` quando se apaga. Enquanto se escreve, não é chamado. */\r\n onChange?: (value: string) => void\r\n /** Ao terminar a edição: sair do campo ou escolher no calendário. */\r\n onBlur?: () => void\r\n onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void\r\n /** Limites, em ISO (só no calendário). */\r\n min?: string\r\n max?: string\r\n disabled?: boolean\r\n readOnly?: boolean\r\n required?: boolean\r\n autoFocus?: boolean\r\n id?: string\r\n /** Marca o campo a vermelho (ex: obrigatório por preencher ao submeter). */\r\n invalid?: boolean\r\n placeholder?: string\r\n /** Nome do campo para leitores de ecrã, quando não há etiqueta. */\r\n 'aria-label'?: string\r\n /** Texto do botão do calendário. */\r\n calendarLabel?: string\r\n /** Classes da caixa à volta (ex: largura). */\r\n className?: string\r\n}\r\n\r\nconst isoToBr = (iso: string): string => {\r\n const m = /^(\\d{4})-(\\d{2})-(\\d{2})/.exec(iso ?? '')\r\n return m ? `${m[3]}/${m[2]}/${m[1]}` : ''\r\n}\r\n\r\nconst brToIso = (br: string): string => {\r\n const m = /^(\\d{2})\\/(\\d{2})\\/(\\d{4})$/.exec(br.trim())\r\n if (!m) return ''\r\n const [, dd, mm, yyyy] = m\r\n const d = new Date(`${yyyy}-${mm}-${dd}T00:00:00`)\r\n // Rejeita 31/02 e afins: o Date normaliza para 03/03 em vez de falhar.\r\n if (Number.isNaN(d.getTime()) || d.getDate() !== Number(dd) || d.getMonth() + 1 !== Number(mm)) return ''\r\n return `${yyyy}-${mm}-${dd}`\r\n}\r\n\r\n/** Mascara o que se escreve, deixando só dígitos e pondo as barras no sítio. */\r\nconst mask = (raw: string): string => {\r\n const d = raw.replace(/\\D/g, '').slice(0, 8)\r\n if (d.length <= 2) return d\r\n if (d.length <= 4) return `${d.slice(0, 2)}/${d.slice(2)}`\r\n return `${d.slice(0, 2)}/${d.slice(2, 4)}/${d.slice(4)}`\r\n}\r\n\r\nfunction CalendarIcon() {\r\n return (\r\n <svg aria-hidden viewBox=\"0 0 24 24\" width={13} height={13} fill=\"none\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\" />\r\n <path d=\"M16 2v4M8 2v4M3 10h18\" />\r\n </svg>\r\n )\r\n}\r\n\r\n/**\r\n * Campo de data, sempre em **dd/mm/aaaa**.\r\n *\r\n * O `<input type=\"date\">` do browser mostra a data no idioma do BROWSER, não no\r\n * da página (num Chrome em inglês aparece mm/dd/aaaa), e não há atributo que o\r\n * force. Aqui o texto é escrito pela biblioteca, com máscara; o calendário\r\n * continua a ser o nativo (acessível e traduzido), aberto pelo ícone.\r\n *\r\n * O valor entra e sai em ISO (`aaaa-mm-dd`). Dentro de um\r\n * [FormField](?path=/docs/v1-components-forms-formfield--docs) fica ligado à\r\n * etiqueta automaticamente.\r\n */\r\nexport default function DateInput({\r\n value,\r\n defaultValue,\r\n onChange,\r\n onBlur,\r\n onKeyDown,\r\n min,\r\n max,\r\n disabled,\r\n readOnly,\r\n required,\r\n autoFocus,\r\n id,\r\n invalid,\r\n placeholder = 'dd/mm/aaaa',\r\n 'aria-label': ariaLabel,\r\n calendarLabel = 'Abrir calendário',\r\n className = '',\r\n}: DateInputProps) {\r\n const field = useField()\r\n const controlled = value !== undefined\r\n const [iso, setIso] = useState(value ?? defaultValue ?? '')\r\n const [text, setText] = useState(isoToBr(value ?? defaultValue ?? ''))\r\n const nativeRef = useRef<HTMLInputElement>(null)\r\n\r\n // Segue o valor de fora, exceto enquanto o campo tem uma data a meio: senão\r\n // um re-render durante a escrita apagava os dígitos já introduzidos.\r\n useEffect(() => {\r\n if (!controlled) return\r\n const outside = value ?? ''\r\n if (outside === brToIso(text)) return\r\n setIso(outside)\r\n setText(isoToBr(outside))\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [value, controlled])\r\n\r\n // Escolher no calendário conta como terminar a edição (quem grava está quase\r\n // sempre no `onBlur`). O aviso espera que o valor novo volte em `value`:\r\n // chamado logo, o `onBlur` de fora ainda lia o valor anterior.\r\n const onBlurRef = useRef(onBlur)\r\n useEffect(() => {\r\n onBlurRef.current = onBlur\r\n })\r\n const pendingCommit = useRef(false)\r\n useEffect(() => {\r\n if (!pendingCommit.current) return\r\n pendingCommit.current = false\r\n onBlurRef.current?.()\r\n }, [value])\r\n\r\n const emit = (next: string) => {\r\n setIso(next)\r\n onChange?.(next)\r\n }\r\n\r\n const type = (raw: string) => {\r\n const masked = mask(raw)\r\n setText(masked)\r\n if (masked === '') return emit('')\r\n const next = brToIso(masked)\r\n if (next) emit(next)\r\n }\r\n\r\n // Ao sair, uma data incompleta ou impossível volta ao último valor bom.\r\n const leave = () => {\r\n if (text !== '' && !brToIso(text)) setText(isoToBr(iso))\r\n onBlur?.()\r\n }\r\n\r\n const openCalendar = () => {\r\n const el = nativeRef.current\r\n if (!el || disabled || readOnly) return\r\n // showPicker() é o caminho normal; sem ele (browsers antigos) resta o clique.\r\n if (typeof (el as HTMLInputElement & { showPicker?: () => void }).showPicker === 'function') el.showPicker()\r\n else el.click()\r\n }\r\n\r\n return (\r\n <span className={`relative inline-flex w-full items-center ${className}`}>\r\n <input\r\n id={id ?? field.id}\r\n type=\"text\"\r\n inputMode=\"numeric\"\r\n autoComplete=\"off\"\r\n aria-label={ariaLabel}\r\n aria-invalid={invalid || undefined}\r\n placeholder={placeholder}\r\n value={text}\r\n onChange={(e) => type(e.target.value)}\r\n onBlur={leave}\r\n onKeyDown={onKeyDown}\r\n autoFocus={autoFocus}\r\n disabled={disabled}\r\n readOnly={readOnly}\r\n required={required ?? field.required}\r\n className={`h-control ${fieldClasses} ${readOnlyClasses} pr-8 tabular-nums`}\r\n />\r\n {!disabled && !readOnly && (\r\n <button\r\n type=\"button\"\r\n tabIndex={-1}\r\n onClick={openCalendar}\r\n aria-label={calendarLabel}\r\n data-tip={calendarLabel}\r\n className=\"absolute right-1.5 flex h-6 w-6 cursor-pointer items-center justify-center rounded border-0 bg-transparent p-0 text-muted-foreground hover:text-foreground\"\r\n >\r\n <CalendarIcon />\r\n </button>\r\n )}\r\n {/* O nativo só serve de calendário: nunca se vê, por isso o idioma dele não\r\n chega ao ecrã. `sr-only` em vez de display:none — o showPicker() recusa\r\n abrir num campo escondido. */}\r\n <input\r\n ref={nativeRef}\r\n type=\"date\"\r\n tabIndex={-1}\r\n aria-hidden\r\n value={iso}\r\n min={min}\r\n max={max}\r\n onChange={(e) => {\r\n const v = e.target.value\r\n setText(isoToBr(v))\r\n emit(v)\r\n // Sem `value` de fora não há nada por que esperar.\r\n if (controlled) pendingCommit.current = true\r\n else onBlurRef.current?.()\r\n }}\r\n className=\"sr-only absolute right-1.5 bottom-0 h-0 w-0 border-0 p-0\"\r\n />\r\n </span>\r\n )\r\n}\r\n\r\nexport { DateInput }\r\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { SearchIcon } from "../../../foundations/icons/icons.js";
|
|
3
|
+
import { useField, fieldClasses, readOnlyClasses } from "../field.js";
|
|
4
|
+
function LookupInput({ value, onLookup, lookupLabel, placeholder, invalid, disabled, id, className = "" }) {
|
|
5
|
+
const field = useField();
|
|
6
|
+
return /* @__PURE__ */ jsxs("div", { className: `flex min-w-0 items-center gap-1.5 ${className}`, children: [
|
|
7
|
+
/* @__PURE__ */ jsx(
|
|
8
|
+
"input",
|
|
9
|
+
{
|
|
10
|
+
id: id ?? field.id,
|
|
11
|
+
readOnly: true,
|
|
12
|
+
required: field.required,
|
|
13
|
+
disabled,
|
|
14
|
+
value,
|
|
15
|
+
placeholder,
|
|
16
|
+
"aria-invalid": invalid || void 0,
|
|
17
|
+
className: `h-control ${fieldClasses} ${readOnlyClasses}`
|
|
18
|
+
}
|
|
19
|
+
),
|
|
20
|
+
/* @__PURE__ */ jsx(
|
|
21
|
+
"button",
|
|
22
|
+
{
|
|
23
|
+
type: "button",
|
|
24
|
+
onClick: onLookup,
|
|
25
|
+
disabled,
|
|
26
|
+
"aria-label": lookupLabel,
|
|
27
|
+
title: lookupLabel,
|
|
28
|
+
className: "flex h-control w-control flex-none cursor-pointer items-center justify-center rounded-lg border border-border bg-muted text-muted-foreground transition-colors duration-150 hover:border-primary/25 hover:bg-primary/5 hover:text-primary focus-visible:border-primary/40 focus-visible:ring-3 focus-visible:ring-primary/10 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:border-border disabled:hover:bg-muted disabled:hover:text-muted-foreground",
|
|
29
|
+
children: /* @__PURE__ */ jsx(SearchIcon, { size: 14 })
|
|
30
|
+
}
|
|
31
|
+
)
|
|
32
|
+
] });
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
LookupInput as default
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=LookupInput.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LookupInput.js","sources":["../../../../../../src/v1/primitives/forms/LookupInput/LookupInput.tsx"],"sourcesContent":["import React from 'react'\r\nimport { SearchIcon } from '../../../foundations/icons/icons'\r\nimport { fieldClasses, readOnlyClasses, useField } from '../field'\r\n\r\nexport interface LookupInputProps {\r\n /** O que foi escolhido, como a app o quer mostrar (ex: \"PRJ-0001 - Projeto de exemplo\"). Vazio se nada. */\r\n value: string\r\n /** Chamado ao carregar na lupa: a app abre a sua pesquisa e, quando se escolhe algo, atualiza o `value`. */\r\n onLookup: () => void\r\n /** O que a lupa faz (ex: \"Pesquisar projeto\"). Lido pelos leitores de ecrã e mostrado ao passar o rato. */\r\n lookupLabel: string\r\n /** Texto quando não há nada escolhido (ex: \"Nenhum projeto\"). */\r\n placeholder?: string\r\n /** Marca o campo a vermelho (ex: obrigatório por escolher ao submeter). */\r\n invalid?: boolean\r\n disabled?: boolean\r\n id?: string\r\n /** Aplica-se à caixa à volta (para a largura, por exemplo). */\r\n className?: string\r\n}\r\n\r\n/**\r\n * Campo que **não se escreve**: o valor escolhe-se numa pesquisa, aberta pela\r\n * lupa ao lado (ex: escolher um projeto). A pesquisa é da app; este campo só\r\n * mostra o que foi escolhido.\r\n *\r\n * Dentro de um [FormField](?path=/docs/v1-components-forms-formfield--docs) fica\r\n * ligado à etiqueta automaticamente.\r\n *\r\n * Não é como um `<input>` HTML: só aceita as props da tabela abaixo.\r\n */\r\nexport default function LookupInput({ value, onLookup, lookupLabel, placeholder, invalid, disabled, id, className = '' }: LookupInputProps) {\r\n const field = useField()\r\n return (\r\n <div className={`flex min-w-0 items-center gap-1.5 ${className}`}>\r\n <input\r\n id={id ?? field.id}\r\n readOnly\r\n required={field.required}\r\n disabled={disabled}\r\n value={value}\r\n placeholder={placeholder}\r\n aria-invalid={invalid || undefined}\r\n className={`h-control ${fieldClasses} ${readOnlyClasses}`}\r\n />\r\n <button\r\n type=\"button\"\r\n onClick={onLookup}\r\n disabled={disabled}\r\n aria-label={lookupLabel}\r\n title={lookupLabel}\r\n className={\r\n 'flex h-control w-control flex-none cursor-pointer items-center justify-center rounded-lg border border-border bg-muted text-muted-foreground ' +\r\n 'transition-colors duration-150 hover:border-primary/25 hover:bg-primary/5 hover:text-primary ' +\r\n 'focus-visible:border-primary/40 focus-visible:ring-3 focus-visible:ring-primary/10 focus-visible:outline-none ' +\r\n 'disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:border-border disabled:hover:bg-muted disabled:hover:text-muted-foreground'\r\n }\r\n >\r\n <SearchIcon size={14} />\r\n </button>\r\n </div>\r\n )\r\n}\r\n"],"names":[],"mappings":";;;AA+BA,SAAwB,YAAY,EAAE,OAAO,UAAU,aAAa,aAAa,SAAS,UAAU,IAAI,YAAY,GAAA,GAAwB;AAC1I,QAAM,QAAQ,SAAA;AACd,SACE,qBAAC,OAAA,EAAI,WAAW,qCAAqC,SAAS,IAC5D,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,IAAI,MAAM,MAAM;AAAA,QAChB,UAAQ;AAAA,QACR,UAAU,MAAM;AAAA,QAChB;AAAA,QACA;AAAA,QACA;AAAA,QACA,gBAAc,WAAW;AAAA,QACzB,WAAW,aAAa,YAAY,IAAI,eAAe;AAAA,MAAA;AAAA,IAAA;AAAA,IAEzD;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS;AAAA,QACT;AAAA,QACA,cAAY;AAAA,QACZ,OAAO;AAAA,QACP,WACE;AAAA,QAMF,UAAA,oBAAC,YAAA,EAAW,MAAM,GAAA,CAAI;AAAA,MAAA;AAAA,IAAA;AAAA,EACxB,GACF;AAEJ;"}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { jsxs, Fragment, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useRef, useState, useCallback, useEffect } from "react";
|
|
3
|
+
import { useEditor, Extension, useEditorState, EditorContent } from "@tiptap/react";
|
|
4
|
+
import StarterKit from "@tiptap/starter-kit";
|
|
5
|
+
import Image from "@tiptap/extension-image";
|
|
6
|
+
import { useField } from "../field.js";
|
|
7
|
+
import { richTextContentClasses, isRichText, textToRichText, richTextIsEmpty } from "../../display/RichText/utils.js";
|
|
8
|
+
import { BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, ListBulletIcon, ListNumberedIcon, QuoteIcon, ImageIcon, MinimizeIcon, MaximizeIcon } from "../../../foundations/icons/icons.js";
|
|
9
|
+
const DEFAULT_LABELS = {
|
|
10
|
+
bold: "Negrito (Ctrl+B)",
|
|
11
|
+
italic: "Itálico (Ctrl+I)",
|
|
12
|
+
underline: "Sublinhado (Ctrl+U)",
|
|
13
|
+
strike: "Riscado",
|
|
14
|
+
bulletList: "Lista com marcas",
|
|
15
|
+
orderedList: "Lista numerada",
|
|
16
|
+
quote: "Citação",
|
|
17
|
+
image: "Inserir imagem",
|
|
18
|
+
maximize: "Maximizar",
|
|
19
|
+
restore: "Restaurar"
|
|
20
|
+
};
|
|
21
|
+
function imageFiles(data) {
|
|
22
|
+
return Array.from(data?.files ?? []).filter((f) => f.type.startsWith("image/"));
|
|
23
|
+
}
|
|
24
|
+
function editorValue(editor) {
|
|
25
|
+
const html = editor.getHTML();
|
|
26
|
+
return richTextIsEmpty(html) ? "" : html;
|
|
27
|
+
}
|
|
28
|
+
function ToolbarButton({ label, active, disabled, onClick, children }) {
|
|
29
|
+
return /* @__PURE__ */ jsx(
|
|
30
|
+
"button",
|
|
31
|
+
{
|
|
32
|
+
type: "button",
|
|
33
|
+
"aria-label": label,
|
|
34
|
+
title: label,
|
|
35
|
+
"aria-pressed": active === void 0 ? void 0 : active,
|
|
36
|
+
disabled,
|
|
37
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
38
|
+
onClick,
|
|
39
|
+
className: "inline-flex h-7 w-7 cursor-pointer items-center justify-center rounded-md transition-colors duration-150 focus-visible:ring-2 focus-visible:ring-primary/30 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 " + (active ? "bg-primary/10 text-primary dark:bg-slate-700 dark:text-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground dark:hover:bg-slate-800"),
|
|
40
|
+
children
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
const Separator = () => /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "mx-1 h-4 w-px bg-border" });
|
|
45
|
+
function RichTextEditor({
|
|
46
|
+
value,
|
|
47
|
+
onChange,
|
|
48
|
+
placeholder,
|
|
49
|
+
invalid,
|
|
50
|
+
disabled,
|
|
51
|
+
minHeight = 80,
|
|
52
|
+
maxHeight,
|
|
53
|
+
onUploadImage,
|
|
54
|
+
maximizable,
|
|
55
|
+
onSubmit,
|
|
56
|
+
submitOnEnter,
|
|
57
|
+
autoFocus,
|
|
58
|
+
"aria-label": ariaLabel,
|
|
59
|
+
id,
|
|
60
|
+
className = "",
|
|
61
|
+
labels: labelsProp
|
|
62
|
+
}) {
|
|
63
|
+
const labels = { ...DEFAULT_LABELS, ...labelsProp };
|
|
64
|
+
const field = useField();
|
|
65
|
+
const fileInputRef = useRef(null);
|
|
66
|
+
const [maximized, setMaximized] = useState(false);
|
|
67
|
+
const onChangeRef = useRef(onChange);
|
|
68
|
+
onChangeRef.current = onChange;
|
|
69
|
+
const uploadRef = useRef(onUploadImage);
|
|
70
|
+
uploadRef.current = onUploadImage;
|
|
71
|
+
const submitRef = useRef({ onSubmit, submitOnEnter });
|
|
72
|
+
submitRef.current = { onSubmit, submitOnEnter };
|
|
73
|
+
const emitted = useRef(null);
|
|
74
|
+
const editorRef = useRef(null);
|
|
75
|
+
const insertImages = useCallback(async (files) => {
|
|
76
|
+
for (const file of files) {
|
|
77
|
+
try {
|
|
78
|
+
const src = await uploadRef.current(file);
|
|
79
|
+
editorRef.current?.chain().focus().setImage({ src }).run();
|
|
80
|
+
} catch {
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}, []);
|
|
84
|
+
const editor = useEditor({
|
|
85
|
+
extensions: [
|
|
86
|
+
StarterKit.configure({
|
|
87
|
+
heading: false,
|
|
88
|
+
codeBlock: false,
|
|
89
|
+
horizontalRule: false,
|
|
90
|
+
link: { openOnClick: false, autolink: true, defaultProtocol: "https" }
|
|
91
|
+
}),
|
|
92
|
+
Image.configure({ inline: false, allowBase64: true }),
|
|
93
|
+
Extension.create({
|
|
94
|
+
name: "submitShortcut",
|
|
95
|
+
addKeyboardShortcuts() {
|
|
96
|
+
const submit = () => {
|
|
97
|
+
const { onSubmit: send } = submitRef.current;
|
|
98
|
+
if (!send) return false;
|
|
99
|
+
send();
|
|
100
|
+
return true;
|
|
101
|
+
};
|
|
102
|
+
return {
|
|
103
|
+
"Mod-Enter": submit,
|
|
104
|
+
Enter: ({ editor: ed }) => {
|
|
105
|
+
if (!submitRef.current.submitOnEnter) return false;
|
|
106
|
+
if (ed.isActive("bulletList") || ed.isActive("orderedList")) return false;
|
|
107
|
+
return submit();
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
})
|
|
112
|
+
],
|
|
113
|
+
content: isRichText(value) ? value : textToRichText(value),
|
|
114
|
+
editable: !disabled,
|
|
115
|
+
autofocus: autoFocus ? "end" : false,
|
|
116
|
+
onUpdate: ({ editor: ed }) => {
|
|
117
|
+
const html = editorValue(ed);
|
|
118
|
+
emitted.current = html;
|
|
119
|
+
onChangeRef.current(html);
|
|
120
|
+
},
|
|
121
|
+
editorProps: {
|
|
122
|
+
attributes: {
|
|
123
|
+
class: `px-2.5 py-2 text-control leading-normal text-foreground outline-none ${richTextContentClasses}`,
|
|
124
|
+
role: "textbox",
|
|
125
|
+
"aria-multiline": "true"
|
|
126
|
+
},
|
|
127
|
+
// Colar/largar imagens só onde há sítio para as guardar.
|
|
128
|
+
handlePaste: (_view, event) => {
|
|
129
|
+
if (!uploadRef.current) return false;
|
|
130
|
+
const files = imageFiles(event.clipboardData);
|
|
131
|
+
if (!files.length) return false;
|
|
132
|
+
event.preventDefault();
|
|
133
|
+
event.stopPropagation();
|
|
134
|
+
void insertImages(files);
|
|
135
|
+
return true;
|
|
136
|
+
},
|
|
137
|
+
handleDrop: (_view, event) => {
|
|
138
|
+
if (!uploadRef.current) return false;
|
|
139
|
+
const files = imageFiles(event.dataTransfer);
|
|
140
|
+
if (!files.length) return false;
|
|
141
|
+
event.preventDefault();
|
|
142
|
+
event.stopPropagation();
|
|
143
|
+
void insertImages(files);
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
editorRef.current = editor;
|
|
149
|
+
const state = useEditorState({
|
|
150
|
+
editor,
|
|
151
|
+
selector: ({ editor: ed }) => ed ? {
|
|
152
|
+
empty: ed.isEmpty,
|
|
153
|
+
bold: ed.isActive("bold"),
|
|
154
|
+
italic: ed.isActive("italic"),
|
|
155
|
+
underline: ed.isActive("underline"),
|
|
156
|
+
strike: ed.isActive("strike"),
|
|
157
|
+
bulletList: ed.isActive("bulletList"),
|
|
158
|
+
orderedList: ed.isActive("orderedList"),
|
|
159
|
+
quote: ed.isActive("blockquote")
|
|
160
|
+
} : null
|
|
161
|
+
});
|
|
162
|
+
useEffect(() => {
|
|
163
|
+
if (!editor || value === emitted.current) return;
|
|
164
|
+
if (!value && editor.isEmpty) return;
|
|
165
|
+
editor.commands.setContent(isRichText(value) ? value : textToRichText(value), { emitUpdate: false });
|
|
166
|
+
emitted.current = value;
|
|
167
|
+
}, [value, editor]);
|
|
168
|
+
useEffect(() => {
|
|
169
|
+
editor?.setEditable(!disabled);
|
|
170
|
+
}, [editor, disabled]);
|
|
171
|
+
useEffect(() => {
|
|
172
|
+
if (!editor) return;
|
|
173
|
+
const el = editor.view.dom;
|
|
174
|
+
const set = (name, v) => v ? el.setAttribute(name, v) : el.removeAttribute(name);
|
|
175
|
+
set("id", id ?? field.id);
|
|
176
|
+
set("aria-label", ariaLabel);
|
|
177
|
+
set("aria-invalid", invalid ? "true" : void 0);
|
|
178
|
+
set("aria-required", field.required ? "true" : void 0);
|
|
179
|
+
set("aria-disabled", disabled ? "true" : void 0);
|
|
180
|
+
}, [editor, id, field.id, field.required, ariaLabel, invalid, disabled]);
|
|
181
|
+
useEffect(() => {
|
|
182
|
+
if (!maximized) return;
|
|
183
|
+
const onKey = (e) => {
|
|
184
|
+
if (e.key === "Escape") {
|
|
185
|
+
e.stopPropagation();
|
|
186
|
+
setMaximized(false);
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
window.addEventListener("keydown", onKey, true);
|
|
190
|
+
return () => window.removeEventListener("keydown", onKey, true);
|
|
191
|
+
}, [maximized]);
|
|
192
|
+
if (!editor || !state) return null;
|
|
193
|
+
const run = (fn) => () => fn(editor.chain().focus()).run();
|
|
194
|
+
const writeArea = maximized ? {} : { minHeight, maxHeight: typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight };
|
|
195
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
196
|
+
maximized && /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-[60] bg-black/40 backdrop-blur-sm", onClick: () => setMaximized(false) }),
|
|
197
|
+
/* @__PURE__ */ jsxs(
|
|
198
|
+
"div",
|
|
199
|
+
{
|
|
200
|
+
className: "overflow-clip rounded-lg border bg-card transition-[border-color,box-shadow] duration-150 dark:bg-slate-900 " + (invalid ? "border-destructive ring-3 ring-destructive/15 " : "border-border focus-within:border-primary/40 focus-within:ring-3 focus-within:ring-primary/10 dark:border-slate-600 ") + (disabled ? "bg-muted opacity-70 " : "") + (maximized ? "fixed inset-4 z-[61] flex flex-col shadow-2xl md:inset-10 " : "w-full min-w-0 ") + className,
|
|
201
|
+
children: [
|
|
202
|
+
/* @__PURE__ */ jsxs("div", { role: "toolbar", "aria-label": "Formatação", className: "sticky top-0 z-10 flex flex-wrap items-center gap-0.5 border-b border-border bg-muted/40 px-1.5 py-1 dark:border-slate-700 dark:bg-slate-800/60", children: [
|
|
203
|
+
/* @__PURE__ */ jsx(ToolbarButton, { label: labels.bold, active: state.bold, disabled, onClick: run((c) => c.toggleBold()), children: /* @__PURE__ */ jsx(BoldIcon, { size: 14 }) }),
|
|
204
|
+
/* @__PURE__ */ jsx(ToolbarButton, { label: labels.italic, active: state.italic, disabled, onClick: run((c) => c.toggleItalic()), children: /* @__PURE__ */ jsx(ItalicIcon, { size: 14 }) }),
|
|
205
|
+
/* @__PURE__ */ jsx(ToolbarButton, { label: labels.underline, active: state.underline, disabled, onClick: run((c) => c.toggleUnderline()), children: /* @__PURE__ */ jsx(UnderlineIcon, { size: 14 }) }),
|
|
206
|
+
/* @__PURE__ */ jsx(ToolbarButton, { label: labels.strike, active: state.strike, disabled, onClick: run((c) => c.toggleStrike()), children: /* @__PURE__ */ jsx(StrikethroughIcon, { size: 14 }) }),
|
|
207
|
+
/* @__PURE__ */ jsx(Separator, {}),
|
|
208
|
+
/* @__PURE__ */ jsx(ToolbarButton, { label: labels.bulletList, active: state.bulletList, disabled, onClick: run((c) => c.toggleBulletList()), children: /* @__PURE__ */ jsx(ListBulletIcon, { size: 14 }) }),
|
|
209
|
+
/* @__PURE__ */ jsx(ToolbarButton, { label: labels.orderedList, active: state.orderedList, disabled, onClick: run((c) => c.toggleOrderedList()), children: /* @__PURE__ */ jsx(ListNumberedIcon, { size: 14 }) }),
|
|
210
|
+
/* @__PURE__ */ jsx(ToolbarButton, { label: labels.quote, active: state.quote, disabled, onClick: run((c) => c.toggleBlockquote()), children: /* @__PURE__ */ jsx(QuoteIcon, { size: 14 }) }),
|
|
211
|
+
onUploadImage && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
212
|
+
/* @__PURE__ */ jsx(Separator, {}),
|
|
213
|
+
/* @__PURE__ */ jsx(ToolbarButton, { label: labels.image, disabled, onClick: () => fileInputRef.current?.click(), children: /* @__PURE__ */ jsx(ImageIcon, { size: 14 }) }),
|
|
214
|
+
/* @__PURE__ */ jsx(
|
|
215
|
+
"input",
|
|
216
|
+
{
|
|
217
|
+
ref: fileInputRef,
|
|
218
|
+
type: "file",
|
|
219
|
+
accept: "image/*",
|
|
220
|
+
multiple: true,
|
|
221
|
+
hidden: true,
|
|
222
|
+
onChange: (e) => {
|
|
223
|
+
const files = Array.from(e.target.files ?? []);
|
|
224
|
+
e.target.value = "";
|
|
225
|
+
void insertImages(files);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
)
|
|
229
|
+
] }),
|
|
230
|
+
maximizable && /* @__PURE__ */ jsx("span", { className: "ml-auto", children: /* @__PURE__ */ jsx(ToolbarButton, { label: maximized ? labels.restore : labels.maximize, onClick: () => setMaximized((m) => !m), children: maximized ? /* @__PURE__ */ jsx(MinimizeIcon, { size: 14 }) : /* @__PURE__ */ jsx(MaximizeIcon, { size: 14 }) }) })
|
|
231
|
+
] }),
|
|
232
|
+
/* @__PURE__ */ jsxs(
|
|
233
|
+
"div",
|
|
234
|
+
{
|
|
235
|
+
className: `relative cursor-text ${maximized ? "flex-1 overflow-y-auto" : "overflow-y-auto"} [&>div]:h-full [&_.ProseMirror]:min-h-full`,
|
|
236
|
+
style: writeArea,
|
|
237
|
+
onClick: () => !disabled && !editor.isFocused && editor.chain().focus().run(),
|
|
238
|
+
children: [
|
|
239
|
+
state.empty && placeholder && /* @__PURE__ */ jsx("p", { "aria-hidden": true, className: "pointer-events-none absolute top-2 left-2.5 m-0 text-control text-muted-foreground/70 select-none", children: placeholder }),
|
|
240
|
+
/* @__PURE__ */ jsx(EditorContent, { editor, className: "h-full" })
|
|
241
|
+
]
|
|
242
|
+
}
|
|
243
|
+
)
|
|
244
|
+
]
|
|
245
|
+
}
|
|
246
|
+
)
|
|
247
|
+
] });
|
|
248
|
+
}
|
|
249
|
+
export {
|
|
250
|
+
RichTextEditor,
|
|
251
|
+
RichTextEditor as default
|
|
252
|
+
};
|
|
253
|
+
//# sourceMappingURL=RichTextEditor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RichTextEditor.js","sources":["../../../../../../src/v1/primitives/forms/RichTextEditor/RichTextEditor.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef, useState } from 'react'\r\nimport { EditorContent, Extension, useEditor, useEditorState, type Editor } from '@tiptap/react'\r\nimport StarterKit from '@tiptap/starter-kit'\r\nimport Image from '@tiptap/extension-image'\r\nimport { useField } from '../field'\r\nimport { isRichText, richTextContentClasses, richTextIsEmpty, textToRichText } from '../../display/RichText/utils'\r\nimport {\r\n BoldIcon,\r\n ItalicIcon,\r\n UnderlineIcon,\r\n StrikethroughIcon,\r\n ListBulletIcon,\r\n ListNumberedIcon,\r\n QuoteIcon,\r\n ImageIcon,\r\n MaximizeIcon,\r\n MinimizeIcon,\r\n} from '../../../foundations/icons/icons'\r\n\r\nexport interface RichTextEditorLabels {\r\n bold: string\r\n italic: string\r\n underline: string\r\n strike: string\r\n bulletList: string\r\n orderedList: string\r\n quote: string\r\n image: string\r\n maximize: string\r\n restore: string\r\n}\r\n\r\nconst DEFAULT_LABELS: RichTextEditorLabels = {\r\n bold: 'Negrito (Ctrl+B)',\r\n italic: 'Itálico (Ctrl+I)',\r\n underline: 'Sublinhado (Ctrl+U)',\r\n strike: 'Riscado',\r\n bulletList: 'Lista com marcas',\r\n orderedList: 'Lista numerada',\r\n quote: 'Citação',\r\n image: 'Inserir imagem',\r\n maximize: 'Maximizar',\r\n restore: 'Restaurar',\r\n}\r\n\r\nexport interface RichTextEditorProps {\r\n /** O texto, em HTML. Texto simples (antigo, sem formatação) também serve: cada linha vira um parágrafo. */\r\n value: string\r\n /** Recebe o HTML a cada alteração; `''` quando fica vazio (para validar \"obrigatório\" sem olhar para `<p></p>`). */\r\n onChange: (html: string) => void\r\n placeholder?: string\r\n /** Marca o campo a vermelho (ex: obrigatório por preencher ao submeter). */\r\n invalid?: boolean\r\n disabled?: boolean\r\n /** Altura mínima da área de escrita, em px. Por omissão 80. */\r\n minHeight?: number\r\n /** Altura máxima (px ou CSS, ex: `'50vh'`): cresce com o texto até aqui e depois faz scroll por dentro. Sem isto, cresce sempre. */\r\n maxHeight?: number | string\r\n /**\r\n * Onde guardar uma imagem (escolhida na barra, colada ou largada); devolve o `src` a pôr no texto.\r\n * Sem isto, o editor não aceita imagens.\r\n */\r\n onUploadImage?: (file: File) => Promise<string>\r\n /** Mostra na barra o botão para escrever com o editor em ecrã quase inteiro (Esc volta). */\r\n maximizable?: boolean\r\n /**\r\n * Enviar com o teclado (ex: uma conversa): Ctrl+Enter chama-o sempre. Com `submitOnEnter`,\r\n * também o Enter — exceto dentro de uma lista, onde o Enter cria o item seguinte. Shift+Enter muda de linha.\r\n */\r\n onSubmit?: () => void\r\n submitOnEnter?: boolean\r\n autoFocus?: boolean\r\n /** Nome acessível, quando não há etiqueta à volta (ex: \"Escrever comentário\"). */\r\n 'aria-label'?: string\r\n id?: string\r\n /** Aplica-se à caixa à volta. */\r\n className?: string\r\n /** Textos da barra (para outra língua). */\r\n labels?: Partial<RichTextEditorLabels>\r\n}\r\n\r\nfunction imageFiles(data: DataTransfer | null): File[] {\r\n return Array.from(data?.files ?? []).filter((f) => f.type.startsWith('image/'))\r\n}\r\n\r\n/** O HTML que o editor tem, ou `''` se estiver vazio. */\r\nfunction editorValue(editor: Editor): string {\r\n const html = editor.getHTML()\r\n return richTextIsEmpty(html) ? '' : html\r\n}\r\n\r\nfunction ToolbarButton({ label, active, disabled, onClick, children }: {\r\n label: string\r\n active?: boolean\r\n disabled?: boolean\r\n onClick: () => void\r\n children: React.ReactNode\r\n}) {\r\n return (\r\n <button\r\n type=\"button\"\r\n aria-label={label}\r\n title={label}\r\n aria-pressed={active === undefined ? undefined : active}\r\n disabled={disabled}\r\n // Não tira o foco ao editor: a formatação aplica-se ao que está selecionado.\r\n onMouseDown={(e) => e.preventDefault()}\r\n onClick={onClick}\r\n className={\r\n 'inline-flex h-7 w-7 cursor-pointer items-center justify-center rounded-md transition-colors duration-150 ' +\r\n 'focus-visible:ring-2 focus-visible:ring-primary/30 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 ' +\r\n (active\r\n ? 'bg-primary/10 text-primary dark:bg-slate-700 dark:text-foreground'\r\n : 'text-muted-foreground hover:bg-muted hover:text-foreground dark:hover:bg-slate-800')\r\n }\r\n >\r\n {children}\r\n </button>\r\n )\r\n}\r\n\r\nconst Separator = () => <span aria-hidden className=\"mx-1 h-4 w-px bg-border\" />\r\n\r\n/**\r\n * Texto com formatação, que se vê enquanto se escreve: negrito, itálico, sublinhado, riscado,\r\n * listas, citações e (com `onUploadImage`) imagens. Atalhos habituais: Ctrl+B, Ctrl+I, Ctrl+U;\r\n * \"- \" ou \"1. \" no início da linha começam uma lista.\r\n *\r\n * Guarda HTML. Para o mostrar, usar sempre o [RichText](?path=/docs/v1-primitives-display-richtext--docs),\r\n * que o limpa antes de entrar na página. Para validar \"obrigatório\", o `onChange` dá `''` quando está vazio\r\n * (ou `richTextIsEmpty`).\r\n *\r\n * Para uma conversa: `onSubmit` + `submitOnEnter` (Enter envia, Shift+Enter muda de linha) e `maxHeight`\r\n * para crescer com o texto até um limite.\r\n *\r\n * Dentro de um [FormField](?path=/docs/v1-components-forms-formfield--docs) fica com o `id` do campo.\r\n */\r\nexport function RichTextEditor({\r\n value,\r\n onChange,\r\n placeholder,\r\n invalid,\r\n disabled,\r\n minHeight = 80,\r\n maxHeight,\r\n onUploadImage,\r\n maximizable,\r\n onSubmit,\r\n submitOnEnter,\r\n autoFocus,\r\n 'aria-label': ariaLabel,\r\n id,\r\n className = '',\r\n labels: labelsProp,\r\n}: RichTextEditorProps) {\r\n const labels = { ...DEFAULT_LABELS, ...labelsProp }\r\n const field = useField()\r\n const fileInputRef = useRef<HTMLInputElement>(null)\r\n const [maximized, setMaximized] = useState(false)\r\n\r\n // Em refs: o editor é criado uma vez e os handlers do ProseMirror ficariam presos à primeira versão das props.\r\n const onChangeRef = useRef(onChange)\r\n onChangeRef.current = onChange\r\n const uploadRef = useRef(onUploadImage)\r\n uploadRef.current = onUploadImage\r\n const submitRef = useRef({ onSubmit, submitOnEnter })\r\n submitRef.current = { onSubmit, submitOnEnter }\r\n // O último valor que o editor deu: um `value` igual vem dele e não volta a ser posto lá dentro.\r\n const emitted = useRef<string | null>(null)\r\n const editorRef = useRef<Editor | null>(null)\r\n\r\n const insertImages = useCallback(async (files: File[]) => {\r\n for (const file of files) {\r\n try {\r\n const src = await uploadRef.current!(file)\r\n editorRef.current?.chain().focus().setImage({ src }).run()\r\n } catch {\r\n // Falhar a subir uma imagem não leva o texto já escrito; quem chama mostra o erro pelo seu lado.\r\n }\r\n }\r\n }, [])\r\n\r\n const editor = useEditor({\r\n extensions: [\r\n StarterKit.configure({\r\n heading: false,\r\n codeBlock: false,\r\n horizontalRule: false,\r\n link: { openOnClick: false, autolink: true, defaultProtocol: 'https' },\r\n }),\r\n Image.configure({ inline: false, allowBase64: true }),\r\n Extension.create({\r\n name: 'submitShortcut',\r\n addKeyboardShortcuts() {\r\n const submit = () => {\r\n const { onSubmit: send } = submitRef.current\r\n if (!send) return false\r\n send()\r\n return true\r\n }\r\n return {\r\n 'Mod-Enter': submit,\r\n Enter: ({ editor: ed }) => {\r\n if (!submitRef.current.submitOnEnter) return false\r\n if (ed.isActive('bulletList') || ed.isActive('orderedList')) return false\r\n return submit()\r\n },\r\n }\r\n },\r\n }),\r\n ],\r\n content: isRichText(value) ? value : textToRichText(value),\r\n editable: !disabled,\r\n autofocus: autoFocus ? 'end' : false,\r\n onUpdate: ({ editor: ed }) => {\r\n const html = editorValue(ed)\r\n emitted.current = html\r\n onChangeRef.current(html)\r\n },\r\n editorProps: {\r\n attributes: {\r\n class: `px-2.5 py-2 text-control leading-normal text-foreground outline-none ${richTextContentClasses}`,\r\n role: 'textbox',\r\n 'aria-multiline': 'true',\r\n },\r\n // Colar/largar imagens só onde há sítio para as guardar.\r\n handlePaste: (_view, event) => {\r\n if (!uploadRef.current) return false\r\n const files = imageFiles(event.clipboardData)\r\n if (!files.length) return false\r\n event.preventDefault()\r\n event.stopPropagation()\r\n void insertImages(files)\r\n return true\r\n },\r\n handleDrop: (_view, event) => {\r\n if (!uploadRef.current) return false\r\n const files = imageFiles((event as DragEvent).dataTransfer)\r\n if (!files.length) return false\r\n event.preventDefault()\r\n event.stopPropagation()\r\n void insertImages(files)\r\n return true\r\n },\r\n },\r\n })\r\n editorRef.current = editor\r\n\r\n // A barra só volta a desenhar quando muda o que mostra (o editor não redesenha a cada tecla).\r\n const state = useEditorState({\r\n editor,\r\n selector: ({ editor: ed }) =>\r\n ed\r\n ? {\r\n empty: ed.isEmpty,\r\n bold: ed.isActive('bold'),\r\n italic: ed.isActive('italic'),\r\n underline: ed.isActive('underline'),\r\n strike: ed.isActive('strike'),\r\n bulletList: ed.isActive('bulletList'),\r\n orderedList: ed.isActive('orderedList'),\r\n quote: ed.isActive('blockquote'),\r\n }\r\n : null,\r\n })\r\n\r\n // Valor mudado por fora (ex: limpar depois de enviar, abrir outro registo).\r\n useEffect(() => {\r\n if (!editor || value === emitted.current) return\r\n if (!value && editor.isEmpty) return\r\n editor.commands.setContent(isRichText(value) ? value : textToRichText(value), { emitUpdate: false })\r\n emitted.current = value\r\n }, [value, editor])\r\n\r\n useEffect(() => {\r\n editor?.setEditable(!disabled)\r\n }, [editor, disabled])\r\n\r\n // Atributos que dependem das props, no próprio campo editável.\r\n useEffect(() => {\r\n if (!editor) return\r\n const el = editor.view.dom as HTMLElement\r\n const set = (name: string, v: string | undefined) => (v ? el.setAttribute(name, v) : el.removeAttribute(name))\r\n set('id', id ?? field.id)\r\n set('aria-label', ariaLabel)\r\n set('aria-invalid', invalid ? 'true' : undefined)\r\n set('aria-required', field.required ? 'true' : undefined)\r\n set('aria-disabled', disabled ? 'true' : undefined)\r\n }, [editor, id, field.id, field.required, ariaLabel, invalid, disabled])\r\n\r\n // Esc sai do modo maximizado (e só isso — não fecha a janela à volta).\r\n useEffect(() => {\r\n if (!maximized) return\r\n const onKey = (e: KeyboardEvent) => {\r\n if (e.key === 'Escape') {\r\n e.stopPropagation()\r\n setMaximized(false)\r\n }\r\n }\r\n window.addEventListener('keydown', onKey, true)\r\n return () => window.removeEventListener('keydown', onKey, true)\r\n }, [maximized])\r\n\r\n if (!editor || !state) return null\r\n\r\n const run = (fn: (chain: ReturnType<Editor['chain']>) => ReturnType<Editor['chain']>) => () => fn(editor.chain().focus()).run()\r\n const writeArea: React.CSSProperties = maximized\r\n ? {}\r\n : { minHeight, maxHeight: typeof maxHeight === 'number' ? `${maxHeight}px` : maxHeight }\r\n\r\n return (\r\n <>\r\n {maximized && <div className=\"fixed inset-0 z-[60] bg-black/40 backdrop-blur-sm\" onClick={() => setMaximized(false)} />}\r\n {/* overflow-clip e não overflow-hidden: o hidden faria disto um contentor de scroll e a barra deixava de ficar presa. */}\r\n <div\r\n className={\r\n 'overflow-clip rounded-lg border bg-card transition-[border-color,box-shadow] duration-150 dark:bg-slate-900 ' +\r\n (invalid\r\n ? 'border-destructive ring-3 ring-destructive/15 '\r\n : 'border-border focus-within:border-primary/40 focus-within:ring-3 focus-within:ring-primary/10 dark:border-slate-600 ') +\r\n (disabled ? 'bg-muted opacity-70 ' : '') +\r\n (maximized ? 'fixed inset-4 z-[61] flex flex-col shadow-2xl md:inset-10 ' : 'w-full min-w-0 ') +\r\n className\r\n }\r\n >\r\n <div role=\"toolbar\" aria-label=\"Formatação\" className=\"sticky top-0 z-10 flex flex-wrap items-center gap-0.5 border-b border-border bg-muted/40 px-1.5 py-1 dark:border-slate-700 dark:bg-slate-800/60\">\r\n <ToolbarButton label={labels.bold} active={state.bold} disabled={disabled} onClick={run((c) => c.toggleBold())}>\r\n <BoldIcon size={14} />\r\n </ToolbarButton>\r\n <ToolbarButton label={labels.italic} active={state.italic} disabled={disabled} onClick={run((c) => c.toggleItalic())}>\r\n <ItalicIcon size={14} />\r\n </ToolbarButton>\r\n <ToolbarButton label={labels.underline} active={state.underline} disabled={disabled} onClick={run((c) => c.toggleUnderline())}>\r\n <UnderlineIcon size={14} />\r\n </ToolbarButton>\r\n <ToolbarButton label={labels.strike} active={state.strike} disabled={disabled} onClick={run((c) => c.toggleStrike())}>\r\n <StrikethroughIcon size={14} />\r\n </ToolbarButton>\r\n <Separator />\r\n <ToolbarButton label={labels.bulletList} active={state.bulletList} disabled={disabled} onClick={run((c) => c.toggleBulletList())}>\r\n <ListBulletIcon size={14} />\r\n </ToolbarButton>\r\n <ToolbarButton label={labels.orderedList} active={state.orderedList} disabled={disabled} onClick={run((c) => c.toggleOrderedList())}>\r\n <ListNumberedIcon size={14} />\r\n </ToolbarButton>\r\n <ToolbarButton label={labels.quote} active={state.quote} disabled={disabled} onClick={run((c) => c.toggleBlockquote())}>\r\n <QuoteIcon size={14} />\r\n </ToolbarButton>\r\n {onUploadImage && (\r\n <>\r\n <Separator />\r\n <ToolbarButton label={labels.image} disabled={disabled} onClick={() => fileInputRef.current?.click()}>\r\n <ImageIcon size={14} />\r\n </ToolbarButton>\r\n <input\r\n ref={fileInputRef}\r\n type=\"file\"\r\n accept=\"image/*\"\r\n multiple\r\n hidden\r\n onChange={(e) => {\r\n const files = Array.from(e.target.files ?? [])\r\n e.target.value = ''\r\n void insertImages(files)\r\n }}\r\n />\r\n </>\r\n )}\r\n {maximizable && (\r\n <span className=\"ml-auto\">\r\n <ToolbarButton label={maximized ? labels.restore : labels.maximize} onClick={() => setMaximized((m) => !m)}>\r\n {maximized ? <MinimizeIcon size={14} /> : <MaximizeIcon size={14} />}\r\n </ToolbarButton>\r\n </span>\r\n )}\r\n </div>\r\n {/* A área de escrita: clicar em qualquer ponto dela põe o cursor no editor. */}\r\n <div\r\n className={`relative cursor-text ${maximized ? 'flex-1 overflow-y-auto' : 'overflow-y-auto'} [&>div]:h-full [&_.ProseMirror]:min-h-full`}\r\n style={writeArea}\r\n onClick={() => !disabled && !editor.isFocused && editor.chain().focus().run()}\r\n >\r\n {state.empty && placeholder && (\r\n <p aria-hidden className=\"pointer-events-none absolute top-2 left-2.5 m-0 text-control text-muted-foreground/70 select-none\">\r\n {placeholder}\r\n </p>\r\n )}\r\n <EditorContent editor={editor} className=\"h-full\" />\r\n </div>\r\n </div>\r\n </>\r\n )\r\n}\r\n\r\nexport default RichTextEditor\r\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { fieldClasses } from "../field.js";
|
|
4
|
+
import { SearchIcon, CloseIcon } from "../../../foundations/icons/icons.js";
|
|
5
|
+
const SearchInput = forwardRef(function SearchInput2({ value, onChange, placeholder = "Pesquisar…", label, clearLabel = "Limpar pesquisa", className = "w-56", icon, onKeyDown, ...props }, ref) {
|
|
6
|
+
return /* @__PURE__ */ jsxs("div", { className: `relative ${className}`, children: [
|
|
7
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "pointer-events-none absolute top-1/2 left-2.5 flex -translate-y-1/2 text-muted-foreground", children: icon ?? /* @__PURE__ */ jsx(SearchIcon, { size: 14 }) }),
|
|
8
|
+
/* @__PURE__ */ jsx(
|
|
9
|
+
"input",
|
|
10
|
+
{
|
|
11
|
+
ref,
|
|
12
|
+
type: "search",
|
|
13
|
+
value,
|
|
14
|
+
onChange: (e) => onChange(e.target.value),
|
|
15
|
+
onKeyDown: (e) => {
|
|
16
|
+
if (e.key === "Escape" && value) {
|
|
17
|
+
e.stopPropagation();
|
|
18
|
+
onChange("");
|
|
19
|
+
}
|
|
20
|
+
onKeyDown?.(e);
|
|
21
|
+
},
|
|
22
|
+
placeholder,
|
|
23
|
+
"aria-label": label ?? placeholder,
|
|
24
|
+
className: `h-control ${fieldClasses} pr-7 pl-8 [&::-webkit-search-cancel-button]:hidden`,
|
|
25
|
+
...props
|
|
26
|
+
}
|
|
27
|
+
),
|
|
28
|
+
value && /* @__PURE__ */ jsx(
|
|
29
|
+
"button",
|
|
30
|
+
{
|
|
31
|
+
type: "button",
|
|
32
|
+
onClick: () => onChange(""),
|
|
33
|
+
"aria-label": clearLabel,
|
|
34
|
+
className: "absolute top-1/2 right-1.5 flex h-5 w-5 -translate-y-1/2 cursor-pointer items-center justify-center rounded border-0 bg-transparent p-0 text-muted-foreground hover:text-foreground focus-visible:ring-2 focus-visible:ring-primary/30 focus-visible:outline-none",
|
|
35
|
+
children: /* @__PURE__ */ jsx(CloseIcon, { size: 12 })
|
|
36
|
+
}
|
|
37
|
+
)
|
|
38
|
+
] });
|
|
39
|
+
});
|
|
40
|
+
export {
|
|
41
|
+
SearchInput as default
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=SearchInput.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchInput.js","sources":["../../../../../../src/v1/primitives/forms/SearchInput/SearchInput.tsx"],"sourcesContent":["import React, { forwardRef } from 'react'\r\nimport { fieldClasses } from '../field'\r\nimport { CloseIcon, SearchIcon } from '../../../foundations/icons/icons'\r\n\r\nexport interface SearchInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange' | 'type' | 'className'> {\r\n value: string\r\n /** O texto novo, a cada tecla (e `''` ao limpar). */\r\n onChange: (value: string) => void\r\n /** Nome do campo para leitores de ecrã. Por omissão, o placeholder. */\r\n label?: string\r\n /** Nome do botão ×, para leitores de ecrã. Por omissão: \"Limpar pesquisa\". */\r\n clearLabel?: string\r\n /** Largura e posição (classes do invólucro). Por omissão `w-56`. */\r\n className?: string\r\n /** Ícone à esquerda, no lugar da lupa, quando o filtro é de algo concreto (ex: empresa, colaborador). Tamanho 14. */\r\n icon?: React.ReactNode\r\n}\r\n\r\n/**\r\n * Caixa de pesquisa das barras de páginas, tabelas e listas: a mesma altura\r\n * dos botões ao lado. Lupa à esquerda; com texto, um × para limpar (Esc também\r\n * limpa).\r\n *\r\n * Aceita os outros atributos do `<input>` (`autoFocus`, `name`, `onKeyDown`, …).\r\n */\r\nconst SearchInput = forwardRef<HTMLInputElement, SearchInputProps>(function SearchInput(\r\n { value, onChange, placeholder = 'Pesquisar…', label, clearLabel = 'Limpar pesquisa', className = 'w-56', icon, onKeyDown, ...props },\r\n ref,\r\n) {\r\n return (\r\n <div className={`relative ${className}`}>\r\n <span aria-hidden className=\"pointer-events-none absolute top-1/2 left-2.5 flex -translate-y-1/2 text-muted-foreground\">\r\n {icon ?? <SearchIcon size={14} />}\r\n </span>\r\n <input\r\n ref={ref}\r\n type=\"search\"\r\n value={value}\r\n onChange={(e) => onChange(e.target.value)}\r\n onKeyDown={(e) => {\r\n if (e.key === 'Escape' && value) {\r\n e.stopPropagation()\r\n onChange('')\r\n }\r\n onKeyDown?.(e)\r\n }}\r\n placeholder={placeholder}\r\n aria-label={label ?? placeholder}\r\n className={`h-control ${fieldClasses} pr-7 pl-8 [&::-webkit-search-cancel-button]:hidden`}\r\n {...props}\r\n />\r\n {value && (\r\n <button\r\n type=\"button\"\r\n onClick={() => onChange('')}\r\n aria-label={clearLabel}\r\n className=\"absolute top-1/2 right-1.5 flex h-5 w-5 -translate-y-1/2 cursor-pointer items-center justify-center rounded border-0 bg-transparent p-0 text-muted-foreground hover:text-foreground focus-visible:ring-2 focus-visible:ring-primary/30 focus-visible:outline-none\"\r\n >\r\n <CloseIcon size={12} />\r\n </button>\r\n )}\r\n </div>\r\n )\r\n})\r\n\r\nexport default SearchInput\r\n"],"names":["SearchInput"],"mappings":";;;;AAyBA,MAAM,cAAc,WAA+C,SAASA,aAC1E,EAAE,OAAO,UAAU,cAAc,cAAc,OAAO,aAAa,mBAAmB,YAAY,QAAQ,MAAM,WAAW,GAAG,MAAA,GAC9H,KACA;AACA,SACE,qBAAC,OAAA,EAAI,WAAW,YAAY,SAAS,IACnC,UAAA;AAAA,IAAA,oBAAC,QAAA,EAAK,eAAW,MAAC,WAAU,6FACzB,kBAAQ,oBAAC,YAAA,EAAW,MAAM,GAAA,CAAI,EAAA,CACjC;AAAA,IACA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,MAAK;AAAA,QACL;AAAA,QACA,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,QACxC,WAAW,CAAC,MAAM;AAChB,cAAI,EAAE,QAAQ,YAAY,OAAO;AAC/B,cAAE,gBAAA;AACF,qBAAS,EAAE;AAAA,UACb;AACA,sBAAY,CAAC;AAAA,QACf;AAAA,QACA;AAAA,QACA,cAAY,SAAS;AAAA,QACrB,WAAW,aAAa,YAAY;AAAA,QACnC,GAAG;AAAA,MAAA;AAAA,IAAA;AAAA,IAEL,SACC;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAM,SAAS,EAAE;AAAA,QAC1B,cAAY;AAAA,QACZ,WAAU;AAAA,QAEV,UAAA,oBAAC,WAAA,EAAU,MAAM,GAAA,CAAI;AAAA,MAAA;AAAA,IAAA;AAAA,EACvB,GAEJ;AAEJ,CAAC;"}
|