@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.
Files changed (166) hide show
  1. package/dist/{chunk-35VGGLOC.js → chunk-CEKPLUQV.js} +2 -2
  2. package/dist/{chunk-35VGGLOC.js.map → chunk-CEKPLUQV.js.map} +1 -1
  3. package/dist/{chunk-62XQWGXU.js → chunk-MXPXKORR.js} +19 -17
  4. package/dist/chunk-MXPXKORR.js.map +1 -0
  5. package/dist/{chunk-7XLEWBKL.js → chunk-N554AFDB.js} +7 -10
  6. package/dist/chunk-N554AFDB.js.map +1 -0
  7. package/dist/{chunk-JDO7W4D4.js → chunk-R5ZQZSEQ.js} +2 -20
  8. package/dist/{chunk-JDO7W4D4.js.map → chunk-R5ZQZSEQ.js.map} +1 -1
  9. package/dist/{chunk-R4TYXKDD.js → chunk-TPQRIPCN.js} +52 -48
  10. package/dist/chunk-TPQRIPCN.js.map +1 -0
  11. package/dist/copy.js +1 -0
  12. package/dist/copy.js.map +1 -0
  13. package/dist/data-display/CardKit.js +15 -4
  14. package/dist/data-display/CardKit.js.map +1 -1
  15. package/dist/data-display/DataViews.js +664 -616
  16. package/dist/data-display/DataViews.js.map +1 -1
  17. package/dist/data-display/SectionOnboarding.js +3 -3
  18. package/dist/data-display/SectionOnboarding.js.map +1 -1
  19. package/dist/feedback/ConfirmAction.js +3 -5
  20. package/dist/form/CategorySelect.js +1 -1
  21. package/dist/form/CepField.js +1 -1
  22. package/dist/form/total-form.js +8 -4
  23. package/dist/form/total-form.js.map +1 -1
  24. package/dist/layout/ContentToolbar.js +1 -1
  25. package/dist/layout/TableFilter.js +1 -1
  26. package/dist/pt-BR.js +222 -0
  27. package/dist/pt-BR.js.map +1 -0
  28. package/dist/types/components/data-display/CardKit/use-remove-confirm.d.ts +4 -1
  29. package/dist/types/components/data-display/CardKit/use-remove-confirm.d.ts.map +1 -1
  30. package/dist/types/components/data-display/CardKit/use-row-confirm.d.ts +5 -2
  31. package/dist/types/components/data-display/CardKit/use-row-confirm.d.ts.map +1 -1
  32. package/dist/types/components/data-display/DataViews/DataViewsBoard.d.ts.map +1 -1
  33. package/dist/types/components/data-display/DataViews/DeleteViewDialog.d.ts.map +1 -1
  34. package/dist/types/components/data-display/DataViews/ManageViewsDialog.d.ts +4 -1
  35. package/dist/types/components/data-display/DataViews/ManageViewsDialog.d.ts.map +1 -1
  36. package/dist/types/components/data-display/DataViews/SaveViewModal.d.ts +0 -5
  37. package/dist/types/components/data-display/DataViews/SaveViewModal.d.ts.map +1 -1
  38. package/dist/types/components/data-display/DataViews/base-card.d.ts.map +1 -1
  39. package/dist/types/components/data-display/DataViews/base-list-card-gutters.d.ts.map +1 -1
  40. package/dist/types/components/data-display/DataViews/data-views-bar-controls.d.ts.map +1 -1
  41. package/dist/types/components/data-display/DataViews/data-views-category-pill.d.ts.map +1 -1
  42. package/dist/types/components/data-display/DataViews/data-views-columns-tab.d.ts.map +1 -1
  43. package/dist/types/components/data-display/DataViews/data-views-copy-context.d.ts +17 -0
  44. package/dist/types/components/data-display/DataViews/data-views-copy-context.d.ts.map +1 -0
  45. package/dist/types/components/data-display/DataViews/data-views-copy.d.ts +205 -0
  46. package/dist/types/components/data-display/DataViews/data-views-copy.d.ts.map +1 -0
  47. package/dist/types/components/data-display/DataViews/data-views-display-panel.d.ts.map +1 -1
  48. package/dist/types/components/data-display/DataViews/data-views-display-tabs.d.ts.map +1 -1
  49. package/dist/types/components/data-display/DataViews/data-views-export.d.ts.map +1 -1
  50. package/dist/types/components/data-display/DataViews/data-views-filter-panel.d.ts.map +1 -1
  51. package/dist/types/components/data-display/DataViews/data-views-grid-helpers.d.ts.map +1 -1
  52. package/dist/types/components/data-display/DataViews/data-views-more-fields.d.ts.map +1 -1
  53. package/dist/types/components/data-display/DataViews/data-views-more-filters.d.ts.map +1 -1
  54. package/dist/types/components/data-display/DataViews/data-views-range-pill.d.ts.map +1 -1
  55. package/dist/types/components/data-display/DataViews/data-views-range-presets.d.ts +3 -2
  56. package/dist/types/components/data-display/DataViews/data-views-range-presets.d.ts.map +1 -1
  57. package/dist/types/components/data-display/DataViews/data-views-scopes.d.ts.map +1 -1
  58. package/dist/types/components/data-display/DataViews/data-views-search.d.ts.map +1 -1
  59. package/dist/types/components/data-display/DataViews/data-views-select-all-strip.d.ts.map +1 -1
  60. package/dist/types/components/data-display/DataViews/data-views-table-parts.d.ts.map +1 -1
  61. package/dist/types/components/data-display/DataViews/data-views-view-nav.d.ts +1 -1
  62. package/dist/types/components/data-display/DataViews/data-views-view-nav.d.ts.map +1 -1
  63. package/dist/types/components/data-display/DataViews/index.d.ts +2 -0
  64. package/dist/types/components/data-display/DataViews/index.d.ts.map +1 -1
  65. package/dist/types/components/data-display/DataViews/save-view-preview.d.ts +10 -0
  66. package/dist/types/components/data-display/DataViews/save-view-preview.d.ts.map +1 -0
  67. package/dist/types/components/data-display/DataViews/use-saved-views-controller.d.ts.map +1 -1
  68. package/dist/types/components/data-display/SectionOnboarding/SectionOnboarding.types.d.ts +6 -5
  69. package/dist/types/components/data-display/SectionOnboarding/SectionOnboarding.types.d.ts.map +1 -1
  70. package/dist/types/components/feedback/ConfirmAction/ConfirmAction.hooks.d.ts +1 -3
  71. package/dist/types/components/feedback/ConfirmAction/ConfirmAction.hooks.d.ts.map +1 -1
  72. package/dist/types/components/feedback/ConfirmAction/ConfirmAction.parts.d.ts +4 -1
  73. package/dist/types/components/feedback/ConfirmAction/ConfirmAction.parts.d.ts.map +1 -1
  74. package/dist/types/components/feedback/ConfirmAction/ConfirmAction.types.d.ts +9 -1
  75. package/dist/types/components/feedback/ConfirmAction/ConfirmAction.types.d.ts.map +1 -1
  76. package/dist/types/components/feedback/ConfirmAction/ConfirmButton.d.ts +2 -1
  77. package/dist/types/components/feedback/ConfirmAction/ConfirmButton.d.ts.map +1 -1
  78. package/dist/types/components/feedback/ConfirmAction/index.d.ts +2 -2
  79. package/dist/types/components/feedback/ConfirmAction/index.d.ts.map +1 -1
  80. package/dist/types/components/feedback/ConfirmAction/with-confirmation.d.ts +5 -1
  81. package/dist/types/components/feedback/ConfirmAction/with-confirmation.d.ts.map +1 -1
  82. package/dist/types/components/form/CategorySelect/CategoryPanel.d.ts +4 -1
  83. package/dist/types/components/form/CategorySelect/CategoryPanel.d.ts.map +1 -1
  84. package/dist/types/components/form/CategorySelect/CategoryPanelFoot.d.ts +5 -2
  85. package/dist/types/components/form/CategorySelect/CategoryPanelFoot.d.ts.map +1 -1
  86. package/dist/types/components/form/CategorySelect/CategoryPanelHead.d.ts +5 -2
  87. package/dist/types/components/form/CategorySelect/CategoryPanelHead.d.ts.map +1 -1
  88. package/dist/types/components/form/CategorySelect/CategoryPanelList.d.ts +3 -0
  89. package/dist/types/components/form/CategorySelect/CategoryPanelList.d.ts.map +1 -1
  90. package/dist/types/components/form/CategorySelect/CategorySelect.types.d.ts +5 -0
  91. package/dist/types/components/form/CategorySelect/CategorySelect.types.d.ts.map +1 -1
  92. package/dist/types/components/form/CategorySelect/CategoryTrigger.d.ts +4 -1
  93. package/dist/types/components/form/CategorySelect/CategoryTrigger.d.ts.map +1 -1
  94. package/dist/types/components/form/CepField/CepField.d.ts +1 -1
  95. package/dist/types/components/form/CepField/CepField.d.ts.map +1 -1
  96. package/dist/types/components/form/CepField/CepField.types.d.ts +3 -0
  97. package/dist/types/components/form/CepField/CepField.types.d.ts.map +1 -1
  98. package/dist/types/components/form/total-form/Fields/CategoryField.d.ts +4 -1
  99. package/dist/types/components/form/total-form/Fields/CategoryField.d.ts.map +1 -1
  100. package/dist/types/components/form/total-form/Fields/CepField.d.ts +4 -1
  101. package/dist/types/components/form/total-form/Fields/CepField.d.ts.map +1 -1
  102. package/dist/types/components/layout/ContentToolbar/ContentToolbar.types.d.ts +6 -1
  103. package/dist/types/components/layout/ContentToolbar/ContentToolbar.types.d.ts.map +1 -1
  104. package/dist/types/components/layout/ContentToolbar/SavedViewsMenu.d.ts.map +1 -1
  105. package/dist/types/copy.d.ts +99 -0
  106. package/dist/types/copy.d.ts.map +1 -0
  107. package/dist/types/pt-BR.d.ts +28 -0
  108. package/dist/types/pt-BR.d.ts.map +1 -0
  109. package/package.json +10 -2
  110. package/src/components/data-display/CardKit/use-remove-confirm.tsx +5 -0
  111. package/src/components/data-display/CardKit/use-row-confirm.tsx +7 -2
  112. package/src/components/data-display/DataViews/DataViewsBoard.tsx +7 -4
  113. package/src/components/data-display/DataViews/DeleteViewDialog.tsx +6 -4
  114. package/src/components/data-display/DataViews/ManageViewsDialog.tsx +26 -10
  115. package/src/components/data-display/DataViews/SaveViewModal.tsx +56 -90
  116. package/src/components/data-display/DataViews/base-card.tsx +3 -1
  117. package/src/components/data-display/DataViews/base-list-card-gutters.tsx +3 -1
  118. package/src/components/data-display/DataViews/data-views-bar-controls.tsx +8 -5
  119. package/src/components/data-display/DataViews/data-views-category-pill.tsx +6 -3
  120. package/src/components/data-display/DataViews/data-views-columns-tab.tsx +5 -3
  121. package/src/components/data-display/DataViews/data-views-copy-context.tsx +43 -0
  122. package/src/components/data-display/DataViews/data-views-copy.ts +214 -0
  123. package/src/components/data-display/DataViews/data-views-display-panel.tsx +15 -9
  124. package/src/components/data-display/DataViews/data-views-display-tabs.tsx +19 -29
  125. package/src/components/data-display/DataViews/data-views-export.tsx +9 -10
  126. package/src/components/data-display/DataViews/data-views-filter-panel.tsx +9 -5
  127. package/src/components/data-display/DataViews/data-views-grid-helpers.tsx +5 -2
  128. package/src/components/data-display/DataViews/data-views-more-fields.tsx +5 -3
  129. package/src/components/data-display/DataViews/data-views-more-filters.tsx +6 -3
  130. package/src/components/data-display/DataViews/data-views-range-pill.tsx +9 -5
  131. package/src/components/data-display/DataViews/data-views-range-presets.ts +7 -8
  132. package/src/components/data-display/DataViews/data-views-scopes.tsx +3 -1
  133. package/src/components/data-display/DataViews/data-views-search.tsx +7 -4
  134. package/src/components/data-display/DataViews/data-views-select-all-strip.tsx +5 -3
  135. package/src/components/data-display/DataViews/data-views-table-parts.tsx +7 -2
  136. package/src/components/data-display/DataViews/data-views-view-nav.tsx +22 -16
  137. package/src/components/data-display/DataViews/index.ts +20 -0
  138. package/src/components/data-display/DataViews/save-view-preview.tsx +78 -0
  139. package/src/components/data-display/DataViews/use-saved-views-controller.ts +3 -1
  140. package/src/components/data-display/SectionOnboarding/SectionOnboarding.tsx +3 -3
  141. package/src/components/data-display/SectionOnboarding/SectionOnboarding.types.ts +8 -7
  142. package/src/components/feedback/ConfirmAction/ConfirmAction.hooks.ts +2 -2
  143. package/src/components/feedback/ConfirmAction/ConfirmAction.parts.tsx +12 -5
  144. package/src/components/feedback/ConfirmAction/ConfirmAction.types.ts +9 -1
  145. package/src/components/feedback/ConfirmAction/ConfirmButton.tsx +12 -4
  146. package/src/components/feedback/ConfirmAction/index.ts +2 -2
  147. package/src/components/feedback/ConfirmAction/with-confirmation.tsx +4 -3
  148. package/src/components/form/CategorySelect/CategoryPanel.tsx +18 -6
  149. package/src/components/form/CategorySelect/CategoryPanelFoot.tsx +10 -5
  150. package/src/components/form/CategorySelect/CategoryPanelHead.tsx +8 -3
  151. package/src/components/form/CategorySelect/CategoryPanelList.tsx +17 -10
  152. package/src/components/form/CategorySelect/CategorySelect.tsx +3 -3
  153. package/src/components/form/CategorySelect/CategorySelect.types.ts +5 -0
  154. package/src/components/form/CategorySelect/CategoryTrigger.tsx +5 -1
  155. package/src/components/form/CepField/CepField.tsx +6 -9
  156. package/src/components/form/CepField/CepField.types.ts +3 -0
  157. package/src/components/form/total-form/Fields/CategoryField.tsx +5 -0
  158. package/src/components/form/total-form/Fields/CepField.tsx +5 -0
  159. package/src/components/layout/ContentToolbar/ContentToolbar.types.ts +6 -1
  160. package/src/components/layout/ContentToolbar/SavedViewsMenu.tsx +1 -21
  161. package/src/components/layout/TableFilter/TableFilter.tsx +1 -1
  162. package/src/copy.ts +103 -0
  163. package/src/pt-BR.ts +247 -0
  164. package/dist/chunk-62XQWGXU.js.map +0 -1
  165. package/dist/chunk-7XLEWBKL.js.map +0 -1
  166. package/dist/chunk-R4TYXKDD.js.map +0 -1
