@crewlethq/ui 0.39.0 → 0.40.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 (90) hide show
  1. package/README.md +47 -1
  2. package/dist/AppShell/AppShell.d.ts +13 -2
  3. package/dist/AppShell/index.js +1 -1
  4. package/dist/{AppShell-NDU4XMGF.css → AppShell-VE2MAV42.css} +71 -7
  5. package/dist/ArtifactBar/index.js +6 -5
  6. package/dist/AvatarPicker/index.js +10 -6
  7. package/dist/CatalogTile/index.js +1 -1
  8. package/dist/{CatalogTile-TGR2ZZVQ.css → CatalogTile-XL4XLFUH.css} +8 -4
  9. package/dist/CharacterPicker/index.js +2 -2
  10. package/dist/Charts/Histogram.d.ts +71 -0
  11. package/dist/Charts/index.d.ts +2 -0
  12. package/dist/Charts/index.js +1 -1
  13. package/dist/{Charts-MBJG72BS.css → Charts-TZ744HT6.css} +118 -0
  14. package/dist/DataGrid/DataGrid.d.ts +267 -0
  15. package/dist/DataGrid/index.d.ts +3 -0
  16. package/dist/DataGrid/index.js +7 -0
  17. package/dist/DataGrid-AQKPJD7W.css +482 -0
  18. package/dist/HuePicker/index.js +11 -4
  19. package/dist/LayersList/index.js +2 -2
  20. package/dist/LockedLabel/LockedLabel.d.ts +34 -0
  21. package/dist/LockedLabel/index.d.ts +3 -0
  22. package/dist/LockedLabel/index.js +3 -0
  23. package/dist/LockedLabel-VQEGEB7G.css +16 -0
  24. package/dist/MarkdownEditor/index.js +8 -5
  25. package/dist/MergeConflicts/index.js +11 -5
  26. package/dist/PageNote/PageNote.d.ts +14 -0
  27. package/dist/PageNote/index.d.ts +3 -0
  28. package/dist/PageNote/index.js +2 -0
  29. package/dist/PageNote-RHLXH3ML.css +12 -0
  30. package/dist/PropertyList/PropertyList.d.ts +88 -0
  31. package/dist/PropertyList/index.d.ts +3 -0
  32. package/dist/PropertyList/index.js +7 -0
  33. package/dist/PropertyList-SCYM66LL.css +96 -0
  34. package/dist/RelatedRow/RelatedRow.d.ts +27 -0
  35. package/dist/RelatedRow/index.d.ts +3 -0
  36. package/dist/RelatedRow/index.js +9 -0
  37. package/dist/RelatedRow-2FVS6QQA.css +6 -0
  38. package/dist/SectionFrame/SectionFrame.d.ts +76 -0
  39. package/dist/SectionFrame/index.d.ts +3 -0
  40. package/dist/SectionFrame/index.js +7 -0
  41. package/dist/SectionFrame-M62UUVFQ.css +164 -0
  42. package/dist/SegmentedControl/index.js +11 -4
  43. package/dist/SheetColumnEditor/index.js +6 -5
  44. package/dist/SheetGrid/index.js +2 -2
  45. package/dist/SidebarNav/SidebarNav.d.ts +35 -2
  46. package/dist/SidebarNav/index.js +2 -1
  47. package/dist/{SidebarNav-7SGUZYKK.css → SidebarNav-YI74SPDC.css} +10 -0
  48. package/dist/Tabs/Tabs.d.ts +55 -1
  49. package/dist/Tabs/fold.d.ts +54 -0
  50. package/dist/Tabs/index.d.ts +1 -1
  51. package/dist/Tabs/index.js +9 -2
  52. package/dist/Tabs/roving.d.ts +3 -3
  53. package/dist/{Tabs-WIF7457H.css → Tabs-S7F4RWAN.css} +77 -0
  54. package/dist/TagsInput/index.js +1 -1
  55. package/dist/ThemeGallery/index.js +2 -2
  56. package/dist/ThemeSwitcher/index.js +12 -5
  57. package/dist/VersionCompare/index.js +12 -5
  58. package/dist/{chunk-B5J23C73.js → chunk-2PEXZ7L4.js} +1 -1
  59. package/dist/{chunk-TZYFTC4M.js → chunk-2VOHUGUA.js} +1 -1
  60. package/dist/{chunk-2QZ2VPHR.js → chunk-4OK4DX3V.js} +2 -2
  61. package/dist/{chunk-ECGGQX2H.js → chunk-A44YHLCQ.js} +2 -2
  62. package/dist/{chunk-F4LPQA4E.js → chunk-BA32AVKS.js} +1 -1
  63. package/dist/chunk-CV4NES3P.js +9 -0
  64. package/dist/{chunk-PPHTIKZO.js → chunk-E4BOVKNJ.js} +1 -1
  65. package/dist/{chunk-W7PAIVAP.js → chunk-E7QLG3PG.js} +30 -9
  66. package/dist/{chunk-RKKO7QHH.js → chunk-EGMQURBR.js} +5 -4
  67. package/dist/{chunk-GMW4ZHST.js → chunk-EX22Q5SH.js} +2 -2
  68. package/dist/{chunk-F3WZ5AKM.js → chunk-GFYQKMQZ.js} +1 -1
  69. package/dist/{chunk-DYB66CNM.js → chunk-GR4YM7HT.js} +6 -3
  70. package/dist/{chunk-HG5VF3TZ.js → chunk-HMVQQEHW.js} +91 -2
  71. package/dist/chunk-INVSUFJK.js +71 -0
  72. package/dist/{chunk-4LRAJXHL.js → chunk-JSWOXRRE.js} +1 -1
  73. package/dist/{chunk-ZMDYQ2HH.js → chunk-KWWP3D7M.js} +1 -1
  74. package/dist/{chunk-46RL3E54.js → chunk-M6NQ4XGK.js} +1 -1
  75. package/dist/chunk-OHGH7O6T.js +19 -0
  76. package/dist/{chunk-4ISUIS6F.js → chunk-OOC7Q67K.js} +1 -1
  77. package/dist/{chunk-XNXK5MA4.js → chunk-PCT47E7O.js} +1 -1
  78. package/dist/{chunk-YEVG2X5R.js → chunk-SNQRGH4A.js} +1 -1
  79. package/dist/chunk-T6MXORP5.js +116 -0
  80. package/dist/chunk-X4IXXLWM.js +306 -0
  81. package/dist/chunk-XIDD7PJO.js +416 -0
  82. package/dist/chunk-ZUTUI27P.js +21 -0
  83. package/dist/generated/index.d.ts +6 -0
  84. package/dist/generated/index.js +62 -56
  85. package/dist/index.js +62 -56
  86. package/dist/styles.css +1087 -20
  87. package/package.json +3 -3
  88. package/dist/chunk-7SDUKCNW.js +0 -141
  89. package/dist/{chunk-JZPK4IXR.js → chunk-DKNBGL26.js} +1 -1
  90. /package/dist/{chunk-QRLIWCLX.js → chunk-S3QTFUJX.js} +0 -0
