@stackcraftmx/calcita 0.52.0 → 0.53.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 +53 -4
- package/dist/datePickers/DateInput.js +5 -3
- package/dist/datePickers/DateInput.js.map +1 -1
- package/dist/datePickers/DateTimeInput.js +6 -4
- package/dist/datePickers/DateTimeInput.js.map +1 -1
- package/dist/datePickers/FormDateField.js +1 -1
- package/dist/datePickers/FormDateField.js.map +1 -1
- package/dist/datePickers/FormDateTimeField.js +1 -1
- package/dist/datePickers/FormDateTimeField.js.map +1 -1
- package/dist/datePickers/FormMonthField.js +1 -1
- package/dist/datePickers/FormMonthField.js.map +1 -1
- package/dist/datePickers/FormTimeField.js +1 -1
- package/dist/datePickers/FormTimeField.js.map +1 -1
- package/dist/datePickers/MonthInput.js +5 -3
- package/dist/datePickers/MonthInput.js.map +1 -1
- package/dist/datePickers/PickerFrame.js +2 -2
- package/dist/datePickers/PickerFrame.js.map +1 -1
- package/dist/datePickers/TimeInput.js +6 -4
- package/dist/datePickers/TimeInput.js.map +1 -1
- package/dist/feedback/Toaster.js +11 -2
- package/dist/feedback/Toaster.js.map +1 -1
- package/dist/forms/CalcitaFormik.js +11 -0
- package/dist/forms/CalcitaFormik.js.map +1 -0
- package/dist/forms/FormAttachmentsField.js +1 -1
- package/dist/forms/FormAttachmentsField.js.map +1 -1
- package/dist/forms/FormCatalogField.js +1 -1
- package/dist/forms/FormCatalogField.js.map +1 -1
- package/dist/forms/FormCheckboxGroupField.js +1 -1
- package/dist/forms/FormCheckboxGroupField.js.map +1 -1
- package/dist/forms/FormColorField.js +1 -1
- package/dist/forms/FormColorField.js.map +1 -1
- package/dist/forms/FormFileField.js +1 -1
- package/dist/forms/FormFileField.js.map +1 -1
- package/dist/forms/FormFileUploadField.js +1 -1
- package/dist/forms/FormFileUploadField.js.map +1 -1
- package/dist/forms/FormImageField.js +1 -1
- package/dist/forms/FormImageField.js.map +1 -1
- package/dist/forms/FormMaskedField.js +1 -1
- package/dist/forms/FormMaskedField.js.map +1 -1
- package/dist/forms/FormNumberField.js +1 -1
- package/dist/forms/FormNumberField.js.map +1 -1
- package/dist/forms/FormSchemaProvider.js +17 -0
- package/dist/forms/FormSchemaProvider.js.map +1 -0
- package/dist/forms/FormSelectField.js +1 -1
- package/dist/forms/FormSelectField.js.map +1 -1
- package/dist/forms/FormTextField.js +1 -1
- package/dist/forms/FormTextField.js.map +1 -1
- package/dist/forms/FormTransferListField.js +1 -1
- package/dist/forms/FormTransferListField.js.map +1 -1
- package/dist/forms/FormWizard.js +2 -0
- package/dist/forms/FormWizard.js.map +1 -1
- package/dist/forms/schemaRequired.js +33 -0
- package/dist/forms/schemaRequired.js.map +1 -0
- package/dist/forms/useFormikField.js +18 -5
- package/dist/forms/useFormikField.js.map +1 -1
- package/dist/forms.js +52 -46
- package/dist/forms.js.map +1 -1
- package/dist/hookForm/FormAttachmentsField.js +1 -1
- package/dist/hookForm/FormAttachmentsField.js.map +1 -1
- package/dist/hookForm/FormCatalogField.js +1 -1
- package/dist/hookForm/FormCatalogField.js.map +1 -1
- package/dist/hookForm/FormCheckboxGroupField.js +1 -1
- package/dist/hookForm/FormCheckboxGroupField.js.map +1 -1
- package/dist/hookForm/FormColorField.js +1 -1
- package/dist/hookForm/FormColorField.js.map +1 -1
- package/dist/hookForm/FormFileField.js +1 -1
- package/dist/hookForm/FormFileField.js.map +1 -1
- package/dist/hookForm/FormFileUploadField.js +1 -1
- package/dist/hookForm/FormFileUploadField.js.map +1 -1
- package/dist/hookForm/FormImageField.js +1 -1
- package/dist/hookForm/FormImageField.js.map +1 -1
- package/dist/hookForm/FormMaskedField.js +1 -1
- package/dist/hookForm/FormMaskedField.js.map +1 -1
- package/dist/hookForm/FormNumberField.js +1 -1
- package/dist/hookForm/FormNumberField.js.map +1 -1
- package/dist/hookForm/FormSelectField.js +1 -1
- package/dist/hookForm/FormSelectField.js.map +1 -1
- package/dist/hookForm/FormTextField.js +1 -1
- package/dist/hookForm/FormTextField.js.map +1 -1
- package/dist/hookForm/FormTransferListField.js +1 -1
- package/dist/hookForm/FormTransferListField.js.map +1 -1
- package/dist/hookForm/FormWizard.js +2 -0
- package/dist/hookForm/FormWizard.js.map +1 -1
- package/dist/hookForm/useHookFormField.js +9 -3
- package/dist/hookForm/useHookFormField.js.map +1 -1
- package/dist/index.js +4 -2
- package/dist/inputs/CatalogInput.js +3 -2
- package/dist/inputs/CatalogInput.js.map +1 -1
- package/dist/inputs/CheckboxGroupInput.js +2 -1
- package/dist/inputs/CheckboxGroupInput.js.map +1 -1
- package/dist/inputs/ColorInput.js +3 -1
- package/dist/inputs/ColorInput.js.map +1 -1
- package/dist/inputs/FieldFrame.js +18 -3
- package/dist/inputs/FieldFrame.js.map +1 -1
- package/dist/inputs/FormSection.js +42 -11
- package/dist/inputs/FormSection.js.map +1 -1
- package/dist/inputs/NumberInput.js +3 -1
- package/dist/inputs/NumberInput.js.map +1 -1
- package/dist/inputs/SelectInput.js +3 -1
- package/dist/inputs/SelectInput.js.map +1 -1
- package/dist/inputs/TextInput.js +1 -1
- package/dist/inputs/TextInput.js.map +1 -1
- package/dist/inputs/TransferListInput.js +2 -1
- package/dist/inputs/TransferListInput.js.map +1 -1
- package/dist/inputs/WizardLayout.js +12 -6
- package/dist/inputs/WizardLayout.js.map +1 -1
- package/dist/inputs/formLayoutContext.js +7 -2
- package/dist/inputs/formLayoutContext.js.map +1 -1
- package/dist/inputs/requiredMark.js +17 -0
- package/dist/inputs/requiredMark.js.map +1 -0
- package/dist/locales/en.js +1 -0
- package/dist/locales/en.js.map +1 -1
- package/dist/locales/es.js +1 -0
- package/dist/locales/es.js.map +1 -1
- package/dist/richText/FormRichTextField.js +1 -1
- package/dist/richText/FormRichTextField.js.map +1 -1
- package/dist/richText/RichTextEditor.js +4 -3
- package/dist/richText/RichTextEditor.js.map +1 -1
- package/dist/toolkit/ToolkitProvider.js +3 -0
- package/dist/toolkit/ToolkitProvider.js.map +1 -1
- package/dist/toolkit/toolkitContext.js.map +1 -1
- package/dist/types/datePickers/DateInput.d.ts +2 -0
- package/dist/types/datePickers/DateTimeInput.d.ts +2 -0
- package/dist/types/datePickers/FormDateField.d.ts +3 -3
- package/dist/types/datePickers/FormDateTimeField.d.ts +3 -3
- package/dist/types/datePickers/FormMonthField.d.ts +3 -3
- package/dist/types/datePickers/FormTimeField.d.ts +3 -3
- package/dist/types/datePickers/MonthInput.d.ts +2 -0
- package/dist/types/datePickers/PickerFrame.d.ts +3 -1
- package/dist/types/datePickers/TimeInput.d.ts +2 -0
- package/dist/types/feedback/Toaster.d.ts +15 -1
- package/dist/types/feedback/index.d.ts +1 -1
- package/dist/types/forms/CalcitaFormik.d.ts +6 -0
- package/dist/types/forms/FormAttachmentsField.d.ts +3 -3
- package/dist/types/forms/FormCatalogField.d.ts +2 -2
- package/dist/types/forms/FormCheckboxGroupField.d.ts +3 -3
- package/dist/types/forms/FormColorField.d.ts +2 -2
- package/dist/types/forms/FormFileField.d.ts +3 -3
- package/dist/types/forms/FormFileUploadField.d.ts +3 -3
- package/dist/types/forms/FormImageField.d.ts +3 -3
- package/dist/types/forms/FormMaskedField.d.ts +2 -2
- package/dist/types/forms/FormNumberField.d.ts +2 -2
- package/dist/types/forms/FormSchemaProvider.d.ts +13 -0
- package/dist/types/forms/FormSelectField.d.ts +2 -2
- package/dist/types/forms/FormTextField.d.ts +2 -2
- package/dist/types/forms/FormTransferListField.d.ts +3 -3
- package/dist/types/forms/FormWizard.d.ts +3 -1
- package/dist/types/forms/index.d.ts +1 -0
- package/dist/types/forms/schemaRequired.d.ts +14 -0
- package/dist/types/forms/useFormikField.d.ts +10 -4
- package/dist/types/forms.d.ts +4 -2
- package/dist/types/hookForm/FormAttachmentsField.d.ts +3 -3
- package/dist/types/hookForm/FormCatalogField.d.ts +3 -3
- package/dist/types/hookForm/FormCheckboxGroupField.d.ts +3 -3
- package/dist/types/hookForm/FormColorField.d.ts +3 -3
- package/dist/types/hookForm/FormFileField.d.ts +3 -3
- package/dist/types/hookForm/FormFileUploadField.d.ts +3 -3
- package/dist/types/hookForm/FormImageField.d.ts +3 -3
- package/dist/types/hookForm/FormMaskedField.d.ts +3 -3
- package/dist/types/hookForm/FormNumberField.d.ts +3 -3
- package/dist/types/hookForm/FormSelectField.d.ts +3 -3
- package/dist/types/hookForm/FormTextField.d.ts +3 -3
- package/dist/types/hookForm/FormTransferListField.d.ts +3 -3
- package/dist/types/hookForm/FormWizard.d.ts +3 -1
- package/dist/types/hookForm/useHookFormField.d.ts +8 -4
- package/dist/types/index.d.ts +2 -2
- package/dist/types/inputs/CatalogInput.d.ts +1 -0
- package/dist/types/inputs/CheckboxGroupInput.d.ts +1 -0
- package/dist/types/inputs/ColorInput.d.ts +1 -0
- package/dist/types/inputs/FieldFrame.d.ts +1 -0
- package/dist/types/inputs/FormSection.d.ts +13 -0
- package/dist/types/inputs/NumberInput.d.ts +1 -0
- package/dist/types/inputs/SelectInput.d.ts +1 -0
- package/dist/types/inputs/TextInput.d.ts +1 -1
- package/dist/types/inputs/TransferListInput.d.ts +1 -0
- package/dist/types/inputs/WizardLayout.d.ts +1 -0
- package/dist/types/inputs/formLayoutContext.d.ts +8 -1
- package/dist/types/inputs/requiredMark.d.ts +9 -0
- package/dist/types/locales/en.d.ts +1 -0
- package/dist/types/locales/es.d.ts +1 -0
- package/dist/types/richText/FormRichTextField.d.ts +3 -3
- package/dist/types/richText/RichTextEditor.d.ts +1 -0
- package/dist/types/toolkit/ToolkitProvider.d.ts +5 -1
- package/dist/types/toolkit/toolkitContext.d.ts +2 -1
- package/dist/types/upload/AttachmentsInput.d.ts +2 -0
- package/dist/types/upload/FileInput.d.ts +1 -0
- package/dist/types/upload/FileUploadInput.d.ts +1 -0
- package/dist/types/upload/ImageInput.d.ts +1 -0
- package/dist/upload/AttachmentsInput.js +2 -1
- package/dist/upload/AttachmentsInput.js.map +1 -1
- package/dist/upload/FileInput.js +2 -1
- package/dist/upload/FileInput.js.map +1 -1
- package/dist/upload/FileUploadInput.js +2 -1
- package/dist/upload/FileUploadInput.js.map +1 -1
- package/dist/upload/ImageInput.js +2 -1
- package/dist/upload/ImageInput.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TransferListInput.js","sources":["../../src/inputs/TransferListInput.jsx"],"sourcesContent":["// La lista de transferencia: dos columnas, «Disponibles» y «Elegidos», y botones para pasar de una a otra. Para elegir\n// muchos de una lista larga viendo siempre qué quedó de cada lado (los usuarios que pueden ver un reporte, las sucursales donde\n// puede comprar un cliente). Al formulario llega la lista de los elegidos, en el orden en que se pasaron.\n//\n// Cada columna trae su título con cuántos tiene, su buscador (searchable) y su casilla de «todos los que se ven» (con algo\n// buscado, solo esos). Se marcan los que se quieren pasar (clic o espacio) y se pasan con ›; » pasa todos los de la\n// columna. Doble clic pasa uno directo. En el teléfono las columnas van una debajo de otra y los botones apuntan hacia\n// abajo y arriba. Va fuera de una FormSection: necesita el ancho completo.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaTransferListInput con defaultProps y\n// styleOverrides de sus partes: root, list, actions.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useId, useState} from 'react';\nimport Button from '@mui/material/Button';\nimport Checkbox from '@mui/material/Checkbox';\nimport FormHelperText from '@mui/material/FormHelperText';\nimport List from '@mui/material/List';\nimport ListItemButton from '@mui/material/ListItemButton';\nimport ListItemIcon from '@mui/material/ListItemIcon';\nimport ListItemText from '@mui/material/ListItemText';\nimport Paper from '@mui/material/Paper';\nimport Stack from '@mui/material/Stack';\nimport TextField from '@mui/material/TextField';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\nimport ChevronLeftRoundedIcon from '@mui/icons-material/ChevronLeftRounded';\nimport ChevronRightRoundedIcon from '@mui/icons-material/ChevronRightRounded';\nimport KeyboardDoubleArrowLeftRoundedIcon from '@mui/icons-material/KeyboardDoubleArrowLeftRounded';\nimport KeyboardDoubleArrowRightRoundedIcon from '@mui/icons-material/KeyboardDoubleArrowRightRounded';\n\nimport {useValidationText} from '@/forms/useValidationText.js';\nimport FieldFrame from '@/inputs/FieldFrame.jsx';\nimport {selectAllStateOf} from '@/inputs/selectAllState.js';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// lo alto de cada columna antes de deslizar\nconst DEFAULT_LIST_HEIGHT = 280;\n// en el teléfono los botones apuntan hacia abajo (pasar) y hacia arriba (regresar)\nconst PHONE_ROTATION = Object.freeze({transform: {xs: 'rotate(90deg)', md: 'none'}});\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaTransferListInput)\nconst THEME_NAME = 'CalcitaTransferListInput';\nconst TransferRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst TransferList = piecePart(THEME_NAME, 'List', Paper);\nconst TransferActions = piecePart(THEME_NAME, 'Actions', Stack);\n\n/**\n * Un texto sin acentos ni mayúsculas, para que «queretaro» encuentre «Querétaro».\n *\n * @param {unknown} text\n * @returns {string}\n */\nfunction plainTextOf(text) {\n return String(text ?? '').normalize('NFD').replace(/[̀-ͯ]/g, '').toLowerCase().trim();\n}\n\n/**\n * Una columna: su título con cuántos tiene, su buscador, su casilla de «todos los que se ven» y sus renglones.\n *\n * @param {object} props\n */\nfunction TransferColumn({title, items, markedValues, onMark, onMarkMany, onMoveOne, searchable, searchLabel, emptyText, listHeight, disabled, t}) {\n const titleId = useId();\n const [searchText, setSearchText] = useState('');\n const wantedText = plainTextOf(searchText);\n const visibleItems = wantedText\n ? items.filter((item) => plainTextOf(`${item.label} ${item.description ?? ''}`).includes(wantedText))\n : items;\n const visibleValues = visibleItems.filter((item) => !item.disabled).map((item) => item.value);\n const markState = selectAllStateOf(markedValues, visibleValues);\n\n return (\n <TransferList variant=\"outlined\" ownSx={{flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column'}}>\n <Stack direction=\"row\" sx={{alignItems: 'center', gap: 1, px: 1.5, py: 1, borderBottom: 1, borderColor: 'divider'}}>\n <Checkbox size=\"small\" sx={{p: 0.5}} disabled={disabled || visibleValues.length === 0}\n checked={markState.allChosen} indeterminate={markState.someChosen}\n onChange={() => onMarkMany(markState.toggled())}\n slotProps={{input: {'aria-label': t('transfer.markVisible', {list: title})}}} />\n <Typography id={titleId} variant=\"subtitle2\" sx={{flexGrow: 1}}>{title}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {markedValues.length > 0 ? t('transfer.markedOf', {marked: markedValues.length, count: items.length}) : items.length}\n </Typography>\n </Stack>\n {searchable && (\n <TextField size=\"small\" type=\"search\" value={searchText} onChange={(event) => setSearchText(event.target.value)}\n placeholder={searchLabel} disabled={disabled} sx={{m: 1}}\n slotProps={{htmlInput: {'aria-label': `${searchLabel} · ${title}`}}} />\n )}\n <List dense role=\"listbox\" aria-labelledby={titleId} aria-multiselectable=\"true\"\n sx={{height: listHeight, overflowY: 'auto', py: 0}}>\n {visibleItems.length === 0 && (\n // vacía de verdad o vacía por lo buscado: no es lo mismo y se dice distinto\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{px: 2, py: 1.5}}>\n {items.length > 0 ? t('transfer.noMatches', {text: searchText.trim()}) : emptyText}\n </Typography>\n )}\n {visibleItems.map((item) => {\n const isMarked = markedValues.includes(item.value);\n return (\n <ListItemButton key={item.value} role=\"option\" aria-selected={isMarked} disabled={disabled || item.disabled}\n onClick={() => onMark(item.value)} onDoubleClick={() => onMoveOne(item.value)} sx={{py: 0.25}}>\n <ListItemIcon sx={{minWidth: 32}}>\n <Checkbox size=\"small\" edge=\"start\" tabIndex={-1} disableRipple checked={isMarked} sx={{p: 0.5}} />\n </ListItemIcon>\n <ListItemText primary={item.label} secondary={item.description} />\n </ListItemButton>\n );\n })}\n </List>\n </TransferList>\n );\n}\n\n/**\n * @param {object} props\n * @param {string} [props.name]\n * @param {import('react').ReactNode} [props.label] ya traducida\n * @param {Array<string|number>|null|undefined} props.value los elegidos\n * @param {(values: Array<string|number>) => void} props.onChange\n * @param {() => void} [props.onBlur]\n * @param {Array<{value: string|number, label: string, description?: string, disabled?: boolean}>} props.options todos\n * @param {string} [props.availableTitle] ya traducido; por omisión «Disponibles»\n * @param {string} [props.chosenTitle] ya traducido; por omisión «Elegidos»\n * @param {boolean} [props.searchable] un buscador en cada columna (por omisión, con más de 8 opciones)\n * @param {number} [props.listHeight] lo alto de cada columna, en px\n * @param {string|{key: string, values?: object}} [props.error]\n * @param {string} [props.helperText] ya traducida\n * @param {boolean} [props.disabled]\n * @param {object} [props.sx]\n * @param {Record<string, string|object>} [props.messages] el texto del error de este campo, por regla de validación\n * ({required: 'Escriba el RFC', matches: 'El RFC lleva 12 o 13 caracteres'}): gana al de Calcita y al de los textos\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nfunction TransferListInputContent(props) {\n const {\n name, label, value, onChange, onBlur, options, availableTitle, chosenTitle, searchable, listHeight = DEFAULT_LIST_HEIGHT, error,\n helperText = ' ', disabled = false, sx, messages, texts,\n ...unknownProps\n } = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n // el texto del error: el de la pantalla (messages), el del proyecto para este campo o el de Calcita\n const validationTextOf = useValidationText({name, label, messages});\n const generatedId = useId();\n const inputId = `${name ?? 'transfer'}-${generatedId}`;\n const errorText = validationTextOf(error);\n const chosenValues = Array.isArray(value) ? value : [];\n // lo marcado para pasar, de cada lado\n const [markedAvailable, setMarkedAvailable] = useState([]);\n const [markedChosen, setMarkedChosen] = useState([]);\n const available = options.filter((option) => !chosenValues.includes(option.value));\n // los elegidos en el orden en que se pasaron\n const chosen = chosenValues.map((chosenValue) => options.find((option) => option.value === chosenValue)).filter(Boolean);\n const isSearchable = searchable ?? options.length > 8;\n const titles = {available: availableTitle ?? t('transfer.available'), chosen: chosenTitle ?? t('transfer.chosen')};\n\n const change = (values) => {\n onChange(values);\n onBlur?.();\n };\n const toggleIn = (setMarked) => (itemValue) => setMarked((current) => (\n current.includes(itemValue) ? current.filter((markedValue) => markedValue !== itemValue) : [...current, itemValue]\n ));\n const moveToChosen = (values) => {\n change([...chosenValues, ...values.filter((itemValue) => !chosenValues.includes(itemValue))]);\n setMarkedAvailable((current) => current.filter((markedValue) => !values.includes(markedValue)));\n };\n const moveToAvailable = (values) => {\n change(chosenValues.filter((chosenValue) => !values.includes(chosenValue)));\n setMarkedChosen((current) => current.filter((markedValue) => !values.includes(markedValue)));\n };\n const movableOf = (items) => items.filter((item) => !item.disabled).map((item) => item.value);\n const actionButton = (titleKey, Icon, onClick, isDisabled) => (\n <Tooltip title={t(titleKey)}>\n <span>\n <Button variant=\"outlined\" size=\"small\" aria-label={t(titleKey)} disabled={disabled || isDisabled} onClick={onClick}\n sx={{minWidth: 40, px: 1}}>\n <Icon fontSize=\"small\" sx={PHONE_ROTATION} />\n </Button>\n </span>\n </Tooltip>\n );\n\n const lists = (\n <TransferRoot direction={{xs: 'column', md: 'row'}} ownSx={{gap: 1.5, alignItems: 'stretch'}} sx={sx} id={inputId}>\n <TransferColumn title={titles.available} items={available} markedValues={markedAvailable}\n onMark={toggleIn(setMarkedAvailable)} onMarkMany={setMarkedAvailable} onMoveOne={(itemValue) => moveToChosen([itemValue])}\n searchable={isSearchable} searchLabel={t('transfer.search')} emptyText={t('transfer.emptyAvailable')}\n listHeight={listHeight} disabled={disabled} t={t} />\n <TransferActions direction={{xs: 'row', md: 'column'}} ownSx={{gap: 1, justifyContent: 'center', alignItems: 'center'}}>\n {actionButton('transfer.moveMarked', ChevronRightRoundedIcon, () => moveToChosen(markedAvailable), markedAvailable.length === 0)}\n {actionButton('transfer.moveAll', KeyboardDoubleArrowRightRoundedIcon, () => moveToChosen(movableOf(available)), movableOf(available).length === 0)}\n {actionButton('transfer.returnMarked', ChevronLeftRoundedIcon, () => moveToAvailable(markedChosen), markedChosen.length === 0)}\n {actionButton('transfer.returnAll', KeyboardDoubleArrowLeftRoundedIcon, () => moveToAvailable(movableOf(chosen)), movableOf(chosen).length === 0)}\n </TransferActions>\n <TransferColumn title={titles.chosen} items={chosen} markedValues={markedChosen}\n onMark={toggleIn(setMarkedChosen)} onMarkMany={setMarkedChosen} onMoveOne={(itemValue) => moveToAvailable([itemValue])}\n searchable={isSearchable} searchLabel={t('transfer.search')} emptyText={t('transfer.emptyChosen')}\n listHeight={listHeight} disabled={disabled} t={t} />\n </TransferRoot>\n );\n\n const field = (\n <div>\n {lists}\n <FormHelperText error={Boolean(errorText)} role={errorText ? 'alert' : undefined}>{errorText ?? helperText}</FormHelperText>\n </div>\n );\n // sin etiqueta va solo (la pantalla pone el título a su manera)\n return label ? <FieldFrame inputId={inputId} label={label}>{field}</FieldFrame> : field;\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst TransferListInput = withPieceSlots(TransferListInputContent, THEME_NAME);\nexport default TransferListInput;\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TransferListInput.js","sources":["../../src/inputs/TransferListInput.jsx"],"sourcesContent":["// La lista de transferencia: dos columnas, «Disponibles» y «Elegidos», y botones para pasar de una a otra. Para elegir\n// muchos de una lista larga viendo siempre qué quedó de cada lado (los usuarios que pueden ver un reporte, las sucursales donde\n// puede comprar un cliente). Al formulario llega la lista de los elegidos, en el orden en que se pasaron.\n//\n// Cada columna trae su título con cuántos tiene, su buscador (searchable) y su casilla de «todos los que se ven» (con algo\n// buscado, solo esos). Se marcan los que se quieren pasar (clic o espacio) y se pasan con ›; » pasa todos los de la\n// columna. Doble clic pasa uno directo. En el teléfono las columnas van una debajo de otra y los botones apuntan hacia\n// abajo y arriba. Va fuera de una FormSection: necesita el ancho completo.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaTransferListInput con defaultProps y\n// styleOverrides de sus partes: root, list, actions.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useId, useState} from 'react';\nimport Button from '@mui/material/Button';\nimport Checkbox from '@mui/material/Checkbox';\nimport FormHelperText from '@mui/material/FormHelperText';\nimport List from '@mui/material/List';\nimport ListItemButton from '@mui/material/ListItemButton';\nimport ListItemIcon from '@mui/material/ListItemIcon';\nimport ListItemText from '@mui/material/ListItemText';\nimport Paper from '@mui/material/Paper';\nimport Stack from '@mui/material/Stack';\nimport TextField from '@mui/material/TextField';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\nimport ChevronLeftRoundedIcon from '@mui/icons-material/ChevronLeftRounded';\nimport ChevronRightRoundedIcon from '@mui/icons-material/ChevronRightRounded';\nimport KeyboardDoubleArrowLeftRoundedIcon from '@mui/icons-material/KeyboardDoubleArrowLeftRounded';\nimport KeyboardDoubleArrowRightRoundedIcon from '@mui/icons-material/KeyboardDoubleArrowRightRounded';\n\nimport {useValidationText} from '@/forms/useValidationText.js';\nimport FieldFrame from '@/inputs/FieldFrame.jsx';\nimport {selectAllStateOf} from '@/inputs/selectAllState.js';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// lo alto de cada columna antes de deslizar\nconst DEFAULT_LIST_HEIGHT = 280;\n// en el teléfono los botones apuntan hacia abajo (pasar) y hacia arriba (regresar)\nconst PHONE_ROTATION = Object.freeze({transform: {xs: 'rotate(90deg)', md: 'none'}});\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaTransferListInput)\nconst THEME_NAME = 'CalcitaTransferListInput';\nconst TransferRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst TransferList = piecePart(THEME_NAME, 'List', Paper);\nconst TransferActions = piecePart(THEME_NAME, 'Actions', Stack);\n\n/**\n * Un texto sin acentos ni mayúsculas, para que «queretaro» encuentre «Querétaro».\n *\n * @param {unknown} text\n * @returns {string}\n */\nfunction plainTextOf(text) {\n return String(text ?? '').normalize('NFD').replace(/[̀-ͯ]/g, '').toLowerCase().trim();\n}\n\n/**\n * Una columna: su título con cuántos tiene, su buscador, su casilla de «todos los que se ven» y sus renglones.\n *\n * @param {object} props\n */\nfunction TransferColumn({title, items, markedValues, onMark, onMarkMany, onMoveOne, searchable, searchLabel, emptyText, listHeight, disabled, t}) {\n const titleId = useId();\n const [searchText, setSearchText] = useState('');\n const wantedText = plainTextOf(searchText);\n const visibleItems = wantedText\n ? items.filter((item) => plainTextOf(`${item.label} ${item.description ?? ''}`).includes(wantedText))\n : items;\n const visibleValues = visibleItems.filter((item) => !item.disabled).map((item) => item.value);\n const markState = selectAllStateOf(markedValues, visibleValues);\n\n return (\n <TransferList variant=\"outlined\" ownSx={{flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column'}}>\n <Stack direction=\"row\" sx={{alignItems: 'center', gap: 1, px: 1.5, py: 1, borderBottom: 1, borderColor: 'divider'}}>\n <Checkbox size=\"small\" sx={{p: 0.5}} disabled={disabled || visibleValues.length === 0}\n checked={markState.allChosen} indeterminate={markState.someChosen}\n onChange={() => onMarkMany(markState.toggled())}\n slotProps={{input: {'aria-label': t('transfer.markVisible', {list: title})}}} />\n <Typography id={titleId} variant=\"subtitle2\" sx={{flexGrow: 1}}>{title}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {markedValues.length > 0 ? t('transfer.markedOf', {marked: markedValues.length, count: items.length}) : items.length}\n </Typography>\n </Stack>\n {searchable && (\n <TextField size=\"small\" type=\"search\" value={searchText} onChange={(event) => setSearchText(event.target.value)}\n placeholder={searchLabel} disabled={disabled} sx={{m: 1}}\n slotProps={{htmlInput: {'aria-label': `${searchLabel} · ${title}`}}} />\n )}\n <List dense role=\"listbox\" aria-labelledby={titleId} aria-multiselectable=\"true\"\n sx={{height: listHeight, overflowY: 'auto', py: 0}}>\n {visibleItems.length === 0 && (\n // vacía de verdad o vacía por lo buscado: no es lo mismo y se dice distinto\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{px: 2, py: 1.5}}>\n {items.length > 0 ? t('transfer.noMatches', {text: searchText.trim()}) : emptyText}\n </Typography>\n )}\n {visibleItems.map((item) => {\n const isMarked = markedValues.includes(item.value);\n return (\n <ListItemButton key={item.value} role=\"option\" aria-selected={isMarked} disabled={disabled || item.disabled}\n onClick={() => onMark(item.value)} onDoubleClick={() => onMoveOne(item.value)} sx={{py: 0.25}}>\n <ListItemIcon sx={{minWidth: 32}}>\n <Checkbox size=\"small\" edge=\"start\" tabIndex={-1} disableRipple checked={isMarked} sx={{p: 0.5}} />\n </ListItemIcon>\n <ListItemText primary={item.label} secondary={item.description} />\n </ListItemButton>\n );\n })}\n </List>\n </TransferList>\n );\n}\n\n/**\n * @param {object} props\n * @param {string} [props.name]\n * @param {import('react').ReactNode} [props.label] ya traducida\n * @param {Array<string|number>|null|undefined} props.value los elegidos\n * @param {(values: Array<string|number>) => void} props.onChange\n * @param {() => void} [props.onBlur]\n * @param {Array<{value: string|number, label: string, description?: string, disabled?: boolean}>} props.options todos\n * @param {string} [props.availableTitle] ya traducido; por omisión «Disponibles»\n * @param {string} [props.chosenTitle] ya traducido; por omisión «Elegidos»\n * @param {boolean} [props.searchable] un buscador en cada columna (por omisión, con más de 8 opciones)\n * @param {number} [props.listHeight] lo alto de cada columna, en px\n * @param {string|{key: string, values?: object}} [props.error]\n * @param {string} [props.helperText] ya traducida\n * @param {boolean} [props.disabled]\n * @param {boolean} [props.required] obligatorio: el asterisco en la etiqueta (lo revisa el esquema del formulario)\n * @param {object} [props.sx]\n * @param {Record<string, string|object>} [props.messages] el texto del error de este campo, por regla de validación\n * ({required: 'Escriba el RFC', matches: 'El RFC lleva 12 o 13 caracteres'}): gana al de Calcita y al de los textos\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nfunction TransferListInputContent(props) {\n const {\n name, label, value, onChange, onBlur, options, availableTitle, chosenTitle, searchable, listHeight = DEFAULT_LIST_HEIGHT, error,\n helperText = ' ', disabled = false, required = false, sx, messages, texts,\n ...unknownProps\n } = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n // el texto del error: el de la pantalla (messages), el del proyecto para este campo o el de Calcita\n const validationTextOf = useValidationText({name, label, messages});\n const generatedId = useId();\n const inputId = `${name ?? 'transfer'}-${generatedId}`;\n const errorText = validationTextOf(error);\n const chosenValues = Array.isArray(value) ? value : [];\n // lo marcado para pasar, de cada lado\n const [markedAvailable, setMarkedAvailable] = useState([]);\n const [markedChosen, setMarkedChosen] = useState([]);\n const available = options.filter((option) => !chosenValues.includes(option.value));\n // los elegidos en el orden en que se pasaron\n const chosen = chosenValues.map((chosenValue) => options.find((option) => option.value === chosenValue)).filter(Boolean);\n const isSearchable = searchable ?? options.length > 8;\n const titles = {available: availableTitle ?? t('transfer.available'), chosen: chosenTitle ?? t('transfer.chosen')};\n\n const change = (values) => {\n onChange(values);\n onBlur?.();\n };\n const toggleIn = (setMarked) => (itemValue) => setMarked((current) => (\n current.includes(itemValue) ? current.filter((markedValue) => markedValue !== itemValue) : [...current, itemValue]\n ));\n const moveToChosen = (values) => {\n change([...chosenValues, ...values.filter((itemValue) => !chosenValues.includes(itemValue))]);\n setMarkedAvailable((current) => current.filter((markedValue) => !values.includes(markedValue)));\n };\n const moveToAvailable = (values) => {\n change(chosenValues.filter((chosenValue) => !values.includes(chosenValue)));\n setMarkedChosen((current) => current.filter((markedValue) => !values.includes(markedValue)));\n };\n const movableOf = (items) => items.filter((item) => !item.disabled).map((item) => item.value);\n const actionButton = (titleKey, Icon, onClick, isDisabled) => (\n <Tooltip title={t(titleKey)}>\n <span>\n <Button variant=\"outlined\" size=\"small\" aria-label={t(titleKey)} disabled={disabled || isDisabled} onClick={onClick}\n sx={{minWidth: 40, px: 1}}>\n <Icon fontSize=\"small\" sx={PHONE_ROTATION} />\n </Button>\n </span>\n </Tooltip>\n );\n\n const lists = (\n <TransferRoot direction={{xs: 'column', md: 'row'}} ownSx={{gap: 1.5, alignItems: 'stretch'}} sx={sx} id={inputId}>\n <TransferColumn title={titles.available} items={available} markedValues={markedAvailable}\n onMark={toggleIn(setMarkedAvailable)} onMarkMany={setMarkedAvailable} onMoveOne={(itemValue) => moveToChosen([itemValue])}\n searchable={isSearchable} searchLabel={t('transfer.search')} emptyText={t('transfer.emptyAvailable')}\n listHeight={listHeight} disabled={disabled} t={t} />\n <TransferActions direction={{xs: 'row', md: 'column'}} ownSx={{gap: 1, justifyContent: 'center', alignItems: 'center'}}>\n {actionButton('transfer.moveMarked', ChevronRightRoundedIcon, () => moveToChosen(markedAvailable), markedAvailable.length === 0)}\n {actionButton('transfer.moveAll', KeyboardDoubleArrowRightRoundedIcon, () => moveToChosen(movableOf(available)), movableOf(available).length === 0)}\n {actionButton('transfer.returnMarked', ChevronLeftRoundedIcon, () => moveToAvailable(markedChosen), markedChosen.length === 0)}\n {actionButton('transfer.returnAll', KeyboardDoubleArrowLeftRoundedIcon, () => moveToAvailable(movableOf(chosen)), movableOf(chosen).length === 0)}\n </TransferActions>\n <TransferColumn title={titles.chosen} items={chosen} markedValues={markedChosen}\n onMark={toggleIn(setMarkedChosen)} onMarkMany={setMarkedChosen} onMoveOne={(itemValue) => moveToAvailable([itemValue])}\n searchable={isSearchable} searchLabel={t('transfer.search')} emptyText={t('transfer.emptyChosen')}\n listHeight={listHeight} disabled={disabled} t={t} />\n </TransferRoot>\n );\n\n const field = (\n <div>\n {lists}\n <FormHelperText error={Boolean(errorText)} role={errorText ? 'alert' : undefined}>{errorText ?? helperText}</FormHelperText>\n </div>\n );\n // sin etiqueta va solo (la pantalla pone el título a su manera)\n return label ? <FieldFrame inputId={inputId} label={label} required={required}>{field}</FieldFrame> : field;\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst TransferListInput = withPieceSlots(TransferListInputContent, THEME_NAME);\nexport default TransferListInput;\n"],"names":[],"mappings":"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"}
|
|
@@ -25,6 +25,7 @@ function WizardLayoutContent(props) {
|
|
|
25
25
|
skippedKeys = NO_SKIPPED_KEYS,
|
|
26
26
|
isSubmitting = false,
|
|
27
27
|
orientation = WIZARD_ORIENTATION.horizontal,
|
|
28
|
+
hideBackOnFirstStep = false,
|
|
28
29
|
onBack,
|
|
29
30
|
onNext,
|
|
30
31
|
onSkip,
|
|
@@ -40,6 +41,7 @@ function WizardLayoutContent(props) {
|
|
|
40
41
|
const isLastStep = activeIndex === steps.length - 1;
|
|
41
42
|
const isVertical = orientation === WIZARD_ORIENTATION.vertical;
|
|
42
43
|
const isSelectable = typeof onStepSelect === "function";
|
|
44
|
+
const isBackHidden = hideBackOnFirstStep && activeIndex === 0;
|
|
43
45
|
const stepTitleOf = (step, index) => {
|
|
44
46
|
let caption;
|
|
45
47
|
if (skippedKeys.has(step.key)) {
|
|
@@ -53,13 +55,17 @@ function WizardLayoutContent(props) {
|
|
|
53
55
|
}
|
|
54
56
|
return /* @__PURE__ */ jsx(StepLabel, { optional, children: step.label });
|
|
55
57
|
};
|
|
56
|
-
const actions =
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
const actions = (
|
|
59
|
+
// sin «Anterior», los de seguir se quedan a la derecha (solos, space-between los mandaba a la izquierda; un margen
|
|
60
|
+
// automático no sirve: Stack les pone margin 0 a sus hijos con más fuerza)
|
|
61
|
+
/* @__PURE__ */ jsxs(WizardActions, { direction: { xs: "column-reverse", sm: "row" }, spacing: 1.5, ownSx: { justifyContent: isBackHidden ? "flex-end" : "space-between" }, children: [
|
|
62
|
+
!isBackHidden && /* @__PURE__ */ jsx(Button, { variant: "text", color: "inherit", disabled: activeIndex === 0 || isSubmitting, onClick: onBack, children: t("wizard.back") }),
|
|
63
|
+
/* @__PURE__ */ jsxs(Stack, { direction: { xs: "column-reverse", sm: "row" }, spacing: 1.5, children: [
|
|
64
|
+
activeStep.optional && !isLastStep && onSkip && /* @__PURE__ */ jsx(Button, { variant: "text", onClick: onSkip, children: t("wizard.skip") }),
|
|
65
|
+
isLastStep ? submitButton : /* @__PURE__ */ jsx(Button, { variant: "contained", size: "large", onClick: onNext, children: t("wizard.next") })
|
|
66
|
+
] })
|
|
61
67
|
] })
|
|
62
|
-
|
|
68
|
+
);
|
|
63
69
|
const completedOf = (step, index) => isStepCompleted(step, { index, activeIndex, skippedKeys, isSelectable });
|
|
64
70
|
if (isVertical) {
|
|
65
71
|
return (
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WizardLayout.js","sources":["../../src/inputs/WizardLayout.jsx"],"sourcesContent":["// Lo que se ve de un formulario por pasos: los pasos, los campos del paso abierto y los botones (Anterior · Omitir este paso ·\n// Siguiente o Enviar). No sabe de formik ni de react-hook-form: el FormWizard de cada uno (/forms y /react-hook-form) pone la\n// lógica (qué revisa «Siguiente», qué hace «Omitir», si se puede saltar a otro paso) y le pasa su botón de enviar y su aviso de\n// errores. Suelto sirve para armar un asistente propio con otra librería.\n//\n// Dos acomodos (WIZARD_ORIENTATION):\n// horizontal los pasos en fila arriba y los campos abajo; en el teléfono no caben los nombres: «Paso 2 de 4» y su nombre;\n// vertical uno debajo del otro, como un acordeón: los campos y los botones van dentro del paso abierto (también en el\n// teléfono). Es el de editar un expediente: se ve de un vistazo qué pasos hay y se entra al que hace falta.\n//\n// Con onStepSelect los títulos de los pasos se pulsan (con teclado también: son botones) y avisan qué paso se pidió; quien lo\n// usa decide si salta. Sin él, los títulos solo informan (lo de siempre). Omitir es opcional: sin onSkip no sale el botón.\n//\n// Los textos se cambian con `texts`, con la forma de `common` en los textos del paquete: {wizard: {next: 'Continuar'}}.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaWizardLayout con defaultProps y\n// styleOverrides de sus partes: stepper, phoneSteps, actions.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport Stack from '@mui/material/Stack';\nimport Step from '@mui/material/Step';\nimport StepButton from '@mui/material/StepButton';\nimport StepContent from '@mui/material/StepContent';\nimport StepLabel from '@mui/material/StepLabel';\nimport Stepper from '@mui/material/Stepper';\nimport Typography from '@mui/material/Typography';\nimport {WIZARD_ORIENTATION, isStepCompleted} from '@/inputs/wizardSteps.js';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// sin pasos omitidos (quien no usa «Omitir» no tiene que mandar nada)\nconst NO_SKIPPED_KEYS = new Set();\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaWizardLayout)\nconst THEME_NAME = 'CalcitaWizardLayout';\nconst WizardStepper = piecePart(THEME_NAME, 'Stepper', Stepper);\nconst WizardPhoneSteps = piecePart(THEME_NAME, 'PhoneSteps', Box);\nconst WizardActions = piecePart(THEME_NAME, 'Actions', Stack);\n\n/**\n * @param {object} props\n * @param {Object[]} props.steps en orden\n * @param {string} props.steps[].key\n * @param {string} props.steps[].label ya traducido\n * @param {boolean} [props.steps[].optional] se puede omitir\n * @param {boolean} [props.steps[].completed] lleva la palomita; por omisión, en fila y sin pulsar, los de antes del abierto\n * @param {import('react').ReactNode} props.steps[].content los campos del paso\n * @param {number} props.activeIndex el paso que se ve\n * @param {Set<string>} [props.skippedKeys] los pasos omitidos\n * @param {boolean} [props.isSubmitting] mientras se envía, «Anterior» se apaga\n * @param {'horizontal'|'vertical'} [props.orientation] uno de WIZARD_ORIENTATION; por omisión horizontal\n * @param {() => void} props.onBack\n * @param {() => void} props.onNext\n * @param {() => void} [props.onSkip] sin él no sale «Omitir este paso»\n * @param {(index: number) => void} [props.onStepSelect] con él, los títulos de los pasos se pulsan y avisan cuál se pidió\n * @param {import('react').ReactNode} props.submitButton el botón de enviar del último paso\n * @param {import('react').ReactNode} [props.problemAlert] el aviso de errores del servidor, arriba de los botones del último paso\n * @param {object} [props.texts] los textos que cambian, con la forma de `common`: {wizard: {next, back, skip, optional, skipped, stepOf}}\n */\nfunction WizardLayoutContent(props) {\n // lo que el proyecto puso en su tema (components.CalcitaWizardLayout.defaultProps) y encima lo que llega aquí\n const {\n steps, activeIndex, skippedKeys = NO_SKIPPED_KEYS, isSubmitting = false, orientation = WIZARD_ORIENTATION.horizontal,\n onBack, onNext, onSkip, onStepSelect, submitButton, problemAlert, texts,\n ...unknownProps\n } = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n const activeStep = steps[activeIndex];\n const isLastStep = activeIndex === steps.length - 1;\n const isVertical = orientation === WIZARD_ORIENTATION.vertical;\n const isSelectable = typeof onStepSelect === 'function';\n\n // el título de un paso: con onStepSelect es un botón (se pulsa y se llega con Tab); sin él, solo informa\n const stepTitleOf = (step, index) => {\n let caption;\n if (skippedKeys.has(step.key)) {\n caption = t('wizard.skipped');\n } else if (step.optional) {\n caption = t('wizard.optional');\n }\n const optional = caption && <Typography variant=\"caption\" color=\"text.secondary\">{caption}</Typography>;\n if (isSelectable) {\n return <StepButton optional={optional} onClick={() => onStepSelect(index)}>{step.label}</StepButton>;\n }\n return <StepLabel optional={optional}>{step.label}</StepLabel>;\n };\n\n // los botones del paso abierto: en fila van abajo de los campos; en vertical, dentro del paso\n const actions = (\n <WizardActions direction={{xs: 'column-reverse', sm: 'row'}} spacing={1.5} ownSx={{justifyContent: 'space-between'}}>\n <Button variant=\"text\" color=\"inherit\" disabled={activeIndex === 0 || isSubmitting} onClick={onBack}>\n {t('wizard.back')}\n </Button>\n <Stack direction={{xs: 'column-reverse', sm: 'row'}} spacing={1.5}>\n {activeStep.optional && !isLastStep && onSkip && (\n <Button variant=\"text\" onClick={onSkip}>{t('wizard.skip')}</Button>\n )}\n {isLastStep\n ? submitButton\n : <Button variant=\"contained\" size=\"large\" onClick={onNext}>{t('wizard.next')}</Button>}\n </Stack>\n </WizardActions>\n );\n const completedOf = (step, index) => isStepCompleted(step, {index, activeIndex, skippedKeys, isSelectable});\n\n if (isVertical) {\n return (\n // nonLinear: con los títulos que se pulsan, MUI no debe apagar los pasos de adelante\n <WizardStepper activeStep={activeIndex} orientation=\"vertical\" nonLinear={isSelectable}>\n {steps.map((step, index) => (\n <Step key={step.key} completed={completedOf(step, index)}>\n {stepTitleOf(step, index)}\n {/* solo el paso abierto tiene sus campos montados: al cerrarse se desmontan (unmountOnExit). Los botones\n van solo en el abierto: el que se cierra (la animación dura un momento) ya no es el paso de esos\n botones, y un «Guardar» repetido confunde */}\n <StepContent slotProps={{transition: {unmountOnExit: true}}}>\n <Stack spacing={3} sx={{pt: 1}}>\n <Box>{step.content}</Box>\n {index === activeIndex && isLastStep && problemAlert}\n {index === activeIndex && actions}\n </Stack>\n </StepContent>\n </Step>\n ))}\n </WizardStepper>\n );\n }\n\n return (\n <Stack spacing={3}>\n {/* en el teléfono los nombres de los pasos no caben: se dice en qué paso va */}\n <WizardStepper activeStep={activeIndex} alternativeLabel nonLinear={isSelectable} ownSx={{display: {xs: 'none', sm: 'flex'}}}>\n {steps.map((step, index) => (\n <Step key={step.key} completed={completedOf(step, index)}>\n {stepTitleOf(step, index)}\n </Step>\n ))}\n </WizardStepper>\n <WizardPhoneSteps ownSx={{display: {xs: 'block', sm: 'none'}}}>\n <Typography variant=\"overline\" color=\"text.secondary\">{t('wizard.stepOf', {current: activeIndex + 1, total: steps.length})}</Typography>\n <Typography variant=\"h6\">{activeStep.label}</Typography>\n </WizardPhoneSteps>\n\n <Box>{activeStep.content}</Box>\n\n {isLastStep && problemAlert}\n\n {actions}\n </Stack>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst WizardLayout = withPieceSlots(WizardLayoutContent, THEME_NAME);\nexport default WizardLayout;\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WizardLayout.js","sources":["../../src/inputs/WizardLayout.jsx"],"sourcesContent":["// Lo que se ve de un formulario por pasos: los pasos, los campos del paso abierto y los botones (Anterior · Omitir este paso ·\n// Siguiente o Enviar). No sabe de formik ni de react-hook-form: el FormWizard de cada uno (/forms y /react-hook-form) pone la\n// lógica (qué revisa «Siguiente», qué hace «Omitir», si se puede saltar a otro paso) y le pasa su botón de enviar y su aviso de\n// errores. Suelto sirve para armar un asistente propio con otra librería.\n//\n// Dos acomodos (WIZARD_ORIENTATION):\n// horizontal los pasos en fila arriba y los campos abajo; en el teléfono no caben los nombres: «Paso 2 de 4» y su nombre;\n// vertical uno debajo del otro, como un acordeón: los campos y los botones van dentro del paso abierto (también en el\n// teléfono). Es el de editar un expediente: se ve de un vistazo qué pasos hay y se entra al que hace falta.\n//\n// Con onStepSelect los títulos de los pasos se pulsan (con teclado también: son botones) y avisan qué paso se pidió; quien lo\n// usa decide si salta. Sin él, los títulos solo informan (lo de siempre). Omitir es opcional: sin onSkip no sale el botón.\n//\n// Los textos se cambian con `texts`, con la forma de `common` en los textos del paquete: {wizard: {next: 'Continuar'}}.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaWizardLayout con defaultProps y\n// styleOverrides de sus partes: stepper, phoneSteps, actions.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport Stack from '@mui/material/Stack';\nimport Step from '@mui/material/Step';\nimport StepButton from '@mui/material/StepButton';\nimport StepContent from '@mui/material/StepContent';\nimport StepLabel from '@mui/material/StepLabel';\nimport Stepper from '@mui/material/Stepper';\nimport Typography from '@mui/material/Typography';\nimport {WIZARD_ORIENTATION, isStepCompleted} from '@/inputs/wizardSteps.js';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// sin pasos omitidos (quien no usa «Omitir» no tiene que mandar nada)\nconst NO_SKIPPED_KEYS = new Set();\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaWizardLayout)\nconst THEME_NAME = 'CalcitaWizardLayout';\nconst WizardStepper = piecePart(THEME_NAME, 'Stepper', Stepper);\nconst WizardPhoneSteps = piecePart(THEME_NAME, 'PhoneSteps', Box);\nconst WizardActions = piecePart(THEME_NAME, 'Actions', Stack);\n\n/**\n * @param {object} props\n * @param {Object[]} props.steps en orden\n * @param {string} props.steps[].key\n * @param {string} props.steps[].label ya traducido\n * @param {boolean} [props.steps[].optional] se puede omitir\n * @param {boolean} [props.steps[].completed] lleva la palomita; por omisión, en fila y sin pulsar, los de antes del abierto\n * @param {import('react').ReactNode} props.steps[].content los campos del paso\n * @param {number} props.activeIndex el paso que se ve\n * @param {Set<string>} [props.skippedKeys] los pasos omitidos\n * @param {boolean} [props.isSubmitting] mientras se envía, «Anterior» se apaga\n * @param {'horizontal'|'vertical'} [props.orientation] uno de WIZARD_ORIENTATION; por omisión horizontal\n * @param {boolean} [props.hideBackOnFirstStep] en el primer paso no se pinta «Anterior» (no hay a dónde volver); por omisión\n * sale apagado, como antes\n * @param {() => void} props.onBack\n * @param {() => void} props.onNext\n * @param {() => void} [props.onSkip] sin él no sale «Omitir este paso»\n * @param {(index: number) => void} [props.onStepSelect] con él, los títulos de los pasos se pulsan y avisan cuál se pidió\n * @param {import('react').ReactNode} props.submitButton el botón de enviar del último paso\n * @param {import('react').ReactNode} [props.problemAlert] el aviso de errores del servidor, arriba de los botones del último paso\n * @param {object} [props.texts] los textos que cambian, con la forma de `common`: {wizard: {next, back, skip, optional, skipped, stepOf}}\n */\nfunction WizardLayoutContent(props) {\n // lo que el proyecto puso en su tema (components.CalcitaWizardLayout.defaultProps) y encima lo que llega aquí\n const {\n steps, activeIndex, skippedKeys = NO_SKIPPED_KEYS, isSubmitting = false, orientation = WIZARD_ORIENTATION.horizontal,\n hideBackOnFirstStep = false, onBack, onNext, onSkip, onStepSelect, submitButton, problemAlert, texts,\n ...unknownProps\n } = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n const activeStep = steps[activeIndex];\n const isLastStep = activeIndex === steps.length - 1;\n const isVertical = orientation === WIZARD_ORIENTATION.vertical;\n const isSelectable = typeof onStepSelect === 'function';\n const isBackHidden = hideBackOnFirstStep && activeIndex === 0;\n\n // el título de un paso: con onStepSelect es un botón (se pulsa y se llega con Tab); sin él, solo informa\n const stepTitleOf = (step, index) => {\n let caption;\n if (skippedKeys.has(step.key)) {\n caption = t('wizard.skipped');\n } else if (step.optional) {\n caption = t('wizard.optional');\n }\n const optional = caption && <Typography variant=\"caption\" color=\"text.secondary\">{caption}</Typography>;\n if (isSelectable) {\n return <StepButton optional={optional} onClick={() => onStepSelect(index)}>{step.label}</StepButton>;\n }\n return <StepLabel optional={optional}>{step.label}</StepLabel>;\n };\n\n // los botones del paso abierto: en fila van abajo de los campos; en vertical, dentro del paso\n const actions = (\n // sin «Anterior», los de seguir se quedan a la derecha (solos, space-between los mandaba a la izquierda; un margen\n // automático no sirve: Stack les pone margin 0 a sus hijos con más fuerza)\n <WizardActions direction={{xs: 'column-reverse', sm: 'row'}} spacing={1.5} ownSx={{justifyContent: isBackHidden ? 'flex-end' : 'space-between'}}>\n {!isBackHidden && (\n <Button variant=\"text\" color=\"inherit\" disabled={activeIndex === 0 || isSubmitting} onClick={onBack}>\n {t('wizard.back')}\n </Button>\n )}\n <Stack direction={{xs: 'column-reverse', sm: 'row'}} spacing={1.5}>\n {activeStep.optional && !isLastStep && onSkip && (\n <Button variant=\"text\" onClick={onSkip}>{t('wizard.skip')}</Button>\n )}\n {isLastStep\n ? submitButton\n : <Button variant=\"contained\" size=\"large\" onClick={onNext}>{t('wizard.next')}</Button>}\n </Stack>\n </WizardActions>\n );\n const completedOf = (step, index) => isStepCompleted(step, {index, activeIndex, skippedKeys, isSelectable});\n\n if (isVertical) {\n return (\n // nonLinear: con los títulos que se pulsan, MUI no debe apagar los pasos de adelante\n <WizardStepper activeStep={activeIndex} orientation=\"vertical\" nonLinear={isSelectable}>\n {steps.map((step, index) => (\n <Step key={step.key} completed={completedOf(step, index)}>\n {stepTitleOf(step, index)}\n {/* solo el paso abierto tiene sus campos montados: al cerrarse se desmontan (unmountOnExit). Los botones\n van solo en el abierto: el que se cierra (la animación dura un momento) ya no es el paso de esos\n botones, y un «Guardar» repetido confunde */}\n <StepContent slotProps={{transition: {unmountOnExit: true}}}>\n <Stack spacing={3} sx={{pt: 1}}>\n <Box>{step.content}</Box>\n {index === activeIndex && isLastStep && problemAlert}\n {index === activeIndex && actions}\n </Stack>\n </StepContent>\n </Step>\n ))}\n </WizardStepper>\n );\n }\n\n return (\n <Stack spacing={3}>\n {/* en el teléfono los nombres de los pasos no caben: se dice en qué paso va */}\n <WizardStepper activeStep={activeIndex} alternativeLabel nonLinear={isSelectable} ownSx={{display: {xs: 'none', sm: 'flex'}}}>\n {steps.map((step, index) => (\n <Step key={step.key} completed={completedOf(step, index)}>\n {stepTitleOf(step, index)}\n </Step>\n ))}\n </WizardStepper>\n <WizardPhoneSteps ownSx={{display: {xs: 'block', sm: 'none'}}}>\n <Typography variant=\"overline\" color=\"text.secondary\">{t('wizard.stepOf', {current: activeIndex + 1, total: steps.length})}</Typography>\n <Typography variant=\"h6\">{activeStep.label}</Typography>\n </WizardPhoneSteps>\n\n <Box>{activeStep.content}</Box>\n\n {isLastStep && problemAlert}\n\n {actions}\n </Stack>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst WizardLayout = withPieceSlots(WizardLayoutContent, THEME_NAME);\nexport default WizardLayout;\n"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { createContext, useContext } from "react";
|
|
3
|
-
const FormSectionContext = createContext(
|
|
4
|
-
|
|
3
|
+
const FormSectionContext = createContext(
|
|
4
|
+
/** @type {false|{labelPlacement: string}} */
|
|
5
|
+
false
|
|
6
|
+
);
|
|
7
|
+
const useIsInsideFormSection = () => Boolean(useContext(FormSectionContext));
|
|
8
|
+
const useFormSectionLayout = () => useContext(FormSectionContext);
|
|
5
9
|
export {
|
|
6
10
|
FormSectionContext,
|
|
11
|
+
useFormSectionLayout,
|
|
7
12
|
useIsInsideFormSection
|
|
8
13
|
};
|
|
9
14
|
//# sourceMappingURL=formLayoutContext.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formLayoutContext.js","sources":["../../src/inputs/formLayoutContext.js"],"sourcesContent":["// Si un campo está dentro de una FormSection (el formulario agrupado de Apple): ahí cada campo se pinta como renglón, con\n// la etiqueta a la izquierda y el valor a la derecha. Fuera de ella, la etiqueta va arriba del campo.\n//\n// Va en su propio archivo y no junto a FormSection: FieldFrame lo lee, y así FieldFrame no importa a FormSection (que a su\n// vez usa FormRow).\nimport {createContext, useContext} from 'react';\n\nexport const FormSectionContext = createContext(false);\n\n/** true si el campo va dentro de una FormSection. */\nexport const useIsInsideFormSection = () => useContext(FormSectionContext);\n"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"formLayoutContext.js","sources":["../../src/inputs/formLayoutContext.js"],"sourcesContent":["// Si un campo está dentro de una FormSection (el formulario agrupado de Apple): ahí cada campo se pinta como renglón, con\n// la etiqueta a la izquierda y el valor a la derecha. Fuera de ella, la etiqueta va arriba del campo.\n//\n// El valor es false fuera de una sección (RepeatingFields lo vuelve a poner en false para sus renglones) y, dentro, cómo\n// pide la sección sus renglones: {labelPlacement}.\n//\n// Va en su propio archivo y no junto a FormSection: FieldFrame lo lee, y así FieldFrame no importa a FormSection (que a su\n// vez usa FormRow).\nimport {createContext, useContext} from 'react';\n\n/** @type {import('react').Context<false|{labelPlacement: string}>} */\nexport const FormSectionContext = createContext(/** @type {false|{labelPlacement: string}} */ (false));\n\n/** true si el campo va dentro de una FormSection. */\nexport const useIsInsideFormSection = () => Boolean(useContext(FormSectionContext));\n\n/** Cómo pide la sección sus renglones ({labelPlacement}); false fuera de una sección. */\nexport const useFormSectionLayout = () => useContext(FormSectionContext);\n"],"names":[],"mappings":";;AAWY,MAAC,qBAAqB;AAAA;AAAA,EAA6D;AAAK;AAGxF,MAAC,yBAAyB,MAAM,QAAQ,WAAW,kBAAkB,CAAC;AAGtE,MAAC,uBAAuB,MAAM,WAAW,kBAAkB;"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const REQUIRED_LABEL_ATTRIBUTE = "data-required";
|
|
2
|
+
function cssStringOf(mark) {
|
|
3
|
+
return `"${String(mark).replace(/["\\]/g, "\\$&")}"`;
|
|
4
|
+
}
|
|
5
|
+
function requiredMarkSxOf(mark) {
|
|
6
|
+
const text = cssStringOf(mark);
|
|
7
|
+
return {
|
|
8
|
+
"&::after": { content: text, marginLeft: "0.15em" },
|
|
9
|
+
// con texto alterno vacío: se ve, pero el lector de pantalla no lo lee
|
|
10
|
+
[`@supports (content: ${text} / "")`]: { "&::after": { content: `${text} / ""` } }
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
REQUIRED_LABEL_ATTRIBUTE,
|
|
15
|
+
requiredMarkSxOf
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=requiredMark.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requiredMark.js","sources":["../../src/inputs/requiredMark.js"],"sourcesContent":["// El asterisco de lo obligatorio en la etiqueta de un campo, compartido por FieldFrame (la etiqueta de arriba) y FormRow (el\n// renglón del formulario agrupado).\n//\n// OJO, por qué va en el estilo (::after) y no como texto dentro de la etiqueta: el texto de la etiqueta es como las pruebas\n// y los lectores encuentran el campo. Con «Nombre*» dentro, getByLabel('Nombre', {exact: true}) de Playwright y\n// getByLabelText('Nombre') de Testing Library dejaban de encontrarlo: subir de versión\n// rompía las pruebas de cualquier proyecto que ya usaba required. En ::after el texto sigue igual, y con «/ \"\"» el lector de\n// pantalla no dice «asterisco» (el campo ya dice que es obligatorio con required o aria-required). Un navegador viejo que no\n// conoce «/ \"\"» pinta el asterisco solo (@supports).\n//\n// La etiqueta lleva data-required: así el tema del proyecto la encuentra (label: {'&[data-required]::after': {color: …}}).\n//\n// Funciones puras, sin React.\n\n/** El atributo que marca la etiqueta de un campo obligatorio. */\nexport const REQUIRED_LABEL_ATTRIBUTE = 'data-required';\n\n/**\n * El texto de la marca como cadena de CSS (entre comillas, con las comillas y diagonales de adentro escapadas).\n *\n * @param {string} mark\n * @returns {string}\n */\nfunction cssStringOf(mark) {\n return `\"${String(mark).replace(/[\"\\\\]/g, '\\\\$&')}\"`;\n}\n\n/**\n * Los estilos de la etiqueta de un campo obligatorio: la marca después del texto, pegada y del mismo color.\n *\n * @param {string} mark el texto de la marca, ya traducido (common.form.requiredMark: «*»)\n * @returns {object} para el sx de la etiqueta\n */\nexport function requiredMarkSxOf(mark) {\n const text = cssStringOf(mark);\n return {\n '&::after': {content: text, marginLeft: '0.15em'},\n // con texto alterno vacío: se ve, pero el lector de pantalla no lo lee\n [`@supports (content: ${text} / \"\")`]: {'&::after': {content: `${text} / \"\"`}},\n };\n}\n"],"names":[],"mappings":"AAeY,MAAC,2BAA2B;AAQxC,SAAS,YAAY,MAAM;AACvB,SAAO,IAAI,OAAO,IAAI,EAAE,QAAQ,UAAU,MAAM,CAAC;AACrD;AAQO,SAAS,iBAAiB,MAAM;AACnC,QAAM,OAAO,YAAY,IAAI;AAC7B,SAAO;AAAA,IACH,YAAY,EAAC,SAAS,MAAM,YAAY,SAAQ;AAAA;AAAA,IAEhD,CAAC,uBAAuB,IAAI,QAAQ,GAAG,EAAC,YAAY,EAAC,SAAS,GAAG,IAAI,QAAO,EAAC;AAAA,EACrF;AACA;"}
|
package/dist/locales/en.js
CHANGED