@pega/cosmos-react-core 10.0.0-build.5.2 → 10.0.0-build.5.21

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 (131) hide show
  1. package/lib/components/AIRewrite/AIRewrite.styles.d.ts +19 -3
  2. package/lib/components/AIRewrite/AIRewrite.styles.d.ts.map +1 -1
  3. package/lib/components/AppShell/AppHeader.styles.d.ts.map +1 -1
  4. package/lib/components/AppShell/AppHeader.styles.js +8 -3
  5. package/lib/components/AppShell/AppHeader.styles.js.map +1 -1
  6. package/lib/components/AppShell/AppShell.d.ts.map +1 -1
  7. package/lib/components/AppShell/AppShell.js +16 -6
  8. package/lib/components/AppShell/AppShell.js.map +1 -1
  9. package/lib/components/AppShell/AppShell.styles.d.ts +3 -0
  10. package/lib/components/AppShell/AppShell.styles.d.ts.map +1 -1
  11. package/lib/components/AppShell/AppShell.styles.js +33 -17
  12. package/lib/components/AppShell/AppShell.styles.js.map +1 -1
  13. package/lib/components/AppShell/AppShell.types.d.ts +33 -0
  14. package/lib/components/AppShell/AppShell.types.d.ts.map +1 -1
  15. package/lib/components/AppShell/AppShell.types.js.map +1 -1
  16. package/lib/components/AppShell/DocumentTabs.d.ts +6 -0
  17. package/lib/components/AppShell/DocumentTabs.d.ts.map +1 -0
  18. package/lib/components/AppShell/DocumentTabs.js +409 -0
  19. package/lib/components/AppShell/DocumentTabs.js.map +1 -0
  20. package/lib/components/AppShell/DocumentTabs.styles.d.ts +231 -0
  21. package/lib/components/AppShell/DocumentTabs.styles.d.ts.map +1 -0
  22. package/lib/components/AppShell/DocumentTabs.styles.js +562 -0
  23. package/lib/components/AppShell/DocumentTabs.styles.js.map +1 -0
  24. package/lib/components/AppShell/NavigationListItemWrapper.d.ts.map +1 -1
  25. package/lib/components/AppShell/NavigationListItemWrapper.js +6 -5
  26. package/lib/components/AppShell/NavigationListItemWrapper.js.map +1 -1
  27. package/lib/components/AppShell/Operator.d.ts.map +1 -1
  28. package/lib/components/AppShell/Operator.js +8 -5
  29. package/lib/components/AppShell/Operator.js.map +1 -1
  30. package/lib/components/AppShell/ThemeSwitcher.d.ts.map +1 -1
  31. package/lib/components/AppShell/ThemeSwitcher.js +1 -0
  32. package/lib/components/AppShell/ThemeSwitcher.js.map +1 -1
  33. package/lib/components/AppShell/index.d.ts +1 -1
  34. package/lib/components/AppShell/index.d.ts.map +1 -1
  35. package/lib/components/AppShell/index.js.map +1 -1
  36. package/lib/components/Backdrop/Backdrop.js +2 -2
  37. package/lib/components/Backdrop/Backdrop.js.map +1 -1
  38. package/lib/components/DateTime/Input/DateInput.d.ts.map +1 -1
  39. package/lib/components/DateTime/Input/DateInput.js +15 -9
  40. package/lib/components/DateTime/Input/DateInput.js.map +1 -1
  41. package/lib/components/DateTime/Input/DateTime.styles.d.ts +3 -0
  42. package/lib/components/DateTime/Input/DateTime.styles.d.ts.map +1 -1
  43. package/lib/components/DateTime/Input/DateTime.styles.js +25 -0
  44. package/lib/components/DateTime/Input/DateTime.styles.js.map +1 -1
  45. package/lib/components/DateTime/Input/DateTimeInput.d.ts.map +1 -1
  46. package/lib/components/DateTime/Input/DateTimeInput.js +27 -18
  47. package/lib/components/DateTime/Input/DateTimeInput.js.map +1 -1
  48. package/lib/components/DateTime/Input/TimeInput.d.ts +6 -3
  49. package/lib/components/DateTime/Input/TimeInput.d.ts.map +1 -1
  50. package/lib/components/DateTime/Input/TimeInput.js +54 -24
  51. package/lib/components/DateTime/Input/TimeInput.js.map +1 -1
  52. package/lib/components/DateTime/Input/WeekInput.d.ts +6 -3
  53. package/lib/components/DateTime/Input/WeekInput.d.ts.map +1 -1
  54. package/lib/components/DateTime/Input/WeekInput.js +29 -16
  55. package/lib/components/DateTime/Input/WeekInput.js.map +1 -1
  56. package/lib/components/DateTime/Picker/Calendar.styles.d.ts.map +1 -1
  57. package/lib/components/DateTime/Picker/Calendar.styles.js +5 -0
  58. package/lib/components/DateTime/Picker/Calendar.styles.js.map +1 -1
  59. package/lib/components/DateTime/Picker/DatePicker.styles.d.ts.map +1 -1
  60. package/lib/components/DateTime/Picker/DatePicker.styles.js +32 -7
  61. package/lib/components/DateTime/Picker/DatePicker.styles.js.map +1 -1
  62. package/lib/components/DateTime/Picker/TimePicker.d.ts.map +1 -1
  63. package/lib/components/DateTime/Picker/TimePicker.js +10 -2
  64. package/lib/components/DateTime/Picker/TimePicker.js.map +1 -1
  65. package/lib/components/Dialog/Dialog.types.d.ts +23 -13
  66. package/lib/components/Dialog/Dialog.types.d.ts.map +1 -1
  67. package/lib/components/Dialog/Dialog.types.js.map +1 -1
  68. package/lib/components/Dialog/FormDialog.d.ts.map +1 -1
  69. package/lib/components/Dialog/FormDialog.js +50 -18
  70. package/lib/components/Dialog/FormDialog.js.map +1 -1
  71. package/lib/components/Dialog/InfoDialog.d.ts.map +1 -1
  72. package/lib/components/Dialog/InfoDialog.js +6 -4
  73. package/lib/components/Dialog/InfoDialog.js.map +1 -1
  74. package/lib/components/Dialog/TouchDialog.js +1 -1
  75. package/lib/components/Dialog/TouchDialog.js.map +1 -1
  76. package/lib/components/Dialog/TouchDialog.styles.d.ts.map +1 -1
  77. package/lib/components/Dialog/TouchDialog.styles.js +2 -1
  78. package/lib/components/Dialog/TouchDialog.styles.js.map +1 -1
  79. package/lib/components/InlineEdit/InlineEdit.d.ts +6 -0
  80. package/lib/components/InlineEdit/InlineEdit.d.ts.map +1 -1
  81. package/lib/components/InlineEdit/InlineEdit.js +45 -4
  82. package/lib/components/InlineEdit/InlineEdit.js.map +1 -1
  83. package/lib/components/InlineEdit/InlineEdit.styles.d.ts +19 -3
  84. package/lib/components/InlineEdit/InlineEdit.styles.d.ts.map +1 -1
  85. package/lib/components/InlineEdit/InlineEdit.styles.js +38 -20
  86. package/lib/components/InlineEdit/InlineEdit.styles.js.map +1 -1
  87. package/lib/components/Link/Link.d.ts +7 -2
  88. package/lib/components/Link/Link.d.ts.map +1 -1
  89. package/lib/components/Link/Link.js +45 -20
  90. package/lib/components/Link/Link.js.map +1 -1
  91. package/lib/components/Link/Link.test-ids.d.ts +1 -1
  92. package/lib/components/Link/Link.test-ids.d.ts.map +1 -1
  93. package/lib/components/Link/Link.test-ids.js +2 -1
  94. package/lib/components/Link/Link.test-ids.js.map +1 -1
  95. package/lib/components/ListToolbar/ListToolbar.styles.d.ts +19 -3
  96. package/lib/components/ListToolbar/ListToolbar.styles.d.ts.map +1 -1
  97. package/lib/components/Menu/FlyoutMenuList.d.ts.map +1 -1
  98. package/lib/components/Menu/FlyoutMenuList.js +1 -1
  99. package/lib/components/Menu/FlyoutMenuList.js.map +1 -1
  100. package/lib/components/Menu/Menu.js +2 -1
  101. package/lib/components/Menu/Menu.js.map +1 -1
  102. package/lib/components/MenuButton/MenuButton.d.ts.map +1 -1
  103. package/lib/components/MenuButton/MenuButton.js +5 -1
  104. package/lib/components/MenuButton/MenuButton.js.map +1 -1
  105. package/lib/components/Popover/getResolvedTarget.d.ts +11 -0
  106. package/lib/components/Popover/getResolvedTarget.d.ts.map +1 -0
  107. package/lib/components/Popover/getResolvedTarget.js +13 -0
  108. package/lib/components/Popover/getResolvedTarget.js.map +1 -0
  109. package/lib/components/Popover/index.d.ts +1 -0
  110. package/lib/components/Popover/index.d.ts.map +1 -1
  111. package/lib/components/Popover/index.js +1 -0
  112. package/lib/components/Popover/index.js.map +1 -1
  113. package/lib/components/QRCode/QRCode.d.ts.map +1 -1
  114. package/lib/components/QRCode/QRCode.js +2 -0
  115. package/lib/components/QRCode/QRCode.js.map +1 -1
  116. package/lib/components/Tooltip/Tooltip.d.ts.map +1 -1
  117. package/lib/components/Tooltip/Tooltip.js +8 -2
  118. package/lib/components/Tooltip/Tooltip.js.map +1 -1
  119. package/lib/hooks/useI18n.d.ts +18 -0
  120. package/lib/hooks/useI18n.d.ts.map +1 -1
  121. package/lib/i18n/default.d.ts +18 -0
  122. package/lib/i18n/default.d.ts.map +1 -1
  123. package/lib/i18n/default.js +23 -3
  124. package/lib/i18n/default.js.map +1 -1
  125. package/lib/i18n/i18n.d.ts +18 -0
  126. package/lib/i18n/i18n.d.ts.map +1 -1
  127. package/lib/theme/theme.d.ts +25 -0
  128. package/lib/theme/theme.d.ts.map +1 -1
  129. package/lib/theme/themeDefinition.json +18 -3
  130. package/lib/theme/themeOverrides.schema.json +16 -0
  131. package/package.json +1 -1
