@12-apps/ui 6.39.15 → 6.39.17

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 (189) hide show
  1. package/dist/_internal/components/data-display/Avatar/Avatar.js +2 -2
  2. package/dist/_internal/components/data-display/Carousel/Carousel.js +3 -3
  3. package/dist/_internal/components/data-display/Chart/SpecChart.js +3 -3
  4. package/dist/_internal/components/data-display/DataViews/DataViewsGrid.js +14 -14
  5. package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +26 -25
  6. package/dist/_internal/components/data-display/DataViews/DeleteViewDialog.js +5 -4
  7. package/dist/_internal/components/data-display/DataViews/ManageViewsDialog.js +5 -4
  8. package/dist/_internal/components/data-display/DataViews/SaveViewModal.js +5 -4
  9. package/dist/_internal/components/data-display/DataViews/base-card.js +2 -2
  10. package/dist/_internal/components/data-display/DataViews/base-list-card-geometry.js +5 -5
  11. package/dist/_internal/components/data-display/DataViews/base-list-card-slots.js +4 -4
  12. package/dist/_internal/components/data-display/DataViews/base-list-card.js +7 -7
  13. package/dist/_internal/components/data-display/DataViews/data-views-display-panel.js +4 -4
  14. package/dist/_internal/components/data-display/DataViews/data-views-display-tabs.js +3 -3
  15. package/dist/_internal/components/data-display/DataViews/data-views-grid-bodies.js +4 -4
  16. package/dist/_internal/components/data-display/DataViews/data-views-grid-parts.js +13 -13
  17. package/dist/_internal/components/data-display/DataViews/data-views-layout-context.js +2 -2
  18. package/dist/_internal/components/data-display/DataViews/data-views-scope-tabs.js +3 -3
  19. package/dist/_internal/components/data-display/DataViews/data-views-shell-toolbar.js +6 -6
  20. package/dist/_internal/components/data-display/DataViews/data-views-table-parts.js +7 -6
  21. package/dist/_internal/components/data-display/DataViews/data-views-toolbar.js +5 -5
  22. package/dist/_internal/components/data-display/DataViews/list-card-rails.js +3 -3
  23. package/dist/_internal/components/data-display/DataViews/use-data-views-state.js +1 -1
  24. package/dist/_internal/components/data-display/DataViews/use-saved-views-controller.js +2 -2
  25. package/dist/_internal/components/data-display/FleetMap/FleetBody.js +11 -11
  26. package/dist/_internal/components/data-display/FleetMap/FleetCanvas.js +8 -8
  27. package/dist/_internal/components/data-display/FleetMap/FleetMap.js +12 -12
  28. package/dist/_internal/components/data-display/FleetMap/FleetRoster.js +2 -2
  29. package/dist/_internal/components/data-display/Lightbox/Lightbox.js +1 -1
  30. package/dist/_internal/components/data-display/MapPreview/MapDecorations.js +2 -2
  31. package/dist/_internal/components/data-display/MapPreview/MapPreview.hooks.js +2 -2
  32. package/dist/_internal/components/data-display/MapPreview/MapPreview.js +7 -7
  33. package/dist/_internal/components/data-display/MapPreview/MapTiles.js +2 -2
  34. package/dist/_internal/components/data-display/MapPreview/StaticMapView.js +4 -4
  35. package/dist/_internal/components/data-display/MapPreview/useMapPreview.js +3 -3
  36. package/dist/_internal/components/data-display/Progress/Progress.js +2 -2
  37. package/dist/_internal/components/data-display/Sheet/Sheet.js +3 -3
  38. package/dist/_internal/components/data-display/Table/Table.helpers.js +7 -1
  39. package/dist/_internal/components/data-display/Table/Table.hooks.js +1 -1
  40. package/dist/_internal/components/data-display/Table/Table.js +5 -5
  41. package/dist/_internal/components/data-display/Table/Table.styles.js +1 -1
  42. package/dist/_internal/components/data-display/Table/TableParts.hooks.js +2 -2
  43. package/dist/_internal/components/data-display/Table/TableParts.js +2 -2
  44. package/dist/_internal/components/data-display/index.js +39 -39
  45. package/dist/_internal/components/feedback/Dialog/Dialog.focus.js +10 -0
  46. package/dist/_internal/components/feedback/Dialog/Dialog.focus.js.map +1 -0
  47. package/dist/_internal/components/feedback/Dialog/Dialog.js +4 -3
  48. package/dist/_internal/components/feedback/Dialog/Dialog.slots.js +5 -3
  49. package/dist/_internal/components/feedback/Dialog/Dialog.styles.js +1 -1
  50. package/dist/_internal/components/feedback/index.js +4 -3
  51. package/dist/_internal/components/index.js +44 -43
  52. package/dist/_internal/components/navigation/AppHeader/AppHeader.details.js +8 -7
  53. package/dist/_internal/components/navigation/index.js +8 -7
  54. package/dist/_internal/user-avatar/user-avatar.js +3 -3
  55. package/dist/charts.js +11 -11
  56. package/dist/{chunk-V2UZQS2K.js → chunk-2622YFM6.js} +4 -4
  57. package/dist/{chunk-5QD6YGZ2.js → chunk-2OWKL4CC.js} +37 -30
  58. package/dist/chunk-2OWKL4CC.js.map +1 -0
  59. package/dist/{chunk-QSRZOXQI.js → chunk-2WVHZIWP.js} +2 -2
  60. package/dist/{chunk-P22W4N5K.js → chunk-37USSARD.js} +2 -2
  61. package/dist/{chunk-RSDYS5B3.js → chunk-4RPFI474.js} +6 -6
  62. package/dist/{chunk-SAOCDKNK.js → chunk-5JCGBCFJ.js} +4 -4
  63. package/dist/{chunk-3BNQDOHC.js → chunk-5OBGW3FG.js} +5 -5
  64. package/dist/{chunk-EMEXXAQI.js → chunk-66O55OZI.js} +6 -6
  65. package/dist/{chunk-SA65SDOY.js → chunk-A2TANYNR.js} +2 -2
  66. package/dist/{chunk-I5T5PQQW.js → chunk-BRM3T4LQ.js} +4 -4
  67. package/dist/{chunk-CCK7FB2V.js → chunk-BVHIKXCN.js} +8 -3
  68. package/dist/{chunk-CCK7FB2V.js.map → chunk-BVHIKXCN.js.map} +1 -1
  69. package/dist/{chunk-PG5C2AA4.js → chunk-DF4QODJ6.js} +2 -2
  70. package/dist/{chunk-ESCF5VMQ.js → chunk-DRSY37PB.js} +2 -2
  71. package/dist/{chunk-DYNJQ3HJ.js → chunk-FLDLUAHW.js} +2 -2
  72. package/dist/{chunk-OGB25P3N.js → chunk-HQZRI7UX.js} +2 -2
  73. package/dist/{chunk-HUPR5JXY.js → chunk-HWSS6C7C.js} +2 -2
  74. package/dist/{chunk-T3DNYPEA.js → chunk-I4MRBEWU.js} +12 -12
  75. package/dist/{chunk-HR7YTBR7.js → chunk-IASDP44E.js} +4 -4
  76. package/dist/{chunk-PX6TWS5T.js → chunk-IBGP3VSR.js} +2 -2
  77. package/dist/{chunk-5WT4YWXC.js → chunk-IRD45DRW.js} +2 -2
  78. package/dist/{chunk-ENRBXB6L.js → chunk-JK5UJM4Y.js} +3 -3
  79. package/dist/{chunk-5NT2M2JI.js → chunk-JKIKHWD2.js} +4 -4
  80. package/dist/{chunk-WVJGNIJZ.js → chunk-JYR6VV4Y.js} +3 -3
  81. package/dist/{chunk-5ETBB2DG.js → chunk-K5V6TCYB.js} +4 -4
  82. package/dist/{chunk-3IF3I3FI.js → chunk-KHPL2J3B.js} +2 -2
  83. package/dist/{chunk-AXKLCWFR.js → chunk-KN4ZE2XZ.js} +14 -14
  84. package/dist/{chunk-M3MHYE2M.js → chunk-L566FMDD.js} +4 -4
  85. package/dist/chunk-LV7LSPBF.js +35 -0
  86. package/dist/chunk-LV7LSPBF.js.map +1 -0
  87. package/dist/{chunk-HQWJUHR4.js → chunk-M4QXG5JP.js} +4 -4
  88. package/dist/{chunk-IFS3BRRL.js → chunk-MCJRHF7Z.js} +3 -3
  89. package/dist/{chunk-JGRBHNK6.js → chunk-ME3WYPYK.js} +2 -2
  90. package/dist/{chunk-GAMLBJE6.js → chunk-MQ277OLB.js} +14 -8
  91. package/dist/chunk-MQ277OLB.js.map +1 -0
  92. package/dist/{chunk-QXSV7Z57.js → chunk-MXCIUKTQ.js} +5 -5
  93. package/dist/{chunk-XS3REOPN.js → chunk-NHEWST3N.js} +12 -2
  94. package/dist/chunk-NHEWST3N.js.map +1 -0
  95. package/dist/{chunk-UBEAJFMW.js → chunk-O25SH2MA.js} +5 -5
  96. package/dist/{chunk-ARDLCGBK.js → chunk-O2DLEAUP.js} +3 -3
  97. package/dist/{chunk-LH7KMYHC.js → chunk-RZSMRBOX.js} +19 -2
  98. package/dist/chunk-RZSMRBOX.js.map +1 -0
  99. package/dist/{chunk-WCRGSMLV.js → chunk-SCZABICW.js} +3 -3
  100. package/dist/{chunk-2WU52FLP.js → chunk-ST7B54JN.js} +9 -4
  101. package/dist/chunk-ST7B54JN.js.map +1 -0
  102. package/dist/{chunk-LH46NYGR.js → chunk-TEEJ4GNY.js} +2 -2
  103. package/dist/{chunk-O4AHF45C.js → chunk-VY6L74JQ.js} +2 -2
  104. package/dist/{chunk-XZJM6EPC.js → chunk-YKEO6UHN.js} +4 -4
  105. package/dist/{chunk-WWGD5YVW.js → chunk-YTY7TD7S.js} +2 -2
  106. package/dist/{chunk-5HW37NSW.js → chunk-Z2JH5KW5.js} +16 -2
  107. package/dist/{chunk-5HW37NSW.js.map → chunk-Z2JH5KW5.js.map} +1 -1
  108. package/dist/{chunk-HMAPQV4C.js → chunk-ZWCYSAI5.js} +2 -2
  109. package/dist/data-display/Avatar.js +2 -2
  110. package/dist/data-display/Carousel.js +3 -3
  111. package/dist/data-display/Chart.js +11 -11
  112. package/dist/data-display/DataViews.js +34 -33
  113. package/dist/data-display/FleetMap.js +12 -12
  114. package/dist/data-display/Lightbox.js +1 -1
  115. package/dist/data-display/MapPreview.js +7 -7
  116. package/dist/data-display/Progress.js +2 -2
  117. package/dist/data-display/Sheet.js +3 -3
  118. package/dist/data-display/Table.js +5 -5
  119. package/dist/feedback/Dialog.js +4 -3
  120. package/dist/navigation/AppHeader.js +8 -7
  121. package/dist/types/components/data-display/Table/Table.d.ts.map +1 -1
  122. package/dist/types/components/data-display/Table/Table.helpers.d.ts +21 -3
  123. package/dist/types/components/data-display/Table/Table.helpers.d.ts.map +1 -1
  124. package/dist/types/components/data-display/Table/Table.hooks.d.ts +7 -3
  125. package/dist/types/components/data-display/Table/Table.hooks.d.ts.map +1 -1
  126. package/dist/types/components/data-display/Table/Table.styles.d.ts.map +1 -1
  127. package/dist/types/components/data-display/Table/Table.types.d.ts +5 -2
  128. package/dist/types/components/data-display/Table/Table.types.d.ts.map +1 -1
  129. package/dist/types/components/feedback/Dialog/Dialog.d.ts.map +1 -1
  130. package/dist/types/components/feedback/Dialog/Dialog.focus.d.ts +51 -0
  131. package/dist/types/components/feedback/Dialog/Dialog.focus.d.ts.map +1 -0
  132. package/dist/types/components/feedback/Dialog/Dialog.slots.d.ts +14 -0
  133. package/dist/types/components/feedback/Dialog/Dialog.slots.d.ts.map +1 -1
  134. package/dist/types/components/feedback/Dialog/Dialog.styles.d.ts.map +1 -1
  135. package/dist/user-avatar.js +3 -3
  136. package/package.json +1 -1
  137. package/src/components/data-display/Table/Table.helpers.ts +38 -4
  138. package/src/components/data-display/Table/Table.hooks.ts +40 -5
  139. package/src/components/data-display/Table/Table.md +9 -3
  140. package/src/components/data-display/Table/Table.styles.ts +8 -3
  141. package/src/components/data-display/Table/Table.tsx +9 -4
  142. package/src/components/data-display/Table/Table.types.ts +5 -2
  143. package/src/components/feedback/Dialog/Dialog.focus.ts +90 -0
  144. package/src/components/feedback/Dialog/Dialog.md +23 -3
  145. package/src/components/feedback/Dialog/Dialog.slots.ts +32 -0
  146. package/src/components/feedback/Dialog/Dialog.styles.ts +15 -0
  147. package/src/components/feedback/Dialog/Dialog.tsx +11 -3
  148. package/dist/chunk-2WU52FLP.js.map +0 -1
  149. package/dist/chunk-5QD6YGZ2.js.map +0 -1
  150. package/dist/chunk-GAMLBJE6.js.map +0 -1
  151. package/dist/chunk-LH7KMYHC.js.map +0 -1
  152. package/dist/chunk-XS3REOPN.js.map +0 -1
  153. /package/dist/{chunk-V2UZQS2K.js.map → chunk-2622YFM6.js.map} +0 -0
  154. /package/dist/{chunk-QSRZOXQI.js.map → chunk-2WVHZIWP.js.map} +0 -0
  155. /package/dist/{chunk-P22W4N5K.js.map → chunk-37USSARD.js.map} +0 -0
  156. /package/dist/{chunk-RSDYS5B3.js.map → chunk-4RPFI474.js.map} +0 -0
  157. /package/dist/{chunk-SAOCDKNK.js.map → chunk-5JCGBCFJ.js.map} +0 -0
  158. /package/dist/{chunk-3BNQDOHC.js.map → chunk-5OBGW3FG.js.map} +0 -0
  159. /package/dist/{chunk-EMEXXAQI.js.map → chunk-66O55OZI.js.map} +0 -0
  160. /package/dist/{chunk-SA65SDOY.js.map → chunk-A2TANYNR.js.map} +0 -0
  161. /package/dist/{chunk-I5T5PQQW.js.map → chunk-BRM3T4LQ.js.map} +0 -0
  162. /package/dist/{chunk-PG5C2AA4.js.map → chunk-DF4QODJ6.js.map} +0 -0
  163. /package/dist/{chunk-ESCF5VMQ.js.map → chunk-DRSY37PB.js.map} +0 -0
  164. /package/dist/{chunk-DYNJQ3HJ.js.map → chunk-FLDLUAHW.js.map} +0 -0
  165. /package/dist/{chunk-OGB25P3N.js.map → chunk-HQZRI7UX.js.map} +0 -0
  166. /package/dist/{chunk-HUPR5JXY.js.map → chunk-HWSS6C7C.js.map} +0 -0
  167. /package/dist/{chunk-T3DNYPEA.js.map → chunk-I4MRBEWU.js.map} +0 -0
  168. /package/dist/{chunk-HR7YTBR7.js.map → chunk-IASDP44E.js.map} +0 -0
  169. /package/dist/{chunk-PX6TWS5T.js.map → chunk-IBGP3VSR.js.map} +0 -0
  170. /package/dist/{chunk-5WT4YWXC.js.map → chunk-IRD45DRW.js.map} +0 -0
  171. /package/dist/{chunk-ENRBXB6L.js.map → chunk-JK5UJM4Y.js.map} +0 -0
  172. /package/dist/{chunk-5NT2M2JI.js.map → chunk-JKIKHWD2.js.map} +0 -0
  173. /package/dist/{chunk-WVJGNIJZ.js.map → chunk-JYR6VV4Y.js.map} +0 -0
  174. /package/dist/{chunk-5ETBB2DG.js.map → chunk-K5V6TCYB.js.map} +0 -0
  175. /package/dist/{chunk-3IF3I3FI.js.map → chunk-KHPL2J3B.js.map} +0 -0
  176. /package/dist/{chunk-AXKLCWFR.js.map → chunk-KN4ZE2XZ.js.map} +0 -0
  177. /package/dist/{chunk-M3MHYE2M.js.map → chunk-L566FMDD.js.map} +0 -0
  178. /package/dist/{chunk-HQWJUHR4.js.map → chunk-M4QXG5JP.js.map} +0 -0
  179. /package/dist/{chunk-IFS3BRRL.js.map → chunk-MCJRHF7Z.js.map} +0 -0
  180. /package/dist/{chunk-JGRBHNK6.js.map → chunk-ME3WYPYK.js.map} +0 -0
  181. /package/dist/{chunk-QXSV7Z57.js.map → chunk-MXCIUKTQ.js.map} +0 -0
  182. /package/dist/{chunk-UBEAJFMW.js.map → chunk-O25SH2MA.js.map} +0 -0
  183. /package/dist/{chunk-ARDLCGBK.js.map → chunk-O2DLEAUP.js.map} +0 -0
  184. /package/dist/{chunk-WCRGSMLV.js.map → chunk-SCZABICW.js.map} +0 -0
  185. /package/dist/{chunk-LH46NYGR.js.map → chunk-TEEJ4GNY.js.map} +0 -0
  186. /package/dist/{chunk-O4AHF45C.js.map → chunk-VY6L74JQ.js.map} +0 -0
  187. /package/dist/{chunk-XZJM6EPC.js.map → chunk-YKEO6UHN.js.map} +0 -0
  188. /package/dist/{chunk-WWGD5YVW.js.map → chunk-YTY7TD7S.js.map} +0 -0
  189. /package/dist/{chunk-HMAPQV4C.js.map → chunk-ZWCYSAI5.js.map} +0 -0