@@ -15,6 +15,7 @@ import FilterAltOffRoundedIcon from "@mui/icons-material/FilterAltOffRounded";
15
15
  import { Tooltip } from "@mui/material";
16
16
 
17
17
  import { Box } from "../../../mui/Box";
18
+ import { useDataViewsCopy } from "./data-views-copy-context";
18
19
 
19
20
  /**
20
21
  * "Limpar" — one gesture back to the unfiltered list.
@@ -38,6 +39,7 @@ export function ClearAllControl({
38
39
  compact: boolean;
39
40
  testIdPrefix: string;
40
41
  }): React.JSX.Element {
42
+ const copy = useDataViewsCopy();
41
43
  // No border, no fill. Every other control on this row is an outlined pill
42
44
  // because it OPENS something; this one is an escape hatch, and giving it the
43
45
  // same weight made it read as a sixth filter. Quiet until hovered.
@@ -47,7 +49,7 @@ export function ClearAllControl({
47
49
  type="button"
48
50
  onClick={onClearAll}
49
51
  data-testid={`${testIdPrefix}-clear-all`}
50
- aria-label="Limpar filtros"
52
+ aria-label={copy.filters.clearAll}
51
53
  sx={{
52
54
  display: "inline-flex",
53
55
  alignItems: "center",
@@ -66,10 +68,10 @@ export function ClearAllControl({
66
68
  }}
67
69
  >
68
70
  <FilterAltOffRoundedIcon sx={{ fontSize: 16 }} />
69
- {!compact && <Box component="span">Limpar</Box>}
71
+ {!compact && <Box component="span">{copy.filters.clear}</Box>}
70
72
  </Box>
71
73
  );
72
- return compact ? <Tooltip title="Limpar filtros">{button}</Tooltip> : button;
74
+ return compact ? <Tooltip title={copy.filters.clearAll}>{button}</Tooltip> : button;
73
75
  }
74
76
 
75
77
  /**
@@ -91,13 +93,14 @@ export function CloseSearchControl({
91
93
  onClose: () => void;
92
94
  testIdPrefix: string;
93
95
  }): React.JSX.Element {
96
+ const copy = useDataViewsCopy();
94
97
  return (
95
- <Tooltip title="Fechar busca">
98
+ <Tooltip title={copy.search.close}>
96
99
  <Box
97
100
  component="button"
98
101
  type="button"
99
102
  onClick={onClose}
100
- aria-label="Fechar busca"
103
+ aria-label={copy.search.close}
101
104
  data-testid={`${testIdPrefix}-search-close`}
102
105
  sx={{
103
106
  display: "inline-flex",
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
 
3
+ import { useDataViewsCopy } from "./data-views-copy-context";
3
4
  import { CategorySelect } from "../../form/CategorySelect";
4
5
  import { MultiSelectDropdown } from "../../layout/ContentToolbar";
5
6
 
@@ -65,10 +66,12 @@ export function PillControl<T extends Record<string, unknown>>({
65
66
  testIdPrefix,
66
67
  layout = "pill",
67
68
  }: PillControlProps<T>): React.JSX.Element {
69
+ const copy = useDataViewsCopy();
68
70
  const testId = `${testIdPrefix}-filter-${fieldId}`;
69
71
  if (pill.control === "category") {
70
72
  return (
71
73
  <CategorySelect
74
+ copy={copy.categorySelect}
72
75
  placeholder={pill.label}
73
76
  label={layout === "stacked" ? pill.label : undefined}
74
77
  fullWidth={layout === "stacked"}
@@ -86,10 +89,10 @@ export function PillControl<T extends Record<string, unknown>>({
86
89
  selected={new Set(selected)}
87
90
  onToggle={(value, checked) => onTogglePill(fieldId, value, checked)}
88
91
  onClear={() => onClearField(fieldId)}
89
- allLabel="Todas"
92
+ allLabel={copy.filters.allOption}
90
93
  searchable={pill.searchEnabled ? true : undefined}
91
- searchPlaceholder="Buscar…"
92
- noResultsLabel="Nenhum resultado"
94
+ searchPlaceholder={copy.filters.optionSearchPlaceholder}
95
+ noResultsLabel={copy.filters.optionsEmpty}
93
96
  layout={layout}
94
97
  onOpenChange={onOpenChange}
95
98
  data-testid={testId}
@@ -6,6 +6,7 @@ import DragIndicatorRoundedIcon from "@mui/icons-material/DragIndicatorRounded";
6
6
  import { Checkbox } from "@mui/material";
7
7
  import { useState } from "react";
8
8
 
9
+ import { useDataViewsCopy } from "./data-views-copy-context";
9
10
  import { Box } from "../../../mui/Box";
10
11
  import { Text } from "../../typography/Text";
11
12
 
@@ -51,6 +52,7 @@ export function ColumnsTab({
51
52
  onReset,
52
53
  testIdPrefix,
53
54
  }: ColumnsTabProps): React.JSX.Element {
55
+ const copy = useDataViewsCopy();
54
56
  const [dragId, setDragId] = useState<string | null>(null);
55
57
  const byId = new Map(columns.map((column) => [column.id, column]));
56
58
  const ordered = order.map((id) => byId.get(id)).filter((column): column is HideableColumn => Boolean(column));
@@ -72,12 +74,12 @@ export function ColumnsTab({
72
74
  <Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between", px: 1.5, py: 1 }}>
73
75
  <Text variant="caption" as="span">
74
76
  <Box component="span" sx={{ color: "text.secondary" }} data-testid={`${testIdPrefix}-columns-count`}>
75
- <strong>{visibleHideableCount}</strong> de {columns.length} visíveis
77
+ {copy.columns.visibleCount(visibleHideableCount, columns.length)}
76
78
  </Box>
77
79
  </Text>
78
80
  <Box sx={{ display: "flex", gap: 1 }}>
79
- <LinkButton label="Mostrar todas" onClick={onShowAll} testId={`${testIdPrefix}-columns-show-all`} />
80
- <LinkButton label="Padrão" onClick={onReset} testId={`${testIdPrefix}-columns-reset`} muted />
81
+ <LinkButton label={copy.columns.showAll} onClick={onShowAll} testId={`${testIdPrefix}-columns-show-all`} />
82
+ <LinkButton label={copy.columns.reset} onClick={onReset} testId={`${testIdPrefix}-columns-reset`} muted />
81
83
  </Box>
82
84
  </Box>
83
85
  <Text variant="caption" as="p">
@@ -0,0 +1,43 @@
1
+ import { createContext, useContext, type JSX, type ReactNode } from "react";
2
+
3
+ import type { DataViewsCopy } from "./data-views-copy";
4
+
5
+ /**
6
+ * The words this component family renders, put in scope once by the host.
7
+ *
8
+ * Context rather than a prop per component for the same reason
9
+ * `data-views-layout-context` uses one: the nineteen files here are a single
10
+ * surface mounted once, and threading words through leaves a host never names
11
+ * is the prop-drilling context exists to avoid.
12
+ */
13
+ const DataViewsCopyContext = createContext<DataViewsCopy | null>(null);
14
+
15
+ export function DataViewsCopyProvider({
16
+ copy,
17
+ children,
18
+ }: {
19
+ copy: DataViewsCopy;
20
+ children: ReactNode;
21
+ }): JSX.Element {
22
+ return <DataViewsCopyContext.Provider value={copy}>{children}</DataViewsCopyContext.Provider>;
23
+ }
24
+
25
+ /**
26
+ * The copy in scope.
27
+ *
28
+ * THROWS outside a provider rather than falling back. There is no meaningful
29
+ * empty answer: a saved-views dialog with no words is broken, and any default
30
+ * would be the origin host's Portuguese — which is the exact thing this config
31
+ * exists to stop being silent. Failing at the first render names the wiring
32
+ * mistake; blank buttons would hide it.
33
+ */
34
+ export function useDataViewsCopy(): DataViewsCopy {
35
+ const copy = useContext(DataViewsCopyContext);
36
+ if (!copy) {
37
+ throw new Error(
38
+ "DataViews components must be rendered inside <DataViewsCopyProvider copy={…}>. " +
39
+ "@12-apps/ui ships no default copy; pass PT_BR_DATA_VIEWS_COPY to keep the pt-BR wording.",
40
+ );
41
+ }
42
+ return copy;
43
+ }
@@ -0,0 +1,214 @@
1
+ import type { CategorySelectCopy, ConfirmActionCopy } from "../../../copy";
2
+ import type { SavedViewsLabels } from "../../layout/ContentToolbar/ContentToolbar.types";
3
+ /**
4
+ * Every word the DataViews family renders, as REQUIRED host config (FUT-760).
5
+ *
6
+ * Nineteen files in this one component tree carried pt-BR — the saved-view
7
+ * dialogs, the display tabs, the column and filter panels, the selection strip,
8
+ * the nav. A design system shipping product copy is the leak at its most
9
+ * expensive: `@12-apps/ui` is the package every host renders, so its Portuguese
10
+ * reached every adopter of every OTHER package too.
11
+ *
12
+ * ONE object threaded through a context rather than a prop per component,
13
+ * because these nineteen files are a single surface a host mounts once, and
14
+ * `data-views-layout-context.tsx` already establishes that shape here for
15
+ * layout. A prop per leaf would make a host thread words through components it
16
+ * never names.
17
+ */
18
+
19
+ /** What the board's per-page footnote says about counts and sums. */
20
+ export interface DataViewsBoardCopy {
21
+ countOnPage(label: string, count: number): string;
22
+ onThisPage(count: number): string;
23
+ pageSum(sum: string): string;
24
+ /** Why the figures below are not the whole set. */
25
+ pageScopeNote: string;
26
+ }
27
+
28
+ export interface DeleteViewCopy {
29
+ title: string;
30
+ /** Shown only when the view is shared with the team. */
31
+ sharedWarning: string;
32
+ /** `entityLabel` is the host's own noun for the rows — never this package's. */
33
+ rowsUnaffected(entityLabel: string): string;
34
+ confirm: string;
35
+ }
36
+
37
+ export interface ManageViewsCopy {
38
+ title: string;
39
+ empty: string;
40
+ defaultTag: string;
41
+ otherUserTag: string;
42
+ deleteTitle: string;
43
+ deleteBody: string;
44
+ deleteConfirm: string;
45
+ }
46
+
47
+ export interface SaveViewCopy {
48
+ sharedDescription: string;
49
+ setDefaultTitle: string;
50
+ setDefaultDescription: string;
51
+ previewHeading: string;
52
+ /** The view would be identical to the unsaved default. */
53
+ previewUnchanged: string;
54
+ sortRowLabel: string;
55
+ saveFailed: string;
56
+ titleEditing: string;
57
+ titleCreating: string;
58
+ descriptionLabel: string;
59
+ descriptionPlaceholder: string;
60
+ submitEditing: string;
61
+ submitCreating: string;
62
+ nameLabel: string;
63
+ /** The dialog's way out, beside the submit. */
64
+ cancel: string;
65
+ /** The pin toggle. Its share twin reuses `sharedDescription` below. */
66
+ pinnedTitle: string;
67
+ pinnedDescription: string;
68
+ sharedTitle: string;
69
+ /** An example of a view worth saving, in the host's own domain. */
70
+ namePlaceholder: string;
71
+ /** The two rows of the preview block. */
72
+ previewFilters: string;
73
+ previewHiddenColumns: string;
74
+ }
75
+
76
+ export interface DataViewsColumnsCopy {
77
+ visibleCount(visible: number, total: number): string;
78
+ reset: string;
79
+ showAll: string;
80
+ }
81
+
82
+ export interface DataViewsDisplayCopy {
83
+ /** The three tabs of the display panel. */
84
+ sortTab: string;
85
+ columnsTab: string;
86
+ panelTab: string;
87
+ direction: string;
88
+ /** What each layout is good for, keyed by layout id. */
89
+ layoutHints: Readonly<Record<string, string>>;
90
+ /**
91
+ * What density MEANS in each layout — same three values, three different
92
+ * questions. A table's is how tall its rows are, a card grid's is how many
93
+ * fit on a line, a board's is how wide its columns are.
94
+ */
95
+ densityHeadings: Readonly<Record<string, string>>;
96
+ /**
97
+ * Density words per layout. They differ by layout on purpose: "Baixa" density
98
+ * on a table and "Muitos" cards describe the same setting from the reader's
99
+ * side, which is the register this surface is written in.
100
+ */
101
+ densityLabels: Readonly<Record<string, Readonly<Record<string, string>>>>;
102
+ /** The board layout needs stages, and this screen declares none. */
103
+ boardUnavailable: string;
104
+ /** Density is unavailable because the viewport only fits one card per row. */
105
+ densityUnavailableNarrow: string;
106
+ /** The control that opens this panel. */
107
+ trigger: string;
108
+ }
109
+
110
+ export interface DataViewsExportCopy {
111
+ /** Format labels and hints, keyed by format id. */
112
+ formats: Readonly<Record<string, { label: string; hint: string }>>;
113
+ visibleColumns(columnCount: number): string;
114
+ /** The control that opens the menu. */
115
+ trigger: string;
116
+ }
117
+
118
+ export interface DataViewsGridCopy {
119
+ /** The per-row kebab's accessible name. */
120
+ rowActions: string;
121
+ bulkActions(selectedCount: number): string;
122
+ }
123
+
124
+ export interface DataViewsFiltersCopy {
125
+ moreFilters(count: number): string;
126
+ moreFiltersApplied(count: number, appliedCount: number): string;
127
+ overflowNote: string;
128
+ rangeEnd: string;
129
+ rangeInvalid: string;
130
+ /** The day-range presets' labels, keyed by preset id. */
131
+ rangePresets: Readonly<Record<string, string>>;
132
+ scopesLabel: string;
133
+ /** The slide-in panel, and the button that opens it. */
134
+ panelTitle: string;
135
+ /** Drop every applied filter. Two spellings: the bar has room for one word. */
136
+ clear: string;
137
+ clearAll: string;
138
+ /** Drop one range filter, named. */
139
+ clearRange(label: string): string;
140
+ /** The multi-select dropdowns this surface mounts. */
141
+ allOption: string;
142
+ optionSearchPlaceholder: string;
143
+ optionsEmpty: string;
144
+ }
145
+
146
+ export interface DataViewsSelectionCopy {
147
+ selectAllOnPage: string;
148
+ clearSelection: string;
149
+ selectAll: string;
150
+ onThisPage(count: number): string;
151
+ /** One row's checkbox, which carries no visible label of its own. */
152
+ selectRow: string;
153
+ }
154
+
155
+ export interface DataViewsNavCopy {
156
+ mainView: string;
157
+ defaultTag: string;
158
+ viewOptions(viewName: string): string;
159
+ emptyHint: string;
160
+ setDefault: string;
161
+ deleteView: string;
162
+ unsavedChanges: string;
163
+ label: string;
164
+ update: string;
165
+ save: string;
166
+ /** The inline error when a view could not be refreshed or saved. */
167
+ updateFailed: string;
168
+ saveFailed: string;
169
+ /** Reopen the save dialog over an existing view. */
170
+ editView: string;
171
+ pinToSidebar: string;
172
+ shareWithTeam: string;
173
+ }
174
+
175
+ /** The search box on the toolbar, and the one inside the filter panel. */
176
+ export interface DataViewsSearchCopy {
177
+ placeholder: string;
178
+ /** The input's accessible name — it says what the term is matched against. */
179
+ allColumnsLabel: string;
180
+ /** The panel's keyword box, which commits on Enter rather than as you type. */
181
+ keywordPlaceholder: string;
182
+ /** The icon button that reveals the input on a narrow bar. */
183
+ open: string;
184
+ close: string;
185
+ clear: string;
186
+ }
187
+
188
+ /** Every word this component family renders, in one object a host passes once. */
189
+ export interface DataViewsCopy {
190
+ /**
191
+ * The words of the components this surface RENDERS but does not own — the
192
+ * saved-views menu, the confirm dialog behind a delete, the category pill.
193
+ *
194
+ * Here rather than threaded as props because this surface already carries a
195
+ * copy context: a host mounting DataViews should pass one object, not one per
196
+ * leaf it never names. Each of those components still takes its own copy when
197
+ * mounted standalone.
198
+ */
199
+ savedViewsMenu: SavedViewsLabels;
200
+ confirmAction: ConfirmActionCopy;
201
+ categorySelect: CategorySelectCopy;
202
+ board: DataViewsBoardCopy;
203
+ deleteView: DeleteViewCopy;
204
+ manageViews: ManageViewsCopy;
205
+ saveView: SaveViewCopy;
206
+ columns: DataViewsColumnsCopy;
207
+ display: DataViewsDisplayCopy;
208
+ export: DataViewsExportCopy;
209
+ grid: DataViewsGridCopy;
210
+ filters: DataViewsFiltersCopy;
211
+ selection: DataViewsSelectionCopy;
212
+ nav: DataViewsNavCopy;
213
+ search: DataViewsSearchCopy;
214
+ }
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
 