@@ -0,0 +1,562 @@
1
+ import styled, { css } from 'styled-components';
2
+ import { useContext } from 'react';
3
+ import { defaultThemeProp } from '../../theme';
4
+ import { StyledIcon } from '../Icon';
5
+ import Button from '../Button';
6
+ import MenuButton from '../MenuButton';
7
+ import Flex from '../Flex';
8
+ import AppShellContext from './AppShellContext';
9
+ export const getDocumentTabsVariant = (theme) => {
10
+ const value = theme.components?.['app-shell']?.['document-tabs']?.variant;
11
+ return value === 'segmented' || value === 'anchored' || value === 'underline' ? value : 'folder';
12
+ };
13
+ const getVariant = getDocumentTabsVariant;
14
+ const MAX_TAB_WIDTH = '12rem';
15
+ const getTabFill = (theme) => theme.components?.['app-shell']?.['document-tabs']?.fill ?? theme.base.palette['app-background'];
16
+ /**
17
+ * Each variant returns the CSS slices that customize the tab strip.
18
+ * All values come from theme tokens (spacing, palette, radius, shadow) —
19
+ * no hard-coded pixel values from any specific design frame.
20
+ */
21
+ /**
22
+ * Shared spacing tokens for tabs. Kept in one place so nudging padding /
23
+ * gap / max-width once affects all variants.
24
+ */
25
+ const tabTokens = (theme) => {
26
+ const { spacing } = theme.base;
27
+ return {
28
+ tabPaddingInline: `calc(1.5 * ${spacing})`
29
+ };
30
+ };
31
+ /**
32
+ * CSS slices shared by every variant. Individual variants layer their own
33
+ * background, radius, padding, and active-state visuals on top.
34
+ */
35
+ const baseVariantStyles = (theme) => {
36
+ const { palette, 'border-radius': borderRadius } = theme.base;
37
+ const { tabPaddingInline } = tabTokens(theme);
38
+ return {
39
+ container: css `
40
+ background-color: ${palette['secondary-background']};
41
+ `,
42
+ tab: css `
43
+ padding-inline: ${tabPaddingInline};
44
+
45
+ &:hover {
46
+ background-color: ${palette['primary-background']};
47
+ }
48
+
49
+ /* Outset outline around the tab body. z-index lifts the tab above the
50
+ panel below so the outline is not clipped where they overlap. */
51
+ &:focus-visible {
52
+ outline: 0.125rem solid ${palette.interactive};
53
+ outline-offset: 0.0625rem;
54
+ box-shadow: none;
55
+ position: relative;
56
+ z-index: 3;
57
+ }
58
+
59
+ /* Active folder tab has top-only rounded corners and scoop pseudos
60
+ that weld it into the panel below. On focus, round all corners and
61
+ hide the scoops so the tab reads as a standalone pill — matching
62
+ the non-active tab focus shape. */
63
+ &[aria-selected='true']:focus-visible {
64
+ border-radius: ${borderRadius};
65
+ }
66
+ &[aria-selected='true']:focus-visible::before,
67
+ &[aria-selected='true']:focus-visible::after {
68
+ display: none;
69
+ }
70
+ `,
71
+ activeIcon: css `
72
+ ${StyledIcon} {
73
+ color: ${palette['foreground-color']};
74
+ opacity: 1;
75
+ }
76
+ `
77
+ };
78
+ };
79
+ /**
80
+ * Shared "browser-tab" shape used by anchored + folder variants.
81
+ * The tab has a filled body that grows into the container's bottom edge on
82
+ * active state, with two outward-curving scoop pseudos that visually flow
83
+ * into the panel below.
84
+ *
85
+ * @param fill Background color for the active tab and its scoops.
86
+ * @param onFill Text/icon color when the tab is active.
87
+ * @param inactiveFill Background color for inactive tabs.
88
+ * @param fontWeight Active tab font weight.
89
+ */
90
+ const browserTabStyles = (theme, { fill, onFill, inactiveFill, fontWeight }) => {
91
+ const { palette, spacing, 'border-radius': borderRadius } = theme.base;
92
+ const base = baseVariantStyles(theme);
93
+ return {
94
+ container: css `
95
+ ${base.container}
96
+ --tab-height: 2rem;
97
+ align-items: flex-end;
98
+ padding-block-start: calc(0.375 * ${spacing});
99
+ padding-inline: ${spacing};
100
+ gap: calc(0.5 * ${spacing});
101
+
102
+ &[data-overflowing='true'] {
103
+ padding-block-start: ${spacing};
104
+ }
105
+
106
+ /* Home is the leftmost tab and has no neighbor to weld into on its
107
+ left side. Hide the ::before scoop so it doesn't curve into empty
108
+ space against the nav. */
109
+ [id='document-tab-home']::before {
110
+ display: none;
111
+ }
112
+ `,
113
+ tab: css `
114
+ ${base.tab}
115
+ height: calc(var(--tab-height) - 0.4375rem);
116
+ margin-block-end: 0.3125rem;
117
+ background-color: ${inactiveFill};
118
+ color: ${palette['foreground-color']};
119
+ opacity: 0.9;
120
+ border-radius: ${borderRadius};
121
+
122
+ &:hover,
123
+ &:focus-visible {
124
+ opacity: 1;
125
+ }
126
+ `,
127
+ active: css `
128
+ background-color: ${fill};
129
+ color: ${onFill};
130
+ opacity: 1;
131
+ font-weight: ${fontWeight};
132
+ height: calc(var(--tab-height) - 0.125rem);
133
+ border-radius: ${borderRadius} ${borderRadius} 0 0;
134
+ margin-block-end: 0;
135
+ padding-block-end: 0.3125rem;
136
+ position: relative;
137
+ overflow: visible;
138
+ z-index: 1;
139
+
140
+ &::before,
141
+ &::after {
142
+ content: '';
143
+ position: absolute;
144
+ inset-block-end: 0;
145
+ width: 1.125rem;
146
+ height: 1.125rem;
147
+ pointer-events: none;
148
+ }
149
+
150
+ &::before {
151
+ inset-inline-start: -1.125rem;
152
+ border-end-end-radius: 0.8125rem;
153
+ box-shadow: 0.45rem 0.05rem 0 ${fill};
154
+ }
155
+
156
+ &::after {
157
+ inset-inline-end: -1.125rem;
158
+ border-end-start-radius: 0.8125rem;
159
+ box-shadow: -0.45rem 0.05rem 0 ${fill};
160
+ }
161
+
162
+ ${StyledIcon} {
163
+ color: ${onFill};
164
+ opacity: 1;
165
+ }
166
+
167
+ &:hover {
168
+ background-color: ${fill};
169
+ }
170
+ `
171
+ };
172
+ };
173
+ const variantStyles = (variant, theme) => {
174
+ const { palette, spacing } = theme.base;
175
+ const base = baseVariantStyles(theme);
176
+ switch (variant) {
177
+ case 'segmented':
178
+ return {
179
+ container: css `
180
+ ${base.container}
181
+ padding-block: calc(0.125 * ${spacing});
182
+ padding-inline: calc(0.75 * ${spacing});
183
+ border-radius: calc(var(--tab-height) / 2);
184
+ align-self: center;
185
+ flex-grow: 0;
186
+ `,
187
+ tab: css `
188
+ ${base.tab}
189
+ border-radius: calc(var(--tab-height) / 2);
190
+ `,
191
+ active: css `
192
+ background-color: ${palette['primary-background']};
193
+ color: ${palette['foreground-color']};
194
+ opacity: 1;
195
+ font-weight: 500;
196
+ border: 0.0625rem solid ${palette['border-line']};
197
+
198
+ ${StyledIcon} {
199
+ color: ${palette.interactive};
200
+ opacity: 1;
201
+ }
202
+
203
+ &:hover {
204
+ background-color: ${palette['primary-background']};
205
+ }
206
+ `
207
+ };
208
+ case 'anchored':
209
+ return browserTabStyles(theme, {
210
+ fill: palette.interactive,
211
+ onFill: palette['primary-background'],
212
+ inactiveFill: palette['primary-background'],
213
+ fontWeight: 500
214
+ });
215
+ case 'folder': {
216
+ // Folder tabs read as one flat surface — active and inactive share
217
+ // the same fill; active state is signaled by the scoop pseudos welding
218
+ // it into the panel below rather than by a distinct color.
219
+ const tabFill = getTabFill(theme);
220
+ return browserTabStyles(theme, {
221
+ fill: tabFill,
222
+ onFill: palette['foreground-color'],
223
+ inactiveFill: tabFill,
224
+ fontWeight: 600
225
+ });
226
+ }
227
+ case 'underline':
228
+ default:
229
+ return {
230
+ container: css `
231
+ ${base.container}
232
+ padding-block: calc(0.5 * ${spacing});
233
+ border-block-end: 0.0625rem solid ${palette['border-line']};
234
+ `,
235
+ tab: css `
236
+ ${base.tab}
237
+ `,
238
+ active: css `
239
+ background-color: ${palette['primary-background']};
240
+ color: ${palette['foreground-color']};
241
+ opacity: 1;
242
+ font-weight: 500;
243
+ box-shadow: 0 calc(-0.125 * ${spacing}) 0 0 ${palette['foreground-color']} inset;
244
+
245
+ ${base.activeIcon}
246
+
247
+ &:hover {
248
+ background-color: ${palette['primary-background']};
249
+ }
250
+ `
251
+ };
252
+ }
253
+ };
254
+ export const documentTabsHeight = '2.25rem';
255
+ export const StyledDocumentTabsContainer = styled(Flex)(({ theme }) => {
256
+ const { spacing } = theme.base;
257
+ const variant = getVariant(theme);
258
+ const { isMobileNav, isTopBar } = useContext(AppShellContext);
259
+ return css `
260
+ --tab-height: ${documentTabsHeight};
261
+ position: sticky;
262
+ top: calc(var(--appshell-top-offset, 0rem) - var(--document-tabs-height, 0rem));
263
+
264
+ /* Sit above CaseView's own sticky wrappers (which use z-index: 1) and
265
+ similar low-z content so case-content doesn't bleed through the tab
266
+ strip background. */
267
+ z-index: ${theme.base['z-index'].popover};
268
+ align-items: stretch;
269
+ gap: calc(0.25 * ${spacing});
270
+ background-color: transparent;
271
+ min-height: ${documentTabsHeight};
272
+ overflow: visible;
273
+ margin-inline-start: ${isMobileNav || isTopBar ? 0 : 'var(--appshell-horizontal-offset, 0)'};
274
+ transition: margin-inline-start
275
+ ${`${theme.base.animation.speed} ${theme.base.animation.timing.ease}`};
276
+
277
+ ${variantStyles(variant, theme).container}
278
+ `;
279
+ });
280
+ StyledDocumentTabsContainer.defaultProps = defaultThemeProp;
281
+ export const StyledDocumentTabButton = styled.button
282
+ .attrs({ type: 'button' })
283
+ .withConfig({ shouldForwardProp: prop => !['hasClose'].includes(prop) })(({ hasClose, theme }) => {
284
+ const { palette, spacing } = theme.base;
285
+ const variant = getVariant(theme);
286
+ return css `
287
+ display: flex;
288
+ align-items: center;
289
+ justify-content: center;
290
+ gap: calc(0.5 * ${spacing});
291
+ box-sizing: border-box;
292
+ height: 100%;
293
+ padding-block: 0;
294
+ border: none;
295
+ background-color: transparent;
296
+ color: ${palette['foreground-color']};
297
+ opacity: 0.7;
298
+ cursor: pointer;
299
+ position: relative;
300
+ max-width: ${MAX_TAB_WIDTH};
301
+ font: inherit;
302
+ text-align: start;
303
+ text-decoration: none;
304
+ transition:
305
+ background-color 120ms ease,
306
+ color 120ms ease,
307
+ opacity 120ms ease;
308
+
309
+ ${StyledIcon} {
310
+ flex-shrink: 0;
311
+ font-size: 1rem;
312
+ opacity: 0.75;
313
+ }
314
+
315
+ &:hover {
316
+ opacity: 1;
317
+
318
+ ${StyledIcon} {
319
+ opacity: 1;
320
+ }
321
+ }
322
+
323
+ ${variantStyles(variant, theme).tab}
324
+
325
+ /* Layered after the variant's shorthand padding-inline so the extra
326
+ right-side room reserved for the close overlay wins the cascade. */
327
+ ${hasClose &&
328
+ css `
329
+ padding-inline-end: calc(1.5rem + ${spacing});
330
+ `}
331
+ `;
332
+ });
333
+ StyledDocumentTabButton.defaultProps = defaultThemeProp;
334
+ /**
335
+ * Absolute-positioned wrapper that overlays the close Button on the tab's
336
+ * inline-end padding. Button has intrinsic min-width/min-height we can't
337
+ * reliably override for tight overlays, so the wrapper handles geometry
338
+ * (flex-centered vertically, full item height) and the Button lives
339
+ * naturally inside.
340
+ */
341
+ export const StyledDocumentTabCloseAnchor = styled.span(({ theme }) => {
342
+ const { spacing } = theme.base;
343
+ return css `
344
+ position: absolute;
345
+ inset-inline-end: calc(0.5 * ${spacing});
346
+ inset-block: 0;
347
+ display: flex;
348
+ align-items: center;
349
+
350
+ /* Sits above the focused tab button (which bumps to z-index: 3 for
351
+ its outline) so the × stays visible while focused. */
352
+ z-index: 4;
353
+ `;
354
+ });
355
+ StyledDocumentTabCloseAnchor.defaultProps = defaultThemeProp;
356
+ export const StyledDocumentTabItem = styled.div.withConfig({
357
+ shouldForwardProp: prop => !['isActive', 'isDropBefore', 'isDragging'].includes(prop)
358
+ })(({ isActive, isDropBefore, isDragging, theme }) => {
359
+ const { palette } = theme.base;
360
+ const variant = getVariant(theme);
361
+ return css `
362
+ flex-shrink: 0;
363
+ white-space: nowrap;
364
+ position: relative;
365
+ display: flex;
366
+ align-items: stretch;
367
+ opacity: ${isDragging ? 0.5 : 1};
368
+
369
+ ${isDropBefore &&
370
+ css `
371
+ &::before {
372
+ content: '';
373
+ position: absolute;
374
+ inset-block: 0.25rem;
375
+ inset-inline-start: -0.0625rem;
376
+ width: 0.125rem;
377
+ background-color: ${palette.interactive};
378
+ border-radius: 0.125rem;
379
+ z-index: 2;
380
+ }
381
+ `}
382
+
383
+ ${StyledDocumentTabButton} {
384
+ ${isActive && variantStyles(variant, theme).active}
385
+ }
386
+
387
+ /* Folder/anchored variants size the row to the active tab (which is
388
+ taller than inactive tabs, and adds padding-block-end on active),
389
+ so the label's optical center sits ~0.3125rem above the row's
390
+ geometric center. Mirror that inset on the close anchor so the ×
391
+ stays optically aligned on every tab in these variants. */
392
+ ${(variant === 'folder' || variant === 'anchored') &&
393
+ css `
394
+ & > ${StyledDocumentTabCloseAnchor} {
395
+ inset-block-end: 0.3125rem;
396
+ }
397
+ `}
398
+ `;
399
+ });
400
+ StyledDocumentTabItem.defaultProps = defaultThemeProp;
401
+ export const StyledDocumentTabList = styled.div(({ theme }) => {
402
+ const { spacing } = theme.base;
403
+ const variant = getVariant(theme);
404
+ const gap = variant === 'segmented' || variant === 'anchored' || variant === 'folder'
405
+ ? `calc(1.5 * ${spacing})`
406
+ : `calc(0.5 * ${spacing})`;
407
+ return css `
408
+ position: relative;
409
+ display: flex;
410
+ align-items: stretch;
411
+ flex-grow: 1;
412
+ min-width: 0;
413
+ gap: ${gap};
414
+ overflow-x: auto;
415
+ overflow-y: hidden;
416
+ margin: 0;
417
+
418
+ /* Padding + negative margin gives the focused-tab pill outline (which
419
+ extends outside the tab body on all sides) room to render inside the
420
+ scroll clip. Negative margins cancel the padding so surrounding
421
+ layout stays put. */
422
+ padding-block-start: 0.5rem;
423
+ padding-block-end: 0.25rem;
424
+ padding-inline: 0.25rem;
425
+ margin-block-start: -0.5rem;
426
+ margin-block-end: -0.25rem;
427
+ margin-inline: -0.25rem;
428
+ `;
429
+ });
430
+ StyledDocumentTabList.defaultProps = defaultThemeProp;
431
+ export const StyledDocumentTabLabel = styled.span `
432
+ overflow: hidden;
433
+ text-overflow: ellipsis;
434
+ min-width: 0;
435
+ `;
436
+ StyledDocumentTabLabel.defaultProps = defaultThemeProp;
437
+ export const StyledDocumentTabClose = styled(Button)(({ theme: { base: { palette, 'border-radius': borderRadius } } }) => {
438
+ return css `
439
+ padding: 0 !important;
440
+ width: 1.5rem !important;
441
+ height: 1.5rem !important;
442
+ min-width: 0 !important;
443
+ min-height: 0 !important;
444
+ border-radius: ${borderRadius};
445
+ opacity: 1;
446
+
447
+ /* Override Button's built-in icon-hover ::before (a currentColor overlay
448
+ positioned at negative inset around the whole 24×24 box) with a
449
+ smaller inset chrome so hover doesn't touch the tab's block edges.
450
+ The 24×24 button remains the pointer target for WCAG 2.5.8. */
451
+ &:hover::before,
452
+ &:active::before {
453
+ top: 0.1875rem !important;
454
+ right: 0.1875rem !important;
455
+ bottom: 0.1875rem !important;
456
+ left: 0.1875rem !important;
457
+ background-color: ${palette['border-line']} !important;
458
+ opacity: 1 !important;
459
+ z-index: -1 !important;
460
+ }
461
+
462
+ ${StyledIcon} {
463
+ font-size: 0.625rem;
464
+ width: 0.625rem;
465
+ height: 0.625rem;
466
+ opacity: 1;
467
+ }
468
+
469
+ svg {
470
+ width: 0.625rem !important;
471
+ height: 0.625rem !important;
472
+ }
473
+ `;
474
+ });
475
+ StyledDocumentTabClose.defaultProps = defaultThemeProp;
476
+ export const StyledOverflowTabMenu = styled(MenuButton)(({ theme }) => {
477
+ const variant = getVariant(theme);
478
+ return css `
479
+ flex-shrink: 0;
480
+
481
+ /* Folder/anchored containers use align-items: flex-end (tabs sit at
482
+ the container bottom); align the caret button to the top edge of
483
+ that same content area so it lines up with the tab tops rather
484
+ than centering in the taller container box. */
485
+ align-self: ${variant === 'folder' || variant === 'anchored' ? 'flex-start' : 'center'};
486
+ `;
487
+ });
488
+ StyledOverflowTabMenu.defaultProps = defaultThemeProp;
489
+ /**
490
+ * Inner content wrapper for each tab. Hosts the pseudo-element flares for
491
+ * the folder variant's active tab. Because this element is inside the button
492
+ * (which we can't force overflow: visible on without breaking other things),
493
+ * the flares live here and can escape their box without fighting the button's
494
+ * inherited overflow behavior.
495
+ */
496
+ export const StyledDocumentTabAnchor = styled.span(({ theme }) => {
497
+ const { spacing } = theme.base;
498
+ return css `
499
+ display: flex;
500
+ align-items: center;
501
+ gap: calc(0.5 * ${spacing});
502
+ position: relative;
503
+ overflow: visible;
504
+
505
+ /* Fill the button so pseudo-flares sit at the button's true edges. */
506
+ align-self: stretch;
507
+ flex: 1;
508
+
509
+ /* Allow the anchor to shrink below its intrinsic content width so the
510
+ label inside can ellipsize when the button hits its max-width cap. */
511
+ min-width: 0;
512
+ `;
513
+ });
514
+ StyledDocumentTabAnchor.defaultProps = defaultThemeProp;
515
+ /**
516
+ * Wrapper for AppShell main content when the tab strip is visible. Certain
517
+ * variants (anchored, folder) require a themed content panel below the tab
518
+ * strip so the active tab can "attach" to it. For other variants this is a
519
+ * transparent pass-through so surrounding layout is unchanged.
520
+ */
521
+ export const StyledDocumentTabPanel = styled.div(({ theme }) => {
522
+ const { palette, spacing, 'border-radius': borderRadius } = theme.base;
523
+ const variant = getVariant(theme);
524
+ switch (variant) {
525
+ case 'anchored':
526
+ return css `
527
+ display: flex;
528
+ flex-direction: column;
529
+ flex: 1;
530
+ min-height: 0;
531
+ background-color: ${palette['primary-background']};
532
+ border-block-start: calc(0.375 * ${spacing}) solid ${palette.interactive};
533
+ border-radius: ${borderRadius} ${borderRadius} 0 0;
534
+ margin-inline: ${spacing};
535
+ `;
536
+ case 'folder':
537
+ return css `
538
+ display: flex;
539
+ flex-direction: column;
540
+ flex: 1;
541
+ min-height: 0;
542
+ background-color: ${palette['primary-background']};
543
+
544
+ /* Top corners are flat so the tab strip welds cleanly into the panel;
545
+ a rounded top-right exposes a curved sliver of the container
546
+ background above the scrollbar when tabs overflow. */
547
+ border-radius: 0;
548
+ margin-block-end: ${spacing};
549
+ `;
550
+ case 'underline':
551
+ case 'segmented':
552
+ default:
553
+ return css `
554
+ display: flex;
555
+ flex-direction: column;
556
+ flex: 1;
557
+ min-height: 0;
558
+ `;
559
+ }
560
+ });
561
+ StyledDocumentTabPanel.defaultProps = defaultThemeProp;
562
+ //# sourceMappingURL=DocumentTabs.styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DocumentTabs.styles.js","sourceRoot":"","sources":["../../../src/components/AppShell/DocumentTabs.styles.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,EAAE,EAAE,GAAG,EAAqB,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAEnC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,MAAM,MAAM,WAAW,CAAC;AAC/B,OAAO,UAAU,MAAM,eAAe,CAAC;AACvC,OAAO,IAAI,MAAM,SAAS,CAAC;AAE3B,OAAO,eAAe,MAAM,mBAAmB,CAAC;AAIhD,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,KAAmB,EAAuB,EAAE;IACjF,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1E,OAAO,KAAK,KAAK,WAAW,IAAI,KAAK,KAAK,UAAU,IAAI,KAAK,KAAK,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AACnG,CAAC,CAAC;AAEF,MAAM,UAAU,GAAG,sBAAsB,CAAC;AAE1C,MAAM,aAAa,GAAG,OAAO,CAAC;AAE9B,MAAM,UAAU,GAAG,CAAC,KAAmB,EAAU,EAAE,CACjD,KAAK,CAAC,UAAU,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,eAAe,CAAC,EAAE,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;AAEnG;;;;GAIG;AAEH;;;GAGG;AACH,MAAM,SAAS,GAAG,CAAC,KAAmB,EAAE,EAAE;IACxC,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC;IAC/B,OAAO;QACL,gBAAgB,EAAE,cAAc,OAAO,GAAG;KAC3C,CAAC;AACJ,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,iBAAiB,GAAG,CAAC,KAAmB,EAAE,EAAE;IAChD,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC;IAC9D,MAAM,EAAE,gBAAgB,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAC9C,OAAO;QACL,SAAS,EAAE,GAAG,CAAA;0BACQ,OAAO,CAAC,sBAAsB,CAAC;KACpD;QACD,GAAG,EAAE,GAAG,CAAA;wBACY,gBAAgB;;;4BAGZ,OAAO,CAAC,oBAAoB,CAAC;;;;;;kCAMvB,OAAO,CAAC,WAAW;;;;;;;;;;;;yBAY5B,YAAY;;;;;;KAMhC;QACD,UAAU,EAAE,GAAG,CAAA;QACX,UAAU;iBACD,OAAO,CAAC,kBAAkB,CAAC;;;KAGvC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,gBAAgB,GAAG,CACvB,KAAmB,EACnB,EACE,IAAI,EACJ,MAAM,EACN,YAAY,EACZ,UAAU,EAMX,EACD,EAAE;IACF,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC;IACvE,MAAM,IAAI,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;IACtC,OAAO;QACL,SAAS,EAAE,GAAG,CAAA;QACV,IAAI,CAAC,SAAS;;;0CAGoB,OAAO;wBACzB,OAAO;wBACP,OAAO;;;+BAGA,OAAO;;;;;;;;;KASjC;QACD,GAAG,EAAE,GAAG,CAAA;QACJ,IAAI,CAAC,GAAG;;;0BAGU,YAAY;eACvB,OAAO,CAAC,kBAAkB,CAAC;;uBAEnB,YAAY;;;;;;KAM9B;QACD,MAAM,EAAE,GAAG,CAAA;0BACW,IAAI;eACf,MAAM;;qBAEA,UAAU;;uBAER,YAAY,IAAI,YAAY;;;;;;;;;;;;;;;;;;;;wCAoBX,IAAI;;;;;;yCAMH,IAAI;;;QAGrC,UAAU;iBACD,MAAM;;;;;4BAKK,IAAI;;KAE3B;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,CAAC,OAA4B,EAAE,KAAmB,EAAE,EAAE;IAC1E,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC;IACxC,MAAM,IAAI,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;IAEtC,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,WAAW;YACd,OAAO;gBACL,SAAS,EAAE,GAAG,CAAA;YACV,IAAI,CAAC,SAAS;wCACc,OAAO;wCACP,OAAO;;;;SAItC;gBACD,GAAG,EAAE,GAAG,CAAA;YACJ,IAAI,CAAC,GAAG;;SAEX;gBACD,MAAM,EAAE,GAAG,CAAA;8BACW,OAAO,CAAC,oBAAoB,CAAC;mBACxC,OAAO,CAAC,kBAAkB,CAAC;;;oCAGV,OAAO,CAAC,aAAa,CAAC;;YAE9C,UAAU;qBACD,OAAO,CAAC,WAAW;;;;;gCAKR,OAAO,CAAC,oBAAoB,CAAC;;SAEpD;aACF,CAAC;QACJ,KAAK,UAAU;YACb,OAAO,gBAAgB,CAAC,KAAK,EAAE;gBAC7B,IAAI,EAAE,OAAO,CAAC,WAAW;gBACzB,MAAM,EAAE,OAAO,CAAC,oBAAoB,CAAC;gBACrC,YAAY,EAAE,OAAO,CAAC,oBAAoB,CAAC;gBAC3C,UAAU,EAAE,GAAG;aAChB,CAAC,CAAC;QACL,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,mEAAmE;YACnE,uEAAuE;YACvE,2DAA2D;YAC3D,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;YAClC,OAAO,gBAAgB,CAAC,KAAK,EAAE;gBAC7B,IAAI,EAAE,OAAO;gBACb,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC;gBACnC,YAAY,EAAE,OAAO;gBACrB,UAAU,EAAE,GAAG;aAChB,CAAC,CAAC;QACL,CAAC;QACD,KAAK,WAAW,CAAC;QACjB;YACE,OAAO;gBACL,SAAS,EAAE,GAAG,CAAA;YACV,IAAI,CAAC,SAAS;sCACY,OAAO;8CACC,OAAO,CAAC,aAAa,CAAC;SAC3D;gBACD,GAAG,EAAE,GAAG,CAAA;YACJ,IAAI,CAAC,GAAG;SACX;gBACD,MAAM,EAAE,GAAG,CAAA;8BACW,OAAO,CAAC,oBAAoB,CAAC;mBACxC,OAAO,CAAC,kBAAkB,CAAC;;;wCAGN,OAAO,SAAS,OAAO,CAAC,kBAAkB,CAAC;;YAEvE,IAAI,CAAC,UAAU;;;gCAGK,OAAO,CAAC,oBAAoB,CAAC;;SAEpD;aACF,CAAC;IACN,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,SAAS,CAAC;AAE5C,MAAM,CAAC,MAAM,2BAA2B,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;IACpE,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC;IAC/B,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAClC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,UAAU,CAAC,eAAe,CAAC,CAAC;IAC9D,OAAO,GAAG,CAAA;oBACQ,kBAAkB;;;;;;;eAOvB,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO;;uBAErB,OAAO;;kBAEZ,kBAAkB;;2BAET,WAAW,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,sCAAsC;;QAEvF,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE;;MAErE,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,SAAS;GAC1C,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,2BAA2B,CAAC,YAAY,GAAG,gBAAgB,CAAC;AAE5D,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC,MAAM;KACjD,KAAK,CAAC,EAAE,IAAI,EAAE,QAAiB,EAAE,CAAC;KAClC,UAAU,CAAC,EAAE,iBAAiB,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CACxE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE;IACtB,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC;IACxC,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAClC,OAAO,GAAG,CAAA;;;;wBAIU,OAAO;;;;;;eAMhB,OAAO,CAAC,kBAAkB,CAAC;;;;mBAIvB,aAAa;;;;;;;;;QASxB,UAAU;;;;;;;;;UASR,UAAU;;;;;QAKZ,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,GAAG;;;;MAInC,QAAQ;QACR,GAAG,CAAA;4CACmC,OAAO;OAC5C;KACF,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,uBAAuB,CAAC,YAAY,GAAG,gBAAgB,CAAC;AAExD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;IACpE,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC;IAC/B,OAAO,GAAG,CAAA;;mCAEuB,OAAO;;;;;;;;GAQvC,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,4BAA4B,CAAC,YAAY,GAAG,gBAAgB,CAAC;AAE7D,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC;IACzD,iBAAiB,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;CACtF,CAAC,CAIC,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,EAAE;IACnD,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC;IAC/B,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAClC,OAAO,GAAG,CAAA;;;;;;eAMG,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;;MAE7B,YAAY;QACd,GAAG,CAAA;;;;;;;4BAOqB,OAAO,CAAC,WAAW;;;;KAI1C;;MAEC,uBAAuB;QACrB,QAAQ,IAAI,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,MAAM;;;;;;;;MAQlD,CAAC,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,UAAU,CAAC;QAClD,GAAG,CAAA;YACK,4BAA4B;;;KAGnC;GACF,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,qBAAqB,CAAC,YAAY,GAAG,gBAAgB,CAAC;AAEtD,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;IAC5D,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC;IAC/B,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAClC,MAAM,GAAG,GACP,OAAO,KAAK,WAAW,IAAI,OAAO,KAAK,UAAU,IAAI,OAAO,KAAK,QAAQ;QACvE,CAAC,CAAC,cAAc,OAAO,GAAG;QAC1B,CAAC,CAAC,cAAc,OAAO,GAAG,CAAC;IAC/B,OAAO,GAAG,CAAA;;;;;;WAMD,GAAG;;;;;;;;;;;;;;;GAeX,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,qBAAqB,CAAC,YAAY,GAAG,gBAAgB,CAAC;AAEtD,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC,IAAI,CAAA;;;;CAIhD,CAAC;AAEF,sBAAsB,CAAC,YAAY,GAAG,gBAAgB,CAAC;AAEvD,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EACpD,KAAK,EAAE,EACL,IAAI,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,EACjD,EACF,EAAE,EAAE;IACH,OAAO,GAAG,CAAA;;;;;;qBAMS,YAAY;;;;;;;;;;;;;0BAaP,OAAO,CAAC,aAAa,CAAC;;;;;MAK1C,UAAU;;;;;;;;;;;GAWb,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,sBAAsB,CAAC,YAAY,GAAG,gBAAgB,CAAC;AAEvD,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;IACpE,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAClC,OAAO,GAAG,CAAA;;;;;;;kBAOM,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ;GACvF,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,qBAAqB,CAAC,YAAY,GAAG,gBAAgB,CAAC;AAEtD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;IAC/D,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC;IAC/B,OAAO,GAAG,CAAA;;;sBAGU,OAAO;;;;;;;;;;;GAW1B,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,uBAAuB,CAAC,YAAY,GAAG,gBAAgB,CAAC;AAExD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;IAC7D,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC;IACvE,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAElC,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,UAAU;YACb,OAAO,GAAG,CAAA;;;;;4BAKY,OAAO,CAAC,oBAAoB,CAAC;2CACd,OAAO,WAAW,OAAO,CAAC,WAAW;yBACvD,YAAY,IAAI,YAAY;yBAC5B,OAAO;OACzB,CAAC;QACJ,KAAK,QAAQ;YACX,OAAO,GAAG,CAAA;;;;;4BAKY,OAAO,CAAC,oBAAoB,CAAC;;;;;;4BAM7B,OAAO;OAC5B,CAAC;QACJ,KAAK,WAAW,CAAC;QACjB,KAAK,WAAW,CAAC;QACjB;YACE,OAAO,GAAG,CAAA;;;;;OAKT,CAAC;IACN,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,sBAAsB,CAAC,YAAY,GAAG,gBAAgB,CAAC","sourcesContent":["import styled, { css, type DefaultTheme } from 'styled-components';\nimport { useContext } from 'react';\n\nimport { defaultThemeProp } from '../../theme';\nimport { StyledIcon } from '../Icon';\nimport Button from '../Button';\nimport MenuButton from '../MenuButton';\nimport Flex from '../Flex';\n\nimport AppShellContext from './AppShellContext';\n\nexport type DocumentTabsVariant = 'underline' | 'segmented' | 'anchored' | 'folder';\n\nexport const getDocumentTabsVariant = (theme: DefaultTheme): DocumentTabsVariant => {\n const value = theme.components?.['app-shell']?.['document-tabs']?.variant;\n return value === 'segmented' || value === 'anchored' || value === 'underline' ? value : 'folder';\n};\n\nconst getVariant = getDocumentTabsVariant;\n\nconst MAX_TAB_WIDTH = '12rem';\n\nconst getTabFill = (theme: DefaultTheme): string =>\n theme.components?.['app-shell']?.['document-tabs']?.fill ?? theme.base.palette['app-background'];\n\n/**\n * Each variant returns the CSS slices that customize the tab strip.\n * All values come from theme tokens (spacing, palette, radius, shadow) —\n * no hard-coded pixel values from any specific design frame.\n */\n\n/**\n * Shared spacing tokens for tabs. Kept in one place so nudging padding /\n * gap / max-width once affects all variants.\n */\nconst tabTokens = (theme: DefaultTheme) => {\n const { spacing } = theme.base;\n return {\n tabPaddingInline: `calc(1.5 * ${spacing})`\n };\n};\n\n/**\n * CSS slices shared by every variant. Individual variants layer their own\n * background, radius, padding, and active-state visuals on top.\n */\nconst baseVariantStyles = (theme: DefaultTheme) => {\n const { palette, 'border-radius': borderRadius } = theme.base;\n const { tabPaddingInline } = tabTokens(theme);\n return {\n container: css`\n background-color: ${palette['secondary-background']};\n `,\n tab: css`\n padding-inline: ${tabPaddingInline};\n\n &:hover {\n background-color: ${palette['primary-background']};\n }\n\n /* Outset outline around the tab body. z-index lifts the tab above the\n panel below so the outline is not clipped where they overlap. */\n &:focus-visible {\n outline: 0.125rem solid ${palette.interactive};\n outline-offset: 0.0625rem;\n box-shadow: none;\n position: relative;\n z-index: 3;\n }\n\n /* Active folder tab has top-only rounded corners and scoop pseudos\n that weld it into the panel below. On focus, round all corners and\n hide the scoops so the tab reads as a standalone pill — matching\n the non-active tab focus shape. */\n &[aria-selected='true']:focus-visible {\n border-radius: ${borderRadius};\n }\n &[aria-selected='true']:focus-visible::before,\n &[aria-selected='true']:focus-visible::after {\n display: none;\n }\n `,\n activeIcon: css`\n ${StyledIcon} {\n color: ${palette['foreground-color']};\n opacity: 1;\n }\n `\n };\n};\n\n/**\n * Shared \"browser-tab\" shape used by anchored + folder variants.\n * The tab has a filled body that grows into the container's bottom edge on\n * active state, with two outward-curving scoop pseudos that visually flow\n * into the panel below.\n *\n * @param fill Background color for the active tab and its scoops.\n * @param onFill Text/icon color when the tab is active.\n * @param inactiveFill Background color for inactive tabs.\n * @param fontWeight Active tab font weight.\n */\nconst browserTabStyles = (\n theme: DefaultTheme,\n {\n fill,\n onFill,\n inactiveFill,\n fontWeight\n }: {\n fill: string;\n onFill: string;\n inactiveFill: string;\n fontWeight: number;\n }\n) => {\n const { palette, spacing, 'border-radius': borderRadius } = theme.base;\n const base = baseVariantStyles(theme);\n return {\n container: css`\n ${base.container}\n --tab-height: 2rem;\n align-items: flex-end;\n padding-block-start: calc(0.375 * ${spacing});\n padding-inline: ${spacing};\n gap: calc(0.5 * ${spacing});\n\n &[data-overflowing='true'] {\n padding-block-start: ${spacing};\n }\n\n /* Home is the leftmost tab and has no neighbor to weld into on its\n left side. Hide the ::before scoop so it doesn't curve into empty\n space against the nav. */\n [id='document-tab-home']::before {\n display: none;\n }\n `,\n tab: css`\n ${base.tab}\n height: calc(var(--tab-height) - 0.4375rem);\n margin-block-end: 0.3125rem;\n background-color: ${inactiveFill};\n color: ${palette['foreground-color']};\n opacity: 0.9;\n border-radius: ${borderRadius};\n\n &:hover,\n &:focus-visible {\n opacity: 1;\n }\n `,\n active: css`\n background-color: ${fill};\n color: ${onFill};\n opacity: 1;\n font-weight: ${fontWeight};\n height: calc(var(--tab-height) - 0.125rem);\n border-radius: ${borderRadius} ${borderRadius} 0 0;\n margin-block-end: 0;\n padding-block-end: 0.3125rem;\n position: relative;\n overflow: visible;\n z-index: 1;\n\n &::before,\n &::after {\n content: '';\n position: absolute;\n inset-block-end: 0;\n width: 1.125rem;\n height: 1.125rem;\n pointer-events: none;\n }\n\n &::before {\n inset-inline-start: -1.125rem;\n border-end-end-radius: 0.8125rem;\n box-shadow: 0.45rem 0.05rem 0 ${fill};\n }\n\n &::after {\n inset-inline-end: -1.125rem;\n border-end-start-radius: 0.8125rem;\n box-shadow: -0.45rem 0.05rem 0 ${fill};\n }\n\n ${StyledIcon} {\n color: ${onFill};\n opacity: 1;\n }\n\n &:hover {\n background-color: ${fill};\n }\n `\n };\n};\n\nconst variantStyles = (variant: DocumentTabsVariant, theme: DefaultTheme) => {\n const { palette, spacing } = theme.base;\n const base = baseVariantStyles(theme);\n\n switch (variant) {\n case 'segmented':\n return {\n container: css`\n ${base.container}\n padding-block: calc(0.125 * ${spacing});\n padding-inline: calc(0.75 * ${spacing});\n border-radius: calc(var(--tab-height) / 2);\n align-self: center;\n flex-grow: 0;\n `,\n tab: css`\n ${base.tab}\n border-radius: calc(var(--tab-height) / 2);\n `,\n active: css`\n background-color: ${palette['primary-background']};\n color: ${palette['foreground-color']};\n opacity: 1;\n font-weight: 500;\n border: 0.0625rem solid ${palette['border-line']};\n\n ${StyledIcon} {\n color: ${palette.interactive};\n opacity: 1;\n }\n\n &:hover {\n background-color: ${palette['primary-background']};\n }\n `\n };\n case 'anchored':\n return browserTabStyles(theme, {\n fill: palette.interactive,\n onFill: palette['primary-background'],\n inactiveFill: palette['primary-background'],\n fontWeight: 500\n });\n case 'folder': {\n // Folder tabs read as one flat surface — active and inactive share\n // the same fill; active state is signaled by the scoop pseudos welding\n // it into the panel below rather than by a distinct color.\n const tabFill = getTabFill(theme);\n return browserTabStyles(theme, {\n fill: tabFill,\n onFill: palette['foreground-color'],\n inactiveFill: tabFill,\n fontWeight: 600\n });\n }\n case 'underline':\n default:\n return {\n container: css`\n ${base.container}\n padding-block: calc(0.5 * ${spacing});\n border-block-end: 0.0625rem solid ${palette['border-line']};\n `,\n tab: css`\n ${base.tab}\n `,\n active: css`\n background-color: ${palette['primary-background']};\n color: ${palette['foreground-color']};\n opacity: 1;\n font-weight: 500;\n box-shadow: 0 calc(-0.125 * ${spacing}) 0 0 ${palette['foreground-color']} inset;\n\n ${base.activeIcon}\n\n &:hover {\n background-color: ${palette['primary-background']};\n }\n `\n };\n }\n};\n\nexport const documentTabsHeight = '2.25rem';\n\nexport const StyledDocumentTabsContainer = styled(Flex)(({ theme }) => {\n const { spacing } = theme.base;\n const variant = getVariant(theme);\n const { isMobileNav, isTopBar } = useContext(AppShellContext);\n return css`\n --tab-height: ${documentTabsHeight};\n position: sticky;\n top: calc(var(--appshell-top-offset, 0rem) - var(--document-tabs-height, 0rem));\n\n /* Sit above CaseView's own sticky wrappers (which use z-index: 1) and\n similar low-z content so case-content doesn't bleed through the tab\n strip background. */\n z-index: ${theme.base['z-index'].popover};\n align-items: stretch;\n gap: calc(0.25 * ${spacing});\n background-color: transparent;\n min-height: ${documentTabsHeight};\n overflow: visible;\n margin-inline-start: ${isMobileNav || isTopBar ? 0 : 'var(--appshell-horizontal-offset, 0)'};\n transition: margin-inline-start\n ${`${theme.base.animation.speed} ${theme.base.animation.timing.ease}`};\n\n ${variantStyles(variant, theme).container}\n `;\n});\n\nStyledDocumentTabsContainer.defaultProps = defaultThemeProp;\n\nexport const StyledDocumentTabButton = styled.button\n .attrs({ type: 'button' as const })\n .withConfig({ shouldForwardProp: prop => !['hasClose'].includes(prop) })<{ hasClose?: boolean }>(\n ({ hasClose, theme }) => {\n const { palette, spacing } = theme.base;\n const variant = getVariant(theme);\n return css`\n display: flex;\n align-items: center;\n justify-content: center;\n gap: calc(0.5 * ${spacing});\n box-sizing: border-box;\n height: 100%;\n padding-block: 0;\n border: none;\n background-color: transparent;\n color: ${palette['foreground-color']};\n opacity: 0.7;\n cursor: pointer;\n position: relative;\n max-width: ${MAX_TAB_WIDTH};\n font: inherit;\n text-align: start;\n text-decoration: none;\n transition:\n background-color 120ms ease,\n color 120ms ease,\n opacity 120ms ease;\n\n ${StyledIcon} {\n flex-shrink: 0;\n font-size: 1rem;\n opacity: 0.75;\n }\n\n &:hover {\n opacity: 1;\n\n ${StyledIcon} {\n opacity: 1;\n }\n }\n\n ${variantStyles(variant, theme).tab}\n\n /* Layered after the variant's shorthand padding-inline so the extra\n right-side room reserved for the close overlay wins the cascade. */\n ${hasClose &&\n css`\n padding-inline-end: calc(1.5rem + ${spacing});\n `}\n `;\n }\n);\n\nStyledDocumentTabButton.defaultProps = defaultThemeProp;\n\n/**\n * Absolute-positioned wrapper that overlays the close Button on the tab's\n * inline-end padding. Button has intrinsic min-width/min-height we can't\n * reliably override for tight overlays, so the wrapper handles geometry\n * (flex-centered vertically, full item height) and the Button lives\n * naturally inside.\n */\nexport const StyledDocumentTabCloseAnchor = styled.span(({ theme }) => {\n const { spacing } = theme.base;\n return css`\n position: absolute;\n inset-inline-end: calc(0.5 * ${spacing});\n inset-block: 0;\n display: flex;\n align-items: center;\n\n /* Sits above the focused tab button (which bumps to z-index: 3 for\n its outline) so the × stays visible while focused. */\n z-index: 4;\n `;\n});\n\nStyledDocumentTabCloseAnchor.defaultProps = defaultThemeProp;\n\nexport const StyledDocumentTabItem = styled.div.withConfig({\n shouldForwardProp: prop => !['isActive', 'isDropBefore', 'isDragging'].includes(prop)\n})<{\n isActive?: boolean;\n isDropBefore?: boolean;\n isDragging?: boolean;\n}>(({ isActive, isDropBefore, isDragging, theme }) => {\n const { palette } = theme.base;\n const variant = getVariant(theme);\n return css`\n flex-shrink: 0;\n white-space: nowrap;\n position: relative;\n display: flex;\n align-items: stretch;\n opacity: ${isDragging ? 0.5 : 1};\n\n ${isDropBefore &&\n css`\n &::before {\n content: '';\n position: absolute;\n inset-block: 0.25rem;\n inset-inline-start: -0.0625rem;\n width: 0.125rem;\n background-color: ${palette.interactive};\n border-radius: 0.125rem;\n z-index: 2;\n }\n `}\n\n ${StyledDocumentTabButton} {\n ${isActive && variantStyles(variant, theme).active}\n }\n\n /* Folder/anchored variants size the row to the active tab (which is\n taller than inactive tabs, and adds padding-block-end on active),\n so the label's optical center sits ~0.3125rem above the row's\n geometric center. Mirror that inset on the close anchor so the ×\n stays optically aligned on every tab in these variants. */\n ${(variant === 'folder' || variant === 'anchored') &&\n css`\n & > ${StyledDocumentTabCloseAnchor} {\n inset-block-end: 0.3125rem;\n }\n `}\n `;\n});\n\nStyledDocumentTabItem.defaultProps = defaultThemeProp;\n\nexport const StyledDocumentTabList = styled.div(({ theme }) => {\n const { spacing } = theme.base;\n const variant = getVariant(theme);\n const gap =\n variant === 'segmented' || variant === 'anchored' || variant === 'folder'\n ? `calc(1.5 * ${spacing})`\n : `calc(0.5 * ${spacing})`;\n return css`\n position: relative;\n display: flex;\n align-items: stretch;\n flex-grow: 1;\n min-width: 0;\n gap: ${gap};\n overflow-x: auto;\n overflow-y: hidden;\n margin: 0;\n\n /* Padding + negative margin gives the focused-tab pill outline (which\n extends outside the tab body on all sides) room to render inside the\n scroll clip. Negative margins cancel the padding so surrounding\n layout stays put. */\n padding-block-start: 0.5rem;\n padding-block-end: 0.25rem;\n padding-inline: 0.25rem;\n margin-block-start: -0.5rem;\n margin-block-end: -0.25rem;\n margin-inline: -0.25rem;\n `;\n});\n\nStyledDocumentTabList.defaultProps = defaultThemeProp;\n\nexport const StyledDocumentTabLabel = styled.span`\n overflow: hidden;\n text-overflow: ellipsis;\n min-width: 0;\n`;\n\nStyledDocumentTabLabel.defaultProps = defaultThemeProp;\n\nexport const StyledDocumentTabClose = styled(Button)(({\n theme: {\n base: { palette, 'border-radius': borderRadius }\n }\n}) => {\n return css`\n padding: 0 !important;\n width: 1.5rem !important;\n height: 1.5rem !important;\n min-width: 0 !important;\n min-height: 0 !important;\n border-radius: ${borderRadius};\n opacity: 1;\n\n /* Override Button's built-in icon-hover ::before (a currentColor overlay\n positioned at negative inset around the whole 24×24 box) with a\n smaller inset chrome so hover doesn't touch the tab's block edges.\n The 24×24 button remains the pointer target for WCAG 2.5.8. */\n &:hover::before,\n &:active::before {\n top: 0.1875rem !important;\n right: 0.1875rem !important;\n bottom: 0.1875rem !important;\n left: 0.1875rem !important;\n background-color: ${palette['border-line']} !important;\n opacity: 1 !important;\n z-index: -1 !important;\n }\n\n ${StyledIcon} {\n font-size: 0.625rem;\n width: 0.625rem;\n height: 0.625rem;\n opacity: 1;\n }\n\n svg {\n width: 0.625rem !important;\n height: 0.625rem !important;\n }\n `;\n});\n\nStyledDocumentTabClose.defaultProps = defaultThemeProp;\n\nexport const StyledOverflowTabMenu = styled(MenuButton)(({ theme }) => {\n const variant = getVariant(theme);\n return css`\n flex-shrink: 0;\n\n /* Folder/anchored containers use align-items: flex-end (tabs sit at\n the container bottom); align the caret button to the top edge of\n that same content area so it lines up with the tab tops rather\n than centering in the taller container box. */\n align-self: ${variant === 'folder' || variant === 'anchored' ? 'flex-start' : 'center'};\n `;\n});\n\nStyledOverflowTabMenu.defaultProps = defaultThemeProp;\n\n/**\n * Inner content wrapper for each tab. Hosts the pseudo-element flares for\n * the folder variant's active tab. Because this element is inside the button\n * (which we can't force overflow: visible on without breaking other things),\n * the flares live here and can escape their box without fighting the button's\n * inherited overflow behavior.\n */\nexport const StyledDocumentTabAnchor = styled.span(({ theme }) => {\n const { spacing } = theme.base;\n return css`\n display: flex;\n align-items: center;\n gap: calc(0.5 * ${spacing});\n position: relative;\n overflow: visible;\n\n /* Fill the button so pseudo-flares sit at the button's true edges. */\n align-self: stretch;\n flex: 1;\n\n /* Allow the anchor to shrink below its intrinsic content width so the\n label inside can ellipsize when the button hits its max-width cap. */\n min-width: 0;\n `;\n});\n\nStyledDocumentTabAnchor.defaultProps = defaultThemeProp;\n\n/**\n * Wrapper for AppShell main content when the tab strip is visible. Certain\n * variants (anchored, folder) require a themed content panel below the tab\n * strip so the active tab can \"attach\" to it. For other variants this is a\n * transparent pass-through so surrounding layout is unchanged.\n */\nexport const StyledDocumentTabPanel = styled.div(({ theme }) => {\n const { palette, spacing, 'border-radius': borderRadius } = theme.base;\n const variant = getVariant(theme);\n\n switch (variant) {\n case 'anchored':\n return css`\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n background-color: ${palette['primary-background']};\n border-block-start: calc(0.375 * ${spacing}) solid ${palette.interactive};\n border-radius: ${borderRadius} ${borderRadius} 0 0;\n margin-inline: ${spacing};\n `;\n case 'folder':\n return css`\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n background-color: ${palette['primary-background']};\n\n /* Top corners are flat so the tab strip welds cleanly into the panel;\n a rounded top-right exposes a curved sliver of the container\n background above the scrollbar when tabs overflow. */\n border-radius: 0;\n margin-block-end: ${spacing};\n `;\n case 'underline':\n case 'segmented':\n default:\n return css`\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n `;\n }\n});\n\nStyledDocumentTabPanel.defaultProps = defaultThemeProp;\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"NavigationListItemWrapper.d.ts","sourceRoot":"","sources":["../../../src/components/AppShell/NavigationListItemWrapper.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAe,EAAE,EAAiC,MAAM,OAAO,CAAC;AAmB5E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAkGhE,QAAA,MAAM,eAAe,EAAE,EAAE,CAAC,uBAAuB,CA8QhD,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"NavigationListItemWrapper.d.ts","sourceRoot":"","sources":["../../../src/components/AppShell/NavigationListItemWrapper.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAe,EAAE,EAAiC,MAAM,OAAO,CAAC;AAmB5E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAkGhE,QAAA,MAAM,eAAe,EAAE,EAAE,CAAC,uBAAuB,CA+QhD,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -105,7 +105,7 @@ const StyledNavigationTouchDialog = styled(TouchDialog)(({ theme }) => {
105
105
  StyledNavigationTouchDialog.defaultProps = defaultThemeProp;