@@ -20,12 +20,46 @@ const scrollHeight = (theme: Theme, containerHeight: number | string | undefined
20
20
  };
21
21
 
22
22
  /**
23
- * The table's one scroll container (FUT-2658): `containerHeight` tall when
24
- * `virtualScrolling` is on, holding the header and the body. Inline, so the
25
- * height it was given reads back off the element.
23
+ * The table's one scroll container (FUT-2658): `containerHeight` tall
24
+ * whenever it is set, or 400 when `virtualScrolling` is on and it is not,
25
+ * holding the header and the body. `containerHeight` sizes the scroller with
26
+ * or without `virtualScrolling` (FUT-2677) — no consumer relies on the old
27
+ * virtual-only gate, and `stickyHeader` needs this box to stick inside.
28
+ * Inline, so the height it was given reads back off the element. A
29
+ * `containerHeight` of 0 counts as unset: a zero-height scroller shows nothing.
26
30
  */
27
31
  export const scrollerStyle = (theme: Theme, p: TableProps): React.CSSProperties | undefined =>
28
- p.virtualScrolling ? { height: scrollHeight(theme, p.containerHeight), overflow: 'auto' } : undefined;
32
+ p.virtualScrolling || p.containerHeight
33
+ ? { height: scrollHeight(theme, p.containerHeight), overflow: 'auto' }
34
+ : undefined;
35
+
36
+ /**
37
+ * With `stickyHeader`, the scroller takes over the rounded clip the `<table>`
38
+ * gives up (`tableStyles`, FUT-2677) — the caller's container owns it on the
39
+ * basic (children) path, and the loading/empty shells get it too, so their
40
+ * corners do not change between states.
41
+ */
42
+ export const scrollerRadiusStyle = (
43
+ theme: Theme,
44
+ stickyHeader: boolean | undefined,
45
+ ): React.CSSProperties | undefined => (stickyHeader ? { borderRadius: theme.spacing(1) } : undefined);
46
+
47
+ /** `scrollerStyle` and, with `stickyHeader`, the rounded clip it takes over. */
48
+ export const containerStyle = (theme: Theme, p: TableProps): React.CSSProperties | undefined => {
49
+ const scroller = scrollerStyle(theme, p);
50
+ const radius = scrollerRadiusStyle(theme, p.stickyHeader);
51
+ return scroller || radius ? { ...scroller, ...radius } : undefined;
52
+ };
53
+
54
+ /**
55
+ * Only a virtualised table needs its header measured — a plain one never
56
+ * reads `scroll.headerPx`, so it gets no `ResizeObserver` either (FUT-2678).
57
+ */
58
+ export const headerRefFor = (
59
+ windowHeight: number | undefined,
60
+ headRef: React.RefObject<globalThis.HTMLTableSectionElement | null>,
61
+ ): React.RefObject<globalThis.HTMLTableSectionElement | null> | undefined =>
62
+ windowHeight ? headRef : undefined;
29
63
 
