@12-apps/ui 6.95.1 → 6.96.1

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 (69) hide show
  1. package/NATIVE.md +1 -1
  2. package/dist/_internal/components/data-display/Chip/Chip.js +3 -3
  3. package/dist/_internal/components/data-display/Chip/Chip.metrics.js +3 -1
  4. package/dist/_internal/components/data-display/Chip/Chip.styles.js +2 -2
  5. package/dist/_internal/components/data-display/index.js +3 -3
  6. package/dist/_internal/components/index.js +12 -12
  7. package/dist/_internal/components/layout/SettingCard/SettingCard.js +8 -8
  8. package/dist/_internal/components/layout/SettingCard/SettingCard.metrics.js +1 -1
  9. package/dist/_internal/components/layout/SettingCard/SettingCard.parts.js +6 -6
  10. package/dist/_internal/components/layout/SettingCard/SettingCard.styles.js +2 -2
  11. package/dist/_internal/components/layout/SettingCard/SettingCard.summary.js +7 -7
  12. package/dist/_internal/components/layout/SettingCard/SettingGrid.js +7 -7
  13. package/dist/_internal/components/layout/SettingCard/SettingGroup.js +9 -9
  14. package/dist/_internal/components/layout/SettingCard/SettingSwitch.js +8 -8
  15. package/dist/_internal/components/layout/SettingCard/SettingToggle.js +9 -9
  16. package/dist/_internal/components/layout/index.js +12 -12
  17. package/dist/{chunk-E5I776YW.js → chunk-52NM5VEW.js} +4 -2
  18. package/dist/{chunk-E5I776YW.js.map → chunk-52NM5VEW.js.map} +1 -1
  19. package/dist/{chunk-NI67M453.js → chunk-BTDRBO4G.js} +3 -3
  20. package/dist/{chunk-X2GWR75Q.js → chunk-FMNOCFD2.js} +8 -3
  21. package/dist/chunk-FMNOCFD2.js.map +1 -0
  22. package/dist/{chunk-DHAXUVMR.js → chunk-GOWKXKWO.js} +20 -4
  23. package/dist/chunk-GOWKXKWO.js.map +1 -0
  24. package/dist/{chunk-ZDAAHCIS.js → chunk-I3QVH34Y.js} +4 -4
  25. package/dist/{chunk-SKIAWOUC.js → chunk-KCH6O6IC.js} +4 -4
  26. package/dist/chunk-KSZ6GH3J.js +44 -0
  27. package/dist/chunk-KSZ6GH3J.js.map +1 -0
  28. package/dist/{chunk-E4NFH77Z.js → chunk-PQ4P4OEA.js} +3 -3
  29. package/dist/{chunk-IQWPVPV5.js → chunk-UJ7EHEXG.js} +2 -2
  30. package/dist/{chunk-CW5Z67NA.js → chunk-UOI3RX4W.js} +4 -4
  31. package/dist/{chunk-6ZAKPYWX.js → chunk-VILNULUY.js} +4 -4
  32. package/dist/{chunk-3EIRRLCQ.js → chunk-Y5J2EIR4.js} +4 -4
  33. package/dist/data-display/Chip.js +3 -3
  34. package/dist/layout/SettingCard.js +12 -12
  35. package/dist/native/data-display/Chip.js +3 -2
  36. package/dist/native/data-display/Chip.js.map +1 -1
  37. package/dist/types/components/data-display/Chip/Chip.base.d.ts +3 -2
  38. package/dist/types/components/data-display/Chip/Chip.base.d.ts.map +1 -1
  39. package/dist/types/components/data-display/Chip/Chip.metrics.d.ts +5 -0
  40. package/dist/types/components/data-display/Chip/Chip.metrics.d.ts.map +1 -1
  41. package/dist/types/components/data-display/Chip/Chip.styles.d.ts.map +1 -1
  42. package/dist/types/components/layout/SettingCard/SettingCard.metrics.d.ts +19 -2
  43. package/dist/types/components/layout/SettingCard/SettingCard.metrics.d.ts.map +1 -1
  44. package/dist/types/components/layout/SettingCard/SettingCard.summary.d.ts.map +1 -1
  45. package/dist/types-native/components/data-display/Chip/Chip.base.d.ts +3 -2
  46. package/dist/types-native/components/data-display/Chip/Chip.base.d.ts.map +1 -1
  47. package/dist/types-native/components/data-display/Chip/Chip.look.native.d.ts.map +1 -1
  48. package/dist/types-native/components/data-display/Chip/Chip.metrics.d.ts +5 -0
  49. package/dist/types-native/components/data-display/Chip/Chip.metrics.d.ts.map +1 -1
  50. package/package.json +1 -1
  51. package/src/components/data-display/Chip/Chip.base.ts +3 -2
  52. package/src/components/data-display/Chip/Chip.look.native.ts +4 -2
  53. package/src/components/data-display/Chip/Chip.metrics.ts +2 -0
  54. package/src/components/data-display/Chip/Chip.styles.tsx +35 -2
  55. package/src/components/data-display/Chip/chip.md +1 -1
  56. package/src/components/layout/SettingCard/SettingCard.metrics.ts +19 -2
  57. package/src/components/layout/SettingCard/SettingCard.summary.tsx +5 -0
  58. package/dist/chunk-BFRVMCQM.js +0 -27
  59. package/dist/chunk-BFRVMCQM.js.map +0 -1
  60. package/dist/chunk-DHAXUVMR.js.map +0 -1
  61. package/dist/chunk-X2GWR75Q.js.map +0 -1
  62. /package/dist/{chunk-NI67M453.js.map → chunk-BTDRBO4G.js.map} +0 -0
  63. /package/dist/{chunk-ZDAAHCIS.js.map → chunk-I3QVH34Y.js.map} +0 -0
  64. /package/dist/{chunk-SKIAWOUC.js.map → chunk-KCH6O6IC.js.map} +0 -0
  65. /package/dist/{chunk-E4NFH77Z.js.map → chunk-PQ4P4OEA.js.map} +0 -0
  66. /package/dist/{chunk-IQWPVPV5.js.map → chunk-UJ7EHEXG.js.map} +0 -0
  67. /package/dist/{chunk-CW5Z67NA.js.map → chunk-UOI3RX4W.js.map} +0 -0
  68. /package/dist/{chunk-6ZAKPYWX.js.map → chunk-VILNULUY.js.map} +0 -0
  69. /package/dist/{chunk-3EIRRLCQ.js.map → chunk-Y5J2EIR4.js.map} +0 -0