106
106
  const ListItemWrapper = props => {
107
107
  const { children, childElementRef, label, tooltipLabel, items, filterAt = 5, content, onMenuToggle, mobileNavBar } = props;
108
- const { navOpen, collapsedHoverMenus, headerEl } = useContext(AppShellContext);
108
+ const { isMobileNav, navOpen, collapsedHoverMenus, headerEl } = useContext(AppShellContext);
109
109
  const popoverRef = useRef(null);
110
110
  const filterElRef = useRef(null);
111
111
  const isMenu = (Array.isArray(items) && items.length > 0) || !!content;
@@ -145,7 +145,7 @@ const ListItemWrapper = props => {
145
145
  useEffect(() => {
146
146
  const onClick = () => {
147
147
  if (isMenu) {
148
- if (!navOpen && !popoverOpen)
148
+ if ((isMobileNav || !navOpen) && !popoverOpen)
149
149
  setPopoverOpen(true);
150
150
  else {
151
151
  setTimeout(() => {
@@ -215,7 +215,7 @@ const ListItemWrapper = props => {
215
215
  hidePopoverTimeout.current = null;
216
216
  }
217
217
  };
218
- }, [isMenu, navOpen, closePopover, collapsedHoverMenus, popoverOpen]);
218
+ }, [isMenu, navOpen, closePopover, collapsedHoverMenus, popoverOpen, isMobileNav]);
219
219
  useEffect(() => {
220
220
  onMenuToggle?.(popoverOpen ? 'open' : 'close');
221
221
  }, [popoverOpen]);
@@ -227,14 +227,15 @@ const ListItemWrapper = props => {
227
227
  return filterRegex.test(item.primary);
228
228
  })
229
229
  : items ?? [];
230
+ const useTouchDialog = mobileNavBar && isTouchDevice;
230
231
  const filterInputProps = renderFilter
231
232
  ? {
232
233
  value: filterValue,
233
234
  ref: filterElRef,
234
- onChange: (e) => setFilterValue(e.target.value)
235
+ onChange: (e) => setFilterValue(e.target.value),
236
+ autoFocus: !useTouchDialog
235
237
  }
236
238
  : undefined;
237
- const useTouchDialog = mobileNavBar && isTouchDevice;
238
239
  const menuContent = content ? (_jsx("div", { onMouseEnter: onMouseEnterContent, onMouseLeave: onMouseLeaveContent, children: content })) : (_jsx(Menu, { mode: 'action', variant: 'flyout', focusControlEl: childElementRef.current ?? undefined, scrollAt: 99, listId: searchListId, filterInputProps: filterInputProps, items: itemsToRender.map(item => {
239
240
  const itemText = 'text' in item && typeof item.text === 'string' ? item.text : '';
240
241
  const itemTextValue = item.primary || itemText;