30
64
  /**
31
65
  * The window's height in design px when the body is virtualised — only a
@@ -1,6 +1,11 @@
1
1
  import { useTheme } from '@mui/material/styles/index.js';
2
2
  import useMediaQuery from '@mui/material/useMediaQuery/index.js';
3
- import { useCallback, useEffect, useMemo, useState } from 'react';
3
+ import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react';
4
+
5
+ // A server render has no layout to measure, and React warns about
6
+ // `useLayoutEffect` there; the effect below only measures, so on the server
7
+ // it can be a plain (never-run) effect.
8
+ const useIsomorphicLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect;
4
9
 
5
10
  import { remPx } from '../../../tokens/relative';
6
11
 
@@ -14,9 +19,13 @@ import type { ColumnConfig, TableProps, VirtualWindow } from './Table.types';
14
19
  * pitch at any type scale.
15
20
  *
16
21
  * The scroller holds the header as well as the body, so the `<tbody>` starts
17
- * the header's height into it. `handleScroll` measures that height from
18
- * `headerRef` in the same live px as `scrollTop`, and the window subtracts it
19
- * before dividing by the pitch (FUT-2658).
22
+ * the header's height into it. That height is measured once after mount, and
23
+ * again from a `ResizeObserver` on `headerRef` whenever it changes —
24
+ * `handleScroll` also measures it on every scroll, so a scroll still carries
25
+ * the latest height, but nothing depends on that any more (FUT-2678: a
26
+ * resize with no scroll event used to leave the window off until the next
27
+ * one). The window subtracts the measured height before dividing by the pitch
28
+ * (FUT-2658).
20
29
  */
