@crewlethq/ui 0.20.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +22 -0
  2. package/dist/AppShell/AccountRow.d.ts +24 -2
  3. package/dist/AppShell/index.d.ts +1 -1
  4. package/dist/AppShell/index.js +3 -1
  5. package/dist/{AppShell-RUNVM4WH.css → AppShell-APHZKJYH.css} +25 -3
  6. package/dist/CommandPalette/index.js +3 -3
  7. package/dist/CommentThread/index.js +2 -2
  8. package/dist/DataTable/index.js +4 -4
  9. package/dist/DataView/index.js +6 -6
  10. package/dist/DateTimePicker/index.js +2 -2
  11. package/dist/LinkInterstitial/index.js +3 -3
  12. package/dist/Menu/Menu.d.ts +45 -2
  13. package/dist/Menu/index.d.ts +1 -1
  14. package/dist/Menu/index.js +1 -1
  15. package/dist/{Menu-BT5PMFJI.css → Menu-KEKAD3BZ.css} +35 -2
  16. package/dist/Modal/index.js +2 -2
  17. package/dist/PeopleRail/index.js +2 -2
  18. package/dist/ShareDialog/index.js +3 -3
  19. package/dist/SheetGrid/index.js +2 -2
  20. package/dist/Switcher/index.js +3 -3
  21. package/dist/TimeWindowPicker/index.js +2 -2
  22. package/dist/VersionTimeline/index.js +2 -2
  23. package/dist/{chunk-UXELEORU.js → chunk-4HRB62EA.js} +1 -1
  24. package/dist/{chunk-7FQEUNHX.js → chunk-7X5WOECO.js} +1 -1
  25. package/dist/{chunk-EDGCPVVD.js → chunk-BFQK7CYJ.js} +28 -3
  26. package/dist/{chunk-AJESMWJS.js → chunk-BXSGT3YC.js} +3 -3
  27. package/dist/{chunk-OIMAK5AE.js → chunk-KYEXTEJ3.js} +4 -4
  28. package/dist/{chunk-A4VMJMXJ.js → chunk-L2OQRPXJ.js} +1 -1
  29. package/dist/{chunk-JULMZNGT.js → chunk-UFKUWVMV.js} +33 -11
  30. package/dist/{chunk-HTCJSUIZ.js → chunk-XMGB3ZAT.js} +2 -2
  31. package/dist/generated/index.js +30 -30
  32. package/dist/index.js +30 -30
  33. package/dist/styles.css +62 -7
  34. package/package.json +3 -3
  35. package/dist/{chunk-J2G4HGQM.js → chunk-36CWC2NH.js} +1 -1
  36. package/dist/{chunk-7IJARUIF.js → chunk-F4DPAJCN.js} +1 -1
  37. package/dist/{chunk-EZBLOUWX.js → chunk-IC64IWOO.js} +1 -1
  38. package/dist/{chunk-N4GFRW5C.js → chunk-J4OKGJQ6.js} +1 -1
  39. package/dist/{chunk-EIGEIT4O.js → chunk-NUZC6PJX.js} +1 -1
  40. package/dist/{chunk-L4H7SSWF.js → chunk-RE6ED5TO.js} +1 -1
  41. package/dist/{chunk-WXAULPBH.js → chunk-UNZ7TVV5.js} +1 -1
package/README.md CHANGED
@@ -203,6 +203,28 @@ places:
203
203
  - A surface that pans or zooms dispatches `LAYER_REPOSITION_EVENT` on its host
204
204
  when the content beneath it moves, and every panel anchored inside follows.
205
205
 
206
+ ## Changes in 0.22.0
207
+
208
+ **`Menu` takes `width`** (`'content'`, the default, or `'trigger'`). `'trigger'` keeps the panel no narrower than its trigger, so a trigger that spans a column opens a menu that covers it edge to edge, and still lets it grow past the trigger when a row needs the room.
209
+
210
+ **`Menu` takes `trailingIcon`**, a glyph after a text trigger's words, such as a picker's chevron. It is drawn as the button's trailing icon, a gap away from the words, where a glyph written into `trigger` sat flush against them.
211
+
212
+ **`Menu` reads more easily.** A header's name and value share one line (`Access … Admin`), and a row's description is one type step under its label rather than two.
213
+
214
+ **`AppShell.AccountRow`'s menu covers the row.** Pressing who you are opens a menu at least as wide as the row itself.
215
+
216
+ What to change: nothing.
217
+
218
+ ## Changes in 0.21.0
219
+
220
+ **`AppShell.AccountRow` takes `menu`** (`AccountRowMenu`: `label`, `header`, `items`): pressing who you are opens the reader's own menu instead of linking anywhere, which is where a reader looks for their account and for signing out. The row becomes the menu button, ending in the up-and-down chevron a menu's trigger draws, keeps the account page's current-row lift (`data-current`), and the menu's header holds the facts the row does not already say, such as the reader's access. Given, `menu` takes the place of `href`.
221
+
222
+ **`Menu` takes `header` and `renderTrigger`.** `header` is a line of facts above the items: never an item, so the arrows never stop on it, and the menu's description, so a screen reader hears it when the menu opens. `renderTrigger` makes the caller's own element the trigger, given the props it spreads (`MenuTriggerProps`), keeping every rule of the menu's button, focus coming back to it included.
223
+
224
+ **`@crewlethq/icons` vendors `log-out` and `log-in`**, for signing out and in from that menu.
225
+
226
+ What to change: nothing. Everything is new.
227
+
206
228
  ## Changes in 0.20.0
