@12-apps/ui 6.41.1 → 6.42.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 (176) hide show
  1. package/dist/_internal/components/data-display/DataGrid/DataGrid.body.js +2 -2
  2. package/dist/_internal/components/data-display/DataGrid/DataGrid.cells.js +1 -1
  3. package/dist/_internal/components/data-display/DataGrid/DataGrid.js +3 -3
  4. package/dist/_internal/components/data-display/DataViews/DataViewsGrid.js +6 -6
  5. package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +7 -7
  6. package/dist/_internal/components/data-display/DataViews/data-views-grid-bodies.js +4 -4
  7. package/dist/_internal/components/data-display/DataViews/data-views-grid-parts.js +5 -5
  8. package/dist/_internal/components/data-display/FleetMap/FleetMap.fixtures.js +1 -1
  9. package/dist/_internal/components/data-display/Lightbox/Lightbox.js +7 -7
  10. package/dist/_internal/components/data-display/Lightbox/LightboxControls.js +2 -2
  11. package/dist/_internal/components/data-display/Lightbox/LightboxCurrentMedia.js +3 -2
  12. package/dist/_internal/components/data-display/Lightbox/LightboxMedia.js +2 -1
  13. package/dist/_internal/components/data-display/Lightbox/LightboxOverlay.js +3 -3
  14. package/dist/_internal/components/data-display/Lightbox/LightboxThumbnails.js +2 -1
  15. package/dist/_internal/components/data-display/TimingDiagram/TimingDiagram.js +2 -2
  16. package/dist/_internal/components/data-display/TimingDiagram/TimingDiagram.views.js +1 -1
  17. package/dist/_internal/components/data-display/index.js +12 -12
  18. package/dist/_internal/components/feedback/TutorialOverlay/TutorialOverlay.js +2 -2
  19. package/dist/_internal/components/feedback/TutorialOverlay/TutorialStepBody.js +1 -1
  20. package/dist/_internal/components/feedback/index.js +2 -2
  21. package/dist/_internal/components/index.js +16 -16
  22. package/dist/_internal/components/layout/Dashboard/Dashboard.js +2 -2
  23. package/dist/_internal/components/layout/Dashboard/DashboardParts.js +1 -1
  24. package/dist/_internal/components/layout/SettingsLayout/SettingsLayout.js +4 -4
  25. package/dist/_internal/components/layout/SettingsLayout/SettingsPanel.js +3 -3
  26. package/dist/_internal/components/layout/SettingsLayout/SettingsSectionChips.js +2 -2
  27. package/dist/_internal/components/layout/SettingsLayout/SettingsSectionChips.scroll.js +7 -1
  28. package/dist/_internal/components/layout/index.js +2 -2
  29. package/dist/_internal/en-US.data-display.js +3 -1
  30. package/dist/_internal/en-US.feedback.js +1 -1
  31. package/dist/_internal/pt-BR.data-display.js +3 -1
  32. package/dist/_internal/pt-BR.feedback.js +1 -1
  33. package/dist/{chunk-K4L42FF6.js → chunk-24JOJJ2J.js} +3 -3
  34. package/dist/chunk-24JOJJ2J.js.map +1 -0
  35. package/dist/{chunk-LODMNSLR.js → chunk-3GYPZ5MI.js} +4 -3
  36. package/dist/chunk-3GYPZ5MI.js.map +1 -0
  37. package/dist/{chunk-HFVYWHJT.js → chunk-AP4LSXRK.js} +2 -2
  38. package/dist/{chunk-MEBQKYH4.js → chunk-BX7QWHKC.js} +2 -2
  39. package/dist/{chunk-UFNIS7KC.js → chunk-GGBFDHXE.js} +11 -8
  40. package/dist/chunk-GGBFDHXE.js.map +1 -0
  41. package/dist/chunk-GT2RCOHM.js +184 -0
  42. package/dist/chunk-GT2RCOHM.js.map +1 -0
  43. package/dist/{chunk-2XHIF3M3.js → chunk-GXQDWHPN.js} +25 -3
  44. package/dist/chunk-GXQDWHPN.js.map +1 -0
  45. package/dist/{chunk-F7JTIHV5.js → chunk-ICDAYOJ6.js} +6 -5
  46. package/dist/chunk-ICDAYOJ6.js.map +1 -0
  47. package/dist/{chunk-ASCUWG55.js → chunk-IOCY5G43.js} +8 -3
  48. package/dist/chunk-IOCY5G43.js.map +1 -0
  49. package/dist/{chunk-RZ2VZ7SL.js → chunk-JMEPGXJG.js} +2 -2
  50. package/dist/{chunk-3MEIGSDK.js → chunk-LTTYUSJ2.js} +5 -2
  51. package/dist/chunk-LTTYUSJ2.js.map +1 -0
  52. package/dist/{chunk-3AQD2EA6.js → chunk-M42ZOCO7.js} +10 -9
  53. package/dist/chunk-M42ZOCO7.js.map +1 -0
  54. package/dist/{chunk-GJFAI3J5.js → chunk-OOB3YWPX.js} +17 -10
  55. package/dist/chunk-OOB3YWPX.js.map +1 -0
  56. package/dist/{chunk-TZASFX6G.js → chunk-P53KRCKW.js} +4 -4
  57. package/dist/{chunk-2DWBJJK6.js → chunk-RBGUS7WO.js} +2 -2
  58. package/dist/{chunk-ZEYUSS3W.js → chunk-SQNQQTP7.js} +4 -3
  59. package/dist/chunk-SQNQQTP7.js.map +1 -0
  60. package/dist/chunk-SV4FYSDL.js +92 -0
  61. package/dist/chunk-SV4FYSDL.js.map +1 -0
  62. package/dist/{chunk-CKHFYTIX.js → chunk-TBMGYQJF.js} +15 -5
  63. package/dist/chunk-TBMGYQJF.js.map +1 -0
  64. package/dist/{chunk-TCNTIGMY.js → chunk-TDXEO2UI.js} +2 -2
  65. package/dist/{chunk-ASHXIAJO.js → chunk-UGH2DDST.js} +5 -2
  66. package/dist/chunk-UGH2DDST.js.map +1 -0
  67. package/dist/{chunk-WFAJTO2B.js → chunk-UVFZQCC7.js} +5 -9
  68. package/dist/chunk-UVFZQCC7.js.map +1 -0
  69. package/dist/{chunk-U5SH3VRJ.js → chunk-V5ZLUJV7.js} +25 -3
  70. package/dist/chunk-V5ZLUJV7.js.map +1 -0
  71. package/dist/{chunk-VCBV5JM7.js → chunk-VNOXUWK7.js} +2 -2
  72. package/dist/{chunk-IVJKILIX.js → chunk-VZ4VAQX3.js} +2 -2
  73. package/dist/{chunk-5QAJ3Y5F.js → chunk-XQWUVQ2F.js} +2 -2
  74. package/dist/{chunk-H5ZTIELC.js → chunk-ZFXTRPQO.js} +5 -4
  75. package/dist/chunk-ZFXTRPQO.js.map +1 -0
  76. package/dist/{chunk-UT73NGRS.js → chunk-ZSTUKSTJ.js} +2 -2
  77. package/dist/data-display/DataGrid.js +3 -3
  78. package/dist/data-display/DataViews.js +7 -7
  79. package/dist/data-display/Lightbox.js +7 -7
  80. package/dist/data-display/TimingDiagram.js +2 -2
  81. package/dist/en-US.js +4 -2
  82. package/dist/feedback/TutorialOverlay.js +2 -2
  83. package/dist/layout/Dashboard.js +2 -2
  84. package/dist/layout/SettingsLayout.js +4 -4
  85. package/dist/locales.js +8 -4
  86. package/dist/locales.js.map +1 -1
  87. package/dist/pt-BR.js +4 -2
  88. package/dist/types/components/data-display/DataGrid/DataGrid.body.d.ts.map +1 -1
  89. package/dist/types/components/data-display/DataGrid/DataGrid.cells.d.ts +3 -1
  90. package/dist/types/components/data-display/DataGrid/DataGrid.cells.d.ts.map +1 -1
  91. package/dist/types/components/data-display/DataGrid/DataGrid.d.ts +1 -1
  92. package/dist/types/components/data-display/DataGrid/DataGrid.d.ts.map +1 -1
  93. package/dist/types/components/data-display/DataGrid/DataGrid.types.d.ts +12 -2
  94. package/dist/types/components/data-display/DataGrid/DataGrid.types.d.ts.map +1 -1
  95. package/dist/types/components/data-display/DataViews/data-views-copy.d.ts +8 -2
  96. package/dist/types/components/data-display/DataViews/data-views-copy.d.ts.map +1 -1
  97. package/dist/types/components/data-display/DataViews/data-views-grid-bodies.d.ts.map +1 -1
  98. package/dist/types/components/data-display/Lightbox/Lightbox.d.ts.map +1 -1
  99. package/dist/types/components/data-display/Lightbox/LightboxMedia.d.ts.map +1 -1
  100. package/dist/types/components/data-display/Lightbox/LightboxThumbnails.d.ts.map +1 -1
  101. package/dist/types/components/data-display/TimingDiagram/TimingDiagram.d.ts.map +1 -1
  102. package/dist/types/components/data-display/TimingDiagram/TimingDiagram.views.d.ts +2 -0
  103. package/dist/types/components/data-display/TimingDiagram/TimingDiagram.views.d.ts.map +1 -1
  104. package/dist/types/components/layout/Dashboard/Dashboard.d.ts +1 -1
  105. package/dist/types/components/layout/Dashboard/Dashboard.types.d.ts +22 -12
  106. package/dist/types/components/layout/Dashboard/Dashboard.types.d.ts.map +1 -1
  107. package/dist/types/components/layout/Dashboard/DashboardParts.d.ts +1 -1
  108. package/dist/types/components/layout/Dashboard/DashboardParts.d.ts.map +1 -1
  109. package/dist/types/components/layout/SettingsLayout/SettingsSectionChips.d.ts.map +1 -1
  110. package/dist/types/components/layout/SettingsLayout/SettingsSectionChips.scroll.d.ts +20 -2
  111. package/dist/types/components/layout/SettingsLayout/SettingsSectionChips.scroll.d.ts.map +1 -1
  112. package/dist/types/copy/data-display.d.ts +40 -1
  113. package/dist/types/copy/data-display.d.ts.map +1 -1
  114. package/dist/types/copy/feedback.d.ts +7 -1
  115. package/dist/types/copy/feedback.d.ts.map +1 -1
  116. package/dist/types/en-US.data-display.d.ts +2 -1
  117. package/dist/types/en-US.data-display.d.ts.map +1 -1
  118. package/dist/types/en-US.feedback.d.ts.map +1 -1
  119. package/dist/types/locales.d.ts +2 -1
  120. package/dist/types/locales.d.ts.map +1 -1
  121. package/dist/types/pt-BR.data-display.d.ts +2 -1
  122. package/dist/types/pt-BR.data-display.d.ts.map +1 -1
  123. package/dist/types/pt-BR.feedback.d.ts.map +1 -1
  124. package/package.json +1 -1
  125. package/src/components/data-display/DataGrid/DataGrid.body.tsx +2 -1
  126. package/src/components/data-display/DataGrid/DataGrid.cells.tsx +7 -4
  127. package/src/components/data-display/DataGrid/DataGrid.tsx +2 -1
  128. package/src/components/data-display/DataGrid/DataGrid.types.ts +13 -2
  129. package/src/components/data-display/DataViews/data-views-copy.ts +8 -2
  130. package/src/components/data-display/DataViews/data-views-grid-bodies.tsx +1 -0
  131. package/src/components/data-display/Lightbox/Lightbox.tsx +8 -2
  132. package/src/components/data-display/Lightbox/LightboxMedia.tsx +5 -2
  133. package/src/components/data-display/Lightbox/LightboxThumbnails.tsx +7 -3
  134. package/src/components/data-display/TimingDiagram/TimingDiagram.tsx +10 -7
  135. package/src/components/data-display/TimingDiagram/TimingDiagram.views.tsx +6 -2
  136. package/src/components/feedback/TutorialOverlay/TutorialStepBody.tsx +2 -2
  137. package/src/components/layout/Dashboard/Dashboard.types.ts +22 -12
  138. package/src/components/layout/Dashboard/DashboardParts.tsx +10 -7
  139. package/src/components/layout/SettingsLayout/SettingsSectionChips.scroll.ts +212 -28
  140. package/src/components/layout/SettingsLayout/SettingsSectionChips.tsx +24 -4
  141. package/src/copy/data-display.ts +41 -1
  142. package/src/copy/feedback.ts +7 -1
  143. package/src/en-US.data-display.ts +23 -0
  144. package/src/en-US.feedback.ts +3 -0
  145. package/src/locales.ts +2 -0
  146. package/src/pt-BR.data-display.ts +23 -0
  147. package/src/pt-BR.feedback.ts +3 -0
  148. package/dist/chunk-2XHIF3M3.js.map +0 -1
  149. package/dist/chunk-3AQD2EA6.js.map +0 -1
  150. package/dist/chunk-3MEIGSDK.js.map +0 -1
  151. package/dist/chunk-ASCUWG55.js.map +0 -1
  152. package/dist/chunk-ASHXIAJO.js.map +0 -1
  153. package/dist/chunk-BAFDSAWY.js +0 -86
  154. package/dist/chunk-BAFDSAWY.js.map +0 -1
  155. package/dist/chunk-CKHFYTIX.js.map +0 -1
  156. package/dist/chunk-F7JTIHV5.js.map +0 -1
  157. package/dist/chunk-GJFAI3J5.js.map +0 -1
  158. package/dist/chunk-H5ZTIELC.js.map +0 -1
  159. package/dist/chunk-K4L42FF6.js.map +0 -1
  160. package/dist/chunk-LODMNSLR.js.map +0 -1
  161. package/dist/chunk-SLJAQA2X.js +0 -82
  162. package/dist/chunk-SLJAQA2X.js.map +0 -1
  163. package/dist/chunk-U5SH3VRJ.js.map +0 -1
  164. package/dist/chunk-UFNIS7KC.js.map +0 -1
  165. package/dist/chunk-WFAJTO2B.js.map +0 -1
  166. package/dist/chunk-ZEYUSS3W.js.map +0 -1
  167. /package/dist/{chunk-HFVYWHJT.js.map → chunk-AP4LSXRK.js.map} +0 -0
  168. /package/dist/{chunk-MEBQKYH4.js.map → chunk-BX7QWHKC.js.map} +0 -0
  169. /package/dist/{chunk-RZ2VZ7SL.js.map → chunk-JMEPGXJG.js.map} +0 -0
  170. /package/dist/{chunk-TZASFX6G.js.map → chunk-P53KRCKW.js.map} +0 -0
  171. /package/dist/{chunk-2DWBJJK6.js.map → chunk-RBGUS7WO.js.map} +0 -0
  172. /package/dist/{chunk-TCNTIGMY.js.map → chunk-TDXEO2UI.js.map} +0 -0
  173. /package/dist/{chunk-VCBV5JM7.js.map → chunk-VNOXUWK7.js.map} +0 -0
  174. /package/dist/{chunk-IVJKILIX.js.map → chunk-VZ4VAQX3.js.map} +0 -0
  175. /package/dist/{chunk-5QAJ3Y5F.js.map → chunk-XQWUVQ2F.js.map} +0 -0
  176. /package/dist/{chunk-UT73NGRS.js.map → chunk-ZSTUKSTJ.js.map} +0 -0
