@stackcraftmx/calcita 0.31.0 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/dist/DataTable/AuditTrailDialog.js +4 -1
- package/dist/DataTable/AuditTrailDialog.js.map +1 -1
- package/dist/DataTable/AuditTrailTable.js +4 -1
- package/dist/DataTable/AuditTrailTable.js.map +1 -1
- package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js +3 -1
- package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js.map +1 -1
- package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js +3 -1
- package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js.map +1 -1
- package/dist/DataTable/ColumnFilters/SortableFilterHeader.js +4 -1
- package/dist/DataTable/ColumnFilters/SortableFilterHeader.js.map +1 -1
- package/dist/DataTable/ColumnFilters/TextColumnFilter.js +3 -1
- package/dist/DataTable/ColumnFilters/TextColumnFilter.js.map +1 -1
- package/dist/DataTable/EmptyState.js +3 -1
- package/dist/DataTable/EmptyState.js.map +1 -1
- package/dist/DataTable/FilterChips.js +3 -1
- package/dist/DataTable/FilterChips.js.map +1 -1
- package/dist/DataTable/GoToPage.js +3 -1
- package/dist/DataTable/GoToPage.js.map +1 -1
- package/dist/DataTable/ServerTable.js +4 -1
- package/dist/DataTable/ServerTable.js.map +1 -1
- package/dist/DataTable/columns.js +3 -1
- package/dist/DataTable/columns.js.map +1 -1
- package/dist/access/Can.js +3 -1
- package/dist/access/Can.js.map +1 -1
- package/dist/access/PermissionMatrix.js +3 -1
- package/dist/access/PermissionMatrix.js.map +1 -1
- package/dist/access/RequireAccess.js +3 -1
- package/dist/access/RequireAccess.js.map +1 -1
- package/dist/account/AccountProvider.js +3 -1
- package/dist/account/AccountProvider.js.map +1 -1
- package/dist/account/AccountSecuritySection.js +3 -1
- package/dist/account/AccountSecuritySection.js.map +1 -1
- package/dist/account/DemoTotpCodeButton.js +3 -1
- package/dist/account/DemoTotpCodeButton.js.map +1 -1
- package/dist/account/ForgotPasswordScreen.js +3 -1
- package/dist/account/ForgotPasswordScreen.js.map +1 -1
- package/dist/account/ProfileScreen.js +4 -1
- package/dist/account/ProfileScreen.js.map +1 -1
- package/dist/account/ResetPasswordScreen.js +4 -1
- package/dist/account/ResetPasswordScreen.js.map +1 -1
- package/dist/account/SignInScreen.js +3 -1
- package/dist/account/SignInScreen.js.map +1 -1
- package/dist/appShell/AccountMenu.js +3 -1
- package/dist/appShell/AccountMenu.js.map +1 -1
- package/dist/appShell/AppLayout.js +4 -1
- package/dist/appShell/AppLayout.js.map +1 -1
- package/dist/appShell/AppearanceSettings.js +4 -1
- package/dist/appShell/AppearanceSettings.js.map +1 -1
- package/dist/appShell/AuthLayout.js +3 -1
- package/dist/appShell/AuthLayout.js.map +1 -1
- package/dist/appShell/BarActions.js +3 -1
- package/dist/appShell/BarActions.js.map +1 -1
- package/dist/appShell/BarSearch.js +3 -1
- package/dist/appShell/BarSearch.js.map +1 -1
- package/dist/appShell/HeaderTools.js +4 -1
- package/dist/appShell/HeaderTools.js.map +1 -1
- package/dist/appShell/MenuLinks.js +3 -1
- package/dist/appShell/MenuLinks.js.map +1 -1
- package/dist/appShell/MobileTabBar.js +3 -1
- package/dist/appShell/MobileTabBar.js.map +1 -1
- package/dist/appShell/SettingsMenu.js +3 -1
- package/dist/appShell/SettingsMenu.js.map +1 -1
- package/dist/appShell/SideMenu.js +4 -1
- package/dist/appShell/SideMenu.js.map +1 -1
- package/dist/appShell/SideMenuEntry.js +3 -1
- package/dist/appShell/SideMenuEntry.js.map +1 -1
- package/dist/appShell/SubmenuActionsMenu.js +3 -1
- package/dist/appShell/SubmenuActionsMenu.js.map +1 -1
- package/dist/appShell/TabBarEditor.js +3 -1
- package/dist/appShell/TabBarEditor.js.map +1 -1
- package/dist/appShell/TopMenu.js +3 -1
- package/dist/appShell/TopMenu.js.map +1 -1
- package/dist/appShell/Wordmark.js +3 -1
- package/dist/appShell/Wordmark.js.map +1 -1
- package/dist/appShell/pageTitle.js +3 -1
- package/dist/appShell/pageTitle.js.map +1 -1
- package/dist/auth/PasswordChecklist.js +3 -1
- package/dist/auth/PasswordChecklist.js.map +1 -1
- package/dist/calendar/EventCalendar.js +4 -1
- package/dist/calendar/EventCalendar.js.map +1 -1
- package/dist/calendar/EventDetails.js +3 -1
- package/dist/calendar/EventDetails.js.map +1 -1
- package/dist/datePickers/DateInput.js +4 -1
- package/dist/datePickers/DateInput.js.map +1 -1
- package/dist/downloads/DownloadManager.js +3 -1
- package/dist/downloads/DownloadManager.js.map +1 -1
- package/dist/feedback/ConfirmDialog.js +4 -1
- package/dist/feedback/ConfirmDialog.js.map +1 -1
- package/dist/feedback/ModalWaiting.js +3 -1
- package/dist/feedback/ModalWaiting.js.map +1 -1
- package/dist/feedback/NewBuildNotice.js +3 -1
- package/dist/feedback/NewBuildNotice.js.map +1 -1
- package/dist/filepond/FileDropzone.js +4 -1
- package/dist/filepond/FileDropzone.js.map +1 -1
- package/dist/formatting.js +8 -5
- package/dist/formatting.js.map +1 -1
- package/dist/forms/FormProblemAlert.js +3 -1
- package/dist/forms/FormProblemAlert.js.map +1 -1
- package/dist/forms/FormServerProblem.js +3 -1
- package/dist/forms/FormServerProblem.js.map +1 -1
- package/dist/forms/FormWizard.js +3 -1
- package/dist/forms/FormWizard.js.map +1 -1
- package/dist/forms/auth/ChangePasswordForm.js +3 -1
- package/dist/forms/auth/ChangePasswordForm.js.map +1 -1
- package/dist/forms/auth/ForgotPasswordForm.js +3 -1
- package/dist/forms/auth/ForgotPasswordForm.js.map +1 -1
- package/dist/forms/auth/SignInForm.js +3 -1
- package/dist/forms/auth/SignInForm.js.map +1 -1
- package/dist/forms/security/SecondStepForm.js +3 -1
- package/dist/forms/security/SecondStepForm.js.map +1 -1
- package/dist/forms/security/TwoStepVerificationCard.js +3 -1
- package/dist/forms/security/TwoStepVerificationCard.js.map +1 -1
- package/dist/hookForm/FormProblemAlert.js +3 -1
- package/dist/hookForm/FormProblemAlert.js.map +1 -1
- package/dist/hookForm/FormWizard.js +3 -1
- package/dist/hookForm/FormWizard.js.map +1 -1
- package/dist/inbox/InboxLayout.js +4 -1
- package/dist/inbox/InboxLayout.js.map +1 -1
- package/dist/inbox/MessageList.js +4 -1
- package/dist/inbox/MessageList.js.map +1 -1
- package/dist/inbox/MessageView.js +3 -1
- package/dist/inbox/MessageView.js.map +1 -1
- package/dist/index.js +3 -1
- package/dist/inputs/CatalogInput.js +4 -1
- package/dist/inputs/CatalogInput.js.map +1 -1
- package/dist/inputs/ColorInput.js +4 -1
- package/dist/inputs/ColorInput.js.map +1 -1
- package/dist/inputs/FieldFrame.js +3 -1
- package/dist/inputs/FieldFrame.js.map +1 -1
- package/dist/inputs/FormSection.js +5 -2
- package/dist/inputs/FormSection.js.map +1 -1
- package/dist/inputs/NumberInput.js +4 -1
- package/dist/inputs/NumberInput.js.map +1 -1
- package/dist/inputs/SelectInput.js +4 -1
- package/dist/inputs/SelectInput.js.map +1 -1
- package/dist/inputs/WizardLayout.js +4 -1
- package/dist/inputs/WizardLayout.js.map +1 -1
- package/dist/kanban/KanbanBoard.js +4 -1
- package/dist/kanban/KanbanBoard.js.map +1 -1
- package/dist/maps/MapView.js +4 -1
- package/dist/maps/MapView.js.map +1 -1
- package/dist/pwa/InstallAppSetting.js +3 -1
- package/dist/pwa/InstallAppSetting.js.map +1 -1
- package/dist/pwa/InstallInstructionsDialog.js +3 -1
- package/dist/pwa/InstallInstructionsDialog.js.map +1 -1
- package/dist/pwa/InstallPromptBanner.js +3 -1
- package/dist/pwa/InstallPromptBanner.js.map +1 -1
- package/dist/security/ActivityLog.js +3 -1
- package/dist/security/ActivityLog.js.map +1 -1
- package/dist/security/RecoveryCodesDialog.js +3 -1
- package/dist/security/RecoveryCodesDialog.js.map +1 -1
- package/dist/security/SessionsCard.js +3 -1
- package/dist/security/SessionsCard.js.map +1 -1
- package/dist/theme/createToolkitTheme.js +4 -1
- package/dist/theme/createToolkitTheme.js.map +1 -1
- package/dist/toolkit/ComponentTexts.js +3 -1
- package/dist/toolkit/ComponentTexts.js.map +1 -1
- package/dist/toolkit/ToolkitProvider.js +24 -3
- package/dist/toolkit/ToolkitProvider.js.map +1 -1
- package/dist/toolkit/toolkitContext.js.map +1 -1
- package/dist/toolkit/toolkitSettings.js +9 -0
- package/dist/toolkit/toolkitSettings.js.map +1 -1
- package/dist/toolkit/unknownProps.js +33 -0
- package/dist/toolkit/unknownProps.js.map +1 -0
- package/dist/types/DataTable/AuditTrailTable.d.ts +1 -1
- package/dist/types/DataTable/ColumnFilters/TextColumnFilter.d.ts +1 -1
- package/dist/types/DataTable/columns.d.ts +3 -1
- package/dist/types/access/Can.d.ts +1 -1
- package/dist/types/access/RequireAccess.d.ts +1 -1
- package/dist/types/account/AccountProvider.d.ts +1 -1
- package/dist/types/account/ForgotPasswordScreen.d.ts +1 -1
- package/dist/types/account/ResetPasswordScreen.d.ts +1 -1
- package/dist/types/appShell/MenuLinks.d.ts +1 -1
- package/dist/types/appShell/pageTitle.d.ts +1 -1
- package/dist/types/datePickers/DateInput.d.ts +1 -1
- package/dist/types/downloads/DownloadManager.d.ts +1 -1
- package/dist/types/formatting.d.ts +2 -1
- package/dist/types/forms/FormProblemAlert.d.ts +1 -1
- package/dist/types/forms/FormServerProblem.d.ts +1 -1
- package/dist/types/forms/FormWizard.d.ts +1 -1
- package/dist/types/forms/auth/ChangePasswordForm.d.ts +1 -1
- package/dist/types/forms/auth/ForgotPasswordForm.d.ts +1 -1
- package/dist/types/hookForm/FormProblemAlert.d.ts +1 -1
- package/dist/types/hookForm/FormWizard.d.ts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/inputs/CatalogInput.d.ts +1 -1
- package/dist/types/inputs/FieldFrame.d.ts +1 -1
- package/dist/types/inputs/NumberInput.d.ts +1 -1
- package/dist/types/pwa/InstallAppSetting.d.ts +1 -1
- package/dist/types/theme/createToolkitTheme.d.ts +1 -1
- package/dist/types/toolkit/ComponentTexts.d.ts +1 -1
- package/dist/types/toolkit/ToolkitProvider.d.ts +4 -1
- package/dist/types/toolkit/toolkitContext.d.ts +2 -1
- package/dist/types/toolkit/toolkitSettings.d.ts +13 -2
- package/dist/types/toolkit/unknownProps.d.ts +23 -0
- package/dist/types/ui/actions/CopyButton.d.ts +1 -1
- package/dist/types/ui/actions/SecretField.d.ts +1 -1
- package/dist/types/ui/labels/DictionaryText.d.ts +1 -1
- package/dist/types/ui/layout/FullPageLoader.d.ts +1 -1
- package/dist/types/ui/metrics/CalendarHeatmap.d.ts +9 -8
- package/dist/types/ui/metrics/chartParts.d.ts +3 -3
- package/dist/types/ui/metrics/heatmapScale.d.ts +23 -0
- package/dist/types/ui/navigation/DocumentTitle.d.ts +1 -1
- package/dist/ui/actions/ActionsMenu.js +3 -1
- package/dist/ui/actions/ActionsMenu.js.map +1 -1
- package/dist/ui/actions/CopyButton.js +3 -1
- package/dist/ui/actions/CopyButton.js.map +1 -1
- package/dist/ui/actions/DownloadMenu.js +4 -1
- package/dist/ui/actions/DownloadMenu.js.map +1 -1
- package/dist/ui/actions/SecretField.js +3 -1
- package/dist/ui/actions/SecretField.js.map +1 -1
- package/dist/ui/actions/SelectionActions.js +3 -1
- package/dist/ui/actions/SelectionActions.js.map +1 -1
- package/dist/ui/filters/DateRangeFilter.js +3 -1
- package/dist/ui/filters/DateRangeFilter.js.map +1 -1
- package/dist/ui/filters/PeriodRangeSelector.js +3 -1
- package/dist/ui/filters/PeriodRangeSelector.js.map +1 -1
- package/dist/ui/filters/QuickFilters.js +3 -1
- package/dist/ui/filters/QuickFilters.js.map +1 -1
- package/dist/ui/filters/SegmentedControl.js +3 -1
- package/dist/ui/filters/SegmentedControl.js.map +1 -1
- package/dist/ui/labels/DictionaryText.js +3 -1
- package/dist/ui/labels/DictionaryText.js.map +1 -1
- package/dist/ui/labels/StatusChip.js +3 -1
- package/dist/ui/labels/StatusChip.js.map +1 -1
- package/dist/ui/layout/CollapsibleSection.js +3 -1
- package/dist/ui/layout/CollapsibleSection.js.map +1 -1
- package/dist/ui/layout/ContentDialog.js +3 -1
- package/dist/ui/layout/ContentDialog.js.map +1 -1
- package/dist/ui/layout/DefinitionList.js +3 -1
- package/dist/ui/layout/DefinitionList.js.map +1 -1
- package/dist/ui/layout/DetailHeader.js +3 -1
- package/dist/ui/layout/DetailHeader.js.map +1 -1
- package/dist/ui/layout/ErrorPage.js +4 -1
- package/dist/ui/layout/ErrorPage.js.map +1 -1
- package/dist/ui/layout/FullPageLoader.js +3 -1
- package/dist/ui/layout/FullPageLoader.js.map +1 -1
- package/dist/ui/layout/PageHeader.js +3 -1
- package/dist/ui/layout/PageHeader.js.map +1 -1
- package/dist/ui/layout/PageHeading.js +3 -1
- package/dist/ui/layout/PageHeading.js.map +1 -1
- package/dist/ui/layout/ProfileHeader.js +3 -1
- package/dist/ui/layout/ProfileHeader.js.map +1 -1
- package/dist/ui/layout/SectionCard.js +3 -1
- package/dist/ui/layout/SectionCard.js.map +1 -1
- package/dist/ui/metrics/BarList.js +3 -1
- package/dist/ui/metrics/BarList.js.map +1 -1
- package/dist/ui/metrics/CalendarHeatmap.js +13 -4
- package/dist/ui/metrics/CalendarHeatmap.js.map +1 -1
- package/dist/ui/metrics/ChartTooltip.js.map +1 -1
- package/dist/ui/metrics/ColumnChart.js +4 -1
- package/dist/ui/metrics/ColumnChart.js.map +1 -1
- package/dist/ui/metrics/LineChart.js +4 -1
- package/dist/ui/metrics/LineChart.js.map +1 -1
- package/dist/ui/metrics/MetricCard.js +4 -1
- package/dist/ui/metrics/MetricCard.js.map +1 -1
- package/dist/ui/metrics/TableToggle.js +3 -1
- package/dist/ui/metrics/TableToggle.js.map +1 -1
- package/dist/ui/metrics/chartParts.js +7 -3
- package/dist/ui/metrics/chartParts.js.map +1 -1
- package/dist/ui/metrics/heatmapScale.js +15 -1
- package/dist/ui/metrics/heatmapScale.js.map +1 -1
- package/dist/ui/navigation/ColorSchemeToggle.js +3 -1
- package/dist/ui/navigation/ColorSchemeToggle.js.map +1 -1
- package/dist/ui/navigation/DocumentTitle.js +3 -1
- package/dist/ui/navigation/DocumentTitle.js.map +1 -1
- package/dist/ui/navigation/FontSizeToggle.js +3 -1
- package/dist/ui/navigation/FontSizeToggle.js.map +1 -1
- package/dist/ui/navigation/LanguageToggle.js +3 -1
- package/dist/ui/navigation/LanguageToggle.js.map +1 -1
- package/dist/ui/navigation/PageBreadcrumbs.js +3 -1
- package/dist/ui/navigation/PageBreadcrumbs.js.map +1 -1
- package/dist/ui/timeline/GroupedTimeline.js +3 -1
- package/dist/ui/timeline/GroupedTimeline.js.map +1 -1
- package/dist/upload/FileDropzone.js +4 -1
- package/dist/upload/FileDropzone.js.map +1 -1
- package/package.json +1 -1
|
@@ -7,11 +7,13 @@ import Typography from "@mui/material/Typography";
|
|
|
7
7
|
import ScienceOutlinedIcon from "@mui/icons-material/ScienceOutlined";
|
|
8
8
|
import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
|
|
9
9
|
import { piecePart, usePieceProps } from "../theme/themePieces.js";
|
|
10
|
+
import { warnUnknownProps } from "../toolkit/unknownProps.js";
|
|
10
11
|
const THEME_NAME = "CalcitaDemoTotpCode";
|
|
11
12
|
const TotpRoot = piecePart(THEME_NAME, "Root", Stack);
|
|
12
13
|
const TotpCode = piecePart(THEME_NAME, "Code", Typography);
|
|
13
14
|
function DemoTotpCodeButton(props) {
|
|
14
|
-
const { loadCode } = usePieceProps(props, THEME_NAME);
|
|
15
|
+
const { loadCode, ...unknownProps } = usePieceProps(props, THEME_NAME);
|
|
16
|
+
warnUnknownProps(THEME_NAME, unknownProps);
|
|
15
17
|
const { t } = useToolkitTranslation("account");
|
|
16
18
|
const { setFieldValue } = useFormikContext();
|
|
17
19
|
const fillCode = async () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DemoTotpCodeButton.js","sources":["../../src/account/DemoTotpCodeButton.jsx"],"sourcesContent":["// El atajo de la DEMOSTRACIÓN para la app autenticadora: llena el campo «code» del formulario con el código que enseñaría\n// la app ahorita. Para quien prueba sin la app en su teléfono (y para las pruebas automáticas, que no escanean QR). Solo\n// sale cuando el conector trae demoTotpCode: con un backend de verdad no existe (el código solo lo conoce la app).\n//\n// Va dentro del formulario de formik (abajo del segundo paso o en el diálogo de activar la app).\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaDemoTotpCode con defaultProps y\n// styleOverrides de sus partes: root, code.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useFormikContext} from 'formik';\nimport Button from '@mui/material/Button';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\nimport ScienceOutlinedIcon from '@mui/icons-material/ScienceOutlined';\n\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaDemoTotpCode)\nconst THEME_NAME = 'CalcitaDemoTotpCode';\nconst TotpRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst TotpCode = piecePart(THEME_NAME, 'Code', Typography);\n\n/**\n * @param {{loadCode: () => Promise<string|null>}} props\n */\nexport default function DemoTotpCodeButton(props) {\n // lo que el proyecto puso en su tema (components.CalcitaDemoTotpCode.defaultProps) y encima lo que llega aquí\n const {loadCode} = usePieceProps(props, THEME_NAME);\n const {t} = useToolkitTranslation('account');\n const {setFieldValue} = useFormikContext();\n\n const fillCode = async () => {\n const code = await loadCode();\n if (code) {\n setFieldValue('code', code);\n }\n };\n\n return (\n <TotpRoot spacing={0.5} ownSx={{alignItems: 'center'}}>\n <Button size=\"small\" startIcon={<ScienceOutlinedIcon />} onClick={fillCode}>{t('demo.totpCode')}</Button>\n <TotpCode variant=\"caption\" color=\"text.secondary\" ownSx={{textAlign: 'center'}}>{t('demo.totpCodeHelp')}</TotpCode>\n </TotpRoot>\n );\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"DemoTotpCodeButton.js","sources":["../../src/account/DemoTotpCodeButton.jsx"],"sourcesContent":["// El atajo de la DEMOSTRACIÓN para la app autenticadora: llena el campo «code» del formulario con el código que enseñaría\n// la app ahorita. Para quien prueba sin la app en su teléfono (y para las pruebas automáticas, que no escanean QR). Solo\n// sale cuando el conector trae demoTotpCode: con un backend de verdad no existe (el código solo lo conoce la app).\n//\n// Va dentro del formulario de formik (abajo del segundo paso o en el diálogo de activar la app).\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaDemoTotpCode con defaultProps y\n// styleOverrides de sus partes: root, code.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useFormikContext} from 'formik';\nimport Button from '@mui/material/Button';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\nimport ScienceOutlinedIcon from '@mui/icons-material/ScienceOutlined';\n\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaDemoTotpCode)\nconst THEME_NAME = 'CalcitaDemoTotpCode';\nconst TotpRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst TotpCode = piecePart(THEME_NAME, 'Code', Typography);\n\n/**\n * @param {{loadCode: () => Promise<string|null>}} props\n */\nexport default function DemoTotpCodeButton(props) {\n // lo que el proyecto puso en su tema (components.CalcitaDemoTotpCode.defaultProps) y encima lo que llega aquí\n const {loadCode, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('account');\n const {setFieldValue} = useFormikContext();\n\n const fillCode = async () => {\n const code = await loadCode();\n if (code) {\n setFieldValue('code', code);\n }\n };\n\n return (\n <TotpRoot spacing={0.5} ownSx={{alignItems: 'center'}}>\n <Button size=\"small\" startIcon={<ScienceOutlinedIcon />} onClick={fillCode}>{t('demo.totpCode')}</Button>\n <TotpCode variant=\"caption\" color=\"text.secondary\" ownSx={{textAlign: 'center'}}>{t('demo.totpCodeHelp')}</TotpCode>\n </TotpRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;AAqBA,MAAM,aAAa;AACnB,MAAM,WAAW,UAAU,YAAY,QAAQ,KAAK;AACpD,MAAM,WAAW,UAAU,YAAY,QAAQ,UAAU;AAKzD,SAAwB,mBAAmB,OAAO;AAE9C,QAAM,EAAC,UAAU,GAAG,iBAAgB,cAAc,OAAO,UAAU;AACnE,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,SAAS;AAC3C,QAAM,EAAC,cAAA,IAAiB,iBAAA;AAExB,QAAM,WAAW,YAAY;AACzB,UAAM,OAAO,MAAM,SAAA;AACnB,QAAI,MAAM;AACN,oBAAc,QAAQ,IAAI;AAAA,IAC9B;AAAA,EACJ;AAEA,SACI,qBAAC,YAAS,SAAS,KAAK,OAAO,EAAC,YAAY,YACxC,UAAA;AAAA,IAAA,oBAAC,QAAA,EAAO,MAAK,SAAQ,WAAW,oBAAC,qBAAA,CAAA,CAAoB,GAAI,SAAS,UAAW,UAAA,EAAE,eAAe,GAAE;AAAA,IAChG,oBAAC,UAAA,EAAS,SAAQ,WAAU,OAAM,kBAAiB,OAAO,EAAC,WAAW,SAAA,GAAY,UAAA,EAAE,mBAAmB,EAAA,CAAE;AAAA,EAAA,GAC7G;AAER;"}
|
|
@@ -5,7 +5,9 @@ import { AuthLayout } from "../appShell/AuthLayout.js";
|
|
|
5
5
|
import ForgotPasswordForm from "../forms/auth/ForgotPasswordForm.js";
|
|
6
6
|
import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
|
|
7
7
|
import ComponentTexts from "../toolkit/ComponentTexts.js";
|
|
8
|
-
|
|
8
|
+
import { warnUnknownProps } from "../toolkit/unknownProps.js";
|
|
9
|
+
function ForgotPasswordScreen({ signInPath, logo, brandName, showLanguageToggle = true, showColorSchemeToggle = true, texts, ...unknownProps }) {
|
|
10
|
+
warnUnknownProps("ForgotPasswordScreen", unknownProps);
|
|
9
11
|
const { t } = useToolkitTranslation("auth", texts);
|
|
10
12
|
const { connector } = useAccount();
|
|
11
13
|
return /* @__PURE__ */ jsx(ComponentTexts, { namespace: "auth", texts, children: /* @__PURE__ */ jsx(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ForgotPasswordScreen.js","sources":["../../src/account/ForgotPasswordScreen.jsx"],"sourcesContent":["// «¿Olvidó su contraseña?», completa: pide el correo y avisa que revise su bandeja (ForgotPasswordForm). Lo del servidor\n// sale del conector de la cuenta (requestPasswordReset).\n//\n// <ForgotPasswordScreen signInPath=\"/sign-in\" logo={<AppLogo />} />\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useAccount} from '@/account/AccountProvider.jsx';\nimport {AuthLayout} from '@/appShell/AuthLayout.jsx';\nimport ForgotPasswordForm from '@/forms/auth/ForgotPasswordForm.jsx';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport ComponentTexts from '@/toolkit/ComponentTexts.jsx';\n\n/**\n * @param {object} props\n * @param {string} [props.signInPath] la liga para regresar a entrar\n * @param {import('react').ReactNode} [props.logo]\n * @param {string} [props.brandName]\n * @param {boolean} [props.showLanguageToggle]\n * @param {boolean} [props.showColorSchemeToggle]\n * @param {object} [props.texts] los textos que cambian, con la forma de `auth` en los textos del paquete\n */\nexport default function ForgotPasswordScreen({signInPath, logo, brandName, showLanguageToggle = true, showColorSchemeToggle = true, texts}) {\n const {t} = useToolkitTranslation('auth', texts);\n const {connector} = useAccount();\n\n return (\n <ComponentTexts namespace=\"auth\" texts={texts}>\n <AuthLayout logo={logo} brandName={brandName} title={t('forgotPassword.title')} description={t('forgotPassword.subtitle')}\n showLanguageToggle={showLanguageToggle} showColorSchemeToggle={showColorSchemeToggle}>\n <ForgotPasswordForm onSubmit={connector.requestPasswordReset} signInPath={signInPath} />\n </AuthLayout>\n </ComponentTexts>\n );\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ForgotPasswordScreen.js","sources":["../../src/account/ForgotPasswordScreen.jsx"],"sourcesContent":["// «¿Olvidó su contraseña?», completa: pide el correo y avisa que revise su bandeja (ForgotPasswordForm). Lo del servidor\n// sale del conector de la cuenta (requestPasswordReset).\n//\n// <ForgotPasswordScreen signInPath=\"/sign-in\" logo={<AppLogo />} />\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useAccount} from '@/account/AccountProvider.jsx';\nimport {AuthLayout} from '@/appShell/AuthLayout.jsx';\nimport ForgotPasswordForm from '@/forms/auth/ForgotPasswordForm.jsx';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport ComponentTexts from '@/toolkit/ComponentTexts.jsx';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n/**\n * @param {object} props\n * @param {string} [props.signInPath] la liga para regresar a entrar\n * @param {import('react').ReactNode} [props.logo]\n * @param {string} [props.brandName]\n * @param {boolean} [props.showLanguageToggle]\n * @param {boolean} [props.showColorSchemeToggle]\n * @param {object} [props.texts] los textos que cambian, con la forma de `auth` en los textos del paquete\n */\nexport default function ForgotPasswordScreen({signInPath, logo, brandName, showLanguageToggle = true, showColorSchemeToggle = true, texts, ...unknownProps}) {\n warnUnknownProps('ForgotPasswordScreen', unknownProps);\n const {t} = useToolkitTranslation('auth', texts);\n const {connector} = useAccount();\n\n return (\n <ComponentTexts namespace=\"auth\" texts={texts}>\n <AuthLayout logo={logo} brandName={brandName} title={t('forgotPassword.title')} description={t('forgotPassword.subtitle')}\n showLanguageToggle={showLanguageToggle} showColorSchemeToggle={showColorSchemeToggle}>\n <ForgotPasswordForm onSubmit={connector.requestPasswordReset} signInPath={signInPath} />\n </AuthLayout>\n </ComponentTexts>\n );\n}\n"],"names":[],"mappings":";;;;;;;;AAsBA,SAAwB,qBAAqB,EAAC,YAAY,MAAM,WAAW,qBAAqB,MAAM,wBAAwB,MAAM,OAAO,GAAG,aAAA,GAAe;AACzJ,mBAAiB,wBAAwB,YAAY;AACrD,QAAM,EAAC,EAAA,IAAK,sBAAsB,QAAQ,KAAK;AAC/C,QAAM,EAAC,UAAA,IAAa,WAAA;AAEpB,SACI,oBAAC,gBAAA,EAAe,WAAU,QAAO,OAC7B,UAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MAAW;AAAA,MAAY;AAAA,MAAsB,OAAO,EAAE,sBAAsB;AAAA,MAAG,aAAa,EAAE,yBAAyB;AAAA,MAC5G;AAAA,MAAwC;AAAA,MAChD,UAAA,oBAAC,oBAAA,EAAmB,UAAU,UAAU,sBAAsB,WAAA,CAAwB;AAAA,IAAA;AAAA,EAAA,GAE9F;AAER;"}
|
|
@@ -21,6 +21,7 @@ import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
|
|
|
21
21
|
import ProfileHeader from "../ui/layout/ProfileHeader.js";
|
|
22
22
|
import SectionCard from "../ui/layout/SectionCard.js";
|
|
23
23
|
import { piecePart, usePieceProps } from "../theme/themePieces.js";
|
|
24
|
+
import { warnUnknownProps } from "../toolkit/unknownProps.js";
|
|
24
25
|
const THEME_NAME = "CalcitaProfileScreen";
|
|
25
26
|
const ProfileScreenSectionTitle = piecePart(THEME_NAME, "SectionTitle", Typography);
|
|
26
27
|
const ProfileScreenForm = piecePart(THEME_NAME, "Form", Stack);
|
|
@@ -81,8 +82,10 @@ function ProfileScreen(props) {
|
|
|
81
82
|
hiddenTabs = [],
|
|
82
83
|
onTabChange,
|
|
83
84
|
onProfileSaved,
|
|
84
|
-
texts
|
|
85
|
+
texts,
|
|
86
|
+
...unknownProps
|
|
85
87
|
} = usePieceProps(props, THEME_NAME);
|
|
88
|
+
warnUnknownProps(THEME_NAME, unknownProps);
|
|
86
89
|
const { t } = useToolkitTranslation("account", texts);
|
|
87
90
|
const { session } = useAccount();
|
|
88
91
|
const { useNavigate, useLocation } = useToolkitNavigation();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProfileScreen.js","sources":["../../src/account/ProfileScreen.jsx"],"sourcesContent":["// Mi perfil, completo: quién está dentro (ProfileHeader con sus perfiles como chips) y tres pestañas:\n// - Sus datos: nombre y teléfono (el correo se ve pero no se cambia aquí); al guardar se vuelve a leer la sesión, así la\n// barra y el menú de la cuenta ya dicen el nombre nuevo;\n// - Seguridad: AccountSecuritySection (contraseña, dos pasos, sesiones y bitácora);\n// - Preferencias: AppearanceSettings (tamaño de letra, idioma y modo de color).\n// La pestaña abierta va en la dirección (?tab=): se puede compartir o recargar sin perderla. Lo del servidor sale del\n// conector de la cuenta.\n//\n// Se extiende sin tocar el framework (cada proyecto tiene su perfil «especial»):\n// - extraFields: campos propios en «Sus datos» (el área, el número de empleado…), con su valor de inicio sacado del usuario\n// de la sesión, sus reglas de yup y sus campos. Al guardar viajan a connector.updateProfile junto con name y phone: un\n// backend que ya existe recibe lo suyo con sus nombres;\n// - extraTabs: pestañas propias después de las de la casa (facturación, notificaciones…); hiddenTabs esconde las de la casa;\n// - eventos: onTabChange y onProfileSaved (lo guardado y lo que contestó el servidor);\n// - texts: cualquier texto, con la forma de `account` en los textos del paquete.\n//\n// <ProfileScreen />\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaProfileScreen con defaultProps y\n// styleOverrides de sus partes: sectionTitle, form, preferences.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useMemo} from 'react';\nimport {Form, Formik} from 'formik';\nimport Stack from '@mui/material/Stack';\nimport Tab from '@mui/material/Tab';\nimport Tabs from '@mui/material/Tabs';\nimport Typography from '@mui/material/Typography';\n\nimport AccountSecuritySection from '@/account/AccountSecuritySection.jsx';\nimport {useAccount} from '@/account/AccountProvider.jsx';\nimport AppearanceSettings from '@/appShell/AppearanceSettings.jsx';\nimport {toastSuccess} from '@/feedback/toast.jsx';\nimport FormProblemAlert from '@/forms/FormProblemAlert.jsx';\nimport FormTextField from '@/forms/FormTextField.jsx';\nimport SubmitButton from '@/forms/SubmitButton.jsx';\nimport {applyServerProblem} from '@/forms/applyServerProblem.js';\nimport {Yup} from '@/forms/validation.js';\nimport TextInput from '@/inputs/TextInput.jsx';\nimport {useToolkitNavigation} from '@/toolkit/toolkitContext.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport ProfileHeader from '@/ui/layout/ProfileHeader.jsx';\nimport SectionCard from '@/ui/layout/SectionCard.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaProfileScreen)\nconst THEME_NAME = 'CalcitaProfileScreen';\nconst ProfileScreenSectionTitle = piecePart(THEME_NAME, 'SectionTitle', Typography);\nconst ProfileScreenForm = piecePart(THEME_NAME, 'Form', Stack);\nconst ProfileScreenPreferences = piecePart(THEME_NAME, 'Preferences', Stack);\n\n/** Las pestañas, en el orden en que se pintan. */\nexport const PROFILE_TAB = Object.freeze({data: 'data', security: 'security', preferences: 'preferences'});\nconst TAB_PARAM = 'tab';\n// el teléfono: dígitos, con + opcional al inicio (formato internacional); lo largo que permite el plan de numeración\nconst PHONE_PATTERN = /^\\+?\\d{7,15}$/;\n// lo ancho de los formularios: un renglón cómodo, no toda la pantalla\nconst FORM_MAX_WIDTH = 520;\n\n/**\n * Sus datos: nombre, teléfono y los campos propios del proyecto (extraFields).\n *\n * @param {object} props\n * @param {object} [props.extraFields]\n * @param {Function} [props.onProfileSaved]\n * @param {object} [props.texts]\n */\nfunction ProfileDataSection({extraFields, onProfileSaved, texts}) {\n const {t} = useToolkitTranslation('account', texts);\n const {connector, session, refreshSession} = useAccount();\n const extraRules = extraFields?.rules;\n // el esquema se arma al pintar: yup toma sus mensajes al armarlo. Las reglas propias se suman a las de la casa\n const schema = useMemo(() => Yup.object({\n name: Yup.string().trim().required(),\n phone: Yup.string().trim().matches(PHONE_PATTERN, {message: {key: 'account:profile.data.phoneInvalid'}, excludeEmptyString: true}),\n ...extraRules,\n }), [extraRules]);\n const initialValues = {name: session.user.name ?? '', phone: session.user.phone ?? '', ...extraFields?.initialValues?.(session.user)};\n\n const save = async (values, formikHelpers) => {\n // lo de la casa limpio de espacios; lo propio, tal como lo dejaron sus campos\n const profile = {...values, name: values.name.trim(), phone: values.phone.trim()};\n try {\n const response = await connector.updateProfile(profile);\n await refreshSession();\n toastSuccess(response?.message ?? t('profile.data.saved'));\n onProfileSaved?.({values: profile, response});\n } catch (error) {\n applyServerProblem(error, {...formikHelpers, values});\n }\n };\n\n return (\n <SectionCard title={t('profile.data.title')}>\n <ProfileScreenSectionTitle variant=\"body2\" color=\"text.secondary\" ownSx={{mb: 2}}>{t('profile.data.text')}</ProfileScreenSectionTitle>\n <Formik initialValues={initialValues} validationSchema={schema} onSubmit={save}>\n <Form noValidate>\n <ProfileScreenForm spacing={2} ownSx={{maxWidth: FORM_MAX_WIDTH}}>\n <FormProblemAlert />\n <FormTextField name=\"name\" label={t('profile.data.name')} autoComplete=\"name\" />\n {/* el correo se ve con el mismo estilo de los demás campos, pero no se cambia aquí */}\n <TextInput name=\"email\" label={t('profile.data.email')} value={session.user.email} onChange={() => {}}\n helperText={t('profile.data.emailHelp')} disabled />\n <FormTextField name=\"phone\" label={t('profile.data.phone')} type=\"tel\" autoComplete=\"tel\" inputMode=\"tel\" />\n {extraFields?.fields}\n <SubmitButton sx={{alignSelf: 'flex-start'}}>{t('profile.data.save')}</SubmitButton>\n </ProfileScreenForm>\n </Form>\n </Formik>\n </SectionCard>\n );\n}\n\n/** @typedef {import('@/account/accountConnector.js').AccountUser} AccountUser */\n\n/**\n * @param {object} props\n * @param {boolean} [props.showColorScheme] el ajuste de claro u oscuro en Preferencias; sin modo oscuro, false\n * @param {{initialValues?: (user: AccountUser & Record<string, any>) => Record<string, any>, rules?: Record<string, any>, fields: import('react').ReactNode}} [props.extraFields]\n * campos propios en «Sus datos», debajo del teléfono: sus valores de inicio salen del usuario de la sesión (lo que su\n * conector ponga en session.user), sus reglas de yup y sus campos (FormTextField, FormSelectField… de /forms). Al guardar\n * viajan a connector.updateProfile junto con name y phone\n * @param {Array<{key: string, label: string, content: import('react').ReactNode}>} [props.extraTabs] pestañas propias,\n * después de las de la casa; label ya traducido\n * @param {Array<'data'|'security'|'preferences'>} [props.hiddenTabs] pestañas de la casa que no se ven (PROFILE_TAB)\n * @param {(tab: string) => void} [props.onTabChange] cada que se cambia de pestaña\n * @param {(saved: {values: Record<string, any>, response: unknown}) => void} [props.onProfileSaved] después de guardar «Sus datos»\n * @param {object} [props.texts] los textos que cambian, con la forma de `account` en los textos del paquete:\n * {profile: {tabs: {data: 'Mis datos'}}}\n */\nexport default function ProfileScreen(props) {\n // lo que el proyecto puso en su tema (components.CalcitaProfileScreen.defaultProps) y encima lo que llega aquí\n const {\n showColorScheme = true, extraFields, extraTabs = [], hiddenTabs = [], onTabChange, onProfileSaved, texts,\n} = usePieceProps(props, THEME_NAME);\n const {t} = useToolkitTranslation('account', texts);\n const {session} = useAccount();\n const {useNavigate, useLocation} = useToolkitNavigation();\n const navigate = useNavigate();\n const {pathname, search} = useLocation();\n // las pestañas que se ven: las de la casa que no se escondieron y luego las del proyecto\n const tabs = [\n ...Object.values(PROFILE_TAB).filter((tab) => !hiddenTabs.includes(tab)).map((tab) => ({key: tab, label: t(`profile.tabs.${tab}`)})),\n ...extraTabs.map(({key, label}) => ({key, label})),\n ];\n const requestedTab = new URLSearchParams(search).get(TAB_PARAM);\n const activeTab = tabs.some((tab) => tab.key === requestedTab) ? requestedTab : tabs[0]?.key;\n const activeExtraTab = extraTabs.find((tab) => tab.key === activeTab);\n const changeTab = (tab) => {\n navigate(`${pathname}?${TAB_PARAM}=${tab}`, {replace: true});\n onTabChange?.(tab);\n };\n\n // guard clause: sin sesión no hay perfil que enseñar (el marco de la app ya lleva a entrar)\n if (!session) {\n return null;\n }\n\n return (\n <Stack spacing={2}>\n <ProfileHeader name={session.user.name} email={session.user.email} subtitle={session.user.subtitle} avatarUrl={session.user.avatarUrl}\n chips={session.labels ?? []} />\n <Tabs value={activeTab} onChange={(event, tab) => changeTab(tab)} aria-label={t('profile.tabs.label')}\n variant=\"scrollable\" allowScrollButtonsMobile>\n {tabs.map((tab) => <Tab key={tab.key} value={tab.key} label={tab.label} />)}\n </Tabs>\n {activeTab === PROFILE_TAB.data && <ProfileDataSection extraFields={extraFields} onProfileSaved={onProfileSaved} texts={texts} />}\n {activeTab === PROFILE_TAB.security && <AccountSecuritySection />}\n {activeTab === PROFILE_TAB.preferences && (\n <SectionCard title={t('profile.preferences.title')}>\n <ProfileScreenSectionTitle variant=\"body2\" color=\"text.secondary\" ownSx={{mb: 1}}>{t('profile.preferences.text')}</ProfileScreenSectionTitle>\n <ProfileScreenPreferences ownSx={{maxWidth: FORM_MAX_WIDTH, mx: -1}}>\n <AppearanceSettings showColorScheme={showColorScheme} />\n </ProfileScreenPreferences>\n </SectionCard>\n )}\n {activeExtraTab?.content}\n </Stack>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProfileScreen.js","sources":["../../src/account/ProfileScreen.jsx"],"sourcesContent":["// Mi perfil, completo: quién está dentro (ProfileHeader con sus perfiles como chips) y tres pestañas:\n// - Sus datos: nombre y teléfono (el correo se ve pero no se cambia aquí); al guardar se vuelve a leer la sesión, así la\n// barra y el menú de la cuenta ya dicen el nombre nuevo;\n// - Seguridad: AccountSecuritySection (contraseña, dos pasos, sesiones y bitácora);\n// - Preferencias: AppearanceSettings (tamaño de letra, idioma y modo de color).\n// La pestaña abierta va en la dirección (?tab=): se puede compartir o recargar sin perderla. Lo del servidor sale del\n// conector de la cuenta.\n//\n// Se extiende sin tocar el framework (cada proyecto tiene su perfil «especial»):\n// - extraFields: campos propios en «Sus datos» (el área, el número de empleado…), con su valor de inicio sacado del usuario\n// de la sesión, sus reglas de yup y sus campos. Al guardar viajan a connector.updateProfile junto con name y phone: un\n// backend que ya existe recibe lo suyo con sus nombres;\n// - extraTabs: pestañas propias después de las de la casa (facturación, notificaciones…); hiddenTabs esconde las de la casa;\n// - eventos: onTabChange y onProfileSaved (lo guardado y lo que contestó el servidor);\n// - texts: cualquier texto, con la forma de `account` en los textos del paquete.\n//\n// <ProfileScreen />\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaProfileScreen con defaultProps y\n// styleOverrides de sus partes: sectionTitle, form, preferences.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useMemo} from 'react';\nimport {Form, Formik} from 'formik';\nimport Stack from '@mui/material/Stack';\nimport Tab from '@mui/material/Tab';\nimport Tabs from '@mui/material/Tabs';\nimport Typography from '@mui/material/Typography';\n\nimport AccountSecuritySection from '@/account/AccountSecuritySection.jsx';\nimport {useAccount} from '@/account/AccountProvider.jsx';\nimport AppearanceSettings from '@/appShell/AppearanceSettings.jsx';\nimport {toastSuccess} from '@/feedback/toast.jsx';\nimport FormProblemAlert from '@/forms/FormProblemAlert.jsx';\nimport FormTextField from '@/forms/FormTextField.jsx';\nimport SubmitButton from '@/forms/SubmitButton.jsx';\nimport {applyServerProblem} from '@/forms/applyServerProblem.js';\nimport {Yup} from '@/forms/validation.js';\nimport TextInput from '@/inputs/TextInput.jsx';\nimport {useToolkitNavigation} from '@/toolkit/toolkitContext.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport ProfileHeader from '@/ui/layout/ProfileHeader.jsx';\nimport SectionCard from '@/ui/layout/SectionCard.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaProfileScreen)\nconst THEME_NAME = 'CalcitaProfileScreen';\nconst ProfileScreenSectionTitle = piecePart(THEME_NAME, 'SectionTitle', Typography);\nconst ProfileScreenForm = piecePart(THEME_NAME, 'Form', Stack);\nconst ProfileScreenPreferences = piecePart(THEME_NAME, 'Preferences', Stack);\n\n/** Las pestañas, en el orden en que se pintan. */\nexport const PROFILE_TAB = Object.freeze({data: 'data', security: 'security', preferences: 'preferences'});\nconst TAB_PARAM = 'tab';\n// el teléfono: dígitos, con + opcional al inicio (formato internacional); lo largo que permite el plan de numeración\nconst PHONE_PATTERN = /^\\+?\\d{7,15}$/;\n// lo ancho de los formularios: un renglón cómodo, no toda la pantalla\nconst FORM_MAX_WIDTH = 520;\n\n/**\n * Sus datos: nombre, teléfono y los campos propios del proyecto (extraFields).\n *\n * @param {object} props\n * @param {object} [props.extraFields]\n * @param {Function} [props.onProfileSaved]\n * @param {object} [props.texts]\n */\nfunction ProfileDataSection({extraFields, onProfileSaved, texts}) {\n const {t} = useToolkitTranslation('account', texts);\n const {connector, session, refreshSession} = useAccount();\n const extraRules = extraFields?.rules;\n // el esquema se arma al pintar: yup toma sus mensajes al armarlo. Las reglas propias se suman a las de la casa\n const schema = useMemo(() => Yup.object({\n name: Yup.string().trim().required(),\n phone: Yup.string().trim().matches(PHONE_PATTERN, {message: {key: 'account:profile.data.phoneInvalid'}, excludeEmptyString: true}),\n ...extraRules,\n }), [extraRules]);\n const initialValues = {name: session.user.name ?? '', phone: session.user.phone ?? '', ...extraFields?.initialValues?.(session.user)};\n\n const save = async (values, formikHelpers) => {\n // lo de la casa limpio de espacios; lo propio, tal como lo dejaron sus campos\n const profile = {...values, name: values.name.trim(), phone: values.phone.trim()};\n try {\n const response = await connector.updateProfile(profile);\n await refreshSession();\n toastSuccess(response?.message ?? t('profile.data.saved'));\n onProfileSaved?.({values: profile, response});\n } catch (error) {\n applyServerProblem(error, {...formikHelpers, values});\n }\n };\n\n return (\n <SectionCard title={t('profile.data.title')}>\n <ProfileScreenSectionTitle variant=\"body2\" color=\"text.secondary\" ownSx={{mb: 2}}>{t('profile.data.text')}</ProfileScreenSectionTitle>\n <Formik initialValues={initialValues} validationSchema={schema} onSubmit={save}>\n <Form noValidate>\n <ProfileScreenForm spacing={2} ownSx={{maxWidth: FORM_MAX_WIDTH}}>\n <FormProblemAlert />\n <FormTextField name=\"name\" label={t('profile.data.name')} autoComplete=\"name\" />\n {/* el correo se ve con el mismo estilo de los demás campos, pero no se cambia aquí */}\n <TextInput name=\"email\" label={t('profile.data.email')} value={session.user.email} onChange={() => {}}\n helperText={t('profile.data.emailHelp')} disabled />\n <FormTextField name=\"phone\" label={t('profile.data.phone')} type=\"tel\" autoComplete=\"tel\" inputMode=\"tel\" />\n {extraFields?.fields}\n <SubmitButton sx={{alignSelf: 'flex-start'}}>{t('profile.data.save')}</SubmitButton>\n </ProfileScreenForm>\n </Form>\n </Formik>\n </SectionCard>\n );\n}\n\n/** @typedef {import('@/account/accountConnector.js').AccountUser} AccountUser */\n\n/**\n * @param {object} props\n * @param {boolean} [props.showColorScheme] el ajuste de claro u oscuro en Preferencias; sin modo oscuro, false\n * @param {{initialValues?: (user: AccountUser & Record<string, any>) => Record<string, any>, rules?: Record<string, any>, fields: import('react').ReactNode}} [props.extraFields]\n * campos propios en «Sus datos», debajo del teléfono: sus valores de inicio salen del usuario de la sesión (lo que su\n * conector ponga en session.user), sus reglas de yup y sus campos (FormTextField, FormSelectField… de /forms). Al guardar\n * viajan a connector.updateProfile junto con name y phone\n * @param {Array<{key: string, label: string, content: import('react').ReactNode}>} [props.extraTabs] pestañas propias,\n * después de las de la casa; label ya traducido\n * @param {Array<'data'|'security'|'preferences'>} [props.hiddenTabs] pestañas de la casa que no se ven (PROFILE_TAB)\n * @param {(tab: string) => void} [props.onTabChange] cada que se cambia de pestaña\n * @param {(saved: {values: Record<string, any>, response: unknown}) => void} [props.onProfileSaved] después de guardar «Sus datos»\n * @param {object} [props.texts] los textos que cambian, con la forma de `account` en los textos del paquete:\n * {profile: {tabs: {data: 'Mis datos'}}}\n */\nexport default function ProfileScreen(props) {\n // lo que el proyecto puso en su tema (components.CalcitaProfileScreen.defaultProps) y encima lo que llega aquí\n const {\n showColorScheme = true, extraFields, extraTabs = [], hiddenTabs = [], onTabChange, onProfileSaved, texts,\n ...unknownProps\n} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('account', texts);\n const {session} = useAccount();\n const {useNavigate, useLocation} = useToolkitNavigation();\n const navigate = useNavigate();\n const {pathname, search} = useLocation();\n // las pestañas que se ven: las de la casa que no se escondieron y luego las del proyecto\n const tabs = [\n ...Object.values(PROFILE_TAB).filter((tab) => !hiddenTabs.includes(tab)).map((tab) => ({key: tab, label: t(`profile.tabs.${tab}`)})),\n ...extraTabs.map(({key, label}) => ({key, label})),\n ];\n const requestedTab = new URLSearchParams(search).get(TAB_PARAM);\n const activeTab = tabs.some((tab) => tab.key === requestedTab) ? requestedTab : tabs[0]?.key;\n const activeExtraTab = extraTabs.find((tab) => tab.key === activeTab);\n const changeTab = (tab) => {\n navigate(`${pathname}?${TAB_PARAM}=${tab}`, {replace: true});\n onTabChange?.(tab);\n };\n\n // guard clause: sin sesión no hay perfil que enseñar (el marco de la app ya lleva a entrar)\n if (!session) {\n return null;\n }\n\n return (\n <Stack spacing={2}>\n <ProfileHeader name={session.user.name} email={session.user.email} subtitle={session.user.subtitle} avatarUrl={session.user.avatarUrl}\n chips={session.labels ?? []} />\n <Tabs value={activeTab} onChange={(event, tab) => changeTab(tab)} aria-label={t('profile.tabs.label')}\n variant=\"scrollable\" allowScrollButtonsMobile>\n {tabs.map((tab) => <Tab key={tab.key} value={tab.key} label={tab.label} />)}\n </Tabs>\n {activeTab === PROFILE_TAB.data && <ProfileDataSection extraFields={extraFields} onProfileSaved={onProfileSaved} texts={texts} />}\n {activeTab === PROFILE_TAB.security && <AccountSecuritySection />}\n {activeTab === PROFILE_TAB.preferences && (\n <SectionCard title={t('profile.preferences.title')}>\n <ProfileScreenSectionTitle variant=\"body2\" color=\"text.secondary\" ownSx={{mb: 1}}>{t('profile.preferences.text')}</ProfileScreenSectionTitle>\n <ProfileScreenPreferences ownSx={{maxWidth: FORM_MAX_WIDTH, mx: -1}}>\n <AppearanceSettings showColorScheme={showColorScheme} />\n </ProfileScreenPreferences>\n </SectionCard>\n )}\n {activeExtraTab?.content}\n </Stack>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -9,6 +9,7 @@ import { AuthLayout } from "../appShell/AuthLayout.js";
|
|
|
9
9
|
import ChangePasswordForm from "../forms/auth/ChangePasswordForm.js";
|
|
10
10
|
import { useToolkitNavigation } from "../toolkit/toolkitContext.js";
|
|
11
11
|
import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
|
|
12
|
+
import { warnUnknownProps } from "../toolkit/unknownProps.js";
|
|
12
13
|
function ResetPasswordScreen({
|
|
13
14
|
signInPath,
|
|
14
15
|
forgotPasswordPath,
|
|
@@ -17,8 +18,10 @@ function ResetPasswordScreen({
|
|
|
17
18
|
brandName,
|
|
18
19
|
showLanguageToggle = true,
|
|
19
20
|
showColorSchemeToggle = true,
|
|
20
|
-
texts
|
|
21
|
+
texts,
|
|
22
|
+
...unknownProps
|
|
21
23
|
}) {
|
|
24
|
+
warnUnknownProps("ResetPasswordScreen", unknownProps);
|
|
22
25
|
const { t } = useToolkitTranslation("account", texts);
|
|
23
26
|
const { connector } = useAccount();
|
|
24
27
|
const { useLocation, Link } = useToolkitNavigation();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResetPasswordScreen.js","sources":["../../src/account/ResetPasswordScreen.jsx"],"sourcesContent":["// Elegir una contraseña nueva desde el enlace del correo, completa: ChangePasswordForm sin la contraseña actual (quien llega\n// aquí la olvidó). El enlace trae su clave (?token=) y el servidor la revisa al guardar (connector.resetPassword). Sin\n// clave en la dirección, se dice que el enlace no sirve y cómo pedir otro.\n//\n// <ResetPasswordScreen signInPath=\"/sign-in\" forgotPasswordPath=\"/forgot-password\" logo={<AppLogo />} />\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useState} from 'react';\nimport Alert from '@mui/material/Alert';\nimport Button from '@mui/material/Button';\nimport Stack from '@mui/material/Stack';\n\nimport {useAccount} from '@/account/AccountProvider.jsx';\nimport {AuthLayout} from '@/appShell/AuthLayout.jsx';\nimport ChangePasswordForm from '@/forms/auth/ChangePasswordForm.jsx';\nimport {useToolkitNavigation} from '@/toolkit/toolkitContext.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\n\n/**\n * @param {object} props\n * @param {string} props.signInPath a dónde ir al terminar\n * @param {string} [props.forgotPasswordPath] para pedir otro enlace si este no sirve\n * @param {string} [props.tokenParam] cómo se llama la clave en la dirección; por omisión 'token'\n * @param {import('react').ReactNode} [props.logo]\n * @param {string} [props.brandName]\n * @param {boolean} [props.showLanguageToggle]\n * @param {boolean} [props.showColorSchemeToggle]\n * @param {object} [props.texts] los textos que cambian, con la forma de `account` en los textos del paquete\n */\nexport default function ResetPasswordScreen({\n signInPath, forgotPasswordPath, tokenParam = 'token', logo, brandName, showLanguageToggle = true, showColorSchemeToggle = true, texts,\n}) {\n const {t} = useToolkitTranslation('account', texts);\n const {connector} = useAccount();\n const {useLocation, Link} = useToolkitNavigation();\n const {search} = useLocation();\n const [isDone, setIsDone] = useState(false);\n const token = new URLSearchParams(search).get(tokenParam);\n\n const save = async ({newPassword}) => {\n await connector.resetPassword({token, newPassword});\n setIsDone(true);\n };\n\n return (\n <AuthLayout logo={logo} brandName={brandName} title={t('reset.title')} description={t('reset.subtitle')}\n showLanguageToggle={showLanguageToggle} showColorSchemeToggle={showColorSchemeToggle}>\n {!token && (\n <Stack spacing={2}>\n <Alert severity=\"error\">{t('reset.missingToken')}</Alert>\n {forgotPasswordPath && <Button component={Link} to={forgotPasswordPath} variant=\"contained\">{t('reset.askAgain')}</Button>}\n </Stack>\n )}\n {token && isDone && (\n <Stack spacing={2}>\n <Alert severity=\"success\" role=\"status\">{t('reset.done')}</Alert>\n <Button component={Link} to={signInPath} variant=\"contained\">{t('reset.goToSignIn')}</Button>\n </Stack>\n )}\n {token && !isDone && <ChangePasswordForm requireCurrentPassword={false} onSubmit={save} />}\n </AuthLayout>\n );\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ResetPasswordScreen.js","sources":["../../src/account/ResetPasswordScreen.jsx"],"sourcesContent":["// Elegir una contraseña nueva desde el enlace del correo, completa: ChangePasswordForm sin la contraseña actual (quien llega\n// aquí la olvidó). El enlace trae su clave (?token=) y el servidor la revisa al guardar (connector.resetPassword). Sin\n// clave en la dirección, se dice que el enlace no sirve y cómo pedir otro.\n//\n// <ResetPasswordScreen signInPath=\"/sign-in\" forgotPasswordPath=\"/forgot-password\" logo={<AppLogo />} />\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useState} from 'react';\nimport Alert from '@mui/material/Alert';\nimport Button from '@mui/material/Button';\nimport Stack from '@mui/material/Stack';\n\nimport {useAccount} from '@/account/AccountProvider.jsx';\nimport {AuthLayout} from '@/appShell/AuthLayout.jsx';\nimport ChangePasswordForm from '@/forms/auth/ChangePasswordForm.jsx';\nimport {useToolkitNavigation} from '@/toolkit/toolkitContext.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n/**\n * @param {object} props\n * @param {string} props.signInPath a dónde ir al terminar\n * @param {string} [props.forgotPasswordPath] para pedir otro enlace si este no sirve\n * @param {string} [props.tokenParam] cómo se llama la clave en la dirección; por omisión 'token'\n * @param {import('react').ReactNode} [props.logo]\n * @param {string} [props.brandName]\n * @param {boolean} [props.showLanguageToggle]\n * @param {boolean} [props.showColorSchemeToggle]\n * @param {object} [props.texts] los textos que cambian, con la forma de `account` en los textos del paquete\n */\nexport default function ResetPasswordScreen({\n signInPath, forgotPasswordPath, tokenParam = 'token', logo, brandName, showLanguageToggle = true, showColorSchemeToggle = true, texts,\n ...unknownProps\n}) {\n warnUnknownProps('ResetPasswordScreen', unknownProps);\n const {t} = useToolkitTranslation('account', texts);\n const {connector} = useAccount();\n const {useLocation, Link} = useToolkitNavigation();\n const {search} = useLocation();\n const [isDone, setIsDone] = useState(false);\n const token = new URLSearchParams(search).get(tokenParam);\n\n const save = async ({newPassword}) => {\n await connector.resetPassword({token, newPassword});\n setIsDone(true);\n };\n\n return (\n <AuthLayout logo={logo} brandName={brandName} title={t('reset.title')} description={t('reset.subtitle')}\n showLanguageToggle={showLanguageToggle} showColorSchemeToggle={showColorSchemeToggle}>\n {!token && (\n <Stack spacing={2}>\n <Alert severity=\"error\">{t('reset.missingToken')}</Alert>\n {forgotPasswordPath && <Button component={Link} to={forgotPasswordPath} variant=\"contained\">{t('reset.askAgain')}</Button>}\n </Stack>\n )}\n {token && isDone && (\n <Stack spacing={2}>\n <Alert severity=\"success\" role=\"status\">{t('reset.done')}</Alert>\n <Button component={Link} to={signInPath} variant=\"contained\">{t('reset.goToSignIn')}</Button>\n </Stack>\n )}\n {token && !isDone && <ChangePasswordForm requireCurrentPassword={false} onSubmit={save} />}\n </AuthLayout>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AA8BA,SAAwB,oBAAoB;AAAA,EACxC;AAAA,EAAY;AAAA,EAAoB,aAAa;AAAA,EAAS;AAAA,EAAM;AAAA,EAAW,qBAAqB;AAAA,EAAM,wBAAwB;AAAA,EAAM;AAAA,EAChI,GAAG;AACP,GAAG;AACC,mBAAiB,uBAAuB,YAAY;AACpD,QAAM,EAAC,EAAA,IAAK,sBAAsB,WAAW,KAAK;AAClD,QAAM,EAAC,UAAA,IAAa,WAAA;AACpB,QAAM,EAAC,aAAa,KAAA,IAAQ,qBAAA;AAC5B,QAAM,EAAC,OAAA,IAAU,YAAA;AACjB,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,QAAM,QAAQ,IAAI,gBAAgB,MAAM,EAAE,IAAI,UAAU;AAExD,QAAM,OAAO,OAAO,EAAC,kBAAiB;AAClC,UAAM,UAAU,cAAc,EAAC,OAAO,aAAY;AAClD,cAAU,IAAI;AAAA,EAClB;AAEA,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MAAW;AAAA,MAAY;AAAA,MAAsB,OAAO,EAAE,aAAa;AAAA,MAAG,aAAa,EAAE,gBAAgB;AAAA,MAC1F;AAAA,MAAwC;AAAA,MAC/C,UAAA;AAAA,QAAA,CAAC,SACE,qBAAC,OAAA,EAAM,SAAS,GACZ,UAAA;AAAA,UAAA,oBAAC,OAAA,EAAM,UAAS,SAAS,UAAA,EAAE,oBAAoB,GAAE;AAAA,UAChD,sBAAsB,oBAAC,QAAA,EAAO,WAAW,MAAM,IAAI,oBAAoB,SAAQ,aAAa,UAAA,EAAE,gBAAgB,EAAA,CAAE;AAAA,QAAA,GACrH;AAAA,QAEH,SAAS,UACN,qBAAC,OAAA,EAAM,SAAS,GACZ,UAAA;AAAA,UAAA,oBAAC,SAAM,UAAS,WAAU,MAAK,UAAU,UAAA,EAAE,YAAY,GAAE;AAAA,UACzD,oBAAC,QAAA,EAAO,WAAW,MAAM,IAAI,YAAY,SAAQ,aAAa,UAAA,EAAE,kBAAkB,EAAA,CAAE;AAAA,QAAA,GACxF;AAAA,QAEH,SAAS,CAAC,UAAU,oBAAC,sBAAmB,wBAAwB,OAAO,UAAU,KAAA,CAAM;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGpG;"}
|
|
@@ -13,10 +13,12 @@ import { useToolkitNavigation } from "../toolkit/toolkitContext.js";
|
|
|
13
13
|
import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
|
|
14
14
|
import ComponentTexts from "../toolkit/ComponentTexts.js";
|
|
15
15
|
import { piecePart, usePieceProps } from "../theme/themePieces.js";
|
|
16
|
+
import { warnUnknownProps } from "../toolkit/unknownProps.js";
|
|
16
17
|
const THEME_NAME = "CalcitaSignInScreen";
|
|
17
18
|
const SignInAlert = piecePart(THEME_NAME, "Alert", Alert);
|
|
18
19
|
function SignInScreen(props) {
|
|
19
|
-
const { homePath = "/", forgotPasswordPath, logo, brandName, footer, showLanguageToggle = true, showColorSchemeToggle = true, texts } = usePieceProps(props, THEME_NAME);
|
|
20
|
+
const { homePath = "/", forgotPasswordPath, logo, brandName, footer, showLanguageToggle = true, showColorSchemeToggle = true, texts, ...unknownProps } = usePieceProps(props, THEME_NAME);
|
|
21
|
+
warnUnknownProps(THEME_NAME, unknownProps);
|
|
20
22
|
const { t } = useToolkitTranslation("auth", texts);
|
|
21
23
|
const { connector, session, refreshSession } = useAccount();
|
|
22
24
|
const { useNavigate, useLocation } = useToolkitNavigation();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SignInScreen.js","sources":["../../src/account/SignInScreen.jsx"],"sourcesContent":["// Entrar, completo: la contraseña (SignInForm) y, si la cuenta tiene verificación en dos pasos, el segundo paso\n// (SecondStepForm: la llave de acceso, el código de la app o uno de recuperación). Al terminar se vuelve a leer la sesión y\n// se va a la pantalla que se quería abrir (readRedirectParam: solo si es de esta app) o al inicio.\n//\n// Lo del servidor sale del conector de la cuenta (useAccount): en el proyecto la pantalla solo se pone en su ruta.\n//\n// <SignInScreen forgotPasswordPath=\"/forgot-password\" logo={<AppLogo />} />\n//\n// footer va abajo de la tarjeta. Si es una función, recibe signIn para entrar desde un botón propio (p. ej. «Entrar con la\n// cuenta de ejemplo»), con el mismo segundo paso; si falla, el motivo sale arriba del formulario.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaSignInScreen con defaultProps y\n// styleOverrides de sus partes: alert.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useEffect, useState} from 'react';\nimport Alert from '@mui/material/Alert';\n\nimport {useAccount} from '@/account/AccountProvider.jsx';\nimport DemoTotpCodeButton from '@/account/DemoTotpCodeButton.jsx';\nimport {AuthLayout} from '@/appShell/AuthLayout.jsx';\nimport SignInForm from '@/forms/auth/SignInForm.jsx';\nimport SecondStepForm, {SECOND_STEP_METHOD} from '@/forms/security/SecondStepForm.jsx';\nimport {readRedirectParam} from '@/navigation.js';\nimport {passkeysSupported, signWithPasskey} from '@/security/passkeys.js';\nimport {useToolkitNavigation} from '@/toolkit/toolkitContext.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport ComponentTexts from '@/toolkit/ComponentTexts.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaSignInScreen)\nconst THEME_NAME = 'CalcitaSignInScreen';\nconst SignInAlert = piecePart(THEME_NAME, 'Alert', Alert);\n\n/**\n * @param {object} props\n * @param {string} [props.homePath] a dónde ir si no se quería abrir otra pantalla; por omisión '/'\n * @param {string} [props.forgotPasswordPath] sin ella no sale «¿Olvidó su contraseña?»\n * @param {import('react').ReactNode} [props.logo]\n * @param {string} [props.brandName] por omisión el appName de ToolkitProvider\n * @param {import('react').ReactNode | ((helpers: {signIn: (credentials: {email: string, password: string, remember?: boolean}) => Promise<void>}) => import('react').ReactNode)} [props.footer]\n * @param {boolean} [props.showLanguageToggle] por omisión sí\n * @param {boolean} [props.showColorSchemeToggle] por omisión sí\n * @param {object} [props.texts] los textos que cambian, con la forma de `auth` en los textos del paquete\n */\nexport default function SignInScreen(props) {\n // lo que el proyecto puso en su tema (components.CalcitaSignInScreen.defaultProps) y encima lo que llega aquí\n const {homePath = '/', forgotPasswordPath, logo, brandName, footer, showLanguageToggle = true, showColorSchemeToggle = true, texts} = usePieceProps(props, THEME_NAME);\n const {t} = useToolkitTranslation('auth', texts);\n const {connector, session, refreshSession} = useAccount();\n const {useNavigate, useLocation} = useToolkitNavigation();\n const navigate = useNavigate();\n const {search} = useLocation();\n // con verificación en dos pasos: los métodos del segundo paso (la contraseña ya fue correcta)\n const [secondStep, setSecondStep] = useState(null);\n const [notice, setNotice] = useState(null);\n const destination = readRedirectParam(search) ?? homePath;\n\n // ya hay sesión (acaba de entrar, o abrió esta pantalla estando dentro): a donde iba\n useEffect(() => {\n if (session) {\n navigate(destination, {replace: true});\n }\n }, [session, destination, navigate]);\n\n // después de la contraseña: el segundo paso si lo pide el servidor; si no, ya está dentro\n const signIn = async (credentials) => {\n setNotice(null);\n const result = await connector.signIn({remember: false, ...credentials});\n if (result?.secondStep) {\n setSecondStep(result.secondStep);\n return;\n }\n await refreshSession();\n };\n // desde un botón propio del footer: el error no tiene formulario donde salir, sale arriba\n const signInFromFooter = async (credentials) => {\n try {\n await signIn(credentials);\n } catch (error) {\n setNotice(error?.message ?? null);\n }\n };\n // se acabaron los intentos o se venció el tiempo: de regreso a la contraseña, con el motivo\n const backToPassword = (message) => {\n setSecondStep(null);\n setNotice(message);\n };\n\n if (session) {\n return null;\n }\n\n if (secondStep) {\n const showsDemoCode = typeof connector.demoTotpCode === 'function' && secondStep.methods.includes(SECOND_STEP_METHOD.totp);\n return (\n <ComponentTexts namespace=\"auth\" texts={texts}>\n <AuthLayout logo={logo} brandName={brandName} title={t('security:twoStep.title')}\n showLanguageToggle={showLanguageToggle} showColorSchemeToggle={showColorSchemeToggle}>\n <SecondStepForm methods={secondStep.methods} canUsePasskeys={passkeysSupported()}\n onUsePasskey={async () => {\n await connector.signInWithPasskey(await signWithPasskey(await connector.secondStepPasskeyOptions()));\n await refreshSession();\n }}\n onSubmitCode={async ({method, code}) => {\n await connector.signInSecondStep({method, code});\n await refreshSession();\n }}\n onCancel={backToPassword}\n footer={showsDemoCode && <DemoTotpCodeButton loadCode={connector.demoTotpCode} />} />\n </AuthLayout>\n </ComponentTexts>\n );\n }\n\n return (\n <ComponentTexts namespace=\"auth\" texts={texts}>\n <AuthLayout logo={logo} brandName={brandName} title={t('signIn.title')} description={t('signIn.subtitle')}\n showLanguageToggle={showLanguageToggle} showColorSchemeToggle={showColorSchemeToggle}\n footer={typeof footer === 'function' ? footer({signIn: signInFromFooter}) : footer}>\n {notice && <SignInAlert severity=\"warning\" ownSx={{mb: 2}}>{notice}</SignInAlert>}\n <SignInForm onSubmit={signIn} forgotPasswordPath={forgotPasswordPath} />\n </AuthLayout>\n </ComponentTexts>\n );\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SignInScreen.js","sources":["../../src/account/SignInScreen.jsx"],"sourcesContent":["// Entrar, completo: la contraseña (SignInForm) y, si la cuenta tiene verificación en dos pasos, el segundo paso\n// (SecondStepForm: la llave de acceso, el código de la app o uno de recuperación). Al terminar se vuelve a leer la sesión y\n// se va a la pantalla que se quería abrir (readRedirectParam: solo si es de esta app) o al inicio.\n//\n// Lo del servidor sale del conector de la cuenta (useAccount): en el proyecto la pantalla solo se pone en su ruta.\n//\n// <SignInScreen forgotPasswordPath=\"/forgot-password\" logo={<AppLogo />} />\n//\n// footer va abajo de la tarjeta. Si es una función, recibe signIn para entrar desde un botón propio (p. ej. «Entrar con la\n// cuenta de ejemplo»), con el mismo segundo paso; si falla, el motivo sale arriba del formulario.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaSignInScreen con defaultProps y\n// styleOverrides de sus partes: alert.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useEffect, useState} from 'react';\nimport Alert from '@mui/material/Alert';\n\nimport {useAccount} from '@/account/AccountProvider.jsx';\nimport DemoTotpCodeButton from '@/account/DemoTotpCodeButton.jsx';\nimport {AuthLayout} from '@/appShell/AuthLayout.jsx';\nimport SignInForm from '@/forms/auth/SignInForm.jsx';\nimport SecondStepForm, {SECOND_STEP_METHOD} from '@/forms/security/SecondStepForm.jsx';\nimport {readRedirectParam} from '@/navigation.js';\nimport {passkeysSupported, signWithPasskey} from '@/security/passkeys.js';\nimport {useToolkitNavigation} from '@/toolkit/toolkitContext.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport ComponentTexts from '@/toolkit/ComponentTexts.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaSignInScreen)\nconst THEME_NAME = 'CalcitaSignInScreen';\nconst SignInAlert = piecePart(THEME_NAME, 'Alert', Alert);\n\n/**\n * @param {object} props\n * @param {string} [props.homePath] a dónde ir si no se quería abrir otra pantalla; por omisión '/'\n * @param {string} [props.forgotPasswordPath] sin ella no sale «¿Olvidó su contraseña?»\n * @param {import('react').ReactNode} [props.logo]\n * @param {string} [props.brandName] por omisión el appName de ToolkitProvider\n * @param {import('react').ReactNode | ((helpers: {signIn: (credentials: {email: string, password: string, remember?: boolean}) => Promise<void>}) => import('react').ReactNode)} [props.footer]\n * @param {boolean} [props.showLanguageToggle] por omisión sí\n * @param {boolean} [props.showColorSchemeToggle] por omisión sí\n * @param {object} [props.texts] los textos que cambian, con la forma de `auth` en los textos del paquete\n */\nexport default function SignInScreen(props) {\n // lo que el proyecto puso en su tema (components.CalcitaSignInScreen.defaultProps) y encima lo que llega aquí\n const {homePath = '/', forgotPasswordPath, logo, brandName, footer, showLanguageToggle = true, showColorSchemeToggle = true, texts, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('auth', texts);\n const {connector, session, refreshSession} = useAccount();\n const {useNavigate, useLocation} = useToolkitNavigation();\n const navigate = useNavigate();\n const {search} = useLocation();\n // con verificación en dos pasos: los métodos del segundo paso (la contraseña ya fue correcta)\n const [secondStep, setSecondStep] = useState(null);\n const [notice, setNotice] = useState(null);\n const destination = readRedirectParam(search) ?? homePath;\n\n // ya hay sesión (acaba de entrar, o abrió esta pantalla estando dentro): a donde iba\n useEffect(() => {\n if (session) {\n navigate(destination, {replace: true});\n }\n }, [session, destination, navigate]);\n\n // después de la contraseña: el segundo paso si lo pide el servidor; si no, ya está dentro\n const signIn = async (credentials) => {\n setNotice(null);\n const result = await connector.signIn({remember: false, ...credentials});\n if (result?.secondStep) {\n setSecondStep(result.secondStep);\n return;\n }\n await refreshSession();\n };\n // desde un botón propio del footer: el error no tiene formulario donde salir, sale arriba\n const signInFromFooter = async (credentials) => {\n try {\n await signIn(credentials);\n } catch (error) {\n setNotice(error?.message ?? null);\n }\n };\n // se acabaron los intentos o se venció el tiempo: de regreso a la contraseña, con el motivo\n const backToPassword = (message) => {\n setSecondStep(null);\n setNotice(message);\n };\n\n if (session) {\n return null;\n }\n\n if (secondStep) {\n const showsDemoCode = typeof connector.demoTotpCode === 'function' && secondStep.methods.includes(SECOND_STEP_METHOD.totp);\n return (\n <ComponentTexts namespace=\"auth\" texts={texts}>\n <AuthLayout logo={logo} brandName={brandName} title={t('security:twoStep.title')}\n showLanguageToggle={showLanguageToggle} showColorSchemeToggle={showColorSchemeToggle}>\n <SecondStepForm methods={secondStep.methods} canUsePasskeys={passkeysSupported()}\n onUsePasskey={async () => {\n await connector.signInWithPasskey(await signWithPasskey(await connector.secondStepPasskeyOptions()));\n await refreshSession();\n }}\n onSubmitCode={async ({method, code}) => {\n await connector.signInSecondStep({method, code});\n await refreshSession();\n }}\n onCancel={backToPassword}\n footer={showsDemoCode && <DemoTotpCodeButton loadCode={connector.demoTotpCode} />} />\n </AuthLayout>\n </ComponentTexts>\n );\n }\n\n return (\n <ComponentTexts namespace=\"auth\" texts={texts}>\n <AuthLayout logo={logo} brandName={brandName} title={t('signIn.title')} description={t('signIn.subtitle')}\n showLanguageToggle={showLanguageToggle} showColorSchemeToggle={showColorSchemeToggle}\n footer={typeof footer === 'function' ? footer({signIn: signInFromFooter}) : footer}>\n {notice && <SignInAlert severity=\"warning\" ownSx={{mb: 2}}>{notice}</SignInAlert>}\n <SignInForm onSubmit={signIn} forgotPasswordPath={forgotPasswordPath} />\n </AuthLayout>\n </ComponentTexts>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -20,6 +20,7 @@ import MenuLinks from "./MenuLinks.js";
|
|
|
20
20
|
import { WHITE_LABEL, MONOGRAM_GRAY } from "../theme/components/glassComponents.js";
|
|
21
21
|
import { isGlassTheme } from "../theme/glassSurface.js";
|
|
22
22
|
import { piecePart, usePieceProps } from "../theme/themePieces.js";
|
|
23
|
+
import { warnUnknownProps } from "../toolkit/unknownProps.js";
|
|
23
24
|
const THEME_NAME = "CalcitaAccountMenu";
|
|
24
25
|
const AccountButton = piecePart(THEME_NAME, "Button", IconButton);
|
|
25
26
|
const AccountAvatar = piecePart(THEME_NAME, "Avatar", Avatar);
|
|
@@ -27,7 +28,8 @@ const AccountHeader = piecePart(THEME_NAME, "Header", Box);
|
|
|
27
28
|
const AccountName = piecePart(THEME_NAME, "Name", Typography);
|
|
28
29
|
const AccountSettings = piecePart(THEME_NAME, "Settings", Box);
|
|
29
30
|
function AccountMenu(props) {
|
|
30
|
-
const { user, profilePath, accountMenuItems = [], onSignOut, isSigningOut = false, settings } = usePieceProps(props, THEME_NAME);
|
|
31
|
+
const { user, profilePath, accountMenuItems = [], onSignOut, isSigningOut = false, settings, ...unknownProps } = usePieceProps(props, THEME_NAME);
|
|
32
|
+
warnUnknownProps(THEME_NAME, unknownProps);
|
|
31
33
|
const { t } = useToolkitTranslation("layout");
|
|
32
34
|
const [anchorElement, setAnchorElement] = useState(null);
|
|
33
35
|
const closeMenu = () => setAnchorElement(null);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccountMenu.js","sources":["../../src/appShell/AccountMenu.jsx"],"sourcesContent":["// La cuenta de quien está dentro, arriba a la derecha (como en las plantillas de MUI): un avatar con sus iniciales (o su\n// foto) que abre un menú con su nombre y correo, Mi perfil, lo que el proyecto agregue (accountMenuItems: Facturación,\n// Mis llaves…) y Salir.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaAccountMenu con defaultProps y\n// styleOverrides de sus partes: button, avatar, header, name, settings.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useState} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Avatar from '@mui/material/Avatar';\nimport Box from '@mui/material/Box';\nimport Divider from '@mui/material/Divider';\nimport IconButton from '@mui/material/IconButton';\nimport ListItemIcon from '@mui/material/ListItemIcon';\nimport ListItemText from '@mui/material/ListItemText';\nimport Menu from '@mui/material/Menu';\nimport MenuItem from '@mui/material/MenuItem';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\nimport LogoutIcon from '@mui/icons-material/Logout';\nimport PersonOutlineIcon from '@mui/icons-material/PersonOutline';\n\nimport {initialsOf} from '@/appShell/menuItemText.js';\nimport {barMenuPlacementOf} from '@/appShell/barMenuPlacement.js';\nimport MenuLinks from '@/appShell/MenuLinks.jsx';\nimport {MONOGRAM_GRAY, WHITE_LABEL} from '@/theme/components/glassComponents.js';\nimport {isGlassTheme} from '@/theme/glassSurface.js';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaAccountMenu)\nconst THEME_NAME = 'CalcitaAccountMenu';\nconst AccountButton = piecePart(THEME_NAME, 'Button', IconButton);\nconst AccountAvatar = piecePart(THEME_NAME, 'Avatar', Avatar);\nconst AccountHeader = piecePart(THEME_NAME, 'Header', Box);\nconst AccountName = piecePart(THEME_NAME, 'Name', Typography);\nconst AccountSettings = piecePart(THEME_NAME, 'Settings', Box);\n\n/**\n * @param {object} props\n * @param {{name: string, email?: string, subtitle?: string, avatarUrl?: string}} props.user\n * @param {string} [props.profilePath] sin ella no sale «Mi perfil»\n * @param {Array<{to?: string, onClick?: Function, label?: string, labelKey?: string, Icon?: import('react').ElementType}>} [props.accountMenuItems]\n * @param {() => void} [props.onSignOut] sin él no sale «Salir»\n * @param {boolean} [props.isSigningOut]\n * @param {import('react').ReactNode} [props.settings] los ajustes de la app, entre los datos de la persona y sus ligas\n */\nexport default function AccountMenu(props) {\n // lo que el proyecto puso en su tema (components.CalcitaAccountMenu.defaultProps) y encima lo que llega aquí\n const {user, profilePath, accountMenuItems = [], onSignOut, isSigningOut = false, settings} = usePieceProps(props, THEME_NAME);\n const {t} = useToolkitTranslation('layout');\n const [anchorElement, setAnchorElement] = useState(null);\n const closeMenu = () => setAnchorElement(null);\n const menuLinks = [\n ...(profilePath ? [{to: profilePath, labelKey: 'layout:account.myProfile', Icon: PersonOutlineIcon}] : []),\n ...accountMenuItems,\n ];\n\n // hacia arriba si la barra está abajo (teléfono con vidrio)\n const placement = barMenuPlacementOf(anchorElement);\n\n const signOut = () => {\n closeMenu();\n onSignOut();\n };\n\n return (\n <>\n <Tooltip title={t('account.open')}>\n <AccountButton size=\"small\" aria-label={t('account.open')} aria-haspopup=\"menu\" onClick={(event) => setAnchorElement(event.currentTarget)} ownSx={{p: 0.5}}>\n <AccountAvatar src={user.avatarUrl} alt=\"\" ownSx={(theme) => ({\n width: 32, height: 32, fontSize: '0.875rem', bgcolor: 'secondary.main', color: 'secondary.contrastText',\n // con vidrio, en oscuro el monograma de Apple (gris oscuro con letra blanca), el que se aprobó. Antes lo\n // ponía el tema porque su regla de oscuro le ganaba a este sx; ahora el sx gana en los dos modos\n ...(isGlassTheme(theme) && theme.applyStyles('dark', {bgcolor: MONOGRAM_GRAY.dark, color: WHITE_LABEL})),\n })}>\n {initialsOf(user.name)}\n </AccountAvatar>\n </AccountButton>\n </Tooltip>\n <Menu anchorEl={anchorElement} open={Boolean(anchorElement)} onClose={closeMenu}\n anchorOrigin={placement.anchorOrigin} transformOrigin={placement.transformOrigin}\n slotProps={{paper: {sx: {minWidth: settings ? 300 : 240, maxWidth: 360, ...placement.gapSx}}}}>\n <AccountHeader ownSx={{px: 2, py: 1.25}}>\n <AccountName variant=\"subtitle2\" noWrap ownSx={{fontWeight: 600}}>{user.name}</AccountName>\n {user.email && <Typography variant=\"body2\" color=\"text.secondary\" noWrap>{user.email}</Typography>}\n {user.subtitle && <Typography variant=\"caption\" color=\"text.secondary\" component=\"p\" noWrap>{user.subtitle}</Typography>}\n </AccountHeader>\n {/* los ajustes de la app (letra, idioma, claro u oscuro y los del proyecto): en la cuenta y no sueltos en la barra */}\n {settings && <Divider />}\n {settings && <AccountSettings ownSx={{py: 0.5}}>{settings}</AccountSettings>}\n {menuLinks.length > 0 && <Divider />}\n <MenuLinks links={menuLinks} onClose={closeMenu} />\n {onSignOut && <Divider />}\n {onSignOut && (\n <MenuItem onClick={signOut} disabled={isSigningOut}>\n <ListItemIcon><LogoutIcon fontSize=\"small\" /></ListItemIcon>\n <ListItemText primary={t('signOut')} />\n </MenuItem>\n )}\n </Menu>\n </>\n );\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AccountMenu.js","sources":["../../src/appShell/AccountMenu.jsx"],"sourcesContent":["// La cuenta de quien está dentro, arriba a la derecha (como en las plantillas de MUI): un avatar con sus iniciales (o su\n// foto) que abre un menú con su nombre y correo, Mi perfil, lo que el proyecto agregue (accountMenuItems: Facturación,\n// Mis llaves…) y Salir.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaAccountMenu con defaultProps y\n// styleOverrides de sus partes: button, avatar, header, name, settings.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useState} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Avatar from '@mui/material/Avatar';\nimport Box from '@mui/material/Box';\nimport Divider from '@mui/material/Divider';\nimport IconButton from '@mui/material/IconButton';\nimport ListItemIcon from '@mui/material/ListItemIcon';\nimport ListItemText from '@mui/material/ListItemText';\nimport Menu from '@mui/material/Menu';\nimport MenuItem from '@mui/material/MenuItem';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\nimport LogoutIcon from '@mui/icons-material/Logout';\nimport PersonOutlineIcon from '@mui/icons-material/PersonOutline';\n\nimport {initialsOf} from '@/appShell/menuItemText.js';\nimport {barMenuPlacementOf} from '@/appShell/barMenuPlacement.js';\nimport MenuLinks from '@/appShell/MenuLinks.jsx';\nimport {MONOGRAM_GRAY, WHITE_LABEL} from '@/theme/components/glassComponents.js';\nimport {isGlassTheme} from '@/theme/glassSurface.js';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaAccountMenu)\nconst THEME_NAME = 'CalcitaAccountMenu';\nconst AccountButton = piecePart(THEME_NAME, 'Button', IconButton);\nconst AccountAvatar = piecePart(THEME_NAME, 'Avatar', Avatar);\nconst AccountHeader = piecePart(THEME_NAME, 'Header', Box);\nconst AccountName = piecePart(THEME_NAME, 'Name', Typography);\nconst AccountSettings = piecePart(THEME_NAME, 'Settings', Box);\n\n/**\n * @param {object} props\n * @param {{name: string, email?: string, subtitle?: string, avatarUrl?: string}} props.user\n * @param {string} [props.profilePath] sin ella no sale «Mi perfil»\n * @param {Array<{to?: string, onClick?: Function, label?: string, labelKey?: string, Icon?: import('react').ElementType}>} [props.accountMenuItems]\n * @param {() => void} [props.onSignOut] sin él no sale «Salir»\n * @param {boolean} [props.isSigningOut]\n * @param {import('react').ReactNode} [props.settings] los ajustes de la app, entre los datos de la persona y sus ligas\n */\nexport default function AccountMenu(props) {\n // lo que el proyecto puso en su tema (components.CalcitaAccountMenu.defaultProps) y encima lo que llega aquí\n const {user, profilePath, accountMenuItems = [], onSignOut, isSigningOut = false, settings, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('layout');\n const [anchorElement, setAnchorElement] = useState(null);\n const closeMenu = () => setAnchorElement(null);\n const menuLinks = [\n ...(profilePath ? [{to: profilePath, labelKey: 'layout:account.myProfile', Icon: PersonOutlineIcon}] : []),\n ...accountMenuItems,\n ];\n\n // hacia arriba si la barra está abajo (teléfono con vidrio)\n const placement = barMenuPlacementOf(anchorElement);\n\n const signOut = () => {\n closeMenu();\n onSignOut();\n };\n\n return (\n <>\n <Tooltip title={t('account.open')}>\n <AccountButton size=\"small\" aria-label={t('account.open')} aria-haspopup=\"menu\" onClick={(event) => setAnchorElement(event.currentTarget)} ownSx={{p: 0.5}}>\n <AccountAvatar src={user.avatarUrl} alt=\"\" ownSx={(theme) => ({\n width: 32, height: 32, fontSize: '0.875rem', bgcolor: 'secondary.main', color: 'secondary.contrastText',\n // con vidrio, en oscuro el monograma de Apple (gris oscuro con letra blanca), el que se aprobó. Antes lo\n // ponía el tema porque su regla de oscuro le ganaba a este sx; ahora el sx gana en los dos modos\n ...(isGlassTheme(theme) && theme.applyStyles('dark', {bgcolor: MONOGRAM_GRAY.dark, color: WHITE_LABEL})),\n })}>\n {initialsOf(user.name)}\n </AccountAvatar>\n </AccountButton>\n </Tooltip>\n <Menu anchorEl={anchorElement} open={Boolean(anchorElement)} onClose={closeMenu}\n anchorOrigin={placement.anchorOrigin} transformOrigin={placement.transformOrigin}\n slotProps={{paper: {sx: {minWidth: settings ? 300 : 240, maxWidth: 360, ...placement.gapSx}}}}>\n <AccountHeader ownSx={{px: 2, py: 1.25}}>\n <AccountName variant=\"subtitle2\" noWrap ownSx={{fontWeight: 600}}>{user.name}</AccountName>\n {user.email && <Typography variant=\"body2\" color=\"text.secondary\" noWrap>{user.email}</Typography>}\n {user.subtitle && <Typography variant=\"caption\" color=\"text.secondary\" component=\"p\" noWrap>{user.subtitle}</Typography>}\n </AccountHeader>\n {/* los ajustes de la app (letra, idioma, claro u oscuro y los del proyecto): en la cuenta y no sueltos en la barra */}\n {settings && <Divider />}\n {settings && <AccountSettings ownSx={{py: 0.5}}>{settings}</AccountSettings>}\n {menuLinks.length > 0 && <Divider />}\n <MenuLinks links={menuLinks} onClose={closeMenu} />\n {onSignOut && <Divider />}\n {onSignOut && (\n <MenuItem onClick={signOut} disabled={isSigningOut}>\n <ListItemIcon><LogoutIcon fontSize=\"small\" /></ListItemIcon>\n <ListItemText primary={t('signOut')} />\n </MenuItem>\n )}\n </Menu>\n </>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -38,6 +38,7 @@ import { isGlassTheme, ambientBackgroundOf, scrollEdgeStylesOf, PANEL_RADIUS } f
|
|
|
38
38
|
import GlassLensFilter from "../ui/layout/GlassLensFilter.js";
|
|
39
39
|
import { useAppBarHeightPublisher, APP_BAR_HEIGHT } from "../ui/layout/appBarHeight.js";
|
|
40
40
|
import { piecePart, usePieceProps } from "../theme/themePieces.js";
|
|
41
|
+
import { warnUnknownProps } from "../toolkit/unknownProps.js";
|
|
41
42
|
const THEME_NAME = "CalcitaAppLayout";
|
|
42
43
|
const LayoutSkipLink = piecePart(THEME_NAME, "SkipLink", Link);
|
|
43
44
|
const LayoutBrand = piecePart(THEME_NAME, "Brand", ButtonBase);
|
|
@@ -503,8 +504,10 @@ const AppLayout = (props) => {
|
|
|
503
504
|
onMobileMenuChange,
|
|
504
505
|
onMobileTabsChange,
|
|
505
506
|
texts,
|
|
506
|
-
children
|
|
507
|
+
children,
|
|
508
|
+
...unknownProps
|
|
507
509
|
} = usePieceProps(props, THEME_NAME);
|
|
510
|
+
warnUnknownProps(THEME_NAME, unknownProps);
|
|
508
511
|
const { appName } = useToolkitSettings();
|
|
509
512
|
const shownMenuItems = useMemo(() => menuItemsWithIconsOf(menuItems), [menuItems]);
|
|
510
513
|
const appMenu = useMemo(() => ({ menuItems: shownMenuItems }), [shownMenuItems]);
|