207
229
 
208
230
  0.20.0 adds the review surfaces the engine dashboard drew for itself: a line diff, two versions compared, a document's comment thread, the note a lost edit race leaves, the People rail beside a shared document, and the read-only cells its tables share. Each takes its data and its callbacks as props, so nothing in it fetches or knows a route.
@@ -1,4 +1,14 @@
1
1
  import type { ReactNode } from 'react';
2
+ import { type MenuEntry } from '../Menu/index.js';
3
+ /** The menu the row opens (`AccountRowProps.menu`). */
4
+ export interface AccountRowMenu {
5
+ /** The menu's name. Defaults to "Your account". */
6
+ label?: string | undefined;
7
+ /** Facts above the items that the row does not already say: the reader's access. */
8
+ header?: ReactNode;
9
+ /** The reader's own actions: their account, signing out. */
10
+ items: readonly MenuEntry[];
11
+ }
2
12
  export interface AccountRowProps {
3
13
  /** The reader's badge, drawn decorative: the name beside it says who it is. */
4
14
  avatar: ReactNode;
@@ -6,8 +16,14 @@ export interface AccountRowProps {
6
16
  name: ReactNode;
7
17
  /** The line under the name: a login, a seat. Left out where it would repeat the name. */
8
18
  detail?: ReactNode;
9
- /** The reader's account page. Without it the row states who is signed in and goes nowhere. */
19
+ /** The reader's account page. Without it (or `menu`) the row states who is signed in and goes nowhere. */
10
20
  href?: string | undefined;
21
+ /**
22
+ * The reader's own menu, which the row OPENS rather than linking anywhere:
23
+ * their account among its items, and signing out. Given, it takes the place
24
+ * of `href`.
25
+ */
26
+ menu?: AccountRowMenu | undefined;
11
27
  /** Whether the reader is on that page, which marks the row as the rail marks its current row. */
12
28
  current?: boolean | undefined;
13
29
  /** What the link opens, as its tooltip. */
@@ -36,5 +52,11 @@ export interface AccountRowProps {
36
52
  *
37
53
  * The controls are siblings of the link, never inside it, so each keeps its
38
54
  * own name and the link's name stays the reader's.
55
+ *
56
+ * OR THE ROW OPENS THE READER'S MENU (`menu`): pressing who you are is where a
57
+ * reader looks for their account and for signing out, so the row is the menu
58
+ * button, ending in the up-and-down chevron a menu's trigger draws, and the
59
+ * account is one item of it. The menu says only what the row does not, in its
60
+ * header (their access), above the actions.
39
61
  */
40
- export declare function AccountRow({ avatar, name, detail, href, current, title, linkSuffix, actions, className, }: AccountRowProps): import("react").JSX.Element;
62
+ export declare function AccountRow({ avatar, name, detail, href, menu, current, title, linkSuffix, actions, className, }: AccountRowProps): import("react").JSX.Element;
@@ -1,5 +1,5 @@
1
1
  import './AppShell.css';
2
2
  export { AppShell, AppShellRail, AppShellRailRow, AppShellToggle, AppShellTopbar, useAppShell } from './AppShell.js';
3
3
  export { AccountRow } from './AccountRow.js';
4
- export type { AccountRowProps } from './AccountRow.js';
4
+ export type { AccountRowMenu, AccountRowProps } from './AccountRow.js';
5
5
  export type { ActionRailRowProps, AppShellContextValue, AppShellProps, AppShellRailProps, AppShellRailRowProps, AppShellToggleProps, AppShellTopbarProps, RailRowCount, StaticRailRowProps, } from './AppShell.js';
@@ -1,5 +1,7 @@
1
- export { AccountRow, AppShell, AppShellRail, AppShellRailRow, AppShellToggle, AppShellTopbar, useAppShell } from '../chunk-EDGCPVVD.js';
1
+ export { AccountRow, AppShell, AppShellRail, AppShellRailRow, AppShellToggle, AppShellTopbar, useAppShell } from '../chunk-BFQK7CYJ.js';
2
2
  import '../chunk-IG75YMUN.js';
3
+ import '../chunk-UFKUWVMV.js';
4
+ import '../chunk-OG6CL3EB.js';
3
5
  import '../chunk-HMPFGIWM.js';
4
6
  import '../chunk-R25RGPUB.js';
5
7
  import '../chunk-4FQT6ZAY.js';
@@ -651,18 +651,40 @@
651
651
  transition: background var(--motion-duration-fast) var(--motion-easing-default);
652
652
  }
653
653
 
654
- a.crewlet-account-row__who:hover {
654
+ /* The row as the reader's menu button: a button drawn as the link is. */
655
+ button.crewlet-account-row__who {
656
+ width: 100%;
657
+ margin: 0;
658
+ border: 0;
659
+ background: none;
660
+ font: inherit;
661
+ text-align: start;
662
+ cursor: pointer;
663
+ }
664
+
665
+ /* A row that opens a menu fills the row as the link does. */
666
+ .crewlet-account-row > .crewlet-menu-anchor {
667
+ display: flex;
668
+ flex: 1 1 auto;
669
+ min-width: 0;
670
+ }
671
+
672
+ a.crewlet-account-row__who:hover,
673
+ button.crewlet-account-row__who:hover,
674
+ button.crewlet-account-row__who[aria-expanded='true'] {
655
675
  background: var(--color-surface-hover);
656
676
  }
657
677
 
658
678
  /* After :hover, so the current row shows the lift rather than the overlay. */
659
- a.crewlet-account-row__who[aria-current='page'] {
679
+ a.crewlet-account-row__who[aria-current='page'],
680
+ button.crewlet-account-row__who[data-current] {
660
681
  background: var(--color-surface-elevated);
661
682
  outline: 1px solid var(--color-border-default);
662
683
  outline-offset: -1px;
663
684
  }
664
685
 
665
- a.crewlet-account-row__who:focus-visible {
686
+ a.crewlet-account-row__who:focus-visible,
687
+ button.crewlet-account-row__who:focus-visible {
666
688
  outline: 2px solid var(--color-focus);
667
689
  outline-offset: var(--size-focus-ring-inset-offset);
668
690
  }
@@ -1,11 +1,11 @@
1
- export { CommandPalette } from '../chunk-UXELEORU.js';
2
- import '../chunk-7IJARUIF.js';
1
+ export { CommandPalette } from '../chunk-4HRB62EA.js';
2
+ import '../chunk-F4DPAJCN.js';
3
3
  import '../chunk-F73MC7EZ.js';
4
4
  import '../chunk-SMBKXWML.js';
5
- import '../chunk-OG6CL3EB.js';
6
5
  import '../chunk-Q55TXPA3.js';
7
6
  import '../chunk-PQADV6P6.js';
8
7
  import '../chunk-BHHIIK3M.js';
8
+ import '../chunk-OG6CL3EB.js';
9
9
  import '../chunk-HMPFGIWM.js';
10
10
  import '../chunk-R25RGPUB.js';
11
11
  import '../chunk-4FQT6ZAY.js';
@@ -1,8 +1,7 @@
1
- export { COMMENT_THREAD_LABELS, CommentThread } from '../chunk-EZBLOUWX.js';
1
+ export { COMMENT_THREAD_LABELS, CommentThread } from '../chunk-IC64IWOO.js';
2
2
  import '../chunk-WI6K5M5X.js';
3
3
  import '../chunk-VJLYGPPE.js';
4
4
  import '../chunk-SMBKXWML.js';
5
- import '../chunk-OG6CL3EB.js';
6
5
  import '../chunk-Q55TXPA3.js';
7
6
  import '../chunk-4KP4RC3O.js';
8
7
  import '../chunk-3CZ7XAVY.js';
@@ -11,6 +10,7 @@ import '../chunk-UAN5NE7M.js';
11
10
  import '../chunk-5OM447RW.js';
12
11
  import '../chunk-PQADV6P6.js';
13
12
  import '../chunk-BHHIIK3M.js';
13
+ import '../chunk-OG6CL3EB.js';
14
14
  import '../chunk-4FQT6ZAY.js';
15
15
  import '../chunk-BZFWDIV6.js';
16
16
  import '../chunk-ODEQTPFM.js';
@@ -1,14 +1,14 @@
1
- export { ALL_ITEMS, CopyableCell, DATA_TABLE_LABELS, DataTable, RowActionsMenu } from '../chunk-AJESMWJS.js';
2
- import '../chunk-JULMZNGT.js';
1
+ export { ALL_ITEMS, CopyableCell, DATA_TABLE_LABELS, DataTable, RowActionsMenu } from '../chunk-BXSGT3YC.js';
3
2
  import '../chunk-STJ7QBC3.js';
4
3
  import '../chunk-DTIW4CHZ.js';
5
- import '../chunk-7IJARUIF.js';
6
- import '../chunk-OG6CL3EB.js';
4
+ import '../chunk-F4DPAJCN.js';
7
5
  import '../chunk-I6NZKJGK.js';
8
6
  import '../chunk-Q55TXPA3.js';
9
7
  import '../chunk-EUCC37WY.js';
10
8
  import '../chunk-AV2DXAEL.js';
11
9
  import '../chunk-PQADV6P6.js';
10
+ import '../chunk-UFKUWVMV.js';
11
+ import '../chunk-OG6CL3EB.js';
12
12
  import '../chunk-HMPFGIWM.js';
13
13
  import '../chunk-R25RGPUB.js';
14
14
  import '../chunk-4FQT6ZAY.js';
@@ -1,16 +1,14 @@
1
- export { DATA_VIEW_TOOLBAR_LABELS, DataView, DataViewToolbar, FILTER_AXIS_LABELS, FilterAxisBar, FilterAxisChip, applyColumnFilters, applyFilters, blankFilterValue, defaultOperator, filterDefsFromColumns, filterHasValue, filterPredicate, formatFilterValue, operatorOf, tableColumns } from '../chunk-OIMAK5AE.js';
1
+ export { DATA_VIEW_TOOLBAR_LABELS, DataView, DataViewToolbar, FILTER_AXIS_LABELS, FilterAxisBar, FilterAxisChip, applyColumnFilters, applyFilters, blankFilterValue, defaultOperator, filterDefsFromColumns, filterHasValue, filterPredicate, formatFilterValue, operatorOf, tableColumns } from '../chunk-KYEXTEJ3.js';
2
2
  import '../chunk-HOXGBLEY.js';
3
3
  import '../chunk-PGRPNDWM.js';
4
- import '../chunk-AJESMWJS.js';
5
- import '../chunk-JULMZNGT.js';
6
- import '../chunk-L4H7SSWF.js';
4
+ import '../chunk-RE6ED5TO.js';
5
+ import '../chunk-BXSGT3YC.js';
7
6
  import '../chunk-STJ7QBC3.js';
8
7
  import '../chunk-DTIW4CHZ.js';
9
- import '../chunk-7IJARUIF.js';
8
+ import '../chunk-F4DPAJCN.js';
10
9
  import '../chunk-F73MC7EZ.js';
11
10
  import '../chunk-SMBKXWML.js';
12
11
  import '../chunk-GXQ3B46I.js';
13
- import '../chunk-OG6CL3EB.js';
14
12
  import '../chunk-I6NZKJGK.js';
15
13
  import '../chunk-Q55TXPA3.js';
16
14
  import '../chunk-3CZ7XAVY.js';
@@ -19,6 +17,8 @@ import '../chunk-BWRGFKJP.js';
19
17
  import '../chunk-AV2DXAEL.js';
20
18
  import '../chunk-PQADV6P6.js';
21
19
  import '../chunk-BHHIIK3M.js';
20
+ import '../chunk-UFKUWVMV.js';
21
+ import '../chunk-OG6CL3EB.js';
22
22
  import '../chunk-HMPFGIWM.js';
23
23
  import '../chunk-R25RGPUB.js';
24
24
  import '../chunk-4FQT6ZAY.js';
@@ -1,7 +1,7 @@
1
- export { DEFAULT_DATE_TIME_PICKER_LABELS, DateTimePicker } from '../chunk-L4H7SSWF.js';
1
+ export { DEFAULT_DATE_TIME_PICKER_LABELS, DateTimePicker } from '../chunk-RE6ED5TO.js';
2
2
  import '../chunk-GXQ3B46I.js';
3
- import '../chunk-OG6CL3EB.js';
4
3
  import '../chunk-BWRGFKJP.js';
4
+ import '../chunk-OG6CL3EB.js';
5
5
  import '../chunk-HMPFGIWM.js';
6
6
  import '../chunk-R25RGPUB.js';
7
7
  import '../chunk-4FQT6ZAY.js';
@@ -1,9 +1,9 @@
1
- export { LinkInterstitial, openExternal } from '../chunk-A4VMJMXJ.js';
1
+ export { LinkInterstitial, openExternal } from '../chunk-L2OQRPXJ.js';
2
+ import '../chunk-F4DPAJCN.js';
2
3
  import '../chunk-5CLW2CXT.js';
3
- import '../chunk-7IJARUIF.js';
4
4
  import '../chunk-SVSCLHHI.js';
5
- import '../chunk-OG6CL3EB.js';
6
5
  import '../chunk-PQADV6P6.js';
6
+ import '../chunk-OG6CL3EB.js';
7
7
  import '../chunk-HMPFGIWM.js';
8
8
  import '../chunk-R25RGPUB.js';
9
9
  import '../chunk-4FQT6ZAY.js';
@@ -53,10 +53,24 @@
53
53
  * - IT CAN BE OPENED FROM OUTSIDE (`open`, `onOpenChange`), because a tree item
54
54
  * that holds focus opens its card's menu from the keyboard while the trigger
55
55
  * itself is out of the tab order (`triggerTabIndex={-1}`).
56
+ * - ITS TRIGGER CAN BE THE CALLER'S OWN (`renderTrigger`): a row that IS the
57
+ * way in, such as the signed-in reader at the foot of the rail, opens the
58
+ * menu itself rather than sitting beside a second button that does. The
59
+ * caller spreads the props it is handed on its element, which keeps every
60
+ * rule above, the focus coming back included.
61
+ * - IT CAN BE NO NARROWER THAN ITS TRIGGER (`width="trigger"`): a trigger
62
+ * that spans a column, such as the signed-in reader at the foot of the
63
+ * rail, opens a panel that covers it edge to edge, and that still grows
64
+ * past it when a row needs the room, so a description reads on one line
65
+ * rather than wrapping into a column of short lines.
66
+ * - A HEADER SAYS WHAT THE ACTIONS ARE ABOUT (`header`): a line of facts
67
+ * above the items, such as the access a signed-in reader carries. It is
68
+ * not an item, so the arrows never stop on it, and the menu is described by
69
+ * it, so a screen reader hears it when the menu opens.
56
70
  *
57
71
  * Ported from the engine dashboard's `ui/Menu.tsx`, with its suite.
58
72
  */
59
- import { type ReactNode } from 'react';
73
+ import { type KeyboardEvent, type ReactNode } from 'react';
60
74
  import { type ButtonVariant } from '../Button/index.js';
61
75
  export interface MenuItem {
62
76
  kind?: 'item';
@@ -97,6 +111,16 @@ type Run = {
97
111
  };
98
112
  /** Gathers each run of consecutive answers (items given `checked`) into one group. */
99
113
  export declare function runs(entries: readonly MenuEntry[]): Run[];
114
+ /** What a caller's own trigger spreads on its element (`renderTrigger`). */
115
+ export interface MenuTriggerProps {
116
+ ref: (el: HTMLElement | null) => void;
117
+ 'aria-haspopup': 'menu';
118
+ 'aria-expanded': boolean;
119
+ 'aria-controls': string | undefined;
120
+ tabIndex: number | undefined;
121
+ onClick: () => void;
122
+ onKeyDown: (event: KeyboardEvent<HTMLElement>) => void;
123
+ }
100
124
  export interface MenuProps {
101
125
  /** The trigger's accessible name, such as "Actions for Software Engineer". */
102
126
  label: string;
@@ -105,6 +129,12 @@ export interface MenuProps {
105
129
  icon?: ReactNode;
106
130
  /** Visible trigger text; without it the trigger is an icon button named by `label`. */
107
131
  trigger?: ReactNode;
132
+ /**
133
+ * A glyph after the trigger's text, such as the chevron of a picker. Drawn
134
+ * as the button's trailing icon, a gap away from the words; a glyph written
135
+ * into `trigger` instead sits flush against them. Read only with `trigger`.
136
+ */
137
+ trailingIcon?: ReactNode;
108
138
  triggerVariant?: ButtonVariant | undefined;
109
139
  /** -1 for a pointer-only trigger whose actions the keyboard reaches another way. */
110
140
  triggerTabIndex?: number | undefined;
@@ -112,7 +142,20 @@ export interface MenuProps {
112
142
  onOpenChange?: ((open: boolean) => void) | undefined;
113
143
  /** Which edge of the trigger the menu lines up with. */
114
144
  align?: 'start' | 'end' | undefined;
145
+ /**
146
+ * How wide the panel is: its longest row (`content`, the default), or its
147
+ * longest row but never narrower than its trigger (`trigger`), for a
148
+ * trigger that spans a column.
149
+ */
150
+ width?: 'content' | 'trigger' | undefined;
151
+ /**
152
+ * The caller's own trigger, in place of the menu's button: an element given
153
+ * these props. `label` still names the menu; the trigger names itself.
154
+ */
155
+ renderTrigger?: ((props: MenuTriggerProps) => ReactNode) | undefined;
156
+ /** Facts above the items: what the actions are about. Never an item. */
157
+ header?: ReactNode;
115
158
  className?: string | undefined;
116
159
  }
117
- export declare function Menu({ label, items, icon, trigger, triggerVariant, triggerTabIndex, open: controlled, onOpenChange, align, className, }: MenuProps): import("react").JSX.Element;
160
+ export declare function Menu({ label, items, icon, trigger, trailingIcon, triggerVariant, triggerTabIndex, open: controlled, onOpenChange, align, width, renderTrigger, header, className, }: MenuProps): import("react").JSX.Element;
118
161
  export {};
@@ -1,3 +1,3 @@
1
1
  import './Menu.css';
2
2
  export { Menu } from './Menu.js';
3
- export type { MenuEntry, MenuItem, MenuProps, MenuSeparator } from './Menu.js';
3
+ export type { MenuEntry, MenuItem, MenuProps, MenuSeparator, MenuTriggerProps } from './Menu.js';
@@ -1,4 +1,4 @@
1
- export { Menu } from '../chunk-JULMZNGT.js';
1
+ export { Menu } from '../chunk-UFKUWVMV.js';
2
2
  import '../chunk-OG6CL3EB.js';
3
3
  import '../chunk-HMPFGIWM.js';
4
4
  import '../chunk-R25RGPUB.js';
@@ -34,9 +34,15 @@
34
34
  * however long that label was and the 320px was a number nothing read. A
35
35
  * width is clamped by the ceiling, and the label that no longer fits is the
36
36
  * one that truncates.
37
+ *
38
+ * A FLOOR, when the trigger sets one (`width="trigger"`, which writes
39
+ * --crewlet-menu-floor): the panel is never narrower than a trigger that
40
+ * spans a column. The ceiling is lifted to meet it, so the two never cross
41
+ * and the rule above still holds.
37
42
  */
38
43
  width: max-content;
39
- max-width: 320px;
44
+ min-width: var(--crewlet-menu-floor, 0px);
45
+ max-width: max(320px, var(--crewlet-menu-floor, 0px));
40
46
  max-height: min(360px, 60vh);
41
47
  overflow-y: auto;
42
48
  overscroll-behavior: contain;
@@ -193,6 +199,7 @@
193
199
  .crewlet-menu__text {
194
200
  display: flex;
195
201
  flex-direction: column;
202
+ gap: calc(var(--spacing-1) / 2);
196
203
  min-width: 0;
197
204
  }
198
205
 
@@ -202,9 +209,14 @@
202
209
  white-space: nowrap;
203
210
  }
204
211
 
212
+ /*
213
+ * ONE STEP UNDER THE LABEL, not two. At 11px under a 13px label the second
214
+ * line read as fine print; at 12px in the tertiary ink it is still plainly the
215
+ * lesser line, and it is legible at a glance.
216
+ */
205
217
  .crewlet-menu__description {
206
218
  color: var(--color-text-tertiary);
207
- font-size: var(--font-size-2xs);
219
+ font-size: var(--font-size-xs);
208
220
  white-space: normal;
209
221
  }
210
222
 
@@ -219,6 +231,27 @@
219
231
  font-size: var(--font-size-xs);
220
232
  }
221
233
 
234
+ /*
235
+ * Facts above the items, across the panel's full width with a hairline under
236
+ * them: what the actions below are about, read rather than pressed.
237
+ *
238
+ * A NAME AND ITS VALUE SHARE ONE LINE, the name at the start and the value at
239
+ * the end, as a property reads ("Access … Admin"). Stacked, the pair spent two
240
+ * lines on one fact. A value too long for the line wraps beneath its name.
241
+ */
242
+ .crewlet-menu__header {
243
+ display: flex;
244
+ flex-wrap: wrap;
245
+ align-items: center;
246
+ justify-content: space-between;
247
+ gap: var(--spacing-1) var(--spacing-2);
248
+ margin: calc(var(--spacing-1) * -1) calc(var(--spacing-1) * -1) var(--spacing-1);
249
+ padding: var(--spacing-2) var(--spacing-3);
250
+ border-bottom: 1px solid var(--color-border-default);
251
+ font-size: var(--font-size-xs);
252
+ color: var(--color-text-secondary);
253
+ }
254
+
222
255
  .crewlet-menu__separator {
223
256
  height: 1px;
224
257
  margin: var(--spacing-1) 0;
@@ -1,6 +1,6 @@
1
- export { ConfirmModal, Modal } from '../chunk-7IJARUIF.js';
2
- import '../chunk-OG6CL3EB.js';
1
+ export { ConfirmModal, Modal } from '../chunk-F4DPAJCN.js';
3
2
  import '../chunk-PQADV6P6.js';
3
+ import '../chunk-OG6CL3EB.js';
4
4
  import '../chunk-HMPFGIWM.js';
5
5
  import '../chunk-R25RGPUB.js';
6
6
  import '../chunk-4FQT6ZAY.js';
@@ -1,11 +1,11 @@
1
- export { PEOPLE_RAIL_LABELS, PeopleRail, peopleRailKey } from '../chunk-N4GFRW5C.js';
1
+ export { PEOPLE_RAIL_LABELS, PeopleRail, peopleRailKey } from '../chunk-J4OKGJQ6.js';
2
2
  import '../chunk-CENOOTAV.js';
3
3
  import '../chunk-S35G6PNC.js';
4
- import '../chunk-OG6CL3EB.js';
5
4
  import '../chunk-UAN5NE7M.js';
6
5
  import '../chunk-AYKXMIOR.js';
7
6
  import '../chunk-5OM447RW.js';
8
7
  import '../chunk-PQADV6P6.js';
8
+ import '../chunk-OG6CL3EB.js';
9
9
  import '../chunk-4FQT6ZAY.js';
10
10
  import '../chunk-BZFWDIV6.js';
11
11
  import '../chunk-ODEQTPFM.js';
@@ -1,17 +1,17 @@
1
- export { ARTIFACT_ROLES, SHAREABLE_ROLES, ShareDialog, roleAtLeast } from '../chunk-HTCJSUIZ.js';
1
+ export { ARTIFACT_ROLES, SHAREABLE_ROLES, ShareDialog, roleAtLeast } from '../chunk-XMGB3ZAT.js';
2
2
  import '../chunk-FC4YTTFJ.js';
3
3
  import '../chunk-W46LPU4R.js';
4
4
  import '../chunk-STJ7QBC3.js';
5
5
  import '../chunk-DTIW4CHZ.js';
6
- import '../chunk-7IJARUIF.js';
6
+ import '../chunk-F4DPAJCN.js';
7
7
  import '../chunk-F73MC7EZ.js';
8
8
  import '../chunk-SVSCLHHI.js';
9
- import '../chunk-OG6CL3EB.js';
10
9
  import '../chunk-4KP4RC3O.js';
11
10
  import '../chunk-UAN5NE7M.js';
12
11
  import '../chunk-5OM447RW.js';
13
12
  import '../chunk-PQADV6P6.js';
14
13
  import '../chunk-IG75YMUN.js';
14
+ import '../chunk-OG6CL3EB.js';
15
15
  import '../chunk-HMPFGIWM.js';
16
16
  import '../chunk-R25RGPUB.js';
17
17
  import '../chunk-4FQT6ZAY.js';
@@ -1,4 +1,4 @@
1
- export { CellDisplay, CellEditor, CheckboxCell, DateCell, LongTextCell, MultiSelectCell, NumberCell, PersonCell, RatingCell, SelectCell, SheetCell, SheetGrid, StatusCell, TextCell, UrlCell } from '../chunk-J2G4HGQM.js';
1
+ export { CellDisplay, CellEditor, CheckboxCell, DateCell, LongTextCell, MultiSelectCell, NumberCell, PersonCell, RatingCell, SelectCell, SheetCell, SheetGrid, StatusCell, TextCell, UrlCell } from '../chunk-36CWC2NH.js';
2
2
  import '../chunk-CENOOTAV.js';
3
3
  import '../chunk-GFV4LJHH.js';
4
4
  import '../chunk-WIATRXEJ.js';
@@ -8,10 +8,10 @@ import '../chunk-PPAQFGS2.js';
8
8
  import '../chunk-YYZRLLLY.js';
9
9
  import '../chunk-S35G6PNC.js';
10
10
  import '../chunk-QWOPX2MN.js';
11
- import '../chunk-OG6CL3EB.js';
12
11
  import '../chunk-UAN5NE7M.js';
13
12
  import '../chunk-AYKXMIOR.js';
14
13
  import '../chunk-5OM447RW.js';
14
+ import '../chunk-OG6CL3EB.js';
15
15
  import '../chunk-HMPFGIWM.js';
16
16
  import '../chunk-R25RGPUB.js';
17
17
  import '../chunk-BZFWDIV6.js';
@@ -1,13 +1,13 @@
1
- export { Switcher } from '../chunk-7FQEUNHX.js';
1
+ export { Switcher } from '../chunk-7X5WOECO.js';
2
2
  import '../chunk-W5J7R5EB.js';
3
- import '../chunk-7IJARUIF.js';
3
+ import '../chunk-F4DPAJCN.js';
4
4
  import '../chunk-F73MC7EZ.js';
5
- import '../chunk-OG6CL3EB.js';
6
5
  import '../chunk-Q55TXPA3.js';
7
6
  import '../chunk-BWRGFKJP.js';
8
7
  import '../chunk-FYTIJM2T.js';
9
8
  import '../chunk-PQADV6P6.js';
10
9
  import '../chunk-IG75YMUN.js';
10
+ import '../chunk-OG6CL3EB.js';
11
11
  import '../chunk-HMPFGIWM.js';
12
12
  import '../chunk-R25RGPUB.js';
13
13
  import '../chunk-RSAQOKH3.js';
@@ -1,11 +1,11 @@
1
- export { DEFAULT_TIME_WINDOW_LABELS, TIME_WINDOW_SPANS, TimeWindowPicker, describeTimeWindow, isTimeWindowSet, parseTimeWindowDuration, resolveTimeWindow, timeWindowMatchesPreset } from '../chunk-EIGEIT4O.js';
1
+ export { DEFAULT_TIME_WINDOW_LABELS, TIME_WINDOW_SPANS, TimeWindowPicker, describeTimeWindow, isTimeWindowSet, parseTimeWindowDuration, resolveTimeWindow, timeWindowMatchesPreset } from '../chunk-NUZC6PJX.js';
2
2
  import '../chunk-FC4YTTFJ.js';
3
3
  import '../chunk-F73MC7EZ.js';
4
4
  import '../chunk-GXQ3B46I.js';
5
- import '../chunk-OG6CL3EB.js';
6
5
  import '../chunk-Q55TXPA3.js';
7
6
  import '../chunk-BWRGFKJP.js';
8
7
  import '../chunk-PQADV6P6.js';
8
+ import '../chunk-OG6CL3EB.js';
9
9
  import '../chunk-HMPFGIWM.js';
10
10
  import '../chunk-R25RGPUB.js';
11
11
  import '../chunk-4FQT6ZAY.js';
@@ -1,10 +1,10 @@
1
- export { VersionTimeline } from '../chunk-WXAULPBH.js';
1
+ export { VersionTimeline } from '../chunk-UNZ7TVV5.js';
2
2
  import '../chunk-AUQPBL4O.js';
3
- import '../chunk-OG6CL3EB.js';
4
3
  import '../chunk-4KP4RC3O.js';
5
4
  import '../chunk-3CZ7XAVY.js';
6
5
  import '../chunk-EUCC37WY.js';
7
6
  import '../chunk-UAN5NE7M.js';
8
7
  import '../chunk-5OM447RW.js';
8
+ import '../chunk-OG6CL3EB.js';
9
9
  import '../chunk-BZFWDIV6.js';
10
10
  import '../chunk-ODEQTPFM.js';
@@ -1,4 +1,4 @@
1
- import { Modal } from './chunk-7IJARUIF.js';
1
+ import { Modal } from './chunk-F4DPAJCN.js';
2
2
  import { useListbox, useHighlightRest } from './chunk-F73MC7EZ.js';
3
3
  import { Kbd } from './chunk-SMBKXWML.js';
4
4
  import { Input } from './chunk-Q55TXPA3.js';
@@ -1,5 +1,5 @@
1
1
  import { Skeleton } from './chunk-W5J7R5EB.js';
2
- import { Modal } from './chunk-7IJARUIF.js';
2
+ import { Modal } from './chunk-F4DPAJCN.js';
3
3
  import { useListbox, useOptionKeys } from './chunk-F73MC7EZ.js';
4
4
  import { Input } from './chunk-Q55TXPA3.js';
5
5
  import { Popover } from './chunk-BWRGFKJP.js';
@@ -1,12 +1,13 @@
1
1
  import { useMediaMatch } from './chunk-IG75YMUN.js';
2
+ import { Menu } from './chunk-UFKUWVMV.js';
2
3
  import { useModalLayer, focusables } from './chunk-R25RGPUB.js';
3
4
  import { IconButton } from './chunk-4FQT6ZAY.js';
4
5
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
5
6
  import { cx } from './chunk-ODEQTPFM.js';
6
- import './AppShell-RUNVM4WH.css';
7
+ import './AppShell-APHZKJYH.css';
7
8
  import { createContext, forwardRef, useContext, useId, useState, useRef, useCallback, useEffect, useLayoutEffect } from 'react';
8
9
  import { breakpoint } from '@crewlethq/tokens';
9
- import { ChevronUpGlyph, ChevronRightGlyph, MenuGlyph } from '@crewlethq/icons/glyphs';
10
+ import { ChevronUpGlyph, ChevronsUpDownGlyph, ChevronRightGlyph, MenuGlyph } from '@crewlethq/icons/glyphs';
10
11
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
11
12
 
12
13
  function AccountRow({
@@ -14,6 +15,7 @@ function AccountRow({
14
15
  name,
15
16
  detail,
16
17
  href,
18
+ menu,
17
19
  current = false,
18
20
  title,
19
21
  linkSuffix = ", your account",
@@ -32,7 +34,30 @@ function AccountRow({
32
34
  ] })
33
35
  ] });
34
36
  return /* @__PURE__ */ jsxs("div", { className: cx("crewlet-account-row", className), children: [
35
- href === void 0 ? /* @__PURE__ */ jsx("span", { className: "crewlet-account-row__who", children: who }) : /* @__PURE__ */ jsxs(
37
+ menu ? /* @__PURE__ */ jsx(
38
+ Menu,
39
+ {
40
+ label: menu.label ?? "Your account",
41
+ items: menu.items,
42
+ header: menu.header,
43
+ width: "trigger",
44
+ renderTrigger: (trigger) => /* @__PURE__ */ jsxs(
45
+ "button",
46
+ {
47
+ type: "button",
48
+ className: "crewlet-account-row__who",
49
+ title,
50
+ "data-current": current ? "" : void 0,
51
+ ...trigger,
52
+ children: [
53
+ who,
54
+ /* @__PURE__ */ jsx(VisuallyHidden, { children: linkSuffix }),
55
+ /* @__PURE__ */ jsx(ChevronsUpDownGlyph, { size: "xs", className: "crewlet-account-row__go", "aria-hidden": "true" })
56
+ ]
57
+ }
58
+ )
59
+ }
60
+ ) : href === void 0 ? /* @__PURE__ */ jsx("span", { className: "crewlet-account-row__who", children: who }) : /* @__PURE__ */ jsxs(
36
61
  "a",
37
62
  {
38
63
  className: "crewlet-account-row__who",
@@ -1,10 +1,10 @@
1
- import { Menu } from './chunk-JULMZNGT.js';
2
1
  import { useClipboard } from './chunk-STJ7QBC3.js';
3
- import { Modal } from './chunk-7IJARUIF.js';
4
- import { Button } from './chunk-OG6CL3EB.js';
2
+ import { Modal } from './chunk-F4DPAJCN.js';
5
3
  import { Checkbox } from './chunk-I6NZKJGK.js';
6
4
  import { EmptyValue } from './chunk-EUCC37WY.js';
7
5
  import { useCardHeaderSlot } from './chunk-AV2DXAEL.js';
6
+ import { Menu } from './chunk-UFKUWVMV.js';
7
+ import { Button } from './chunk-OG6CL3EB.js';
8
8
  import { IconButton } from './chunk-4FQT6ZAY.js';
9
9
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
10
10
  import { cx } from './chunk-ODEQTPFM.js';
@@ -1,15 +1,15 @@
1
1
  import { PageHeader } from './chunk-HOXGBLEY.js';
2
2
  import { Toolbar } from './chunk-PGRPNDWM.js';
3
- import { DataTable } from './chunk-AJESMWJS.js';
4
- import { Menu } from './chunk-JULMZNGT.js';
5
- import { DateTimePicker } from './chunk-L4H7SSWF.js';
3
+ import { DateTimePicker } from './chunk-RE6ED5TO.js';
4
+ import { DataTable } from './chunk-BXSGT3YC.js';
6
5
  import { useListbox, useOptionKeys } from './chunk-F73MC7EZ.js';
7
6
  import { Kbd } from './chunk-SMBKXWML.js';
8
- import { Button } from './chunk-OG6CL3EB.js';
9
7
  import { Input } from './chunk-Q55TXPA3.js';
10
8
  import { RelativeTime } from './chunk-3CZ7XAVY.js';
11
9
  import { Popover } from './chunk-BWRGFKJP.js';
12
10
  import { Count } from './chunk-BHHIIK3M.js';
11
+ import { Menu } from './chunk-UFKUWVMV.js';
12
+ import { Button } from './chunk-OG6CL3EB.js';
13
13
  import { IconButton } from './chunk-4FQT6ZAY.js';
14
14
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
15
15
  import { cx } from './chunk-ODEQTPFM.js';
@@ -1,5 +1,5 @@
1
+ import { ConfirmModal } from './chunk-F4DPAJCN.js';
1
2
  import { InlineCode } from './chunk-5CLW2CXT.js';
2
- import { ConfirmModal } from './chunk-7IJARUIF.js';
3
3
  import { Callout } from './chunk-SVSCLHHI.js';
4
4
  import './LinkInterstitial-ET4MSVSV.css';
5
5
  import { jsx, jsxs } from 'react/jsx-runtime';