@@ -64,11 +64,13 @@ function softPaint(theme: UiTheme, color: ChipColor): ChipPaint {
64
64
  };
65
65
  }
66
66
  const accent = theme.palette[color];
67
+ // The ink that reads on a 14% tint: `dark` over a light page, `light` over a dark one.
68
+ const ink = theme.mode === 'dark' ? accent.light : accent.dark;
67
69
  return {
68
70
  container: { backgroundColor: alpha(accent.main, SOFT_GROUND_ALPHA) },
69
71
  pressed: { backgroundColor: alpha(accent.main, SOFT_HOVER_ALPHA) },
70
- label: { color: accent.dark, fontWeight: '600' },
71
- deleteColor: alpha(accent.dark, DELETE_ICON_ALPHA),
72
+ label: { color: ink, fontWeight: '600' },
73
+ deleteColor: ink,
72
74
  };
73
75
  }
74
76
 
@@ -105,3 +105,5 @@ export const CHIP_TRANSITION_EASING = 'cubic-bezier(0.4, 0, 0.2, 1)';
105
105
  export const SOFT_GROUND_ALPHA = 0.14;
106
106
  /** A soft chip's hover ground. */
107
107
  export const SOFT_HOVER_ALPHA = 0.22;
108
+ /** A soft chip's keyboard-focus ring, in design px (read through `rem`). */
109
+ export const SOFT_FOCUS_RING = { width: 2, offset: 2 } as const;
@@ -12,6 +12,7 @@ import {
12
12
  CHIP_TRANSITION_MS,
13
13
  HOVER_LIFT_PX,
14
14
  HOVER_SHADOW,
15
+ SOFT_FOCUS_RING,
15
16
  SOFT_GROUND_ALPHA,
16
17
  SOFT_HOVER_ALPHA,
17
18
  } from './Chip.metrics';
@@ -78,12 +79,21 @@ const paletteKey = (color: NonNullable<ChipProps['color']>): 'primary' | 'second
78
79
  return color === 'danger' ? 'error' : color;
79
80
  };
80
81
 
