@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
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/en-US.feedback.ts"],"sourcesContent":["/**\n * The en-US pack for the feedback family. Split the same way\n * `pt-BR.feedback.ts` is — see `en-US.ts` for why.\n */\nimport type {\n ChromeCopy,\n NotificationUnblockCopy,\n TutorialCopy,\n} from './copy';\n\nexport const EN_US_TUTORIAL_COPY: TutorialCopy = {\n skip: \"Skip\",\n previous: \"Back\",\n next: \"Next\",\n restart: \"Start over\",\n};\n\nexport const EN_US_CHROME_COPY: ChromeCopy = {\n dismissToast: \"Dismiss\",\n goBack: \"Back\",\n closePanel: \"Close\",\n closeTab: \"Close tab\",\n scrollRegion: \"Scrollable content\",\n scrollToTop: \"Back to top\",\n share: \"Share\",\n};\n\nconst EN_US_CHROMIUM_DESKTOP = [\n \"Click the icon to the left of the site's address.\",\n \"Open \\\"Site settings\\\".\",\n \"Under \\\"Notifications\\\", choose \\\"Allow\\\".\",\n \"Come back to this page and reload it.\",\n] as const;\n\nconst EN_US_CHROMIUM_ANDROID = [\n \"Tap the icon to the left of the site's address.\",\n \"Tap \\\"Permissions\\\".\",\n \"Tap \\\"Notifications\\\" and choose \\\"Allow\\\".\",\n \"Come back to this page and reload it.\",\n] as const;\n\nexport const EN_US_NOTIFICATION_UNBLOCK_COPY: NotificationUnblockCopy = {\n ios: [\n \"Open the iPhone's Settings.\",\n \"Tap \\\"Notifications\\\".\",\n \"Find this app in the list and turn on \\\"Allow Notifications\\\".\",\n ],\n chrome: { desktop: EN_US_CHROMIUM_DESKTOP, android: EN_US_CHROMIUM_ANDROID },\n edge: {\n desktop: [\n \"Click the lock to the left of the site's address.\",\n \"Open \\\"Permissions for this site\\\".\",\n \"Under \\\"Notifications\\\", choose \\\"Allow\\\".\",\n \"Come back to this page and reload it.\",\n ],\n android: EN_US_CHROMIUM_ANDROID,\n },\n firefox: {\n desktop: [\n \"Click the permissions icon to the left of the site's address.\",\n \"Next to \\\"Send notifications\\\", click the X to clear the block.\",\n \"Reload the page and turn notifications on again.\",\n ],\n android: [\n \"Open the browser menu and tap \\\"Settings\\\".\",\n \"Tap \\\"Site permissions\\\", then \\\"Notifications\\\".\",\n \"Find this site and choose \\\"Allow\\\".\",\n \"Come back to this page and reload it.\",\n ],\n },\n opera: { desktop: EN_US_CHROMIUM_DESKTOP, android: EN_US_CHROMIUM_ANDROID },\n safari: {\n desktop: [\n \"In the Safari menu, open \\\"Settings\\\".\",\n \"Go to the \\\"Websites\\\" tab and pick \\\"Notifications\\\" in the sidebar.\",\n \"Find this site and choose \\\"Allow\\\".\",\n \"Come back to this page and reload it.\",\n ],\n },\n samsung: {\n android: [\n \"Open the browser menu and tap \\\"Settings\\\".\",\n \"Tap \\\"Sites and downloads\\\", then \\\"Notifications\\\".\",\n \"Find this site and allow notifications.\",\n \"Come back to this page and reload it.\",\n ],\n },\n other: [\n \"Open the browser's settings.\",\n \"Look for site permissions, then \\\"Notifications\\\".\",\n \"Allow notifications for this site.\",\n \"Come back to this page and reload it.\",\n ],\n};\n"],"mappings":";AAUO,IAAM,sBAAoC;AAAA,EAC/C,MAAM;AAAA,EACN,UAAU;AAAA,EACV,MAAM;AAAA,EACN,SAAS;AACX;AAEO,IAAM,oBAAgC;AAAA,EAC3C,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,cAAc;AAAA,EACd,aAAa;AAAA,EACb,OAAO;AACT;AAEA,IAAM,yBAAyB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,yBAAyB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,IAAM,kCAA2D;AAAA,EACtE,KAAK;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,QAAQ,EAAE,SAAS,wBAAwB,SAAS,uBAAuB;AAAA,EAC3E,MAAM;AAAA,IACJ,SAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,SAAS;AAAA,EACX;AAAA,EACA,SAAS;AAAA,IACP,SAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,SAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EACA,OAAO,EAAE,SAAS,wBAAwB,SAAS,uBAAuB;AAAA,EAC1E,QAAQ;AAAA,IACN,SAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP,SAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EACA,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
@@ -1,86 +0,0 @@
1
- import {
2
- thumbnailStripSx
3
- } from "./chunk-3KA6MYIR.js";
4
- import {
5
- onMedia,
6
- sheen
7
- } from "./chunk-FQ6UW7IY.js";
8
- import {
9
- rem,
10
- sxRem
11
- } from "./chunk-YKCAJ2TN.js";
12
-
13
- // src/components/data-display/Lightbox/LightboxThumbnails.tsx
14
- import PlayIcon from "@mui/icons-material/PlayArrow";
15
- import Box from "@mui/material/Box/index.js";
16
- import { jsx } from "react/jsx-runtime";
17
- var THUMB = { widthPx: 60, heightPx: 40 };
18
- var frame = (theme, color) => `${rem(theme, 2)} solid ${color}`;
19
- var VideoThumbnail = () => /* @__PURE__ */ jsx(
20
- Box,
21
- {
22
- sx: {
23
- width: "100%",
24
- height: "100%",
25
- background: (theme) => sheen(theme, 0.1),
26
- display: "flex",
27
- alignItems: "center",
28
- justifyContent: "center"
29
- },
30
- children: /* @__PURE__ */ jsx(PlayIcon, { sx: { color: onMedia, fontSize: sxRem(16) } })
31
- }
32
- );
33
- var LightboxThumbnails = ({
34
- items,
35
- currentIndex,
36
- testId,
37
- onSelect
38
- }) => /* @__PURE__ */ jsx(
39
- Box,
40
- {
41
- sx: {
42
- ...thumbnailStripSx,
43
- position: "absolute",
44
- bottom: sxRem(16),
45
- left: "50%",
46
- transform: "translateX(-50%)",
47
- display: "flex",
48
- gap: 1,
49
- maxWidth: "90vw",
50
- overflowX: "auto",
51
- padding: 1
52
- },
53
- "data-testid": testId("thumbnails"),
54
- children: items.map((item, index) => /* @__PURE__ */ jsx(
55
- Box,
56
- {
57
- onClick: () => onSelect(index),
58
- sx: {
59
- width: sxRem(THUMB.widthPx),
60
- height: sxRem(THUMB.heightPx),
61
- cursor: "pointer",
62
- border: (theme) => frame(theme, currentIndex === index ? onMedia(theme) : "transparent"),
63
- borderRadius: 0.5,
64
- overflow: "hidden",
65
- flexShrink: 0,
66
- "&:hover": { border: (theme) => frame(theme, sheen(theme, 0.7)) }
67
- },
68
- "data-testid": testId(`thumbnail-${index}`),
69
- children: item.type === "video" ? /* @__PURE__ */ jsx(VideoThumbnail, {}) : /* @__PURE__ */ jsx(
70
- "img",
71
- {
72
- src: item.src,
73
- alt: item.alt || `Thumbnail ${index + 1}`,
74
- style: { width: "100%", height: "100%", objectFit: "cover" }
75
- }
76
- )
77
- },
78
- `${item.src}-${index}`
79
- ))
80
- }
81
- );
82
-
83
- export {
84
- LightboxThumbnails
85
- };
86
- //# sourceMappingURL=chunk-BAFDSAWY.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/data-display/Lightbox/LightboxThumbnails.tsx"],"sourcesContent":["import PlayIcon from '@mui/icons-material/PlayArrow';\nimport Box from '@mui/material/Box/index.js';\nimport type { Theme } from '@mui/material/styles/index.js';\nimport type { FC } from 'react';\nimport React from 'react';\n\nimport { thumbnailStripSx } from './Lightbox.constants';\nimport type { LightboxItem } from './Lightbox.types';\nimport { onMedia, sheen } from '../../../tokens/ink';\nimport { rem, sxRem } from '../../../tokens/relative';\n\n/** One filmstrip frame, in design px. */\nconst THUMB = { widthPx: 60, heightPx: 40 } as const;\n\nconst frame = (theme: Theme, color: string): string => `${rem(theme, 2)} solid ${color}`;\n\nconst VideoThumbnail: FC = () => (\n <Box\n sx={{\n width: '100%',\n height: '100%',\n background: (theme: Theme) => sheen(theme, 0.1),\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <PlayIcon sx={{ color: onMedia, fontSize: sxRem(16) }} />\n </Box>\n);\n\nexport interface LightboxThumbnailsProps {\n items: LightboxItem[];\n currentIndex: number;\n testId: (suffix: string) => string;\n onSelect: (index: number) => void;\n}\n\nexport const LightboxThumbnails: FC<LightboxThumbnailsProps> = ({\n items,\n currentIndex,\n testId,\n onSelect,\n}) => (\n <Box\n sx={{\n ...thumbnailStripSx,\n position: 'absolute',\n bottom: sxRem(16),\n left: '50%',\n transform: 'translateX(-50%)',\n display: 'flex',\n gap: 1,\n maxWidth: '90vw',\n overflowX: 'auto',\n padding: 1,\n }}\n data-testid={testId('thumbnails')}\n >\n {items.map((item, index) => (\n <Box\n key={`${item.src}-${index}`}\n onClick={() => onSelect(index)}\n sx={{\n width: sxRem(THUMB.widthPx),\n height: sxRem(THUMB.heightPx),\n cursor: 'pointer',\n border: (theme: Theme) => frame(theme, currentIndex === index ? onMedia(theme) : 'transparent'),\n borderRadius: 0.5,\n overflow: 'hidden',\n flexShrink: 0,\n '&:hover': { border: (theme: Theme) => frame(theme, sheen(theme, 0.7)) },\n }}\n data-testid={testId(`thumbnail-${index}`)}\n >\n {item.type === 'video' ? (\n <VideoThumbnail />\n ) : (\n <img\n src={item.src}\n alt={item.alt || `Thumbnail ${index + 1}`}\n style={{ width: '100%', height: '100%', objectFit: 'cover' }}\n />\n )}\n </Box>\n ))}\n </Box>\n);\n"],"mappings":";;;;;;;;;;;;;AAAA,OAAO,cAAc;AACrB,OAAO,SAAS;AA0BZ;AAfJ,IAAM,QAAQ,EAAE,SAAS,IAAI,UAAU,GAAG;AAE1C,IAAM,QAAQ,CAAC,OAAc,UAA0B,GAAG,IAAI,OAAO,CAAC,CAAC,UAAU,KAAK;AAEtF,IAAM,iBAAqB,MACzB;AAAA,EAAC;AAAA;AAAA,IACC,IAAI;AAAA,MACF,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,YAAY,CAAC,UAAiB,MAAM,OAAO,GAAG;AAAA,MAC9C,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,gBAAgB;AAAA,IAClB;AAAA,IAEA,8BAAC,YAAS,IAAI,EAAE,OAAO,SAAS,UAAU,MAAM,EAAE,EAAE,GAAG;AAAA;AACzD;AAUK,IAAM,qBAAkD,CAAC;AAAA,EAC9D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MACE;AAAA,EAAC;AAAA;AAAA,IACC,IAAI;AAAA,MACF,GAAG;AAAA,MACH,UAAU;AAAA,MACV,QAAQ,MAAM,EAAE;AAAA,MAChB,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS;AAAA,MACT,KAAK;AAAA,MACL,UAAU;AAAA,MACV,WAAW;AAAA,MACX,SAAS;AAAA,IACX;AAAA,IACA,eAAa,OAAO,YAAY;AAAA,IAE/B,gBAAM,IAAI,CAAC,MAAM,UAChB;AAAA,MAAC;AAAA;AAAA,QAEC,SAAS,MAAM,SAAS,KAAK;AAAA,QAC7B,IAAI;AAAA,UACF,OAAO,MAAM,MAAM,OAAO;AAAA,UAC1B,QAAQ,MAAM,MAAM,QAAQ;AAAA,UAC5B,QAAQ;AAAA,UACR,QAAQ,CAAC,UAAiB,MAAM,OAAO,iBAAiB,QAAQ,QAAQ,KAAK,IAAI,aAAa;AAAA,UAC9F,cAAc;AAAA,UACd,UAAU;AAAA,UACV,YAAY;AAAA,UACZ,WAAW,EAAE,QAAQ,CAAC,UAAiB,MAAM,OAAO,MAAM,OAAO,GAAG,CAAC,EAAE;AAAA,QACzE;AAAA,QACA,eAAa,OAAO,aAAa,KAAK,EAAE;AAAA,QAEvC,eAAK,SAAS,UACb,oBAAC,kBAAe,IAEhB;AAAA,UAAC;AAAA;AAAA,YACC,KAAK,KAAK;AAAA,YACV,KAAK,KAAK,OAAO,aAAa,QAAQ,CAAC;AAAA,YACvC,OAAO,EAAE,OAAO,QAAQ,QAAQ,QAAQ,WAAW,QAAQ;AAAA;AAAA,QAC7D;AAAA;AAAA,MArBG,GAAG,KAAK,GAAG,IAAI,KAAK;AAAA,IAuB3B,CACD;AAAA;AACH;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/layout/SettingsLayout/SettingsSectionChips.tsx"],"sourcesContent":["'use client';\n\nimport Box from '@mui/material/Box/index.js';\nimport { alpha, useTheme, type Theme } from '@mui/material/styles/index.js';\nimport React, { useEffect, useRef, type RefObject } from 'react';\n\nimport { watchVisitorScroll } from './SettingsSectionChips.scroll';\nimport { SettingsStatusMarker } from './SettingsStatusMarker';\nimport { TOUCH_TARGET } from './SettingsLayout.styles';\nimport { rem, sxRem } from '../../../tokens/relative';\n\n/**\n * The chip's drawn height, against `TOUCH_TARGET`'s 44 for the tappable one.\n *\n * The strip sits between a section's header and its first field on the width\n * with the least room for either, so the pill is sized to its text rather than\n * to the thumb — and the thumb is served by the hit area instead.\n */\nconst CHIP_HEIGHT = sxRem(34);\nimport type { SettingsLayoutProps, SettingsNavItem } from './SettingsLayout.types';\n\nexport interface SettingsSectionChipsProps {\n /** The sibling sections to offer — usually the open item's own group. */\n items: SettingsNavItem[];\n /** Which one is open. */\n activeItemId?: string;\n /** Accessible name of the strip, in the host's language. */\n ariaLabel: string;\n linkComponent?: SettingsLayoutProps['linkComponent'];\n onSelectItem?: (id: string) => void;\n testIdPrefix: string;\n}\n\n/** True when the visitor asked the OS for less movement. Re-read per scroll. */\nfunction prefersReducedMotion(): boolean {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return false;\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n}\n\n/**\n * Where the strip has to scroll for `chip`'s centre to sit on its own, clamped\n * to what the strip can scroll.\n *\n * Measured from the two boxes rather than from `chip.offsetLeft`. `offsetLeft`\n * counts from the nearest POSITIONED ancestor, and the strip is not one — nor\n * are the panel and layout around it — so it counted from whatever box the host\n * happened to position, and every target overshot by the strip's offset inside\n * it. The clamp hid that for the last chip; a middle one was simply off-centre.\n * The boxes are both in viewport coordinates, so their difference is the strip's\n * own, whatever the host wraps it in.\n */\nfunction centredScrollLeft(strip: HTMLElement, chip: HTMLElement): number {\n const chipBox = chip.getBoundingClientRect();\n const visibleStart = strip.getBoundingClientRect().left + strip.clientLeft;\n const chipCentre = chipBox.left - visibleStart + strip.scrollLeft + chipBox.width / 2;\n const target = chipCentre - strip.clientWidth / 2;\n return Math.max(0, Math.min(target, strip.scrollWidth - strip.clientWidth));\n}\n\n/** The chip for `id`, walked rather than selected. */\nfunction findChip(strip: HTMLElement, id: string): HTMLElement | undefined {\n // An id is host data, and a section id carrying a quote would turn a selector\n // string into a thrown SyntaxError — which here would take the whole strip\n // down to centre one chip.\n return Array.from(strip.children).find(\n (node): node is HTMLElement => node instanceof HTMLElement && node.dataset.chipId === id,\n );\n}\n\n/**\n * Keep the open section's chip in view, however the visitor got here — and\n * however the strip's content settles after it mounted.\n *\n * Keyed on `activeItemId` in an effect rather than done in a click handler:\n * arriving by the desktop rail, by a card, by a pasted link and by the browser's\n * back button all have to land the same way, and only one of those is a click on\n * a chip. Every re-render otherwise starts the strip at scroll 0, which parks\n * the active chip off the right edge on any list longer than a screen — the\n * visitor is told where they are by an element they cannot see.\n *\n * Centring ONCE is not enough (FUT-2606). A host can widen a chip after mount\n * with the ids unchanged — a status marker whose read resolves late, a web font\n * arriving — and a strip that fitted at mount then overflows with its last chip\n * clipped, because the one centring saw nothing to scroll. So the strip and\n * every chip are watched with a `ResizeObserver`, and a resize re-aims at the\n * active chip when its target has moved.\n *\n * Never against the visitor, though: once they have scrolled the strip\n * themselves, it is theirs until the open section changes\n * ({@link watchVisitorScroll}, which also says why the strip's OWN smooth scroll\n * never counts as theirs). A strip that yanks back mid-drag because a\n * marker loaded is worse than one that does not centre.\n *\n * `itemsKey` rather than `items`: a host almost always rebuilds that array per\n * render (`groups.flatMap(...)`), and depending on it would re-run this on every\n * render and reset the visitor's latch with it.\n *\n * The key joins on NUL — as the ESCAPE `'\\u0000'`, which it must stay. A\n * literal NUL byte works identically at runtime and makes git classify this file\n * as BINARY: `git diff` prints \"Binary file not shown\" and the GitHub review UI\n * shows nothing at all. This file shipped that way once, and the cost was not\n * the byte — it was a whole change nobody could read.\n */\nfunction useCentreActiveChip(\n stripRef: RefObject<HTMLDivElement | null>,\n activeItemId: string | undefined,\n itemsKey: string,\n): void {\n useEffect(() => {\n const strip = stripRef.current;\n if (!strip || !activeItemId) return undefined;\n // Feature-checked, not assumed. `Element.scrollTo` is absent in jsdom and in\n // a few embedded webviews, and an unguarded call there THROWS out of an\n // effect — which React escalates to the nearest error boundary. The whole\n // settings area would go down to centre one chip, and the host's own tests\n // could not render the shell at all. Same reasoning as walking the children\n // instead of building a selector: nothing in here is worth a crash.\n if (typeof strip.scrollTo !== 'function') return undefined;\n const visitor = watchVisitorScroll(strip);\n const centre = (): void => {\n const chip = findChip(strip, activeItemId);\n // Not while a scroll that may be the visitor's is still moving: a resize\n // mid-drag must not yank the strip. It is re-tried once that scroll rests.\n if (!chip || visitor.hasScrolled() || visitor.isUndecided()) return;\n const left = centredScrollLeft(strip, chip);\n // Only when the target MOVED: a resize that leaves it where it was must not\n // restart a smooth scroll that is already on its way there. The aim is a\n // runtime-computed scroll offset, like the exempt `left` below — not a size.\n if (Math.abs(left - visitor.aimedAt()) < 0.5) return;\n visitor.beforeOwnScroll(left);\n strip.scrollTo({ left, behavior: prefersReducedMotion() ? 'auto' : 'smooth' });\n };\n visitor.onSettled(centre);\n centre();\n // Also feature-checked: without it the strip still centres once, as before.\n const resizes = typeof ResizeObserver === 'function' ? new ResizeObserver(centre) : undefined;\n resizes?.observe(strip);\n for (const child of Array.from(strip.children)) resizes?.observe(child);\n return () => {\n resizes?.disconnect();\n visitor.detach();\n };\n }, [stripRef, activeItemId, itemsKey]);\n}\n\n/** One chip: a link when the host gave it a target, else a button. */\nfunction SectionChip({\n item,\n active,\n theme,\n linkComponent,\n onSelectItem,\n testIdPrefix,\n}: {\n item: SettingsNavItem;\n active: boolean;\n theme: Theme;\n linkComponent?: SettingsLayoutProps['linkComponent'];\n onSelectItem?: (id: string) => void;\n testIdPrefix: string;\n}): React.JSX.Element {\n const asLink = item.href !== undefined && linkComponent !== undefined;\n const behaviour = asLink\n ? { component: linkComponent, href: item.href }\n : { component: 'button' as const, type: 'button' as const, onClick: () => onSelectItem?.(item.id) };\n\n return (\n <Box\n {...behaviour}\n data-chip-id={item.id}\n data-testid={`${testIdPrefix}-chip-${item.id}`}\n aria-current={active ? 'page' : undefined}\n sx={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: 0.75,\n flex: '0 0 auto',\n position: 'relative',\n // The chip LOOKS this tall; it is still tapped at `TOUCH_TARGET`.\n //\n // Shrinking `minHeight` alone would have bought a slimmer strip with a\n // smaller hit area — on the one width where the strip IS the navigation\n // and the input is a thumb. The `::after` below keeps the tappable\n // region at the full target while the pill itself takes less room, so\n // this is a visual change and not an accessibility trade.\n minHeight: CHIP_HEIGHT,\n px: 1.5,\n borderRadius: 999,\n cursor: 'pointer',\n font: 'inherit',\n fontSize: rem(theme, 13),\n fontWeight: active ? 700 : 500,\n textDecoration: 'none',\n whiteSpace: 'nowrap',\n color: active ? 'primary.main' : 'text.secondary',\n bgcolor: active ? alpha(theme.palette.primary.main, 0.12) : 'transparent',\n border: `1px solid ${active ? alpha(theme.palette.primary.main, 0.4) : theme.palette.divider}`,\n // Spans the chip's width only, so neighbours never overlap: the strip\n // is a row, and the extra reach is vertical.\n '&::after': {\n content: '\"\"',\n position: 'absolute',\n insetInlineStart: 0,\n insetInlineEnd: 0,\n top: '50%',\n transform: 'translateY(-50%)',\n height: rem(theme, TOUCH_TARGET),\n },\n }}\n >\n {item.status ? (\n <SettingsStatusMarker\n status={item.status}\n label={item.statusLabel}\n testId={`${testIdPrefix}-chip-status-${item.id}`}\n />\n ) : null}\n {item.label}\n </Box>\n );\n}\n\n/**\n * The narrow-width section strip: horizontally scrollable chips for the sections\n * beside the open one.\n *\n * It clips its own overflow — `overflow-x: auto` on the strip, never on an\n * ancestor. A strip that pushes the page wide makes every OTHER screen at that\n * width scroll sideways too, and the cause is nowhere near the symptom.\n */\nexport function SettingsSectionChips({\n items,\n activeItemId,\n ariaLabel,\n linkComponent,\n onSelectItem,\n testIdPrefix,\n}: SettingsSectionChipsProps): React.JSX.Element {\n const theme = useTheme();\n const stripRef = useRef<HTMLDivElement | null>(null);\n useCentreActiveChip(stripRef, activeItemId, items.map((item) => item.id).join('\\u0000'));\n\n return (\n <Box\n ref={stripRef}\n component=\"nav\"\n aria-label={ariaLabel}\n data-testid={`${testIdPrefix}-chips`}\n sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 0.75,\n px: 0.25,\n py: 0.25,\n overflowX: 'auto',\n overflowY: 'hidden',\n scrollbarWidth: 'none',\n '&::-webkit-scrollbar': { display: 'none' },\n }}\n >\n {items.map((item) => (\n <SectionChip\n key={item.id}\n item={item}\n active={item.id === activeItemId}\n theme={theme}\n linkComponent={linkComponent}\n onSelectItem={onSelectItem}\n testIdPrefix={testIdPrefix}\n />\n ))}\n </Box>\n );\n}\n\nSettingsSectionChips.displayName = 'SettingsSectionChips';\n"],"mappings":";;;;;;;;;;;;;;;AAEA,OAAO,SAAS;AAChB,SAAS,OAAO,gBAA4B;AAC5C,SAAgB,WAAW,cAA8B;AAmKrD,SA4CI,KA5CJ;AArJJ,IAAM,cAAc,MAAM,EAAE;AAgB5B,SAAS,uBAAgC;AACvC,MAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,WAAY,QAAO;AACrF,SAAO,OAAO,WAAW,kCAAkC,EAAE;AAC/D;AAcA,SAAS,kBAAkB,OAAoB,MAA2B;AACxE,QAAM,UAAU,KAAK,sBAAsB;AAC3C,QAAM,eAAe,MAAM,sBAAsB,EAAE,OAAO,MAAM;AAChE,QAAM,aAAa,QAAQ,OAAO,eAAe,MAAM,aAAa,QAAQ,QAAQ;AACpF,QAAM,SAAS,aAAa,MAAM,cAAc;AAChD,SAAO,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,MAAM,cAAc,MAAM,WAAW,CAAC;AAC5E;AAGA,SAAS,SAAS,OAAoB,IAAqC;AAIzE,SAAO,MAAM,KAAK,MAAM,QAAQ,EAAE;AAAA,IAChC,CAAC,SAA8B,gBAAgB,eAAe,KAAK,QAAQ,WAAW;AAAA,EACxF;AACF;AAoCA,SAAS,oBACP,UACA,cACA,UACM;AACN,YAAU,MAAM;AACd,UAAM,QAAQ,SAAS;AACvB,QAAI,CAAC,SAAS,CAAC,aAAc,QAAO;AAOpC,QAAI,OAAO,MAAM,aAAa,WAAY,QAAO;AACjD,UAAM,UAAU,mBAAmB,KAAK;AACxC,UAAM,SAAS,MAAY;AACzB,YAAM,OAAO,SAAS,OAAO,YAAY;AAGzC,UAAI,CAAC,QAAQ,QAAQ,YAAY,KAAK,QAAQ,YAAY,EAAG;AAC7D,YAAM,OAAO,kBAAkB,OAAO,IAAI;AAI1C,UAAI,KAAK,IAAI,OAAO,QAAQ,QAAQ,CAAC,IAAI,IAAK;AAC9C,cAAQ,gBAAgB,IAAI;AAC5B,YAAM,SAAS,EAAE,MAAM,UAAU,qBAAqB,IAAI,SAAS,SAAS,CAAC;AAAA,IAC/E;AACA,YAAQ,UAAU,MAAM;AACxB,WAAO;AAEP,UAAM,UAAU,OAAO,mBAAmB,aAAa,IAAI,eAAe,MAAM,IAAI;AACpF,aAAS,QAAQ,KAAK;AACtB,eAAW,SAAS,MAAM,KAAK,MAAM,QAAQ,EAAG,UAAS,QAAQ,KAAK;AACtE,WAAO,MAAM;AACX,eAAS,WAAW;AACpB,cAAQ,OAAO;AAAA,IACjB;AAAA,EACF,GAAG,CAAC,UAAU,cAAc,QAAQ,CAAC;AACvC;AAGA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAOsB;AACpB,QAAM,SAAS,KAAK,SAAS,UAAa,kBAAkB;AAC5D,QAAM,YAAY,SACd,EAAE,WAAW,eAAe,MAAM,KAAK,KAAK,IAC5C,EAAE,WAAW,UAAmB,MAAM,UAAmB,SAAS,MAAM,eAAe,KAAK,EAAE,EAAE;AAEpG,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,gBAAc,KAAK;AAAA,MACnB,eAAa,GAAG,YAAY,SAAS,KAAK,EAAE;AAAA,MAC5C,gBAAc,SAAS,SAAS;AAAA,MAChC,IAAI;AAAA,QACF,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,KAAK;AAAA,QACL,MAAM;AAAA,QACN,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAQV,WAAW;AAAA,QACX,IAAI;AAAA,QACJ,cAAc;AAAA,QACd,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,UAAU,IAAI,OAAO,EAAE;AAAA,QACvB,YAAY,SAAS,MAAM;AAAA,QAC3B,gBAAgB;AAAA,QAChB,YAAY;AAAA,QACZ,OAAO,SAAS,iBAAiB;AAAA,QACjC,SAAS,SAAS,MAAM,MAAM,QAAQ,QAAQ,MAAM,IAAI,IAAI;AAAA,QAC5D,QAAQ,aAAa,SAAS,MAAM,MAAM,QAAQ,QAAQ,MAAM,GAAG,IAAI,MAAM,QAAQ,OAAO;AAAA;AAAA;AAAA,QAG5F,YAAY;AAAA,UACV,SAAS;AAAA,UACT,UAAU;AAAA,UACV,kBAAkB;AAAA,UAClB,gBAAgB;AAAA,UAChB,KAAK;AAAA,UACL,WAAW;AAAA,UACX,QAAQ,IAAI,OAAO,YAAY;AAAA,QACjC;AAAA,MACF;AAAA,MAEC;AAAA,aAAK,SACJ;AAAA,UAAC;AAAA;AAAA,YACC,QAAQ,KAAK;AAAA,YACb,OAAO,KAAK;AAAA,YACZ,QAAQ,GAAG,YAAY,gBAAgB,KAAK,EAAE;AAAA;AAAA,QAChD,IACE;AAAA,QACH,KAAK;AAAA;AAAA;AAAA,EACR;AAEJ;AAUO,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAiD;AAC/C,QAAM,QAAQ,SAAS;AACvB,QAAM,WAAW,OAA8B,IAAI;AACnD,sBAAoB,UAAU,cAAc,MAAM,IAAI,CAAC,SAAS,KAAK,EAAE,EAAE,KAAK,IAAQ,CAAC;AAEvF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,WAAU;AAAA,MACV,cAAY;AAAA,MACZ,eAAa,GAAG,YAAY;AAAA,MAC5B,IAAI;AAAA,QACF,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,KAAK;AAAA,QACL,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,WAAW;AAAA,QACX,WAAW;AAAA,QACX,gBAAgB;AAAA,QAChB,wBAAwB,EAAE,SAAS,OAAO;AAAA,MAC5C;AAAA,MAEC,gBAAM,IAAI,CAAC,SACV;AAAA,QAAC;AAAA;AAAA,UAEC;AAAA,UACA,QAAQ,KAAK,OAAO;AAAA,UACpB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA,QANK,KAAK;AAAA,MAOZ,CACD;AAAA;AAAA,EACH;AAEJ;AAEA,qBAAqB,cAAc;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/data-display/DataGrid/DataGrid.cells.tsx"],"sourcesContent":["/**\n * The DataGrid's cell and row renderers.\n *\n * Components rather than closures over the grid's scope: as inline `render*`\n * functions they could reach every piece of the component's state, which is how\n * the body grew past 700 lines. Each one now states exactly what it needs.\n */\nimport ArrowDownward from '@mui/icons-material/ArrowDownward';\nimport ArrowUpward from '@mui/icons-material/ArrowUpward';\nimport ExpandLess from '@mui/icons-material/ExpandLess';\nimport ExpandMore from '@mui/icons-material/ExpandMore';\nimport UnfoldMore from '@mui/icons-material/UnfoldMore';\nimport Button from '@mui/material/Button/index.js';\nimport Checkbox from '@mui/material/Checkbox/index.js';\nimport IconButton from '@mui/material/IconButton/index.js';\nimport TableCell from '@mui/material/TableCell/index.js';\nimport TableRow from '@mui/material/TableRow/index.js';\nimport Typography from '@mui/material/Typography/index.js';\nimport { useTheme, type Theme } from '@mui/material/styles/index.js';\nimport React from 'react';\n\nimport { rem } from '../../../tokens/relative';\n\nimport { cellValue } from './DataGrid.rows';\nimport type { DataGridModel } from './DataGrid.model';\nimport type { DataGridProps, GridColumn, GridSort } from './DataGrid.types';\n\n/** The glyph for a column's current sort state — unsorted included. */\nfunction SortIcon({ dir }: { dir: GridSort['dir'] | undefined }): React.JSX.Element {\n if (!dir) return <UnfoldMore fontSize=\"small\" sx={{ opacity: 0.5 }} />;\n return dir === 'asc' ? <ArrowUpward fontSize=\"small\" /> : <ArrowDownward fontSize=\"small\" />;\n}\n\n/** `aria-sort`'s three values, which are not the same words as `SortDirection`. */\nfunction ariaSort(dir: GridSort['dir'] | undefined): 'none' | 'ascending' | 'descending' {\n if (!dir) return 'none';\n return dir === 'asc' ? 'ascending' : 'descending';\n}\n\n/**\n * One of a column's `width`/`minWidth`/`maxWidth` as CSS. A number is design\n * px through the type scale — except 1 or less, which `sx` has always read as a\n * fraction of the table and still does; a string (`'312px'`, `'20%'`) is used as\n * given.\n */\nfunction columnLength(theme: Theme, value: number | string | undefined): string | undefined {\n if (typeof value !== 'number') return value;\n return value <= 1 && value !== 0 ? `${value * 100}%` : rem(theme, value);\n}\n\n/** A column's size constraints, as the `sx` of its header and its cells. */\nfunction columnBox<T extends Record<string, unknown>>(\n theme: Theme,\n column: GridColumn<T>,\n): { minWidth?: string; maxWidth?: string; width?: string } {\n return {\n minWidth: columnLength(theme, column.minWidth),\n maxWidth: columnLength(theme, column.maxWidth),\n width: columnLength(theme, column.width),\n };\n}\n\nexport interface HeaderCellProps<T extends Record<string, unknown>> {\n column: GridColumn<T>;\n sort: GridSort | undefined;\n sortable: boolean;\n stickyHeader: boolean;\n /** The header row's height, as CSS. */\n headerHeight: string;\n onSort: (columnId: string) => void;\n}\n\nexport function HeaderCell<T extends Record<string, unknown>>({\n column,\n sort,\n sortable,\n stickyHeader,\n headerHeight,\n onSort,\n}: HeaderCellProps<T>): React.JSX.Element {\n const theme = useTheme();\n const content = column.headerCell ? column.headerCell(column) : column.header;\n return (\n <TableCell\n data-slot=\"header-cell\"\n data-sort={sort?.dir ?? 'none'}\n sx={{\n position: stickyHeader ? 'sticky' : 'static',\n top: 0,\n zIndex: 1,\n backgroundColor: theme.palette.background.paper,\n borderBottom: `1px solid ${theme.palette.divider}`,\n height: headerHeight,\n ...columnBox(theme, column),\n }}\n role=\"columnheader\"\n aria-sort={ariaSort(sort?.dir)}\n >\n {sortable ? (\n <Button\n onClick={() => onSort(column.id)}\n sx={{\n justifyContent: 'flex-start',\n textTransform: 'none',\n fontWeight: 500,\n color: 'inherit',\n p: 0,\n minWidth: 0,\n '&:hover': { backgroundColor: 'transparent', opacity: 0.8 },\n }}\n endIcon={<SortIcon dir={sort?.dir} />}\n aria-label={column.ariaLabel ?? `Sort by ${String(column.header)}`}\n >\n {content}\n </Button>\n ) : (\n <Typography variant=\"subtitle2\" fontWeight={500}>\n {content}\n </Typography>\n )}\n </TableCell>\n );\n}\n\nexport interface DataCellProps<T extends Record<string, unknown>> {\n row: T;\n rowIndex: number;\n rowId: string | number;\n column: GridColumn<T>;\n /** The row's height, as CSS — `DataGridModel.rowHeight`. */\n rowHeight: string;\n editing: NonNullable<DataGridProps<T>['editing']>;\n model: Pick<DataGridModel<T>, 'editingCell' | 'setEditingCell'>;\n}\n\nexport function DataCell<T extends Record<string, unknown>>({\n row,\n rowIndex,\n rowId,\n column,\n rowHeight,\n editing,\n model,\n}: DataCellProps<T>): React.JSX.Element {\n const theme = useTheme();\n const value = cellValue(row, column);\n const isEditing =\n model.editingCell?.rowId === rowId && model.editingCell?.colId === column.id;\n const content = column.cell\n ? column.cell({ value, row, rowIndex, col: column })\n : String(value ?? '');\n return (\n <TableCell\n data-slot=\"cell\"\n data-col-id={column.id}\n data-editing={isEditing}\n sx={{\n ...columnBox(theme, column),\n height: rowHeight,\n }}\n role=\"gridcell\"\n tabIndex={-1}\n >\n {isEditing && column.editor\n ? column.editor({\n value,\n row,\n onChange: () => undefined,\n commit: () => {\n editing.onEditCommit?.({ rowId, colId: column.id, value, row });\n model.setEditingCell(null);\n },\n cancel: () => model.setEditingCell(null),\n })\n : content}\n </TableCell>\n );\n}\n\nexport interface GridRowProps<T extends Record<string, unknown>> {\n row: T;\n index: number;\n rowId: string | number;\n isSelected: boolean;\n isExpanded: boolean;\n totalColumns: number;\n model: DataGridModel<T>;\n props: DataGridProps<T>;\n}\n\n/** The leading checkbox / chevron cells, which exist only for enabled features. */\nfunction RowControls<T extends Record<string, unknown>>({\n row,\n index,\n rowId,\n isSelected,\n isExpanded,\n model,\n props,\n}: GridRowProps<T>): React.JSX.Element {\n const { selection = { mode: 'none' }, expansion } = props;\n return (\n <>\n {selection.mode !== 'none' && (\n <TableCell padding=\"checkbox\">\n <Checkbox\n checked={isSelected}\n onChange={(event) => model.onToggleRow(rowId, event.target.checked)}\n inputProps={{ 'aria-label': `Select row ${index + 1}` }}\n />\n </TableCell>\n )}\n {expansion && (\n <TableCell padding=\"checkbox\">\n {expansion.isRowExpandable?.(row) === false ? null : (\n <IconButton\n size=\"small\"\n // Stopped so a host that opens the record on a row click does not\n // ALSO open it here: the chevron is its own control.\n onClick={(event) => {\n event.stopPropagation();\n model.onToggleExpansion(rowId);\n }}\n aria-expanded={isExpanded}\n aria-label={\n isExpanded\n ? (expansion.collapseLabel ?? 'Collapse row')\n : (expansion.expandLabel ?? 'Expand row')\n }\n data-slot=\"expand-toggle\"\n >\n {isExpanded ? <ExpandLess /> : <ExpandMore />}\n </IconButton>\n )}\n </TableCell>\n )}\n </>\n );\n}\n\nexport function GridRow<T extends Record<string, unknown>>(\n rowProps: GridRowProps<T>,\n): React.JSX.Element {\n const { row, index, rowId, isSelected, isExpanded, totalColumns, model, props } = rowProps;\n const theme = useTheme();\n const expansion = props.expansion;\n return (\n <React.Fragment>\n <TableRow\n data-slot=\"row\"\n data-selected={isSelected}\n data-expanded={isExpanded}\n sx={{\n '&:hover': { backgroundColor: theme.palette.action.hover },\n ...(isSelected && { backgroundColor: theme.palette.action.selected }),\n height: model.rowHeight,\n }}\n role=\"row\"\n aria-selected={isSelected}\n >\n <RowControls {...rowProps} />\n {model.visibleColumns.map((column) => (\n <DataCell\n key={column.id}\n row={row}\n rowIndex={index}\n rowId={rowId}\n column={column}\n rowHeight={model.rowHeight}\n editing={props.editing ?? { mode: 'none' }}\n model={model}\n />\n ))}\n </TableRow>\n {expansion && isExpanded && expansion.isRowExpandable?.(row) !== false && (\n <TableRow data-slot=\"row-detail\">\n <TableCell colSpan={totalColumns}>{expansion.render(row, index)}</TableCell>\n </TableRow>\n )}\n </React.Fragment>\n );\n}\n"],"mappings":";;;;;;;;AAOA,OAAO,mBAAmB;AAC1B,OAAO,iBAAiB;AACxB,OAAO,gBAAgB;AACvB,OAAO,gBAAgB;AACvB,OAAO,gBAAgB;AACvB,OAAO,YAAY;AACnB,OAAO,cAAc;AACrB,OAAO,gBAAgB;AACvB,OAAO,eAAe;AACtB,OAAO,cAAc;AACrB,OAAO,gBAAgB;AACvB,SAAS,gBAA4B;AACrC,OAAO,WAAW;AAUC,SA6Kf,UA7Ke,KA6Kf,YA7Ke;AADnB,SAAS,SAAS,EAAE,IAAI,GAA4D;AAClF,MAAI,CAAC,IAAK,QAAO,oBAAC,cAAW,UAAS,SAAQ,IAAI,EAAE,SAAS,IAAI,GAAG;AACpE,SAAO,QAAQ,QAAQ,oBAAC,eAAY,UAAS,SAAQ,IAAK,oBAAC,iBAAc,UAAS,SAAQ;AAC5F;AAGA,SAAS,SAAS,KAAuE;AACvF,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,QAAQ,QAAQ,cAAc;AACvC;AAQA,SAAS,aAAa,OAAc,OAAwD;AAC1F,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,SAAO,SAAS,KAAK,UAAU,IAAI,GAAG,QAAQ,GAAG,MAAM,IAAI,OAAO,KAAK;AACzE;AAGA,SAAS,UACP,OACA,QAC0D;AAC1D,SAAO;AAAA,IACL,UAAU,aAAa,OAAO,OAAO,QAAQ;AAAA,IAC7C,UAAU,aAAa,OAAO,OAAO,QAAQ;AAAA,IAC7C,OAAO,aAAa,OAAO,OAAO,KAAK;AAAA,EACzC;AACF;AAYO,SAAS,WAA8C;AAAA,EAC5D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0C;AACxC,QAAM,QAAQ,SAAS;AACvB,QAAM,UAAU,OAAO,aAAa,OAAO,WAAW,MAAM,IAAI,OAAO;AACvE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,aAAW,MAAM,OAAO;AAAA,MACxB,IAAI;AAAA,QACF,UAAU,eAAe,WAAW;AAAA,QACpC,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,iBAAiB,MAAM,QAAQ,WAAW;AAAA,QAC1C,cAAc,aAAa,MAAM,QAAQ,OAAO;AAAA,QAChD,QAAQ;AAAA,QACR,GAAG,UAAU,OAAO,MAAM;AAAA,MAC5B;AAAA,MACA,MAAK;AAAA,MACL,aAAW,SAAS,MAAM,GAAG;AAAA,MAE5B,qBACC;AAAA,QAAC;AAAA;AAAA,UACC,SAAS,MAAM,OAAO,OAAO,EAAE;AAAA,UAC/B,IAAI;AAAA,YACF,gBAAgB;AAAA,YAChB,eAAe;AAAA,YACf,YAAY;AAAA,YACZ,OAAO;AAAA,YACP,GAAG;AAAA,YACH,UAAU;AAAA,YACV,WAAW,EAAE,iBAAiB,eAAe,SAAS,IAAI;AAAA,UAC5D;AAAA,UACA,SAAS,oBAAC,YAAS,KAAK,MAAM,KAAK;AAAA,UACnC,cAAY,OAAO,aAAa,WAAW,OAAO,OAAO,MAAM,CAAC;AAAA,UAE/D;AAAA;AAAA,MACH,IAEA,oBAAC,cAAW,SAAQ,aAAY,YAAY,KACzC,mBACH;AAAA;AAAA,EAEJ;AAEJ;AAaO,SAAS,SAA4C;AAAA,EAC1D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAwC;AACtC,QAAM,QAAQ,SAAS;AACvB,QAAM,QAAQ,UAAU,KAAK,MAAM;AACnC,QAAM,YACJ,MAAM,aAAa,UAAU,SAAS,MAAM,aAAa,UAAU,OAAO;AAC5E,QAAM,UAAU,OAAO,OACnB,OAAO,KAAK,EAAE,OAAO,KAAK,UAAU,KAAK,OAAO,CAAC,IACjD,OAAO,SAAS,EAAE;AACtB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,eAAa,OAAO;AAAA,MACpB,gBAAc;AAAA,MACd,IAAI;AAAA,QACF,GAAG,UAAU,OAAO,MAAM;AAAA,QAC1B,QAAQ;AAAA,MACV;AAAA,MACA,MAAK;AAAA,MACL,UAAU;AAAA,MAET,uBAAa,OAAO,SACjB,OAAO,OAAO;AAAA,QACZ;AAAA,QACA;AAAA,QACA,UAAU,MAAM;AAAA,QAChB,QAAQ,MAAM;AACZ,kBAAQ,eAAe,EAAE,OAAO,OAAO,OAAO,IAAI,OAAO,IAAI,CAAC;AAC9D,gBAAM,eAAe,IAAI;AAAA,QAC3B;AAAA,QACA,QAAQ,MAAM,MAAM,eAAe,IAAI;AAAA,MACzC,CAAC,IACD;AAAA;AAAA,EACN;AAEJ;AAcA,SAAS,YAA+C;AAAA,EACtD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAuC;AACrC,QAAM,EAAE,YAAY,EAAE,MAAM,OAAO,GAAG,UAAU,IAAI;AACpD,SACE,iCACG;AAAA,cAAU,SAAS,UAClB,oBAAC,aAAU,SAAQ,YACjB;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,QACT,UAAU,CAAC,UAAU,MAAM,YAAY,OAAO,MAAM,OAAO,OAAO;AAAA,QAClE,YAAY,EAAE,cAAc,cAAc,QAAQ,CAAC,GAAG;AAAA;AAAA,IACxD,GACF;AAAA,IAED,aACC,oBAAC,aAAU,SAAQ,YAChB,oBAAU,kBAAkB,GAAG,MAAM,QAAQ,OAC5C;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QAGL,SAAS,CAAC,UAAU;AAClB,gBAAM,gBAAgB;AACtB,gBAAM,kBAAkB,KAAK;AAAA,QAC/B;AAAA,QACA,iBAAe;AAAA,QACf,cACE,aACK,UAAU,iBAAiB,iBAC3B,UAAU,eAAe;AAAA,QAEhC,aAAU;AAAA,QAET,uBAAa,oBAAC,cAAW,IAAK,oBAAC,cAAW;AAAA;AAAA,IAC7C,GAEJ;AAAA,KAEJ;AAEJ;AAEO,SAAS,QACd,UACmB;AACnB,QAAM,EAAE,KAAK,OAAO,OAAO,YAAY,YAAY,cAAc,OAAO,MAAM,IAAI;AAClF,QAAM,QAAQ,SAAS;AACvB,QAAM,YAAY,MAAM;AACxB,SACE,qBAAC,MAAM,UAAN,EACC;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,aAAU;AAAA,QACV,iBAAe;AAAA,QACf,iBAAe;AAAA,QACf,IAAI;AAAA,UACF,WAAW,EAAE,iBAAiB,MAAM,QAAQ,OAAO,MAAM;AAAA,UACzD,GAAI,cAAc,EAAE,iBAAiB,MAAM,QAAQ,OAAO,SAAS;AAAA,UACnE,QAAQ,MAAM;AAAA,QAChB;AAAA,QACA,MAAK;AAAA,QACL,iBAAe;AAAA,QAEf;AAAA,8BAAC,eAAa,GAAG,UAAU;AAAA,UAC1B,MAAM,eAAe,IAAI,CAAC,WACzB;AAAA,YAAC;AAAA;AAAA,cAEC;AAAA,cACA,UAAU;AAAA,cACV;AAAA,cACA;AAAA,cACA,WAAW,MAAM;AAAA,cACjB,SAAS,MAAM,WAAW,EAAE,MAAM,OAAO;AAAA,cACzC;AAAA;AAAA,YAPK,OAAO;AAAA,UAQd,CACD;AAAA;AAAA;AAAA,IACH;AAAA,IACC,aAAa,cAAc,UAAU,kBAAkB,GAAG,MAAM,SAC/D,oBAAC,YAAS,aAAU,cAClB,8BAAC,aAAU,SAAS,cAAe,oBAAU,OAAO,KAAK,KAAK,GAAE,GAClE;AAAA,KAEJ;AAEJ;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/data-display/Lightbox/Lightbox.tsx"],"sourcesContent":["import Dialog from '@mui/material/Dialog/index.js';\nimport Fade from '@mui/material/Fade/index.js';\nimport Typography from '@mui/material/Typography/index.js';\nimport type { Theme } from '@mui/material/styles/index.js';\nimport React from 'react';\n\nimport { makeTestId } from './Lightbox.constants';\nimport { resolveLightboxProps } from './Lightbox.helpers';\nimport { LightboxCopyProvider } from './lightbox-copy-context';\nimport type { LightboxProps, LightboxRef } from './Lightbox.types';\nimport { LightboxCurrentMedia } from './LightboxCurrentMedia';\nimport { LightboxOverlay } from './LightboxOverlay';\nimport { LightboxStage } from './LightboxStage';\nimport { LightboxThumbnails } from './LightboxThumbnails';\nimport { useLightbox } from './useLightbox';\nimport { scrim } from '../../../tokens/ink';\nimport { rem, sxRem } from '../../../tokens/relative';\n\nconst DIALOG_STATIC_PROPS = {\n maxWidth: false,\n fullScreen: true,\n TransitionComponent: Fade,\n TransitionProps: { timeout: 300 },\n PaperProps: { sx: { background: (theme: Theme) => scrim(theme, 0.9), backdropFilter: (theme: Theme) => `blur(${rem(theme, 2)})` } },\n 'aria-label': 'Lightbox',\n 'aria-labelledby': 'lightbox-title',\n role: 'dialog',\n 'aria-modal': 'true',\n} as const;\n\nexport const Lightbox = React.forwardRef<LightboxRef, LightboxProps>((componentProps, ref) => {\n const props = resolveLightboxProps(componentProps);\n const { isOpen, items, loop, autoplay, showControls, showCaptions, thumbnails, zoomable } = props;\n const { className, style, dataTestId } = props;\n\n const testId = makeTestId(dataTestId);\n const lightbox = useLightbox(props, ref);\n const { currentIndex, currentItem, zoom } = lightbox;\n\n return (\n <LightboxCopyProvider copy={props.copy}>\n <Dialog\n open={isOpen}\n onClose={lightbox.close}\n {...DIALOG_STATIC_PROPS}\n className={className}\n style={style}\n onTouchStart={lightbox.handleTouchStart}\n onTouchEnd={lightbox.handleTouchEnd}\n data-testid={dataTestId || 'lightbox'}\n >\n {/* Visually hidden title for screen readers */}\n <Typography id=\"lightbox-title\" variant=\"h6\" sx={{ position: 'absolute', left: sxRem(-10000) }}>\n Lightbox - {currentItem?.alt || `Item ${currentIndex + 1} of ${items.length}`}\n </Typography>\n\n <LightboxOverlay\n testId={testId}\n itemCount={items.length}\n currentIndex={currentIndex}\n showControls={showControls}\n loop={loop}\n autoplay={autoplay}\n canZoom={lightbox.canZoom}\n isAutoPlaying={lightbox.isAutoPlaying}\n onClose={lightbox.close}\n onPrev={lightbox.prev}\n onNext={lightbox.next}\n onZoomIn={zoom.zoomIn}\n onZoomOut={zoom.zoomOut}\n onResetZoom={zoom.resetZoom}\n onToggleAutoplay={() => lightbox.setIsAutoPlaying((playing) => !playing)}\n />\n\n <LightboxStage\n items={items}\n currentItem={currentItem}\n currentIndex={currentIndex}\n isLoading={lightbox.isLoading}\n showCaptions={showCaptions}\n thumbnails={thumbnails}\n testId={testId}\n media={\n <LightboxCurrentMedia\n item={currentItem}\n index={currentIndex}\n total={items.length}\n zoomable={zoomable}\n zoom={zoom}\n testId={testId}\n onLoadingChange={lightbox.setIsLoading}\n onWheel={lightbox.handleWheel}\n />\n }\n thumbnailStrip={\n thumbnails &&\n items.length > 1 && (\n <LightboxThumbnails\n items={items}\n currentIndex={currentIndex}\n testId={testId}\n onSelect={lightbox.goToIndex}\n />\n )\n }\n />\n </Dialog>\n </LightboxCopyProvider>\n );\n});\n\nLightbox.displayName = 'Lightbox';\n\nexport default Lightbox;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,YAAY;AACnB,OAAO,UAAU;AACjB,OAAO,gBAAgB;AAEvB,OAAO,WAAW;AAgDZ,SAIA,KAJA;AAlCN,IAAM,sBAAsB;AAAA,EAC1B,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,qBAAqB;AAAA,EACrB,iBAAiB,EAAE,SAAS,IAAI;AAAA,EAChC,YAAY,EAAE,IAAI,EAAE,YAAY,CAAC,UAAiB,MAAM,OAAO,GAAG,GAAG,gBAAgB,CAAC,UAAiB,QAAQ,IAAI,OAAO,CAAC,CAAC,IAAI,EAAE;AAAA,EAClI,cAAc;AAAA,EACd,mBAAmB;AAAA,EACnB,MAAM;AAAA,EACN,cAAc;AAChB;AAEO,IAAM,WAAW,MAAM,WAAuC,CAAC,gBAAgB,QAAQ;AAC5F,QAAM,QAAQ,qBAAqB,cAAc;AACjD,QAAM,EAAE,QAAQ,OAAO,MAAM,UAAU,cAAc,cAAc,YAAY,SAAS,IAAI;AAC5F,QAAM,EAAE,WAAW,OAAO,WAAW,IAAI;AAEzC,QAAM,SAAS,WAAW,UAAU;AACpC,QAAM,WAAW,YAAY,OAAO,GAAG;AACvC,QAAM,EAAE,cAAc,aAAa,KAAK,IAAI;AAE5C,SACE,oBAAC,wBAAqB,MAAM,MAAM,MAClC;AAAA,IAAC;AAAA;AAAA,MACC,MAAM;AAAA,MACN,SAAS,SAAS;AAAA,MACjB,GAAG;AAAA,MACJ;AAAA,MACA;AAAA,MACA,cAAc,SAAS;AAAA,MACvB,YAAY,SAAS;AAAA,MACrB,eAAa,cAAc;AAAA,MAG3B;AAAA,6BAAC,cAAW,IAAG,kBAAiB,SAAQ,MAAK,IAAI,EAAE,UAAU,YAAY,MAAM,MAAM,IAAM,EAAE,GAAG;AAAA;AAAA,UAClF,aAAa,OAAO,QAAQ,eAAe,CAAC,OAAO,MAAM,MAAM;AAAA,WAC7E;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA,WAAW,MAAM;AAAA,YACjB;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,SAAS,SAAS;AAAA,YAClB,eAAe,SAAS;AAAA,YACxB,SAAS,SAAS;AAAA,YAClB,QAAQ,SAAS;AAAA,YACjB,QAAQ,SAAS;AAAA,YACjB,UAAU,KAAK;AAAA,YACf,WAAW,KAAK;AAAA,YAChB,aAAa,KAAK;AAAA,YAClB,kBAAkB,MAAM,SAAS,iBAAiB,CAAC,YAAY,CAAC,OAAO;AAAA;AAAA,QACzE;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA;AAAA,YACA,WAAW,SAAS;AAAA,YACpB;AAAA,YACA;AAAA,YACA;AAAA,YACA,OACE;AAAA,cAAC;AAAA;AAAA,gBACC,MAAM;AAAA,gBACN,OAAO;AAAA,gBACP,OAAO,MAAM;AAAA,gBACb;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA,iBAAiB,SAAS;AAAA,gBAC1B,SAAS,SAAS;AAAA;AAAA,YACpB;AAAA,YAEF,gBACE,cACA,MAAM,SAAS,KACb;AAAA,cAAC;AAAA;AAAA,gBACC;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA,UAAU,SAAS;AAAA;AAAA,YACrB;AAAA;AAAA,QAGN;AAAA;AAAA;AAAA,EACF,GACA;AAEJ,CAAC;AAED,SAAS,cAAc;AAEvB,IAAO,mBAAQ;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/data-display/DataGrid/DataGrid.body.tsx"],"sourcesContent":["/**\n * The DataGrid's `<thead>` and `<tbody>`.\n *\n * Split from the shell so each stays inside the size budget and so the\n * virtualization spacers — which are pure layout, not data — sit next to the\n * rows they pad rather than in the middle of the component that owns the paper.\n */\nimport Checkbox from '@mui/material/Checkbox/index.js';\nimport TableBody from '@mui/material/TableBody/index.js';\nimport TableCell from '@mui/material/TableCell/index.js';\nimport TableHead from '@mui/material/TableHead/index.js';\nimport TableRow from '@mui/material/TableRow/index.js';\nimport { useTheme } from '@mui/material/styles/index.js';\nimport type React from 'react';\n\nimport { rem } from '../../../tokens/relative';\n\nimport { GridRow, HeaderCell } from './DataGrid.cells';\nimport type { DataGridModel } from './DataGrid.model';\nimport type { DataGridProps } from './DataGrid.types';\n\nexport interface GridSectionProps<T extends Record<string, unknown>> {\n model: DataGridModel<T>;\n props: DataGridProps<T>;\n totalColumns: number;\n}\n\n/** The leading header cells for the selection / expansion columns. */\nfunction HeaderControls<T extends Record<string, unknown>>({\n model,\n props,\n}: GridSectionProps<T>): React.JSX.Element {\n const theme = useTheme();\n const { selection = { mode: 'none' }, expansion, stickyHeader = true } = props;\n const sticky = {\n position: stickyHeader ? ('sticky' as const) : ('static' as const),\n top: 0,\n zIndex: 1,\n backgroundColor: theme.palette.background.paper,\n };\n const total = model.processedRows.length;\n const picked = model.selectedRowIds.length;\n return (\n <>\n {selection.mode !== 'none' && (\n <TableCell padding=\"checkbox\" sx={sticky}>\n {selection.mode === 'multi' && (\n <Checkbox\n indeterminate={picked > 0 && picked < total}\n checked={total > 0 && picked === total}\n onChange={(event) =>\n model.setSelectedRowIds(\n event.target.checked\n ? model.processedRows.map((row, index) => rowIdOf(props, row, index))\n : [],\n )\n }\n inputProps={{ 'aria-label': 'Select all rows' }}\n />\n )}\n </TableCell>\n )}\n {expansion && <TableCell padding=\"checkbox\" sx={sticky} />}\n </>\n );\n}\n\n/** The caller's `getRowId`, or the row's own `id`, or its index. */\nexport function rowIdOf<T extends Record<string, unknown>>(\n props: DataGridProps<T>,\n row: T,\n index: number,\n): string | number {\n if (props.getRowId) return props.getRowId(row, index);\n const candidate = (row as { id?: string | number }).id;\n return candidate ?? index;\n}\n\nexport function GridHeader<T extends Record<string, unknown>>(\n section: GridSectionProps<T>,\n): React.JSX.Element {\n const { model, props } = section;\n const theme = useTheme();\n const { sorting = {}, stickyHeader = true } = props;\n // 56 design px unless the caller says, drawn through the type scale.\n const headerHeight = rem(theme, props.headerHeight ?? 56);\n const sortable = sorting.mode === 'client' || sorting.mode === 'server';\n return (\n <TableHead data-slot=\"header\">\n <TableRow data-slot=\"header-row\" role=\"row\">\n <HeaderControls {...section} />\n {model.visibleColumns.map((column) => (\n <HeaderCell\n key={column.id}\n column={column}\n sort={model.sortBy.find((entry) => entry.id === column.id)}\n sortable={column.enableSort !== false && sortable}\n stickyHeader={stickyHeader}\n headerHeight={headerHeight}\n onSort={model.onSort}\n />\n ))}\n </TableRow>\n </TableHead>\n );\n}\n\n/**\n * An invisible row standing in for `rows` rows the window is not rendering —\n * that many times the row's own CSS height, so the spacer and the rows it\n * replaces are the same length by construction.\n */\nfunction Spacer({\n rows,\n rowHeight,\n colSpan,\n}: {\n rows: number;\n rowHeight: string;\n colSpan: number;\n}): React.JSX.Element | null {\n if (rows <= 0) return null;\n return (\n <TableRow>\n <TableCell\n colSpan={colSpan}\n sx={{ height: `calc(${rows} * ${rowHeight})`, border: 'none', p: 0 }}\n />\n </TableRow>\n );\n}\n\nexport function GridBody<T extends Record<string, unknown>>(\n section: GridSectionProps<T>,\n): React.JSX.Element {\n const { model, props, totalColumns } = section;\n const { start, end } = model.visibleRange;\n const trailing = model.virtualized ? model.processedRows.length - end : 0;\n return (\n <TableBody data-slot=\"body\">\n {model.virtualized ? (\n <Spacer rows={start} rowHeight={model.rowHeight} colSpan={totalColumns} />\n ) : null}\n {model.visibleRows.map((row, offset) => {\n const index = model.virtualized ? start + offset : offset;\n const rowId = rowIdOf(props, row, index);\n return (\n <GridRow\n key={rowId}\n row={row}\n index={index}\n rowId={rowId}\n isSelected={model.selectedRowIdsSet.has(rowId)}\n isExpanded={model.expandedRowIdsSet.has(rowId)}\n totalColumns={totalColumns}\n model={model}\n props={props}\n />\n );\n })}\n {model.virtualized ? (\n <Spacer rows={trailing} rowHeight={model.rowHeight} colSpan={totalColumns} />\n ) : null}\n </TableBody>\n );\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/feedback/TutorialOverlay/TutorialStepBody.tsx"],"sourcesContent":["import CompleteIcon from '@mui/icons-material/CheckCircle';\nimport CloseIcon from '@mui/icons-material/Close';\nimport PrevIcon from '@mui/icons-material/NavigateBefore';\nimport NextIcon from '@mui/icons-material/NavigateNext';\nimport RestartIcon from '@mui/icons-material/Refresh';\nimport Box from '@mui/material/Box/index.js';\nimport Button from '@mui/material/Button/index.js';\nimport IconButton from '@mui/material/IconButton/index.js';\nimport Stack from '@mui/material/Stack/index.js';\nimport Typography from '@mui/material/Typography/index.js';\nimport { alpha, styled } from '@mui/material/styles/index.js';\nimport React, { } from 'react';\n\nimport { onMedia, uiInk } from '../../../tokens/ink';\nimport { rem } from '../../../tokens/relative';\n\nimport type { TutorialOverlayProps } from './TutorialOverlay.types';\nimport type { TutorialCopy } from '../../../copy';\n\n// Animation keyframes\n\nconst StepIndicator = styled(Box)(({ theme }) => ({\n display: 'flex',\n gap: theme.spacing(1),\n marginTop: theme.spacing(2),\n marginBottom: theme.spacing(2) }));\n\n\nconst StepDot = styled(Box, {\n shouldForwardProp: (prop) => prop !== 'active' && prop !== 'completed' })<{ active?: boolean; completed?: boolean }>(({ theme, active, completed }) => ({\n width: rem(theme, 8),\n height: rem(theme, 8),\n borderRadius: '50%',\n background: completed\n ? theme.palette.success.main\n : active\n ? theme.palette.primary.main\n : alpha(theme.palette.text.primary, 0.3),\n transition: 'all 0.3s ease',\n ...(active && {\n transform: 'scale(1.5)' }) }));\n\n// Title, body copy, the step dots and the navigation row.\n\n// The step's controls: skip/restart on the left, previous/next on the right.\nconst TutorialStepNav: React.FC<{\n copy: TutorialCopy;\n currentStep: number;\n stepCount: number;\n isLastStep: boolean;\n allowSkip: boolean;\n requiresActionBeforeNext?: boolean;\n onNext: () => void;\n onPrev: () => void;\n onSkip: () => void;\n onRestart: () => void;\n}> = ({\n copy,\n currentStep,\n stepCount,\n isLastStep,\n allowSkip,\n requiresActionBeforeNext,\n onNext,\n onPrev,\n onSkip,\n onRestart }) => (\n <Stack\n direction=\"row\"\n spacing={1}\n justifyContent=\"space-between\"\n data-testid=\"tutorial-navigation\"\n >\n <Stack direction=\"row\" spacing={1}>\n {allowSkip && (\n <Button size=\"small\" onClick={onSkip} variant=\"text\">\n {copy.skip}\n </Button>\n )}\n {stepCount > 1 && (\n <IconButton\n size=\"small\"\n onClick={onRestart}\n disabled={currentStep === 0}\n title={copy.restart}\n >\n <RestartIcon fontSize=\"small\" />\n </IconButton>\n )}\n </Stack>\n\n <Stack direction=\"row\" spacing={1}>\n {stepCount > 1 && currentStep > 0 && (\n <Button\n size=\"small\"\n startIcon={<PrevIcon />}\n onClick={onPrev}\n disabled={currentStep === 0}\n data-testid=\"tutorial-prev-button\"\n >\n {copy.previous}\n </Button>\n )}\n\n {!isLastStep ? (\n <Button\n variant=\"contained\"\n size=\"small\"\n endIcon={<NextIcon />}\n onClick={onNext}\n disabled={requiresActionBeforeNext}\n title={requiresActionBeforeNext ? 'Complete the required action first' : ''}\n data-testid=\"tutorial-next-button\"\n >\n {copy.next}\n </Button>\n ) : (\n <Button\n variant=\"contained\"\n size=\"small\"\n endIcon={<CompleteIcon />}\n onClick={onNext}\n sx={(theme) => {\n const [from, to] = uiInk(theme).celebration.mint;\n return { background: `linear-gradient(135deg, ${from} 0%, ${to} 100%)` };\n }}\n data-testid=\"tutorial-finish-button\"\n >\n {stepCount === 1 ? 'Complete' : 'Finish'}\n </Button>\n )}\n </Stack>\n </Stack>\n);\n\nconst StepDots: React.FC<{ currentStep: number; stepCount: number }> = ({\n currentStep,\n stepCount }) => (\n <StepIndicator data-testid=\"tutorial-step-indicators\">\n {Array.from({ length: stepCount }).map((_, index) => (\n <StepDot\n key={index}\n active={index === currentStep}\n completed={index < currentStep}\n data-testid={`tutorial-indicator-${index}`}\n />\n ))}\n </StepIndicator>\n);\n\n// Title, and the close button when skipping is allowed.\nconst TutorialStepHeader: React.FC<{\n title: React.ReactNode;\n currentStep: number;\n allowSkip: boolean;\n onSkip: () => void;\n}> = ({ title, currentStep, allowSkip, onSkip }) => (\n <Box\n sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}\n >\n <Typography\n id={`tutorial-title-${currentStep}`}\n variant=\"h6\"\n fontWeight=\"bold\"\n sx={{ flex: 1 }}\n data-testid=\"tutorial-step-title\"\n >\n {title}\n </Typography>\n {allowSkip && (\n <IconButton\n size=\"small\"\n onClick={onSkip}\n sx={{ ml: 1, mt: -1, mr: -1 }}\n data-testid=\"tutorial-close-button\"\n >\n <CloseIcon fontSize=\"small\" />\n </IconButton>\n )}\n </Box>\n);\n\nexport const TutorialStepBody: React.FC<{\n copy: TutorialCopy;\n step: TutorialOverlayProps['steps'][number];\n currentStep: number;\n stepCount: number;\n progress: number;\n isLastStep: boolean;\n allowSkip: boolean;\n showProgress: boolean;\n requiresActionBeforeNext?: boolean;\n onNext: () => void;\n onPrev: () => void;\n onSkip: () => void;\n onRestart: () => void;\n}> = ({\n copy,\n step,\n currentStep,\n stepCount,\n progress: _progress,\n isLastStep,\n allowSkip,\n showProgress,\n requiresActionBeforeNext,\n onNext,\n onPrev,\n onSkip,\n onRestart }) => (\n <Stack spacing={2}>\n <TutorialStepHeader\n title={step.title}\n currentStep={currentStep}\n allowSkip={allowSkip}\n onSkip={onSkip}\n />\n\n <Typography\n id={`tutorial-content-${currentStep}`}\n variant=\"body2\"\n color=\"text.secondary\"\n data-testid=\"tutorial-step-content\"\n >\n {step.content}\n </Typography>\n\n {showProgress && (\n <Typography variant=\"caption\" color=\"text.secondary\" align=\"center\">\n {currentStep + 1} of {stepCount}\n </Typography>\n )}\n\n {step.action && (\n <Button\n variant=\"contained\"\n size=\"small\"\n onClick={step.action.onClick}\n sx={(theme) => {\n const [from, to] = uiInk(theme).celebration.violet;\n return { background: `linear-gradient(135deg, ${from} 0%, ${to} 100%)`, color: onMedia(theme) };\n }}\n >\n {step.action.label}\n </Button>\n )}\n\n <StepDots currentStep={currentStep} stepCount={stepCount} />\n\n <TutorialStepNav\n copy={copy}\n currentStep={currentStep}\n stepCount={stepCount}\n isLastStep={isLastStep}\n allowSkip={allowSkip}\n requiresActionBeforeNext={requiresActionBeforeNext}\n onNext={onNext}\n onPrev={onPrev}\n onSkip={onSkip}\n onRestart={onRestart}\n />\n </Stack>\n);\n\n// Main component\n"],"mappings":";;;;;;;;;AAAA,OAAO,kBAAkB;AACzB,OAAO,eAAe;AACtB,OAAO,cAAc;AACrB,OAAO,cAAc;AACrB,OAAO,iBAAiB;AACxB,OAAO,SAAS;AAChB,OAAO,YAAY;AACnB,OAAO,gBAAgB;AACvB,OAAO,WAAW;AAClB,OAAO,gBAAgB;AACvB,SAAS,OAAO,cAAc;AA+DpB,SAEI,KAFJ;AApDV,IAAM,gBAAgB,OAAO,GAAG,EAAE,CAAC,EAAE,MAAM,OAAO;AAAA,EAChD,SAAS;AAAA,EACT,KAAK,MAAM,QAAQ,CAAC;AAAA,EACpB,WAAW,MAAM,QAAQ,CAAC;AAAA,EAC1B,cAAc,MAAM,QAAQ,CAAC;AAAE,EAAE;AAGnC,IAAM,UAAU,OAAO,KAAK;AAAA,EAC1B,mBAAmB,CAAC,SAAS,SAAS,YAAY,SAAS;AAAY,CAAC,EAA6C,CAAC,EAAE,OAAO,QAAQ,UAAU,OAAO;AAAA,EACxJ,OAAO,IAAI,OAAO,CAAC;AAAA,EACnB,QAAQ,IAAI,OAAO,CAAC;AAAA,EACpB,cAAc;AAAA,EACd,YAAY,YACR,MAAM,QAAQ,QAAQ,OACtB,SACE,MAAM,QAAQ,QAAQ,OACtB,MAAM,MAAM,QAAQ,KAAK,SAAS,GAAG;AAAA,EAC3C,YAAY;AAAA,EACZ,GAAI,UAAU;AAAA,IACZ,WAAW;AAAA,EAAa;AAAG,EAAE;AAKjC,IAAM,kBAWD,CAAC;AAAA,EACJ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAU,MACJ;AAAA,EAAC;AAAA;AAAA,IACC,WAAU;AAAA,IACV,SAAS;AAAA,IACT,gBAAe;AAAA,IACf,eAAY;AAAA,IAEZ;AAAA,2BAAC,SAAM,WAAU,OAAM,SAAS,GAC7B;AAAA,qBACC,oBAAC,UAAO,MAAK,SAAQ,SAAS,QAAQ,SAAQ,QAC3C,eAAK,MACR;AAAA,QAED,YAAY,KACX;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS;AAAA,YACT,UAAU,gBAAgB;AAAA,YAC1B,OAAO,KAAK;AAAA,YAEZ,8BAAC,eAAY,UAAS,SAAQ;AAAA;AAAA,QAChC;AAAA,SAEJ;AAAA,MAEA,qBAAC,SAAM,WAAU,OAAM,SAAS,GAC7B;AAAA,oBAAY,KAAK,cAAc,KAC9B;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,WAAW,oBAAC,YAAS;AAAA,YACrB,SAAS;AAAA,YACT,UAAU,gBAAgB;AAAA,YAC1B,eAAY;AAAA,YAEX,eAAK;AAAA;AAAA,QACR;AAAA,QAGD,CAAC,aACA;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAAS,oBAAC,YAAS;AAAA,YACnB,SAAS;AAAA,YACT,UAAU;AAAA,YACV,OAAO,2BAA2B,uCAAuC;AAAA,YACzE,eAAY;AAAA,YAEX,eAAK;AAAA;AAAA,QACR,IAEA;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAAS,oBAAC,gBAAa;AAAA,YACvB,SAAS;AAAA,YACT,IAAI,CAAC,UAAU;AACb,oBAAM,CAAC,MAAM,EAAE,IAAI,MAAM,KAAK,EAAE,YAAY;AAC5C,qBAAO,EAAE,YAAY,2BAA2B,IAAI,QAAQ,EAAE,SAAS;AAAA,YACzE;AAAA,YACA,eAAY;AAAA,YAEX,wBAAc,IAAI,aAAa;AAAA;AAAA,QAClC;AAAA,SAEJ;AAAA;AAAA;AACF;AAGR,IAAM,WAAiE,CAAC;AAAA,EACtE;AAAA,EACA;AAAU,MACV,oBAAC,iBAAc,eAAY,4BACxB,gBAAM,KAAK,EAAE,QAAQ,UAAU,CAAC,EAAE,IAAI,CAAC,GAAG,UACzC;AAAA,EAAC;AAAA;AAAA,IAEC,QAAQ,UAAU;AAAA,IAClB,WAAW,QAAQ;AAAA,IACnB,eAAa,sBAAsB,KAAK;AAAA;AAAA,EAHnC;AAIP,CACD,GACH;AAIF,IAAM,qBAKD,CAAC,EAAE,OAAO,aAAa,WAAW,OAAO,MACtC;AAAA,EAAC;AAAA;AAAA,IACC,IAAI,EAAE,SAAS,QAAQ,gBAAgB,iBAAiB,YAAY,aAAa;AAAA,IAEjF;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,IAAI,kBAAkB,WAAW;AAAA,UACjC,SAAQ;AAAA,UACR,YAAW;AAAA,UACX,IAAI,EAAE,MAAM,EAAE;AAAA,UACd,eAAY;AAAA,UAEX;AAAA;AAAA,MACH;AAAA,MACC,aACC;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS;AAAA,UACT,IAAI,EAAE,IAAI,GAAG,IAAI,IAAI,IAAI,GAAG;AAAA,UAC5B,eAAY;AAAA,UAEZ,8BAAC,aAAU,UAAS,SAAQ;AAAA;AAAA,MAC9B;AAAA;AAAA;AAEJ;AAGD,IAAM,mBAcR,CAAC;AAAA,EACJ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAU,MACN,qBAAC,SAAM,SAAS,GACd;AAAA;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,KAAK;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACF;AAAA,EAEA;AAAA,IAAC;AAAA;AAAA,MACC,IAAI,oBAAoB,WAAW;AAAA,MACnC,SAAQ;AAAA,MACR,OAAM;AAAA,MACN,eAAY;AAAA,MAEX,eAAK;AAAA;AAAA,EACR;AAAA,EAEC,gBACC,qBAAC,cAAW,SAAQ,WAAU,OAAM,kBAAiB,OAAM,UACxD;AAAA,kBAAc;AAAA,IAAE;AAAA,IAAK;AAAA,KACxB;AAAA,EAGD,KAAK,UACJ;AAAA,IAAC;AAAA;AAAA,MACC,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,SAAS,KAAK,OAAO;AAAA,MACrB,IAAI,CAAC,UAAU;AACb,cAAM,CAAC,MAAM,EAAE,IAAI,MAAM,KAAK,EAAE,YAAY;AAC5C,eAAO,EAAE,YAAY,2BAA2B,IAAI,QAAQ,EAAE,UAAU,OAAO,QAAQ,KAAK,EAAE;AAAA,MAChG;AAAA,MAEC,eAAK,OAAO;AAAA;AAAA,EACf;AAAA,EAGF,oBAAC,YAAS,aAA0B,WAAsB;AAAA,EAE1D;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACF;AAAA,GACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/data-display/DataViews/data-views-grid-bodies.tsx"],"sourcesContent":["\"use client\";\n\nimport React from \"react\";\n\nimport { DataGrid, type GridColumn, type GridSort } from \"../DataGrid\";\nimport { Box } from \"../../../mui/Box\";\n\nimport {\n cardTargetWidthFor,\n cardScaleForZoom,\n DENSITY_BOARD_SCALE,\n DENSITY_ROW_PADDING,\n useDataViewsLayout,\n type DataViewsDensity,\n} from \"./data-views-layout-context\";\nimport { cardGridTracks } from \"./data-views-grid-helpers\";\nimport { DataViewsBoard, type BoardConfig } from \"./DataViewsBoard\";\nimport { SelectAllStrip } from \"./data-views-select-all-strip\";\nimport { ListCardGroup, type ListGroupConfig } from \"./list-card-rails\";\nimport type { DataViewCardSelection } from \"./data-views-types\";\nimport { toGridExpansion, type DataViewRowDetail } from \"./data-views-row-detail\";\nimport type { DataViewsController } from \"./use-data-views-state\";\nimport { useDataViewsCopy } from \"./data-views-copy-context\";\nimport { sxRem } from \"../../../tokens/relative\";\n\n/* ── Body (grid) ─────────────────────────────────────────────────────────── */\n\ninterface GridBodyProps<T extends Record<string, unknown>> {\n rows: T[];\n columns: GridColumn<T>[];\n getRowId: (row: T) => string | number;\n selectedIds: Array<string | number>;\n onChangeSelected: (ids: Array<string | number>) => void;\n sortBy: GridSort[];\n onChangeSortBy: (next: GridSort[]) => void;\n /** \"server\" defers ordering to the backend (rows render as-is); \"client\" sorts in-grid. */\n sortMode: \"client\" | \"server\";\n /** Vertical cell padding, from the density preference. */\n rowPadding: number;\n rowDetail?: DataViewRowDetail<T>;\n dataTestId?: string;\n emptyState?: React.ReactNode;\n}\n\n/** The dense DataGrid with multi-select, wrapped in the scrollable table region. */\nfunction GridBody<T extends Record<string, unknown>>({\n rows,\n columns,\n getRowId,\n selectedIds,\n onChangeSelected,\n sortBy,\n onChangeSortBy,\n sortMode,\n rowPadding,\n rowDetail,\n dataTestId,\n emptyState,\n}: GridBodyProps<T>): React.JSX.Element {\n const copy = useDataViewsCopy();\n return (\n <Box\n sx={{\n width: \"100%\",\n overflowX: \"auto\",\n mt: 1.5,\n // Tabwoah-style dense rows: MUI's default TableCell padding keeps rows\n // tall regardless of rowHeight, so the DENSITY preference is applied\n // here rather than through `rowHeight`, which it would fight.\n \"& .MuiTableCell-root\": { py: rowPadding, fontSize: sxRem(13) },\n \"& .MuiTableCell-head\": { py: 0.5, fontSize: sxRem(12) },\n }}\n >\n <DataGrid<T>\n rows={rows}\n columns={columns}\n getRowId={(row) => getRowId(row)}\n virtualizeRows={false}\n density=\"compact\"\n rowHeight={36}\n headerHeight={36}\n selection={{ mode: \"multi\", selectedRowIds: selectedIds, onChangeSelected }}\n sorting={{ mode: sortMode, sortBy, onChangeSortBy }}\n expansion={toGridExpansion(rowDetail, copy)}\n data-testid={dataTestId}\n emptyState={emptyState}\n emptyText={copy.grid.emptyFilteredTitle}\n />\n </Box>\n );\n}\n\n/* ── Body (cards) ────────────────────────────────────────────────────────── */\n\ninterface CardBodyProps<T extends Record<string, unknown>> {\n rows: T[];\n renderCard: (row: T, selection: DataViewCardSelection) => React.ReactNode;\n getRowId: (row: T) => string | number;\n selectedIds: Set<string | number>;\n onToggleId: (id: string | number) => void;\n /** The width each card asks for; `auto-fill` turns it into a column count. */\n targetCardWidth: number;\n /** Content scale (padding + type) handed to each card, from the zoom slider. */\n cardScale: number;\n dataTestId?: string;\n emptyState?: React.ReactNode;\n}\n\n/**\n * The \"Grade\" layout: the filtered/sorted rows rendered as an auto-filling grid\n * of entity-supplied cards. Reuses `rows` (= `c.matched`), so search/filter/sort\n * apply; the column width comes from the zoom slider, and each card is handed its\n * selection state so it can drive its own checkbox (BaseCard) — the same\n * selection model as the table.\n */\nfunction CardBody<T extends Record<string, unknown>>({\n rows,\n renderCard,\n getRowId,\n selectedIds,\n onToggleId,\n targetCardWidth,\n cardScale,\n dataTestId,\n emptyState,\n}: CardBodyProps<T>): React.JSX.Element {\n if (rows.length === 0) {\n return <Box sx={{ mt: 1.5 }}>{emptyState}</Box>;\n }\n return (\n <Box\n sx={{\n mt: 1.5,\n display: \"grid\",\n // Fixed inter-card gap — deliberately NOT scaled by the zoom slider, so\n // only the cards grow while the space between them stays constant.\n gap: 1.5,\n ...cardGridTracks(targetCardWidth),\n }}\n data-testid={dataTestId ? `${dataTestId}-cards` : \"data-views-cards\"}\n >\n {rows.map((row) => {\n const id = getRowId(row);\n return (\n <Box key={id}>\n {renderCard(row, {\n selected: selectedIds.has(id),\n onToggleSelect: () => onToggleId(id),\n scale: cardScale,\n })}\n </Box>\n );\n })}\n </Box>\n );\n}\n\n/* ── Body (list) ─────────────────────────────────────────────────────────── */\n\ninterface ListBodyProps<T extends Record<string, unknown>> {\n rows: T[];\n renderListRow: (row: T, selection: DataViewCardSelection) => React.ReactNode;\n getRowId: (row: T) => string | number;\n selectedIds: Set<string | number>;\n onToggleId: (id: string | number) => void;\n /** Gap between rows, from the density preference. */\n rowGap: number;\n /** The list's shared column config. See {@link ListGroupConfig}. */\n group?: ListGroupConfig<T>;\n /** The density every row answers, handed to the group when there is one. */\n density: DataViewsDensity;\n dataTestId?: string;\n emptyState?: React.ReactNode;\n}\n\n/**\n * The \"Lista\" layout: one FULL-WIDTH row per record, rendered by the entity — a\n * marker, a title, a subtitle and a value on the right is the shape it was\n * designed for (FUT-733).\n *\n * It sits between the table and the cards rather than replacing either: the\n * table is for comparing many columns, the cards are for browsing, and the list\n * is for scanning a queue on a narrow screen. Selection is the SAME model as\n * both — each row receives its selection state, so it can drive its own\n * checkbox and the bulk menu behaves identically in every layout.\n *\n * `scale` is handed over as 1 rather than the zoom multiplier, and the zoom\n * slider is hidden in this layout: a full-width row has no card size to\n * multiply. See {@link DataViewsZoomSlider}.\n */\nfunction ListBody<T extends Record<string, unknown>>({\n rows,\n renderListRow,\n getRowId,\n selectedIds,\n onToggleId,\n rowGap,\n group,\n density,\n dataTestId,\n emptyState,\n}: ListBodyProps<T>): React.JSX.Element {\n if (rows.length === 0) {\n return <Box sx={{ mt: 1.5 }}>{emptyState}</Box>;\n }\n const testId = dataTestId ? `${dataTestId}-list` : \"data-views-list\";\n const selectionFor = (id: string | number): DataViewCardSelection => ({\n selected: selectedIds.has(id),\n onToggleSelect: () => onToggleId(id),\n scale: 1,\n });\n\n if (group) {\n return (\n <Box sx={{ mt: 1.5 }}>\n <ListCardGroup\n cells={group.cells}\n metaColumns={group.metaColumns}\n rails={group.rails}\n reserveGutters={group.reserveGutters}\n density={density}\n gap={rowGap}\n dataTestId={testId}\n >\n {rows.map((row) => {\n const id = getRowId(row);\n // A FRAGMENT, NOT A BOX. The row is subgrid over the group's tracks\n // (`gridColumn: span railCount`), which only resolves while the card\n // is a DIRECT child of the group's grid. One wrapper element and the\n // span is measured against a grid that isn't there, so every rail\n // collapses — the exact failure the group exists to prevent.\n return (\n <React.Fragment key={id}>\n {renderListRow(row, selectionFor(id))}\n </React.Fragment>\n );\n })}\n </ListCardGroup>\n </Box>\n );\n }\n\n return (\n <Box\n sx={{ mt: 1.5, display: \"flex\", flexDirection: \"column\", gap: rowGap }}\n data-testid={testId}\n >\n {rows.map((row) => {\n const id = getRowId(row);\n return <Box key={id}>{renderListRow(row, selectionFor(id))}</Box>;\n })}\n </Box>\n );\n}\n\n/* ── Body selector (board vs list vs cards vs table, from context) ───────── */\n\ninterface GridMainProps<T extends Record<string, unknown>> {\n c: DataViewsController<T>;\n getRowId: (row: T) => string | number;\n renderCard?: (row: T, selection: DataViewCardSelection) => React.ReactNode;\n /** Opt-in \"Lista\" layout — one full-width row per record. */\n renderListRow?: (row: T, selection: DataViewCardSelection) => React.ReactNode;\n /** The Lista's shared columns. Omitted, each row resolves its own tracks. */\n listGroup?: ListGroupConfig<T>;\n /** Opt-in \"Quadro\" (board) layout — needs `renderCard`, since it reuses the card. */\n board?: BoardConfig<T>;\n /** Opt-in expandable rows — the TABLE only; the headerless layouts ignore it. */\n rowDetail?: DataViewRowDetail<T>;\n dataTestId?: string;\n emptyState?: React.ReactNode;\n testIdPrefix: string;\n}\n\n/**\n * The headerless layouts, each preceded by its own select-all.\n *\n * The strip is rendered HERE rather than inside each body so all three agree on\n * where it sits and what it says — and so the table, which already has one in\n * its `<thead>`, never gets a second.\n */\nfunction Headerless<T extends Record<string, unknown>>({\n c,\n getRowId,\n testIdPrefix,\n children,\n}: {\n c: DataViewsController<T>;\n getRowId: (row: T) => string | number;\n testIdPrefix: string;\n children: React.ReactNode;\n}): React.JSX.Element {\n return (\n <>\n <SelectAllStrip\n rows={c.matched}\n getRowId={getRowId}\n selectedIds={c.selectedIds}\n onChange={(next) => c.setSelectedIds(next)}\n testIdPrefix={testIdPrefix}\n />\n {children}\n </>\n );\n}\n\n/**\n * The body for one of the three HEADERLESS layouts, or `null` for the table.\n *\n * Split out from {@link GridMain} so the select-all strip is wrapped around the\n * result exactly once instead of being repeated identically in every branch —\n * which is also what keeps either function inside the line budget.\n */\nfunction headerlessBody<T extends Record<string, unknown>>(\n { c, getRowId, renderCard, renderListRow, listGroup, board, dataTestId, emptyState }: GridMainProps<T>,\n { layout, zoom, density }: ReturnType<typeof useDataViewsLayout>,\n): React.ReactNode | null {\n if (layout === \"list\" && renderListRow) {\n return (\n <ListBody\n rows={c.matched}\n renderListRow={renderListRow}\n getRowId={getRowId}\n selectedIds={c.selectedIds}\n onToggleId={c.toggleId}\n rowGap={DENSITY_ROW_PADDING[density]}\n group={listGroup}\n density={density}\n dataTestId={dataTestId}\n emptyState={emptyState}\n />\n );\n }\n if (layout === \"board\" && board && renderCard) {\n return (\n <DataViewsBoard\n rows={c.matched}\n board={board}\n getRowId={getRowId}\n renderCard={renderCard}\n selectedIds={c.selectedIds}\n onToggleId={c.toggleId}\n // DENSITY, not zoom: the board's own knob in the Exibição tab is how\n // wide its columns are, and it is the only sizing control the board\n // has since the zoom slider was removed.\n cardScale={DENSITY_BOARD_SCALE[density]}\n dataTestId={dataTestId}\n />\n );\n }\n if (layout === \"cards\" && renderCard) {\n return (\n <CardBody\n rows={c.matched}\n renderCard={renderCard}\n getRowId={getRowId}\n selectedIds={c.selectedIds}\n onToggleId={c.toggleId}\n targetCardWidth={cardTargetWidthFor(zoom, density)}\n cardScale={cardScaleForZoom(zoom)}\n dataTestId={dataTestId}\n emptyState={emptyState}\n />\n );\n }\n return null;\n}\n\n/** Picks the body from the layout context: board, list, cards, or the dense grid. */\nexport function GridMain<T extends Record<string, unknown>>(props: GridMainProps<T>): React.JSX.Element {\n const { c, getRowId, dataTestId, emptyState, testIdPrefix } = props;\n const layoutState = useDataViewsLayout();\n const body = headerlessBody(props, layoutState);\n if (body) {\n return (\n <Headerless c={c} getRowId={getRowId} testIdPrefix={testIdPrefix}>\n {body}\n </Headerless>\n );\n }\n return (\n <GridBody\n rows={c.matched}\n columns={c.gridColumns}\n getRowId={getRowId}\n selectedIds={[...c.selectedIds]}\n onChangeSelected={(ids) => c.setSelectedIds(new Set(ids))}\n sortBy={c.state.sortBy}\n onChangeSortBy={(next: GridSort[]) => c.patch({ sortBy: next })}\n sortMode={c.serverMode ? \"server\" : \"client\"}\n rowPadding={DENSITY_ROW_PADDING[layoutState.density]}\n rowDetail={props.rowDetail}\n dataTestId={dataTestId}\n emptyState={emptyState}\n />\n );\n}\n\n"],"mappings":"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","names":["default"]}
@@ -1,82 +0,0 @@
1
- // src/components/layout/SettingsLayout/SettingsSectionChips.scroll.ts
2
- var LANDED_SLACK = 1;
3
- var QUIET_BEFORE_SETTLED_MS = 250;
4
- function horizontalDelta(event) {
5
- if (!(event instanceof WheelEvent)) return 0;
6
- return event.deltaX !== 0 ? event.deltaX : event.shiftKey ? event.deltaY : 0;
7
- }
8
- function restsOnAim(strip, aimed) {
9
- const reachable = Math.min(aimed, strip.scrollWidth - strip.clientWidth);
10
- return Math.abs(strip.scrollLeft - reachable) <= LANDED_SLACK;
11
- }
12
- function watchVisitorScroll(strip) {
13
- const view = strip.ownerDocument.defaultView;
14
- const hasScrollEnd = "onscrollend" in strip;
15
- const state = {
16
- pointer: false,
17
- touch: false,
18
- nudged: false,
19
- undecided: false,
20
- scrolled: false,
21
- aimed: Number.NaN,
22
- quiet: void 0,
23
- settled: () => void 0
24
- };
25
- const set = (key, value) => () => {
26
- state[key] = value;
27
- };
28
- const settle = () => {
29
- if (!state.undecided) return;
30
- state.undecided = false;
31
- state.nudged = false;
32
- if (!restsOnAim(strip, state.aimed)) state.scrolled = true;
33
- state.settled();
34
- };
35
- const onWheel = (event) => {
36
- if (horizontalDelta(event) !== 0) state.nudged = true;
37
- };
38
- const onScroll = () => {
39
- if (state.pointer || state.touch || state.nudged) state.undecided = true;
40
- if (!state.undecided || hasScrollEnd) return;
41
- clearTimeout(state.quiet);
42
- state.quiet = setTimeout(settle, QUIET_BEFORE_SETTLED_MS);
43
- };
44
- const onStrip = [
45
- ["pointerdown", set("pointer", true)],
46
- ["touchstart", set("touch", true)],
47
- ["pointercancel", set("nudged", true)],
48
- ["keydown", set("nudged", true)],
49
- ["wheel", onWheel],
50
- ["scroll", onScroll],
51
- ["scrollend", settle]
52
- ];
53
- const onView = [
54
- ["pointerup", set("pointer", false)],
55
- ["pointercancel", set("pointer", false)],
56
- ["touchend", set("touch", false)],
57
- ["touchcancel", set("touch", false)]
58
- ];
59
- for (const [type, listener] of onStrip) strip.addEventListener(type, listener, { passive: true });
60
- for (const [type, listener] of onView) view?.addEventListener(type, listener, { passive: true });
61
- return {
62
- hasScrolled: () => state.scrolled,
63
- isUndecided: () => state.undecided,
64
- aimedAt: () => state.aimed,
65
- beforeOwnScroll: (left) => {
66
- state.aimed = left;
67
- },
68
- onSettled: (listener) => {
69
- state.settled = listener;
70
- },
71
- detach: () => {
72
- clearTimeout(state.quiet);
73
- for (const [type, listener] of onStrip) strip.removeEventListener(type, listener);
74
- for (const [type, listener] of onView) view?.removeEventListener(type, listener);
75
- }
76
- };
77
- }
78
-
79
- export {
80
- watchVisitorScroll
81
- };
82
- //# sourceMappingURL=chunk-SLJAQA2X.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/layout/SettingsLayout/SettingsSectionChips.scroll.ts"],"sourcesContent":["/**\n * Telling the strip's own scrolls from the visitor's (FUT-2606).\n *\n * Split from `SettingsSectionChips.tsx` so the chips stay a component file and\n * the rule for \"who moved the strip\" can be read in one place.\n */\n\n/**\n * How near to where the strip aimed itself it has to come to rest for the scroll\n * to count as the strip's own. A smooth scroll lands on a device pixel, and the\n * target it was given is fractional.\n */\nconst LANDED_SLACK = 1;\n\n/**\n * Where `scrollend` is missing: how long the strip has to go without a `scroll`\n * before it counts as settled. Generous on purpose — a busy main thread can go\n * several frames between ticks of a smooth scroll, and judging one mid-flight\n * would read the strip's own animation as the visitor's. Too long only delays a\n * re-centre; too short can latch the strip for good.\n */\nconst QUIET_BEFORE_SETTLED_MS = 250;\n\ninterface VisitorScrollWatch {\n /** True once the visitor has moved the strip themselves. */\n hasScrolled: () => boolean;\n /**\n * True while a scroll the visitor MAY be making has not come to rest yet. The\n * strip must not scroll itself under it: that would yank a drag in progress.\n */\n isUndecided: () => boolean;\n /** Where the strip last aimed itself, in its own pixels; `NaN` before it has. */\n aimedAt: () => number;\n /**\n * The strip is about to scroll itself to `left`. Records the aim and NOTHING\n * else: it used to disarm too, and a re-centre landing between a visitor's key\n * press (or wheel, or pan) and the first tick of the scroll it causes wiped\n * the arming — their scroll went unclaimed, read as the strip's own. Left\n * armed, the worst a stale arming does is put the strip's OWN next scroll\n * under judgement, which rests on its aim, is not latched, and disarms.\n */\n beforeOwnScroll: (left: number) => void;\n /** Called once an undecided scroll has come to rest and been judged. */\n onSettled: (listener: () => void) => void;\n detach: () => void;\n}\n\ntype Listeners = Array<[string, (event: Event) => void]>;\n\n/** A wheel's sideways travel: `deltaX`, or `deltaY` with Shift held, as browsers read it. */\nfunction horizontalDelta(event: Event): number {\n if (!(event instanceof WheelEvent)) return 0;\n return event.deltaX !== 0 ? event.deltaX : event.shiftKey ? event.deltaY : 0;\n}\n\ninterface WatchState {\n pointer: boolean;\n touch: boolean;\n nudged: boolean;\n undecided: boolean;\n scrolled: boolean;\n aimed: number;\n quiet: ReturnType<typeof setTimeout> | undefined;\n settled: () => void;\n}\n\n/** Whether the strip came to rest where it last aimed itself — clamped as the browser would. */\nfunction restsOnAim(strip: HTMLElement, aimed: number): boolean {\n const reachable = Math.min(aimed, strip.scrollWidth - strip.clientWidth);\n // Written so that `NaN` — the strip never aimed — reads as \"not on aim\".\n return Math.abs(strip.scrollLeft - reachable) <= LANDED_SLACK;\n}\n\n/**\n * Tell a scroll the VISITOR made from every other one.\n *\n * The `scroll` event cannot say: the strip's own `scrollTo` fires it, and so does\n * the browser clamping a strip whose content shrank. So a scroll is only a\n * CANDIDATE when it arrives during something only a visitor does:\n *\n * - a finger held on the strip (`touchstart` until `touchend`) — a drag;\n * - a pointer held on it (`pointerdown` until `pointerup`);\n * - a key press, a SIDEWAYS wheel, or the browser taking a pointer over to pan\n * it (`pointercancel`), each armed until the next scroll under judgement has\n * been judged — whoever's it turns out to be.\n *\n * and the verdict waits until the strip comes to REST (`scrollend`, or a quiet\n * spell where the browser has no `scrollend`): it is the visitor's only if the\n * strip rests somewhere other than where it last aimed itself.\n *\n * Judged at rest rather than per `scroll` because the strip's own smooth scroll\n * fires `scroll` for a third of a second, and a visitor who presses Tab or puts\n * a finger on a chip to scroll the PAGE in that window is not scrolling the\n * strip. Every tick of that animation used to count as theirs, the strip stopped\n * re-centring for good, and the open chip could be left clipped (FUT-2606\n * again, by another door). A visitor who really drags or wheels the strip\n * mid-animation cancels it, so the strip rests where THEY left it — and that\n * still counts. The one loss: a visitor who happens to leave it within a pixel\n * of the strip's own aim is not told apart from it, and the strip there is\n * already where it would have put itself.\n *\n * A tap is a pointer held with no scroll under it, so it never counts. A\n * vertical wheel scrolls the PAGE — the strip is `overflowY: hidden` — and is\n * not armed at all.\n */\nexport function watchVisitorScroll(strip: HTMLElement): VisitorScrollWatch {\n const view = strip.ownerDocument.defaultView;\n const hasScrollEnd = 'onscrollend' in strip;\n const state: WatchState = {\n pointer: false,\n touch: false,\n nudged: false,\n undecided: false,\n scrolled: false,\n aimed: Number.NaN,\n quiet: undefined,\n settled: () => undefined,\n };\n const set =\n (key: 'pointer' | 'touch' | 'nudged', value: boolean) =>\n (): void => {\n state[key] = value;\n };\n const settle = (): void => {\n // Only a scroll that was UNDER JUDGEMENT disarms. Chromium can end the\n // strip's own smooth scroll with a `scrollend` when another scroll cuts it\n // off, fired BEFORE that scroll's first `scroll` (seen with an instant one);\n // disarming there would hand the visitor's scroll to nobody.\n if (!state.undecided) return;\n state.undecided = false;\n state.nudged = false;\n if (!restsOnAim(strip, state.aimed)) state.scrolled = true;\n state.settled();\n };\n const onWheel = (event: Event): void => {\n if (horizontalDelta(event) !== 0) state.nudged = true;\n };\n const onScroll = (): void => {\n if (state.pointer || state.touch || state.nudged) state.undecided = true;\n if (!state.undecided || hasScrollEnd) return;\n // Every tick while undecided, armed or not: a quiet spell that began while\n // the strip was still moving would judge it mid-flight, away from its aim.\n clearTimeout(state.quiet);\n state.quiet = setTimeout(settle, QUIET_BEFORE_SETTLED_MS);\n };\n const onStrip: Listeners = [\n ['pointerdown', set('pointer', true)],\n ['touchstart', set('touch', true)],\n ['pointercancel', set('nudged', true)],\n ['keydown', set('nudged', true)],\n ['wheel', onWheel],\n ['scroll', onScroll],\n ['scrollend', settle],\n ];\n // A gesture can END off the strip, so its end is heard on the window.\n const onView: Listeners = [\n ['pointerup', set('pointer', false)],\n ['pointercancel', set('pointer', false)],\n ['touchend', set('touch', false)],\n ['touchcancel', set('touch', false)],\n ];\n for (const [type, listener] of onStrip) strip.addEventListener(type, listener, { passive: true });\n for (const [type, listener] of onView) view?.addEventListener(type, listener, { passive: true });\n return {\n hasScrolled: () => state.scrolled,\n isUndecided: () => state.undecided,\n aimedAt: () => state.aimed,\n beforeOwnScroll: (left) => {\n state.aimed = left;\n },\n onSettled: (listener) => {\n state.settled = listener;\n },\n detach: () => {\n clearTimeout(state.quiet);\n for (const [type, listener] of onStrip) strip.removeEventListener(type, listener);\n for (const [type, listener] of onView) view?.removeEventListener(type, listener);\n },\n };\n}\n"],"mappings":";AAYA,IAAM,eAAe;AASrB,IAAM,0BAA0B;AA6BhC,SAAS,gBAAgB,OAAsB;AAC7C,MAAI,EAAE,iBAAiB,YAAa,QAAO;AAC3C,SAAO,MAAM,WAAW,IAAI,MAAM,SAAS,MAAM,WAAW,MAAM,SAAS;AAC7E;AAcA,SAAS,WAAW,OAAoB,OAAwB;AAC9D,QAAM,YAAY,KAAK,IAAI,OAAO,MAAM,cAAc,MAAM,WAAW;AAEvE,SAAO,KAAK,IAAI,MAAM,aAAa,SAAS,KAAK;AACnD;AAkCO,SAAS,mBAAmB,OAAwC;AACzE,QAAM,OAAO,MAAM,cAAc;AACjC,QAAM,eAAe,iBAAiB;AACtC,QAAM,QAAoB;AAAA,IACxB,SAAS;AAAA,IACT,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,UAAU;AAAA,IACV,OAAO,OAAO;AAAA,IACd,OAAO;AAAA,IACP,SAAS,MAAM;AAAA,EACjB;AACA,QAAM,MACJ,CAAC,KAAqC,UACtC,MAAY;AACV,UAAM,GAAG,IAAI;AAAA,EACf;AACF,QAAM,SAAS,MAAY;AAKzB,QAAI,CAAC,MAAM,UAAW;AACtB,UAAM,YAAY;AAClB,UAAM,SAAS;AACf,QAAI,CAAC,WAAW,OAAO,MAAM,KAAK,EAAG,OAAM,WAAW;AACtD,UAAM,QAAQ;AAAA,EAChB;AACA,QAAM,UAAU,CAAC,UAAuB;AACtC,QAAI,gBAAgB,KAAK,MAAM,EAAG,OAAM,SAAS;AAAA,EACnD;AACA,QAAM,WAAW,MAAY;AAC3B,QAAI,MAAM,WAAW,MAAM,SAAS,MAAM,OAAQ,OAAM,YAAY;AACpE,QAAI,CAAC,MAAM,aAAa,aAAc;AAGtC,iBAAa,MAAM,KAAK;AACxB,UAAM,QAAQ,WAAW,QAAQ,uBAAuB;AAAA,EAC1D;AACA,QAAM,UAAqB;AAAA,IACzB,CAAC,eAAe,IAAI,WAAW,IAAI,CAAC;AAAA,IACpC,CAAC,cAAc,IAAI,SAAS,IAAI,CAAC;AAAA,IACjC,CAAC,iBAAiB,IAAI,UAAU,IAAI,CAAC;AAAA,IACrC,CAAC,WAAW,IAAI,UAAU,IAAI,CAAC;AAAA,IAC/B,CAAC,SAAS,OAAO;AAAA,IACjB,CAAC,UAAU,QAAQ;AAAA,IACnB,CAAC,aAAa,MAAM;AAAA,EACtB;AAEA,QAAM,SAAoB;AAAA,IACxB,CAAC,aAAa,IAAI,WAAW,KAAK,CAAC;AAAA,IACnC,CAAC,iBAAiB,IAAI,WAAW,KAAK,CAAC;AAAA,IACvC,CAAC,YAAY,IAAI,SAAS,KAAK,CAAC;AAAA,IAChC,CAAC,eAAe,IAAI,SAAS,KAAK,CAAC;AAAA,EACrC;AACA,aAAW,CAAC,MAAM,QAAQ,KAAK,QAAS,OAAM,iBAAiB,MAAM,UAAU,EAAE,SAAS,KAAK,CAAC;AAChG,aAAW,CAAC,MAAM,QAAQ,KAAK,OAAQ,OAAM,iBAAiB,MAAM,UAAU,EAAE,SAAS,KAAK,CAAC;AAC/F,SAAO;AAAA,IACL,aAAa,MAAM,MAAM;AAAA,IACzB,aAAa,MAAM,MAAM;AAAA,IACzB,SAAS,MAAM,MAAM;AAAA,IACrB,iBAAiB,CAAC,SAAS;AACzB,YAAM,QAAQ;AAAA,IAChB;AAAA,IACA,WAAW,CAAC,aAAa;AACvB,YAAM,UAAU;AAAA,IAClB;AAAA,IACA,QAAQ,MAAM;AACZ,mBAAa,MAAM,KAAK;AACxB,iBAAW,CAAC,MAAM,QAAQ,KAAK,QAAS,OAAM,oBAAoB,MAAM,QAAQ;AAChF,iBAAW,CAAC,MAAM,QAAQ,KAAK,OAAQ,OAAM,oBAAoB,MAAM,QAAQ;AAAA,IACjF;AAAA,EACF;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/pt-BR.data-display.ts"],"sourcesContent":["/**\n * The pt-BR pack for the data-display family. Split out of `pt-BR.ts`, which is a\n * barrel over this folder — see that file for why.\n */\nimport type { DataViewsCopy } from \"./components/data-display/DataViews/data-views-copy\";\nimport type {\n CarouselCopy,\n DataStateCopy,\n LightboxCopy,\n MapPreviewCopy,\n TimingDiagramCopy,\n} from './copy';\nimport { PT_BR_TABLE_FILTER_COPY } from './pt-BR.layout';\nimport {\n PT_BR_CATEGORY_SELECT_COPY,\n PT_BR_CONFIRM_ACTION_COPY,\n PT_BR_SAVED_VIEWS_LABELS,\n} from './pt-BR.shared';\n\nexport const PT_BR_LIGHTBOX_COPY: LightboxCopy = {\n close: \"Fechar\",\n previous: \"Anterior\",\n next: \"Próximo\",\n zoomIn: \"Aproximar\",\n zoomOut: \"Afastar\",\n resetZoom: \"Restaurar o zoom\",\n play: \"Iniciar a apresentação\",\n pause: \"Pausar a apresentação\",\n};\n\nexport const PT_BR_MAP_PREVIEW_COPY: MapPreviewCopy = {\n zoomIn: \"Aproximar\",\n zoomOut: \"Afastar\",\n center: \"Centralizar o mapa\",\n mapType: \"Trocar o tipo de mapa\",\n fullscreen: \"Tela cheia\",\n search: \"Buscar endereço\",\n};\n\nexport const PT_BR_CAROUSEL_COPY: CarouselCopy = {\n previous: \"Anterior\",\n next: \"Próximo\",\n};\n\nexport const PT_BR_TIMING_DIAGRAM_COPY: TimingDiagramCopy = {\n regionLabel: \"Diagrama de tempos\",\n heading: \"Tempo da requisição\",\n};\n\nexport const PT_BR_DATA_STATE_COPY: DataStateCopy = {\n empty: \"Nenhum dado por aqui\",\n loading: \"Carregando…\",\n endOfList: \"Não há mais itens para carregar\",\n dismissAlert: \"Fechar o aviso\",\n dismissBanner: \"Fechar a faixa\",\n};\n\nexport const PT_BR_DATA_VIEWS_COPY: DataViewsCopy = {\n savedViewsMenu: PT_BR_SAVED_VIEWS_LABELS,\n confirmAction: PT_BR_CONFIRM_ACTION_COPY,\n categorySelect: PT_BR_CATEGORY_SELECT_COPY,\n board: {\n countOnPage: (label, count) => `${label}: ${count} nesta página`,\n onThisPage: (count) => `${count} nesta página`,\n pageSum: (sum) => `Soma desta página: ${sum}`,\n emptyColumn: \"Nada nesta etapa\",\n pageScopeNote:\n \"As contagens e somas abaixo referem-se apenas aos itens desta página.\",\n },\n deleteView: {\n title: \"Excluir visão\",\n target: (viewName) => `Excluir \"${viewName}\"?`,\n sharedWarning: \"Esta visão está compartilhada — a equipe perderá o acesso a ela.\",\n rowsUnaffected: (entityLabel) =>\n `${entityLabel} não são afetados; apenas o recorte salvo é removido.`,\n confirm: \"Excluir visão\",\n cancel: \"Cancelar\",\n },\n manageViews: {\n title: \"Gerenciar visões\",\n empty: \"Nenhuma visão salva.\",\n edit: \"Editar\",\n defaultTag: \"Padrão\",\n otherUserTag: \"De outro usuário\",\n deleteTitle: \"Excluir a visão salva?\",\n deleteBody: \"Os filtros e colunas guardados nela são perdidos. Não é possível restaurar.\",\n deleteConfirm: \"Excluir\",\n },\n saveView: {\n sharedDescription: \"Qualquer pessoa da loja poderá abrir e usar esta visão.\",\n setDefaultTitle: \"Definir como padrão\",\n setDefaultDescription: \"Esta tela abre nesta visão em vez da Visão principal.\",\n previewHeading: \"O que esta visão guarda\",\n previewUnchanged: \"Nada foi alterado — esta visão ficará igual à Visão principal.\",\n sortRowLabel: \"Ordenação\",\n saveFailed: \"Não foi possível salvar a visão.\",\n titleEditing: \"Editar visão\",\n titleCreating: \"Salvar visão\",\n descriptionLabel: \"Descrição — opcional\",\n descriptionPlaceholder: \"Para que serve esta visão\",\n submitEditing: \"Salvar alterações\",\n submitCreating: \"Salvar visão\",\n nameLabel: \"Nome\",\n cancel: \"Cancelar\",\n pinnedTitle: \"Fixar na barra lateral\",\n pinnedDescription: \"Aparece como atalho no menu, abaixo desta tela.\",\n sharedTitle: \"Compartilhar com a equipe\",\n namePlaceholder: \"Ex.: Recusados no PIX desta semana\",\n previewFilters: \"Filtros\",\n previewHiddenColumns: \"Colunas ocultas\",\n },\n columns: {\n visibleCount: (visible, total) => `${visible} de ${total} visíveis`,\n reset: \"Padrão\",\n showAll: \"Mostrar todas\",\n dragHint: \"Arraste para reordenar as colunas.\",\n moveUp: (columnLabel) => `Mover ${columnLabel} para cima`,\n moveDown: (columnLabel) => `Mover ${columnLabel} para baixo`,\n },\n display: {\n sortTab: \"Ordenar\",\n columnsTab: \"Colunas\",\n panelTab: \"Exibição\",\n direction: \"Direção\",\n layoutHints: {\n table: \"Colunas comparáveis, boa para varrer números.\",\n list: \"Uma linha por item, com os dados principais.\",\n cards: \"Blocos maiores, bom para poucos itens.\",\n board: \"Colunas por etapa, para acompanhar o que está onde.\",\n },\n densityHeadings: {\n table: \"Altura das linhas\",\n list: \"Altura das linhas\",\n cards: \"Cards por linha\",\n board: \"Largura das colunas\",\n },\n densityLabels: {\n table: { compact: \"Baixa\", cozy: \"Média\", comfortable: \"Alta\" },\n list: { compact: \"Baixa\", cozy: \"Média\", comfortable: \"Alta\" },\n cards: { compact: \"Muitos\", cozy: \"Médio\", comfortable: \"Poucos\" },\n board: { compact: \"Estreita\", cozy: \"Média\", comfortable: \"Larga\" },\n },\n boardUnavailable: \"Esta tela não declara etapas, então não oferece quadro.\",\n densityUnavailableNarrow:\n \"Um card por linha nesta largura — a densidade volta em telas maiores.\",\n trigger: \"Exibir\",\n fieldHeading: \"Campo\",\n formatHeading: \"Formato\",\n cardZoom: \"Tamanho dos cards\",\n },\n export: {\n formats: {\n json: { label: \"JSON (.json)\", hint: \"Para integrações\" },\n },\n visibleColumns: (columnCount) => `${columnCount} colunas visíveis, na ordem atual`,\n trigger: \"Exportar\",\n triggerLabel: \"Exportar\",\n },\n tableFilter: PT_BR_TABLE_FILTER_COPY,\n grid: {\n rowActions: \"Ações\",\n bulkActions: (selectedCount) => `Ações (${selectedCount}) ▾`,\n emptyFilteredTitle: \"Nenhum resultado para esses filtros\",\n emptyFilteredHint: \"Ajuste ou remova os filtros.\",\n emptyFilteredAction: \"Limpar filtros\",\n },\n filters: {\n moreFilters: (count) => `Mais filtros: ${count} sem espaço na barra`,\n moreFiltersApplied: (count, appliedCount) =>\n `Mais filtros: ${count} sem espaço na barra, ${appliedCount} aplicado(s)`,\n moreTriggerLabel: \"Mais\",\n moreHeading: \"Mais filtros\",\n overflowNote: \"sem espaço na barra\",\n rangeEnd: \"Até\",\n rangeInvalid: \"O início precisa ser menor que o fim.\",\n rangeInclusiveNote: \"Ambas as datas entram no resultado.\",\n rangeStart: \"De\",\n dayMask: \"dd/mm/aaaa\",\n clearAllFilters: \"Limpar todos os filtros\",\n rangePresets: {\n hoje: \"Hoje\",\n ontem: \"Ontem\",\n semana: \"Esta semana\",\n mes: \"Este mês\",\n ano: \"Este ano\",\n },\n scopesLabel: \"Situação\",\n panelTitle: \"Filtros\",\n clear: \"Limpar\",\n clearAll: \"Limpar filtros\",\n clearRange: (label) => `Limpar ${label}`,\n allOption: \"Todas\",\n optionSearchPlaceholder: \"Buscar…\",\n optionsEmpty: \"Nenhum resultado\",\n optionsHeading: \"Opções\",\n },\n selection: {\n selectAllOnPage: \"Selecionar todos nesta página\",\n clearSelection: \"Limpar seleção\",\n selectAll: \"Selecionar tudo\",\n onThisPage: (count) => `${count} nesta página`,\n selectRow: \"Selecionar\",\n expandRow: \"Expandir detalhes\",\n collapseRow: \"Recolher detalhes\",\n },\n nav: {\n mainView: \"Visão principal\",\n defaultTag: \"Padrão\",\n viewOptions: (viewName) => `Opções de ${viewName}`,\n emptyHint: \"Nenhuma visão salva. Ajuste filtros, colunas ou ordenação e salve abaixo.\",\n setDefault: \"Definir como padrão\",\n deleteView: \"Excluir visão\",\n unsavedChanges: \"Alterações não salvas\",\n label: \"Visão\",\n update: \"Atualizar visão\",\n save: \"Salvar visão\",\n saveAs: \"Salvar como nova\",\n reset: \"Redefinir\",\n updateFailed: \"Não foi possível atualizar a visão\",\n dismissError: \"Fechar o aviso\",\n goBack: \"Voltar\",\n pageSize: \"Mostrar:\",\n saveFailed: \"Não foi possível salvar a alteração da visão.\",\n editView: \"Renomear e editar\",\n pinToSidebar: \"Fixar na barra lateral\",\n shareWithTeam: \"Compartilhar com a equipe\",\n },\n search: {\n placeholder: \"Buscar…\",\n allColumnsLabel: \"Buscar em todas as colunas\",\n keywordPlaceholder: \"Pressione Enter para filtrar\",\n open: \"Buscar\",\n close: \"Fechar busca\",\n clear: \"Limpar busca\",\n },\n};\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/layout/Dashboard/DashboardParts.tsx"],"sourcesContent":["'use client';\n\nimport CloseIcon from '@mui/icons-material/Close';\nimport ExpandMoreIcon from '@mui/icons-material/ExpandMore';\nimport ExportIcon from '@mui/icons-material/FileDownloadOutlined';\nimport FilterIcon from '@mui/icons-material/FilterListRounded';\nimport InfoIcon from '@mui/icons-material/InfoOutlined';\nimport SettingsIcon from '@mui/icons-material/SettingsOutlined';\nimport Badge from '@mui/material/Badge/index.js';\nimport Box from '@mui/material/Box/index.js';\nimport Dialog from '@mui/material/Dialog/index.js';\nimport DialogContent from '@mui/material/DialogContent/index.js';\nimport DialogTitle from '@mui/material/DialogTitle/index.js';\nimport IconButton from '@mui/material/IconButton/index.js';\nimport Menu from '@mui/material/Menu/index.js';\nimport MenuItem from '@mui/material/MenuItem/index.js';\nimport Popover from '@mui/material/Popover/index.js';\nimport Tooltip from '@mui/material/Tooltip/index.js';\nimport Typography from '@mui/material/Typography/index.js';\nimport React, { useState } from 'react';\n\nimport { HeaderActions } from '../../form/HeaderActions';\nimport { HeaderButton } from '../../form/HeaderButton';\nimport { useDashboardContext } from './DashboardContext';\nimport type {\n DashboardActionProps,\n DashboardActionsProps,\n DashboardExportFormat,\n DashboardExportProps,\n DashboardFilterToggleProps,\n DashboardInfoProps,\n DashboardSettingsProps,\n} from './Dashboard.types';\nimport { sxRem } from '../../../tokens/relative';\n\n/** Flexible spacer — everything composed after it is pushed to the right. */\nexport const DashboardSpacer = (): React.JSX.Element => <Box sx={{ flex: 1 }} aria-hidden />;\nDashboardSpacer.displayName = 'Dashboard.Spacer';\n\nexport const DashboardInfo = ({\n title = 'About this page',\n children,\n ariaLabel = 'Page information',\n}: DashboardInfoProps): React.JSX.Element => {\n const { testIdPrefix } = useDashboardContext();\n const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);\n const open = Boolean(anchorEl);\n return (\n <>\n <Tooltip title={ariaLabel}>\n <IconButton\n size=\"small\"\n aria-label={ariaLabel}\n aria-haspopup=\"dialog\"\n onClick={(e) => setAnchorEl(e.currentTarget)}\n data-testid={`${testIdPrefix}-info-trigger`}\n sx={{ color: 'text.secondary' }}\n >\n <InfoIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <Popover\n open={open}\n anchorEl={anchorEl}\n onClose={() => setAnchorEl(null)}\n anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}\n slotProps={{ paper: { sx: { width: sxRem(360), maxWidth: '90vw' } } }}\n data-testid={`${testIdPrefix}-info-popover`}\n >\n <Box sx={{ px: 2, py: 1.5, borderBottom: 1, borderColor: 'divider', display: 'flex', gap: 1, alignItems: 'center' }}>\n <InfoIcon fontSize=\"small\" sx={{ color: 'text.secondary' }} />\n <Typography sx={{ fontWeight: 600 }}>{title}</Typography>\n </Box>\n <Box sx={{ px: 2, py: 1.5, fontSize: sxRem(14), color: 'text.secondary' }}>{children}</Box>\n </Popover>\n </>\n );\n};\nDashboardInfo.displayName = 'Dashboard.Info';\n\nexport const DashboardFilterToggle = ({ ariaLabel }: DashboardFilterToggleProps): React.JSX.Element => {\n const { filtersVisible, toggleFilters, activeFilterCount, testIdPrefix } = useDashboardContext();\n const label = ariaLabel ?? (filtersVisible ? 'Hide filters' : 'Show filters');\n return (\n <Tooltip title={label}>\n <IconButton\n size=\"small\"\n aria-label={label}\n aria-pressed={filtersVisible}\n onClick={toggleFilters}\n data-testid={`${testIdPrefix}-filter-toggle`}\n sx={{ color: filtersVisible ? 'primary.main' : 'text.secondary', bgcolor: filtersVisible ? 'action.selected' : 'transparent' }}\n >\n <Badge badgeContent={activeFilterCount} color=\"primary\" overlap=\"circular\">\n <FilterIcon fontSize=\"small\" />\n </Badge>\n </IconButton>\n </Tooltip>\n );\n};\nDashboardFilterToggle.displayName = 'Dashboard.FilterToggle';\n\nexport const DashboardSettings = ({\n title = 'Settings',\n closeLabel,\n children,\n ariaLabel = 'Settings',\n href,\n linkComponent,\n}: DashboardSettingsProps): React.JSX.Element => {\n const { testIdPrefix } = useDashboardContext();\n const [open, setOpen] = useState(false);\n\n // Link mode: the gear navigates to a settings route (e.g. the page's\n // Configuração section) instead of opening an in-page dialog.\n if (href) {\n const LinkComponent = linkComponent ?? 'a';\n return (\n <Tooltip title={ariaLabel}>\n <IconButton\n size=\"small\"\n aria-label={ariaLabel}\n component={LinkComponent}\n href={href}\n data-testid={`${testIdPrefix}-settings-trigger`}\n sx={{ color: 'text.secondary' }}\n >\n <SettingsIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n );\n }\n\n return (\n <>\n <Tooltip title={ariaLabel}>\n <IconButton\n size=\"small\"\n aria-label={ariaLabel}\n aria-haspopup=\"dialog\"\n onClick={() => setOpen(true)}\n data-testid={`${testIdPrefix}-settings-trigger`}\n sx={{ color: 'text.secondary' }}\n >\n <SettingsIcon fontSize=\"small\" />\n </IconButton>\n </Tooltip>\n <Dialog open={open} onClose={() => setOpen(false)} maxWidth=\"sm\" fullWidth data-testid={`${testIdPrefix}-settings-dialog`}>\n <DialogTitle sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>\n {title}\n <IconButton aria-label={closeLabel} size=\"small\" onClick={() => setOpen(false)}>\n <CloseIcon fontSize=\"small\" />\n </IconButton>\n </DialogTitle>\n <DialogContent dividers>{children}</DialogContent>\n </Dialog>\n </>\n );\n};\nDashboardSettings.displayName = 'Dashboard.Settings';\n\nconst DEFAULT_EXPORT_FORMATS: DashboardExportFormat[] = [\n { id: 'csv', label: 'CSV (.csv)' },\n { id: 'xlsx', label: 'Excel (.xlsx)' },\n { id: 'json', label: 'JSON (.json)' },\n];\n\nexport const DashboardExport = ({\n formats = DEFAULT_EXPORT_FORMATS,\n onExport,\n label = 'Export',\n}: DashboardExportProps): React.JSX.Element => {\n const { testIdPrefix } = useDashboardContext();\n const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);\n const open = Boolean(anchorEl);\n return (\n <>\n <HeaderButton\n variant=\"outlined\"\n color=\"inherit\"\n text={label}\n icon={<ExportIcon fontSize=\"small\" />}\n endIcon={<ExpandMoreIcon fontSize=\"small\" />}\n onClick={(e) => setAnchorEl(e.currentTarget)}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n dataTestId={`${testIdPrefix}-export-trigger`}\n />\n <Menu anchorEl={anchorEl} open={open} onClose={() => setAnchorEl(null)} data-testid={`${testIdPrefix}-export-menu`}>\n {formats.map((format) => (\n <MenuItem\n key={format.id}\n onClick={() => {\n onExport(format.id);\n setAnchorEl(null);\n }}\n data-testid={`${testIdPrefix}-export-${format.id}`}\n >\n {format.label}\n </MenuItem>\n ))}\n </Menu>\n </>\n );\n};\nDashboardExport.displayName = 'Dashboard.Export';\n\nexport const DashboardAction = ({ children }: DashboardActionProps): React.JSX.Element => (\n <Box sx={{ display: 'inline-flex' }}>{children}</Box>\n);\nDashboardAction.displayName = 'Dashboard.Action';\n\n/**\n * The header's actions, declared as a LIST — `<Dashboard.Action>`'s plural.\n *\n * `<Dashboard.Action>` is a slot: it renders whatever you hand it, once per\n * action, and a page with five of them draws five equally-loud buttons. That is\n * the right primitive for one button and the wrong one for five, and the pages\n * here that grew a fifth action all grew it the same way — by adding a fifth\n * slot, because the slot was the only thing on offer.\n *\n * This part answers the question the slot cannot: given N actions, how many\n * belong on the bar? See {@link HeaderActions} for the rule (0 ⇒ nothing,\n * 1 ⇒ a button, n ⇒ a button and a menu of the rest).\n *\n * Both stay. A header still composes `<Dashboard.Action>` for the one control\n * that is not an action at all — a link, a toggle, a status pill — and reaches\n * for this when it has actions to rank.\n */\nexport const DashboardActions = ({\n actions,\n moreLabel,\n collapseBelow,\n}: DashboardActionsProps): React.JSX.Element => {\n const { testIdPrefix } = useDashboardContext();\n return (\n <HeaderActions\n actions={actions}\n moreLabel={moreLabel}\n collapseBelow={collapseBelow}\n testIdPrefix={`${testIdPrefix}-actions`}\n />\n );\n};\nDashboardActions.displayName = 'Dashboard.Actions';\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/data-display/TimingDiagram/TimingDiagram.views.tsx"],"sourcesContent":["import Box from '@mui/material/Box/index.js';\nimport Tooltip from '@mui/material/Tooltip/index.js';\nimport Typography from '@mui/material/Typography/index.js';\nimport { alpha, styled, useTheme } from '@mui/material/styles/index.js';\nimport type { Theme } from '@mui/material/styles/index.js';\nimport type { FC, ReactElement } from 'react';\nimport React from 'react';\n\nimport type { TimingData } from './TimingDiagram.types';\nimport { onMedia, sheen, uiInk } from '../../../tokens/ink';\nimport { rem, rems } from '../../../tokens/relative';\n\nexport type PhaseKey = 'dns' | 'connect' | 'ssl' | 'request' | 'response';\n\n// Each phase's colour, from the theme's named timing set (`uiInk`).\nexport const phaseColors = (theme: Theme): Record<PhaseKey, string> => {\n const phases = uiInk(theme).timingPhases;\n return {\n dns: phases.dns,\n connect: phases.connect,\n ssl: phases.tls,\n request: phases.request,\n response: phases.response,\n };\n};\n\nexport interface Phase {\n key: string;\n label: string;\n value?: number;\n}\n\nexport interface TimingViewProps {\n phases: Phase[];\n percentages: Record<string, number>;\n data: TimingData;\n animated: boolean;\n showLabels: boolean;\n showTooltips: boolean;\n /** The waterfall's plot height in design px — drawn through `rem`. */\n plotHeightPx: number;\n}\n\nexport const formatTime = (ms: number): string => {\n if (ms < 1000) return `${ms}ms`;\n return `${(ms / 1000).toFixed(2)}s`;\n};\n\nconst colorOf = (theme: Theme, phase: Phase): string => phaseColors(theme)[phase.key as PhaseKey];\nconst widthOf = (percentages: Record<string, number>, phase: Phase): number =>\n percentages[phase.key] ?? 0;\n\n// Waterfall and stacked both offer the same hover explanation of a segment; only\n// whether tooltips are on at all varies.\nconst withTooltip = (\n phase: Phase,\n enabled: boolean,\n element: ReactElement,\n): ReactElement =>\n enabled ? (\n <Tooltip\n key={phase.key}\n title={`${phase.label}: ${formatTime(phase.value!)}`}\n placement=\"top\"\n role=\"tooltip\"\n aria-describedby={`tooltip-${phase.key}`}\n >\n {element}\n </Tooltip>\n ) : (\n element\n );\n\nconst WaterfallContainer = styled(Box)(({ theme }) => ({\n position: 'relative',\n width: '100%',\n marginTop: theme.spacing(2),\n}));\n\nconst WaterfallBar = styled(Box, {\n shouldForwardProp: (prop) =>\n !['phaseColor', 'offset', 'widthPct', 'animated'].includes(prop as string),\n})<{\n phaseColor: string;\n offset: number;\n widthPct: number;\n animated: boolean;\n}>(({ theme, phaseColor, offset, widthPct, animated }) => ({\n position: 'absolute',\n height: rem(theme, 32),\n left: `${offset}%`,\n width: `${widthPct}%`,\n background: `linear-gradient(90deg, ${phaseColor} 0%, ${alpha(phaseColor, 0.8)} 100%)`,\n borderRadius: theme.shape.borderRadius,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: theme.palette.getContrastText(phaseColor),\n fontSize: rem(theme, 12),\n fontWeight: 500,\n boxShadow: `${rems(theme, 0, 2, 8)} ${alpha(phaseColor, 0.3)}`,\n transition: animated ? 'all 0.5s ease' : 'none',\n animation: animated ? 'slideIn 0.5s ease' : 'none',\n '@keyframes slideIn': {\n from: {\n transform: `translateX(${rem(theme, -20)})`,\n opacity: 0,\n },\n to: {\n transform: 'translateX(0)',\n opacity: 1,\n },\n },\n '&:hover': {\n transform: `translateY(${rem(theme, -2)})`,\n boxShadow: `${rems(theme, 0, 4, 12)} ${alpha(phaseColor, 0.5)}`,\n zIndex: 10,\n },\n}));\n\nconst TimelineAxis = styled(Box)(({ theme }) => ({\n display: 'flex',\n justifyContent: 'space-between',\n marginTop: theme.spacing(1),\n paddingTop: theme.spacing(1),\n borderTop: `1px solid ${alpha(theme.palette.divider, 0.2)}`,\n}));\n\nconst TimeLabel = styled(Typography)(({ theme }) => ({\n fontSize: rem(theme, 11.2),\n color: theme.palette.text.secondary,\n fontWeight: 500,\n}));\n\nexport const WaterfallView: FC<TimingViewProps> = ({\n phases,\n percentages,\n data,\n animated,\n showLabels,\n showTooltips,\n plotHeightPx,\n}) => {\n const theme = useTheme();\n // Each bar starts where the previous one ended, so the row reads as a timeline.\n let offset = 0;\n\n return (\n <WaterfallContainer style={{ height: rem(theme, plotHeightPx + 40) }} data-variant=\"waterfall\">\n {phases.map((phase, index) => {\n const width = widthOf(percentages, phase);\n const currentOffset = offset;\n offset += width;\n\n return withTooltip(\n phase,\n showTooltips,\n <WaterfallBar\n key={phase.key}\n data-testid={`timing-segment-${phase.key}`}\n phaseColor={colorOf(theme, phase)}\n offset={currentOffset}\n widthPct={width}\n animated={animated}\n data-animated={animated.toString()}\n style={{\n top: rem(theme, index * 8),\n width: `${width}%`,\n left: `${currentOffset}%`,\n }}\n >\n {showLabels && width > 10 && (\n <span data-testid=\"timing-label\">{formatTime(phase.value!)}</span>\n )}\n </WaterfallBar>,\n );\n })}\n <TimelineAxis style={{ marginTop: rem(theme, plotHeightPx) }}>\n <TimeLabel>0ms</TimeLabel>\n <TimeLabel>{formatTime(data.total / 2)}</TimeLabel>\n <TimeLabel>{formatTime(data.total)}</TimeLabel>\n </TimelineAxis>\n </WaterfallContainer>\n );\n};\n\nconst StackedBar = styled(Box, {\n shouldForwardProp: (prop) => prop !== 'animated',\n})<{ animated: boolean }>(({ theme, animated }) => ({\n display: 'flex',\n width: '100%',\n height: rem(theme, 40),\n borderRadius: theme.shape.borderRadius,\n overflow: 'hidden',\n boxShadow: theme.shadows[2],\n ...(animated && {\n '& > div': {\n animation: 'expandWidth 0.8s ease',\n },\n '@keyframes expandWidth': {\n from: { width: 0 },\n to: { width: '100%' },\n },\n }),\n}));\n\nconst StackedSegment = styled(Box, {\n shouldForwardProp: (prop) => !['phaseColor', 'widthPct'].includes(prop as string),\n})<{ phaseColor: string; widthPct: number }>(({ theme, phaseColor, widthPct }) => ({\n width: `${widthPct}%`,\n background: `linear-gradient(135deg, ${phaseColor} 0%, ${alpha(phaseColor, 0.85)} 100%)`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: onMedia(theme),\n fontSize: rem(theme, 11.2),\n fontWeight: 600,\n position: 'relative',\n transition: 'all 0.3s ease',\n '&:hover': {\n filter: 'brightness(1.1)',\n zIndex: 1,\n },\n}));\n\nexport const StackedView: FC<TimingViewProps> = ({\n phases,\n percentages,\n data,\n animated,\n showLabels,\n showTooltips,\n}) => {\n const theme = useTheme();\n return (\n <Box data-variant=\"stacked\">\n <StackedBar animated={animated} data-animated={animated.toString()}>\n {phases.map((phase) => {\n const width = widthOf(percentages, phase);\n\n return withTooltip(\n phase,\n showTooltips,\n <StackedSegment\n key={phase.key}\n data-testid={`timing-segment-${phase.key}`}\n phaseColor={colorOf(theme, phase)}\n widthPct={width}\n style={{ width: `${width}%` }}\n >\n {showLabels && width > 10 && (\n <span data-testid=\"timing-label\">{formatTime(phase.value!)}</span>\n )}\n </StackedSegment>,\n );\n })}\n </StackedBar>\n <Box sx={{ display: 'flex', justifyContent: 'space-between', mt: 1 }}>\n <Typography variant=\"caption\" color=\"text.secondary\">\n 0ms\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" fontWeight=\"bold\">\n Total: {formatTime(data.total)}\n </Typography>\n </Box>\n </Box>\n );\n};\n\nconst HorizontalBar = styled(Box)(({ theme }) => ({\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(1),\n marginTop: theme.spacing(2),\n}));\n\nconst HorizontalSegment = styled(Box, {\n shouldForwardProp: (prop) => !['phaseColor', 'widthPct', 'animated'].includes(prop as string),\n})<{\n phaseColor: string;\n widthPct: number;\n animated: boolean;\n}>(({ theme, phaseColor, animated }) => ({\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(2),\n '& .label': {\n minWidth: rem(theme, 80),\n fontSize: rem(theme, 13.6),\n fontWeight: 500,\n color: theme.palette.text.secondary,\n },\n '& .bar': {\n flex: 1,\n height: rem(theme, 24),\n borderRadius: theme.shape.borderRadius,\n background: `linear-gradient(90deg, ${phaseColor} 0%, ${alpha(phaseColor, 0.7)} 100%)`,\n position: 'relative',\n overflow: 'hidden',\n boxShadow: `${rems(theme, 0, 2, 6)} ${alpha(phaseColor, 0.25)}`,\n ...(animated && {\n '&::after': {\n content: '\"\"',\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n background: `linear-gradient(90deg, transparent 0%, ${sheen(theme, 0.3)} 50%, transparent 100%)`,\n animation: 'shimmer 2s infinite',\n },\n '@keyframes shimmer': {\n from: { transform: 'translateX(-100%)' },\n to: { transform: 'translateX(100%)' },\n },\n }),\n },\n '& .value': {\n minWidth: rem(theme, 60),\n textAlign: 'right',\n fontSize: rem(theme, 13.6),\n fontWeight: 600,\n color: phaseColor,\n },\n}));\n\nexport const HorizontalView: FC<TimingViewProps> = ({\n phases,\n percentages,\n data,\n animated,\n}) => {\n const theme = useTheme();\n\n return (\n <HorizontalBar data-variant=\"horizontal\">\n {phases.map((phase) => (\n <HorizontalSegment\n key={phase.key}\n data-testid={`timing-segment-${phase.key}`}\n phaseColor={colorOf(theme, phase)}\n widthPct={widthOf(percentages, phase)}\n animated={animated}\n data-animated={animated.toString()}\n >\n <Typography className=\"label\">{phase.label}</Typography>\n <Box className=\"bar\" style={{ width: `${percentages[phase.key]}%` }} />\n <Typography className=\"value\" data-testid=\"timing-label\">\n {formatTime(phase.value!)}\n </Typography>\n </HorizontalSegment>\n ))}\n <Box sx={{ mt: 2, pt: 2, borderTop: `1px solid ${alpha(theme.palette.divider, 0.2)}` }}>\n <Typography variant=\"body2\" fontWeight=\"bold\" color=\"primary\">\n Total Time: {formatTime(data.total)}\n </Typography>\n </Box>\n </HorizontalBar>\n );\n};\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/data-display/DataGrid/DataGrid.tsx"],"sourcesContent":["/**\n * `DataGrid` — the shell.\n *\n * Everything that is not \"which of the four renders is this, and what wraps the\n * table\" lives beside it: the state in `DataGrid.model.ts`, the client-mode row\n * pipeline in `DataGrid.rows.ts`, the cells and rows in `DataGrid.cells.tsx`,\n * the head/body in `DataGrid.body.tsx`, and the loading/error/empty renders in\n * `DataGrid.states.tsx`.\n *\n * All FOUR renders carry the caller's `data-testid`. It used to be applied only\n * on the populated one, so a grid whose first paint had no rows could not be\n * found by a test at all — see `DataGrid.states.tsx` for the full story.\n */\nimport Paper from '@mui/material/Paper/index.js';\nimport Table from '@mui/material/Table/index.js';\nimport TableContainer from '@mui/material/TableContainer/index.js';\nimport type React from 'react';\n\nimport { GridBody, GridHeader } from './DataGrid.body';\nimport { useDataGridModel } from './DataGrid.model';\nimport { DataGridEmpty, DataGridError, DataGridLoading } from './DataGrid.states';\nimport type { DataGridProps } from './DataGrid.types';\n\n/**\n * The chrome every render needs, with the defaults resolved ONCE.\n *\n * Extracted from the component body because a dozen destructuring defaults are\n * a dozen branches: the gate counted them, correctly, as complexity the render\n * did not need to carry.\n */\nfunction resolveChrome<T extends Record<string, unknown>>(props: DataGridProps<T>): {\n dataAttrs: Record<string, unknown>;\n placeholder: {\n dataTestId?: string;\n ariaLabel: string;\n className?: string;\n style?: React.CSSProperties;\n htmlProps: React.HTMLAttributes<HTMLElement>;\n };\n} {\n const { className, style, 'data-testid': dataTestId, ...rest } = props;\n const stickyHeader = props.stickyHeader ?? true;\n return {\n dataAttrs: {\n 'data-ui': 'datagrid',\n 'data-density': props.density ?? 'comfortable',\n 'data-size-mode': props.sizeMode ?? 'auto',\n 'data-virtual-rows': props.virtualizeRows ?? true,\n 'data-virtual-cols': props.virtualizeColumns ?? false,\n 'data-sticky-header': stickyHeader,\n },\n placeholder: {\n dataTestId,\n ariaLabel: props.ariaLabel ?? 'Data grid',\n className,\n style,\n // Only the DOM-safe leftovers reach the element: every grid-specific prop\n // is named in `GRID_ONLY_PROPS`, so this cannot smuggle `rows` onto a div.\n htmlProps: omitGridProps(rest as Record<string, unknown>),\n },\n };\n}\n\nexport const DataGrid = <T extends Record<string, unknown> = Record<string, unknown>>(\n props: DataGridProps<T>,\n): React.JSX.Element => {\n const model = useDataGridModel(props);\n const { dataAttrs, placeholder } = resolveChrome(props);\n\n if (props.loading) return <DataGridLoading {...placeholder} />;\n if (props.error) return <DataGridError {...placeholder} error={props.error} />;\n if (model.processedRows.length === 0) {\n return <DataGridEmpty {...placeholder} emptyState={props.emptyState} emptyText={props.emptyText} />;\n }\n\n const leadingColumns = (props.selection?.mode ?? 'none') !== 'none' ? 1 : 0;\n const totalColumns =\n model.visibleColumns.length + leadingColumns + (props.expansion ? 1 : 0);\n const section = { model, props, totalColumns };\n\n return (\n <Paper\n ref={model.containerRef}\n {...dataAttrs}\n data-testid={placeholder.dataTestId}\n className={placeholder.className}\n style={placeholder.style}\n role=\"grid\"\n aria-label={placeholder.ariaLabel}\n aria-description={props.ariaDescription}\n aria-rowcount={model.processedRows.length + 1} // +1 for the header row\n aria-colcount={totalColumns}\n sx={{ height: '100%', overflow: 'hidden', display: 'flex', flexDirection: 'column' }}\n {...placeholder.htmlProps}\n >\n <TableContainer\n sx={{ flex: 1, overflow: 'auto', position: 'relative' }}\n onScroll={model.onScroll}\n >\n <Table stickyHeader={props.stickyHeader ?? true}>\n <GridHeader {...section} />\n <GridBody {...section} />\n </Table>\n </TableContainer>\n </Paper>\n );\n};\n\n/**\n * The grid props that are NOT HTML attributes.\n *\n * `DataGridProps` extends `HTMLAttributes`, so the rest-spread carries the\n * grid's own configuration too. React would warn (or worse, serialize an array\n * of rows into an attribute) if any of it reached the DOM.\n *\n * Exported so a test can render a grid carrying every name on it and assert\n * none reaches the DOM — the check that would have caught `emptyText` missing.\n */\nexport const GRID_ONLY_PROPS = [\n 'rows',\n 'columns',\n 'getRowId',\n 'sizeMode',\n 'density',\n 'rowHeight',\n 'headerHeight',\n 'footerHeight',\n 'selection',\n 'pagination',\n 'sorting',\n 'filtering',\n 'expansion',\n 'editing',\n 'virtualizeRows',\n 'virtualizeColumns',\n 'stickyHeader',\n 'stickyFooter',\n 'loading',\n 'error',\n 'emptyState',\n 'emptyText',\n 'onRequestData',\n 'ariaLabel',\n 'ariaDescription',\n] as const;\n\nfunction omitGridProps(rest: Record<string, unknown>): React.HTMLAttributes<HTMLElement> {\n const html: Record<string, unknown> = { ...rest };\n for (const key of GRID_ONLY_PROPS) delete html[key];\n return html as React.HTMLAttributes<HTMLElement>;\n}\n\nDataGrid.displayName = 'DataGrid';\n"],"mappings":";;;;;;;;;;;;;;AAaA,OAAO,WAAW;AAClB,OAAO,WAAW;AAClB,OAAO,oBAAoB;AAsDC,cA8BpB,YA9BoB;AAvC5B,SAAS,cAAiD,OASxD;AACA,QAAM,EAAE,WAAW,OAAO,eAAe,YAAY,GAAG,KAAK,IAAI;AACjE,QAAM,eAAe,MAAM,gBAAgB;AAC3C,SAAO;AAAA,IACL,WAAW;AAAA,MACT,WAAW;AAAA,MACX,gBAAgB,MAAM,WAAW;AAAA,MACjC,kBAAkB,MAAM,YAAY;AAAA,MACpC,qBAAqB,MAAM,kBAAkB;AAAA,MAC7C,qBAAqB,MAAM,qBAAqB;AAAA,MAChD,sBAAsB;AAAA,IACxB;AAAA,IACA,aAAa;AAAA,MACX;AAAA,MACA,WAAW,MAAM,aAAa;AAAA,MAC9B;AAAA,MACA;AAAA;AAAA;AAAA,MAGA,WAAW,cAAc,IAA+B;AAAA,IAC1D;AAAA,EACF;AACF;AAEO,IAAM,WAAW,CACtB,UACsB;AACtB,QAAM,QAAQ,iBAAiB,KAAK;AACpC,QAAM,EAAE,WAAW,YAAY,IAAI,cAAc,KAAK;AAEtD,MAAI,MAAM,QAAS,QAAO,oBAAC,mBAAiB,GAAG,aAAa;AAC5D,MAAI,MAAM,MAAO,QAAO,oBAAC,iBAAe,GAAG,aAAa,OAAO,MAAM,OAAO;AAC5E,MAAI,MAAM,cAAc,WAAW,GAAG;AACpC,WAAO,oBAAC,iBAAe,GAAG,aAAa,YAAY,MAAM,YAAY,WAAW,MAAM,WAAW;AAAA,EACnG;AAEA,QAAM,kBAAkB,MAAM,WAAW,QAAQ,YAAY,SAAS,IAAI;AAC1E,QAAM,eACJ,MAAM,eAAe,SAAS,kBAAkB,MAAM,YAAY,IAAI;AACxE,QAAM,UAAU,EAAE,OAAO,OAAO,aAAa;AAE7C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK,MAAM;AAAA,MACV,GAAG;AAAA,MACJ,eAAa,YAAY;AAAA,MACzB,WAAW,YAAY;AAAA,MACvB,OAAO,YAAY;AAAA,MACnB,MAAK;AAAA,MACL,cAAY,YAAY;AAAA,MACxB,oBAAkB,MAAM;AAAA,MACxB,iBAAe,MAAM,cAAc,SAAS;AAAA,MAC5C,iBAAe;AAAA,MACf,IAAI,EAAE,QAAQ,QAAQ,UAAU,UAAU,SAAS,QAAQ,eAAe,SAAS;AAAA,MAClF,GAAG,YAAY;AAAA,MAEhB;AAAA,QAAC;AAAA;AAAA,UACC,IAAI,EAAE,MAAM,GAAG,UAAU,QAAQ,UAAU,WAAW;AAAA,UACtD,UAAU,MAAM;AAAA,UAEhB,+BAAC,SAAM,cAAc,MAAM,gBAAgB,MACzC;AAAA,gCAAC,cAAY,GAAG,SAAS;AAAA,YACzB,oBAAC,YAAU,GAAG,SAAS;AAAA,aACzB;AAAA;AAAA,MACF;AAAA;AAAA,EACF;AAEJ;AAYO,IAAM,kBAAkB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,cAAc,MAAkE;AACvF,QAAM,OAAgC,EAAE,GAAG,KAAK;AAChD,aAAW,OAAO,gBAAiB,QAAO,KAAK,GAAG;AAClD,SAAO;AACT;AAEA,SAAS,cAAc;","names":[]}