21
30
  export const useVirtualScrolling = (
22
31
  data: Record<string, unknown>[],
@@ -28,7 +37,33 @@ export const useVirtualScrolling = (
28
37
  const theme = useTheme();
29
38
  // Both live px, as the browser measures them.
30
39
  const [scroll, setScroll] = useState({ scrollTop: 0, headerPx: 0 });
31
-
40
+
41
+ const measureHeader = useCallback(() => {
42
+ setScroll((prev) => {
43
+ const headerPx = headerRef?.current?.offsetHeight ?? 0;
44
+ return headerPx === prev.headerPx ? prev : { ...prev, headerPx };
45
+ });
46
+ }, [headerRef]);
47
+
48
+ // Once after mount, so a header measured before any scroll or resize is
49
+ // still right the first time the window is drawn.
50
+ useIsomorphicLayoutEffect(() => {
51
+ measureHeader();
52
+ }, [measureHeader]);
53
+
54
+ // Then on every change the header makes on its own: a responsive column
55
+ // hidden or shown, a label wrapping at a new width, a web font loading, a
56
+ // `density` change. Where `ResizeObserver` is undefined, only the mount
57
+ // measurement above and `handleScroll` below still apply.
58
+ useEffect(() => {
59
+ const header = headerRef?.current;
60
+ if (!header || typeof ResizeObserver === 'undefined') return undefined;
61
+
62
+ const observer = new ResizeObserver(() => measureHeader());
63
+ observer.observe(header);
64
+ return () => observer.disconnect();
65
+ }, [headerRef, measureHeader]);
66
+
32
67
  const visibleItems = useMemo((): VirtualWindow => {
33
68
  const pitch = remPx(theme, rowHeight);
34
69
  const bodyScrollTop = Math.max(0, scroll.scrollTop - scroll.headerPx);
@@ -53,7 +53,7 @@ import { Table } from '@procurement/ui';
53
53
  - **selectable** `boolean` - Enable row selection
54
54
  - **selectedRows** `(string | number)[]` - Currently selected row IDs
55
55
  - **onSelectionChange** `(rows: (string | number)[]) => void` - Selection change handler
56
- - **stickyHeader** `boolean` - Keep header fixed when scrolling
56
+ - **stickyHeader** `boolean` - Keep header fixed when scrolling. Sticks inside the `containerHeight` scroller — set both together, or the header has nothing to stick within
57
57
  - **responsive** `boolean` - Enable responsive column hiding
58
58
  - **virtualScrolling** `boolean` - Enable virtual scrolling for large datasets
59
59
  - **loading** `boolean` - Show loading state
@@ -67,7 +67,7 @@ import { Table } from '@procurement/ui';
67
67
 
68
68
  ### Container Props
69
69
 
70
- - **containerHeight** `number` - Fixed height for scrollable container
70
+ - **containerHeight** `number | string` - Fixed height for the scrollable container, with or without `virtualScrolling` — a number is design px, a string is used as given (e.g. `'50vh'`)
71
71
  - **rowHeight** `number` - Height per row (for virtual scrolling)
72
72
  - **overscan** `number` - Number of rows to render outside viewport
73
73
 
@@ -246,4 +246,10 @@ const columns = [
246
246
  </TableBody>
247
247
  </Table>
248
248
  </TableContainer>
249
- ```
249
+ ```
250
+
251
+ On this path the caller supplies its own `TableContainer`, so the rounded clip
252
+ is the caller's. Without `stickyHeader` the `<table>` still rounds and clips
253
+ itself, as above; with `stickyHeader` the `<table>` does not, and the
254
+ caller's own container should carry the radius that used to be the
255
+ `<table>`'s (`theme.spacing(1)` at the default theme).
@@ -220,10 +220,15 @@ export const tableStyles = ({
220
220
  virtualised?: boolean;
221
221
  }): CSSObject => {
222
222
  const densityConfig = getDensityConfig(theme, density);
223
-
223
+
224
224
  return {
225
- borderRadius: theme.spacing(1),
226
- overflow: 'hidden',
225
+ // `overflow: hidden` makes the `<table>` a scroll container, which stops
226
+ // a `stickyHeader`'s `<thead>` sticking within it — a sticky element
227
+ // sticks within its nearest ancestor scroll container (FUT-2677). With
228
+ // `stickyHeader`, the rounded clip moves to the `TableContainer` instead
229
+ // (`containerStyle` and `scrollerRadiusStyle` in `Table.helpers.ts`), which already clips a
230
+ // scrolling table.
231
+ ...(stickyHeader ? {} : { borderRadius: theme.spacing(1), overflow: 'hidden' }),
227
232
  transition: 'all 0.3s ease',
228
233
  position: 'relative',
229
234
 
@@ -21,8 +21,10 @@ import type {
21
21
  TableStripeColor} from './Table.types';
22
22
  import {
23
23
  TABLE_DEFAULTS,
24
+ containerStyle,
24
25
  definedProps,
25
- scrollerStyle,
26
+ headerRefFor,
27
+ scrollerRadiusStyle,
26
28
  tableDomProps,
27
29
  tableRowHeight,
28
30
  virtualHeight,
@@ -84,7 +86,10 @@ const TableShell: React.FC<{
84
86
  header,
85
87
  rest,
86
88
  children }) => (
87
- <TableContainer>
89
+ // The loading and empty shells are not scrollers (no `containerHeight`), so
90
+ // they get only the rounded clip `stickyHeader` moves off the `<table>`,
91
+ // never a height (FUT-2677).
92
+ <TableContainer style={scrollerRadiusStyle(useTheme(), stickyHeader)}>
88
93
  <StyledTable
89
94
  ref={innerRef}
90
95
  customVariant={variant}
@@ -198,13 +203,13 @@ const AdvancedTable: React.FC<RendererProps> = ({ resolved: p, selection, innerR
198
203
  tableRowHeight(p.rowHeight) || 40,
199
204
  windowHeight ?? 400,
200
205
  p.overscan,
201
- headRef,
206
+ headerRefFor(windowHeight, headRef),
202
207
  );
203
208
 
204
209
  return (
205
210
  <Box position="relative">
206
211
  <TableContainer
207
- style={scrollerStyle(theme, p)}
212
+ style={containerStyle(theme, p)}
208
213
  onScroll={windowHeight ? handleScroll : undefined}
209
214
  >
210
215
  <StyledTable
@@ -229,8 +229,11 @@ export interface TableProps extends Omit<MuiTableProps, 'variant'> {
229
229
  showColumnToggle?: boolean;
230
230
 
231
231
  /**
232
- * Container height for virtual scrolling (default 400). A number is design
233
- * px, scaled with the theme's type scale; a string is used as given.
232
+ * The scroller's height — with or without `virtualScrolling` (FUT-2677).
233
+ * The 400 default applies only when `virtualScrolling` is on and this is
234
+ * unset; without it, no `containerHeight` means no height at all. A number
235
+ * is design px, scaled with the theme's type scale; a string is used as
236
+ * given.
234
237
  */
235
238
  containerHeight?: number | string;
236
239
 
@@ -0,0 +1,90 @@
1
+ /**
2
+ * WHERE INITIAL FOCUS LANDS WHEN A DIALOG OPENS (FUT-2696).
3
+ *
4
+ * MUI's `FocusTrap` focuses ITS OWN root when nothing inside already has
5
+ * focus (`FocusTrap.js`: `if (!rootRef.current.contains(doc.activeElement))
6
+ * … rootRef.current.focus()`). For `MuiDialog` that root is
7
+ * `.MuiDialog-container` — the `role="presentation"` wrapper the Transition
8
+ * clones its ref onto — which sits OUTSIDE the `role="dialog"` paper. A
9
+ * screen reader user landing there hears the page behind the dialog, not the
10
+ * dialog, and the first Tab does not start from the dialog's own controls.
11
+ *
12
+ * The WAI-ARIA APG dialog pattern wants focus INSIDE the dialog on open: the
13
+ * first tabbable descendant of the element carrying `role="dialog"`, or that
14
+ * element itself (given `tabIndex={-1}`, since it is not otherwise reachable
15
+ * by Tab) when it holds nothing focusable.
16
+ *
17
+ * `focusDialogOnEntered` is wired to `TransitionProps.onEntered` /
18
+ * `SlideProps.onEntered` on both renderers rather than to a mount effect,
19
+ * because it needs to run AFTER `FocusTrap`'s own mount effect has already
20
+ * had its turn — `onEntered` fires once the enter transition has finished,
21
+ * well after every mount effect has settled, so there is nothing left to
22
+ * race. A caller's own `autoFocus` on a field inside the dialog already wins
23
+ * against `FocusTrap` for the same reason `FocusTrap` documents: React's
24
+ * `autoFocus` runs synchronously during commit, before `FocusTrap`'s effect
25
+ * even checks whether focus is already inside its root — so by the time this
26
+ * runs, that field is already `contains()`-ed by the dialog and this backs
27
+ * off rather than moving focus away from it.
28
+ */
29
+
30
+ /**
31
+ * The candidate list `FocusTrap`'s own `defaultGetTabbable` uses
32
+ * (`@mui/material/Unstable_TrapFocus/FocusTrap.js`), so "first tabbable
33
+ * descendant" means the same thing here as it does to the trap that then
34
+ * keeps Tab cycling inside it. Like the trap, a match whose resolved
35
+ * `tabIndex` is -1 is skipped: `<button tabIndex={-1}>` is focusable but out
36
+ * of the Tab order, so it is not the first Tab stop.
37
+ */
38
+ const FOCUSABLE_SELECTOR = [
39
+ 'input:not([disabled]):not([type="hidden"])',
40
+ 'select:not([disabled])',
41
+ 'textarea:not([disabled])',
42
+ 'a[href]',
43
+ 'button:not([disabled])',
44
+ '[tabindex]:not([tabindex="-1"])',
45
+ 'audio[controls]',
46
+ 'video[controls]',
47
+ '[contenteditable]:not([contenteditable="false"])',
48
+ ].join(',');
49
+
50
+ /**
51
+ * Move focus into `target`: its first tabbable descendant, or `target`
52
+ * itself — given `tabIndex={-1}` if it does not already carry one, exactly as
53
+ * `FocusTrap` gives its own root — when nothing inside is focusable.
54
+ *
55
+ * Backs off when focus already sits on a DESCENDANT of `target` other than
56
+ * `target` itself: that is a caller's `autoFocus` (or an explicit `.focus()`
57
+ * of their own) that arrived before this ran, and it keeps winning. Focus
58
+ * already sitting ON `target` (as `FocusTrap` leaves it on the drawer's
59
+ * paper, which is its own trap root) is not a caller's choice, so it does
60
+ * not block a first-tabbable descendant from taking over.
61
+ */
62
+ export function focusFirstTabbable(target: HTMLElement): void {
63
+ const active = target.ownerDocument.activeElement;
64
+ if (active !== target && target.contains(active)) return;
65
+
66
+ const tabbable = Array.from(target.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)).find(
67
+ (element) => element.tabIndex >= 0,
68
+ );
69
+ if (tabbable) {
70
+ tabbable.focus();
71
+ return;
72
+ }
73
+ if (!target.hasAttribute('tabindex')) target.setAttribute('tabindex', '-1');
74
+ target.focus();
75
+ }
76
+
77
+ /**
78
+ * `node` is what the transition hands back: `.MuiDialog-container` for
79
+ * `ModalDialog` (the paper is a descendant, carrying `role="dialog"`), or the
80
+ * drawer's own paper directly for `DrawerDialog` (`Slide` wraps the paper with
81
+ * no intermediate container, and the paper carries no `role` at all — see
82
+ * `Dialog.md`). Either way, focus the `[role="dialog"]` descendant if there is
83
+ * one, else `node` itself.
84
+ */
85
+ export function focusDialogOnEntered(node: HTMLElement): void {
86
+ const dialog = node.getAttribute('role') === 'dialog'
87
+ ? node
88
+ : (node.querySelector<HTMLElement>('[role="dialog"]') ?? node);
89
+ focusFirstTabbable(dialog);
90
+ }
@@ -317,12 +317,32 @@ Slides in from the right side of the screen, similar to a side panel or drawer.
317
317
 
318
318
  The Dialog component implements comprehensive accessibility features:
319
319
 
320
- - **ARIA Roles**: Uses `role="dialog"` with proper ARIA attributes
320
+ - **ARIA Roles**: Uses `role="dialog"` with proper ARIA attributes (the `default`,
321
+ `glass` and `fullscreen` variants; the `drawer` variant does not — see below)
321
322
  - **ARIA Labels**: Proper labeling for title (`aria-labelledby`) and description (`aria-describedby`)
322
- - **Focus Management**:
323
+ - **Focus Management** (FUT-2696):
323
324
  - Focus is trapped within dialog when open
324
325
  - Focus returns to trigger element when closed
325
- - First focusable element receives focus on open
326
+ - On open, focus moves to the first tabbable descendant of the
327
+ `role="dialog"` paper — or, when the paper holds nothing focusable, to the
328
+ paper itself (`tabIndex={-1}`). This is NOT where MUI's own `FocusTrap`
329
+ would otherwise park it: left alone, `FocusTrap` focuses its root, which
330
+ for MUI's `Dialog` is `.MuiDialog-container` — the wrapper AROUND the
331
+ paper, and so outside the element a screen reader announces as the
332
+ dialog. `Dialog.tsx` corrects this itself, off `TransitionProps.onEntered`
333
+ (see `Dialog.focus.ts`), rather than relying on MUI's default.
334
+ - A caller's own `autoFocus` on a field inside the dialog keeps winning:
335
+ React applies it synchronously on mount, before `FocusTrap` or this fix
336
+ ever runs, so by the time either would move focus, it is already inside
337
+ the dialog and both back off.
338
+ - The `drawer` variant gets the same first-tabbable behaviour, but its
339
+ paper carries no `role="dialog"` — MUI's `Drawer` sets no `role` on it at
340
+ all, unlike `Dialog`'s paper — and there is no `.MuiDrawer-container`
341
+ wrapper either: `Slide` wraps the drawer's paper directly, so it IS
342
+ `FocusTrap`'s own root and was never reachable only from outside it the
343
+ way `.MuiDialog-container` was. The drawer therefore never had this bug;
344
+ the same fix on it only saves a caller an extra Tab press to reach the
345
+ panel's first control.
326
346
  - **Keyboard Navigation**:
327
347
  - `Escape` - Closes dialog (unless persistent mode is enabled)
328
348
  - `Tab` - Navigates between focusable elements
@@ -98,3 +98,35 @@ export function mergedBackdropSlot<O>(
98
98
  ): Slot<SlotValue, O> {
99
99
  return mergedSlot(look, legacy, slot);
100
100
  }
101
+
102
+ /** What the transition slot's `onEntered` looks like on either renderer. */
103
+ interface TransitionSlotValue {
104
+ onEntered?: (node: HTMLElement, isAppearing: boolean) => void;
105
+ }
106
+
107
+ /**
108
+ * The transition slot: `onFocusEntered` (initial-focus, FUT-2696) runs
109
+ * first, then the deprecated `TransitionProps`/`SlideProps`, then
110
+ * `slotProps.transition` — so a caller's own `onEntered` still runs, and
111
+ * still runs last, meaning it can move focus again if it wants to.
112
+ *
113
+ * No `sx`/`look` here: unlike the paper and the backdrop, the transition slot
114
+ * carries no visual look of the Dialog's own to merge under a caller's.
115
+ */
116
+ export function mergedTransitionSlot<O>(
117
+ onFocusEntered: (node: HTMLElement, isAppearing: boolean) => void,
118
+ legacy: TransitionSlotValue | undefined,
119
+ slot: Slot<TransitionSlotValue, O> | undefined,
120
+ ): Slot<TransitionSlotValue, O> {
121
+ const compose = (merged: TransitionSlotValue): TransitionSlotValue => ({
122
+ ...merged,
123
+ onEntered: (node: HTMLElement, isAppearing: boolean) => {
124
+ onFocusEntered(node, isAppearing);
125
+ merged.onEntered?.(node, isAppearing);
126
+ },
127
+ });
128
+ if (typeof slot === 'function') {
129
+ return (ownerState: O) => compose({ ...legacy, ...slot(ownerState) });
130
+ }
131
+ return compose({ ...legacy, ...slot });
132
+ }
@@ -125,6 +125,17 @@ function defaultVariantStyles(theme: Theme, opts: VariantStyleOptions) {
125
125
  };
126
126
  }
127
127
 
128
+ /**
129
+ * The paper never grows an outline of its own — same as `.MuiDialog-container`
130
+ * (`outline: 0`, unconditionally, in MUI's own `Dialog.js`). It matters once
131
+ * `focusDialogOnEntered` (FUT-2696) falls back to focusing the paper itself: a
132
+ * browser's default `:focus`/`:focus-visible` ring is drawn OUTSIDE the box
133
+ * model — it never resizes a box or shifts a sibling — but this keeps the
134
+ * paper visually identical whether or not that fallback ever fires, rather
135
+ * than relying on that guarantee.
136
+ */
137
+ const NO_FOCUS_OUTLINE = { outline: 0 } as const;
138
+
128
139
  export function variantStylesOf(theme: Theme, opts: VariantStyleOptions): SxProps<Theme> {
129
140
  const decorations = {
130
141
  ...glowStylesOf(theme, opts.glow),
@@ -135,6 +146,7 @@ export function variantStylesOf(theme: Theme, opts: VariantStyleOptions): SxProp
135
146
  return {
136
147
  ...baseStylesOf(theme, opts),
137
148
  ...decorations,
149
+ ...NO_FOCUS_OUTLINE,
138
150
  backgroundColor: alpha(theme.palette.background.paper, DIALOG_GLASS.backgroundAlpha),
139
151
  backdropFilter: `blur(${rem(theme, DIALOG_GLASS.blurPx)})`,
140
152
  border: `${DIALOG_BORDER_WIDTH}px solid ${alpha(theme.palette.primary.main, DIALOG_GLASS.borderAlpha)}`,
@@ -150,6 +162,7 @@ export function variantStylesOf(theme: Theme, opts: VariantStyleOptions): SxProp
150
162
  maxWidth: 'none',
151
163
  maxHeight: 'none',
152
164
  ...decorations,
165
+ ...NO_FOCUS_OUTLINE,
153
166
  };
154
167
  case 'drawer': {
155
168
  const radius = borderRadiusOf(theme, opts.borderRadius);
@@ -166,6 +179,7 @@ export function variantStylesOf(theme: Theme, opts: VariantStyleOptions): SxProp
166
179
  ...dynamicViewportHeight('height'),
167
180
  maxHeight: 'none',
168
181
  ...decorations,
182
+ ...NO_FOCUS_OUTLINE,
169
183
  };
170
184
  }
171
185
  default:
@@ -173,6 +187,7 @@ export function variantStylesOf(theme: Theme, opts: VariantStyleOptions): SxProp
173
187
  ...baseStylesOf(theme, opts),
174
188
  ...decorations,
175
189
  ...defaultVariantStyles(theme, opts),
190
+ ...NO_FOCUS_OUTLINE,
176
191
  };
177
192
  }
178
193
  }
@@ -11,6 +11,7 @@ import Typography from '@mui/material/Typography/index.js';
11
11
  import { useTheme, type SxProps, type Theme } from '@mui/material/styles/index.js';
12
12
  import React from 'react';
13
13
 
14
+ import { focusDialogOnEntered } from './Dialog.focus';
14
15
  import { hasSpacingSlot, withDialogDefaults } from './Dialog.helpers';
15
16
  import {
16
17
  DIALOG_ACTIONS,
@@ -20,7 +21,7 @@ import {
20
21
  DIALOG_TITLE,
21
22
  DIALOG_TITLED_BODY_PADDING_TOP_UNITS,
22
23
  } from './Dialog.metrics';
23
- import { mergedBackdropSlot, mergedPaperSlot } from './Dialog.slots';
24
+ import { mergedBackdropSlot, mergedPaperSlot, mergedTransitionSlot } from './Dialog.slots';
24
25
  import { backdropSxOf, variantStylesOf } from './Dialog.styles';
25
26
  import { childTestId, resolveTestId, slotTestId, withoutTestIdProps } from '../../../platform/test-id';
26
27
  import type {
@@ -106,6 +107,8 @@ type RendererProps = DialogLooks & { children: React.ReactNode };
106
107
  * `slotProps.backdrop`, not the deprecated `BackdropProps`, and a caller's
107
108
  * backdrop props from either spelling merge over it rather than replacing it
108
109
  * (FUT-2672) — as their paper props merge over the variant's look (FUT-2613).
110
+ * `slotProps.transition` gives initial focus to the paper (FUT-2696, see
111
+ * `Dialog.focus.ts` and `Dialog.md`) ahead of a caller's own `onEntered`.
109
112
  */
110
113
  function ModalDialog({
111
114
  paperSx,
@@ -114,7 +117,7 @@ function ModalDialog({
114
117
  dialogProps,
115
118
  children,
116
119
  }: RendererProps & { dialogProps: MuiDialogProps }) {
117
- const { PaperProps: callerPaper, BackdropProps: callerBackdrop, slotProps, ...rest } = dialogProps;
120
+ const { PaperProps: callerPaper, BackdropProps: callerBackdrop, TransitionProps: callerTransition, slotProps, ...rest } = dialogProps;
118
121
  return (
119
122
  <MuiDialog
120
123
  {...rest}
@@ -122,6 +125,7 @@ function ModalDialog({
122
125
  ...slotProps,
123
126
  paper: mergedPaperSlot(paperSx, testId, callerPaper, slotProps?.paper),
124
127
  backdrop: mergedBackdropSlot(backdropSx, callerBackdrop, slotProps?.backdrop),
128
+ transition: mergedTransitionSlot(focusDialogOnEntered, callerTransition, slotProps?.transition),
125
129
  }}
126
130
  >
127
131
  {children}
@@ -139,6 +143,9 @@ function ModalDialog({
139
143
  * `glass` blurs it here too; the paper does not frost (FUT-2673). MUI's
140
144
  * `Drawer` does not merge `BackdropProps` into `slotProps.backdrop` — it takes
141
145
  * one or the other — so both are folded into the one slot here.
146
+ * `slotProps.transition` gives initial focus the same way `ModalDialog` does
147
+ * (FUT-2696, see `Dialog.focus.ts` and `Dialog.md` for why the drawer's paper
148
+ * differs from the modal's paper here and needed the fix less).
142
149
  */
143
150
  function DrawerDialog({
144
151
  paperSx,
@@ -147,7 +154,7 @@ function DrawerDialog({
147
154
  drawerProps,
148
155
  children,
149
156
  }: RendererProps & { drawerProps: DrawerProps }) {
150
- const { PaperProps: callerPaper, BackdropProps: callerBackdrop, slotProps, ...rest } = drawerProps;
157
+ const { PaperProps: callerPaper, BackdropProps: callerBackdrop, SlideProps: callerTransition, slotProps, ...rest } = drawerProps;
151
158
  return (
152
159
  <Drawer
153
160
  anchor="right"
@@ -157,6 +164,7 @@ function DrawerDialog({
157
164
  ...slotProps,
158
165
  paper: mergedPaperSlot(paperSx, undefined, callerPaper, slotProps?.paper),
159
166
  backdrop: mergedBackdropSlot(backdropSx, callerBackdrop, slotProps?.backdrop),
167
+ transition: mergedTransitionSlot(focusDialogOnEntered, callerTransition, slotProps?.transition),
160
168
  }}
161
169
  >
162
170
  {children}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/feedback/Dialog/Dialog.styles.ts"],"sourcesContent":["import type { SxProps, Theme } from '@mui/material/styles/index.js';\nimport { alpha, keyframes } from '@mui/material/styles/index.js';\n\nimport type { DialogBorderRadius, DialogSize, DialogVariant } from './Dialog.base';\nimport {\n DIALOG_BACKDROP,\n DIALOG_BORDER_WIDTH,\n DIALOG_GLASS,\n DIALOG_GLOW,\n DIALOG_GRADIENT,\n DIALOG_MARGIN_UNITS,\n DIALOG_MAX_WIDTH,\n DIALOG_PULSE,\n DIALOG_RADIUS_UNITS,\n DIALOG_WIDTH_PERCENT,\n} from './Dialog.metrics';\nimport { scrim, shadowInk } from '../../../tokens/ink';\nimport { rem, rems } from '../../../tokens/relative';\nimport { dynamicViewportHeight } from '../../../utils/viewport';\n\n/**\n * Paper/backdrop styling for the Dialog component (FUT-181 gate cleanup):\n * pure helpers so `Dialog.tsx` stays within the size/complexity budget.\n *\n * Every number comes from `Dialog.metrics.ts`, which the native renderer reads\n * too — so a paper cannot be 800px wide on one side and 780 on the other.\n */\n\n// Define pulse animation — a function of the theme so the ring's spread follows the type scale.\nconst pulseAnimation = (theme: Theme) => keyframes`\n 0% {\n box-shadow: 0 0 0 0 currentColor;\n opacity: 1;\n }\n 70% {\n box-shadow: 0 0 0 ${rem(theme, DIALOG_PULSE.spread)} currentColor;\n opacity: 0;\n }\n 100% {\n box-shadow: 0 0 0 0 currentColor;\n opacity: 0;\n }\n`;\n\n/** Style toggles that shape the dialog paper (extracted so each fn stays small). */\ninterface VariantStyleOptions {\n variant: DialogVariant;\n size: DialogSize;\n borderRadius: DialogBorderRadius;\n glass: boolean;\n gradient: boolean;\n glow: boolean;\n pulse: boolean;\n}\n\nfunction borderRadiusOf(theme: Theme, borderRadius: VariantStyleOptions['borderRadius']) {\n const units = DIALOG_RADIUS_UNITS[borderRadius] ?? DIALOG_RADIUS_UNITS.lg;\n // `none` is a bare 0 rather than `spacing(0)`, as this has always written it.\n return units === 0 ? '0' : theme.spacing(units);\n}\n\nfunction maxWidthOf(theme: Theme, size: VariantStyleOptions['size']): string {\n return rem(theme, DIALOG_MAX_WIDTH[size] ?? DIALOG_MAX_WIDTH.md);\n}\n\nfunction baseStylesOf(theme: Theme, opts: VariantStyleOptions) {\n return {\n borderRadius: borderRadiusOf(theme, opts.borderRadius),\n maxWidth: maxWidthOf(theme, opts.size),\n width: `${DIALOG_WIDTH_PERCENT}vw`,\n margin: theme.spacing(DIALOG_MARGIN_UNITS),\n transition: theme.transitions.create(\n ['box-shadow', 'background-color', 'backdrop-filter'],\n { duration: theme.transitions.duration.standard },\n ),\n };\n}\n\nfunction glowStylesOf(theme: Theme, glow: boolean) {\n return glow\n ? {\n boxShadow: `${rems(theme, 0, 0, DIALOG_GLOW.blurRadius)} ${alpha(theme.palette.primary.main, DIALOG_GLOW.alpha)}`,\n }\n : {};\n}\n\nfunction pulseStylesOf(theme: Theme, pulse: boolean) {\n if (!pulse) return {};\n return {\n position: 'relative' as const,\n '&::after': {\n content: '\"\"',\n position: 'absolute' as const,\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n borderRadius: 'inherit',\n backgroundColor: theme.palette.primary.main,\n opacity: DIALOG_PULSE.alpha,\n animation: `${pulseAnimation(theme)} ${DIALOG_PULSE.durationMs / 1000}s infinite`,\n pointerEvents: 'none' as const,\n zIndex: DIALOG_PULSE.zIndex,\n },\n };\n}\n\n/** The default variant's paper: optional gradient/glass over the base styles. */\nfunction defaultVariantStyles(theme: Theme, opts: VariantStyleOptions) {\n const gradientStyles = opts.gradient\n ? {\n background: `linear-gradient(${DIALOG_GRADIENT.angleDeg}deg, ${alpha(theme.palette.primary.main, DIALOG_GRADIENT.stopAlpha)}, ${alpha(theme.palette.secondary.main, DIALOG_GRADIENT.stopAlpha)})`,\n backdropFilter: `blur(${rem(theme, DIALOG_GRADIENT.blurPx)})`,\n }\n : {};\n return {\n ...gradientStyles,\n backgroundColor: opts.glass\n ? alpha(theme.palette.background.paper, DIALOG_GLASS.backgroundAlpha)\n : theme.palette.background.paper,\n backdropFilter: opts.glass ? `blur(${rem(theme, DIALOG_GLASS.blurPx)})` : 'none',\n border: opts.glass\n ? `${DIALOG_BORDER_WIDTH}px solid ${alpha(theme.palette.primary.main, DIALOG_GLASS.borderAlpha)}`\n : 'none',\n };\n}\n\nexport function variantStylesOf(theme: Theme, opts: VariantStyleOptions): SxProps<Theme> {\n const decorations = {\n ...glowStylesOf(theme, opts.glow),\n ...pulseStylesOf(theme, opts.pulse),\n };\n switch (opts.variant) {\n case 'glass':\n return {\n ...baseStylesOf(theme, opts),\n ...decorations,\n backgroundColor: alpha(theme.palette.background.paper, DIALOG_GLASS.backgroundAlpha),\n backdropFilter: `blur(${rem(theme, DIALOG_GLASS.blurPx)})`,\n border: `${DIALOG_BORDER_WIDTH}px solid ${alpha(theme.palette.primary.main, DIALOG_GLASS.borderAlpha)}`,\n boxShadow: `${rems(theme, 0, DIALOG_GLASS.shadow.offsetY, DIALOG_GLASS.shadow.blurRadius)} ${shadowInk(theme, DIALOG_GLASS.shadow.alpha)}`,\n };\n case 'fullscreen':\n return {\n borderRadius: 0,\n margin: 0,\n width: '100vw',\n // `100dvh`, not `100vh` — see `dynamicViewportHeight`.\n ...dynamicViewportHeight('height'),\n maxWidth: 'none',\n maxHeight: 'none',\n ...decorations,\n };\n case 'drawer': {\n const radius = borderRadiusOf(theme, opts.borderRadius);\n return {\n // `radius` is already a length (`theme.spacing(n)` → '16px', or 0): gluing\n // another `px` on wrote '16pxpx', which the browser dropped, leaving the\n // panel's leading corners square.\n borderRadius: `${radius} 0 0 ${radius}`,\n margin: 0,\n width: maxWidthOf(theme, opts.size),\n // Never wider than the screen: a 600px panel on a 375px phone put its\n // title and the start of every line off the left edge.\n maxWidth: '100%',\n ...dynamicViewportHeight('height'),\n maxHeight: 'none',\n ...decorations,\n };\n }\n default:\n return {\n ...baseStylesOf(theme, opts),\n ...decorations,\n ...defaultVariantStyles(theme, opts),\n };\n }\n}\n\nexport function backdropSxOf(theme: Theme, glass: boolean) {\n return {\n backgroundColor: scrim(theme, glass ? DIALOG_BACKDROP.alpha.glass : DIALOG_BACKDROP.alpha.plain),\n backdropFilter: glass ? `blur(${rem(theme, DIALOG_BACKDROP.blurPx)})` : 'none',\n };\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/data-display/Table/Table.tsx"],"sourcesContent":["import MoreVertIcon from '@mui/icons-material/MoreVert';\nimport Box from '@mui/material/Box/index.js';\nimport FormControlLabel from '@mui/material/FormControlLabel/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 Skeleton from '@mui/material/Skeleton/index.js';\nimport Switch from '@mui/material/Switch/index.js';\nimport MuiTable from '@mui/material/Table/index.js';\nimport TableBody from '@mui/material/TableBody/index.js';\nimport TableCell from '@mui/material/TableCell/index.js';\nimport TableContainer from '@mui/material/TableContainer/index.js';\nimport TableRow from '@mui/material/TableRow/index.js';\nimport { styled, useTheme } from '@mui/material/styles/index.js';\nimport React from 'react';\n\nimport type {\n ColumnConfig,\n TableDensity,\n TableProps,\n TableStripeColor} from './Table.types';\nimport {\n TABLE_DEFAULTS,\n definedProps,\n scrollerStyle,\n tableDomProps,\n tableRowHeight,\n virtualHeight,\n} from './Table.helpers';\nimport { useTableSelection, useVirtualScrolling } from './Table.hooks';\nimport { EnhancedTableBody, EnhancedTableHeader } from './TableParts';\nimport { EmptyRow, NoDataPlaceholder } from './TableStates';\nimport {\n tableStyles } from './Table.styles';\nimport { rem } from '../../../tokens/relative';\n\n// Helper function to get stripe color from theme\nconst StyledTable = styled(MuiTable, {\n shouldForwardProp: (prop) =>\n !['customVariant', 'glow', 'pulse', 'hoverable', 'density', 'stickyHeader', 'stripeColor', 'virtualised'].includes(prop as string) })<{\n customVariant?: string;\n glow?: boolean;\n pulse?: boolean;\n hoverable?: boolean;\n density?: TableDensity;\n stickyHeader?: boolean;\n stripeColor?: TableStripeColor;\n virtualised?: boolean;\n}>(({ theme, customVariant, glow, pulse, hoverable, density, stickyHeader, stripeColor = 'neutral', virtualised }) => {\n return tableStyles({\n theme,\n customVariant,\n glow,\n pulse,\n hoverable,\n density,\n stickyHeader,\n stripeColor,\n virtualised });\n});\n\n// Virtual Scrolling Hook\nconst TableShell: React.FC<{\n innerRef: React.Ref<globalThis.HTMLTableElement>;\n variant?: string;\n stripeColor?: TableStripeColor;\n glow?: boolean;\n pulse?: boolean;\n hoverable?: boolean;\n density?: TableDensity;\n stickyHeader?: boolean;\n header: React.ReactNode;\n rest: Record<string, unknown>;\n children: React.ReactNode;\n}> = ({\n innerRef,\n variant,\n stripeColor,\n glow,\n pulse,\n hoverable,\n density,\n stickyHeader,\n header,\n rest,\n children }) => (\n <TableContainer>\n <StyledTable\n ref={innerRef}\n customVariant={variant}\n stripeColor={stripeColor}\n glow={glow}\n pulse={pulse}\n hoverable={hoverable}\n density={density}\n stickyHeader={stickyHeader}\n {...rest}\n >\n {header}\n {children}\n </StyledTable>\n </TableContainer>\n);\n\nconst SKELETON_ROW_COUNT = 5;\n\nconst LoadingSkeletonRows: React.FC<{ columns?: ColumnConfig[] }> = ({ columns }) => {\n const theme = useTheme();\n return (\n <>\n {Array.from({ length: SKELETON_ROW_COUNT }, (_, index) => (\n <TableRow key={index}>\n {columns?.map((column) => (\n <TableCell key={column.key}>\n <Skeleton height={rem(theme, 20)} />\n </TableCell>\n ))}\n </TableRow>\n ))}\n </>\n );\n};\n\nexport type TableShellProps = Omit<React.ComponentProps<typeof TableShell>, 'children'>;\n\ntype Selection = ReturnType<typeof useTableSelection>;\n\ninterface RendererProps {\n resolved: TableProps;\n selection: Selection;\n innerRef: React.Ref<globalThis.HTMLTableElement>;\n rest: Record<string, unknown>;\n}\n\n// The column-visibility control, shown only when responsive mode has actually\n// hidden something on a narrow viewport.\nconst ColumnToggleMenu: React.FC<{\n columns: ColumnConfig[];\n hiddenColumns: number[];\n anchor: HTMLElement | null;\n setAnchor: (element: HTMLElement | null) => void;\n setHiddenColumns: (next: number[]) => void;\n}> = ({ columns, hiddenColumns, anchor, setAnchor, setHiddenColumns }) => (\n <Box position=\"absolute\" top={8} right={8}>\n <IconButton onClick={(event) => setAnchor(event.currentTarget)} size=\"small\">\n <MoreVertIcon />\n </IconButton>\n <Menu anchorEl={anchor} open={Boolean(anchor)} onClose={() => setAnchor(null)}>\n {columns.map((column, index) => (\n <MenuItem key={column.key}>\n <FormControlLabel\n control={\n <Switch\n checked={!hiddenColumns.includes(index)}\n onChange={(event) =>\n setHiddenColumns(\n event.target.checked\n ? hiddenColumns.filter((i: number) => i !== index)\n : [...hiddenColumns, index],\n )\n }\n size=\"small\"\n />\n }\n label={column.label}\n />\n </MenuItem>\n ))}\n </Menu>\n </Box>\n);\n\n// The populated table. Local because StyledTable cannot cross a module\n// boundary (TS2742).\nconst columnsFor = (resolved: TableProps, selection: Selection): ColumnConfig[] =>\n (resolved.responsive ? selection.visibleColumns : resolved.columns) ?? [];\n\n// The toggle only earns its place when responsive mode has actually hidden\n// something on a narrow viewport.\nconst showsColumnToggle = (resolved: TableProps, selection: Selection): boolean =>\n Boolean(\n resolved.responsive &&\n selection.isMobile &&\n resolved.showColumnToggle &&\n selection.hiddenColumns.length > 0,\n );\n\n// The virtual window lives here, with the one scroller whose offset drives it;\n// the header's ref lets it subtract the height the `<thead>` pushes the body down.\nconst AdvancedTable: React.FC<RendererProps> = ({ resolved: p, selection, innerRef, rest }) => {\n const theme = useTheme();\n const finalColumns = columnsFor(p, selection);\n const showToggle = showsColumnToggle(p, selection);\n const headRef = React.useRef<globalThis.HTMLTableSectionElement>(null);\n const windowHeight = virtualHeight(p);\n const { visibleItems, handleScroll } = useVirtualScrolling(\n p.data ?? [],\n tableRowHeight(p.rowHeight) || 40,\n windowHeight ?? 400,\n p.overscan,\n headRef,\n );\n\n return (\n <Box position=\"relative\">\n <TableContainer\n style={scrollerStyle(theme, p)}\n onScroll={windowHeight ? handleScroll : undefined}\n >\n <StyledTable\n ref={innerRef}\n customVariant={p.variant}\n stripeColor={p.stripeColor}\n glow={p.glow}\n pulse={p.pulse}\n hoverable={p.hoverable}\n density={p.density}\n stickyHeader={p.stickyHeader}\n virtualised={Boolean(windowHeight)}\n {...rest}\n >\n <EnhancedTableHeader\n columns={finalColumns}\n data={p.data ?? []}\n sortable={p.sortable}\n sortConfig={p.sortConfig}\n onSortChange={p.onSortChange}\n selectable={p.selectable}\n selectedRows={p.selectedRows}\n onSelectAll={selection.handleSelectAll}\n density={p.density}\n stickyHeader={p.stickyHeader}\n headRef={headRef}\n />\n <EnhancedTableBody\n data={p.data ?? []}\n columns={finalColumns}\n selectedRows={p.selectedRows}\n onRowClick={p.onRowClick}\n onRowFocus={p.onRowFocus}\n onRowBlur={p.onRowBlur}\n onSelectionChange={selection.handleSelectionChange}\n rowKeyExtractor={p.rowKeyExtractor}\n density={p.density}\n selectable={p.selectable}\n hoverable={p.hoverable}\n renderRow={p.renderRow}\n renderCell={p.renderCell}\n virtualWindow={windowHeight ? visibleItems : undefined}\n rowHeight={p.rowHeight}\n />\n </StyledTable>\n </TableContainer>\n\n {showToggle && (\n <ColumnToggleMenu\n columns={p.columns ?? []}\n hiddenColumns={selection.hiddenColumns}\n anchor={selection.columnMenuAnchor}\n setAnchor={selection.setColumnMenuAnchor}\n setHiddenColumns={selection.setHiddenColumns}\n />\n )}\n </Box>\n );\n};\n\n// The loading and empty states render the same shell as the populated table, so\n// they share TableShell rather than repeating it three times.\nconst buildShell = ({\n resolved,\n selection,\n innerRef,\n rest,\n finalColumns }: RendererProps & { finalColumns?: ColumnConfig[] }) => ({\n innerRef,\n variant: resolved.variant,\n stripeColor: resolved.stripeColor,\n glow: resolved.glow,\n pulse: resolved.pulse,\n hoverable: resolved.hoverable,\n density: resolved.density,\n stickyHeader: resolved.stickyHeader,\n header: resolved.columns ? (\n <EnhancedTableHeader\n columns={finalColumns ?? []}\n data={[]}\n sortable={resolved.sortable}\n sortConfig={resolved.sortConfig}\n onSortChange={resolved.onSortChange}\n selectable={resolved.selectable}\n selectedRows={resolved.selectedRows}\n onSelectAll={selection.handleSelectAll}\n density={resolved.density}\n stickyHeader={resolved.stickyHeader}\n />\n ) : null,\n rest: rest as Record<string, unknown> });\n\nconst TableLoadingState: React.FC<{\n shell: TableShellProps;\n loadingComponent?: React.ReactNode;\n columns?: ColumnConfig[];\n}> = ({ shell, loadingComponent, columns }) => (\n <TableShell {...shell}>\n <TableBody data-testid=\"table-loading\">\n {loadingComponent || <LoadingSkeletonRows columns={columns} />}\n </TableBody>\n </TableShell>\n);\n\nconst TableEmptyState: React.FC<{\n shell: TableShellProps;\n emptyStateComponent?: React.ReactNode;\n emptyText: string;\n colSpan: number;\n}> = ({ shell, emptyStateComponent, emptyText, colSpan }) => (\n <TableShell {...shell}>\n <EmptyRow colSpan={colSpan}>\n {emptyStateComponent || <NoDataPlaceholder emptyText={emptyText} />}\n </EmptyRow>\n </TableShell>\n);\n\nexport const Table = React.forwardRef<globalThis.HTMLTableElement, TableProps>(\n (tableProps, ref) => {\n const resolved = { ...TABLE_DEFAULTS, ...definedProps(tableProps) } as TableProps;\n const {\n columns,\n data,\n responsive,\n loading,\n loadingComponent,\n emptyStateComponent,\n emptyText,\n children,\n } = resolved;\n\n const selection = useTableSelection({\n columns,\n data,\n responsive,\n columnPriorities: resolved.columnPriorities,\n selectedRows: resolved.selectedRows ?? [],\n rowKeyExtractor: resolved.rowKeyExtractor,\n onSelectionChange: resolved.onSelectionChange });\n\n // Only MUI's and the DOM's own props reach the `<table>` (FUT-2658).\n const rest = tableDomProps(tableProps);\n const renderer: RendererProps = { resolved, selection, innerRef: ref, rest };\n const finalColumns = responsive ? selection.visibleColumns : columns;\n const shell = buildShell({ ...renderer, finalColumns });\n\n if (loading) {\n return (\n <TableLoadingState shell={shell} loadingComponent={loadingComponent} columns={columns} />\n );\n }\n\n if (data && data.length === 0) {\n return (\n <TableEmptyState\n shell={shell}\n emptyStateComponent={emptyStateComponent}\n emptyText={emptyText}\n colSpan={finalColumns?.length || 1}\n />\n );\n }\n\n if (columns && data) return <AdvancedTable {...renderer} />;\n\n // Basic table (backward compatibility)\n return (\n <StyledTable\n ref={ref}\n customVariant={resolved.variant}\n stripeColor={resolved.stripeColor}\n glow={resolved.glow}\n pulse={resolved.pulse}\n hoverable={resolved.hoverable}\n density={resolved.density}\n stickyHeader={resolved.stickyHeader}\n {...rest}\n >\n {children}\n </StyledTable>\n );\n },\n);\n\nTable.displayName = 'Table';"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/feedback/Dialog/Dialog.tsx"],"sourcesContent":["import CloseIcon from '@mui/icons-material/Close';\nimport Backdrop from '@mui/material/Backdrop/index.js';\nimport Box from '@mui/material/Box/index.js';\nimport MuiDialog, { type DialogProps as MuiDialogProps } from '@mui/material/Dialog/index.js';\nimport MuiDialogActions from '@mui/material/DialogActions/index.js';\nimport MuiDialogContent from '@mui/material/DialogContent/index.js';\nimport MuiDialogTitle from '@mui/material/DialogTitle/index.js';\nimport Drawer, { type DrawerProps } from '@mui/material/Drawer/index.js';\nimport IconButton from '@mui/material/IconButton/index.js';\nimport Typography from '@mui/material/Typography/index.js';\nimport { useTheme, type SxProps, type Theme } from '@mui/material/styles/index.js';\nimport React from 'react';\n\nimport { hasSpacingSlot, withDialogDefaults } from './Dialog.helpers';\nimport {\n DIALOG_ACTIONS,\n DIALOG_BODY_PADDING_UNITS,\n DIALOG_CONTENT_PADDING_UNITS,\n DIALOG_HEADER_CHILDREN_PADDING_UNITS,\n DIALOG_TITLE,\n DIALOG_TITLED_BODY_PADDING_TOP_UNITS,\n} from './Dialog.metrics';\nimport { mergedBackdropSlot, mergedPaperSlot } from './Dialog.slots';\nimport { backdropSxOf, variantStylesOf } from './Dialog.styles';\nimport { childTestId, resolveTestId, slotTestId, withoutTestIdProps } from '../../../platform/test-id';\nimport type {\n DialogActionsProps,\n DialogContentProps,\n DialogHeaderProps,\n DialogProps,\n} from './Dialog.types';\n\n/**\n * The padding a dialog gives children that are not managing their own — and the\n * rule that takes it back when it turns out they are.\n *\n * `:has()` is doing what {@link hasSpacingSlot} cannot. A slot passed through a\n * COMPONENT (`<Body />` rendering a `DialogContent`) is invisible to any check\n * on element type: React does not know what a component renders until it has\n * rendered it, and by then the wrapper is already in the tree. The selector\n * asks the question one step later, of the DOM, where the answer exists.\n *\n * `display: contents` rather than `padding: 0`, because the padding is only\n * half of what a wrapper does. The other half is standing between the paper and\n * its children: MUI's `scroll=\"paper\"` makes the paper a flex column with\n * `overflow-y: auto`, so a `DialogContent` that is no longer its direct child\n * cannot be the thing that scrolls — the whole dialog scrolls instead and\n * carries the `DialogActions` off the bottom with it. An element with\n * `display: contents` generates no box at all: its children become the paper's\n * flex items, and its padding is never applied. Both halves, one declaration.\n *\n * A browser without `:has()` falls back to the padded box — the layout this\n * had before, not a broken one.\n */\nconst BODY_SX = {\n px: DIALOG_BODY_PADDING_UNITS.horizontal,\n pb: DIALOG_BODY_PADDING_UNITS.bottom,\n '&:has(> .MuiDialogContent-root), &:has(> .MuiDialogActions-root)': {\n display: 'contents',\n },\n} as const;\n\n/**\n * The dialog body. Consumers that pass raw children (no <DialogContent>) used\n * to render them flush against the paper edges — give them comfortable default\n * padding; <DialogContent>/<DialogActions> users keep managing their own\n * spacing.\n */\nfunction bodyOf(children: React.ReactNode, hasTitle: boolean): React.ReactNode {\n // Read lazily: both slots are declared below this function.\n if (hasSpacingSlot(children, [DialogContent, DialogActions])) return children;\n const pt = hasTitle\n ? DIALOG_BODY_PADDING_UNITS.topUnderTitle\n : DIALOG_BODY_PADDING_UNITS.top;\n return <Box sx={{ ...BODY_SX, pt }}>{children}</Box>;\n}\n\n/**\n * MUI's `onClose` for either renderer: a `persistent` dialog swallows the\n * backdrop press and Escape, and the caller's `onClose` is called with no\n * arguments, as `Dialog.base.ts` promises. The drawer used to get the caller's\n * raw `onClose` — so it closed when `persistent` said it must not, and was\n * handed MUI's `(event, reason)` (FUT-2673).\n */\nfunction closeHandlerOf(persistent: boolean, onClose: (() => void) | undefined) {\n return (_event: object, reason: 'backdropClick' | 'escapeKeyDown') => {\n if (persistent && (reason === 'backdropClick' || reason === 'escapeKeyDown')) {\n return;\n }\n onClose?.();\n };\n}\n\n/** The looks the Dialog lays under a caller's paper and backdrop props. */\ninterface DialogLooks {\n paperSx: SxProps<Theme>;\n backdropSx: SxProps<Theme>;\n testId: string | undefined;\n}\n\n/** What either renderer below takes: the looks, and the dialog's own children. */\ntype RendererProps = DialogLooks & { children: React.ReactNode };\n\n/**\n * Every variant but the drawer: MUI's `Dialog`. The scrim reaches MUI through\n * `slotProps.backdrop`, not the deprecated `BackdropProps`, and a caller's\n * backdrop props from either spelling merge over it rather than replacing it\n * (FUT-2672) — as their paper props merge over the variant's look (FUT-2613).\n */\nfunction ModalDialog({\n paperSx,\n backdropSx,\n testId,\n dialogProps,\n children,\n}: RendererProps & { dialogProps: MuiDialogProps }) {\n const { PaperProps: callerPaper, BackdropProps: callerBackdrop, slotProps, ...rest } = dialogProps;\n return (\n <MuiDialog\n {...rest}\n slotProps={{\n ...slotProps,\n paper: mergedPaperSlot(paperSx, testId, callerPaper, slotProps?.paper),\n backdrop: mergedBackdropSlot(backdropSx, callerBackdrop, slotProps?.backdrop),\n }}\n >\n {children}\n </MuiDialog>\n );\n}\n\n/**\n * The drawer variant: MUI's `Drawer`, with the variant's look on the Drawer's\n * OWN paper — on an inner Box it left the paper 0px wide and clipped the panel —\n * and a caller's paper props merged over it rather than replacing it. The\n * test id stays on the Drawer root, so the paper carries none of its own.\n *\n * The scrim rides the drawer's backdrop exactly as it rides the dialog's, so\n * `glass` blurs it here too; the paper does not frost (FUT-2673). MUI's\n * `Drawer` does not merge `BackdropProps` into `slotProps.backdrop` — it takes\n * one or the other — so both are folded into the one slot here.\n */\nfunction DrawerDialog({\n paperSx,\n backdropSx,\n testId,\n drawerProps,\n children,\n}: RendererProps & { drawerProps: DrawerProps }) {\n const { PaperProps: callerPaper, BackdropProps: callerBackdrop, slotProps, ...rest } = drawerProps;\n return (\n <Drawer\n anchor=\"right\"\n data-testid={testId}\n {...rest}\n slotProps={{\n ...slotProps,\n paper: mergedPaperSlot(paperSx, undefined, callerPaper, slotProps?.paper),\n backdrop: mergedBackdropSlot(backdropSx, callerBackdrop, slotProps?.backdrop),\n }}\n >\n {children}\n </Drawer>\n );\n}\n\nexport const Dialog: React.FC<DialogProps> = (rawProps) => {\n const {\n children,\n variant,\n size,\n title,\n description,\n showCloseButton,\n backdrop,\n persistent,\n glass,\n gradient,\n glow,\n pulse,\n borderRadius,\n onClose,\n open,\n ...others\n } = withDialogDefaults(rawProps);\n const theme = useTheme();\n // Every spelling of the test id the shared contract allows, mapped to the one\n // the DOM reads, and stripped from what is spread — `testID` is React\n // Native's name for it and is not a DOM attribute. The native `Dialog` does\n // the same in reverse.\n const testId = resolveTestId(others, 'dialog');\n const props = withoutTestIdProps(others);\n const looks: DialogLooks = {\n paperSx: variantStylesOf(theme, { variant, size, borderRadius, glass, gradient, glow, pulse }),\n backdropSx: backdropSxOf(theme, glass),\n testId,\n };\n const handleClose = closeHandlerOf(persistent, onClose);\n\n const header = title ? (\n <DialogHeader\n title={title}\n subtitle={description}\n showCloseButton={showCloseButton}\n onClose={onClose}\n dataTestId={testId}\n />\n ) : null;\n const body = bodyOf(children, Boolean(title));\n\n if (variant === 'drawer') {\n return (\n <DrawerDialog {...looks} drawerProps={{ ...props, open, onClose: handleClose }}>\n {header}\n {body}\n </DrawerDialog>\n );\n }\n\n return (\n <ModalDialog\n {...looks}\n dialogProps={{\n open,\n onClose: handleClose,\n fullScreen: variant === 'fullscreen',\n BackdropComponent: backdrop ? Backdrop : undefined,\n ...props,\n }}\n >\n {header}\n {body}\n </ModalDialog>\n );\n};\n\nexport const DialogHeader: React.FC<DialogHeaderProps> = ({\n children,\n title,\n subtitle,\n showCloseButton = true,\n onClose,\n ...others\n}) => {\n const props = withoutTestIdProps(others);\n\n if (children) {\n return (\n <Box\n data-testid={slotTestId(others, 'header', 'dialog')}\n sx={{\n p: DIALOG_HEADER_CHILDREN_PADDING_UNITS,\n borderBottom: '1px solid',\n borderColor: 'divider',\n }}\n >\n {children}\n </Box>\n );\n }\n\n return (\n <MuiDialogTitle\n data-testid={slotTestId(others, 'title', 'dialog')}\n sx={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n pb: subtitle\n ? DIALOG_TITLE.paddingBottomUnits.withSubtitle\n : DIALOG_TITLE.paddingBottomUnits.plain,\n }}\n {...props}\n >\n <Box>\n <Typography variant=\"h6\" component=\"div\">\n {title}\n </Typography>\n {subtitle && (\n <Typography\n variant=\"body2\"\n color=\"text.secondary\"\n sx={{ mt: DIALOG_TITLE.subtitleGapUnits }}\n >\n {subtitle}\n </Typography>\n )}\n </Box>\n {showCloseButton && onClose && (\n <IconButton\n aria-label=\"close\"\n onClick={onClose}\n data-testid={childTestId(others, 'close', 'dialog')}\n sx={{\n color: 'text.secondary',\n '&:hover': {\n backgroundColor: 'action.hover',\n },\n }}\n >\n <CloseIcon />\n </IconButton>\n )}\n </MuiDialogTitle>\n );\n};\n\n/**\n * Top padding for a body that sits directly under the title.\n *\n * MUI zeroes it there (`.MuiDialogTitle-root + &` on a non-`dividers` content),\n * assuming the title's own bottom padding is the whole gap. That assumption\n * breaks for a body opening with an outlined field: a filled field floats its\n * label ABOVE the input's border box, and `DialogContent` is `overflow-y: auto`\n * — a clipping box — so the label gets sliced in half (FUT-544: \"Tipo\" in the\n * \"Novo insumo\" dialog).\n *\n * Reserve the overhang rather than restore the full 24px: the title already\n * contributes its bottom padding, so a shrunk label's `translate(…, -9px)` is\n * all that is missing. 12px clears it and leaves the gap visually tight.\n */\nconst TITLED_BODY_PADDING_TOP = DIALOG_TITLED_BODY_PADDING_TOP_UNITS;\n\n/**\n * `.MuiDialogTitle-root + &` is `(0,2,0)`-specific and a plain `sx` entry is\n * `(0,1,0)`, so the padding above only survives the cascade by naming the class\n * again — `(0,3,0)`. Scoped to the title-following case so an untitled dialog\n * keeps MUI's roomier default.\n */\nconst TITLED_BODY_SELECTOR = '.MuiDialogTitle-root + &.MuiDialogContent-root';\n\nexport const DialogContent: React.FC<DialogContentProps> = ({\n children,\n dividers = false,\n dense = false,\n ...others\n}) => (\n <MuiDialogContent\n data-testid={slotTestId(others, 'content', 'dialog')}\n dividers={dividers}\n sx={{\n padding: dense ? DIALOG_CONTENT_PADDING_UNITS.dense : DIALOG_CONTENT_PADDING_UNITS.normal,\n [TITLED_BODY_SELECTOR]: { paddingTop: TITLED_BODY_PADDING_TOP },\n '&.MuiDialogContent-dividers': {\n borderTop: dividers ? '1px solid' : 'none',\n borderBottom: dividers ? '1px solid' : 'none',\n borderColor: 'divider',\n },\n }}\n {...withoutTestIdProps(others)}\n >\n {children}\n </MuiDialogContent>\n );\n\nexport const DialogActions: React.FC<DialogActionsProps> = ({\n children,\n alignment = 'right',\n spacing = DIALOG_ACTIONS.defaultSpacingUnits,\n ...others\n}) => {\n const getJustifyContent = () => {\n switch (alignment) {\n case 'left': return 'flex-start';\n case 'center': return 'center';\n case 'right': return 'flex-end';\n case 'space-between': return 'space-between';\n default: return 'flex-end';\n }\n };\n\n return (\n <MuiDialogActions\n data-testid={slotTestId(others, 'actions', 'dialog')}\n sx={{\n justifyContent: getJustifyContent(),\n gap: spacing,\n p: DIALOG_ACTIONS.paddingUnits,\n }}\n {...withoutTestIdProps(others)}\n >\n {children}\n </MuiDialogActions>\n );\n};"],"mappings":"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","names":[]}