@12-apps/ui 6.2.0 → 6.3.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/dist/{chunk-35VGGLOC.js → chunk-CEKPLUQV.js} +2 -2
- package/dist/{chunk-35VGGLOC.js.map → chunk-CEKPLUQV.js.map} +1 -1
- package/dist/{chunk-62XQWGXU.js → chunk-MXPXKORR.js} +19 -17
- package/dist/chunk-MXPXKORR.js.map +1 -0
- package/dist/{chunk-7XLEWBKL.js → chunk-N554AFDB.js} +7 -10
- package/dist/chunk-N554AFDB.js.map +1 -0
- package/dist/{chunk-JDO7W4D4.js → chunk-R5ZQZSEQ.js} +2 -20
- package/dist/{chunk-JDO7W4D4.js.map → chunk-R5ZQZSEQ.js.map} +1 -1
- package/dist/{chunk-R4TYXKDD.js → chunk-TPQRIPCN.js} +52 -48
- package/dist/chunk-TPQRIPCN.js.map +1 -0
- package/dist/copy.js +1 -0
- package/dist/copy.js.map +1 -0
- package/dist/data-display/CardKit.js +15 -4
- package/dist/data-display/CardKit.js.map +1 -1
- package/dist/data-display/DataViews.js +664 -616
- package/dist/data-display/DataViews.js.map +1 -1
- package/dist/data-display/SectionOnboarding.js +3 -3
- package/dist/data-display/SectionOnboarding.js.map +1 -1
- package/dist/feedback/ConfirmAction.js +3 -5
- package/dist/form/CategorySelect.js +1 -1
- package/dist/form/CepField.js +1 -1
- package/dist/form/total-form.js +8 -4
- package/dist/form/total-form.js.map +1 -1
- package/dist/layout/ContentToolbar.js +1 -1
- package/dist/layout/TableFilter.js +1 -1
- package/dist/pt-BR.js +222 -0
- package/dist/pt-BR.js.map +1 -0
- package/dist/types/components/data-display/CardKit/use-remove-confirm.d.ts +4 -1
- package/dist/types/components/data-display/CardKit/use-remove-confirm.d.ts.map +1 -1
- package/dist/types/components/data-display/CardKit/use-row-confirm.d.ts +5 -2
- package/dist/types/components/data-display/CardKit/use-row-confirm.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/DataViewsBoard.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/DeleteViewDialog.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/ManageViewsDialog.d.ts +4 -1
- package/dist/types/components/data-display/DataViews/ManageViewsDialog.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/SaveViewModal.d.ts +0 -5
- package/dist/types/components/data-display/DataViews/SaveViewModal.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/base-card.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/base-list-card-gutters.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-bar-controls.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-category-pill.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-columns-tab.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-copy-context.d.ts +17 -0
- package/dist/types/components/data-display/DataViews/data-views-copy-context.d.ts.map +1 -0
- package/dist/types/components/data-display/DataViews/data-views-copy.d.ts +205 -0
- package/dist/types/components/data-display/DataViews/data-views-copy.d.ts.map +1 -0
- package/dist/types/components/data-display/DataViews/data-views-display-panel.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-display-tabs.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-export.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-filter-panel.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-grid-helpers.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-more-fields.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-more-filters.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-range-pill.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-range-presets.d.ts +3 -2
- package/dist/types/components/data-display/DataViews/data-views-range-presets.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-scopes.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-search.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-select-all-strip.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-table-parts.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-view-nav.d.ts +1 -1
- package/dist/types/components/data-display/DataViews/data-views-view-nav.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/index.d.ts +2 -0
- package/dist/types/components/data-display/DataViews/index.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/save-view-preview.d.ts +10 -0
- package/dist/types/components/data-display/DataViews/save-view-preview.d.ts.map +1 -0
- package/dist/types/components/data-display/DataViews/use-saved-views-controller.d.ts.map +1 -1
- package/dist/types/components/data-display/SectionOnboarding/SectionOnboarding.types.d.ts +6 -5
- package/dist/types/components/data-display/SectionOnboarding/SectionOnboarding.types.d.ts.map +1 -1
- package/dist/types/components/feedback/ConfirmAction/ConfirmAction.hooks.d.ts +1 -3
- package/dist/types/components/feedback/ConfirmAction/ConfirmAction.hooks.d.ts.map +1 -1
- package/dist/types/components/feedback/ConfirmAction/ConfirmAction.parts.d.ts +4 -1
- package/dist/types/components/feedback/ConfirmAction/ConfirmAction.parts.d.ts.map +1 -1
- package/dist/types/components/feedback/ConfirmAction/ConfirmAction.types.d.ts +9 -1
- package/dist/types/components/feedback/ConfirmAction/ConfirmAction.types.d.ts.map +1 -1
- package/dist/types/components/feedback/ConfirmAction/ConfirmButton.d.ts +2 -1
- package/dist/types/components/feedback/ConfirmAction/ConfirmButton.d.ts.map +1 -1
- package/dist/types/components/feedback/ConfirmAction/index.d.ts +2 -2
- package/dist/types/components/feedback/ConfirmAction/index.d.ts.map +1 -1
- package/dist/types/components/feedback/ConfirmAction/with-confirmation.d.ts +5 -1
- package/dist/types/components/feedback/ConfirmAction/with-confirmation.d.ts.map +1 -1
- package/dist/types/components/form/CategorySelect/CategoryPanel.d.ts +4 -1
- package/dist/types/components/form/CategorySelect/CategoryPanel.d.ts.map +1 -1
- package/dist/types/components/form/CategorySelect/CategoryPanelFoot.d.ts +5 -2
- package/dist/types/components/form/CategorySelect/CategoryPanelFoot.d.ts.map +1 -1
- package/dist/types/components/form/CategorySelect/CategoryPanelHead.d.ts +5 -2
- package/dist/types/components/form/CategorySelect/CategoryPanelHead.d.ts.map +1 -1
- package/dist/types/components/form/CategorySelect/CategoryPanelList.d.ts +3 -0
- package/dist/types/components/form/CategorySelect/CategoryPanelList.d.ts.map +1 -1
- package/dist/types/components/form/CategorySelect/CategorySelect.types.d.ts +5 -0
- package/dist/types/components/form/CategorySelect/CategorySelect.types.d.ts.map +1 -1
- package/dist/types/components/form/CategorySelect/CategoryTrigger.d.ts +4 -1
- package/dist/types/components/form/CategorySelect/CategoryTrigger.d.ts.map +1 -1
- package/dist/types/components/form/CepField/CepField.d.ts +1 -1
- package/dist/types/components/form/CepField/CepField.d.ts.map +1 -1
- package/dist/types/components/form/CepField/CepField.types.d.ts +3 -0
- package/dist/types/components/form/CepField/CepField.types.d.ts.map +1 -1
- package/dist/types/components/form/total-form/Fields/CategoryField.d.ts +4 -1
- package/dist/types/components/form/total-form/Fields/CategoryField.d.ts.map +1 -1
- package/dist/types/components/form/total-form/Fields/CepField.d.ts +4 -1
- package/dist/types/components/form/total-form/Fields/CepField.d.ts.map +1 -1
- package/dist/types/components/layout/ContentToolbar/ContentToolbar.types.d.ts +6 -1
- package/dist/types/components/layout/ContentToolbar/ContentToolbar.types.d.ts.map +1 -1
- package/dist/types/components/layout/ContentToolbar/SavedViewsMenu.d.ts.map +1 -1
- package/dist/types/copy.d.ts +99 -0
- package/dist/types/copy.d.ts.map +1 -0
- package/dist/types/pt-BR.d.ts +28 -0
- package/dist/types/pt-BR.d.ts.map +1 -0
- package/package.json +10 -2
- package/src/components/data-display/CardKit/use-remove-confirm.tsx +5 -0
- package/src/components/data-display/CardKit/use-row-confirm.tsx +7 -2
- package/src/components/data-display/DataViews/DataViewsBoard.tsx +7 -4
- package/src/components/data-display/DataViews/DeleteViewDialog.tsx +6 -4
- package/src/components/data-display/DataViews/ManageViewsDialog.tsx +26 -10
- package/src/components/data-display/DataViews/SaveViewModal.tsx +56 -90
- package/src/components/data-display/DataViews/base-card.tsx +3 -1
- package/src/components/data-display/DataViews/base-list-card-gutters.tsx +3 -1
- package/src/components/data-display/DataViews/data-views-bar-controls.tsx +8 -5
- package/src/components/data-display/DataViews/data-views-category-pill.tsx +6 -3
- package/src/components/data-display/DataViews/data-views-columns-tab.tsx +5 -3
- package/src/components/data-display/DataViews/data-views-copy-context.tsx +43 -0
- package/src/components/data-display/DataViews/data-views-copy.ts +214 -0
- package/src/components/data-display/DataViews/data-views-display-panel.tsx +15 -9
- package/src/components/data-display/DataViews/data-views-display-tabs.tsx +19 -29
- package/src/components/data-display/DataViews/data-views-export.tsx +9 -10
- package/src/components/data-display/DataViews/data-views-filter-panel.tsx +9 -5
- package/src/components/data-display/DataViews/data-views-grid-helpers.tsx +5 -2
- package/src/components/data-display/DataViews/data-views-more-fields.tsx +5 -3
- package/src/components/data-display/DataViews/data-views-more-filters.tsx +6 -3
- package/src/components/data-display/DataViews/data-views-range-pill.tsx +9 -5
- package/src/components/data-display/DataViews/data-views-range-presets.ts +7 -8
- package/src/components/data-display/DataViews/data-views-scopes.tsx +3 -1
- package/src/components/data-display/DataViews/data-views-search.tsx +7 -4
- package/src/components/data-display/DataViews/data-views-select-all-strip.tsx +5 -3
- package/src/components/data-display/DataViews/data-views-table-parts.tsx +7 -2
- package/src/components/data-display/DataViews/data-views-view-nav.tsx +22 -16
- package/src/components/data-display/DataViews/index.ts +20 -0
- package/src/components/data-display/DataViews/save-view-preview.tsx +78 -0
- package/src/components/data-display/DataViews/use-saved-views-controller.ts +3 -1
- package/src/components/data-display/SectionOnboarding/SectionOnboarding.tsx +3 -3
- package/src/components/data-display/SectionOnboarding/SectionOnboarding.types.ts +8 -7
- package/src/components/feedback/ConfirmAction/ConfirmAction.hooks.ts +2 -2
- package/src/components/feedback/ConfirmAction/ConfirmAction.parts.tsx +12 -5
- package/src/components/feedback/ConfirmAction/ConfirmAction.types.ts +9 -1
- package/src/components/feedback/ConfirmAction/ConfirmButton.tsx +12 -4
- package/src/components/feedback/ConfirmAction/index.ts +2 -2
- package/src/components/feedback/ConfirmAction/with-confirmation.tsx +4 -3
- package/src/components/form/CategorySelect/CategoryPanel.tsx +18 -6
- package/src/components/form/CategorySelect/CategoryPanelFoot.tsx +10 -5
- package/src/components/form/CategorySelect/CategoryPanelHead.tsx +8 -3
- package/src/components/form/CategorySelect/CategoryPanelList.tsx +17 -10
- package/src/components/form/CategorySelect/CategorySelect.tsx +3 -3
- package/src/components/form/CategorySelect/CategorySelect.types.ts +5 -0
- package/src/components/form/CategorySelect/CategoryTrigger.tsx +5 -1
- package/src/components/form/CepField/CepField.tsx +6 -9
- package/src/components/form/CepField/CepField.types.ts +3 -0
- package/src/components/form/total-form/Fields/CategoryField.tsx +5 -0
- package/src/components/form/total-form/Fields/CepField.tsx +5 -0
- package/src/components/layout/ContentToolbar/ContentToolbar.types.ts +6 -1
- package/src/components/layout/ContentToolbar/SavedViewsMenu.tsx +1 -21
- package/src/components/layout/TableFilter/TableFilter.tsx +1 -1
- package/src/copy.ts +103 -0
- package/src/pt-BR.ts +247 -0
- package/dist/chunk-62XQWGXU.js.map +0 -1
- package/dist/chunk-7XLEWBKL.js.map +0 -1
- package/dist/chunk-R4TYXKDD.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/data-display/CardKit/CardKebab.tsx","../../src/components/data-display/CardKit/card-actions-context.tsx","../../src/components/data-display/CardKit/row-actions-to-menu.ts","../../src/components/data-display/CardKit/list-card-parts.tsx","../../src/components/data-display/CardKit/use-row-confirm.tsx","../../src/components/data-display/CardKit/use-remove-confirm.tsx"],"sourcesContent":["'use client';\n\nimport type { JSX } from 'react';\n\nimport { Button } from '../../form/Button';\nimport { DropdownMenu, type DropdownMenuItem } from '../../navigation/DropdownMenu';\n\n/**\n * The \"⋮\" trigger every row and card menu opens from.\n *\n * One component rather than a `DropdownMenu` per entity, so the kebab looks and\n * behaves identically in the card, in the list row and in the table row. The\n * entity's menu owns its own popups; this is the trigger and the item list.\n */\nexport function CardKebab({\n items,\n menuLabel,\n dataTestId,\n}: {\n items: DropdownMenuItem[];\n /**\n * The trigger's accessible name — required, and with no default.\n *\n * It is the only text this component renders, and a screen reader announces\n * it verbatim. A default here would be a word in the origin's language that\n * reads as finished to the next adopter right up until somebody using a\n * screen reader meets it.\n */\n menuLabel: string;\n dataTestId?: string;\n}): JSX.Element {\n return (\n <DropdownMenu\n size=\"sm\"\n items={items}\n trigger={\n <Button variant=\"text\" size=\"sm\" aria-label={menuLabel} dataTestId={dataTestId}>\n ⋮\n </Button>\n }\n />\n );\n}\n","'use client';\n\nimport { createContext, useCallback, useContext, useState, type JSX, type ReactNode } from 'react';\n\nimport { Snackbar } from '@mui/material';\n\nimport { Alert } from '../Alert';\n\n/**\n * The ambient wiring a self-contained row/card menu needs, and nothing else.\n *\n * A menu that owns its own popups still needs three things it cannot know: the\n * tenant it is acting inside, what to do after a write lands, and somewhere to\n * put a failure. Passing those down through the grid, the layout and the card\n * is four props of drilling per entity; holding them in context is one.\n *\n * Kept deliberately SMALL — it is not an edit-dialog host. A menu that read its\n * dialogs from here would stop being portable, because the set of dialogs is\n * per-entity. What it may read is the three facts below.\n *\n * The provider renders ONE shared error snackbar, which is the whole reason the\n * error channel is here rather than per-menu: before it, every page carried its\n * own error alert and every menu had to find its page's.\n */\ninterface CardActionsValue {\n /** The tenant every action in this subtree acts inside. */\n tenantSlug: string;\n /** Re-read the list after a write. */\n onRefresh: () => void;\n /** Surface a failed action's message (the shared snackbar). */\n notifyError: (message: string) => void;\n}\n\nconst CardActionsContext = createContext<CardActionsValue | null>(null);\n\nexport function CardActionsProvider({\n tenantSlug,\n onRefresh,\n errorTitle,\n autoHideMs = 6_000,\n children,\n}: {\n tenantSlug: string;\n onRefresh: () => void;\n /**\n * The snackbar's heading — required, no default.\n *\n * It is the one sentence this provider renders on its own, and a default\n * would be the origin's language shipped as a finished-looking silence. The\n * MESSAGE beside it comes from whatever failed, which is already the host's.\n */\n errorTitle: string;\n /** How long the snackbar stays up. */\n autoHideMs?: number;\n children: ReactNode;\n}): JSX.Element {\n const [error, setError] = useState<string | null>(null);\n const notifyError = useCallback((message: string) => setError(message), []);\n\n return (\n <CardActionsContext.Provider value={{ tenantSlug, onRefresh, notifyError }}>\n {children}\n <Snackbar\n open={error !== null}\n autoHideDuration={autoHideMs}\n onClose={() => setError(null)}\n anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}\n >\n <span>\n <Alert\n variant=\"danger\"\n title={errorTitle}\n description={error ?? ''}\n closable\n onClose={() => setError(null)}\n data-testid=\"card-action-error\"\n />\n </span>\n </Snackbar>\n </CardActionsContext.Provider>\n );\n}\n\n/**\n * Read the tenant + refresh + error wiring.\n *\n * THROWS outside a provider rather than answering a null object, deliberately:\n * a menu whose `onRefresh` silently did nothing would leave the operator\n * looking at a stale row after a delete that worked, which reads as the delete\n * having failed. Failing at mount says where the provider is missing.\n */\nexport function useCardActions(): CardActionsValue {\n const value = useContext(CardActionsContext);\n if (!value) {\n throw new Error('useCardActions must be used within a CardActionsProvider');\n }\n return value;\n}\n","import type { DropdownMenuItem } from '../../navigation/DropdownMenu';\nimport type { RowAction } from '../DataViews';\n\n/**\n * Adapt a list of {@link RowAction}s into single-row kebab items.\n *\n * Applies each action's `isVisible` guard, resolves its per-row `rowLabel`\n * override, carries its colour, and fires `onSelect([row])` on click.\n *\n * The point is that ONE definition drives both surfaces. An entity that already\n * declares its per-row actions as `RowAction[]` — because the table's multi-\n * select menu needs them — gets the card's kebab from the same array through\n * `renderRowMenu` / `renderCard`, with no second list to keep in step. Two\n * lists is how a \"Duplicar\" that appears in the table and not on the card\n * happens, and nothing reports it.\n */\nexport function rowActionsToMenuItems<T extends Record<string, unknown>>(\n actions: RowAction<T>[],\n row: T,\n): DropdownMenuItem[] {\n return actions\n .filter((action) => action.isVisible?.(row) ?? true)\n .map((action) => ({\n id: action.id,\n label: action.rowLabel?.(row) ?? action.label,\n color: action.color,\n onClick: () => void action.onSelect([row]),\n }));\n}\n","'use client';\n\nimport type { JSX, ReactNode } from 'react';\n\nimport { Box } from '../../../mui/Box';\n\nimport type { CardFactProps, CardLedgerLine } from './CardKit.types';\n\n/**\n * THE SHARED FURNITURE OF AN EXPANDED LIST-CARD BODY.\n *\n * `BaseListCard` says nothing about what goes inside a row's expanded area — it\n * spans the rails and stops, because the design belongs to the consumer. Right\n * for the card; wrong as the place where every entity in an admin app invents\n * its own two-column layout, its own label/value pair and its own ledger.\n *\n * So the four shapes that actually repeat live here, once. Nothing here knows a\n * domain: they take `ReactNode` and lay it out.\n */\n\n/** The expanded body's two-column split: detail on the left, a ledger right. */\nexport function DetailColumns({ left, right }: { left: ReactNode; right: ReactNode }): JSX.Element {\n return (\n <Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr', md: '1fr 1fr' }, gap: 3 }}>\n <Box sx={{ minWidth: 0 }}>{left}</Box>\n <Box sx={{ minWidth: 0 }}>{right}</Box>\n </Box>\n );\n}\n\n/**\n * One labelled fact inside an expanded body.\n *\n * Horizontal, not stacked: the body is already a wide area with room for a\n * label beside its value, and stacking them there would ape the summary rails\n * above without their alignment.\n */\nexport function Fact({ label, value }: CardFactProps): JSX.Element {\n return (\n <Box sx={{ display: 'flex', justifyContent: 'space-between', gap: 2, fontSize: 13, py: 0.25 }}>\n <Box component=\"span\" sx={{ color: 'text.secondary', flexShrink: 0 }}>\n {label}\n </Box>\n <Box component=\"span\" sx={{ minWidth: 0, textAlign: 'right', overflowWrap: 'anywhere' }}>\n {value}\n </Box>\n </Box>\n );\n}\n\n/**\n * A money ledger: rows of label/amount, then a ruled total.\n *\n * The total is separated by a RULE rather than by weight alone, because a\n * subtotal and a total in one column with only bold between them is the classic\n * misread — the eye lands on whichever number is larger.\n *\n * The figures arrive pre-formatted. This is a layout, and a component that\n * formatted money would be choosing a locale on the consumer's behalf.\n */\nexport function Ledger({\n lines,\n total,\n}: {\n lines: CardLedgerLine[];\n total: { label: string; value: ReactNode };\n}): JSX.Element {\n return (\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.25 }}>\n {lines.map((line) => (\n <Box\n key={line.label}\n sx={{\n display: 'flex',\n justifyContent: 'space-between',\n fontSize: 13,\n color: line.tone === 'info' ? 'info.main' : 'text.secondary',\n }}\n >\n <Box component=\"span\">{line.label}</Box>\n <Box component=\"span\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {line.value}\n </Box>\n </Box>\n ))}\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'space-between',\n fontWeight: 700,\n borderTop: 1,\n borderColor: 'divider',\n pt: 0.5,\n mt: 0.5,\n }}\n >\n <Box component=\"span\">{total.label}</Box>\n <Box component=\"span\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {total.value}\n </Box>\n </Box>\n </Box>\n );\n}\n\n/** A heading inside the expanded body, for a section that needs naming. */\nexport function BodyHeading({ children }: { children: ReactNode }): JSX.Element {\n return (\n <Box\n sx={{\n fontSize: 11,\n fontWeight: 700,\n letterSpacing: 0.4,\n textTransform: 'uppercase',\n color: 'text.disabled',\n mb: 0.5,\n }}\n >\n {children}\n </Box>\n );\n}\n\n/**\n * A wrapping run of small items — permission names, role names, target ids.\n *\n * The whole reason several entities earn a list card at all: a `string[]` has no\n * honest table cell. Truncated to \"3 items\" it says nothing; printed in full it\n * destroys the column. Here it simply wraps.\n */\nexport function TagList({\n items,\n empty,\n}: {\n items: readonly string[];\n /** What to show for an empty run — the consumer's sentence, no default. */\n empty: string;\n}): JSX.Element {\n if (items.length === 0) {\n return <Box sx={{ fontSize: 13, color: 'text.disabled' }}>{empty}</Box>;\n }\n return (\n <Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5 }}>\n {items.map((item) => (\n <Box\n key={item}\n component=\"span\"\n sx={{\n fontSize: 12,\n px: 0.75,\n py: 0.25,\n borderRadius: 1,\n bgcolor: 'action.hover',\n color: 'text.secondary',\n fontFamily: 'monospace',\n }}\n >\n {item}\n </Box>\n ))}\n </Box>\n );\n}\n","'use client';\n\nimport { useState, type JSX } from 'react';\n\nimport { ConfirmActionDialog, useConfirmAction } from '../../feedback/ConfirmAction';\n\n/**\n * How the popup should read for the rows about to be acted on.\n *\n * Built from the SELECTION rather than from a single row, because the same\n * guard covers a bulk action: \"Delete 4 categories?\" and \"Delete the category\n * Drinks?\" are the same question asked of a different-sized selection — and an\n * operator who multi-selected by mistake is exactly who this popup is for.\n */\nexport interface RowConfirmCopy {\n title: string;\n description: string;\n /** Echoed into the popup; omit for a multi-row selection the title covers. */\n entityName?: string;\n /** The VERB. Required, never defaulted — see {@link useRowConfirm}. */\n confirmText: string;\n /** Override where the word \"cancel\" would mean the ACTION itself. */\n cancelText?: string;\n /** Require typing this before the confirm enables — for the unrecoverable few. */\n typeToConfirm?: string;\n}\n\ninterface RowConfirmOptions<T> {\n /**\n * The destructive write, over the whole selection. Called ONLY after the\n * operator confirms; throw (or reject) to keep the popup open carrying the\n * message.\n */\n write: (rows: T[]) => Promise<unknown>;\n /** The wording, given the selection. */\n describe: (rows: T[]) => RowConfirmCopy;\n dataTestId: string;\n /** Shown when `write` fails without a message of its own. */\n errorText?: string;\n}\n\nexport interface RowConfirm<T> {\n /** Hand this a grid action's `rows`: it opens the popup and writes nothing. */\n request: (rows: T[]) => void;\n /** Render next to the grid. */\n dialog: JSX.Element | null;\n}\n\n/**\n * Confirmation for a grid's `RowAction` — the per-row kebab entry and the\n * multi-select actions menu both, since they run the same handler.\n *\n * The SELECTION is held while the popup is open, so the write sees exactly the\n * rows the operator was looking at when they were asked. Re-reading the grid's\n * live selection at confirm time is the bug this shape avoids: the list can\n * refresh underneath an open dialog.\n *\n * `confirmText` is required and comes from `describe`, with no default. A verb\n * defaulted in the origin's language reads as finished to the next adopter\n * right up until an operator sees it — and `ConfirmOptions` already refuses to\n * default one for the same reason.\n */\nexport function useRowConfirm<T>({\n write,\n describe,\n dataTestId,\n errorText,\n}: RowConfirmOptions<T>): RowConfirm<T> {\n const [target, setTarget] = useState<T[] | null>(null);\n\n const state = useConfirmAction(async () => {\n if (!target) return;\n await write(target);\n setTarget(null);\n }, errorText);\n\n const request = (rows: T[]): void => {\n // An empty selection has nothing to confirm — asking would be a popup about\n // nothing, and confirming it would write nothing.\n if (rows.length === 0) return;\n setTarget(rows);\n state.request();\n };\n\n return {\n request,\n dialog: target ? (\n <ConfirmActionDialog state={state} {...describe(target)} dataTestId={dataTestId} />\n ) : null,\n };\n}\n","'use client';\n\nimport type { JSX } from 'react';\n\nimport { ConfirmActionDialog, useConfirmAction } from '../../feedback/ConfirmAction';\n\nimport { useCardActions } from './card-actions-context';\n\n/** The `{ ok, error }` envelope a write action answers with. */\nexport interface CardWriteResult {\n ok: boolean;\n error?: string;\n}\n\ninterface RemoveConfirmOptions {\n /** The destructive write. Called ONLY after the operator confirms. */\n write: () => Promise<CardWriteResult>;\n /** The popup's question. */\n title: string;\n /** The row being removed, echoed into the popup so it names a thing. */\n entityName: string;\n /**\n * What happens, and whether it can be walked back. Say which — the difference\n * between a soft delete a recycle bin recovers and one nothing recovers is\n * the whole content of the decision being asked for.\n */\n description: string;\n /** The confirm button's VERB. Required, never defaulted. */\n confirmText: string;\n /** Used when the write fails without a message of its own. */\n fallbackError: string;\n dataTestId: string;\n}\n\ninterface RemoveConfirm {\n /** Hand this to the menu item's `onClick`: it opens the popup, nothing more. */\n request: () => void;\n /** Render alongside the trigger. */\n dialog: JSX.Element;\n}\n\n/**\n * The confirm-before-removing wiring every card/row menu repeats, in one place.\n *\n * It closes the three gaps a hand-rolled version keeps re-opening: the write\n * leaves ONLY on confirm; a refusal is surfaced twice — inside the popup, where\n * the operator is still deciding, and in the shared snackbar behind it — and a\n * failed attempt leaves the popup OPEN to be retried instead of vanishing over\n * a delete that never happened.\n *\n * The difference from {@link useRowConfirm} is which surface it serves: this one\n * is for a SELF-CONTAINED menu that already sits inside a\n * `CardActionsProvider`, so it reads the refresh and the error channel from\n * context and answers the `{ ok, error }` envelope those actions use.\n * `useRowConfirm` is for a grid whose actions are declared as `RowAction[]` and\n * act on a selection.\n *\n * ```tsx\n * const remove = useRemoveConfirm({\n * write: () => deleteCategory({ tenantSlug, id: row.id }),\n * title: copy.deleteTitle,\n * entityName: row.name,\n * description: copy.deleteDescription,\n * confirmText: copy.delete,\n * fallbackError: copy.deleteFailed,\n * dataTestId: 'category-delete-confirm',\n * });\n * ```\n */\nexport function useRemoveConfirm({\n write,\n title,\n entityName,\n description,\n confirmText,\n fallbackError,\n dataTestId,\n}: RemoveConfirmOptions): RemoveConfirm {\n const { onRefresh, notifyError } = useCardActions();\n\n const state = useConfirmAction(async () => {\n const result = await write();\n if (!result.ok) {\n const message = result.error ?? fallbackError;\n notifyError(message);\n // Rejecting is what keeps the popup open carrying `message`; the snackbar\n // above is what remains once the operator dismisses it.\n throw new Error(message);\n }\n onRefresh();\n }, fallbackError);\n\n return {\n request: state.request,\n dialog: (\n <ConfirmActionDialog\n state={state}\n title={title}\n entityName={entityName}\n description={description}\n confirmText={confirmText}\n dataTestId={dataTestId}\n />\n ),\n };\n}\n"],"mappings":"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","names":["jsx","jsx","jsxs","useState","jsx","useState","jsx"]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/data-display/CardKit/CardKebab.tsx","../../src/components/data-display/CardKit/card-actions-context.tsx","../../src/components/data-display/CardKit/row-actions-to-menu.ts","../../src/components/data-display/CardKit/list-card-parts.tsx","../../src/components/data-display/CardKit/use-row-confirm.tsx","../../src/components/data-display/CardKit/use-remove-confirm.tsx"],"sourcesContent":["'use client';\n\nimport type { JSX } from 'react';\n\nimport { Button } from '../../form/Button';\nimport { DropdownMenu, type DropdownMenuItem } from '../../navigation/DropdownMenu';\n\n/**\n * The \"⋮\" trigger every row and card menu opens from.\n *\n * One component rather than a `DropdownMenu` per entity, so the kebab looks and\n * behaves identically in the card, in the list row and in the table row. The\n * entity's menu owns its own popups; this is the trigger and the item list.\n */\nexport function CardKebab({\n items,\n menuLabel,\n dataTestId,\n}: {\n items: DropdownMenuItem[];\n /**\n * The trigger's accessible name — required, and with no default.\n *\n * It is the only text this component renders, and a screen reader announces\n * it verbatim. A default here would be a word in the origin's language that\n * reads as finished to the next adopter right up until somebody using a\n * screen reader meets it.\n */\n menuLabel: string;\n dataTestId?: string;\n}): JSX.Element {\n return (\n <DropdownMenu\n size=\"sm\"\n items={items}\n trigger={\n <Button variant=\"text\" size=\"sm\" aria-label={menuLabel} dataTestId={dataTestId}>\n ⋮\n </Button>\n }\n />\n );\n}\n","'use client';\n\nimport { createContext, useCallback, useContext, useState, type JSX, type ReactNode } from 'react';\n\nimport { Snackbar } from '@mui/material';\n\nimport { Alert } from '../Alert';\n\n/**\n * The ambient wiring a self-contained row/card menu needs, and nothing else.\n *\n * A menu that owns its own popups still needs three things it cannot know: the\n * tenant it is acting inside, what to do after a write lands, and somewhere to\n * put a failure. Passing those down through the grid, the layout and the card\n * is four props of drilling per entity; holding them in context is one.\n *\n * Kept deliberately SMALL — it is not an edit-dialog host. A menu that read its\n * dialogs from here would stop being portable, because the set of dialogs is\n * per-entity. What it may read is the three facts below.\n *\n * The provider renders ONE shared error snackbar, which is the whole reason the\n * error channel is here rather than per-menu: before it, every page carried its\n * own error alert and every menu had to find its page's.\n */\ninterface CardActionsValue {\n /** The tenant every action in this subtree acts inside. */\n tenantSlug: string;\n /** Re-read the list after a write. */\n onRefresh: () => void;\n /** Surface a failed action's message (the shared snackbar). */\n notifyError: (message: string) => void;\n}\n\nconst CardActionsContext = createContext<CardActionsValue | null>(null);\n\nexport function CardActionsProvider({\n tenantSlug,\n onRefresh,\n errorTitle,\n autoHideMs = 6_000,\n children,\n}: {\n tenantSlug: string;\n onRefresh: () => void;\n /**\n * The snackbar's heading — required, no default.\n *\n * It is the one sentence this provider renders on its own, and a default\n * would be the origin's language shipped as a finished-looking silence. The\n * MESSAGE beside it comes from whatever failed, which is already the host's.\n */\n errorTitle: string;\n /** How long the snackbar stays up. */\n autoHideMs?: number;\n children: ReactNode;\n}): JSX.Element {\n const [error, setError] = useState<string | null>(null);\n const notifyError = useCallback((message: string) => setError(message), []);\n\n return (\n <CardActionsContext.Provider value={{ tenantSlug, onRefresh, notifyError }}>\n {children}\n <Snackbar\n open={error !== null}\n autoHideDuration={autoHideMs}\n onClose={() => setError(null)}\n anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}\n >\n <span>\n <Alert\n variant=\"danger\"\n title={errorTitle}\n description={error ?? ''}\n closable\n onClose={() => setError(null)}\n data-testid=\"card-action-error\"\n />\n </span>\n </Snackbar>\n </CardActionsContext.Provider>\n );\n}\n\n/**\n * Read the tenant + refresh + error wiring.\n *\n * THROWS outside a provider rather than answering a null object, deliberately:\n * a menu whose `onRefresh` silently did nothing would leave the operator\n * looking at a stale row after a delete that worked, which reads as the delete\n * having failed. Failing at mount says where the provider is missing.\n */\nexport function useCardActions(): CardActionsValue {\n const value = useContext(CardActionsContext);\n if (!value) {\n throw new Error('useCardActions must be used within a CardActionsProvider');\n }\n return value;\n}\n","import type { DropdownMenuItem } from '../../navigation/DropdownMenu';\nimport type { RowAction } from '../DataViews';\n\n/**\n * Adapt a list of {@link RowAction}s into single-row kebab items.\n *\n * Applies each action's `isVisible` guard, resolves its per-row `rowLabel`\n * override, carries its colour, and fires `onSelect([row])` on click.\n *\n * The point is that ONE definition drives both surfaces. An entity that already\n * declares its per-row actions as `RowAction[]` — because the table's multi-\n * select menu needs them — gets the card's kebab from the same array through\n * `renderRowMenu` / `renderCard`, with no second list to keep in step. Two\n * lists is how a \"Duplicar\" that appears in the table and not on the card\n * happens, and nothing reports it.\n */\nexport function rowActionsToMenuItems<T extends Record<string, unknown>>(\n actions: RowAction<T>[],\n row: T,\n): DropdownMenuItem[] {\n return actions\n .filter((action) => action.isVisible?.(row) ?? true)\n .map((action) => ({\n id: action.id,\n label: action.rowLabel?.(row) ?? action.label,\n color: action.color,\n onClick: () => void action.onSelect([row]),\n }));\n}\n","'use client';\n\nimport type { JSX, ReactNode } from 'react';\n\nimport { Box } from '../../../mui/Box';\n\nimport type { CardFactProps, CardLedgerLine } from './CardKit.types';\n\n/**\n * THE SHARED FURNITURE OF AN EXPANDED LIST-CARD BODY.\n *\n * `BaseListCard` says nothing about what goes inside a row's expanded area — it\n * spans the rails and stops, because the design belongs to the consumer. Right\n * for the card; wrong as the place where every entity in an admin app invents\n * its own two-column layout, its own label/value pair and its own ledger.\n *\n * So the four shapes that actually repeat live here, once. Nothing here knows a\n * domain: they take `ReactNode` and lay it out.\n */\n\n/** The expanded body's two-column split: detail on the left, a ledger right. */\nexport function DetailColumns({ left, right }: { left: ReactNode; right: ReactNode }): JSX.Element {\n return (\n <Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr', md: '1fr 1fr' }, gap: 3 }}>\n <Box sx={{ minWidth: 0 }}>{left}</Box>\n <Box sx={{ minWidth: 0 }}>{right}</Box>\n </Box>\n );\n}\n\n/**\n * One labelled fact inside an expanded body.\n *\n * Horizontal, not stacked: the body is already a wide area with room for a\n * label beside its value, and stacking them there would ape the summary rails\n * above without their alignment.\n */\nexport function Fact({ label, value }: CardFactProps): JSX.Element {\n return (\n <Box sx={{ display: 'flex', justifyContent: 'space-between', gap: 2, fontSize: 13, py: 0.25 }}>\n <Box component=\"span\" sx={{ color: 'text.secondary', flexShrink: 0 }}>\n {label}\n </Box>\n <Box component=\"span\" sx={{ minWidth: 0, textAlign: 'right', overflowWrap: 'anywhere' }}>\n {value}\n </Box>\n </Box>\n );\n}\n\n/**\n * A money ledger: rows of label/amount, then a ruled total.\n *\n * The total is separated by a RULE rather than by weight alone, because a\n * subtotal and a total in one column with only bold between them is the classic\n * misread — the eye lands on whichever number is larger.\n *\n * The figures arrive pre-formatted. This is a layout, and a component that\n * formatted money would be choosing a locale on the consumer's behalf.\n */\nexport function Ledger({\n lines,\n total,\n}: {\n lines: CardLedgerLine[];\n total: { label: string; value: ReactNode };\n}): JSX.Element {\n return (\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.25 }}>\n {lines.map((line) => (\n <Box\n key={line.label}\n sx={{\n display: 'flex',\n justifyContent: 'space-between',\n fontSize: 13,\n color: line.tone === 'info' ? 'info.main' : 'text.secondary',\n }}\n >\n <Box component=\"span\">{line.label}</Box>\n <Box component=\"span\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {line.value}\n </Box>\n </Box>\n ))}\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'space-between',\n fontWeight: 700,\n borderTop: 1,\n borderColor: 'divider',\n pt: 0.5,\n mt: 0.5,\n }}\n >\n <Box component=\"span\">{total.label}</Box>\n <Box component=\"span\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {total.value}\n </Box>\n </Box>\n </Box>\n );\n}\n\n/** A heading inside the expanded body, for a section that needs naming. */\nexport function BodyHeading({ children }: { children: ReactNode }): JSX.Element {\n return (\n <Box\n sx={{\n fontSize: 11,\n fontWeight: 700,\n letterSpacing: 0.4,\n textTransform: 'uppercase',\n color: 'text.disabled',\n mb: 0.5,\n }}\n >\n {children}\n </Box>\n );\n}\n\n/**\n * A wrapping run of small items — permission names, role names, target ids.\n *\n * The whole reason several entities earn a list card at all: a `string[]` has no\n * honest table cell. Truncated to \"3 items\" it says nothing; printed in full it\n * destroys the column. Here it simply wraps.\n */\nexport function TagList({\n items,\n empty,\n}: {\n items: readonly string[];\n /** What to show for an empty run — the consumer's sentence, no default. */\n empty: string;\n}): JSX.Element {\n if (items.length === 0) {\n return <Box sx={{ fontSize: 13, color: 'text.disabled' }}>{empty}</Box>;\n }\n return (\n <Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5 }}>\n {items.map((item) => (\n <Box\n key={item}\n component=\"span\"\n sx={{\n fontSize: 12,\n px: 0.75,\n py: 0.25,\n borderRadius: 1,\n bgcolor: 'action.hover',\n color: 'text.secondary',\n fontFamily: 'monospace',\n }}\n >\n {item}\n </Box>\n ))}\n </Box>\n );\n}\n","'use client';\n\nimport { useState, type JSX } from 'react';\n\nimport type { ConfirmActionCopy } from '../../../copy';\nimport { ConfirmActionDialog, useConfirmAction } from '../../feedback/ConfirmAction';\n\n/**\n * How the popup should read for the rows about to be acted on.\n *\n * Built from the SELECTION rather than from a single row, because the same\n * guard covers a bulk action: \"Delete 4 categories?\" and \"Delete the category\n * Drinks?\" are the same question asked of a different-sized selection — and an\n * operator who multi-selected by mistake is exactly who this popup is for.\n */\nexport interface RowConfirmCopy {\n title: string;\n description: string;\n /** Echoed into the popup; omit for a multi-row selection the title covers. */\n entityName?: string;\n /** The VERB. Required, never defaulted — see {@link useRowConfirm}. */\n confirmText: string;\n /** Override where the word \"cancel\" would mean the ACTION itself. */\n cancelText?: string;\n /** Require typing this before the confirm enables — for the unrecoverable few. */\n typeToConfirm?: string;\n}\n\ninterface RowConfirmOptions<T> {\n /**\n * The destructive write, over the whole selection. Called ONLY after the\n * operator confirms; throw (or reject) to keep the popup open carrying the\n * message.\n */\n write: (rows: T[]) => Promise<unknown>;\n /** The wording, given the selection. */\n describe: (rows: T[]) => RowConfirmCopy;\n dataTestId: string;\n /** Shown when `write` fails without a message of its own. */\n errorText: string;\n /** The dialog's own words. REQUIRED — this package ships no default copy. */\n copy: ConfirmActionCopy;\n}\n\nexport interface RowConfirm<T> {\n /** Hand this a grid action's `rows`: it opens the popup and writes nothing. */\n request: (rows: T[]) => void;\n /** Render next to the grid. */\n dialog: JSX.Element | null;\n}\n\n/**\n * Confirmation for a grid's `RowAction` — the per-row kebab entry and the\n * multi-select actions menu both, since they run the same handler.\n *\n * The SELECTION is held while the popup is open, so the write sees exactly the\n * rows the operator was looking at when they were asked. Re-reading the grid's\n * live selection at confirm time is the bug this shape avoids: the list can\n * refresh underneath an open dialog.\n *\n * `confirmText` is required and comes from `describe`, with no default. A verb\n * defaulted in the origin's language reads as finished to the next adopter\n * right up until an operator sees it — and `ConfirmOptions` already refuses to\n * default one for the same reason.\n */\nexport function useRowConfirm<T>({\n write,\n describe,\n dataTestId,\n errorText,\n copy,\n}: RowConfirmOptions<T>): RowConfirm<T> {\n const [target, setTarget] = useState<T[] | null>(null);\n\n const state = useConfirmAction(async () => {\n if (!target) return;\n await write(target);\n setTarget(null);\n }, errorText);\n\n const request = (rows: T[]): void => {\n // An empty selection has nothing to confirm — asking would be a popup about\n // nothing, and confirming it would write nothing.\n if (rows.length === 0) return;\n setTarget(rows);\n state.request();\n };\n\n return {\n request,\n dialog: target ? (\n <ConfirmActionDialog state={state}\n copy={copy} {...describe(target)} dataTestId={dataTestId} />\n ) : null,\n };\n}\n","'use client';\n\nimport type { ConfirmActionCopy } from \"../../../copy\";\nimport type { JSX } from 'react';\n\nimport { ConfirmActionDialog, useConfirmAction } from '../../feedback/ConfirmAction';\n\nimport { useCardActions } from './card-actions-context';\n\n/** The `{ ok, error }` envelope a write action answers with. */\nexport interface CardWriteResult {\n ok: boolean;\n error?: string;\n}\n\ninterface RemoveConfirmOptions {\n /** The destructive write. Called ONLY after the operator confirms. */\n write: () => Promise<CardWriteResult>;\n /** The popup's question. */\n title: string;\n /** The row being removed, echoed into the popup so it names a thing. */\n entityName: string;\n /**\n * What happens, and whether it can be walked back. Say which — the difference\n * between a soft delete a recycle bin recovers and one nothing recovers is\n * the whole content of the decision being asked for.\n */\n description: string;\n /** The confirm button's VERB. Required, never defaulted. */\n confirmText: string;\n /** Used when the write fails without a message of its own. */\n fallbackError: string;\n /** The dialog's own words. REQUIRED — this package ships no default copy. */\n copy: ConfirmActionCopy;\n dataTestId: string;\n}\n\ninterface RemoveConfirm {\n /** Hand this to the menu item's `onClick`: it opens the popup, nothing more. */\n request: () => void;\n /** Render alongside the trigger. */\n dialog: JSX.Element;\n}\n\n/**\n * The confirm-before-removing wiring every card/row menu repeats, in one place.\n *\n * It closes the three gaps a hand-rolled version keeps re-opening: the write\n * leaves ONLY on confirm; a refusal is surfaced twice — inside the popup, where\n * the operator is still deciding, and in the shared snackbar behind it — and a\n * failed attempt leaves the popup OPEN to be retried instead of vanishing over\n * a delete that never happened.\n *\n * The difference from {@link useRowConfirm} is which surface it serves: this one\n * is for a SELF-CONTAINED menu that already sits inside a\n * `CardActionsProvider`, so it reads the refresh and the error channel from\n * context and answers the `{ ok, error }` envelope those actions use.\n * `useRowConfirm` is for a grid whose actions are declared as `RowAction[]` and\n * act on a selection.\n *\n * ```tsx\n * const remove = useRemoveConfirm({\n * write: () => deleteCategory({ tenantSlug, id: row.id }),\n * title: copy.deleteTitle,\n * entityName: row.name,\n * description: copy.deleteDescription,\n * confirmText: copy.delete,\n * fallbackError: copy.deleteFailed,\n * dataTestId: 'category-delete-confirm',\n * });\n * ```\n */\nexport function useRemoveConfirm({\n write,\n title,\n entityName,\n description,\n confirmText,\n fallbackError,\n dataTestId,\n copy,\n}: RemoveConfirmOptions): RemoveConfirm {\n const { onRefresh, notifyError } = useCardActions();\n\n const state = useConfirmAction(async () => {\n const result = await write();\n if (!result.ok) {\n const message = result.error ?? fallbackError;\n notifyError(message);\n // Rejecting is what keeps the popup open carrying `message`; the snackbar\n // above is what remains once the operator dismisses it.\n throw new Error(message);\n }\n onRefresh();\n }, fallbackError);\n\n return {\n request: state.request,\n dialog: (\n <ConfirmActionDialog\n state={state}\n copy={copy}\n title={title}\n entityName={entityName}\n description={description}\n confirmText={confirmText}\n dataTestId={dataTestId}\n />\n ),\n };\n}\n"],"mappings":"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","names":["jsx","jsx","jsxs","useState","jsx","useState","jsx"]}
|