3
+ import type { DataViewsCopy } from "./data-views-copy";
3
4
  import KeyboardArrowDownRoundedIcon from "@mui/icons-material/KeyboardArrowDownRounded";
4
5
  // Says "display settings" rather than the generic tune sliders it used to
5
6
  // share with the "Mais" FILTER trigger — see the note there.
@@ -7,6 +8,7 @@ import DisplaySettingsRoundedIcon from "@mui/icons-material/DisplaySettingsRound
7
8
  import { Popover } from "@mui/material";
8
9
  import { useState } from "react";
9
10
 
11
+ import { useDataViewsCopy } from "./data-views-copy-context";
10
12
  import { Button } from "../../form/Button";
11
13
  import { Box } from "../../../mui/Box";
12
14
 
@@ -39,11 +41,13 @@ import type { DataViewsController } from "./use-data-views-state";
39
41
  /** Which tab is showing. `columns` first: it is what an operator opens this for. */
40
42
  type DisplayTabKey = "sort" | "columns" | "display";
41
43
 
42
- const TABS: { key: DisplayTabKey; label: string }[] = [
43
- { key: "sort", label: "Ordenar" },
44
- { key: "columns", label: "Colunas" },
45
- { key: "display", label: "Exibição" },
46
- ];
44
+ function displayTabs(copy: DataViewsCopy): { key: DisplayTabKey; label: string }[] {
45
+ return [
46
+ { key: "sort", label: copy.display.sortTab },
47
+ { key: "columns", label: copy.display.columnsTab },
48
+ { key: "display", label: copy.display.panelTab },
49
+ ];
50
+ }
47
51
 
