@12-apps/ui 6.3.1 → 6.5.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-WFPXRSIZ.js → chunk-5TCPZ6GR.js} +7 -5
- package/dist/chunk-5TCPZ6GR.js.map +1 -0
- package/dist/{chunk-TPQRIPCN.js → chunk-AR5LUIBC.js} +12 -9
- package/dist/chunk-AR5LUIBC.js.map +1 -0
- package/dist/{chunk-R5ZQZSEQ.js → chunk-NUCLEOHF.js} +12 -6
- package/dist/chunk-NUCLEOHF.js.map +1 -0
- package/dist/data-display/CardKit.js +1 -1
- package/dist/data-display/DataViews.js +30 -23
- package/dist/data-display/DataViews.js.map +1 -1
- package/dist/feedback/ConfirmAction.js +1 -1
- package/dist/form/CategorySelect.js +1 -1
- package/dist/form/CreatableSelect.js +1 -1
- package/dist/form/CreatableSelect.js.map +1 -1
- package/dist/form/SearchPalette.js +3 -4
- package/dist/form/SearchPalette.js.map +1 -1
- package/dist/form/total-form.js +1 -1
- package/dist/layout/ContentToolbar.js +1 -1
- package/dist/pt-BR.js +28 -5
- package/dist/pt-BR.js.map +1 -1
- package/dist/types/components/data-display/DataViews/DataViewsBoard.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-category-pill.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-copy.d.ts +44 -1
- package/dist/types/components/data-display/DataViews/data-views-copy.d.ts.map +1 -1
- package/dist/types/components/data-display/DataViews/data-views-empty.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-toolbar.d.ts.map +1 -1
- package/dist/types/components/feedback/ConfirmAction/ConfirmAction.parts.d.ts.map +1 -1
- package/dist/types/components/form/CategorySelect/CategoryPanelList.d.ts.map +1 -1
- package/dist/types/components/form/CategorySelect/CategoryQuickActions.d.ts +4 -1
- package/dist/types/components/form/CategorySelect/CategoryQuickActions.d.ts.map +1 -1
- package/dist/types/components/form/CategorySelect/CategoryRows.d.ts +3 -1
- package/dist/types/components/form/CategorySelect/CategoryRows.d.ts.map +1 -1
- package/dist/types/components/form/CreatableSelect/CreatableSelect.d.ts.map +1 -1
- package/dist/types/components/form/CreatableSelect/CreatableSelect.types.d.ts +2 -1
- package/dist/types/components/form/CreatableSelect/CreatableSelect.types.d.ts.map +1 -1
- package/dist/types/components/form/SearchPalette/SearchPalette.d.ts.map +1 -1
- package/dist/types/components/form/SearchPalette/SearchPalette.types.d.ts +3 -3
- package/dist/types/components/form/SearchPalette/SearchPalette.types.d.ts.map +1 -1
- package/dist/types/components/layout/ContentToolbar/ContentToolbar.d.ts +1 -1
- package/dist/types/components/layout/ContentToolbar/ContentToolbar.d.ts.map +1 -1
- package/dist/types/components/layout/ContentToolbar/ContentToolbar.types.d.ts +12 -0
- package/dist/types/components/layout/ContentToolbar/ContentToolbar.types.d.ts.map +1 -1
- package/dist/types/components/layout/ContentToolbar/MultiSelectDropdown.d.ts +1 -1
- package/dist/types/components/layout/ContentToolbar/MultiSelectDropdown.d.ts.map +1 -1
- package/dist/types/components/layout/ContentToolbar/MultiSelectTriggers.d.ts +10 -2
- package/dist/types/components/layout/ContentToolbar/MultiSelectTriggers.d.ts.map +1 -1
- package/dist/types/copy.d.ts +29 -0
- package/dist/types/copy.d.ts.map +1 -1
- package/dist/types/pt-BR.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/data-display/DataViews/DataViewsBoard.tsx +2 -1
- package/src/components/data-display/DataViews/DeleteViewDialog.tsx +2 -2
- package/src/components/data-display/DataViews/ManageViewsDialog.tsx +1 -1
- package/src/components/data-display/DataViews/base-list-card-gutters.tsx +2 -1
- package/src/components/data-display/DataViews/data-views-category-pill.tsx +1 -0
- package/src/components/data-display/DataViews/data-views-columns-tab.tsx +4 -3
- package/src/components/data-display/DataViews/data-views-copy.ts +44 -1
- package/src/components/data-display/DataViews/data-views-empty.tsx +6 -3
- package/src/components/data-display/DataViews/data-views-more-fields.tsx +3 -1
- package/src/components/data-display/DataViews/data-views-more-filters.tsx +2 -1
- package/src/components/data-display/DataViews/data-views-range-pill.tsx +2 -1
- package/src/components/data-display/DataViews/data-views-toolbar.tsx +3 -0
- package/src/components/data-display/DataViews/data-views-view-nav.tsx +2 -2
- package/src/components/feedback/ConfirmAction/ConfirmAction.parts.tsx +6 -2
- package/src/components/form/CategorySelect/CategoryPanel.tsx +1 -1
- package/src/components/form/CategorySelect/CategoryPanelList.tsx +1 -0
- package/src/components/form/CategorySelect/CategoryQuickActions.tsx +7 -2
- package/src/components/form/CategorySelect/CategoryRows.tsx +6 -1
- package/src/components/form/CategorySelect/CategorySelect.tsx +1 -1
- package/src/components/form/CreatableSelect/CreatableSelect.md +2 -2
- package/src/components/form/CreatableSelect/CreatableSelect.tsx +1 -1
- package/src/components/form/CreatableSelect/CreatableSelect.types.ts +2 -1
- package/src/components/form/SearchPalette/SearchPalette.tsx +3 -4
- package/src/components/form/SearchPalette/SearchPalette.types.ts +3 -3
- package/src/components/layout/ContentToolbar/ContentToolbar.tsx +13 -2
- package/src/components/layout/ContentToolbar/ContentToolbar.types.ts +12 -0
- package/src/components/layout/ContentToolbar/MultiSelectDropdown.tsx +2 -0
- package/src/components/layout/ContentToolbar/MultiSelectTriggers.tsx +15 -2
- package/src/copy.ts +29 -0
- package/src/pt-BR.ts +23 -0
- package/dist/chunk-R5ZQZSEQ.js.map +0 -1
- package/dist/chunk-TPQRIPCN.js.map +0 -1
- package/dist/chunk-WFPXRSIZ.js.map +0 -1
|
@@ -60,6 +60,7 @@ function OverflowPill<T extends Record<string, unknown>>({
|
|
|
60
60
|
if (options.length > INLINE_OPTION_LIMIT) {
|
|
61
61
|
return (
|
|
62
62
|
<MultiSelectDropdown
|
|
63
|
+
clearLabel={copy.filters.clearRange(field.label)}
|
|
63
64
|
label={field.pill?.label ?? field.label}
|
|
64
65
|
options={options}
|
|
65
66
|
selected={new Set(values)}
|
|
@@ -213,6 +214,7 @@ export function MoreGroup<T extends Record<string, unknown>>({
|
|
|
213
214
|
}: {
|
|
214
215
|
field: OverflowField<T>;
|
|
215
216
|
} & MoreFieldProps): React.JSX.Element {
|
|
217
|
+
const copy = useDataViewsCopy();
|
|
216
218
|
const { applied, clear } = fieldClearing({ field, pills, ranges, onTogglePill, onChangeRange });
|
|
217
219
|
return (
|
|
218
220
|
<Box sx={{ mb: 1.5, "&:last-of-type": { mb: 0 } }}>
|
|
@@ -245,7 +247,7 @@ export function MoreGroup<T extends Record<string, unknown>>({
|
|
|
245
247
|
"&:hover": { textDecoration: "underline" },
|
|
246
248
|
}}
|
|
247
249
|
>
|
|
248
|
-
|
|
250
|
+
{copy.filters.clear}
|
|
249
251
|
</Box>
|
|
250
252
|
)}
|
|
251
253
|
</Box>
|
|
@@ -153,6 +153,7 @@ function MoreFooter({
|
|
|
153
153
|
onClearAll: () => void;
|
|
154
154
|
testIdPrefix: string;
|
|
155
155
|
}): React.JSX.Element {
|
|
156
|
+
const copy = useDataViewsCopy();
|
|
156
157
|
return (
|
|
157
158
|
<Box sx={{ px: 1.5, py: 1, borderTop: 1, borderColor: "divider" }}>
|
|
158
159
|
<Box
|
|
@@ -173,7 +174,7 @@ function MoreFooter({
|
|
|
173
174
|
"&:hover": { textDecoration: "underline" },
|
|
174
175
|
}}
|
|
175
176
|
>
|
|
176
|
-
|
|
177
|
+
{copy.filters.clearAll}
|
|
177
178
|
</Box>
|
|
178
179
|
</Box>
|
|
179
180
|
);
|
|
@@ -261,6 +261,7 @@ export function RangePill<T extends Record<string, unknown>>({
|
|
|
261
261
|
onOpenChange?: (open: boolean) => void;
|
|
262
262
|
testIdPrefix: string;
|
|
263
263
|
}): React.JSX.Element {
|
|
264
|
+
const copy = useDataViewsCopy();
|
|
264
265
|
const [anchor, setAnchor] = useState<HTMLElement | null>(null);
|
|
265
266
|
const active = isRangeSet(value);
|
|
266
267
|
const testId = `${testIdPrefix}-range-${field.id}`;
|
|
@@ -303,7 +304,7 @@ export function RangePill<T extends Record<string, unknown>>({
|
|
|
303
304
|
data-testid={`${testId}-clear`}
|
|
304
305
|
sx={{ textTransform: 'none' }}
|
|
305
306
|
>
|
|
306
|
-
|
|
307
|
+
{copy.filters.clear}
|
|
307
308
|
</Button>
|
|
308
309
|
</Box>
|
|
309
310
|
)}
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
import { Box } from "../../../mui/Box";
|
|
12
12
|
import { Text } from "../../typography/Text";
|
|
13
13
|
|
|
14
|
+
import { useDataViewsCopy } from "./data-views-copy-context";
|
|
14
15
|
import { DataViewsDisplayPanel, type DisplayPanelView } from "./data-views-display-panel";
|
|
15
16
|
import { DataViewsExportMenu, type DataViewExport } from "./data-views-export";
|
|
16
17
|
import { renderBulkActions } from "./data-views-grid-helpers";
|
|
@@ -136,6 +137,7 @@ function ToolbarRightControls<T extends Record<string, unknown>>(props: GridTool
|
|
|
136
137
|
* separators reach the sidebar's vertical line and the window edge.
|
|
137
138
|
*/
|
|
138
139
|
export function GridToolbar<T extends Record<string, unknown>>(props: GridToolbarProps<T>): React.JSX.Element {
|
|
140
|
+
const copy = useDataViewsCopy();
|
|
139
141
|
const { testIdPrefix, selectedRows } = props;
|
|
140
142
|
return (
|
|
141
143
|
<Box
|
|
@@ -150,6 +152,7 @@ export function GridToolbar<T extends Record<string, unknown>>(props: GridToolba
|
|
|
150
152
|
}}
|
|
151
153
|
>
|
|
152
154
|
<ContentToolbar
|
|
155
|
+
selectAllLabel={copy.selection.selectAll}
|
|
153
156
|
hasSelection={selectedRows.length > 0}
|
|
154
157
|
selectedCount={selectedRows.length}
|
|
155
158
|
selectAll={props.selectAll}
|
|
@@ -342,7 +342,7 @@ export function ViewFooter({
|
|
|
342
342
|
onClick={view.onReset}
|
|
343
343
|
dataTestId={`${testIdPrefix}-display-reset`}
|
|
344
344
|
>
|
|
345
|
-
|
|
345
|
+
{copy.nav.reset}
|
|
346
346
|
</Button>
|
|
347
347
|
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
|
|
348
348
|
{/* Only meaningful with a view APPLIED: on {copy.nav.mainView} the single
|
|
@@ -358,7 +358,7 @@ export function ViewFooter({
|
|
|
358
358
|
}}
|
|
359
359
|
dataTestId={`${testIdPrefix}-display-save-as`}
|
|
360
360
|
>
|
|
361
|
-
|
|
361
|
+
{copy.nav.saveAs}
|
|
362
362
|
</Button>
|
|
363
363
|
)}
|
|
364
364
|
{/* Enabled only when something in Ordenar / Colunas / Exibição (or the
|
|
@@ -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 ??
|
|
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 ??
|
|
87
|
+
'aria-label': label ?? copy.typeToConfirm(expected),
|
|
85
88
|
'data-testid': `${dataTestId}-type-to-confirm`,
|
|
86
89
|
}}
|
|
87
90
|
/>
|
|
@@ -161,6 +164,7 @@ export function ConfirmActionDialog({
|
|
|
161
164
|
onChange={setTyped}
|
|
162
165
|
disabled={state.pending}
|
|
163
166
|
dataTestId={dataTestId}
|
|
167
|
+
copy={copy}
|
|
164
168
|
/>
|
|
165
169
|
)}
|
|
166
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 ?
|
|
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 ?
|
|
70
|
+
{allExpanded ? copy.collapseAll : copy.expandAll}
|
|
66
71
|
</Box>
|
|
67
72
|
</>
|
|
68
73
|
);
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { Box } from '@mui/material';
|
|
4
4
|
|
|
5
|
+
import type { CategorySelectCopy } from '../../../copy';
|
|
5
6
|
import { CheckGlyph, DisclosureGlyph } from './CategoryIcons';
|
|
6
7
|
import { highlightSegments, type CategoryCheckState } from './category-tree';
|
|
7
8
|
import {
|
|
@@ -69,6 +70,7 @@ interface CategoryHeadRowProps {
|
|
|
69
70
|
onToggleExpanded: () => void;
|
|
70
71
|
onActivate: () => void;
|
|
71
72
|
dataTestId: string;
|
|
73
|
+
copy: CategorySelectCopy;
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
/** The trailing number: how many children are picked, else the item count. */
|
|
@@ -101,6 +103,7 @@ export function CategoryHeadRow({
|
|
|
101
103
|
onToggleExpanded,
|
|
102
104
|
onActivate,
|
|
103
105
|
dataTestId,
|
|
106
|
+
copy,
|
|
104
107
|
}: CategoryHeadRowProps): React.JSX.Element {
|
|
105
108
|
const meta = rowMeta(selectedCount, showCounts, option.count);
|
|
106
109
|
return (
|
|
@@ -117,7 +120,9 @@ export function CategoryHeadRow({
|
|
|
117
120
|
component="button"
|
|
118
121
|
type="button"
|
|
119
122
|
tabIndex={-1}
|
|
120
|
-
aria-label={
|
|
123
|
+
aria-label={
|
|
124
|
+
expanded ? copy.collapseCategory(option.name) : copy.expandCategory(option.name)
|
|
125
|
+
}
|
|
121
126
|
data-testid={`${dataTestId}-expand-${option.id}`}
|
|
122
127
|
sx={(theme) => chevronButtonSx(theme, expanded)}
|
|
123
128
|
onClick={(event: React.MouseEvent) => {
|
|
@@ -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 ?
|
|
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
|
|
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.
|
|
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
|
|
|
@@ -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
|
-
|
|
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
|
|
60
|
-
noResultsLabel: props.noResultsLabel
|
|
61
|
-
placeholder: props.placeholder
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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':
|
|
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
|
-
|
|
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={
|
|
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,29 @@ 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
|
+
* ONE row's chevron, in its two states — a glyph button inside the row
|
|
65
|
+
* button, so this pair is the whole of what a screen reader reads for it.
|
|
66
|
+
* The category's own name is appended by the caller.
|
|
67
|
+
*/
|
|
68
|
+
expandCategory(name: string): string;
|
|
69
|
+
collapseCategory(name: string): string;
|
|
70
|
+
/**
|
|
71
|
+
* What the closed control invites, and it differs by mode: picking ONE
|
|
72
|
+
* category is a move, picking several is a filter. Both were pt-BR defaults
|
|
73
|
+
* behind an optional prop, which is the arrangement this port removes.
|
|
74
|
+
*/
|
|
75
|
+
placeholderSingle: string;
|
|
76
|
+
placeholderMulti: string;
|
|
48
77
|
/** The empty state, when the host has no categories at all. */
|
|
49
78
|
emptyTitle: string;
|
|
50
79
|
createCategory: string;
|
package/src/pt-BR.ts
CHANGED
|
@@ -26,11 +26,20 @@ 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
|
+
expandCategory: (name) => `Expandir ${name}`,
|
|
40
|
+
collapseCategory: (name) => `Recolher ${name}`,
|
|
41
|
+
placeholderSingle: "Mover para…",
|
|
42
|
+
placeholderMulti: "Categoria",
|
|
34
43
|
emptyTitle: "Nenhuma categoria ainda",
|
|
35
44
|
createCategory: "Criar categoria",
|
|
36
45
|
noResults: {
|
|
@@ -102,19 +111,23 @@ export const PT_BR_DATA_VIEWS_COPY: DataViewsCopy = {
|
|
|
102
111
|
countOnPage: (label, count) => `${label}: ${count} nesta página`,
|
|
103
112
|
onThisPage: (count) => `${count} nesta página`,
|
|
104
113
|
pageSum: (sum) => `Soma desta página: ${sum}`,
|
|
114
|
+
emptyColumn: "Nada nesta etapa",
|
|
105
115
|
pageScopeNote:
|
|
106
116
|
"As contagens e somas abaixo referem-se apenas aos itens desta página.",
|
|
107
117
|
},
|
|
108
118
|
deleteView: {
|
|
109
119
|
title: "Excluir visão",
|
|
120
|
+
target: (viewName) => `Excluir "${viewName}"?`,
|
|
110
121
|
sharedWarning: "Esta visão está compartilhada — a equipe perderá o acesso a ela.",
|
|
111
122
|
rowsUnaffected: (entityLabel) =>
|
|
112
123
|
`${entityLabel} não são afetados; apenas o recorte salvo é removido.`,
|
|
113
124
|
confirm: "Excluir visão",
|
|
125
|
+
cancel: "Cancelar",
|
|
114
126
|
},
|
|
115
127
|
manageViews: {
|
|
116
128
|
title: "Gerenciar visões",
|
|
117
129
|
empty: "Nenhuma visão salva.",
|
|
130
|
+
edit: "Editar",
|
|
118
131
|
defaultTag: "Padrão",
|
|
119
132
|
otherUserTag: "De outro usuário",
|
|
120
133
|
deleteTitle: "Excluir a visão salva?",
|
|
@@ -148,6 +161,9 @@ export const PT_BR_DATA_VIEWS_COPY: DataViewsCopy = {
|
|
|
148
161
|
visibleCount: (visible, total) => `${visible} de ${total} visíveis`,
|
|
149
162
|
reset: "Padrão",
|
|
150
163
|
showAll: "Mostrar todas",
|
|
164
|
+
dragHint: "Arraste para reordenar as colunas.",
|
|
165
|
+
moveUp: (columnLabel) => `Mover ${columnLabel} para cima`,
|
|
166
|
+
moveDown: (columnLabel) => `Mover ${columnLabel} para baixo`,
|
|
151
167
|
},
|
|
152
168
|
display: {
|
|
153
169
|
sortTab: "Ordenar",
|
|
@@ -187,6 +203,9 @@ export const PT_BR_DATA_VIEWS_COPY: DataViewsCopy = {
|
|
|
187
203
|
grid: {
|
|
188
204
|
rowActions: "Ações",
|
|
189
205
|
bulkActions: (selectedCount) => `Ações (${selectedCount}) ▾`,
|
|
206
|
+
emptyFilteredTitle: "Nenhum resultado para esses filtros",
|
|
207
|
+
emptyFilteredHint: "Ajuste ou remova os filtros.",
|
|
208
|
+
emptyFilteredAction: "Limpar filtros",
|
|
190
209
|
},
|
|
191
210
|
filters: {
|
|
192
211
|
moreFilters: (count) => `Mais filtros: ${count} sem espaço na barra`,
|
|
@@ -217,6 +236,8 @@ export const PT_BR_DATA_VIEWS_COPY: DataViewsCopy = {
|
|
|
217
236
|
selectAll: "Selecionar tudo",
|
|
218
237
|
onThisPage: (count) => `${count} nesta página`,
|
|
219
238
|
selectRow: "Selecionar",
|
|
239
|
+
expandRow: "Expandir detalhes",
|
|
240
|
+
collapseRow: "Recolher detalhes",
|
|
220
241
|
},
|
|
221
242
|
nav: {
|
|
222
243
|
mainView: "Visão principal",
|
|
@@ -229,6 +250,8 @@ export const PT_BR_DATA_VIEWS_COPY: DataViewsCopy = {
|
|
|
229
250
|
label: "Visão",
|
|
230
251
|
update: "Atualizar visão",
|
|
231
252
|
save: "Salvar visão",
|
|
253
|
+
saveAs: "Salvar como nova",
|
|
254
|
+
reset: "Redefinir",
|
|
232
255
|
updateFailed: "Não foi possível atualizar a visão",
|
|
233
256
|
saveFailed: "Não foi possível salvar a alteração da visão.",
|
|
234
257
|
editView: "Renomear e editar",
|