@@ -51,7 +51,7 @@ function resolveChrome<T extends Record<string, unknown>>(props: DataGridProps<T
51
51
  },
52
52
  placeholder: {
53
53
  dataTestId,
54
- ariaLabel: props.ariaLabel ?? 'Data grid',
54
+ ariaLabel: props.ariaLabel ?? props.copy.gridLabel,
55
55
  className,
56
56
  style,
57
57
  // Only the DOM-safe leftovers reach the element: every grid-specific prop
@@ -117,6 +117,7 @@ export const DataGrid = <T extends Record<string, unknown> = Record<string, unkn
117
117
  * none reaches the DOM — the check that would have caught `emptyText` missing.
118
118
  */
119
119
  export const GRID_ONLY_PROPS = [
120
+ 'copy',
120
121
  'rows',
121
122
  'columns',
122
123
  'getRowId',
@@ -1,5 +1,7 @@
1
1
  import type React from 'react';
2
2
 
3
+ import type { DataGridCopy } from '../../../copy';
4
+
3
5
  export type GridSizeMode = 'auto' | 'fixed' | 'fill';
4
6
  export type GridDensity = 'compact' | 'comfortable' | 'spacious';
5
7
  export type SortDirection = 'asc' | 'desc' | null;
@@ -83,9 +85,9 @@ export interface GridRowExpansion<T = Record<string, unknown>> {
83
85
  * toggle — a chevron that opens onto nothing is a promise the row cannot keep.
84
86
  */
85
87
  isRowExpandable?: (row: T) => boolean;
86
- /** The chevron's accessible name while the row is collapsed. Default "Expand row". */
88
+ /** The chevron's accessible name while the row is collapsed. Defaults to `copy.expandRow`. */
87
89
  expandLabel?: string;
88
- /** The chevron's accessible name while the row is expanded. Default "Collapse row". */
90
+ /** The chevron's accessible name while the row is expanded. Defaults to `copy.collapseRow`. */
89
91
  collapseLabel?: string;
90
92
  }
91
93
 
@@ -138,6 +140,15 @@ export interface DataGridProps<T = Record<string, unknown>> extends React.HTMLAt
138
140
  * "No data available", on the package every host renders.
139
141
  */
140
142
  emptyText: string;
143
+ /**
144
+ * Every fallback word the grid's own chrome renders — a sortable header's
145
+ * name, a row's selection checkbox, the select-all checkbox, the expand
146
+ * chevron's two states, and the grid's own accessible name. REQUIRED — the
147
+ * fallbacks were English literals with no way to localise them. A caller's
148
+ * `column.ariaLabel`, `expansion.expandLabel`/`collapseLabel` and the grid's
149
+ * own `ariaLabel` still win over it wherever both are given.
150
+ */
151
+ copy: DataGridCopy;
141
152
  /** Dataset (client mode uses this array; server mode renders current page) */
142
153
  rows: T[];
143
154
  /** Stable row id accessor */
@@ -1,4 +1,4 @@
1
- import type { CategorySelectCopy, ConfirmActionCopy, TableFilterCopy } from "../../../copy";
1
+ import type { CategorySelectCopy, ConfirmActionCopy, DataGridCopy, TableFilterCopy } from "../../../copy";
2
2
  import type { SavedViewsLabels } from "../../layout/ContentToolbar/ContentToolbar.types";
3
3
  /**
4
4
  * Every word the DataViews family renders, as REQUIRED host config (FUT-760).
@@ -143,7 +143,13 @@ export interface DataViewsExportCopy {
143
143
  triggerLabel: string;
144
144
  }
145
145
 
146
- export interface DataViewsGridCopy {
146
+ /**
147
+ * The table layout's own `<DataGrid>`, which this surface mounts but does not
148
+ * own — so it carries the grid's full `DataGridCopy` (its sortable headers,
149
+ * its row/select-all checkboxes, its expand chevron, its own accessible name)
150
+ * alongside the words DataViews renders around it.
151
+ */
152
+ export interface DataViewsGridCopy extends DataGridCopy {
147
153
  /** The per-row kebab's accessible name. */
148
154
  rowActions: string;
149
155
  bulkActions(selectedCount: number): string;
@@ -85,6 +85,7 @@ function GridBody<T extends Record<string, unknown>>({
85
85
  data-testid={dataTestId}
86
86
  emptyState={emptyState}
87
87
  emptyText={copy.grid.emptyFilteredTitle}
88
+ copy={copy.grid}
88
89
  />
89
90
  </Box>
90
91
  );
@@ -22,7 +22,13 @@ const DIALOG_STATIC_PROPS = {
22
22
  TransitionComponent: Fade,
23
23
  TransitionProps: { timeout: 300 },
24
24
  PaperProps: { sx: { background: (theme: Theme) => scrim(theme, 0.9), backdropFilter: (theme: Theme) => `blur(${rem(theme, 2)})` } },
25
- 'aria-label': 'Lightbox',
25
+ // `aria-labelledby` is the one accessible name for the modal itself: MUI
26
+ // forwards it (with `aria-modal` and its own `role="dialog"`) onto the
27
+ // Paper, the element that is actually the WAI-ARIA dialog. A plain
28
+ // `aria-label` alongside it would land on the OUTER root instead — a
29
+ // second, non-modal `role="dialog"` this component sets of its own accord
30
+ // — duplicating (and, as a static English literal, contradicting) the name
31
+ // the Paper already carries.
26
32
  'aria-labelledby': 'lightbox-title',
27
33
  role: 'dialog',
28
34
  'aria-modal': 'true',
@@ -51,7 +57,7 @@ export const Lightbox = React.forwardRef<LightboxRef, LightboxProps>((componentP
51
57
  >
52
58
  {/* Visually hidden title for screen readers */}
53
59
  <Typography id="lightbox-title" variant="h6" sx={{ position: 'absolute', left: sxRem(-10000) }}>
54
- Lightbox - {currentItem?.alt || `Item ${currentIndex + 1} of ${items.length}`}
60
+ {props.copy.dialogLabel} - {currentItem?.alt || props.copy.itemPosition(currentIndex + 1, items.length)}
55
61
  </Typography>
56
62
 
57
63
  <LightboxOverlay
@@ -1,6 +1,7 @@
1
1
  import type { FC } from 'react';
2
2
  import React from 'react';
3
3
 
4
+ import { useLightboxCopy } from './lightbox-copy-context';
4
5
  import type { LightboxItem } from './Lightbox.types';
5
6
 
6
7
  export interface LightboxMediaProps {
@@ -37,6 +38,8 @@ export const LightboxMedia: FC<LightboxMediaProps> = ({
37
38
  onWheel,
38
39
  onDoubleClick,
39
40
  }) => {
41
+ const copy = useLightboxCopy();
42
+
40
43
  if (item.type === 'video') {
41
44
  return (
42
45
  <video
@@ -45,7 +48,7 @@ export const LightboxMedia: FC<LightboxMediaProps> = ({
45
48
  style={{ maxWidth: '90vw', maxHeight: '80vh', objectFit: 'contain' }}
46
49
  onLoadStart={onLoadStart}
47
50
  onLoadedData={onLoaded}
48
- aria-label={item.alt || `Video ${index + 1} of ${total}`}
51
+ aria-label={item.alt || copy.videoFallback(index + 1, total)}
49
52
  data-testid={testId('video')}
50
53
  />
51
54
  );
@@ -54,7 +57,7 @@ export const LightboxMedia: FC<LightboxMediaProps> = ({
54
57
  return (
55
58
  <img
56
59
  src={item.src}
57
- alt={item.alt || `Image ${index + 1} of ${total}`}
60
+ alt={item.alt || copy.imageFallback(index + 1, total)}
58
61
  style={{
59
62
  // At 1x the image is bounded by the viewport; once zoomed it is allowed
60
63
  // to overflow so there is something to pan around.
@@ -5,6 +5,7 @@ import type { FC } from 'react';
5
5
  import React from 'react';
6
6
 
7
7
  import { thumbnailStripSx } from './Lightbox.constants';
8
+ import { useLightboxCopy } from './lightbox-copy-context';
8
9
  import type { LightboxItem } from './Lightbox.types';
9
10
  import { onMedia, sheen } from '../../../tokens/ink';
10
11
  import { rem, sxRem } from '../../../tokens/relative';
@@ -41,7 +42,9 @@ export const LightboxThumbnails: FC<LightboxThumbnailsProps> = ({
41
42
  currentIndex,
42
43
  testId,
43
44
  onSelect,
44
- }) => (
45
+ }) => {
46
+ const copy = useLightboxCopy();
47
+ return (
45
48
  <Box
46
49
  sx={{
47
50
  ...thumbnailStripSx,
@@ -78,11 +81,12 @@ export const LightboxThumbnails: FC<LightboxThumbnailsProps> = ({
78
81
  ) : (
79
82
  <img
80
83
  src={item.src}
81
- alt={item.alt || `Thumbnail ${index + 1}`}
84
+ alt={item.alt || copy.thumbnailFallback(index + 1)}
82
85
  style={{ width: '100%', height: '100%', objectFit: 'cover' }}
83
86
  />
84
87
  )}
85
88
  </Box>
86
89
  ))}
87
90
  </Box>
88
- );
91
+ );
92
+ };
@@ -5,6 +5,8 @@ import { alpha, styled } from '@mui/material/styles/index.js';
5
5
  import type { FC } from 'react';
6
6
  import React, { useMemo } from 'react';
7
7
 
8
+ import type { TimingDiagramCopy } from '../../../copy';
9
+
8
10
  import type { TimingData, TimingDiagramProps } from './TimingDiagram.types';
9
11
  import type { Phase, PhaseKey, TimingViewProps } from './TimingDiagram.views';
10
12
  import {
@@ -63,13 +65,13 @@ const calculatePercentages = (data: TimingData): Record<string, number> => {
63
65
 
64
66
  // A phase with no recorded time never happened — an HTTP request has no SSL
65
67
  // handshake, for instance — so it gets no bar and no legend entry.
66
- const phasesOf = (data: TimingData): Phase[] =>
68
+ const phasesOf = (data: TimingData, copy: TimingDiagramCopy): Phase[] =>
67
69
  [
68
- { key: 'dns', label: 'DNS Lookup', value: data.dns },
69
- { key: 'connect', label: 'Connection', value: data.connect },
70
- { key: 'ssl', label: 'SSL/TLS', value: data.ssl },
71
- { key: 'request', label: 'Request', value: data.request },
72
- { key: 'response', label: 'Response', value: data.response },
70
+ { key: 'dns', label: copy.dns, value: data.dns },
71
+ { key: 'connect', label: copy.connect, value: data.connect },
72
+ { key: 'ssl', label: copy.ssl, value: data.ssl },
73
+ { key: 'request', label: copy.request, value: data.request },
74
+ { key: 'response', label: copy.response, value: data.response },
73
75
  ].filter((phase) => phase.value !== undefined && phase.value > 0);
74
76
 
75
77
  const VIEWS: Record<string, FC<TimingViewProps>> = {
@@ -89,7 +91,7 @@ export const TimingDiagram: FC<TimingDiagramProps> = ({
89
91
  variant = 'waterfall',
90
92
  }) => {
91
93
  const percentages = useMemo(() => calculatePercentages(data), [data]);
92
- const phases = phasesOf(data);
94
+ const phases = phasesOf(data, copy);
93
95
  const View = VIEWS[variant];
94
96
 
95
97
  return (
@@ -103,6 +105,7 @@ export const TimingDiagram: FC<TimingDiagramProps> = ({
103
105
  phases={phases}
104
106
  percentages={percentages}
105
107
  data={data}
108
+ copy={copy}
106
109
  animated={animated}
107
110
  showLabels={showLabels}
108
111
  showTooltips={showTooltips}
@@ -7,6 +7,7 @@ import type { FC, ReactElement } from 'react';
7
7
  import React from 'react';
8
8
 
9
9
  import type { TimingData } from './TimingDiagram.types';
10
+ import type { TimingDiagramCopy } from '../../../copy';
10
11
  import { onMedia, sheen, uiInk } from '../../../tokens/ink';
11
12
  import { rem, rems } from '../../../tokens/relative';
12
13
 
@@ -34,6 +35,7 @@ export interface TimingViewProps {
34
35
  phases: Phase[];
35
36
  percentages: Record<string, number>;
36
37
  data: TimingData;
38
+ copy: TimingDiagramCopy;
37
39
  animated: boolean;
38
40
  showLabels: boolean;
39
41
  showTooltips: boolean;
@@ -227,6 +229,7 @@ export const StackedView: FC<TimingViewProps> = ({
227
229
  phases,
228
230
  percentages,
229
231
  data,
232
+ copy,
230
233
  animated,
231
234
  showLabels,
232
235
  showTooltips,
@@ -260,7 +263,7 @@ export const StackedView: FC<TimingViewProps> = ({
260
263
  0ms
261
264
  </Typography>
262
265
  <Typography variant="caption" color="text.secondary" fontWeight="bold">
263
- Total: {formatTime(data.total)}
266
+ {copy.total(formatTime(data.total))}
264
267
  </Typography>
265
268
  </Box>
266
269
  </Box>
@@ -328,6 +331,7 @@ export const HorizontalView: FC<TimingViewProps> = ({
328
331
  phases,
329
332
  percentages,
330
333
  data,
334
+ copy,
331
335
  animated,
332
336
  }) => {
333
337
  const theme = useTheme();
@@ -352,7 +356,7 @@ export const HorizontalView: FC<TimingViewProps> = ({
352
356
  ))}
353
357
  <Box sx={{ mt: 2, pt: 2, borderTop: `1px solid ${alpha(theme.palette.divider, 0.2)}` }}>
354
358
  <Typography variant="body2" fontWeight="bold" color="primary">
355
- Total Time: {formatTime(data.total)}
359
+ {copy.totalTime(formatTime(data.total))}
356
360
  </Typography>
357
361
  </Box>
358
362
  </HorizontalBar>
@@ -109,7 +109,7 @@ const TutorialStepNav: React.FC<{
109
109
  endIcon={<NextIcon />}
110
110
  onClick={onNext}
111
111
  disabled={requiresActionBeforeNext}
112
- title={requiresActionBeforeNext ? 'Complete the required action first' : ''}
112
+ title={requiresActionBeforeNext ? copy.requiresAction : ''}
113
113
  data-testid="tutorial-next-button"
114
114
  >
115
115
  {copy.next}
@@ -126,7 +126,7 @@ const TutorialStepNav: React.FC<{
126
126
  }}
127
127
  data-testid="tutorial-finish-button"
128
128
  >
129
- {stepCount === 1 ? 'Complete' : 'Finish'}
129
+ {stepCount === 1 ? copy.complete : copy.finish}
130
130
  </Button>
131
131
  )}
132
132
  </Stack>
@@ -52,24 +52,32 @@ export interface DashboardHeaderProps {
52
52
 
53
53
  /** Props for `<Dashboard.Info>` — an `[i]` popover summarising the page. */
54
54
  export interface DashboardInfoProps {
55
- /** Popover heading. Defaults to `"About this page"`. */
56
- title?: ReactNode;
55
+ /** Popover heading. REQUIRED — the fallback was the English "About this page". */
56
+ title: ReactNode;
57
57
  /** Popover body content. */
58
58
  children: ReactNode;
59
- /** Accessible label for the trigger. Defaults to `"Page information"`. */
60
- ariaLabel?: string;
59
+ /** Accessible label for the trigger. REQUIRED — the fallback was the English "Page information". */
60
+ ariaLabel: string;
61
61
  }
62
62
 
63
63
  /** Props for `<Dashboard.FilterToggle>` — the funnel icon. */
64
64
  export interface DashboardFilterToggleProps {
65
- /** Accessible label. Defaults to a show/hide string based on state. */
66
- ariaLabel?: string;
65
+ /**
66
+ * Accessible label while `<Dashboard.Filters>` is expanded. REQUIRED — the
67
+ * fallback was the English "Hide filters".
68
+ */
69
+ hideLabel: string;
70
+ /**
71
+ * Accessible label while `<Dashboard.Filters>` is collapsed. REQUIRED — the
72
+ * fallback was the English "Show filters".
73
+ */
74
+ showLabel: string;
67
75
  }
68
76
 
69
77
  /** Shared props for both modes of `<Dashboard.Settings>`. */
70
78
  interface DashboardSettingsBaseProps {
71
- /** Accessible label for the trigger. Defaults to `"Settings"`. */
72
- ariaLabel?: string;
79
+ /** Accessible label for the trigger. REQUIRED — the fallback was the English "Settings". */
80
+ ariaLabel: string;
73
81
  }
74
82
 
75
83
  /**
@@ -79,8 +87,8 @@ interface DashboardSettingsBaseProps {
79
87
  export interface DashboardSettingsDialogProps extends DashboardSettingsBaseProps {
80
88
  /** The dialog's close button — a glyph with no visible label. REQUIRED. */
81
89
  closeLabel: string;
82
- /** Dialog title. Defaults to `"Settings"`. */
83
- title?: ReactNode;
90
+ /** Dialog title. REQUIRED — the fallback was the English "Settings". */
91
+ title: ReactNode;
84
92
  /** Dialog body. */
85
93
  children: ReactNode;
86
94
  href?: never;
@@ -132,8 +140,10 @@ export interface DashboardExportProps {
132
140
  formats?: DashboardExportFormat[];
133
141
  /** Invoked with the chosen format id. */
134
142
  onExport: (formatId: string) => void;
135
- /** Button label. Defaults to `"Export"`. */
136
- label?: ReactNode;
143
+ /**
144
+ * Button label. REQUIRED — the fallback was the English "Export" (FUT-2568).
145
+ */
146
+ label: ReactNode;
137
147
  }
138
148
 
139
149
  /** Props for `<Dashboard.Action>` — a slot for a primary/secondary button. */
@@ -38,9 +38,9 @@ export const DashboardSpacer = (): React.JSX.Element => <Box sx={{ flex: 1 }} ar
38
38
  DashboardSpacer.displayName = 'Dashboard.Spacer';
39
39
 
40
40
  export const DashboardInfo = ({
41
- title = 'About this page',
41
+ title,
42
42
  children,
43
- ariaLabel = 'Page information',
43
+ ariaLabel,
44
44
  }: DashboardInfoProps): React.JSX.Element => {
45
45
  const { testIdPrefix } = useDashboardContext();
46
46
  const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
@@ -78,9 +78,12 @@ export const DashboardInfo = ({
78
78
  };
79
79
  DashboardInfo.displayName = 'Dashboard.Info';
80
80
 
81
- export const DashboardFilterToggle = ({ ariaLabel }: DashboardFilterToggleProps): React.JSX.Element => {
81
+ export const DashboardFilterToggle = ({
82
+ hideLabel,
83
+ showLabel,
84
+ }: DashboardFilterToggleProps): React.JSX.Element => {
82
85
  const { filtersVisible, toggleFilters, activeFilterCount, testIdPrefix } = useDashboardContext();
83
- const label = ariaLabel ?? (filtersVisible ? 'Hide filters' : 'Show filters');
86
+ const label = filtersVisible ? hideLabel : showLabel;
84
87
  return (
85
88
  <Tooltip title={label}>
86
89
  <IconButton
@@ -101,10 +104,10 @@ export const DashboardFilterToggle = ({ ariaLabel }: DashboardFilterToggleProps)
101
104
  DashboardFilterToggle.displayName = 'Dashboard.FilterToggle';
102
105
 
103
106
  export const DashboardSettings = ({
104
- title = 'Settings',
107
+ title,
105
108
  closeLabel,
106
109
  children,
107
- ariaLabel = 'Settings',
110
+ ariaLabel,
108
111
  href,
109
112
  linkComponent,
110
113
  }: DashboardSettingsProps): React.JSX.Element => {
@@ -168,7 +171,7 @@ const DEFAULT_EXPORT_FORMATS: DashboardExportFormat[] = [
168
171
  export const DashboardExport = ({
169
172
  formats = DEFAULT_EXPORT_FORMATS,
170
173
  onExport,
171
- label = 'Export',
174
+ label,
172
175
  }: DashboardExportProps): React.JSX.Element => {
173
176
  const { testIdPrefix } = useDashboardContext();
174
177
  const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);