@12-apps/ui 6.3.0 → 6.4.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.
Files changed (79) hide show
  1. package/dist/{chunk-MXPXKORR.js → chunk-5TCPZ6GR.js} +8 -6
  2. package/dist/chunk-5TCPZ6GR.js.map +1 -0
  3. package/dist/{chunk-R5ZQZSEQ.js → chunk-NUCLEOHF.js} +12 -6
  4. package/dist/chunk-NUCLEOHF.js.map +1 -0
  5. package/dist/{chunk-TPQRIPCN.js → chunk-ZF5ERIC4.js} +7 -6
  6. package/dist/chunk-ZF5ERIC4.js.map +1 -0
  7. package/dist/data-display/CardKit.js +1 -1
  8. package/dist/data-display/DataViews.js +28 -22
  9. package/dist/data-display/DataViews.js.map +1 -1
  10. package/dist/feedback/ConfirmAction.js +1 -1
  11. package/dist/form/CategorySelect.js +1 -1
  12. package/dist/form/CreatableSelect.js +1 -1
  13. package/dist/form/CreatableSelect.js.map +1 -1
  14. package/dist/form/SearchPalette.js +3 -4
  15. package/dist/form/SearchPalette.js.map +1 -1
  16. package/dist/form/total-form.js +1 -1
  17. package/dist/layout/ContentToolbar.js +1 -1
  18. package/dist/pt-BR.js +23 -4
  19. package/dist/pt-BR.js.map +1 -1
  20. package/dist/types/components/data-display/DataViews/DataViewsBoard.d.ts.map +1 -1
  21. package/dist/types/components/data-display/DataViews/data-views-category-pill.d.ts.map +1 -1
  22. package/dist/types/components/data-display/DataViews/data-views-copy.d.ts +38 -1
  23. package/dist/types/components/data-display/DataViews/data-views-copy.d.ts.map +1 -1
  24. package/dist/types/components/data-display/DataViews/data-views-empty.d.ts.map +1 -1
  25. package/dist/types/components/data-display/DataViews/data-views-more-fields.d.ts.map +1 -1
  26. package/dist/types/components/data-display/DataViews/data-views-more-filters.d.ts.map +1 -1
  27. package/dist/types/components/data-display/DataViews/data-views-range-pill.d.ts.map +1 -1
  28. package/dist/types/components/data-display/DataViews/data-views-toolbar.d.ts.map +1 -1
  29. package/dist/types/components/feedback/ConfirmAction/ConfirmAction.parts.d.ts.map +1 -1
  30. package/dist/types/components/form/CategorySelect/CategoryQuickActions.d.ts +4 -1
  31. package/dist/types/components/form/CategorySelect/CategoryQuickActions.d.ts.map +1 -1
  32. package/dist/types/components/form/CreatableSelect/CreatableSelect.d.ts.map +1 -1
  33. package/dist/types/components/form/CreatableSelect/CreatableSelect.types.d.ts +2 -1
  34. package/dist/types/components/form/CreatableSelect/CreatableSelect.types.d.ts.map +1 -1
  35. package/dist/types/components/form/SearchPalette/SearchPalette.d.ts.map +1 -1
  36. package/dist/types/components/form/SearchPalette/SearchPalette.types.d.ts +3 -3
  37. package/dist/types/components/form/SearchPalette/SearchPalette.types.d.ts.map +1 -1
  38. package/dist/types/components/layout/ContentToolbar/ContentToolbar.d.ts +1 -1
  39. package/dist/types/components/layout/ContentToolbar/ContentToolbar.d.ts.map +1 -1
  40. package/dist/types/components/layout/ContentToolbar/ContentToolbar.types.d.ts +12 -0
  41. package/dist/types/components/layout/ContentToolbar/ContentToolbar.types.d.ts.map +1 -1
  42. package/dist/types/components/layout/ContentToolbar/MultiSelectDropdown.d.ts +1 -1
  43. package/dist/types/components/layout/ContentToolbar/MultiSelectDropdown.d.ts.map +1 -1
  44. package/dist/types/components/layout/ContentToolbar/MultiSelectTriggers.d.ts +10 -2
  45. package/dist/types/components/layout/ContentToolbar/MultiSelectTriggers.d.ts.map +1 -1
  46. package/dist/types/copy.d.ts +22 -0
  47. package/dist/types/copy.d.ts.map +1 -1
  48. package/dist/types/pt-BR.d.ts.map +1 -1
  49. package/package.json +1 -1
  50. package/src/components/data-display/DataViews/DataViewsBoard.tsx +2 -1
  51. package/src/components/data-display/DataViews/DeleteViewDialog.tsx +2 -2
  52. package/src/components/data-display/DataViews/ManageViewsDialog.tsx +1 -1
  53. package/src/components/data-display/DataViews/data-views-category-pill.tsx +1 -0
  54. package/src/components/data-display/DataViews/data-views-columns-tab.tsx +4 -3
  55. package/src/components/data-display/DataViews/data-views-copy.ts +38 -1
  56. package/src/components/data-display/DataViews/data-views-empty.tsx +6 -3
  57. package/src/components/data-display/DataViews/data-views-more-fields.tsx +3 -1
  58. package/src/components/data-display/DataViews/data-views-more-filters.tsx +2 -1
  59. package/src/components/data-display/DataViews/data-views-range-pill.tsx +2 -1
  60. package/src/components/data-display/DataViews/data-views-toolbar.tsx +3 -0
  61. package/src/components/data-display/DataViews/data-views-view-nav.tsx +2 -2
  62. package/src/components/feedback/ConfirmAction/ConfirmAction.parts.tsx +14 -3
  63. package/src/components/form/CategorySelect/CategoryPanel.tsx +1 -1
  64. package/src/components/form/CategorySelect/CategoryQuickActions.tsx +7 -2
  65. package/src/components/form/CategorySelect/CategorySelect.tsx +1 -1
  66. package/src/components/form/CreatableSelect/CreatableSelect.md +2 -2
  67. package/src/components/form/CreatableSelect/CreatableSelect.tsx +1 -1
  68. package/src/components/form/CreatableSelect/CreatableSelect.types.ts +2 -1
  69. package/src/components/form/SearchPalette/SearchPalette.tsx +3 -4
  70. package/src/components/form/SearchPalette/SearchPalette.types.ts +3 -3
  71. package/src/components/layout/ContentToolbar/ContentToolbar.tsx +13 -2
  72. package/src/components/layout/ContentToolbar/ContentToolbar.types.ts +12 -0
  73. package/src/components/layout/ContentToolbar/MultiSelectDropdown.tsx +2 -0
  74. package/src/components/layout/ContentToolbar/MultiSelectTriggers.tsx +15 -2
  75. package/src/copy.ts +22 -0
  76. package/src/pt-BR.ts +19 -0
  77. package/dist/chunk-MXPXKORR.js.map +0 -1
  78. package/dist/chunk-R5ZQZSEQ.js.map +0 -1
  79. package/dist/chunk-TPQRIPCN.js.map +0 -1