81
- /** `soft`: the colour's tint for a ground, its dark step for ink (and the icon). */
82
+ /**
83
+ * `soft`: the colour's tint for a ground, and for ink the step that reads on it:
84
+ * the `dark` step in light mode, the `light` step in dark mode (FUT-4442). The
85
+ * ground is a 14% tint over the page, so on a near-black page the ink has to be
86
+ * lighter than `main`; `dark` there is 2.6 to 3.9:1, `light` clears 4.5:1. The
87
+ * label, the icon and the delete glyph all take it.
88
+ */
82
89
  const softStyles = (color: NonNullable<ChipProps['color']>): SxProps<Theme> => {
83
90
  const key = paletteKey(color);
84
91
  const ground = (theme: Theme): string =>
85
92
  key ? alpha(theme.palette[key].main, SOFT_GROUND_ALPHA) : theme.palette.action.selected;
86
- const ink = (theme: Theme): string => (key ? theme.palette[key].dark : theme.palette.text.secondary);
93
+ const ink = (theme: Theme): string => {
94
+ if (!key) return theme.palette.text.secondary;
95
+ return theme.palette.mode === 'dark' ? theme.palette[key].light : theme.palette[key].dark;
96
+ };
87
97
  return {
88
98
  backgroundColor: ground,
89
99
  color: ink,
@@ -93,9 +103,32 @@ const softStyles = (color: NonNullable<ChipProps['color']>): SxProps<Theme> => {
93
103
  '&.MuiChip-clickable:hover': {
94
104
  backgroundColor: (theme: Theme) => (key ? alpha(theme.palette[key].main, SOFT_HOVER_ALPHA) : theme.palette.action.hover),
95
105
  },
106
+ // `neutral` keeps MUI's glyph and focus exactly as they were.
107
+ ...(key ? (accentedStates(key, ink) as object) : {}),
96
108
  };
97
109
  };
98
110
 
111
+ /**
112
+ * What only an accented soft chip changes (FUT-4442, FUT-4461). MUI paints the
113
+ * delete glyph in `contrastText` at 0.7, near-black on a dark ground, so the glyph
114
+ * takes the ink. Focus, in both modes: the chip keeps its resting ground (MUI's
115
+ * `dark` step puts the ink at about 1:1 in light mode and sinks the light ink in
116
+ * dark mode) and draws a ring in the ink, so focus shows without the ground.
117
+ */
118
+ const accentedStates = (
119
+ key: Exclude<ReturnType<typeof paletteKey>, null>,
120
+ ink: (theme: Theme) => string,
121
+ ): SxProps<Theme> => ({
122
+ '& .MuiChip-deleteIcon': { color: ink, '&:hover': { color: ink } },
123
+ '&.Mui-focusVisible': {
124
+ backgroundColor: (theme: Theme) => alpha(theme.palette[key].main, SOFT_GROUND_ALPHA),
125
+ outlineStyle: 'solid',
126
+ outlineWidth: (theme: Theme) => rem(theme, SOFT_FOCUS_RING.width),
127
+ outlineColor: ink,
128
+ outlineOffset: (theme: Theme) => rem(theme, SOFT_FOCUS_RING.offset),
129
+ },
130
+ });
131
+
99
132
  export const chipStyles = ({
100
133
  variant,
101
134
  color = 'primary',
@@ -29,7 +29,7 @@ interface ChipProps {
29
29
 
30
30
  **Features**
31
31
 
32
- - Filled/Outlined/Soft variants; optional avatar or icon. `soft` is a status chip: the colour's tint for a ground and its dark step for ink.
32
+ - Filled/Outlined/Soft variants; optional avatar or icon. `soft` is a status chip: the colour's tint for a ground and, for ink, its dark step in light mode and its light step in dark mode.
33
33
  - Selectable (toggle) and/or deletable (× button).
34
34
  - Keyboard: Space/Enter activates; Delete/Backspace triggers remove when focused.
35
35
 
@@ -15,9 +15,26 @@ export const SETTING_CARD = {
15
15
  gridMinColumnWidth: 320,
16
16
  /** The widest the [i]'s full-summary tooltip gets. */
17
17
  infoMaxWidth: 360,
18
- /** The [i]'s keyboard focus ring: its width, and its gap from the glyph. */
18
+ /**
19
+ * The [i]'s tap target, the house 40 px floor (FUT-4443). The glyph stays 16 px
20
+ * (`xs`); a negative margin of `(infoTapTarget - glyph) / 2` gives the box back
21
+ * to the title row, so nothing moves.
22
+ */
23
+ infoTapTarget: 40,
24
+ /** Above and below the glyph: (40 - 16) / 2, so the title row keeps its height. */
25
+ infoTapMarginBlock: -12,
26
+ /**
27
+ * Beside the glyph: minus the title row's `gap` (8 px), not (40 - 16) / 2, so the
28
+ * box ends where the status pill ends and never overlaps it.
29
+ */
30
+ infoTapMarginInline: -8,
31
+ /**
32
+ * The [i]'s keyboard focus ring: its width, and its offset from the box. The
33
+ * offset is negative so the ring's OUTER edge is the 40 px box (a 40 px circle
34
+ * round a 16 px glyph), instead of a 44 px one crowding the title and the pill.
35
+ */
19
36
  infoFocusRingWidth: 2,
20
- infoFocusRingOffset: 2,
37
+ infoFocusRingOffset: -2,
21
38
  } as const;
22
39
 
23
40
  /** The grid's default gap, in theme SPACING units (not px): what `sx`'s `gap: 2` means. */
@@ -61,6 +61,11 @@ export const SummaryInfo: React.FC<{ label: string; summary: React.ReactNode; da
61
61
  display: 'inline-flex',
62
62
  alignItems: 'center',
63
63
  justifyContent: 'center',
64
+ // A real box, not an overlay: a 16 px glyph in a 40 px target whose extra
65
+ // height is handed back as margin, so the title row keeps its height.
66
+ minWidth: rem(theme, SETTING_CARD.infoTapTarget),
67
+ minHeight: rem(theme, SETTING_CARD.infoTapTarget),
68
+ margin: `${rem(theme, SETTING_CARD.infoTapMarginBlock)} ${rem(theme, SETTING_CARD.infoTapMarginInline)}`,
64
69
  padding: 0,
65
70
  border: 0,
66
71
  background: 'none',
@@ -1,27 +0,0 @@
1
- // src/components/layout/SettingCard/SettingCard.metrics.ts
2
- var SETTING_CARD = {
3
- /** Between the icon and the title. */
4
- iconGap: 12,
5
- /** The spinner beside a switch while its flip is saving. */
6
- spinnerSize: 16,
7
- /** How far a group's dependent rows sit in from its main switch. */
8
- groupIndent: 24,
9
- /** The rule down the left of a group's dependent rows. */
10
- groupRuleWidth: 2,
11
- /** The narrowest a grid column gets by default. */
12
- gridMinColumnWidth: 320,
13
- /** The widest the [i]'s full-summary tooltip gets. */
14
- infoMaxWidth: 360,
15
- /** The [i]'s keyboard focus ring: its width, and its gap from the glyph. */
16
- infoFocusRingWidth: 2,
17
- infoFocusRingOffset: 2
18
- };
19
- var SETTING_GRID_GAP_UNITS = 2;
20
- var SETTING_GROUP_INACTIVE_OPACITY = 0.5;
21
-
22
- export {
23
- SETTING_CARD,
24
- SETTING_GRID_GAP_UNITS,
25
- SETTING_GROUP_INACTIVE_OPACITY
26
- };
27
- //# sourceMappingURL=chunk-BFRVMCQM.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/layout/SettingCard/SettingCard.metrics.ts"],"sourcesContent":["/**\n * The setting-card family's lengths, in design px. The web reads every one\n * through `rem(theme, n)`, so they scale with the host's type scale.\n */\nexport const SETTING_CARD = {\n /** Between the icon and the title. */\n iconGap: 12,\n /** The spinner beside a switch while its flip is saving. */\n spinnerSize: 16,\n /** How far a group's dependent rows sit in from its main switch. */\n groupIndent: 24,\n /** The rule down the left of a group's dependent rows. */\n groupRuleWidth: 2,\n /** The narrowest a grid column gets by default. */\n gridMinColumnWidth: 320,\n /** The widest the [i]'s full-summary tooltip gets. */\n infoMaxWidth: 360,\n /** The [i]'s keyboard focus ring: its width, and its gap from the glyph. */\n infoFocusRingWidth: 2,\n infoFocusRingOffset: 2,\n} as const;\n\n/** The grid's default gap, in theme SPACING units (not px): what `sx`'s `gap: 2` means. */\nexport const SETTING_GRID_GAP_UNITS = 2;\n\n/** How faded a group's dependent rows are while the main switch is off. */\nexport const SETTING_GROUP_INACTIVE_OPACITY = 0.5;\n"],"mappings":";AAIO,IAAM,eAAe;AAAA;AAAA,EAE1B,SAAS;AAAA;AAAA,EAET,aAAa;AAAA;AAAA,EAEb,aAAa;AAAA;AAAA,EAEb,gBAAgB;AAAA;AAAA,EAEhB,oBAAoB;AAAA;AAAA,EAEpB,cAAc;AAAA;AAAA,EAEd,oBAAoB;AAAA,EACpB,qBAAqB;AACvB;AAGO,IAAM,yBAAyB;AAG/B,IAAM,iCAAiC;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/data-display/Chip/Chip.styles.tsx"],"sourcesContent":["import Avatar from '@mui/material/Avatar/index.js';\nimport type { SxProps, Theme } from '@mui/material/styles/index.js';\nimport type { KeyboardEvent, ReactElement } from 'react';\nimport React from 'react';\n\nimport { chipKeyAction, type ChipKeyArgs } from './Chip.helpers';\nimport { alpha } from '@mui/material/styles/index.js';\n\nimport {\n CHIP_SIZES,\n CHIP_TRANSITION_EASING,\n CHIP_TRANSITION_MS,\n HOVER_LIFT_PX,\n HOVER_SHADOW,\n SOFT_GROUND_ALPHA,\n SOFT_HOVER_ALPHA,\n} from './Chip.metrics';\nimport type { ChipProps } from './Chip.types';\nimport { shadowInk } from '../../../tokens/ink';\nimport { rem, rems, sxRem } from '../../../tokens/relative';\n\n/**\n * A chip is not a native control, so the two keyboard conventions it stands in\n * for are wired by hand: Delete/Backspace removes it, Enter/Space activates it.\n * The DECISION is `chipKeyAction`, which the native half reads too.\n */\nexport const makeKeyDownHandler =\n (args: ChipKeyArgs & { onClick?: () => void; onDelete?: () => void }) =>\n (event: KeyboardEvent): void => {\n const action = chipKeyAction(event.key, args);\n if (action === null) return;\n event.preventDefault();\n if (action === 'delete') {\n args.onDelete?.();\n return;\n }\n args.onClick?.();\n };\n\nexport const avatarFor = (\n avatar: ChipProps['avatar'],\n avatarSrc?: string,\n): ReactElement | undefined => {\n if (avatar && React.isValidElement(avatar)) {\n return avatar;\n }\n if (avatarSrc) {\n const { avatarSize } = CHIP_SIZES.medium;\n return <Avatar src={avatarSrc} sx={{ width: sxRem(avatarSize), height: sxRem(avatarSize) }} />;\n }\n return undefined;\n};\n\ninterface ChipStyleArgs {\n variant: ChipProps['variant'];\n color?: ChipProps['color'];\n selected?: boolean;\n clickable?: boolean;\n disabled?: boolean;\n}\n\n/** The lift's shadow, per mode — the same numbers the native chip reads. */\nconst hoverShadow = (theme: Theme): string =>\n `0 ${rems(theme, HOVER_SHADOW.offsetY, HOVER_SHADOW.blur)} ${shadowInk(\n theme,\n theme.palette.mode === 'dark' ? HOVER_SHADOW.alphaDark : HOVER_SHADOW.alphaLight,\n )}`;\n\n/**\n * Selection styling uses SEMANTIC palette tokens (not hardcoded rgba). A filled\n * selected chip keeps MUI's solid `color.main` + contrast text (clear active\n * state); an outlined selected chip gets a subtle theme-driven `action.selected`\n * tint so it reads as active without muddying the fill.\n */\n/** The palette entry a colour paints with; `neutral` has none and takes the ink. */\nconst paletteKey = (color: NonNullable<ChipProps['color']>): 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning' | null => {\n if (color === 'neutral') return null;\n return color === 'danger' ? 'error' : color;\n};\n\n/** `soft`: the colour's tint for a ground, its dark step for ink (and the icon). */\nconst softStyles = (color: NonNullable<ChipProps['color']>): SxProps<Theme> => {\n const key = paletteKey(color);\n const ground = (theme: Theme): string =>\n key ? alpha(theme.palette[key].main, SOFT_GROUND_ALPHA) : theme.palette.action.selected;\n const ink = (theme: Theme): string => (key ? theme.palette[key].dark : theme.palette.text.secondary);\n return {\n backgroundColor: ground,\n color: ink,\n // A state is read at a glance: the label is set semibold.\n fontWeight: 600,\n '& .MuiChip-icon': { color: ink },\n '&.MuiChip-clickable:hover': {\n backgroundColor: (theme: Theme) => (key ? alpha(theme.palette[key].main, SOFT_HOVER_ALPHA) : theme.palette.action.hover),\n },\n };\n};\n\nexport const chipStyles = ({\n variant,\n color = 'primary',\n selected,\n clickable,\n disabled,\n}: ChipStyleArgs): SxProps<Theme> => {\n const lifts = clickable && !disabled;\n\n return {\n ...(variant === 'soft' ? (softStyles(color) as object) : {}),\n // Enhanced styling for outlined variant\n ...(variant === 'outlined' && {\n borderWidth: '1px',\n borderStyle: 'solid',\n backgroundColor: 'transparent',\n }),\n ...(selected &&\n variant === 'outlined' && {\n backgroundColor: (theme: Theme) => theme.palette.action.selected,\n }),\n '&:hover': {\n ...(lifts && {\n transform: (theme: Theme) => `translateY(${rem(theme, -HOVER_LIFT_PX)})`,\n boxShadow: (theme: Theme) => hoverShadow(theme),\n }),\n },\n '&:active': {\n ...(lifts && {\n transform: 'translateY(0px)',\n }),\n },\n transition: `all ${CHIP_TRANSITION_MS / 1000}s ${CHIP_TRANSITION_EASING}`,\n };\n};\n\nexport const iconWithTestId = (\n icon: ChipProps['icon'],\n testId: string,\n): ReactElement | undefined =>\n icon && React.isValidElement(icon)\n ? React.cloneElement(icon as ReactElement, {\n 'data-testid': testId,\n } as Record<string, unknown>)\n : undefined;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,YAAY;AAGnB,OAAO,WAAW;AAGlB,SAAS,aAAa;AA0CX;AAtBJ,IAAM,qBACX,CAAC,SACD,CAAC,UAA+B;AAC9B,QAAM,SAAS,cAAc,MAAM,KAAK,IAAI;AAC5C,MAAI,WAAW,KAAM;AACrB,QAAM,eAAe;AACrB,MAAI,WAAW,UAAU;AACvB,SAAK,WAAW;AAChB;AAAA,EACF;AACA,OAAK,UAAU;AACjB;AAEK,IAAM,YAAY,CACvB,QACA,cAC6B;AAC7B,MAAI,UAAU,MAAM,eAAe,MAAM,GAAG;AAC1C,WAAO;AAAA,EACT;AACA,MAAI,WAAW;AACb,UAAM,EAAE,WAAW,IAAI,WAAW;AAClC,WAAO,oBAAC,UAAO,KAAK,WAAW,IAAI,EAAE,OAAO,MAAM,UAAU,GAAG,QAAQ,MAAM,UAAU,EAAE,GAAG;AAAA,EAC9F;AACA,SAAO;AACT;AAWA,IAAM,cAAc,CAAC,UACnB,KAAK,KAAK,OAAO,aAAa,SAAS,aAAa,IAAI,CAAC,IAAI;AAAA,EAC3D;AAAA,EACA,MAAM,QAAQ,SAAS,SAAS,aAAa,YAAY,aAAa;AACxE,CAAC;AASH,IAAM,aAAa,CAAC,UAAsH;AACxI,MAAI,UAAU,UAAW,QAAO;AAChC,SAAO,UAAU,WAAW,UAAU;AACxC;AAGA,IAAM,aAAa,CAAC,UAA2D;AAC7E,QAAM,MAAM,WAAW,KAAK;AAC5B,QAAM,SAAS,CAAC,UACd,MAAM,MAAM,MAAM,QAAQ,GAAG,EAAE,MAAM,iBAAiB,IAAI,MAAM,QAAQ,OAAO;AACjF,QAAM,MAAM,CAAC,UAA0B,MAAM,MAAM,QAAQ,GAAG,EAAE,OAAO,MAAM,QAAQ,KAAK;AAC1F,SAAO;AAAA,IACL,iBAAiB;AAAA,IACjB,OAAO;AAAA;AAAA,IAEP,YAAY;AAAA,IACZ,mBAAmB,EAAE,OAAO,IAAI;AAAA,IAChC,6BAA6B;AAAA,MAC3B,iBAAiB,CAAC,UAAkB,MAAM,MAAM,MAAM,QAAQ,GAAG,EAAE,MAAM,gBAAgB,IAAI,MAAM,QAAQ,OAAO;AAAA,IACpH;AAAA,EACF;AACF;AAEO,IAAM,aAAa,CAAC;AAAA,EACzB;AAAA,EACA,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA;AACF,MAAqC;AACnC,QAAM,QAAQ,aAAa,CAAC;AAE5B,SAAO;AAAA,IACL,GAAI,YAAY,SAAU,WAAW,KAAK,IAAe,CAAC;AAAA;AAAA,IAE1D,GAAI,YAAY,cAAc;AAAA,MAC5B,aAAa;AAAA,MACb,aAAa;AAAA,MACb,iBAAiB;AAAA,IACnB;AAAA,IACA,GAAI,YACF,YAAY,cAAc;AAAA,MACxB,iBAAiB,CAAC,UAAiB,MAAM,QAAQ,OAAO;AAAA,IAC1D;AAAA,IACF,WAAW;AAAA,MACT,GAAI,SAAS;AAAA,QACX,WAAW,CAAC,UAAiB,cAAc,IAAI,OAAO,CAAC,aAAa,CAAC;AAAA,QACrE,WAAW,CAAC,UAAiB,YAAY,KAAK;AAAA,MAChD;AAAA,IACF;AAAA,IACA,YAAY;AAAA,MACV,GAAI,SAAS;AAAA,QACX,WAAW;AAAA,MACb;AAAA,IACF;AAAA,IACA,YAAY,OAAO,qBAAqB,GAAI,KAAK,sBAAsB;AAAA,EACzE;AACF;AAEO,IAAM,iBAAiB,CAC5B,MACA,WAEA,QAAQ,MAAM,eAAe,IAAI,IAC7B,MAAM,aAAa,MAAsB;AAAA,EACvC,eAAe;AACjB,CAA4B,IAC5B;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/layout/SettingCard/SettingCard.summary.tsx"],"sourcesContent":["import Box from '@mui/material/Box/index.js';\nimport { useTheme } from '@mui/material/styles/index.js';\nimport React, { useCallback, useLayoutEffect, useState } from 'react';\n\nimport { Icon } from '../../../icons';\nimport { rem } from '../../../tokens/relative';\nimport { InteractiveTooltip } from '../../data-display/InteractiveTooltip';\n\nimport { SETTING_CARD } from './SettingCard.metrics';\nimport { partTestId } from './SettingCard.parts';\n\n/**\n * Whether a clamped element is hiding text — measured, never guessed from the\n * string's length, because what fits depends on the width the card is GIVEN.\n * Re-measured whenever the element resizes, so a card that widens drops its [i].\n */\nexport const useClamped = (content?: unknown): { ref: (node: HTMLElement | null) => void; clamped: boolean } => {\n const [node, setNode] = useState<HTMLElement | null>(null);\n const [clamped, setClamped] = useState(false);\n const ref = useCallback((next: HTMLElement | null) => setNode(next), []);\n\n useLayoutEffect(() => {\n if (!node) return undefined;\n const measure = (): void => setClamped(node.scrollHeight > node.clientHeight + 1);\n measure();\n if (typeof ResizeObserver === 'undefined') return undefined;\n const observer = new ResizeObserver(measure);\n observer.observe(node);\n return () => observer.disconnect();\n // `content` too: a summary that grows from two lines to three inside the\n // same clamped height fires no resize, so the text changing re-measures.\n }, [node, content]);\n\n return { ref, clamped };\n};\n\n/**\n * The [i] beside a card's title while its summary is cut: hover shows the whole\n * text, a click or tap pins it — so it works on a phone, where there is no hover.\n */\nexport const SummaryInfo: React.FC<{ label: string; summary: React.ReactNode; dataTestId?: string }> = ({\n label,\n summary,\n dataTestId,\n}) => {\n const theme = useTheme();\n return (\n <InteractiveTooltip\n variant=\"light\"\n size=\"sm\"\n maxWidth={SETTING_CARD.infoMaxWidth}\n hoverContent={summary}\n pinnedContent={summary}\n dataTestId={partTestId(dataTestId, 'info')}\n >\n <Box\n component=\"button\"\n type=\"button\"\n aria-label={label}\n sx={{\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n padding: 0,\n border: 0,\n background: 'none',\n color: theme.palette.text.secondary,\n cursor: 'pointer',\n borderRadius: '50%',\n '&:focus-visible': {\n outline: `${rem(theme, SETTING_CARD.infoFocusRingWidth)} solid ${theme.palette.primary.main}`,\n outlineOffset: rem(theme, SETTING_CARD.infoFocusRingOffset),\n },\n }}\n >\n <Icon name=\"InfoOutlined\" size=\"xs\" />\n </Box>\n </InteractiveTooltip>\n );\n};\n\n/**\n * The summary's measuring ref, and the [i] for the header while it is cut —\n * `null` when there is no summary, it fits, or `show` is false (an open card).\n */\nexport const useSummaryInfo = ({\n summary,\n show = true,\n label,\n dataTestId,\n}: {\n summary: React.ReactNode;\n show?: boolean;\n label: string;\n dataTestId?: string;\n}): { ref: (node: HTMLElement | null) => void; info: React.ReactNode } => {\n const { ref, clamped } = useClamped(summary);\n const visible = show && clamped && summary != null;\n return { ref, info: visible ? <SummaryInfo label={label} summary={summary} dataTestId={dataTestId} /> : null };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;AAAA,OAAO,SAAS;AAChB,SAAS,gBAAgB;AACzB,SAAgB,aAAa,iBAAiB,gBAAgB;AAyEtD;AA3DD,IAAM,aAAa,CAAC,YAAqF;AAC9G,QAAM,CAAC,MAAM,OAAO,IAAI,SAA6B,IAAI;AACzD,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAC5C,QAAM,MAAM,YAAY,CAAC,SAA6B,QAAQ,IAAI,GAAG,CAAC,CAAC;AAEvE,kBAAgB,MAAM;AACpB,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,UAAU,MAAY,WAAW,KAAK,eAAe,KAAK,eAAe,CAAC;AAChF,YAAQ;AACR,QAAI,OAAO,mBAAmB,YAAa,QAAO;AAClD,UAAM,WAAW,IAAI,eAAe,OAAO;AAC3C,aAAS,QAAQ,IAAI;AACrB,WAAO,MAAM,SAAS,WAAW;AAAA,EAGnC,GAAG,CAAC,MAAM,OAAO,CAAC;AAElB,SAAO,EAAE,KAAK,QAAQ;AACxB;AAMO,IAAM,cAA0F,CAAC;AAAA,EACtG;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,QAAQ,SAAS;AACvB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,UAAU,aAAa;AAAA,MACvB,cAAc;AAAA,MACd,eAAe;AAAA,MACf,YAAY,WAAW,YAAY,MAAM;AAAA,MAEzC;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,MAAK;AAAA,UACL,cAAY;AAAA,UACZ,IAAI;AAAA,YACF,SAAS;AAAA,YACT,YAAY;AAAA,YACZ,gBAAgB;AAAA,YAChB,SAAS;AAAA,YACT,QAAQ;AAAA,YACR,YAAY;AAAA,YACZ,OAAO,MAAM,QAAQ,KAAK;AAAA,YAC1B,QAAQ;AAAA,YACR,cAAc;AAAA,YACd,mBAAmB;AAAA,cACjB,SAAS,GAAG,IAAI,OAAO,aAAa,kBAAkB,CAAC,UAAU,MAAM,QAAQ,QAAQ,IAAI;AAAA,cAC3F,eAAe,IAAI,OAAO,aAAa,mBAAmB;AAAA,YAC5D;AAAA,UACF;AAAA,UAEA,8BAAC,QAAK,MAAK,gBAAe,MAAK,MAAK;AAAA;AAAA,MACtC;AAAA;AAAA,EACF;AAEJ;AAMO,IAAM,iBAAiB,CAAC;AAAA,EAC7B;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AACF,MAK0E;AACxE,QAAM,EAAE,KAAK,QAAQ,IAAI,WAAW,OAAO;AAC3C,QAAM,UAAU,QAAQ,WAAW,WAAW;AAC9C,SAAO,EAAE,KAAK,MAAM,UAAU,oBAAC,eAAY,OAAc,SAAkB,YAAwB,IAAK,KAAK;AAC/G;","names":[]}