@hanzo/ui 8.27.18 → 8.27.20
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.
- package/dist/backends/gui/apple-cards-carousel.cjs +1 -1
- package/dist/backends/gui/apple-cards-carousel.d.ts.map +1 -1
- package/dist/backends/gui/apple-cards-carousel.js +1 -1
- package/dist/backends/gui/apple-cards-carousel.js.map +1 -1
- package/dist/backends/gui/dialog.cjs +1 -1
- package/dist/backends/gui/dialog.d.ts.map +1 -1
- package/dist/backends/gui/dialog.js +1 -1
- package/dist/backends/gui/dialog.js.map +1 -1
- package/dist/backends/gui/input.cjs +5 -1
- package/dist/backends/gui/input.d.ts.map +1 -1
- package/dist/backends/gui/input.js +5 -1
- package/dist/backends/gui/input.js.map +1 -1
- package/dist/backends/gui/item.cjs +2 -3
- package/dist/backends/gui/item.d.ts.map +1 -1
- package/dist/backends/gui/item.js +1 -2
- package/dist/backends/gui/item.js.map +1 -1
- package/dist/backends/gui/press.cjs +29 -0
- package/dist/backends/gui/press.d.ts +28 -0
- package/dist/backends/gui/press.d.ts.map +1 -0
- package/dist/backends/gui/press.js +26 -0
- package/dist/backends/gui/press.js.map +1 -0
- package/dist/backends/gui/slider.cjs +5 -1
- package/dist/backends/gui/slider.d.ts.map +1 -1
- package/dist/backends/gui/slider.js +5 -1
- package/dist/backends/gui/slider.js.map +1 -1
- package/dist/backends/gui/toggle-group.cjs +2 -3
- package/dist/backends/gui/toggle-group.d.ts.map +1 -1
- package/dist/backends/gui/toggle-group.js +1 -2
- package/dist/backends/gui/toggle-group.js.map +1 -1
- package/dist/backends/gui/toggle.cjs +3 -4
- package/dist/backends/gui/toggle.d.ts.map +1 -1
- package/dist/backends/gui/toggle.js +1 -2
- package/dist/backends/gui/toggle.js.map +1 -1
- package/dist/catalog/Shelf.cjs +76 -0
- package/dist/catalog/Shelf.d.ts +55 -0
- package/dist/catalog/Shelf.d.ts.map +1 -0
- package/dist/catalog/Shelf.js +74 -0
- package/dist/catalog/Shelf.js.map +1 -0
- package/dist/catalog/Tile.cjs +72 -0
- package/dist/catalog/Tile.d.ts +56 -0
- package/dist/catalog/Tile.d.ts.map +1 -0
- package/dist/catalog/Tile.js +67 -0
- package/dist/catalog/Tile.js.map +1 -0
- package/dist/catalog/index.cjs +23 -0
- package/dist/catalog/index.d.ts +16 -0
- package/dist/catalog/index.d.ts.map +1 -0
- package/dist/catalog/index.js +16 -0
- package/dist/catalog/index.js.map +1 -0
- package/dist/chat/Home.cjs +30 -0
- package/dist/chat/Home.d.ts +35 -0
- package/dist/chat/Home.d.ts.map +1 -0
- package/dist/chat/Home.js +28 -0
- package/dist/chat/Home.js.map +1 -0
- package/dist/chat/SessionRail.cjs +165 -37
- package/dist/chat/SessionRail.d.ts +92 -14
- package/dist/chat/SessionRail.d.ts.map +1 -1
- package/dist/chat/SessionRail.js +165 -39
- package/dist/chat/SessionRail.js.map +1 -1
- package/dist/chat/index.cjs +6 -1
- package/dist/chat/index.d.ts +2 -1
- package/dist/chat/index.d.ts.map +1 -1
- package/dist/chat/index.js +2 -1
- package/dist/chat/index.js.map +1 -1
- package/dist/gallery.cjs +72 -1
- package/dist/gallery.d.ts +13 -0
- package/dist/gallery.d.ts.map +1 -1
- package/dist/gallery.html +45 -3
- package/dist/gallery.js +72 -2
- package/dist/gallery.js.map +1 -1
- package/dist/product/ChipSelect.cjs +2 -3
- package/dist/product/ChipSelect.d.ts.map +1 -1
- package/dist/product/ChipSelect.js +1 -2
- package/dist/product/ChipSelect.js.map +1 -1
- package/dist/product/MenuRow.cjs +2 -1
- package/dist/product/MenuRow.d.ts +11 -7
- package/dist/product/MenuRow.d.ts.map +1 -1
- package/dist/product/MenuRow.js +3 -2
- package/dist/product/MenuRow.js.map +1 -1
- package/dist/product/OrgSwitcher.cjs +16 -5
- package/dist/product/OrgSwitcher.d.ts.map +1 -1
- package/dist/product/OrgSwitcher.js +16 -5
- package/dist/product/OrgSwitcher.js.map +1 -1
- package/dist/product/UserMenu.cjs +19 -27
- package/dist/product/UserMenu.d.ts +2 -21
- package/dist/product/UserMenu.d.ts.map +1 -1
- package/dist/product/UserMenu.js +23 -31
- package/dist/product/UserMenu.js.map +1 -1
- package/dist/product/account.cjs +37 -0
- package/dist/product/account.d.ts +55 -0
- package/dist/product/account.d.ts.map +1 -0
- package/dist/product/account.js +35 -0
- package/dist/product/account.js.map +1 -0
- package/dist/product/menu/roving.cjs +4 -1
- package/dist/product/menu/roving.d.ts +8 -3
- package/dist/product/menu/roving.d.ts.map +1 -1
- package/dist/product/menu/roving.js +4 -1
- package/dist/product/menu/roving.js.map +1 -1
- package/dist/settings/Section.cjs +71 -0
- package/dist/settings/Section.d.ts +78 -0
- package/dist/settings/Section.d.ts.map +1 -0
- package/dist/settings/Section.js +62 -0
- package/dist/settings/Section.js.map +1 -0
- package/dist/settings/Settings.cjs +54 -0
- package/dist/settings/Settings.d.ts +50 -0
- package/dist/settings/Settings.d.ts.map +1 -0
- package/dist/settings/Settings.js +52 -0
- package/dist/settings/Settings.js.map +1 -0
- package/dist/settings/index.cjs +26 -0
- package/dist/settings/index.d.ts +15 -0
- package/dist/settings/index.d.ts.map +1 -0
- package/dist/settings/index.js +15 -0
- package/dist/settings/index.js.map +1 -0
- package/dist/styles.css +42 -0
- package/package.json +13 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Home.js","sourceRoot":"","sources":["../../src/chat/Home.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAGpE,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAA;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AAIpC,2EAA2E;AAC3E,MAAM,MAAM,GAAG,GAAG,CAAA;AAelB,MAAM,UAAU,IAAI,CAAC,EAAE,KAAK,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,GAAG,CAAC,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAa;IACnG,OAAO,CAKL,KAAC,UAAU,OACL,IAAI,CAAC,MAAM,CAAC,EAChB,IAAI,EAAE,CAAC,EACP,IAAI,EAAE,CAAC,EACP,IAAI,EAAE,CAAC,EACP,SAAS,EAAC,MAAM,EAChB,4BAA4B,EAAE,KAAK,EACnC,qBAAqB,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,KACjD,IAAI,YAGR,KAAC,MAAM,IAAC,KAAK,EAAC,MAAM,EAAC,KAAK,EAAC,QAAQ,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,KAAK,YAClD,MAAC,MAAM,IAAC,KAAK,EAAC,MAAM,EAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAC,IAAI,aAC3C,MAAC,MAAM,IAAC,OAAO,EAAC,QAAQ,EAAC,KAAK,EAAC,QAAQ,EAAC,GAAG,EAAC,IAAI,EAAC,QAAQ,EAAC,MAAM,aAC7D,IAAI,CAAC,CAAC,CAAC,CACN,KAAC,MAAM,OAAK,IAAI,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAC,QAAQ,iCACrD,IAAI,GACE,CACV,CAAC,CAAC,CAAC,IAAI,EACR,KAAC,WAAW,OACN,IAAI,CAAC,YAAY,CAAC,EACtB,IAAI,EAAC,SAAS,gBACF,KAAK,EACjB,IAAI,EAAC,IAAI,EACT,KAAK,EAAC,MAAM,EACZ,IAAI,EAAC,QAAQ,YAEZ,KAAK,GACM,IACP,EACR,QAAQ,CAAC,CAAC,CAAC,KAAC,MAAM,IAAC,GAAG,EAAC,IAAI,YAAE,QAAQ,GAAU,CAAC,CAAC,CAAC,IAAI,IAC9C,GACF,GACE,CACd,CAAA;AACH,CAAC"}
|
|
@@ -3,43 +3,59 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.StatusDot = StatusDot;
|
|
5
5
|
exports.SessionRail = SessionRail;
|
|
6
|
+
exports.RailNotice = RailNotice;
|
|
7
|
+
exports.RailBar = RailBar;
|
|
6
8
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
7
9
|
/**
|
|
8
|
-
* SessionRail — the left rail of a sessions surface:
|
|
9
|
-
* reopen a recent one, and who you are.
|
|
10
|
+
* SessionRail — the left rail of a sessions surface: who it is, find one, start
|
|
11
|
+
* one, go somewhere, reopen a recent one, and who you are.
|
|
10
12
|
*
|
|
13
|
+
* Hanzo Build the brand; pressing it starts a new session
|
|
14
|
+
* [⌕ Search ] finds a session
|
|
11
15
|
* + New the primary row; the current view on a fresh pane
|
|
12
16
|
* Artifacts · Customize … the surface's own places, as `links`
|
|
13
17
|
* More ⌄ a disclosure over `more`, when there are more
|
|
14
18
|
* Recents ⇅ the sessions, newest first, each with a status dot
|
|
15
|
-
*
|
|
19
|
+
* [ Try Hanzo in Slack × ] `notice` — a `RailNotice`, when the host has one
|
|
20
|
+
* (D) Dave ⌄ ◧ the account and its menu, then collapse
|
|
21
|
+
* acme
|
|
16
22
|
*
|
|
17
23
|
* Presentational: no routing, no fetching. `active` comes in, `onOpen` goes out.
|
|
18
24
|
*
|
|
19
|
-
* THE SIDEBAR CANON (console, hanzo.app, hanzo.chat, the extension):
|
|
25
|
+
* THE SIDEBAR CANON (console, hanzo.app, hanzo.chat, hanzo.build, the extension):
|
|
20
26
|
* - Collapse is an EXPLICIT toggle and the host persists it. `collapsed` in,
|
|
21
27
|
* `onCollapse` out. There is no hover-to-expand and no pin.
|
|
22
28
|
* - Collapsed is a narrow RAIL that stays on screen — icons only, labels as
|
|
23
29
|
* tooltips — and its top row is the expand control.
|
|
24
|
-
* - Below `md` there is no rail at all. The column hides,
|
|
25
|
-
*
|
|
26
|
-
*
|
|
30
|
+
* - Below `md` there is no rail at all. The column hides, `RailBar` is the
|
|
31
|
+
* pane's header (menu · brand · search), and its menu opens the same
|
|
32
|
+
* contents as a drawer from the left (`open`, `onOpenChange`). Anything
|
|
33
|
+
* chosen in the drawer closes it: the drawer is the way to a place, not a
|
|
34
|
+
* place.
|
|
35
|
+
*
|
|
36
|
+
* ONE WAY to each thing. Search is the box in the head (an icon on the collapsed
|
|
37
|
+
* rail); settings, usage and signing out are rows of the account menu. There is
|
|
38
|
+
* no second search or settings control at the foot.
|
|
27
39
|
*
|
|
28
40
|
* Built from the chat `Sidebar` column and its icon button, so the rail is the
|
|
29
|
-
* same material as every other chat surface's.
|
|
41
|
+
* same material as every other chat surface's. The account menu is the same
|
|
42
|
+
* body `UserMenu` draws (`product/account.tsx`), anchored to the account row
|
|
43
|
+
* itself — above it on the open rail, beside it on the collapsed one.
|
|
30
44
|
*/
|
|
31
45
|
const gui_1 = require("@hanzo/gui");
|
|
32
46
|
const lucide_icons_2_1 = require("@hanzogui/lucide-icons-2");
|
|
33
47
|
const react_1 = require("react");
|
|
48
|
+
const button_1 = require("../backends/gui/button.cjs");
|
|
49
|
+
const popover_1 = require("../backends/gui/popover.cjs");
|
|
50
|
+
const press_1 = require("../backends/gui/press.cjs");
|
|
34
51
|
const sheet_1 = require("../backends/gui/sheet.cjs");
|
|
35
52
|
const slot_1 = require("../backends/gui/slot.cjs");
|
|
53
|
+
const account_1 = require("../product/account.cjs");
|
|
36
54
|
const Sidebar_1 = require("./Sidebar.cjs");
|
|
37
55
|
/** Expanded width, px — the column's own width, its hairline outside it. */
|
|
38
56
|
const WIDTH = 272;
|
|
39
57
|
/** Collapsed width, px. The same rail width every chat surface collapses to. */
|
|
40
58
|
const RAIL = 56;
|
|
41
|
-
/** The keyboard focus ring every control in the package draws. */
|
|
42
|
-
const RING = { outlineColor: '$outlineColor', outlineWidth: 2, outlineStyle: 'solid' };
|
|
43
59
|
/** One row: 32px, the 8px radius, icon then label. */
|
|
44
60
|
const ROW = { minH: 32, px: '$2', rounded: '$3', gap: '$2.5' };
|
|
45
61
|
/** The status mark: a 6px dot, filled while something is happening. */
|
|
@@ -52,46 +68,158 @@ function StatusDot({ status = 'idle' }) {
|
|
|
52
68
|
}
|
|
53
69
|
/** Where a row starts: the 16px column every icon and dot sits centred in. */
|
|
54
70
|
const Lead = ({ children }) => ((0, jsx_runtime_1.jsx)(gui_1.XStack, { width: 16, height: 16, shrink: 0, items: "center", justify: "center", children: children }));
|
|
71
|
+
/**
|
|
72
|
+
* The surface's name, the head's first line and the phone bar's middle. A
|
|
73
|
+
* press when there is somewhere to go; the words alone otherwise.
|
|
74
|
+
*/
|
|
75
|
+
function Brand({ brand, onPress }) {
|
|
76
|
+
const face = typeof brand === 'string' ? ((0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$5", fontWeight: "600", color: "$ink", numberOfLines: 1, children: brand })) : (brand);
|
|
77
|
+
if (!onPress)
|
|
78
|
+
return (0, jsx_runtime_1.jsx)(gui_1.XStack, { ...(0, slot_1.slot)('rail-brand'), items: "center", minW: 0, children: face });
|
|
79
|
+
return ((0, jsx_runtime_1.jsx)(gui_1.XStack, { ...(0, slot_1.slot)('rail-brand'), ...(0, press_1.press)(onPress), items: "center", minW: 0, rounded: "$2", cursor: "pointer", focusVisibleStyle: press_1.RING, children: face }));
|
|
80
|
+
}
|
|
55
81
|
/** One nav row. On the rail it is the icon alone, the label its tooltip and name. */
|
|
56
|
-
function
|
|
57
|
-
return ((0, jsx_runtime_1.jsxs)(gui_1.XStack, { ...(0, slot_1.slot)(data), ...(rail ? (0, slot_1.tip)(label) : null), ...ROW, items: "center", justify: rail ? 'center' : 'flex-start', cursor: "pointer",
|
|
58
|
-
if (e?.key !== 'Enter' && e?.key !== ' ')
|
|
59
|
-
return;
|
|
60
|
-
e.preventDefault?.();
|
|
61
|
-
onPress?.();
|
|
62
|
-
}, children: [(0, jsx_runtime_1.jsx)(Lead, { children: icon }), rail ? null : ((0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$3", numberOfLines: 1, flex: 1, color: quiet ? '$soft' : '$ink', children: label }))] }));
|
|
82
|
+
function Item({ label, icon, onPress, active, rail, quiet, expanded, controls, data = 'rail-row' }) {
|
|
83
|
+
return ((0, jsx_runtime_1.jsxs)(gui_1.XStack, { ...(0, slot_1.slot)(data), ...(rail ? (0, slot_1.tip)(label) : null), ...(0, press_1.press)(onPress), ...ROW, items: "center", justify: rail ? 'center' : 'flex-start', cursor: "pointer", "aria-label": rail ? label : undefined, "aria-current": active ? 'page' : undefined, "aria-expanded": expanded, "aria-controls": controls, bg: active ? '$raised' : undefined, hoverStyle: { bg: active ? '$raised' : '$hover' }, pressStyle: { bg: '$raised' }, focusVisibleStyle: press_1.RING, children: [(0, jsx_runtime_1.jsx)(Lead, { children: icon }), rail ? null : ((0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$3", numberOfLines: 1, flex: 1, color: quiet ? '$soft' : '$ink', children: label }))] }));
|
|
63
84
|
}
|
|
64
|
-
/** The
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
85
|
+
/** The menu exists when there is something in it to do. */
|
|
86
|
+
const hasMenu = (a) => Boolean(a.onSignOut || a.groups?.some((g) => (Array.isArray(g) ? g : g.items).length));
|
|
87
|
+
/**
|
|
88
|
+
* The account row: avatar, the name over its second line, the caret — and the
|
|
89
|
+
* menu it opens, anchored to the row itself.
|
|
90
|
+
*/
|
|
91
|
+
function Who({ account, rail }) {
|
|
92
|
+
const [open, setOpen] = (0, react_1.useState)(false);
|
|
93
|
+
// The row, so closing the menu can hand focus back to it: the popover's own
|
|
94
|
+
// return goes through a trigger ref that an `asChild` stack never fills.
|
|
95
|
+
const row = (0, react_1.useRef)(null);
|
|
96
|
+
const menu = hasMenu(account);
|
|
97
|
+
const acts = menu || Boolean(account.onPress);
|
|
98
|
+
const said = account.sub ? `${account.name} · ${account.sub}` : account.name;
|
|
99
|
+
const face = ((0, jsx_runtime_1.jsx)(gui_1.XStack, { width: 24, height: 24, rounded: 9999, items: "center", justify: "center", bg: "$raised", overflow: "hidden", shrink: 0, "aria-hidden": true, children: account.avatar ?? ((0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$1", fontWeight: "600", color: "$ink", children: account.name.charAt(0).toUpperCase() })) }));
|
|
100
|
+
const look = {
|
|
101
|
+
...(0, slot_1.slot)('rail-account'),
|
|
102
|
+
...(rail ? (0, slot_1.tip)(said) : null),
|
|
103
|
+
...ROW,
|
|
104
|
+
gap: '$2',
|
|
105
|
+
px: '$1',
|
|
106
|
+
flex: rail ? undefined : 1,
|
|
107
|
+
minW: 0,
|
|
108
|
+
items: 'center',
|
|
109
|
+
justify: rail ? 'center' : 'flex-start',
|
|
110
|
+
cursor: acts ? 'pointer' : undefined,
|
|
111
|
+
hoverStyle: acts ? { bg: '$hover' } : undefined,
|
|
112
|
+
focusVisibleStyle: acts ? press_1.RING : undefined,
|
|
113
|
+
};
|
|
114
|
+
const body = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [face, rail ? null : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(gui_1.YStack, { flex: 1, minW: 0, children: [(0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$3", numberOfLines: 1, color: "$ink", children: account.name }), account.sub ? ((0, jsx_runtime_1.jsx)(gui_1.SizableText, { ...(0, slot_1.slot)('rail-account-sub'), size: "$1", numberOfLines: 1, color: "$soft", children: account.sub })) : null] }), acts ? (0, jsx_runtime_1.jsx)(lucide_icons_2_1.ChevronDown, { size: 14, color: "$soft" }) : null] }))] }));
|
|
115
|
+
if (!menu)
|
|
116
|
+
return account.onPress ? ((0, jsx_runtime_1.jsx)(gui_1.XStack, { ...look, ...(0, press_1.press)(account.onPress), "aria-label": `Account: ${said}`, children: body })) : ((0, jsx_runtime_1.jsx)(gui_1.XStack, { ...look, children: body }));
|
|
117
|
+
return ((0, jsx_runtime_1.jsxs)(popover_1.Popover, { open: open, onOpenChange: setOpen,
|
|
118
|
+
// Above the row on the open rail, where the row spans the column; beside
|
|
119
|
+
// it on the collapsed rail, where above would cover the rail's icons.
|
|
120
|
+
placement: rail ? 'right-end' : 'top-start', allowFlip: true, stayInFrame: true, children: [(0, jsx_runtime_1.jsx)(popover_1.PopoverTrigger, { asChild: true, children: (0, jsx_runtime_1.jsx)(gui_1.XStack, { ref: row, ...look, role: "button", tabIndex: 0, "aria-label": `Account: ${said}`, "aria-haspopup": "menu", "aria-expanded": open,
|
|
121
|
+
// The trigger opens on a press; the keyboard is this row's own (gui
|
|
122
|
+
// does not activate role="button" on Enter).
|
|
123
|
+
onKeyDown: (e) => {
|
|
124
|
+
if (e?.key !== 'Enter' && e?.key !== ' ')
|
|
125
|
+
return;
|
|
126
|
+
e.preventDefault?.();
|
|
127
|
+
setOpen(!open);
|
|
128
|
+
}, children: body }) }), (0, jsx_runtime_1.jsx)(popover_1.PopoverContent, { ...(0, slot_1.slot)('rail-menu'), role: "menu", "aria-label": "Account", sideOffset: 6,
|
|
129
|
+
// A menu's rows run its full width; gui's popper centres children.
|
|
130
|
+
// 260 fits a 390 phone's drawer, and the popper keeps it in frame.
|
|
131
|
+
items: "stretch", width: 260, p: "$1", rounded: "$3", elevation: "$2", onCloseAutoFocus: (e) => {
|
|
132
|
+
e.preventDefault();
|
|
133
|
+
row.current?.focus();
|
|
134
|
+
}, children: (0, jsx_runtime_1.jsx)(account_1.Account, { name: account.name, email: account.email, groups: account.groups, onSignOut: account.onSignOut, signOutLabel: account.signOutLabel, onDone: () => setOpen(false), component: "SessionRail" }) })] }));
|
|
73
135
|
}
|
|
74
136
|
/** The rail's contents — the same tree in the column and in the drawer. */
|
|
75
|
-
function Contents({ onNew, newLabel = 'New', fresh = false, links = [], more = [], moreLabel = 'More', recents, recentsLabel = 'Recents', active = null, onOpen, onSort, sortLabel = 'Sort and filter', empty, notice, account,
|
|
137
|
+
function Contents({ brand, onBrand, onSearch, searchLabel = 'Search', onNew, newLabel = 'New', fresh = false, links = [], more = [], moreLabel = 'More', recents, recentsLabel = 'Recents', active = null, onOpen, onSort, sortLabel = 'Sort and filter', empty, notice, account, collapsed = false, onCollapse, mark, rail, }) {
|
|
76
138
|
const [unfolded, setUnfolded] = (0, react_1.useState)(false);
|
|
77
139
|
const id = (0, react_1.useId)();
|
|
78
140
|
const moreId = `${id}-more`;
|
|
79
141
|
const headId = `${id}-recents`;
|
|
80
|
-
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [rail ? ((0, jsx_runtime_1.
|
|
142
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [rail ? ((0, jsx_runtime_1.jsxs)(gui_1.YStack, { items: "center", gap: "$1", pb: "$1", children: [(0, jsx_runtime_1.jsx)(Sidebar_1.SidebarIconButton, { label: "Expand sidebar", width: 36, height: 36, onPress: () => onCollapse?.(false), children: mark ?? (0, jsx_runtime_1.jsx)(lucide_icons_2_1.PanelLeft, { size: 16 }) }), onSearch ? ((0, jsx_runtime_1.jsx)(Item, { label: searchLabel, icon: (0, jsx_runtime_1.jsx)(lucide_icons_2_1.Search, { size: 16 }), onPress: onSearch, rail: true, data: "rail-search" })) : null] })) : brand || onSearch ? ((0, jsx_runtime_1.jsxs)(gui_1.YStack, { ...(0, slot_1.slot)('rail-head'), gap: "$2.5", pt: 2, pb: "$4", shrink: 0, children: [brand ? ((0, jsx_runtime_1.jsx)(gui_1.XStack, { px: "$2.5", children: (0, jsx_runtime_1.jsx)(Brand, { brand: brand, onPress: onBrand ?? onNew }) })) : null, onSearch ? ((0, jsx_runtime_1.jsxs)(gui_1.XStack, { ...(0, slot_1.slot)('rail-search'), ...(0, press_1.press)(onSearch), "aria-label": searchLabel, items: "center", gap: "$2", px: "$2.5", height: 34, rounded: "$3", borderWidth: 1, borderColor: "$borderColor", bg: "$panel", cursor: "pointer", hoverStyle: { bg: '$hover' }, focusVisibleStyle: press_1.RING, children: [(0, jsx_runtime_1.jsx)(lucide_icons_2_1.Search, { size: 15, color: "$soft" }), (0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$2", color: "$soft", children: searchLabel })] })) : null] })) : null, (0, jsx_runtime_1.jsxs)(gui_1.YStack, { ...(0, slot_1.slot)('rail-nav'), gap: "$0", role: "list", children: [onNew ? ((0, jsx_runtime_1.jsx)(gui_1.YStack, { role: "listitem", children: (0, jsx_runtime_1.jsx)(Item, { label: newLabel, icon: (0, jsx_runtime_1.jsx)(lucide_icons_2_1.Plus, { size: 16 }), onPress: onNew, active: fresh, rail: rail, data: "rail-new" }) })) : null, links.map((link) => ((0, jsx_runtime_1.jsx)(gui_1.YStack, { role: "listitem", children: (0, jsx_runtime_1.jsx)(Item, { label: link.label, icon: link.icon, onPress: link.onPress, active: link.active, rail: rail }) }, link.id))), more.length ? ((0, jsx_runtime_1.jsxs)(gui_1.YStack, { role: "listitem", children: [(0, jsx_runtime_1.jsx)(Item, { label: moreLabel, icon: unfolded ? (0, jsx_runtime_1.jsx)(lucide_icons_2_1.ChevronUp, { size: 16 }) : (0, jsx_runtime_1.jsx)(lucide_icons_2_1.ChevronDown, { size: 16 }), onPress: () => setUnfolded((v) => !v), rail: rail, quiet: true, expanded: unfolded, controls: moreId, data: "rail-more" }), unfolded ? ((0, jsx_runtime_1.jsx)(gui_1.YStack, { id: moreId, role: "list", gap: "$0", children: more.map((link) => ((0, jsx_runtime_1.jsx)(gui_1.YStack, { role: "listitem", children: (0, jsx_runtime_1.jsx)(Item, { label: link.label, icon: link.icon, onPress: link.onPress, active: link.active, rail: rail }) }, link.id))) })) : null] })) : null] }), rail ? ((0, jsx_runtime_1.jsx)(gui_1.YStack, { flex: 1 })) : ((0, jsx_runtime_1.jsxs)(gui_1.YStack, { ...(0, slot_1.slot)('rail-recents'), flex: 1, minH: 0, mt: "$5", children: [(0, jsx_runtime_1.jsxs)(gui_1.XStack, { items: "center", justify: "space-between", height: 28, pl: "$2", pr: "$1", shrink: 0, children: [(0, jsx_runtime_1.jsx)(gui_1.SizableText, { id: headId, size: "$2", color: "$soft", children: recentsLabel }), onSort ? ((0, jsx_runtime_1.jsx)(Sidebar_1.SidebarIconButton, { label: sortLabel, onPress: onSort, width: 24, height: 24, children: (0, jsx_runtime_1.jsx)(lucide_icons_2_1.ArrowDownUp, { size: 14 }) })) : null] }), (0, jsx_runtime_1.jsx)(gui_1.ScrollView, { flex: 1, showsVerticalScrollIndicator: false, children: recents.length === 0 ? (empty ? ((0, jsx_runtime_1.jsx)(gui_1.YStack, { px: "$2", py: "$2", children: typeof empty === 'string' ? ((0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$2", color: "$soft", children: empty })) : (empty) })) : null) : ((0, jsx_runtime_1.jsx)(gui_1.YStack, { role: "list", "aria-labelledby": headId, gap: 1, children: recents.map((s) => {
|
|
81
143
|
const on = s.id === active;
|
|
82
|
-
return ((0, jsx_runtime_1.jsx)(gui_1.YStack, { role: "listitem", children: (0, jsx_runtime_1.jsxs)(gui_1.XStack, { ...(0, slot_1.slot)('rail-session'), ...ROW, items: "center", cursor: "pointer",
|
|
83
|
-
|
|
84
|
-
return;
|
|
85
|
-
e.preventDefault?.();
|
|
86
|
-
onOpen(s.id);
|
|
87
|
-
}, children: [(0, jsx_runtime_1.jsx)(Lead, { children: (0, jsx_runtime_1.jsx)(StatusDot, { status: s.status }) }), (0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$3", numberOfLines: 1, flex: 1, minW: 0, color: on ? '$ink' : '$quiet', children: s.title })] }) }, s.id));
|
|
88
|
-
}) })) })] })), notice && !rail ? (0, jsx_runtime_1.jsx)(gui_1.YStack, { pt: "$2", children: notice }) : null, (0, jsx_runtime_1.jsxs)(gui_1.XStack, { ...(0, slot_1.slot)('rail-foot'), items: "center", gap: "$1", pt: "$2", mt: "$1", borderTopWidth: 1, borderColor: "$borderColor", flexDirection: rail ? 'column' : 'row', children: [account ? (0, jsx_runtime_1.jsx)(Account, { account: account, rail: rail }) : (0, jsx_runtime_1.jsx)(gui_1.XStack, { flex: 1 }), onSettings ? ((0, jsx_runtime_1.jsx)(Sidebar_1.SidebarIconButton, { label: "Settings", onPress: onSettings, children: (0, jsx_runtime_1.jsx)(lucide_icons_2_1.Settings, { size: 16 }) })) : null, onSearch ? ((0, jsx_runtime_1.jsx)(Sidebar_1.SidebarIconButton, { label: "Search", onPress: onSearch, children: (0, jsx_runtime_1.jsx)(lucide_icons_2_1.Search, { size: 16 }) })) : null, onCollapse && !rail ? ((0, jsx_runtime_1.jsx)(Sidebar_1.SidebarIconButton, { label: "Collapse sidebar", onPress: () => onCollapse(!collapsed), children: (0, jsx_runtime_1.jsx)(lucide_icons_2_1.PanelLeft, { size: 16 }) })) : null] })] }));
|
|
144
|
+
return ((0, jsx_runtime_1.jsx)(gui_1.YStack, { role: "listitem", children: (0, jsx_runtime_1.jsxs)(gui_1.XStack, { ...(0, slot_1.slot)('rail-session'), ...(0, press_1.press)(() => onOpen(s.id)), ...ROW, items: "center", cursor: "pointer", "aria-current": on ? 'page' : undefined, bg: on ? '$raised' : undefined, hoverStyle: { bg: on ? '$raised' : '$hover' }, pressStyle: { bg: '$raised' }, focusVisibleStyle: press_1.RING, children: [(0, jsx_runtime_1.jsx)(Lead, { children: (0, jsx_runtime_1.jsx)(StatusDot, { status: s.status }) }), (0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$3", numberOfLines: 1, flex: 1, minW: 0, color: on ? '$ink' : '$quiet', children: s.title })] }) }, s.id));
|
|
145
|
+
}) })) })] })), notice && !rail ? (0, jsx_runtime_1.jsx)(gui_1.YStack, { pt: "$2", children: notice }) : null, (0, jsx_runtime_1.jsxs)(gui_1.XStack, { ...(0, slot_1.slot)('rail-foot'), items: "center", gap: "$1", pt: "$2", mt: "$1", borderTopWidth: 1, borderColor: "$borderColor", flexDirection: rail ? 'column' : 'row', children: [account ? (0, jsx_runtime_1.jsx)(Who, { account: account, rail: rail }) : (0, jsx_runtime_1.jsx)(gui_1.XStack, { flex: 1 }), onCollapse && !rail ? ((0, jsx_runtime_1.jsx)(Sidebar_1.SidebarIconButton, { label: "Collapse sidebar", onPress: () => onCollapse(!collapsed), children: (0, jsx_runtime_1.jsx)(lucide_icons_2_1.PanelLeft, { size: 16 }) })) : null] })] }));
|
|
89
146
|
}
|
|
147
|
+
/** `run`, then close the drawer — or nothing, when there is nothing to run. */
|
|
148
|
+
const closing = (close) => (run) => run ? (...args) => (close(), run(...args)) : undefined;
|
|
90
149
|
function SessionRail(props) {
|
|
91
150
|
const {
|
|
92
151
|
// Everything the contents read is named here, so none of it reaches the
|
|
93
152
|
// column as a stray DOM attribute through `rest`.
|
|
94
|
-
onNew, newLabel, fresh, links, more, moreLabel, recents, recentsLabel, active, onOpen, onSort, sortLabel, empty, notice, account,
|
|
153
|
+
brand, onBrand, onSearch, searchLabel, onNew, newLabel, fresh, links, more, moreLabel, recents, recentsLabel, active, onOpen, onSort, sortLabel, empty, notice, account, collapsed = false, onCollapse, mark, open = false, onOpenChange, label = 'Sessions', width = WIDTH, ...rest } = props;
|
|
95
154
|
const rail = collapsed;
|
|
96
|
-
|
|
155
|
+
// Where focus was when the drawer opened — the phone bar's menu button — and
|
|
156
|
+
// where it goes back to when the drawer closes, by Escape or by a choice. A
|
|
157
|
+
// dialog returns focus to its own trigger, and this drawer has none: the host
|
|
158
|
+
// opens it from `RailBar`, which the dialog cannot see.
|
|
159
|
+
//
|
|
160
|
+
// Read in RENDER, on the one render where `open` turns true — before the
|
|
161
|
+
// drawer exists. gui's Dialog is a native `<dialog>`, and a browser moves focus
|
|
162
|
+
// into one the moment it opens, so by any effect (the focus scope's own
|
|
163
|
+
// `onOpenAutoFocus` included, which then never fires because focus is already
|
|
164
|
+
// inside) the opener is gone. jsdom's `<dialog>` moves nothing, which is why
|
|
165
|
+
// the unit suite could not see this and the consumer suite asserts it.
|
|
166
|
+
const back = (0, react_1.useRef)(null);
|
|
167
|
+
const was = (0, react_1.useRef)(false);
|
|
168
|
+
if (open && !was.current && typeof document !== 'undefined')
|
|
169
|
+
back.current = document.activeElement;
|
|
170
|
+
was.current = open;
|
|
171
|
+
// One way out, said ONCE per gesture. A choice closes the drawer, and the
|
|
172
|
+
// dialog can also report its own dismissal while it unmounts in that same
|
|
173
|
+
// turn; the host hears one `onOpenChange(false)`. The latch lets go after the
|
|
174
|
+
// turn, so a host that keeps the drawer open still hears the next choice.
|
|
175
|
+
const closed = (0, react_1.useRef)(false);
|
|
176
|
+
const close = () => {
|
|
177
|
+
if (closed.current)
|
|
178
|
+
return;
|
|
179
|
+
closed.current = true;
|
|
180
|
+
setTimeout(() => {
|
|
181
|
+
closed.current = false;
|
|
182
|
+
}, 0);
|
|
183
|
+
onOpenChange?.(false);
|
|
184
|
+
};
|
|
185
|
+
const shut = closing(close);
|
|
186
|
+
const relink = (list) => list?.map((l) => ({ ...l, onPress: shut(l.onPress) }));
|
|
187
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(Sidebar_1.Sidebar, { ...(0, slot_1.slot)('session-rail'), role: "navigation", "aria-label": label, "data-collapsed": rail ? 'true' : 'false', width: rail ? RAIL : width, gap: "$0", px: rail ? '$1.5' : '$2', py: "$2", "$max-md": { display: 'none' }, ...rest, children: (0, jsx_runtime_1.jsx)(Contents, { ...props, rail: rail }) }), open ? ((0, jsx_runtime_1.jsx)(sheet_1.Sheet, { open: open, onOpenChange: (next) => (next ? onOpenChange?.(true) : close()), children: (0, jsx_runtime_1.jsxs)(sheet_1.SheetContent, { side: "left", width: width, maxW: "86%", p: "$2", gap: "$0", bg: "$panel", onCloseAutoFocus: (e) => {
|
|
188
|
+
const to = back.current;
|
|
189
|
+
if (!to?.isConnected)
|
|
190
|
+
return;
|
|
191
|
+
e.preventDefault();
|
|
192
|
+
// After the event that closed it: a tap on the overlay dismisses on
|
|
193
|
+
// pointerdown, and the mousedown that follows would blur this
|
|
194
|
+
// focus straight back to the page.
|
|
195
|
+
setTimeout(() => {
|
|
196
|
+
if (to.isConnected)
|
|
197
|
+
to.focus();
|
|
198
|
+
}, 0);
|
|
199
|
+
}, children: [(0, jsx_runtime_1.jsx)(sheet_1.SheetTitle, { ...(0, slot_1.slot)('session-rail-title'), position: "absolute", opacity: 0, pointerEvents: "none", children: label }), (0, jsx_runtime_1.jsx)(gui_1.YStack, { ...(0, slot_1.slot)('session-rail-drawer'), role: "navigation", "aria-label": label, flex: 1, minH: 0, children: (0, jsx_runtime_1.jsx)(Contents, { ...props, rail: false, collapsed: false, onCollapse: undefined, onBrand: shut(onBrand ?? onNew), onSearch: shut(onSearch), onNew: shut(onNew), onOpen: shut(onOpen), links: relink(links), more: relink(more), account: account && {
|
|
200
|
+
...account,
|
|
201
|
+
onPress: shut(account.onPress),
|
|
202
|
+
onSignOut: shut(account.onSignOut),
|
|
203
|
+
groups: account.groups?.map((g) => Array.isArray(g)
|
|
204
|
+
? g.map((i) => ({ ...i, onPress: shut(i.onPress) }))
|
|
205
|
+
: { ...g, items: g.items.map((i) => ({ ...i, onPress: shut(i.onPress) })) }),
|
|
206
|
+
} }) })] }) })) : null] }));
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* RailNotice — a small card at the rail's foot, above the account: an offer
|
|
210
|
+
* ("Try Hanzo in Slack"), its one action, and a way to put it away. Pass it as
|
|
211
|
+
* `SessionRail notice`; the host decides when it shows and remembers a dismissal.
|
|
212
|
+
*/
|
|
213
|
+
function RailNotice({ icon, title, action, onAction, onDismiss, dismissLabel = 'Dismiss', ...rest }) {
|
|
214
|
+
const id = (0, react_1.useId)();
|
|
215
|
+
return ((0, jsx_runtime_1.jsxs)(gui_1.XStack, { ...(0, slot_1.slot)('rail-notice'), items: "center", gap: "$2.5", px: "$3", py: "$2.5", rounded: "$3", borderWidth: 1, borderColor: "$borderColor", bg: "$panel", ...rest, children: [icon ? ((0, jsx_runtime_1.jsx)(gui_1.XStack, { shrink: 0, "aria-hidden": true, children: icon })) : null, (0, jsx_runtime_1.jsxs)(gui_1.YStack, { flex: 1, minW: 0, gap: "$0.5", children: [(0, jsx_runtime_1.jsx)(gui_1.SizableText, { id: `${id}-title`, size: "$2", color: "$ink", numberOfLines: 1, children: title }), action && onAction ? ((0, jsx_runtime_1.jsx)(gui_1.XStack, { ...(0, slot_1.slot)('rail-notice-action'), ...(0, press_1.press)(onAction), "aria-describedby": `${id}-title`, self: "flex-start", cursor: "pointer", rounded: "$1", focusVisibleStyle: press_1.RING, children: (0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$1", color: "$soft", textDecorationLine: "underline", children: action }) })) : null] }), onDismiss ? ((0, jsx_runtime_1.jsx)(gui_1.XStack, { ...(0, slot_1.slot)('rail-notice-dismiss'), ...(0, press_1.press)(onDismiss), ...(0, slot_1.tip)(dismissLabel), "aria-label": dismissLabel, p: "$1", rounded: "$2", cursor: "pointer", hoverStyle: { bg: '$hover' }, focusVisibleStyle: press_1.RING, children: (0, jsx_runtime_1.jsx)(lucide_icons_2_1.X, { size: 14 }) })) : null] }));
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* RailBar — the phone's header for a surface with a `SessionRail`: the menu
|
|
219
|
+
* that opens the rail's drawer, the brand, and search on the right. Only below
|
|
220
|
+
* `md`, where there is no rail; from `md` up it draws nothing and the rail's own
|
|
221
|
+
* head carries the same three. Place it at the top of the pane, in flow.
|
|
222
|
+
*/
|
|
223
|
+
function RailBar({ onMenu, menuLabel = 'Open menu', brand, onBrand, onSearch, searchLabel = 'Search', ...rest }) {
|
|
224
|
+
return ((0, jsx_runtime_1.jsxs)(gui_1.XStack, { ...(0, slot_1.slot)('rail-bar'), height: 44, px: "$2", gap: "$2", items: "center", shrink: 0, $md: { display: 'none' }, ...rest, children: [(0, jsx_runtime_1.jsx)(button_1.Button, { variant: "ghost", size: "icon-sm", onPress: onMenu, "aria-label": menuLabel, children: (0, jsx_runtime_1.jsx)(lucide_icons_2_1.Menu, { size: 18 }) }), brand ? (0, jsx_runtime_1.jsx)(Brand, { brand: brand, onPress: onBrand }) : null, (0, jsx_runtime_1.jsx)(gui_1.XStack, { flex: 1 }), onSearch ? ((0, jsx_runtime_1.jsx)(button_1.Button, { variant: "ghost", size: "icon-sm", onPress: onSearch, "aria-label": searchLabel, children: (0, jsx_runtime_1.jsx)(lucide_icons_2_1.Search, { size: 18 }) })) : null] }));
|
|
97
225
|
}
|
|
@@ -1,30 +1,44 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* SessionRail — the left rail of a sessions surface:
|
|
3
|
-
* reopen a recent one, and who you are.
|
|
2
|
+
* SessionRail — the left rail of a sessions surface: who it is, find one, start
|
|
3
|
+
* one, go somewhere, reopen a recent one, and who you are.
|
|
4
4
|
*
|
|
5
|
+
* Hanzo Build the brand; pressing it starts a new session
|
|
6
|
+
* [⌕ Search ] finds a session
|
|
5
7
|
* + New the primary row; the current view on a fresh pane
|
|
6
8
|
* Artifacts · Customize … the surface's own places, as `links`
|
|
7
9
|
* More ⌄ a disclosure over `more`, when there are more
|
|
8
10
|
* Recents ⇅ the sessions, newest first, each with a status dot
|
|
9
|
-
*
|
|
11
|
+
* [ Try Hanzo in Slack × ] `notice` — a `RailNotice`, when the host has one
|
|
12
|
+
* (D) Dave ⌄ ◧ the account and its menu, then collapse
|
|
13
|
+
* acme
|
|
10
14
|
*
|
|
11
15
|
* Presentational: no routing, no fetching. `active` comes in, `onOpen` goes out.
|
|
12
16
|
*
|
|
13
|
-
* THE SIDEBAR CANON (console, hanzo.app, hanzo.chat, the extension):
|
|
17
|
+
* THE SIDEBAR CANON (console, hanzo.app, hanzo.chat, hanzo.build, the extension):
|
|
14
18
|
* - Collapse is an EXPLICIT toggle and the host persists it. `collapsed` in,
|
|
15
19
|
* `onCollapse` out. There is no hover-to-expand and no pin.
|
|
16
20
|
* - Collapsed is a narrow RAIL that stays on screen — icons only, labels as
|
|
17
21
|
* tooltips — and its top row is the expand control.
|
|
18
|
-
* - Below `md` there is no rail at all. The column hides,
|
|
19
|
-
*
|
|
20
|
-
*
|
|
22
|
+
* - Below `md` there is no rail at all. The column hides, `RailBar` is the
|
|
23
|
+
* pane's header (menu · brand · search), and its menu opens the same
|
|
24
|
+
* contents as a drawer from the left (`open`, `onOpenChange`). Anything
|
|
25
|
+
* chosen in the drawer closes it: the drawer is the way to a place, not a
|
|
26
|
+
* place.
|
|
27
|
+
*
|
|
28
|
+
* ONE WAY to each thing. Search is the box in the head (an icon on the collapsed
|
|
29
|
+
* rail); settings, usage and signing out are rows of the account menu. There is
|
|
30
|
+
* no second search or settings control at the foot.
|
|
21
31
|
*
|
|
22
32
|
* Built from the chat `Sidebar` column and its icon button, so the rail is the
|
|
23
|
-
* same material as every other chat surface's.
|
|
33
|
+
* same material as every other chat surface's. The account menu is the same
|
|
34
|
+
* body `UserMenu` draws (`product/account.tsx`), anchored to the account row
|
|
35
|
+
* itself — above it on the open rail, beside it on the collapsed one.
|
|
24
36
|
*/
|
|
25
|
-
import { YStack } from '@hanzo/gui';
|
|
37
|
+
import { XStack, YStack } from '@hanzo/gui';
|
|
26
38
|
import { type ComponentProps, type ReactNode } from 'react';
|
|
39
|
+
import { type UserMenuGroup } from '../product/account.js';
|
|
27
40
|
type Col = Omit<ComponentProps<typeof YStack>, 'children'>;
|
|
41
|
+
type Row = Omit<ComponentProps<typeof XStack>, 'children'>;
|
|
28
42
|
/** Where a session is. `running` pulses; finished and idle are an open ring. */
|
|
29
43
|
export type SessionStatus = 'running' | 'paused' | 'done' | 'stopped' | 'error' | 'idle';
|
|
30
44
|
export interface RailSession {
|
|
@@ -41,14 +55,41 @@ export interface RailLink {
|
|
|
41
55
|
active?: boolean;
|
|
42
56
|
}
|
|
43
57
|
export interface RailAccount {
|
|
44
|
-
/** The line
|
|
58
|
+
/** The first line — the person's name, or their email. */
|
|
45
59
|
name: string;
|
|
60
|
+
/** The second line, muted — the organization they act in. */
|
|
61
|
+
sub?: string;
|
|
46
62
|
/** Avatar slot. Falls back to the first letter of `name`. */
|
|
47
63
|
avatar?: ReactNode;
|
|
48
|
-
/**
|
|
64
|
+
/** Heads the menu, under the name, when it is not the name itself. */
|
|
65
|
+
email?: string;
|
|
66
|
+
/**
|
|
67
|
+
* The menu's rows, in groups with a rule between. A group whose every row
|
|
68
|
+
* carries `active` is a choice — a named group, the chosen row checked —
|
|
69
|
+
* which is how an organization switcher is drawn.
|
|
70
|
+
*/
|
|
71
|
+
groups?: UserMenuGroup[];
|
|
72
|
+
/** Sign out, at the foot of the menu. */
|
|
73
|
+
onSignOut?: () => void;
|
|
74
|
+
signOutLabel?: string;
|
|
75
|
+
/**
|
|
76
|
+
* With no menu (no `groups`, no `onSignOut`), the row is this one action —
|
|
77
|
+
* a signed-out rail's "Sign in".
|
|
78
|
+
*/
|
|
49
79
|
onPress?: () => void;
|
|
50
80
|
}
|
|
51
81
|
export interface SessionRailProps extends Col {
|
|
82
|
+
/**
|
|
83
|
+
* The head's first line — the surface's name. A string is drawn as the
|
|
84
|
+
* wordmark; a node brings its own (and its own accessible name).
|
|
85
|
+
*/
|
|
86
|
+
brand?: ReactNode;
|
|
87
|
+
/** Pressing the brand. Starts a new session (`onNew`) unless given. */
|
|
88
|
+
onBrand?: () => void;
|
|
89
|
+
/** Search. The head draws a search box; the collapsed rail an icon. */
|
|
90
|
+
onSearch?: () => void;
|
|
91
|
+
/** The search control's accessible name — "Search runs". */
|
|
92
|
+
searchLabel?: string;
|
|
52
93
|
/** Starts a new session. */
|
|
53
94
|
onNew?: () => void;
|
|
54
95
|
newLabel?: string;
|
|
@@ -70,11 +111,10 @@ export interface SessionRailProps extends Col {
|
|
|
70
111
|
sortLabel?: string;
|
|
71
112
|
/** Shown in place of the list when there are no recents. */
|
|
72
113
|
empty?: ReactNode;
|
|
73
|
-
/** Drawn above the account row — a
|
|
114
|
+
/** Drawn above the account row — a `RailNotice`. */
|
|
74
115
|
notice?: ReactNode;
|
|
116
|
+
/** Who is signed in, and their menu. */
|
|
75
117
|
account?: RailAccount;
|
|
76
|
-
onSettings?: () => void;
|
|
77
|
-
onSearch?: () => void;
|
|
78
118
|
/** Collapsed to the icon rail. The host owns and persists it. */
|
|
79
119
|
collapsed?: boolean;
|
|
80
120
|
onCollapse?: (collapsed: boolean) => void;
|
|
@@ -93,5 +133,43 @@ export declare function StatusDot({ status }: {
|
|
|
93
133
|
status?: SessionStatus;
|
|
94
134
|
}): import("react").JSX.Element;
|
|
95
135
|
export declare function SessionRail(props: SessionRailProps): import("react").JSX.Element;
|
|
136
|
+
export interface RailNoticeProps extends Row {
|
|
137
|
+
/** The notice's mark, ~16px. */
|
|
138
|
+
icon?: ReactNode;
|
|
139
|
+
/** What is on offer, one line. */
|
|
140
|
+
title: string;
|
|
141
|
+
/** The action's words — "Set up". */
|
|
142
|
+
action?: string;
|
|
143
|
+
onAction?: () => void;
|
|
144
|
+
/** Dismissing it. The host remembers that it was. */
|
|
145
|
+
onDismiss?: () => void;
|
|
146
|
+
dismissLabel?: string;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* RailNotice — a small card at the rail's foot, above the account: an offer
|
|
150
|
+
* ("Try Hanzo in Slack"), its one action, and a way to put it away. Pass it as
|
|
151
|
+
* `SessionRail notice`; the host decides when it shows and remembers a dismissal.
|
|
152
|
+
*/
|
|
153
|
+
export declare function RailNotice({ icon, title, action, onAction, onDismiss, dismissLabel, ...rest }: RailNoticeProps): import("react").JSX.Element;
|
|
154
|
+
export interface RailBarProps extends Row {
|
|
155
|
+
/** Opens the rail's drawer. */
|
|
156
|
+
onMenu: () => void;
|
|
157
|
+
/** The menu button's accessible name — "Open runs". */
|
|
158
|
+
menuLabel?: string;
|
|
159
|
+
/** The surface's name, as the rail's head draws it. */
|
|
160
|
+
brand?: ReactNode;
|
|
161
|
+
/** Pressing the brand. */
|
|
162
|
+
onBrand?: () => void;
|
|
163
|
+
/** Search, as the rail's head offers it. */
|
|
164
|
+
onSearch?: () => void;
|
|
165
|
+
searchLabel?: string;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* RailBar — the phone's header for a surface with a `SessionRail`: the menu
|
|
169
|
+
* that opens the rail's drawer, the brand, and search on the right. Only below
|
|
170
|
+
* `md`, where there is no rail; from `md` up it draws nothing and the rail's own
|
|
171
|
+
* head carries the same three. Place it at the top of the pane, in flow.
|
|
172
|
+
*/
|
|
173
|
+
export declare function RailBar({ onMenu, menuLabel, brand, onBrand, onSearch, searchLabel, ...rest }: RailBarProps): import("react").JSX.Element;
|
|
96
174
|
export {};
|
|
97
175
|
//# sourceMappingURL=SessionRail.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionRail.d.ts","sourceRoot":"","sources":["../../src/chat/SessionRail.tsx"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"SessionRail.d.ts","sourceRoot":"","sources":["../../src/chat/SessionRail.tsx"],"names":[],"mappings":"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"}
|