@@ -60,9 +60,12 @@ function TypeToConfirmField({
60
60
  onChange,
61
61
  disabled,
62
62
  dataTestId,
63
+ copy,
63
64
  }: {
64
65
  expected: string;
65
66
  label?: string;
67
+ /** The words this prompt renders. REQUIRED — no default copy. */
68
+ copy: ConfirmActionCopy;
66
69
  value: string;
67
70
  onChange: (next: string) => void;
68
71
  disabled: boolean;
@@ -71,7 +74,7 @@ function TypeToConfirmField({
71
74
  return (
72
75
  <Stack spacing={1} sx={{ mt: 2 }}>
73
76
  <Typography variant="body2" color="text.secondary">
74
- {label ?? `Digite "${expected}" para confirmar.`}
77
+ {label ?? copy.typeToConfirm(expected)}
75
78
  </Typography>
76
79
  <TextField
77
80
  size="small"
@@ -81,7 +84,7 @@ function TypeToConfirmField({
81
84
  // On the INPUT rather than the wrapper: a test id on MUI's TextField
82
85
  // lands on the outer div, which is not the node a test can type into.
83
86
  inputProps={{
84
- 'aria-label': label ?? `Digite ${expected} para confirmar`,
87
+ 'aria-label': label ?? copy.typeToConfirm(expected),
85
88
  'data-testid': `${dataTestId}-type-to-confirm`,
86
89
  }}
87
90
  />
@@ -132,7 +135,14 @@ export function ConfirmActionDialog({
132
135
  title={title}
133
136
  description={confirmBody(description, copy, entityName)}
134
137
  confirmText={confirmText}
135
- cancelText={cancelText}
138
+ // `copy.cancel` is the fallback, NOT `AlertDialog`'s own. The 6.3.0 copy
139
+ // sweep deleted this component's `cancelText = 'Cancelar'` default and
140
+ // put the word in `ConfirmActionCopy` — where nothing then read it, so
141
+ // every confirmation that names no `cancelText` of its own fell through
142
+ // to `AlertDialog`'s English `'Cancel'`, in a pt-BR dialog. That is the
143
+ // precise failure the sweep exists to prevent, one layer down: a port
144
+ // that is required, supplied, and ignored.
145
+ cancelText={cancelText ?? copy.cancel}
136
146
  loading={state.pending}
137
147
  confirmDisabled={gateUnmet}
138
148
  initialFocus={resolveInitialFocus(tone, initialFocus)}
@@ -154,6 +164,7 @@ export function ConfirmActionDialog({
154
164
  onChange={setTyped}
155
165
  disabled={state.pending}
156
166
  dataTestId={dataTestId}
167
+ copy={copy}
157
168
  />
158
169
  )}
159
170
  </AlertDialog>
@@ -74,7 +74,7 @@ export function CategoryPanel({
74
74
  placeholder={single ? copy.search.placeholderSingle : copy.search.placeholderMulti}
75
75
  sheet={sheet}
76
76
  quickActions={
77
- single ? undefined : <CategoryQuickActions state={state} dataTestId={dataTestId} />
77
+ single ? undefined : <CategoryQuickActions state={state} dataTestId={dataTestId} copy={copy} />
78
78
  }
79
79
  onQueryChange={state.setQuery}
80
80
  searchInputRef={searchInputRef}
@@ -3,6 +3,8 @@
3
3
  import { Box } from '@mui/material';
4
4
  import { useMemo } from 'react';
5
5
 
6
+ import type { CategorySelectCopy } from '../../../copy';
7
+
6
8
  import { collectLeafIds } from './category-tree';
7
9
  import type { CategorySelectState } from './useCategorySelect';
8
10
 
@@ -30,9 +32,12 @@ const linkButtonSx = {
30
32
  export function CategoryQuickActions({
31
33
  state,
32
34
  dataTestId,
35
+ copy,
33
36
  }: {
34
37
  state: CategorySelectState;
35
38
  dataTestId: string;
39
+ /** The words this control renders. REQUIRED — no default copy. */
40
+ copy: CategorySelectCopy;
36
41
  }): React.JSX.Element {
37
42
  const allLeafIds = useMemo(() => collectLeafIds(state.allGroups), [state.allGroups]);
38
43
  const everythingPicked = allLeafIds.length > 0 && state.draft.size >= allLeafIds.length;
@@ -50,7 +55,7 @@ export function CategoryQuickActions({
50
55
  sx={linkButtonSx}
51
56
  onClick={() => state.setDraft(everythingPicked ? new Set() : new Set(allLeafIds))}
52
57
  >
53
- {everythingPicked ? 'Desmarcar tudo' : 'Marcar tudo'}
58
+ {everythingPicked ? copy.deselectAll : copy.selectAll}
54
59
  </Box>
55
60
  <Box component="span" sx={{ color: 'divider' }}>
56
61
  ·
@@ -62,7 +67,7 @@ export function CategoryQuickActions({
62
67
  sx={linkButtonSx}
63
68
  onClick={() => state.setAllExpanded(!allExpanded)}
64
69
  >
65
- {allExpanded ? 'Recolher tudo' : 'Expandir tudo'}
70
+ {allExpanded ? copy.collapseAll : copy.expandAll}
66
71
  </Box>
67
72
  </>
68
73
  );
@@ -51,7 +51,7 @@ function resolveConfig(props: CategorySelectProps): ResolvedConfig {
51
51
  const single = props.mode === 'single';
52
52
  return {
53
53
  single,
54
- placeholder: props.placeholder ?? (single ? 'Mover para…' : 'Categoria'),
54
+ placeholder: props.placeholder ?? (single ? props.copy.placeholderSingle : props.copy.placeholderMulti),
55
55
  disabled: props.disabled ?? false,
56
56
  loading: props.loading ?? false,
57
57
  fullWidth: props.fullWidth ?? false,
@@ -21,7 +21,7 @@ Type to filter the options; when the typed text matches nothing, an optional
21
21
  - **onCreate** (`(label: string) => void | Promise<void>`): enables create-on-Enter. When the typed text matches no option, a create row appears; choosing it calls `onCreate` with the raw text. The parent persists it and feeds the new option back through `options`/`value`. Omit to make the field a plain searchable select.
22
22
  - **label** (`string`): field label.
23
23
  - **placeholder** (`string`): placeholder shown when empty.
24
- - **createOptionLabel** (`(input: string) => string`): builds the create-row label (default: `Criar "<input>"`).
24
+ - **createOptionLabel** (`(input: string) => string`, REQUIRED): builds the create-row label. No default — a pt-BR one used to ship, which is how a host in any other language inherited it silently (FUT-760).
25
25
  - **noOptionsText** (`string`): text shown when nothing matches and creation is disabled.
26
26
  - **disabled** (`boolean`): disable the field.
27
27
  - **loading** (`boolean`): show a spinner in the adornment (e.g. while a create request is in flight).
@@ -71,7 +71,7 @@ Type to filter the options; when the typed text matches nothing, an optional
71
71
  1. Keep `options` in sync after `onCreate` resolves — append the created option and
72
72
  set `value` to it so the new selection sticks.
73
73
  2. Use `loading` while the create request is in flight to signal progress.
74
- 3. Provide a localized `createOptionLabel` when the UI language isn't Portuguese.
74
+ 3. `createOptionLabel` is required, so the create-row label is always the host’s own.
75
75
  4. Omit `onCreate` entirely when free creation is not allowed — the field then
76
76
  behaves as a plain searchable select and shows `noOptionsText`.
77
77
 
@@ -185,7 +185,7 @@ export function CreatableSelect({
185
185
  label,
186
186
  error,
187
187
  placeholder,
188
- createOptionLabel = (input) => `Criar "${input}"`,
188
+ createOptionLabel,
189
189
  noOptionsText,
190
190
  disabled = false,
191
191
  loading = false,
@@ -33,7 +33,8 @@ export interface CreatableSelectProps {
33
33
  /** Placeholder shown when empty. */
34
34
  placeholder?: string;
35
35
  /** Builds the create-row label from the typed text (default: `Criar "<text>"`). */
36
- createOptionLabel?: (input: string) => string;
36
+ /** How a new option is offered, naming what was typed. REQUIRED — no default copy. */
37
+ createOptionLabel: (input: string) => string;
37
38
  /** Text shown when no option matches and creation is disabled. */
38
39
  noOptionsText?: string;
39
40
  disabled?: boolean;
@@ -27,7 +27,6 @@ import type { SearchPaletteProps } from './SearchPalette.types';
27
27
  */
28
28
 
29
29
  const DEFAULT_MAX_ITEMS = 5;
30
- const defaultSubmitLabel = (q: string): string => `Todos os resultados para "${q}"`;
31
30
 
32
31
  /** Non-string option defaults (numbers / flags / arrays). */
33
32
  function resolveOpts<T>(props: SearchPaletteProps<T>): {
@@ -56,9 +55,9 @@ function resolveText<T>(props: SearchPaletteProps<T>): {
56
55
  dataTestId: string;
57
56
  } {
58
57
  return {
59
- submitAllLabel: props.submitAllLabel ?? defaultSubmitLabel,
60
- noResultsLabel: props.noResultsLabel ?? 'Nenhum resultado encontrado',
61
- placeholder: props.placeholder ?? 'Buscar…',
58
+ submitAllLabel: props.submitAllLabel,
59
+ noResultsLabel: props.noResultsLabel,
60
+ placeholder: props.placeholder,
62
61
  dataTestId: props.dataTestId ?? 'search-palette',
63
62
  };
64
63
  }
@@ -55,7 +55,7 @@ export interface SearchPaletteProps<T> {
55
55
  /** Footer "see all results" action; hidden when omitted. */
56
56
  onSubmitAll?: (query: string) => void;
57
57
  /** Footer label builder; defaults to `Todos os resultados para "{q}"`. */
58
- submitAllLabel?: (query: string) => string;
58
+ submitAllLabel: (query: string) => string;
59
59
 
60
60
  /**
61
61
  * Content shown when the query is empty (e.g. a "Populares" block). Keeps the
@@ -63,7 +63,7 @@ export interface SearchPaletteProps<T> {
63
63
  */
64
64
  emptyQueryContent?: React.ReactNode;
65
65
  /** Message when a non-empty query yields no items. */
66
- noResultsLabel?: string;
66
+ noResultsLabel: string;
67
67
 
68
68
  /** Loading spinner in the input while results resolve. */
69
69
  isLoading?: boolean;
@@ -71,7 +71,7 @@ export interface SearchPaletteProps<T> {
71
71
  showGhostText?: boolean;
72
72
  /** Autofocus the input on mount. */
73
73
  autoFocus?: boolean;
74
- placeholder?: string;
74
+ placeholder: string;
75
75
  inputAriaLabel?: string;
76
76
  /** Esc handler (host closes the overlay). */
77
77
  onClose?: () => void;
@@ -19,7 +19,15 @@ const selectionButtonSx = {
19
19
 
20
20
  type SelectionClusterProps = Pick<
21
21
  ContentToolbarProps,
22
- 'hasSelection' | 'selectedCount' | 'selectAll' | 'clearSelection' | 'actions' | 'selectAllTestId' | 'clearAllTestId' | 'edgeAlign'
22
+ | 'hasSelection'
23
+ | 'selectedCount'
24
+ | 'selectAll'
25
+ | 'clearSelection'
26
+ | 'actions'
27
+ | 'selectAllTestId'
28
+ | 'clearAllTestId'
29
+ | 'edgeAlign'
30
+ | 'selectAllLabel'
23
31
  >;
24
32
 
25
33
  /** The left cluster: Select All + (when selecting) Clear All / count / actions. */
@@ -32,6 +40,7 @@ function SelectionCluster({
32
40
  selectAllTestId,
33
41
  clearAllTestId,
34
42
  edgeAlign = false,
43
+ selectAllLabel,
35
44
  }: SelectionClusterProps): React.JSX.Element {
36
45
  const actionsSlot = actions !== undefined && (
37
46
  <Box sx={{ ml: 0.5, display: 'flex', flexShrink: 0, alignItems: 'center' }}>{actions}</Box>
@@ -66,7 +75,7 @@ function SelectionCluster({
66
75
  checked={hasSelection}
67
76
  onChange={(event) => (event.target.checked ? selectAll() : clearSelection())}
68
77
  data-testid={`${selectAllTestId}-checkbox`}
69
- inputProps={{ 'aria-label': 'Selecionar todos' }}
78
+ inputProps={{ 'aria-label': selectAllLabel }}
70
79
  sx={{ p: 0.5, display: { xs: 'inline-flex', md: 'none' } }}
71
80
  />
72
81
  {hasSelection ? (
@@ -206,6 +215,7 @@ export function ContentToolbar({
206
215
  clearAllTestId,
207
216
  edgeAlign = false,
208
217
  exclusiveSelection = false,
218
+ selectAllLabel,
209
219
  }: ContentToolbarProps): React.JSX.Element {
210
220
  // Under `exclusiveSelection` the two states are alternatives, not neighbours:
211
221
  // browsing shows the controls and no checkbox, selecting shows the checkbox
@@ -238,6 +248,7 @@ export function ContentToolbar({
238
248
  actions={actions}
239
249
  selectAllTestId={selectAllTestId}
240
250
  clearAllTestId={clearAllTestId}
251
+ selectAllLabel={selectAllLabel}
241
252
  edgeAlign={edgeAlign}
242
253
  />
243
254
  )}
@@ -4,6 +4,12 @@ import type { ReactNode } from 'react';
4
4
 
5
5
  /** Props for {@link ContentToolbar} — the shared content-page toolbar. */
6
6
  export interface ContentToolbarProps {
7
+ /**
8
+ * The select-all checkbox's accessible name. It carries no visible label of
9
+ * its own, so this is the only thing a screen reader gets for it. REQUIRED:
10
+ * this package ships no default copy.
11
+ */
12
+ selectAllLabel: string;
7
13
  /** Whether the page is in selection mode (shows Clear All + count + actions). */
8
14
  hasSelection: boolean;
9
15
  /** Number of currently selected items. */
@@ -129,6 +135,12 @@ export interface MultiSelectDropdownProps<TValue extends string = string> {
129
135
  onClear: () => void;
130
136
  /** Text when nothing or everything is selected. @default "All" */
131
137
  allLabel?: string;
138
+ /**
139
+ * The clear affordance's accessible name. The pill's own label is already on
140
+ * screen, so this is all a screen reader gets for the little cross.
141
+ * REQUIRED: this package ships no default copy.
142
+ */
143
+ clearLabel: string;
132
144
  /** Extra toggles under a labelled "Options" section. */
133
145
  extraOptions?: MultiSelectExtraOption[];
134
146
  /**
@@ -61,6 +61,7 @@ export function MultiSelectDropdown<TValue extends string = string>({
61
61
  onToggle,
62
62
  onClear,
63
63
  allLabel = 'All',
64
+ clearLabel,
64
65
  extraOptions,
65
66
  searchable,
66
67
  searchPlaceholder = 'Search…',
@@ -96,6 +97,7 @@ export function MultiSelectDropdown<TValue extends string = string>({
96
97
  if (layout === 'pill')
97
98
  return (
98
99
  <PillTrigger
100
+ clearLabel={clearLabel}
99
101
  label={label}
100
102
  selectedCount={selected.size}
101
103
  onClear={onClear}
@@ -102,6 +102,18 @@ export function StackedTrigger({ label, triggerLabel, open, onOpen, testId }: Tr
102
102
  }
103
103
 
104
104
  /** Rounded outlined chip (`Label ▾`, `Label (N) ▾` when selected) for a filter row. */
105
+ /** The pill's own props, above the component so the signature stays short. */
106
+ export type PillTriggerProps = TriggerProps & {
107
+ selectedCount: number;
108
+ onClear?: () => void;
109
+ /**
110
+ * The clear affordance's accessible name — the pill's own label is already
111
+ * on screen, so this is the only thing a screen reader gets for the little
112
+ * cross. REQUIRED: this package ships no default copy.
113
+ */
114
+ clearLabel: string;
115
+ };
116
+
105
117
  export function PillTrigger({
106
118
  label,
107
119
  open,
@@ -109,7 +121,8 @@ export function PillTrigger({
109
121
  testId,
110
122
  selectedCount,
111
123
  onClear,
112
- }: TriggerProps & { selectedCount: number; onClear?: () => void }): React.JSX.Element {
124
+ clearLabel,
125
+ }: PillTriggerProps): React.JSX.Element {
113
126
  const active = selectedCount > 0;
114
127
  return (
115
128
  <Button
@@ -129,7 +142,7 @@ export function PillTrigger({
129
142
  component="span"
130
143
  role="button"
131
144
  tabIndex={0}
132
- aria-label={`Limpar ${label}`}
145
+ aria-label={clearLabel}
133
146
  data-testid={testId ? `${testId}-clear` : undefined}
134
147
  onClick={(event: React.MouseEvent) => {
135
148
  // The pill's own click opens the menu; clearing must not.
package/src/copy.ts CHANGED
@@ -33,6 +33,12 @@ export interface ConfirmActionCopy {
33
33
  * never guesses a noun for someone else's rows.
34
34
  */
35
35
  irreversible: string;
36
+ /**
37
+ * The typed-confirmation prompt, naming the exact word that unlocks the
38
+ * button. A function because where that word sits in the sentence, and how
39
+ * it is quoted, is the translator's call.
40
+ */
41
+ typeToConfirm(expected: string): string;
36
42
  }
37
43
 
38
44
  export interface CategorySelectCopy {
@@ -45,6 +51,22 @@ export interface CategorySelectCopy {
45
51
  */
46
52
  purpose: string;
47
53
  clearSelection: string;
54
+ /**
55
+ * The quick actions above the tree. Each toggles as a PAIR, and each label
56
+ * says what pressing it will do rather than what state the list is in — so a
57
+ * translator needs both halves, not one plus a negation.
58
+ */
59
+ selectAll: string;
60
+ deselectAll: string;
61
+ expandAll: string;
62
+ collapseAll: string;
63
+ /**
64
+ * What the closed control invites, and it differs by mode: picking ONE
65
+ * category is a move, picking several is a filter. Both were pt-BR defaults
66
+ * behind an optional prop, which is the arrangement this port removes.
67
+ */
68
+ placeholderSingle: string;
69
+ placeholderMulti: string;
48
70
  /** The empty state, when the host has no categories at all. */
49
71
  emptyTitle: string;
50
72
  createCategory: string;
package/src/pt-BR.ts CHANGED
@@ -26,11 +26,18 @@ export const PT_BR_CONFIRM_ACTION_COPY: ConfirmActionCopy = {
26
26
  cancel: "Cancelar",
27
27
  defaultError: "Não foi possível concluir a ação. Tente novamente.",
28
28
  irreversible: "Esta ação não pode ser desfeita.",
29
+ typeToConfirm: (expected) => `Digite "${expected}" para confirmar.`,
29
30
  };
30
31
 
31
32
  export const PT_BR_CATEGORY_SELECT_COPY: CategorySelectCopy = {
32
33
  purpose: "Categorias organizam o cardápio e os filtros da loja.",
33
34
  clearSelection: "Limpar seleção",
35
+ selectAll: "Marcar tudo",
36
+ deselectAll: "Desmarcar tudo",
37
+ expandAll: "Expandir tudo",
38
+ collapseAll: "Recolher tudo",
39
+ placeholderSingle: "Mover para…",
40
+ placeholderMulti: "Categoria",
34
41
  emptyTitle: "Nenhuma categoria ainda",
35
42
  createCategory: "Criar categoria",
36
43
  noResults: {
@@ -102,19 +109,23 @@ export const PT_BR_DATA_VIEWS_COPY: DataViewsCopy = {
102
109
  countOnPage: (label, count) => `${label}: ${count} nesta página`,
103
110
  onThisPage: (count) => `${count} nesta página`,
104
111
  pageSum: (sum) => `Soma desta página: ${sum}`,
112
+ emptyColumn: "Nada nesta etapa",
105
113
  pageScopeNote:
106
114
  "As contagens e somas abaixo referem-se apenas aos itens desta página.",
107
115
  },
108
116
  deleteView: {
109
117
  title: "Excluir visão",
118
+ target: (viewName) => `Excluir "${viewName}"?`,
110
119
  sharedWarning: "Esta visão está compartilhada — a equipe perderá o acesso a ela.",
111
120
  rowsUnaffected: (entityLabel) =>
112
121
  `${entityLabel} não são afetados; apenas o recorte salvo é removido.`,
113
122
  confirm: "Excluir visão",
123
+ cancel: "Cancelar",
114
124
  },
115
125
  manageViews: {
116
126
  title: "Gerenciar visões",
117
127
  empty: "Nenhuma visão salva.",
128
+ edit: "Editar",
118
129
  defaultTag: "Padrão",
119
130
  otherUserTag: "De outro usuário",
120
131
  deleteTitle: "Excluir a visão salva?",
@@ -148,6 +159,9 @@ export const PT_BR_DATA_VIEWS_COPY: DataViewsCopy = {
148
159
  visibleCount: (visible, total) => `${visible} de ${total} visíveis`,
149
160
  reset: "Padrão",
150
161
  showAll: "Mostrar todas",
162
+ dragHint: "Arraste para reordenar as colunas.",
163
+ moveUp: (columnLabel) => `Mover ${columnLabel} para cima`,
164
+ moveDown: (columnLabel) => `Mover ${columnLabel} para baixo`,
151
165
  },
152
166
  display: {
153
167
  sortTab: "Ordenar",
@@ -187,6 +201,9 @@ export const PT_BR_DATA_VIEWS_COPY: DataViewsCopy = {
187
201
  grid: {
188
202
  rowActions: "Ações",
189
203
  bulkActions: (selectedCount) => `Ações (${selectedCount}) ▾`,
204
+ emptyFilteredTitle: "Nenhum resultado para esses filtros",
205
+ emptyFilteredHint: "Ajuste ou remova os filtros.",
206
+ emptyFilteredAction: "Limpar filtros",
190
207
  },
191
208
  filters: {
192
209
  moreFilters: (count) => `Mais filtros: ${count} sem espaço na barra`,
@@ -229,6 +246,8 @@ export const PT_BR_DATA_VIEWS_COPY: DataViewsCopy = {
229
246
  label: "Visão",
230
247
  update: "Atualizar visão",
231
248
  save: "Salvar visão",
249
+ saveAs: "Salvar como nova",
250
+ reset: "Redefinir",
232
251
  updateFailed: "Não foi possível atualizar a visão",
233
252
  saveFailed: "Não foi possível salvar a alteração da visão.",
234
253
  editView: "Renomear e editar",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/feedback/ConfirmAction/ConfirmAction.hooks.ts","../src/components/feedback/ConfirmAction/ConfirmAction.parts.tsx","../src/components/feedback/ConfirmAction/ConfirmAction.tsx","../src/components/feedback/ConfirmAction/with-confirmation.tsx","../src/components/feedback/ConfirmAction/ConfirmButton.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nimport type { ConfirmHandler, UseConfirmActionResult } from './ConfirmAction.types';\n\n/** Used when the guarded action rejects and the caller supplied no wording. */\n\n\n/**\n * What the popup says after a failed attempt.\n *\n * A rejection carrying a message wins: the server's sentence (\"esta categoria\n * ainda tem produtos vinculados\") is the one the operator can act on, and it is\n * strictly better than the generic fallback. Handlers that have nothing useful\n * to say reject with nothing and get `errorText`.\n */\nfunction failureMessage(cause: unknown, errorText: string): string {\n if (cause instanceof Error && cause.message) return cause.message;\n return errorText;\n}\n\n/**\n * The confirmation state machine, headless.\n *\n * It is the whole safety contract in one place, so every consumer gets the same\n * behaviour: the action runs ONLY from `confirm`, never from opening the popup;\n * a second confirm while the first is in flight is dropped (a double-click\n * cannot send two deletes); a rejection keeps the popup open carrying the\n * failure instead of closing over a write that never happened.\n */\nexport function useConfirmAction(\n onConfirm: ConfirmHandler,\n errorText: string,\n): UseConfirmActionResult {\n const [open, setOpen] = useState(false);\n const [pending, setPending] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n // `pending` is mirrored in a ref because the two guards that matter — drop a\n // second confirm, ignore a cancel mid-flight — are read inside callbacks that\n // must not be rebuilt on every state change. Reading the state variable there\n // would leave a stale closure holding `false` for the whole in-flight window,\n // which is exactly the double-submit this component exists to prevent.\n const busy = useRef(false);\n\n // The action can settle after the trigger has unmounted (a row deleted from\n // under its own menu), so the settle path must not touch state by then.\n const mounted = useRef(true);\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n };\n }, []);\n\n const request = useCallback((): void => {\n setError(null);\n setOpen(true);\n }, []);\n\n const cancel = useCallback((): void => {\n // Inert mid-flight: the write has already left, and closing here would hide\n // its outcome.\n if (busy.current) return;\n setOpen(false);\n setError(null);\n }, []);\n\n const settle = useCallback((failure: string | null): void => {\n busy.current = false;\n if (!mounted.current) return;\n setPending(false);\n setError(failure);\n if (!failure) setOpen(false);\n }, []);\n\n const confirm = useCallback((): void => {\n if (busy.current) return;\n busy.current = true;\n setPending(true);\n setError(null);\n // The handler is invoked synchronously, exactly as a plain `onClick` would\n // be — only the OUTCOME is awaited. The try/catch is what puts a handler\n // that throws synchronously on the same failure path as one that returns a\n // rejected promise.\n try {\n const result = onConfirm();\n void Promise.resolve(result)\n .then(() => settle(null))\n .catch((cause: unknown) => settle(failureMessage(cause, errorText)));\n } catch (cause) {\n settle(failureMessage(cause, errorText));\n }\n }, [errorText, onConfirm, settle]);\n\n return { open, pending, error, request, cancel, confirm };\n}\n","import type { ConfirmActionCopy } from \"../../../copy\";\nimport { Alert, Stack, TextField, Typography } from '@mui/material';\nimport React, { type ReactNode } from 'react';\n\nimport { AlertDialog } from '../../data-display/AlertDialog';\n\nimport type {\n ConfirmInitialFocus,\n ConfirmOptions,\n ConfirmTone,\n UseConfirmActionResult,\n} from './ConfirmAction.types';\n\nconst DEFAULT_TEST_ID = 'confirm-action';\n\n/**\n * The popup's body: the row being acted on, then what happens to it.\n *\n * The NAME is rendered in its own right rather than woven into the sentence, so\n * it is there whatever the caller wrote — \"the popup names the specific entity\"\n * is the one thing that must not depend on each call site remembering to\n * mention it. A body with neither a name nor a description would leave the\n * operator with only the title to decide on, so a neutral fallback covers that.\n */\nfunction confirmBody(\n description: ReactNode,\n copy: ConfirmActionCopy,\n entityName?: string,\n): ReactNode {\n if (!entityName) return description ?? copy.irreversible;\n return (\n <>\n <Typography component=\"span\" sx={{ fontWeight: 600, display: \"block\" }}>\n {entityName}\n </Typography>\n {description}\n </>\n );\n}\n\n/** Destructive dialogs open on Cancel; anything else opens on the confirm. */\nfunction resolveInitialFocus(\n tone: ConfirmTone,\n initialFocus?: ConfirmInitialFocus,\n): ConfirmInitialFocus {\n if (initialFocus) return initialFocus;\n return tone === 'destructive' ? 'cancel' : 'confirm';\n}\n\n/**\n * The type-to-confirm field. Rendered only when `typeToConfirm` is set, which\n * should be rare: it is the guard for actions with NO recovery path, where a\n * click is too cheap a gesture. Comparison is exact — trimmed of surrounding\n * whitespace only, so a trailing space from a paste does not read as a mismatch.\n */\nfunction TypeToConfirmField({\n expected,\n label,\n value,\n onChange,\n disabled,\n dataTestId,\n}: {\n expected: string;\n label?: string;\n value: string;\n onChange: (next: string) => void;\n disabled: boolean;\n dataTestId: string;\n}): React.ReactElement {\n return (\n <Stack spacing={1} sx={{ mt: 2 }}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {label ?? `Digite \"${expected}\" para confirmar.`}\n </Typography>\n <TextField\n size=\"small\"\n value={value}\n disabled={disabled}\n onChange={(event) => onChange(event.target.value)}\n // On the INPUT rather than the wrapper: a test id on MUI's TextField\n // lands on the outer div, which is not the node a test can type into.\n inputProps={{\n 'aria-label': label ?? `Digite ${expected} para confirmar`,\n 'data-testid': `${dataTestId}-type-to-confirm`,\n }}\n />\n </Stack>\n );\n}\n\nexport interface ConfirmActionDialogProps extends ConfirmOptions {\n /** The fallback body when no entity is named. REQUIRED — no default copy. */\n copy: ConfirmActionCopy;\n state: UseConfirmActionResult;\n}\n\n/**\n * The popup itself: an `AlertDialog` in its destructive skin, plus the two\n * things a bare AlertDialog has no opinion about — the failure the last attempt\n * produced (shown IN the dialog, which stays open, rather than closing over a\n * write that never landed) and the optional type-to-confirm gate.\n */\nexport function ConfirmActionDialog({\n state,\n title,\n description,\n entityName,\n confirmText,\n cancelText,\n typeToConfirm,\n typeToConfirmLabel,\n tone = 'destructive',\n initialFocus,\n dataTestId = DEFAULT_TEST_ID,\n copy,\n}: ConfirmActionDialogProps): React.ReactElement {\n const [typed, setTyped] = React.useState('');\n\n // Every fresh open starts from an empty field: carrying the previous answer\n // over would hand the next delete a pre-satisfied gate.\n React.useEffect(() => {\n if (state.open) setTyped('');\n }, [state.open]);\n\n const gateUnmet = typeToConfirm !== undefined && typed.trim() !== typeToConfirm;\n\n return (\n <AlertDialog\n open={state.open}\n variant={tone === 'destructive' ? 'destructive' : 'default'}\n title={title}\n description={confirmBody(description, copy, entityName)}\n confirmText={confirmText}\n cancelText={cancelText}\n loading={state.pending}\n confirmDisabled={gateUnmet}\n initialFocus={resolveInitialFocus(tone, initialFocus)}\n onConfirm={state.confirm}\n onCancel={state.cancel}\n onClose={state.cancel}\n data-testid={dataTestId}\n >\n {state.error && (\n <Alert severity=\"error\" sx={{ mt: 1 }} data-testid={`${dataTestId}-error`}>\n {state.error}\n </Alert>\n )}\n {typeToConfirm !== undefined && (\n <TypeToConfirmField\n expected={typeToConfirm}\n label={typeToConfirmLabel}\n value={typed}\n onChange={setTyped}\n disabled={state.pending}\n dataTestId={dataTestId}\n />\n )}\n </AlertDialog>\n );\n}\n","import React from 'react';\n\nimport { useConfirmAction } from './ConfirmAction.hooks';\nimport { ConfirmActionDialog } from './ConfirmAction.parts';\nimport type { ConfirmActionProps } from './ConfirmAction.types';\n\n/**\n * Wraps any trigger in a confirmation popup.\n *\n * The trigger is a render prop rather than a fixed element, so the same guard\n * covers a button, a dropdown item, an icon or a table row action without this\n * component knowing what any of them look like. The guarded handler runs ONLY\n * after the operator confirms:\n *\n * ```tsx\n * <ConfirmAction\n * title=\"Excluir a categoria?\"\n * entityName={row.name}\n * description=\"Ela vai para a lixeira e pode ser restaurada de lá.\"\n * confirmText=\"Excluir\"\n * onConfirm={() => deleteCategoryAction({ tenantSlug, id: row.id })}\n * >\n * {(request) => <Button color=\"danger\" onClick={request}>Excluir</Button>}\n * </ConfirmAction>\n * ```\n *\n * For the common case — an existing button whose `onClick` is already the\n * destructive write — reach for {@link withConfirmation} instead, which needs\n * no restructuring of the call site.\n */\nexport function ConfirmAction({\n onConfirm,\n children,\n ...options\n}: ConfirmActionProps): React.ReactElement {\n const state = useConfirmAction(onConfirm, options.errorText);\n\n return (\n <>\n {children(state.request, { pending: state.pending })}\n <ConfirmActionDialog state={state} {...options} />\n </>\n );\n}\n\nConfirmAction.displayName = 'ConfirmAction';\n","import type { ConfirmActionCopy } from '../../../copy';\nimport React from 'react';\nimport type { ComponentType } from 'react';\n\nimport { useConfirmAction } from './ConfirmAction.hooks';\nimport { ConfirmActionDialog } from './ConfirmAction.parts';\nimport type {\n ConfirmHandler,\n ConfirmOptions,\n ConfirmableComponent,\n ConfirmableProps,\n WithConfirmationProps,\n} from './ConfirmAction.types';\n\n/**\n * Merge the HOC's baked-in defaults with the per-instance `confirm` prop.\n * Returns null when the instance opts out (`confirm={false}`) or when neither\n * side supplies the two fields a confirmation cannot be written without — the\n * question and the verb. A null result means \"render the plain component\",\n * which keeps the wrapped export usable in harmless contexts.\n */\nfunction resolveOptions(\n defaults: Partial<ConfirmOptions> | undefined,\n instance: Partial<ConfirmOptions> | false | undefined,\n): ConfirmOptions | null {\n if (instance === false) return null;\n const merged = { ...defaults, ...instance };\n if (!merged.title || !merged.confirmText) return null;\n return { ...merged, title: merged.title, confirmText: merged.confirmText };\n}\n\n/**\n * Adapt the wrapped component's `onClick` into a {@link ConfirmHandler}.\n *\n * The click argument is dropped (see `ConfirmHandler`) and the return value is\n * narrowed: a promise is handed back so the popup can hold its pending state\n * until the write settles, anything else becomes `undefined`. A component with\n * no `onClick` has nothing to guard, so confirming is a no-op.\n */\nfunction useGuardedHandler(onClick: ConfirmableProps['onClick']): ConfirmHandler {\n return React.useCallback((): void | Promise<unknown> => {\n const result = onClick?.();\n return result instanceof Promise ? result : undefined;\n }, [onClick]);\n}\n\n/**\n * Give any click-driven component a confirmation popup, without restructuring\n * the call site.\n *\n * The wrapped component's own `onClick` becomes the GUARDED action: clicking\n * now opens the popup, and the handler runs only if the operator confirms. It\n * inherits the whole contract from `useConfirmAction` — cancel sends nothing, a\n * returned promise holds the popup in its pending state so a double-click\n * cannot fire two writes, and a rejection keeps the popup open carrying the\n * error.\n *\n * ```tsx\n * const ConfirmButton = withConfirmation(Button);\n *\n * <ConfirmButton\n * color=\"danger\"\n * onClick={() => deleteCategoryAction({ tenantSlug, id: row.id })}\n * confirm={{\n * title: \"Excluir a categoria?\",\n * entityName: row.name,\n * description: \"Ela vai para a lixeira e pode ser restaurada de lá.\",\n * confirmText: \"Excluir\",\n * }}\n * >\n * Excluir\n * </ConfirmButton>\n * ```\n *\n * Bake the wording in once when the same guard repeats — `withConfirmation(Button,\n * { confirmText: \"Excluir\" })` — and let each instance override what differs.\n * `confirm={false}` falls through to the plain component.\n *\n * Refs are not forwarded: the HOC renders a fragment (trigger + popup), so there\n * is no single node to hand back. Wrap a component that needs a ref at its own\n * call site with {@link ConfirmAction} instead.\n */\nexport function withConfirmation<P extends ConfirmableProps>(\n Wrapped: ComponentType<P>,\n defaults: Partial<ConfirmOptions> & { errorText: string; copy: ConfirmActionCopy },\n): ConfirmableComponent<P> {\n function WithConfirmation(props: P & WithConfirmationProps): React.ReactElement {\n const { confirm, onClick } = props;\n const options = resolveOptions(defaults, confirm);\n const state = useConfirmAction(useGuardedHandler(onClick), defaults.errorText);\n\n // `confirm` is ours and must not reach the DOM — an unknown attribute on a\n // <button> is a React warning at every render. The cast is the standard HOC\n // one: TypeScript cannot prove `Omit<P & X, 'confirm'>` is still a `P`.\n const { confirm: _confirm, ...rest } = props;\n const forwarded = rest as unknown as P;\n\n if (!options) return <Wrapped {...forwarded} />;\n\n return (\n <>\n <Wrapped {...forwarded} onClick={state.request} />\n <ConfirmActionDialog state={state} {...options} copy={defaults.copy} />\n </>\n );\n }\n\n WithConfirmation.displayName = `withConfirmation(${\n Wrapped.displayName ?? Wrapped.name ?? 'Component'\n })`;\n\n return WithConfirmation;\n}\n","import type { ConfirmActionCopy } from '../../../copy';\nimport { Button } from '../../form/Button';\nimport type { ButtonProps } from '../../form/Button/Button.types';\n\nimport { withConfirmation } from './with-confirmation';\nimport type { ConfirmableComponent } from './ConfirmAction.types';\n\n/**\n * The library `Button`, already wrapped — the shape most call sites want.\n *\n * Adding the guard to an existing button is then an import swap plus the\n * `confirm` prop; the button's own props (colour, size, icon) are untouched.\n * The baked-in defaults are only the wording and tone every destructive\n * confirmation shares, and each instance can still override them.\n */\nexport function createConfirmButton(\n copy: ConfirmActionCopy,\n errorText: string,\n): ConfirmableComponent<ButtonProps> {\n return withConfirmation<ButtonProps>(Button, {\n cancelText: copy.cancel,\n tone: 'destructive',\n errorText,\n copy,\n });\n}\n"],"mappings":"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","names":["Fragment","jsx","jsxs","React","Fragment","jsx","jsxs","React"]}