@@ -7,6 +7,12 @@ import React, { type ReactNode, type Ref } from 'react';
7
7
  */
8
8
  export type TabsVariant = 'pill' | 'underline' | 'chip';
9
9
  export type TabsSize = 'sm' | 'md';
10
+ /**
11
+ * What a row does with tabs it has no room for. `scroll` scrolls the row with
12
+ * its bar hidden; `menu` draws the tabs that fit and folds the rest into a
13
+ * "More" menu at the row's end.
14
+ */
15
+ export type TabsOverflow = 'scroll' | 'menu';
10
16
  export interface TabsItem {
11
17
  /** Stable identity: the value reported, and half of the tab's id. */
12
18
  value: string;
@@ -26,6 +32,18 @@ export interface TabsItem {
26
32
  * replaces the count while it is set. `label` is what a screen reader hears.
27
33
  */
28
34
  marker?: TabsMarker | undefined;
35
+ /**
36
+ * What is happening behind the tab right now, IN WORDS ("running now"):
37
+ * drawn as a pulsing dot in place of the icon and read after the label. The
38
+ * words rather than a flag, so a tab cannot be marked without saying what
39
+ * the mark means; folded into "More", they are the item's second line.
40
+ */
41
+ live?: string | undefined;
42
+ /**
43
+ * How the tab reads folded into "More", where `label` is a node (a label
44
+ * drawn with a lock, say). A string `label` is used as it is.
45
+ */
46
+ menuLabel?: string | undefined;
29
47
  disabled?: boolean;
30
48
  /** Any extra props the consumer's renderItem needs to read. */
31
49
  [key: string]: unknown;
@@ -57,6 +75,20 @@ export interface TabsRenderItemProps {
57
75
  onSelect: () => void;
58
76
  /** Pre-rendered icon, label and count nodes for the tab body. */
59
77
  children: ReactNode;
78
+ /** Folded into "More" (overflow `menu`): drawn there, and kept here only to be measured. */
79
+ folded: boolean;
80
+ /**
81
+ * SPREAD THESE on the element you render. A folded link stays in the row to
82
+ * be measured, and these take it out of reach of the pointer, the keyboard
83
+ * and a screen reader, which meet it in the menu instead. Empty while it is
84
+ * drawn.
85
+ */
86
+ foldProps: TabsFoldProps;
87
+ }
88
+ /** What takes a folded item out of reach. See [TabsRenderItemProps.foldProps]. */
89
+ export interface TabsFoldProps {
90
+ 'aria-hidden'?: true;
91
+ inert?: true;
60
92
  }
61
93
  export interface TabsProps {
62
94
  items: TabsItem[];
@@ -64,6 +96,7 @@ export interface TabsProps {
64
96
  size?: TabsSize;
65
97
  /** Names the row. A tab row with no name is announced as "tab list" alone. */
66
98
  ariaLabel?: string;
99
+ /** On the row's root: the row, or with overflow `menu` on a tab list, the box holding the row and "More". */
67
100
  className?: string;
68
101
  /** Currently active item value. */
69
102
  value?: string;
@@ -89,6 +122,27 @@ export interface TabsProps {
89
122
  * without `renderItem` ignores it.
90
123
  */
91
124
  trailing?: ReactNode;
125
+ /**
126
+ * What the row does with tabs it has no room for. `scroll` (the default)
127
+ * scrolls it. `menu` draws the tabs that FIT, in order, and folds the rest
128
+ * into a "More" menu at its end, each entry with its figure; the tab the
129
+ * reader is on is always drawn, taking the last place that fits. The widths
130
+ * are measured, not guessed, and measured again whenever anything in the
131
+ * row changes size. Choosing an entry calls `onValueChange`, in router mode
132
+ * too, where it is the consumer's navigation.
133
+ */
134
+ overflow?: TabsOverflow | undefined;
135
+ /** The "More" trigger's words. */
136
+ moreLabel?: string | undefined;
137
+ /** The menu's accessible name. Defaults to "More of" the row's `ariaLabel`. */
138
+ moreMenuLabel?: string | undefined;
139
+ /**
140
+ * A sentence about every tab, at the row's far end, overflow `menu` only.
141
+ * It GIVES WAY TO THE TABS: drawn only where every tab fits beside it, and
142
+ * gone before a single tab folds, because a tab is a place and the note is
143
+ * not.
144
+ */
145
+ note?: ReactNode;
92
146
  /**
93
147
  * The row's root element, for a consumer that measures the row: which of
94
148
  * its items fit, and what folds into its trailing menu.
@@ -120,7 +174,7 @@ export declare function tabId(panelId: string, value: string): string;
120
174
  * says. In router mode that IS what the items are, so the root becomes a
121
175
  * `nav`, the tab roles go, and the consumer's own link carries the state.
122
176
  */
123
- export declare function Tabs({ items, variant, size, ariaLabel, className, value, onValueChange, panelId, renderItem, trailing, ref, }: TabsProps): React.JSX.Element;
177
+ export declare function Tabs({ items, variant, size, ariaLabel, className, value, onValueChange, panelId, renderItem, trailing, overflow, moreLabel, moreMenuLabel, note, ref, }: TabsProps): React.JSX.Element;
124
178
  export interface TabPanelProps {
125
179
  /** The same id the row was given as `panelId`. */
126
180
  id: string;
@@ -0,0 +1,54 @@
1
+ import { type RefObject } from 'react';
2
+ /**
3
+ * Which tabs of a row fold into its "More" menu, from their widths: the
4
+ * arithmetic, apart from the DOM it is measured in, so it can be held to its
5
+ * rules directly.
6
+ *
7
+ * `widths` are the tabs' own, in order; `space` is the row's inner width,
8
+ * `gap` the space between two items and `more` the "More" trigger's width.
9
+ * Returns the INDEXES that fold. Everything fits, none. Otherwise the row
10
+ * keeps the tab the reader is on (`current`) and, before it, as long a run of
11
+ * the others FROM THE START as fits beside it and the trigger. A run, never a
12
+ * pick of whichever narrower tabs would squeeze in further along, because a
13
+ * row whose order changes with its width is one a reader cannot learn.
14
+ */
15
+ export declare function foldTabs({ widths, current, space, gap, more, }: {
16
+ widths: readonly number[];
17
+ current: number;
18
+ space: number;
19
+ gap: number;
20
+ more: number;
21
+ }): number[];
22
+ /**
23
+ * Whether a row's note has room at its end BESIDE EVERY TAB.
24
+ *
25
+ * THE TABS COME FIRST. A note is a sentence about how to read the row; a tab
26
+ * is a place. So the note takes no room a tab would need: it is drawn only
27
+ * where every tab fits with it, and gives way before a single tab folds. A
28
+ * note measured at no width is one the page is not drawing, and has nothing
29
+ * to fit.
30
+ */
31
+ export declare function noteFits({ widths, space, gap, note, }: {
32
+ widths: readonly number[];
33
+ space: number;
34
+ gap: number;
35
+ note: number;
36
+ }): boolean;
37
+ /** What a folding row draws: the values that live in "More", and whether its note is shown. */
38
+ export interface Fold {
39
+ folded: readonly string[];
40
+ note: boolean;
41
+ }
42
+ /**
43
+ * The fold of a row, MEASURED after layout and again whenever the row or
44
+ * anything in it changes size: a count arriving, a web font replacing its
45
+ * fallback, a density step.
46
+ *
47
+ * A folded tab STAYS IN THE DOCUMENT, out of the flow and invisible, so its
48
+ * width is known when the row grows again; "More" and the note are always in
49
+ * the document for the same reason. `box` is the element whose inner width is
50
+ * the room the row has; `row` holds the tabs. They are one element for a row
51
+ * of links, and two for a tab list, which holds tabs alone and leaves "More"
52
+ * beside it, where the box's own gap and the row's chrome are counted too.
53
+ */
54
+ export declare function useFold(enabled: boolean, box: RefObject<HTMLElement | null>, row: RefObject<HTMLElement | null>, values: readonly string[], current: string | undefined): Fold;
@@ -1,4 +1,4 @@
1
1
  import '../HitArea/HitArea.css';
2
2
  import './Tabs.css';
3
3
  export { TabPanel, Tabs, tabId } from './Tabs.js';
4
- export type { TabPanelProps, TabsItem, TabsMarker, TabsProps, TabsRenderItemProps, TabsSize, TabsVariant, } from './Tabs.js';
4
+ export type { TabPanelProps, TabsFoldProps, TabsItem, TabsMarker, TabsOverflow, TabsProps, TabsRenderItemProps, TabsSize, TabsVariant, } from './Tabs.js';
@@ -1,6 +1,13 @@
1
- export { TabPanel, Tabs, tabId } from '../chunk-7SDUKCNW.js';
2
- import '../chunk-RKKO7QHH.js';
1
+ export { TabPanel, Tabs, tabId } from '../chunk-X4IXXLWM.js';
2
+ import '../chunk-WIATRXEJ.js';
3
+ import '../chunk-EGMQURBR.js';
3
4
  import '../chunk-BHHIIK3M.js';
5
+ import '../chunk-D6FEHY5G.js';
6
+ import '../chunk-OMV5W53A.js';
7
+ import '../chunk-H5XTJ7GJ.js';
4
8
  import '../chunk-2YTOOH3A.js';
9
+ import '../chunk-OG6CL3EB.js';
10
+ import '../chunk-4FQT6ZAY.js';
11
+ import '../chunk-NUZHC6MM.js';
5
12
  import '../chunk-BZFWDIV6.js';
6
13
  import '../chunk-ODEQTPFM.js';
@@ -63,9 +63,9 @@ export interface RovingOptions {
63
63
  * under manual activation and wants `followFocus`, because the stop and the
64
64
  * selection have come apart; a caller that passes one wants neither.
65
65
  *
66
- * A DISABLED BUTTON IS STEPPED OVER rather than focused: a browser refuses it
67
- * focus, so a move that lands on one drops focus on the page body and the
68
- * next arrow press does nothing at all.
66
+ * A DISABLED OR INERT BUTTON IS STEPPED OVER rather than focused: a browser
67
+ * refuses it focus, so a move that lands on one drops focus on the page body
68
+ * and the next arrow press does nothing at all.
69
69
  */
70
70
  export declare function useRoving(count: number, select: ((index: number) => void) | null, { followFocus, columns }?: RovingOptions): {
71
71
  buttons: import("react").RefObject<(HTMLButtonElement | null)[]>;
@@ -400,6 +400,83 @@
400
400
  display: contents;
401
401
  }
402
402
 
403
+ /* ─── Fold (overflow: menu) ───────────────────────────────────── */
404
+ /*
405
+ * THE ROW NEVER SCROLLS: what does not fit has already left it for "More".
406
+ * A scroll with its bar hidden cut a whole tab off at a phone's edge with
407
+ * nothing to say it was there, and a fade at the edge is too quiet to read as
408
+ * "there is more"; a menu that says More is not.
409
+ */
410
+ .crewlet-tabs--fold {
411
+ position: relative;
412
+ min-width: 0;
413
+ overflow: visible;
414
+ }
415
+
416
+ /*
417
+ * A FOLDED ITEM STAYS IN THE DOCUMENT, out of the flow and invisible, so it
418
+ * can be measured again when the row grows. Pinned to the row's start, inside
419
+ * it, so it can never widen the page. A tab, "More" with nothing in it, and a
420
+ * note with no room alike.
421
+ */
422
+ .crewlet-tabs--fold > .crewlet-tabs__tab.is-folded,
423
+ .crewlet-tabs__more.is-folded,
424
+ .crewlet-tabs__note.is-folded {
425
+ position: absolute;
426
+ inset-block-start: 0;
427
+ inset-inline-start: 0;
428
+ visibility: hidden;
429
+ pointer-events: none;
430
+ }
431
+
432
+ /* "More" is the quiet menu button, centred on the tabs' line. */
433
+ .crewlet-tabs__more {
434
+ display: inline-flex;
435
+ flex: none;
436
+ align-items: center;
437
+ }
438
+
439
+ /* The note sits at the row's far end, a sentence about every tab and never
440
+ one of them. */
441
+ .crewlet-tabs__note {
442
+ flex: none;
443
+ align-self: center;
444
+ margin-inline-start: auto;
445
+ font-size: var(--font-size-xs);
446
+ color: var(--color-text-tertiary);
447
+ white-space: nowrap;
448
+ }
449
+
450
+ .crewlet-tabs__trailing {
451
+ display: inline-flex;
452
+ flex: none;
453
+ align-items: center;
454
+ }
455
+
456
+ /*
457
+ * A TAB LIST HOLDS TABS ALONE, so its "More" stands beside it in a box. The
458
+ * row is as wide as the tabs it draws, and the underline's rule is the box's,
459
+ * painted on its last pixel row (the one the row's own border sits on), so
460
+ * it runs on under "More" to the edge.
461
+ */
462
+ .crewlet-tabs-fold {
463
+ position: relative;
464
+ display: flex;
465
+ align-items: stretch;
466
+ gap: var(--spacing-2);
467
+ min-width: 0;
468
+ }
469
+
470
+ .crewlet-tabs-fold > .crewlet-tabs {
471
+ flex: 0 1 auto;
472
+ width: auto;
473
+ min-width: 0;
474
+ }
475
+
476
+ .crewlet-tabs-fold--underline {
477
+ box-shadow: inset 0 -1px 0 var(--color-border-default);
478
+ }
479
+
403
480
  /*
404
481
  * The slider ARRIVES rather than travels, and a chip changes without a fade.
405
482
  * The indicator still moves; what stops is the animation between the two
@@ -1,7 +1,7 @@
1
1
  export { TagsInput } from '../chunk-BH52LIY6.js';
2
2
  import '../chunk-KYIAFNU7.js';
3
- import '../chunk-WIATRXEJ.js';
4
3
  import '../chunk-7KHM2FZH.js';
4
+ import '../chunk-WIATRXEJ.js';
5
5
  import '../chunk-RSAQOKH3.js';
6
6
  import '../chunk-OMV5W53A.js';
7
7
  import '../chunk-H5XTJ7GJ.js';
@@ -1,7 +1,7 @@
1
- export { ThemeGallery } from '../chunk-PPHTIKZO.js';
1
+ export { ThemeGallery } from '../chunk-E4BOVKNJ.js';
2
2
  import '../chunk-MNFU2RNT.js';
3
3
  import '../chunk-7KHM2FZH.js';
4
- import '../chunk-RKKO7QHH.js';
4
+ import '../chunk-EGMQURBR.js';
5
5
  import '../chunk-H5XTJ7GJ.js';
6
6
  import '../chunk-NUZHC6MM.js';
7
7
  import '../chunk-ODEQTPFM.js';
@@ -1,11 +1,18 @@
1
- export { DensitySwitcher, ThemeSwitcher } from '../chunk-ZMDYQ2HH.js';
1
+ export { DensitySwitcher, ThemeSwitcher } from '../chunk-KWWP3D7M.js';
2
2
  export { applyStoredPreferences, resolveTheme, useDensityPreference, useSystemTheme, useThemePreference } from '../chunk-Z24ZUSTX.js';
3
3
  export { DENSITY_PREFERENCES, PALETTE_ID, THEME_PREFERENCES, applyDensity, applyPalette, applyTheme, isDensityPreference, isPaletteId, isThemePreference } from '../chunk-ZXXDZJQN.js';
4
- import '../chunk-4ISUIS6F.js';
5
- import '../chunk-2QZ2VPHR.js';
6
- import '../chunk-7SDUKCNW.js';
7
- import '../chunk-RKKO7QHH.js';
4
+ import '../chunk-OOC7Q67K.js';
5
+ import '../chunk-4OK4DX3V.js';
6
+ import '../chunk-X4IXXLWM.js';
7
+ import '../chunk-WIATRXEJ.js';
8
+ import '../chunk-EGMQURBR.js';
8
9
  import '../chunk-BHHIIK3M.js';
10
+ import '../chunk-D6FEHY5G.js';
11
+ import '../chunk-OMV5W53A.js';
12
+ import '../chunk-H5XTJ7GJ.js';
9
13
  import '../chunk-2YTOOH3A.js';
14
+ import '../chunk-OG6CL3EB.js';
15
+ import '../chunk-4FQT6ZAY.js';
16
+ import '../chunk-NUZHC6MM.js';
10
17
  import '../chunk-BZFWDIV6.js';
11
18
  import '../chunk-ODEQTPFM.js';
@@ -1,12 +1,19 @@
1
- export { VERSION_COMPARE_LABELS, VERSION_COMPARE_LENSES, VersionCompare } from '../chunk-4LRAJXHL.js';
1
+ export { VERSION_COMPARE_LABELS, VERSION_COMPARE_LENSES, VersionCompare } from '../chunk-JSWOXRRE.js';
2
2
  import '../chunk-BVWSLXTY.js';
3
- import '../chunk-4ISUIS6F.js';
4
- import '../chunk-2QZ2VPHR.js';
5
- import '../chunk-7SDUKCNW.js';
6
- import '../chunk-RKKO7QHH.js';
3
+ import '../chunk-OOC7Q67K.js';
4
+ import '../chunk-4OK4DX3V.js';
5
+ import '../chunk-X4IXXLWM.js';
6
+ import '../chunk-WIATRXEJ.js';
7
+ import '../chunk-EGMQURBR.js';
7
8
  import '../chunk-RA2ULG6H.js';
8
9
  import '../chunk-BHHIIK3M.js';
9
10
  import '../chunk-PQADV6P6.js';
11
+ import '../chunk-D6FEHY5G.js';
12
+ import '../chunk-OMV5W53A.js';
13
+ import '../chunk-H5XTJ7GJ.js';
10
14
  import '../chunk-2YTOOH3A.js';
15
+ import '../chunk-OG6CL3EB.js';
16
+ import '../chunk-4FQT6ZAY.js';
17
+ import '../chunk-NUZHC6MM.js';
11
18
  import '../chunk-BZFWDIV6.js';
12
19
  import '../chunk-ODEQTPFM.js';
@@ -1,4 +1,4 @@
1
- import { SegmentedControl } from './chunk-2QZ2VPHR.js';
1
+ import { SegmentedControl } from './chunk-4OK4DX3V.js';
2
2
  import { Button } from './chunk-OG6CL3EB.js';
3
3
  import { cx } from './chunk-ODEQTPFM.js';
4
4
  import './MergeConflicts-O44ESH4T.css';
@@ -1,4 +1,4 @@
1
- import { SegmentedControl } from './chunk-2QZ2VPHR.js';
1
+ import { SegmentedControl } from './chunk-4OK4DX3V.js';
2
2
  import { Tooltip } from './chunk-I33UIUZD.js';
3
3
  import { ArtifactIcon } from './chunk-ILDNJHRU.js';
4
4
  import { isApplePlatform, Kbd } from './chunk-SMBKXWML.js';
@@ -1,5 +1,5 @@
1
- import { tabId } from './chunk-7SDUKCNW.js';
2
- import { useRoving, tabStop } from './chunk-RKKO7QHH.js';
1
+ import { tabId } from './chunk-X4IXXLWM.js';
2
+ import { useRoving, tabStop } from './chunk-EGMQURBR.js';
3
3
  import { Count } from './chunk-BHHIIK3M.js';
4
4
  import { HIT_AREA_CLASS } from './chunk-2YTOOH3A.js';
5
5
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
@@ -1,7 +1,7 @@
1
- import { HuePicker } from './chunk-F4LPQA4E.js';
1
+ import { HuePicker } from './chunk-BA32AVKS.js';
2
2
  import { Popover } from './chunk-KHJIEPZV.js';
3
3
  import { NODE_HUE_NAMES } from './chunk-AYKXMIOR.js';
4
- import { CharacterPicker } from './chunk-YEVG2X5R.js';
4
+ import { CharacterPicker } from './chunk-SNQRGH4A.js';
5
5
  import { Avatar } from './chunk-PZKHBB7D.js';
6
6
  import { cx } from './chunk-ODEQTPFM.js';
7
7
  import './AvatarPicker-PREY36MG.css';
@@ -1,5 +1,5 @@
1
1
  import { NODE_HUES, NODE_HUE_NAMES } from './chunk-AYKXMIOR.js';
2
- import { SegmentedControl } from './chunk-2QZ2VPHR.js';
2
+ import { SegmentedControl } from './chunk-4OK4DX3V.js';
3
3
  import { cx } from './chunk-ODEQTPFM.js';
4
4
  import { jsx } from 'react/jsx-runtime';
5
5
 
@@ -0,0 +1,9 @@
1
+ import { cx } from './chunk-ODEQTPFM.js';
2
+ import './PageNote-RHLXH3ML.css';
3
+ import { jsx } from 'react/jsx-runtime';
4
+
5
+ function PageNote({ className, children, ...rest }) {
6
+ return /* @__PURE__ */ jsx("p", { ...rest, className: cx("crewlet-page-note", className), children });
7
+ }
8
+
9
+ export { PageNote };
@@ -1,6 +1,6 @@
1
1
  import { ThemeSwatch } from './chunk-MNFU2RNT.js';
2
2
  import { useHighlightRest } from './chunk-7KHM2FZH.js';
3
- import { useRoving, tabStop } from './chunk-RKKO7QHH.js';
3
+ import { useRoving, tabStop } from './chunk-EGMQURBR.js';
4
4
  import { cx } from './chunk-ODEQTPFM.js';
5
5
  import './ThemeGallery-X35Y25EX.css';
6
6
  import { useId } from 'react';
@@ -1,31 +1,34 @@
1
+ import { LockedLabel } from './chunk-OHGH7O6T.js';
1
2
  import { KeyChip } from './chunk-FYTIJM2T.js';
2
3
  import { HIT_AREA_CLASS } from './chunk-2YTOOH3A.js';
3
4
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
4
5
  import { cx } from './chunk-ODEQTPFM.js';
5
6
  import './HitArea-QUOS6ZDJ.css';
6
- import './SidebarNav-7SGUZYKK.css';
7
- import { useId, useState } from 'react';
7
+ import './SidebarNav-YI74SPDC.css';
8
+ import { createContext, useId, useContext, useState } from 'react';
8
9
  import { ChevronDownGlyph } from '@crewlethq/icons/glyphs';
9
10
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
10
11
 
12
+ var GroupLocked = createContext(false);
11
13
  function SidebarNav({ label, className, children }) {
12
14
  return /* @__PURE__ */ jsx("nav", { className: cx("crewlet-sidebar-nav", className), "aria-label": label, children });
13
15
  }
14
- function NavGroup({ label, action, className, children }) {
16
+ function NavGroup({ label, action, locked, className, children }) {
15
17
  const id = useId();
16
18
  const named = label !== void 0 && label !== null && label !== false && label !== "";
19
+ const groupLocked = named && locked !== void 0 && locked !== "";
17
20
  return /* @__PURE__ */ jsxs(
18
21
  "div",
19
22
  {
20
- className: cx("crewlet-nav-group", className),
23
+ className: cx("crewlet-nav-group", groupLocked && "crewlet-nav-group--locked", className),
21
24
  role: named ? "group" : void 0,
22
25
  "aria-labelledby": named ? id : void 0,
23
26
  children: [
24
27
  named || action ? /* @__PURE__ */ jsxs("div", { className: "crewlet-nav-group__head", children: [
25
- named ? /* @__PURE__ */ jsx("span", { className: "crewlet-nav-group__label", id, children: label }) : null,
28
+ named ? /* @__PURE__ */ jsx("span", { className: "crewlet-nav-group__label", id, children: /* @__PURE__ */ jsx(LockedLabel, { reason: groupLocked ? locked : void 0, children: label }) }) : null,
26
29
  action ? /* @__PURE__ */ jsx("button", { type: "button", className: "crewlet-nav-group__action", "aria-label": action.label, onClick: action.onClick, children: /* @__PURE__ */ jsx("span", { className: "crewlet-nav-group__action-icon", "aria-hidden": true, children: action.icon }) }) : null
27
30
  ] }) : null,
28
- children
31
+ /* @__PURE__ */ jsx(GroupLocked.Provider, { value: groupLocked, children })
29
32
  ]
30
33
  }
31
34
  );
@@ -48,6 +51,9 @@ function NavItem({
48
51
  href,
49
52
  current = false,
50
53
  disabledReason,
54
+ locked,
55
+ title,
56
+ onPrefetch,
51
57
  renderLink,
52
58
  onClick,
53
59
  children,
@@ -58,6 +64,7 @@ function NavItem({
58
64
  className
59
65
  }) {
60
66
  const id = useId();
67
+ const inLockedGroup = useContext(GroupLocked);
61
68
  const [ownExpanded, setOwnExpanded] = useState(defaultExpanded);
62
69
  const open = expanded ?? ownExpanded;
63
70
  const nested = children !== void 0 && children !== null && children !== false;
@@ -72,7 +79,7 @@ function NavItem({
72
79
  lead ? /* @__PURE__ */ jsx(KeyChip, { className: "crewlet-nav-item__lead", children: lead }) : null,
73
80
  lead ? " " : null,
74
81
  /* @__PURE__ */ jsxs("span", { className: "crewlet-nav-item__label", children: [
75
- label,
82
+ /* @__PURE__ */ jsx(LockedLabel, { reason: locked, mark: !inLockedGroup, children: label }),
76
83
  count || badge ? /* @__PURE__ */ jsx(VisuallyHidden, { children: spoken([count, badge]) }) : null
77
84
  ] }),
78
85
  count ? /* @__PURE__ */ jsx(Figure, { figure: count, mark: count.mark, className: "crewlet-nav-item__count" }) : null,
@@ -99,10 +106,24 @@ function NavItem({
99
106
  children: inside,
100
107
  ...href === void 0 ? {} : { href },
101
108
  ...current ? { "aria-current": "page" } : {},
102
- ...onClick === void 0 ? {} : { onClick }
109
+ ...onClick === void 0 ? {} : { onClick },
110
+ ...title === void 0 ? {} : { title },
111
+ ...onPrefetch === void 0 ? {} : { onPointerEnter: onPrefetch, onFocus: onPrefetch }
103
112
  });
104
113
  } else if (href !== void 0) {
105
- row = /* @__PURE__ */ jsx("a", { className: rowClass, href, "aria-current": current ? "page" : void 0, onClick, children: inside });
114
+ row = /* @__PURE__ */ jsx(
115
+ "a",
116
+ {
117
+ className: rowClass,
118
+ href,
119
+ "aria-current": current ? "page" : void 0,
120
+ onClick,
121
+ title,
122
+ onPointerEnter: onPrefetch,
123
+ onFocus: onPrefetch,
124
+ children: inside
125
+ }
126
+ );
106
127
  } else {
107
128
  row = /* @__PURE__ */ jsxs(
108
129
  "button",
@@ -5,22 +5,23 @@ function tabStop(items, selected) {
5
5
  if (selected >= 0 && !items[selected]?.disabled) return selected;
6
6
  return items.findIndex((item) => !item.disabled);
7
7
  }
8
+ function reachable(el) {
9
+ return Boolean(el) && !el.disabled && !el.hasAttribute("inert");
10
+ }
8
11
  function useRoving(count, select, { followFocus = false, columns } = {}) {
9
12
  const buttons = useRef([]);
10
13
  const [landed, setLanded] = useState(null);
11
14
  function step(from, by) {
12
15
  for (let i = 0; i < count; i += 1) {
13
16
  const at = ((from + by * i) % count + count) % count;
14
- const el = buttons.current[at];
15
- if (el && !el.disabled) return at;
17
+ if (reachable(buttons.current[at])) return at;
16
18
  }
17
19
  return null;
18
20
  }
19
21
  function rowStep(at, by, across) {
20
22
  const target = at + by * across;
21
23
  if (target < 0 || target >= count) return null;
22
- const el = buttons.current[target];
23
- return el && !el.disabled ? target : null;
24
+ return reachable(buttons.current[target]) ? target : null;
24
25
  }
25
26
  function moveTo(key, at, vertical) {
26
27
  if (count === 0) return null;
@@ -1,6 +1,6 @@
1
1
  import { Toolbar } from './chunk-NR4CPM4T.js';
2
- import { SegmentedControl } from './chunk-2QZ2VPHR.js';
3
- import { tabId } from './chunk-7SDUKCNW.js';
2
+ import { SegmentedControl } from './chunk-4OK4DX3V.js';
3
+ import { tabId } from './chunk-X4IXXLWM.js';
4
4
  import { IconButton } from './chunk-4FQT6ZAY.js';
5
5
  import { cx } from './chunk-ODEQTPFM.js';
6
6
  import './MarkdownEditor-WOKV7CLK.css';
@@ -1,6 +1,6 @@
1
1
  import { Select } from './chunk-XQZ6EWOE.js';
2
2
  import { SHEET_LABELS, SHEET_COLUMN_TYPES, optionHue, retypeColumn } from './chunk-LFSIKGRQ.js';
3
- import { HueSwatch } from './chunk-F4LPQA4E.js';
3
+ import { HueSwatch } from './chunk-BA32AVKS.js';
4
4
  import { NODE_HUES, NODE_HUE_NAMES } from './chunk-AYKXMIOR.js';
5
5
  import { Checkbox } from './chunk-AXS6MBNH.js';
6
6
  import { FormField, Input } from './chunk-TYONQSOK.js';
@@ -6,7 +6,7 @@ import { IconButton } from './chunk-4FQT6ZAY.js';
6
6
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
7
7
  import { cx } from './chunk-ODEQTPFM.js';
8
8
  import './HitArea-QUOS6ZDJ.css';
9
- import './AppShell-NDU4XMGF.css';
9
+ import './AppShell-VE2MAV42.css';
10
10
  import { createContext, forwardRef, useContext, useId, useState, useRef, useCallback, useEffect, useLayoutEffect } from 'react';
11
11
  import { breakpoint } from '@crewlethq/tokens';
12
12
  import { ChevronUpGlyph, ChevronsUpDownGlyph, ChevronRightGlyph, MenuGlyph } from '@crewlethq/icons/glyphs';
@@ -231,10 +231,13 @@ function ShellDrawer({
231
231
  }
232
232
  );
233
233
  }
234
- function AppShellRail({ header, footer, className, children }) {
234
+ function AppShellRail({ header, search, footer, className, children }) {
235
235
  return /* @__PURE__ */ jsxs("div", { className: cx("crewlet-app-shell__rail-inner", className), children: [
236
236
  header ? /* @__PURE__ */ jsx("div", { className: "crewlet-app-shell__rail-head", children: header }) : null,
237
- /* @__PURE__ */ jsx("div", { className: "crewlet-app-shell__rail-body", children }),
237
+ /* @__PURE__ */ jsxs("div", { className: "crewlet-app-shell__rail-body", children: [
238
+ search ? /* @__PURE__ */ jsx("div", { className: "crewlet-app-shell__rail-search", children: search }) : null,
239
+ children
240
+ ] }),
238
241
  footer ? /* @__PURE__ */ jsx("div", { className: "crewlet-app-shell__rail-foot", children: footer }) : null
239
242
  ] });
240
243
  }