48
52
  /** The saved-view chrome the panel brackets its tabs with, when a host supplies it. */
49
53
  export interface DisplayPanelView {
@@ -89,9 +93,10 @@ function PanelTabs({
89
93
  muted?: boolean;
90
94
  testIdPrefix: string;
91
95
  }): React.JSX.Element {
96
+ const copy = useDataViewsCopy();
92
97
  return (
93
98
  <Box sx={{ display: "flex", gap: 0.5, p: 0.75, bgcolor: "action.hover", borderBottom: 1, borderColor: "divider" }}>
94
- {TABS.map((entry) => {
99
+ {displayTabs(copy).map((entry) => {
95
100
  const active = tab === entry.key && !muted;
96
101
  return (
97
102
  <Box
@@ -258,6 +263,7 @@ function DisplayTrigger({
258
263
  onOpen: (anchor: HTMLElement) => void;
259
264
  testIdPrefix: string;
260
265
  }): React.JSX.Element {
266
+ const copy = useDataViewsCopy();
261
267
  return (
262
268
  <Button
263
269
  variant="outline"
@@ -265,14 +271,14 @@ function DisplayTrigger({
265
271
  color="neutral"
266
272
  onClick={(event) => onOpen(event.currentTarget as HTMLElement)}
267
273
  dataTestId={`${testIdPrefix}-display-trigger`}
268
- aria-label="Exibir"
269
- title={compact ? "Exibir" : undefined}
274
+ aria-label={copy.display.trigger}
275
+ title={compact ? copy.display.trigger : undefined}
270
276
  >
271
277
  <Box component="span" sx={{ display: "inline-flex", alignItems: "center", gap: 0.5 }}>
272
278
  <DisplaySettingsRoundedIcon fontSize="small" />
273
279
  {!compact && (
274
280
  <Box component="span" sx={{ display: { xs: "none", sm: "inline" } }}>
275
- Exibir
281
+ {copy.display.trigger}
276
282
  </Box>
277
283
  )}
278
284
  {dirty && (
@@ -1,10 +1,12 @@
1
1
  "use client";
2
2
 
3
+ import type { DataViewsCopy } from "./data-views-copy";
3
4
  import ArrowDownwardRoundedIcon from "@mui/icons-material/ArrowDownwardRounded";
4
5
  import ArrowUpwardRoundedIcon from "@mui/icons-material/ArrowUpwardRounded";
5
6
  import { useMediaQuery } from "@mui/material";
6
7
  import type { Theme } from "@mui/material";
7
8
 
9
+ import { useDataViewsCopy } from "./data-views-copy-context";
8
10
  import type { SortFieldDefinition } from "../../layout/ContentToolbar";
9
11
  import { Box } from "../../../mui/Box";
10
12
  import { Text } from "../../typography/Text";
@@ -121,12 +123,13 @@ export function SortTab({
121
123
  sortKinds,
122
124
  testIdPrefix,
123
125
  }: SortTabProps): React.JSX.Element {
126
+ const copy = useDataViewsCopy();
124
127
  const [ascLabel, descLabel] = directionLabels(sortKinds?.[activeField]);
125
128
  return (
126
129
  <Box sx={{ p: 1 }}>
127
130
  <Text variant="caption" as="p">
128
131
  <Box component="span" sx={{ px: 0.5, color: "text.secondary" }}>
129
- Direção
132
+ {copy.display.direction}
130
133
  </Box>
131
134
  </Text>
132
135
  <Box sx={{ display: "flex", gap: 0.75, mb: 1.5, mt: 0.5 }}>
@@ -214,13 +217,6 @@ function SortFieldRow({
214
217
 
215
218
  /* ── Exibição ────────────────────────────────────────────────────────────── */
216
219
 
217
- /** One line of copy per layout, saying what it is FOR rather than what it is. */
218
- const LAYOUT_HINTS: Record<DataViewsLayout, string> = {
219
- table: "Colunas comparáveis, boa para varrer números.",
220
- list: "Uma linha por item, com os dados principais.",
221
- cards: "Blocos maiores, bom para poucos itens.",
222
- board: "Colunas por etapa, para acompanhar o que está onde.",
223
- };
224
220
 
225
221
  /**
226
222
  * What density MEANS in each layout — same three values, three different
@@ -229,29 +225,21 @@ const LAYOUT_HINTS: Record<DataViewsLayout, string> = {
229
225
  * tile labels change with the layout because "Alta" over a board is meaningless
230
226
  * where "Larga" is not.
231
227
  */
232
- const DENSITY_HEADINGS: Record<DataViewsLayout, string> = {
233
- table: "Altura das linhas",
234
- list: "Altura das linhas",
235
- cards: "Cards por linha",
236
- board: "Largura das colunas",
237
- };
238
228
 
239
- const DENSITY_LABELS: Record<DataViewsLayout, Record<DataViewsDensity, string>> = {
240
- table: { compact: "Baixa", cozy: "Média", comfortable: "Alta" },
241
- list: { compact: "Baixa", cozy: "Média", comfortable: "Alta" },
242
- cards: { compact: "Muitos", cozy: "Médio", comfortable: "Poucos" },
243
- board: { compact: "Estreita", cozy: "Média", comfortable: "Larga" },
244
- };
245
229
 
246
230
  /** The density tiles, phrased for whichever layout is on screen. */
247
231
  function densityTiles(
248
232
  layout: DataViewsLayout,
233
+ copy: DataViewsCopy,
249
234
  ): { value: DataViewsDensity; label: string; gap: number; columns: number }[] {
250
- const labels = DENSITY_LABELS[layout];
235
+ // A layout the pack does not key falls back to the table's words rather
236
+ // than rendering three blank tiles — a host adding a layout should still see
237
+ // a usable control while it writes the labels for it.
238
+ const labels = copy.display.densityLabels[layout] ?? copy.display.densityLabels.table;
251
239
  return [
252
- { value: "compact", label: labels.compact, gap: 2, columns: 4 },
253
- { value: "cozy", label: labels.cozy, gap: 5, columns: 3 },
254
- { value: "comfortable", label: labels.comfortable, gap: 8, columns: 2 },
240
+ { value: "compact", label: labels?.compact ?? "compact", gap: 2, columns: 4 },
241
+ { value: "cozy", label: labels?.cozy ?? "cozy", gap: 5, columns: 3 },
242
+ { value: "comfortable", label: labels?.comfortable ?? "comfortable", gap: 8, columns: 2 },
255
243
  ];
256
244
  }
257
245
 
@@ -294,6 +282,7 @@ const LAYOUT_TILE_LABELS: Record<DataViewsLayout, string> = {
294
282
  * so rather than vanishing, for the same reason as the board note below it.
295
283
  */
296
284
  function DensityTiles({ testIdPrefix }: { testIdPrefix: string }): React.JSX.Element {
285
+ const copy = useDataViewsCopy();
297
286
  const { layout, density, setDensity } = useDataViewsLayout();
298
287
  // Matches the card grid's own `xs: "1fr"` track, so the control and the thing
299
288
  // it controls agree on where density stops meaning anything.
@@ -302,14 +291,14 @@ function DensityTiles({ testIdPrefix }: { testIdPrefix: string }): React.JSX.Ele
302
291
  return (
303
292
  <Text variant="caption" as="p">
304
293
  <Box component="span" sx={{ px: 0.5, pt: 0.5, display: "block", color: "text.disabled" }}>
305
- Um card por linha nesta largura — a densidade volta em telas maiores.
294
+ {copy.display.densityUnavailableNarrow}
306
295
  </Box>
307
296
  </Text>
308
297
  );
309
298
  }
310
299
  return (
311
300
  <Box sx={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 0.75, mt: 0.5 }}>
312
- {densityTiles(layout).map((tile) => (
301
+ {densityTiles(layout, copy).map((tile) => (
313
302
  <Tile
314
303
  key={tile.value}
315
304
  active={density === tile.value}
@@ -325,6 +314,7 @@ function DensityTiles({ testIdPrefix }: { testIdPrefix: string }): React.JSX.Ele
325
314
  }
326
315
 
327
316
  export function DisplayTab({ testIdPrefix }: { testIdPrefix: string }): React.JSX.Element {
317
+ const copy = useDataViewsCopy();
328
318
  const { layout, setLayout, canUseCards, canUseList, canUseBoard } = useDataViewsLayout();
329
319
  const available: DataViewsLayout[] = [
330
320
  "table",
@@ -361,7 +351,7 @@ export function DisplayTab({ testIdPrefix }: { testIdPrefix: string }): React.JS
361
351
  </Box>
362
352
  <Text variant="caption" as="p">
363
353
  <Box component="span" sx={{ px: 0.5, py: 1, display: "block", color: "text.disabled" }}>
364
- {LAYOUT_HINTS[layout]}
354
+ {copy.display.layoutHints[layout]}
365
355
  </Box>
366
356
  </Text>
367
357
  {/* Every layout gets this, the board included. It used to be hidden on
@@ -370,14 +360,14 @@ export function DisplayTab({ testIdPrefix }: { testIdPrefix: string }): React.JS
370
360
  control that broke rather than one that does not apply. */}
371
361
  <Text variant="caption" as="p">
372
362
  <Box component="span" sx={{ px: 0.5, color: "text.secondary" }}>
373
- {DENSITY_HEADINGS[layout]}
363
+ {copy.display.densityHeadings[layout]}
374
364
  </Box>
375
365
  </Text>
376
366
  <DensityTiles testIdPrefix={testIdPrefix} />
377
367
  {!canUseBoard && (
378
368
  <Text variant="caption" as="p">
379
369
  <Box component="span" sx={{ px: 0.5, pt: 1.25, display: "block", color: "text.disabled" }}>
380
- Esta tela não declara etapas, então não oferece quadro.
370
+ {copy.display.boardUnavailable}
381
371
  </Box>
382
372
  </Text>
383
373
  )}
@@ -5,6 +5,7 @@ import KeyboardArrowDownRoundedIcon from "@mui/icons-material/KeyboardArrowDownR
5
5
  import { CircularProgress, Popover } from "@mui/material";
6
6
  import { useState } from "react";
7
7
 
8
+ import { useDataViewsCopy } from "./data-views-copy-context";
8
9
  import { Button } from "../../form/Button";
9
10
  import { Box } from "../../../mui/Box";
10
11
  import { Text } from "../../typography/Text";
@@ -55,11 +56,6 @@ export interface DataViewExport {
55
56
  }
56
57
 
57
58
  /** One line per format: what it is, and when to reach for it. */
58
- const FORMAT_COPY: Record<DataViewExportFormat, { label: string; hint: string }> = {
59
- xlsx: { label: "Excel (.xlsx)", hint: "Abre direto, com as colunas dimensionadas" },
60
- csv: { label: "CSV (.csv)", hint: "Para importar em outro sistema" },
61
- json: { label: "JSON (.json)", hint: "Para integrações" },
62
- };
63
59
 
64
60
  const ALL_FORMATS: DataViewExportFormat[] = ["xlsx", "csv", "json"];
65
61
 
@@ -97,6 +93,7 @@ function ExportTrigger({
97
93
  /** Icon only — step 2 of the toolbar's degradation ladder. */
98
94
  compact?: boolean;
99
95
  }): React.JSX.Element {
96
+ const copy = useDataViewsCopy();
100
97
  return (
101
98
  <Button
102
99
  variant="outline"
@@ -105,9 +102,9 @@ function ExportTrigger({
105
102
  disabled={busy}
106
103
  onClick={(event) => onOpen(event.currentTarget as HTMLElement)}
107
104
  dataTestId={`${testIdPrefix}-export-trigger`}
108
- aria-label="Exportar"
105
+ aria-label={copy.export.trigger}
109
106
  // The label is gone, so the tooltip is the only thing naming the control.
110
- title={compact ? "Exportar" : undefined}
107
+ title={compact ? copy.export.trigger : undefined}
111
108
  >
112
109
  <Box component="span" sx={{ display: "inline-flex", alignItems: "center", gap: 0.5 }}>
113
110
  {busy ? <CircularProgress size={14} /> : <DownloadRoundedIcon fontSize="small" />}
@@ -133,6 +130,7 @@ function FormatRow({
133
130
  onPick: () => void;
134
131
  testIdPrefix: string;
135
132
  }): React.JSX.Element {
133
+ const copy = useDataViewsCopy();
136
134
  return (
137
135
  <Box
138
136
  component="button"
@@ -155,10 +153,10 @@ function FormatRow({
155
153
  }}
156
154
  >
157
155
  <Box component="span" sx={{ fontSize: "0.8125rem" }}>
158
- {FORMAT_COPY[format].label}
156
+ {copy.export.formats[format]?.label ?? format}
159
157
  </Box>
160
158
  <Box component="span" sx={{ fontSize: "0.6875rem", color: "text.disabled" }}>
161
- {FORMAT_COPY[format].hint}
159
+ {copy.export.formats[format]?.hint ?? ""}
162
160
  </Box>
163
161
  </Box>
164
162
  );
@@ -180,6 +178,7 @@ function ExportPanel({
180
178
  onPick: (format: DataViewExportFormat) => void;
181
179
  testIdPrefix: string;
182
180
  }): React.JSX.Element {
181
+ const copy = useDataViewsCopy();
183
182
  return (
184
183
  <Box data-testid={`${testIdPrefix}-export-panel`}>
185
184
  <Box sx={{ px: 1.5, pt: 1, pb: 1, borderBottom: 1, borderColor: "divider" }}>
@@ -190,7 +189,7 @@ function ExportPanel({
190
189
  </Text>
191
190
  <Text variant="caption" as="p">
192
191
  <Box component="span" sx={{ color: "text.disabled" }}>
193
- {columnCount} colunas visíveis, na ordem atual
192
+ {copy.export.visibleColumns(columnCount)}
194
193
  </Box>
195
194
  </Text>
196
195
  </Box>