@hanzo/ui 8.27.15 → 8.27.16
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/NOTICE +19 -0
- package/dist/agents/Attachments.cjs +29 -0
- package/dist/agents/Attachments.d.ts +31 -0
- package/dist/agents/Attachments.d.ts.map +1 -0
- package/dist/agents/Attachments.js +27 -0
- package/dist/agents/Attachments.js.map +1 -0
- package/dist/agents/Choice.cjs +47 -0
- package/dist/agents/Choice.d.ts +34 -0
- package/dist/agents/Choice.d.ts.map +1 -0
- package/dist/agents/Choice.js +44 -0
- package/dist/agents/Choice.js.map +1 -0
- package/dist/agents/Console.cjs +106 -0
- package/dist/agents/Console.d.ts +54 -0
- package/dist/agents/Console.d.ts.map +1 -0
- package/dist/agents/Console.js +104 -0
- package/dist/agents/Console.js.map +1 -0
- package/dist/agents/Feedback.cjs +50 -0
- package/dist/agents/Feedback.d.ts +25 -0
- package/dist/agents/Feedback.d.ts.map +1 -0
- package/dist/agents/Feedback.js +48 -0
- package/dist/agents/Feedback.js.map +1 -0
- package/dist/agents/FileTabs.cjs +63 -0
- package/dist/agents/FileTabs.d.ts +45 -0
- package/dist/agents/FileTabs.d.ts.map +1 -0
- package/dist/agents/FileTabs.js +61 -0
- package/dist/agents/FileTabs.js.map +1 -0
- package/dist/agents/FileTree.cjs +160 -0
- package/dist/agents/FileTree.d.ts +41 -0
- package/dist/agents/FileTree.d.ts.map +1 -0
- package/dist/agents/FileTree.js +157 -0
- package/dist/agents/FileTree.js.map +1 -0
- package/dist/agents/PreviewFrame.cjs +108 -0
- package/dist/agents/PreviewFrame.d.ts +78 -0
- package/dist/agents/PreviewFrame.d.ts.map +1 -0
- package/dist/agents/PreviewFrame.js +105 -0
- package/dist/agents/PreviewFrame.js.map +1 -0
- package/dist/agents/Suggestions.cjs +29 -0
- package/dist/agents/Suggestions.d.ts +28 -0
- package/dist/agents/Suggestions.d.ts.map +1 -0
- package/dist/agents/Suggestions.js +26 -0
- package/dist/agents/Suggestions.js.map +1 -0
- package/dist/agents/Workspace.cjs +103 -0
- package/dist/agents/Workspace.d.ts +104 -0
- package/dist/agents/Workspace.d.ts.map +1 -0
- package/dist/agents/Workspace.js +98 -0
- package/dist/agents/Workspace.js.map +1 -0
- package/dist/agents/bridge.cjs +201 -0
- package/dist/agents/bridge.d.ts +102 -0
- package/dist/agents/bridge.d.ts.map +1 -0
- package/dist/agents/bridge.js +197 -0
- package/dist/agents/bridge.js.map +1 -0
- package/dist/agents/index.cjs +64 -1
- package/dist/agents/index.d.ts +23 -0
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +23 -0
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/log.cjs +75 -0
- package/dist/agents/log.d.ts +58 -0
- package/dist/agents/log.d.ts.map +1 -0
- package/dist/agents/log.js +65 -0
- package/dist/agents/log.js.map +1 -0
- package/dist/agents/tree.cjs +238 -0
- package/dist/agents/tree.d.ts +99 -0
- package/dist/agents/tree.d.ts.map +1 -0
- package/dist/agents/tree.js +226 -0
- package/dist/agents/tree.js.map +1 -0
- package/dist/backends/gui/3d-card.d.ts +6 -6
- package/dist/backends/gui/3d-marquee.d.ts +7 -8
- package/dist/backends/gui/3d-marquee.d.ts.map +1 -1
- package/dist/backends/gui/3d-pin.d.ts +1 -1
- package/dist/backends/gui/alert.d.ts +3 -3
- package/dist/backends/gui/android.d.ts +1 -1
- package/dist/backends/gui/animated-testimonials.d.ts +1 -1
- package/dist/backends/gui/animated-tooltip.d.ts +1 -1
- package/dist/backends/gui/announcement.d.ts +1 -1
- package/dist/backends/gui/banner.d.ts +1 -1
- package/dist/backends/gui/button.d.ts +1 -1
- package/dist/backends/gui/card.d.ts +7 -7
- package/dist/backends/gui/code-editor.cjs +2 -2
- package/dist/backends/gui/code-editor.d.ts +7 -1
- package/dist/backends/gui/code-editor.d.ts.map +1 -1
- package/dist/backends/gui/code-editor.js +2 -2
- package/dist/backends/gui/code-editor.js.map +1 -1
- package/dist/backends/gui/command.d.ts +5 -5
- package/dist/backends/gui/command.d.ts.map +1 -1
- package/dist/backends/gui/context-menu.d.ts +14 -14
- package/dist/backends/gui/context-menu.d.ts.map +1 -1
- package/dist/backends/gui/credit-card.d.ts +1 -1
- package/dist/backends/gui/desktop.d.ts +1 -1
- package/dist/backends/gui/dock.d.ts +3 -3
- package/dist/backends/gui/dropdown-menu.d.ts +16 -16
- package/dist/backends/gui/dropdown-menu.d.ts.map +1 -1
- package/dist/backends/gui/empty.d.ts +6 -6
- package/dist/backends/gui/field.d.ts +3 -3
- package/dist/backends/gui/gantt.d.ts +1 -1
- package/dist/backends/gui/grid-pattern.d.ts +1 -2
- package/dist/backends/gui/grid-pattern.d.ts.map +1 -1
- package/dist/backends/gui/image-zoom.d.ts +1 -1
- package/dist/backends/gui/iphone-15-pro.d.ts +1 -1
- package/dist/backends/gui/item.d.ts +9 -9
- package/dist/backends/gui/list.d.ts +2 -2
- package/dist/backends/gui/macos-dock.d.ts +2 -2
- package/dist/backends/gui/magnetic.d.ts +1 -1
- package/dist/backends/gui/marquee.d.ts +1 -15
- package/dist/backends/gui/marquee.d.ts.map +1 -1
- package/dist/backends/gui/menu-dock.d.ts +1 -1
- package/dist/backends/gui/menubar.d.ts +15 -15
- package/dist/backends/gui/menubar.d.ts.map +1 -1
- package/dist/backends/gui/message-dock.d.ts +1 -1
- package/dist/backends/gui/motion-highlight.d.ts +1 -12
- package/dist/backends/gui/motion-highlight.d.ts.map +1 -1
- package/dist/backends/gui/pagination.d.ts +4 -4
- package/dist/backends/gui/qr-code.d.ts +1 -2
- package/dist/backends/gui/qr-code.d.ts.map +1 -1
- package/dist/backends/gui/scroll-area.d.ts +3 -14
- package/dist/backends/gui/scroll-area.d.ts.map +1 -1
- package/dist/backends/gui/sheet.d.ts +3 -3
- package/dist/backends/gui/sheet.d.ts.map +1 -1
- package/dist/backends/gui/status.d.ts +1 -1
- package/dist/backends/gui/table.d.ts +8 -8
- package/dist/backends/gui/toaster.d.ts +1 -15
- package/dist/backends/gui/toaster.d.ts.map +1 -1
- package/dist/backends/gui/toggle.d.ts +1 -1
- package/dist/backends/gui/video-player.d.ts +1 -1
- package/dist/chat/Composer.cjs +60 -9
- package/dist/chat/Composer.d.ts +42 -2
- package/dist/chat/Composer.d.ts.map +1 -1
- package/dist/chat/Composer.js +61 -11
- package/dist/chat/Composer.js.map +1 -1
- package/dist/chat/EmptyPrompt.cjs +27 -0
- package/dist/chat/EmptyPrompt.d.ts +30 -0
- package/dist/chat/EmptyPrompt.d.ts.map +1 -0
- package/dist/chat/EmptyPrompt.js +24 -0
- package/dist/chat/EmptyPrompt.js.map +1 -0
- package/dist/chat/SessionRail.cjs +97 -0
- package/dist/chat/SessionRail.d.ts +97 -0
- package/dist/chat/SessionRail.d.ts.map +1 -0
- package/dist/chat/SessionRail.js +94 -0
- package/dist/chat/SessionRail.js.map +1 -0
- package/dist/chat/Thread.d.ts +2 -8
- package/dist/chat/Thread.d.ts.map +1 -1
- package/dist/chat/index.cjs +8 -1
- package/dist/chat/index.d.ts +3 -1
- package/dist/chat/index.d.ts.map +1 -1
- package/dist/chat/index.js +3 -1
- package/dist/chat/index.js.map +1 -1
- package/dist/gallery.cjs +28 -1
- package/dist/gallery.d.ts.map +1 -1
- package/dist/gallery.html +71 -3
- package/dist/gallery.js +30 -3
- package/dist/gallery.js.map +1 -1
- package/dist/product/BranchSelect.cjs +27 -0
- package/dist/product/BranchSelect.d.ts +27 -0
- package/dist/product/BranchSelect.d.ts.map +1 -0
- package/dist/product/BranchSelect.js +23 -0
- package/dist/product/BranchSelect.js.map +1 -0
- package/dist/product/ChipSelect.cjs +267 -0
- package/dist/product/ChipSelect.d.ts +71 -0
- package/dist/product/ChipSelect.d.ts.map +1 -0
- package/dist/product/ChipSelect.js +265 -0
- package/dist/product/ChipSelect.js.map +1 -0
- package/dist/product/RepoSelect.cjs +75 -0
- package/dist/product/RepoSelect.d.ts +63 -0
- package/dist/product/RepoSelect.d.ts.map +1 -0
- package/dist/product/RepoSelect.js +69 -0
- package/dist/product/RepoSelect.js.map +1 -0
- package/dist/product/chipSelect.logic.cjs +147 -0
- package/dist/product/chipSelect.logic.d.ts +92 -0
- package/dist/product/chipSelect.logic.d.ts.map +1 -0
- package/dist/product/chipSelect.logic.js +138 -0
- package/dist/product/chipSelect.logic.js.map +1 -0
- package/dist/product/index.cjs +23 -1
- package/dist/product/index.d.ts +4 -0
- package/dist/product/index.d.ts.map +1 -1
- package/dist/product/index.js +7 -0
- package/dist/product/index.js.map +1 -1
- package/dist/styles.css +68 -0
- package/package.json +2 -1
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Toaster — the toast viewport, mounted once near the root of an app.
|
|
3
|
-
*
|
|
4
|
-
* gui already owns the whole thing: `@hanzogui/toast/v2` ships a sonner-shaped
|
|
5
|
-
* `toast()` observer and a `Toaster` that portals a themed, swipe-dismissable
|
|
6
|
-
* stack on web, native and desktop. So this is a prop translation, not a
|
|
7
|
-
* reimplementation.
|
|
8
|
-
*
|
|
9
|
-
* `className`, `style` and the per-part `classNames` are accepted and ignored:
|
|
10
|
-
* gui paints from theme tokens (`$background`, `$color`, `$borderColor`), the one
|
|
11
|
-
* styling channel that also exists on native. They stay in the type so existing
|
|
12
|
-
* call sites keep compiling.
|
|
13
|
-
*/
|
|
14
|
-
import type { GuiElement } from '@hanzo/gui';
|
|
15
1
|
import { toast, type ExternalToast, type ToasterProps as GuiToasterProps } from '@hanzogui/toast/v2';
|
|
16
2
|
/** Sonner's per-part class hooks. Inert — see the note above. */
|
|
17
3
|
export type ToasterClassNames = Partial<Record<'toast' | 'title' | 'description' | 'icon' | 'actionButton' | 'cancelButton' | 'closeButton', string>>;
|
|
@@ -26,6 +12,6 @@ export interface ToasterProps extends Omit<GuiToasterProps, 'toastOptions'> {
|
|
|
26
12
|
classNames?: ToasterClassNames;
|
|
27
13
|
};
|
|
28
14
|
}
|
|
29
|
-
declare const Toaster: import("react").ForwardRefExoticComponent<ToasterProps & import("react").RefAttributes<
|
|
15
|
+
declare const Toaster: import("react").ForwardRefExoticComponent<ToasterProps & import("react").RefAttributes<any>>;
|
|
30
16
|
export { Toaster, toast };
|
|
31
17
|
//# sourceMappingURL=toaster.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toaster.d.ts","sourceRoot":"","sources":["../../../src/backends/gui/toaster.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"toaster.d.ts","sourceRoot":"","sources":["../../../src/backends/gui/toaster.tsx"],"names":[],"mappings":"AAgBA,OAAO,EAEL,KAAK,EACL,KAAK,aAAa,EAClB,KAAK,YAAY,IAAI,eAAe,EACrC,MAAM,oBAAoB,CAAA;AAG3B,iEAAiE;AACjE,MAAM,MAAM,iBAAiB,GAAG,OAAO,CACrC,MAAM,CACF,OAAO,GACP,OAAO,GACP,aAAa,GACb,MAAM,GACN,cAAc,GACd,cAAc,GACd,aAAa,EACf,MAAM,CACP,CACF,CAAA;AAED,MAAM,WAAW,YAAa,SAAQ,IAAI,CAAC,eAAe,EAAE,cAAc,CAAC;IACzE,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAA;IACvC,2EAA2E;IAC3E,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,YAAY,CAAC,EAAE,aAAa,GAAG;QAAE,UAAU,CAAC,EAAE,iBAAiB,CAAA;KAAE,CAAA;CAClE;AAED,QAAA,MAAM,OAAO,8FAGX,CAAA;AAEF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ComponentProps, MouseEventHandler, ReactNode } from 'react';
|
|
2
2
|
export type ToggleVariant = 'default' | 'outline';
|
|
3
3
|
export type ToggleSize = 'default' | 'sm' | 'lg';
|
|
4
|
-
declare const ToggleFrame: import("@hanzogui/web").GuiComponent<import("@hanzogui/web").TamaDefer,
|
|
4
|
+
declare const ToggleFrame: import("@hanzogui/web").GuiComponent<import("@hanzogui/web").TamaDefer, any, import("@hanzogui/core").RNGuiViewNonStyleProps, import("@hanzogui/web").StackStyleBase, {
|
|
5
5
|
disabled?: boolean | undefined;
|
|
6
6
|
elevation?: number | import("@hanzogui/web").SizeTokens | undefined;
|
|
7
7
|
fullscreen?: boolean | undefined;
|
|
@@ -24,7 +24,7 @@ export type MediaSubtitleTrack = {
|
|
|
24
24
|
default?: boolean;
|
|
25
25
|
};
|
|
26
26
|
export type MediaPlayerSize = 'sm' | 'md' | 'lg' | 'full';
|
|
27
|
-
declare const Frame: import("@hanzogui/web").GuiComponent<import("@hanzogui/web").TamaDefer,
|
|
27
|
+
declare const Frame: import("@hanzogui/web").GuiComponent<import("@hanzogui/web").TamaDefer, any, import("@hanzogui/core").RNGuiViewNonStyleProps, import("@hanzogui/web").StackStyleBase, {
|
|
28
28
|
elevation?: number | import("@hanzogui/web").SizeTokens | undefined;
|
|
29
29
|
fullscreen?: boolean | undefined;
|
|
30
30
|
size?: "full" | "lg" | "md" | "sm" | undefined;
|
package/dist/chat/Composer.cjs
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.ASK = void 0;
|
|
5
5
|
exports.Composer = Composer;
|
|
6
|
+
exports.ComposerTool = ComposerTool;
|
|
6
7
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
7
8
|
/**
|
|
8
9
|
* Composer — the one chat input for every Hanzo surface.
|
|
@@ -35,6 +36,16 @@ const CEILING = 200;
|
|
|
35
36
|
/** Floor for the field, px. `Textarea` defaults to 64, which is three lines of
|
|
36
37
|
* chrome before anything is typed. 44 is the touch-target floor. */
|
|
37
38
|
const FLOOR = 44;
|
|
39
|
+
/**
|
|
40
|
+
* The one-line frame: 40px outside, so the field inside is 38 — a 20px line
|
|
41
|
+
* with 9px above and below it. The frame is the target, not the glyph, which
|
|
42
|
+
* is why the send control can be a 28px mark inside a row a thumb already hits.
|
|
43
|
+
*/
|
|
44
|
+
const LINE = 40;
|
|
45
|
+
const LINE_FIELD = LINE - 2;
|
|
46
|
+
const LINE_PAD = (LINE_FIELD - 20) / 2;
|
|
47
|
+
/** The inline send mark: a glyph in the field's own row, never a filled slab. */
|
|
48
|
+
const MARK = 28;
|
|
38
49
|
/**
|
|
39
50
|
* The resting placeholder.
|
|
40
51
|
*
|
|
@@ -44,7 +55,7 @@ const FLOOR = 44;
|
|
|
44
55
|
* changes — which is what a model-named placeholder forces a surface to do.
|
|
45
56
|
*/
|
|
46
57
|
exports.ASK = 'Ask anything';
|
|
47
|
-
function Composer({ value, onChange, onSend, onStop, busy = false, disabled = false, placeholder = exports.ASK, rows = MIN_ROWS, maxHeight = CEILING, children, hint, label, field, send, ...props }) {
|
|
58
|
+
function Composer({ value, onChange, onSend, onStop, busy = false, disabled = false, placeholder = exports.ASK, rows = MIN_ROWS, maxHeight = CEILING, children, hint, label, field, send, head, foot, inline = false, ...props }) {
|
|
48
59
|
const sendable = (0, send_1.ready)(value, busy, disabled);
|
|
49
60
|
const keyed = (e) => {
|
|
50
61
|
const key = e.key ?? e.nativeEvent?.key ?? '';
|
|
@@ -64,12 +75,52 @@ function Composer({ value, onChange, onSend, onStop, busy = false, disabled = fa
|
|
|
64
75
|
if (sendable)
|
|
65
76
|
onSend();
|
|
66
77
|
};
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
78
|
+
const input = ((0, jsx_runtime_1.jsx)(gui_2.Textarea, { ...(0, slot_1.slot)('composer-field'), rows: rows, placeholder: placeholder, disabled: disabled, borderWidth: 0, ...(inline
|
|
79
|
+
? {
|
|
80
|
+
flex: 1,
|
|
81
|
+
minW: 0,
|
|
82
|
+
minH: LINE_FIELD,
|
|
83
|
+
px: 0,
|
|
84
|
+
pt: LINE_PAD,
|
|
85
|
+
pb: LINE_PAD,
|
|
86
|
+
bg: 'transparent',
|
|
87
|
+
}
|
|
88
|
+
: { minH: FLOOR }), maxH: maxHeight, "aria-label": label ?? placeholder, ...field,
|
|
89
|
+
// After `field`: spread over, a caller's `onKeyDown` would replace the
|
|
90
|
+
// Enter rule and the IME guard. Theirs runs first and can claim the key.
|
|
91
|
+
value: value, onChangeText: onChange, onKeyDown: (e) => {
|
|
92
|
+
field?.onKeyDown?.(e);
|
|
93
|
+
if (!e?.defaultPrevented)
|
|
94
|
+
keyed(e);
|
|
95
|
+
} }));
|
|
96
|
+
const said = hint ? ((0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$1", color: "$soft", children: hint })) : null;
|
|
97
|
+
const frame = inline ? ((0, jsx_runtime_1.jsxs)(gui_1.XStack, { ...(0, slot_1.slot)('composer'), width: "100%", items: "center", rounded: "$3", borderWidth: 1, borderColor: "$rim", bg: "$hover", pl: "$3", pr: "$1.5", gap: "$1.5", ...props, children: [input, children, said, send ?? ((0, jsx_runtime_1.jsx)(gui_1.XStack, { ...(0, slot_1.slot)('composer-send'), ...(0, slot_1.tip)(busy ? 'Stop' : 'Send'), role: "button", tabIndex: busy ? (onStop ? 0 : -1) : sendable ? 0 : -1, "aria-label": busy ? 'Stop' : 'Send', "aria-disabled": busy ? !onStop : !sendable, width: MARK, height: MARK, shrink: 0, rounded: "$2", items: "center", justify: "center", cursor: (busy ? onStop : sendable) ? 'pointer' : 'default', opacity: (busy ? onStop : sendable) ? 1 : 0.6, hoverStyle: { bg: '$raised' }, onPress: () => (busy ? onStop?.() : sendable ? onSend() : undefined), onKeyDown: (e) => {
|
|
98
|
+
if (e?.key !== 'Enter' && e?.key !== ' ')
|
|
99
|
+
return;
|
|
100
|
+
e.preventDefault?.();
|
|
101
|
+
if (busy)
|
|
102
|
+
onStop?.();
|
|
103
|
+
else if (sendable)
|
|
104
|
+
onSend();
|
|
105
|
+
}, children: busy ? (0, jsx_runtime_1.jsx)(lucide_icons_2_1.Square, { size: 12, color: "$soft" }) : (0, jsx_runtime_1.jsx)(lucide_icons_2_1.CornerDownLeft, { size: 14, color: "$soft" }) }))] })) : ((0, jsx_runtime_1.jsxs)(gui_1.YStack, { ...(0, slot_1.slot)('composer'), width: "100%", rounded: "$5", borderWidth: 1, borderColor: "$borderColor", bg: "$background", p: PAD, gap: PAD, ...props, children: [input, (0, jsx_runtime_1.jsxs)(gui_1.XStack, { items: "center", gap: PAD, children: [children, (0, jsx_runtime_1.jsx)(gui_1.XStack, { flex: 1 }), said, send ?? ((0, jsx_runtime_1.jsx)(gui_2.Button, { ...(0, slot_1.slot)('composer-send'), size: "sm", disabled: busy ? !onStop : !sendable, onPress: busy ? onStop : onSend, "aria-label": busy ? 'Stop' : 'Send', children: busy ? (0, jsx_runtime_1.jsx)(lucide_icons_2_1.Square, { size: 14 }) : (0, jsx_runtime_1.jsx)(lucide_icons_2_1.ArrowUp, { size: 16 }) }))] })] }));
|
|
106
|
+
// With nothing above or below it the composer IS the frame, exactly as it
|
|
107
|
+
// was before either existed — no wrapper, so every caller's tree is unchanged.
|
|
108
|
+
if (!head && !foot)
|
|
109
|
+
return frame;
|
|
110
|
+
return ((0, jsx_runtime_1.jsxs)(gui_1.YStack, { ...(0, slot_1.slot)('composer-shell'), width: "100%", gap: "$2.5", children: [head ? ((0, jsx_runtime_1.jsx)(gui_1.XStack, { ...(0, slot_1.slot)('composer-head'), items: "center", gap: "$1.5", flexWrap: "wrap", children: head })) : null, frame, foot ? ((0, jsx_runtime_1.jsx)(gui_1.XStack, { ...(0, slot_1.slot)('composer-foot'), items: "center", gap: "$2", px: "$1.5", mt: -4, children: foot })) : null] }));
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* ComposerTool — one quiet control in a composer's `foot` or `head`: attach,
|
|
114
|
+
* voice, a mode, the model. 24px tall, muted until pointed at, and a real
|
|
115
|
+
* button to the keyboard. Its name is `label` whether or not it shows words,
|
|
116
|
+
* because an icon-only control is the whole navigation for someone who cannot
|
|
117
|
+
* see the icon.
|
|
118
|
+
*/
|
|
119
|
+
function ComposerTool({ label, icon, text, caret = false, onPress, disabled = false, ...rest }) {
|
|
120
|
+
return ((0, jsx_runtime_1.jsxs)(gui_1.XStack, { ...(0, slot_1.slot)('composer-tool'), ...(0, slot_1.tip)(label), role: "button", tabIndex: disabled ? -1 : 0, "aria-label": label, "aria-disabled": disabled || undefined, "aria-haspopup": caret ? 'menu' : undefined, height: 24, px: text ? '$1.5' : '$1', gap: "$1", items: "center", rounded: "$2", shrink: 0, cursor: disabled ? 'default' : 'pointer', opacity: disabled ? 0.5 : 1, hoverStyle: disabled ? undefined : { bg: '$hover' }, focusVisibleStyle: { outlineColor: '$outlineColor', outlineWidth: 2, outlineStyle: 'solid' }, hitSlop: { top: 10, bottom: 10, left: 2, right: 2 }, onPress: disabled ? undefined : onPress, onKeyDown: (e) => {
|
|
121
|
+
if (disabled || (e?.key !== 'Enter' && e?.key !== ' '))
|
|
122
|
+
return;
|
|
123
|
+
e.preventDefault?.();
|
|
124
|
+
onPress?.();
|
|
125
|
+
}, ...rest, children: [icon ? ((0, jsx_runtime_1.jsx)(gui_1.XStack, { "aria-hidden": true, items: "center", children: icon })) : null, text ? ((0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$2", color: "$quiet", numberOfLines: 1, children: text })) : null, caret ? (0, jsx_runtime_1.jsx)(lucide_icons_2_1.ChevronDown, { size: 12, color: "$soft", "aria-hidden": true }) : null] }));
|
|
75
126
|
}
|
package/dist/chat/Composer.d.ts
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* Growth is `Textarea`'s and follows the content, so a wrapped paragraph raises
|
|
17
17
|
* the field. `rows` is the floor, `maxHeight` the ceiling.
|
|
18
18
|
*/
|
|
19
|
-
import { YStack } from '@hanzo/gui';
|
|
19
|
+
import { XStack, YStack } from '@hanzo/gui';
|
|
20
20
|
import type { ComponentProps, ReactNode } from 'react';
|
|
21
21
|
import { Textarea } from '../backends/gui/index.js';
|
|
22
22
|
/** `onChange` is dropped: here it carries the draft, not a DOM change event. */
|
|
@@ -63,7 +63,47 @@ export interface ComposerProps extends Stack {
|
|
|
63
63
|
/** Replaces the send control. `children` is the START of the footer row, so a
|
|
64
64
|
* second commit mode has nowhere else to go. */
|
|
65
65
|
send?: ReactNode;
|
|
66
|
+
/**
|
|
67
|
+
* Drawn ABOVE the frame — the row of context a draft is sent with (where it
|
|
68
|
+
* runs, which repository, which branch). Outside the frame on purpose: it
|
|
69
|
+
* says what the draft is about, and the field says what it is.
|
|
70
|
+
*/
|
|
71
|
+
head?: ReactNode;
|
|
72
|
+
/**
|
|
73
|
+
* Drawn UNDER the frame — attach, voice, mode at its start and the model at
|
|
74
|
+
* its end, as the host arranges them. Unlike `children`, which lives inside
|
|
75
|
+
* the frame beside the send control.
|
|
76
|
+
*/
|
|
77
|
+
foot?: ReactNode;
|
|
78
|
+
/**
|
|
79
|
+
* One line: the field and the send control share a single row inside the
|
|
80
|
+
* frame, and the send control is a glyph at the field's end — Enter's own
|
|
81
|
+
* mark while idle, Stop while busy. `children` and `hint` join that row
|
|
82
|
+
* before it. Unset, the frame is the stacked field-over-toolbar it has
|
|
83
|
+
* always been.
|
|
84
|
+
*/
|
|
85
|
+
inline?: boolean;
|
|
86
|
+
}
|
|
87
|
+
export declare function Composer({ value, onChange, onSend, onStop, busy, disabled, placeholder, rows, maxHeight, children, hint, label, field, send, head, foot, inline, ...props }: ComposerProps): import("react").JSX.Element;
|
|
88
|
+
type Row = Omit<ComponentProps<typeof XStack>, 'children'>;
|
|
89
|
+
export interface ComposerToolProps extends Row {
|
|
90
|
+
/** The control's name — what a screen reader says and the tooltip shows. */
|
|
91
|
+
label: string;
|
|
92
|
+
icon?: ReactNode;
|
|
93
|
+
/** Words drawn after the icon — a mode, a model. Absent, the tool is icon-only. */
|
|
94
|
+
text?: string;
|
|
95
|
+
/** A trailing caret: this opens a menu. */
|
|
96
|
+
caret?: boolean;
|
|
97
|
+
onPress?: () => void;
|
|
98
|
+
disabled?: boolean;
|
|
66
99
|
}
|
|
67
|
-
|
|
100
|
+
/**
|
|
101
|
+
* ComposerTool — one quiet control in a composer's `foot` or `head`: attach,
|
|
102
|
+
* voice, a mode, the model. 24px tall, muted until pointed at, and a real
|
|
103
|
+
* button to the keyboard. Its name is `label` whether or not it shows words,
|
|
104
|
+
* because an icon-only control is the whole navigation for someone who cannot
|
|
105
|
+
* see the icon.
|
|
106
|
+
*/
|
|
107
|
+
export declare function ComposerTool({ label, icon, text, caret, onPress, disabled, ...rest }: ComposerToolProps): import("react").JSX.Element;
|
|
68
108
|
export {};
|
|
69
109
|
//# sourceMappingURL=Composer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Composer.d.ts","sourceRoot":"","sources":["../../src/chat/Composer.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,
|
|
1
|
+
{"version":3,"file":"Composer.d.ts","sourceRoot":"","sources":["../../src/chat/Composer.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAe,MAAM,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAExD,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtD,OAAO,EAAU,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAIlD,gFAAgF;AAChF,KAAK,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC,CAAA;AACzE,KAAK,UAAU,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,QAAQ,CAAC,EAAE,OAAO,GAAG,cAAc,CAAC,CAAA;AAyBjF;;;;;;;GAOG;AACH,eAAO,MAAM,GAAG,iBAAiB,CAAA;AAEjC,MAAM,WAAW,aAAc,SAAQ,KAAK;IAC1C,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,8EAA8E;IAC9E,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB,0DAA0D;IAC1D,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,gFAAgF;IAChF,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB;qDACiD;IACjD,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;;;;OAIG;IACH,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;;;;OAIG;IACH,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,QAAQ,EACR,MAAM,EACN,MAAM,EACN,IAAY,EACZ,QAAgB,EAChB,WAAiB,EACjB,IAAe,EACf,SAAmB,EACnB,QAAQ,EACR,IAAI,EACJ,KAAK,EACL,KAAK,EACL,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,MAAc,EACd,GAAG,KAAK,EACT,EAAE,aAAa,+BA2Jf;AAED,KAAK,GAAG,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,EAAE,UAAU,CAAC,CAAA;AAE1D,MAAM,WAAW,iBAAkB,SAAQ,GAAG;IAC5C,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,mFAAmF;IACnF,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,2CAA2C;IAC3C,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,IAAI,EACJ,IAAI,EACJ,KAAa,EACb,OAAO,EACP,QAAgB,EAChB,GAAG,IAAI,EACR,EAAE,iBAAiB,+BA0CnB"}
|
package/dist/chat/Composer.js
CHANGED
|
@@ -19,9 +19,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
19
19
|
* the field. `rows` is the floor, `maxHeight` the ceiling.
|
|
20
20
|
*/
|
|
21
21
|
import { SizableText, XStack, YStack } from '@hanzo/gui';
|
|
22
|
-
import { ArrowUp, Square } from '@hanzogui/lucide-icons-2';
|
|
22
|
+
import { ArrowUp, ChevronDown, CornerDownLeft, Square } from '@hanzogui/lucide-icons-2';
|
|
23
23
|
import { Button, Textarea } from '../backends/gui/index.js';
|
|
24
|
-
import { slot } from '../backends/gui/slot.js';
|
|
24
|
+
import { slot, tip } from '../backends/gui/slot.js';
|
|
25
25
|
import { ready, sends } from './send.js';
|
|
26
26
|
const PAD = 8;
|
|
27
27
|
const MIN_ROWS = 1;
|
|
@@ -31,6 +31,16 @@ const CEILING = 200;
|
|
|
31
31
|
/** Floor for the field, px. `Textarea` defaults to 64, which is three lines of
|
|
32
32
|
* chrome before anything is typed. 44 is the touch-target floor. */
|
|
33
33
|
const FLOOR = 44;
|
|
34
|
+
/**
|
|
35
|
+
* The one-line frame: 40px outside, so the field inside is 38 — a 20px line
|
|
36
|
+
* with 9px above and below it. The frame is the target, not the glyph, which
|
|
37
|
+
* is why the send control can be a 28px mark inside a row a thumb already hits.
|
|
38
|
+
*/
|
|
39
|
+
const LINE = 40;
|
|
40
|
+
const LINE_FIELD = LINE - 2;
|
|
41
|
+
const LINE_PAD = (LINE_FIELD - 20) / 2;
|
|
42
|
+
/** The inline send mark: a glyph in the field's own row, never a filled slab. */
|
|
43
|
+
const MARK = 28;
|
|
34
44
|
/**
|
|
35
45
|
* The resting placeholder.
|
|
36
46
|
*
|
|
@@ -40,7 +50,7 @@ const FLOOR = 44;
|
|
|
40
50
|
* changes — which is what a model-named placeholder forces a surface to do.
|
|
41
51
|
*/
|
|
42
52
|
export const ASK = 'Ask anything';
|
|
43
|
-
export function Composer({ value, onChange, onSend, onStop, busy = false, disabled = false, placeholder = ASK, rows = MIN_ROWS, maxHeight = CEILING, children, hint, label, field, send, ...props }) {
|
|
53
|
+
export function Composer({ value, onChange, onSend, onStop, busy = false, disabled = false, placeholder = ASK, rows = MIN_ROWS, maxHeight = CEILING, children, hint, label, field, send, head, foot, inline = false, ...props }) {
|
|
44
54
|
const sendable = ready(value, busy, disabled);
|
|
45
55
|
const keyed = (e) => {
|
|
46
56
|
const key = e.key ?? e.nativeEvent?.key ?? '';
|
|
@@ -60,13 +70,53 @@ export function Composer({ value, onChange, onSend, onStop, busy = false, disabl
|
|
|
60
70
|
if (sendable)
|
|
61
71
|
onSend();
|
|
62
72
|
};
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
const input = (_jsx(Textarea, { ...slot('composer-field'), rows: rows, placeholder: placeholder, disabled: disabled, borderWidth: 0, ...(inline
|
|
74
|
+
? {
|
|
75
|
+
flex: 1,
|
|
76
|
+
minW: 0,
|
|
77
|
+
minH: LINE_FIELD,
|
|
78
|
+
px: 0,
|
|
79
|
+
pt: LINE_PAD,
|
|
80
|
+
pb: LINE_PAD,
|
|
81
|
+
bg: 'transparent',
|
|
82
|
+
}
|
|
83
|
+
: { minH: FLOOR }), maxH: maxHeight, "aria-label": label ?? placeholder, ...field,
|
|
84
|
+
// After `field`: spread over, a caller's `onKeyDown` would replace the
|
|
85
|
+
// Enter rule and the IME guard. Theirs runs first and can claim the key.
|
|
86
|
+
value: value, onChangeText: onChange, onKeyDown: (e) => {
|
|
87
|
+
field?.onKeyDown?.(e);
|
|
88
|
+
if (!e?.defaultPrevented)
|
|
89
|
+
keyed(e);
|
|
90
|
+
} }));
|
|
91
|
+
const said = hint ? (_jsx(SizableText, { size: "$1", color: "$soft", children: hint })) : null;
|
|
92
|
+
const frame = inline ? (_jsxs(XStack, { ...slot('composer'), width: "100%", items: "center", rounded: "$3", borderWidth: 1, borderColor: "$rim", bg: "$hover", pl: "$3", pr: "$1.5", gap: "$1.5", ...props, children: [input, children, said, send ?? (_jsx(XStack, { ...slot('composer-send'), ...tip(busy ? 'Stop' : 'Send'), role: "button", tabIndex: busy ? (onStop ? 0 : -1) : sendable ? 0 : -1, "aria-label": busy ? 'Stop' : 'Send', "aria-disabled": busy ? !onStop : !sendable, width: MARK, height: MARK, shrink: 0, rounded: "$2", items: "center", justify: "center", cursor: (busy ? onStop : sendable) ? 'pointer' : 'default', opacity: (busy ? onStop : sendable) ? 1 : 0.6, hoverStyle: { bg: '$raised' }, onPress: () => (busy ? onStop?.() : sendable ? onSend() : undefined), onKeyDown: (e) => {
|
|
93
|
+
if (e?.key !== 'Enter' && e?.key !== ' ')
|
|
94
|
+
return;
|
|
95
|
+
e.preventDefault?.();
|
|
96
|
+
if (busy)
|
|
97
|
+
onStop?.();
|
|
98
|
+
else if (sendable)
|
|
99
|
+
onSend();
|
|
100
|
+
}, children: busy ? _jsx(Square, { size: 12, color: "$soft" }) : _jsx(CornerDownLeft, { size: 14, color: "$soft" }) }))] })) : (_jsxs(YStack, { ...slot('composer'), width: "100%", rounded: "$5", borderWidth: 1, borderColor: "$borderColor", bg: "$background", p: PAD, gap: PAD, ...props, children: [input, _jsxs(XStack, { items: "center", gap: PAD, children: [children, _jsx(XStack, { flex: 1 }), said, send ?? (_jsx(Button, { ...slot('composer-send'), size: "sm", disabled: busy ? !onStop : !sendable, onPress: busy ? onStop : onSend, "aria-label": busy ? 'Stop' : 'Send', children: busy ? _jsx(Square, { size: 14 }) : _jsx(ArrowUp, { size: 16 }) }))] })] }));
|
|
101
|
+
// With nothing above or below it the composer IS the frame, exactly as it
|
|
102
|
+
// was before either existed — no wrapper, so every caller's tree is unchanged.
|
|
103
|
+
if (!head && !foot)
|
|
104
|
+
return frame;
|
|
105
|
+
return (_jsxs(YStack, { ...slot('composer-shell'), width: "100%", gap: "$2.5", children: [head ? (_jsx(XStack, { ...slot('composer-head'), items: "center", gap: "$1.5", flexWrap: "wrap", children: head })) : null, frame, foot ? (_jsx(XStack, { ...slot('composer-foot'), items: "center", gap: "$2", px: "$1.5", mt: -4, children: foot })) : null] }));
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* ComposerTool — one quiet control in a composer's `foot` or `head`: attach,
|
|
109
|
+
* voice, a mode, the model. 24px tall, muted until pointed at, and a real
|
|
110
|
+
* button to the keyboard. Its name is `label` whether or not it shows words,
|
|
111
|
+
* because an icon-only control is the whole navigation for someone who cannot
|
|
112
|
+
* see the icon.
|
|
113
|
+
*/
|
|
114
|
+
export function ComposerTool({ label, icon, text, caret = false, onPress, disabled = false, ...rest }) {
|
|
115
|
+
return (_jsxs(XStack, { ...slot('composer-tool'), ...tip(label), role: "button", tabIndex: disabled ? -1 : 0, "aria-label": label, "aria-disabled": disabled || undefined, "aria-haspopup": caret ? 'menu' : undefined, height: 24, px: text ? '$1.5' : '$1', gap: "$1", items: "center", rounded: "$2", shrink: 0, cursor: disabled ? 'default' : 'pointer', opacity: disabled ? 0.5 : 1, hoverStyle: disabled ? undefined : { bg: '$hover' }, focusVisibleStyle: { outlineColor: '$outlineColor', outlineWidth: 2, outlineStyle: 'solid' }, hitSlop: { top: 10, bottom: 10, left: 2, right: 2 }, onPress: disabled ? undefined : onPress, onKeyDown: (e) => {
|
|
116
|
+
if (disabled || (e?.key !== 'Enter' && e?.key !== ' '))
|
|
117
|
+
return;
|
|
118
|
+
e.preventDefault?.();
|
|
119
|
+
onPress?.();
|
|
120
|
+
}, ...rest, children: [icon ? (_jsx(XStack, { "aria-hidden": true, items: "center", children: icon })) : null, text ? (_jsx(SizableText, { size: "$2", color: "$quiet", numberOfLines: 1, children: text })) : null, caret ? _jsx(ChevronDown, { size: 12, color: "$soft", "aria-hidden": true }) : null] }));
|
|
71
121
|
}
|
|
72
122
|
//# sourceMappingURL=Composer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Composer.js","sourceRoot":"","sources":["../../src/chat/Composer.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"Composer.js","sourceRoot":"","sources":["../../src/chat/Composer.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use client';"use strict";
|
|
2
|
+
'use client';
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.NEXT = void 0;
|
|
5
|
+
exports.EmptyPrompt = EmptyPrompt;
|
|
6
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
7
|
+
/**
|
|
8
|
+
* EmptyPrompt — what an empty conversation pane says before anything is asked.
|
|
9
|
+
*
|
|
10
|
+
* One line at the top of the pane: a small mark and a question. It is aligned
|
|
11
|
+
* to the COLUMN the composer sits in, not centred on the pane, so the question
|
|
12
|
+
* and the field that answers it start at the same left edge — the eye reads
|
|
13
|
+
* down one line into the other.
|
|
14
|
+
*
|
|
15
|
+
* The mark is a slot, never a brand this package picks: a surface passes its
|
|
16
|
+
* own (`BrandMark`, an org mark, nothing), and the heading is the same either
|
|
17
|
+
* way.
|
|
18
|
+
*/
|
|
19
|
+
const gui_1 = require("@hanzo/gui");
|
|
20
|
+
const slot_1 = require("../backends/gui/slot.cjs");
|
|
21
|
+
/** The composer column's width, so the two line up by default. */
|
|
22
|
+
const COLUMN = 768;
|
|
23
|
+
/** What an empty pane asks when the surface says nothing else. */
|
|
24
|
+
exports.NEXT = 'What’s up next?';
|
|
25
|
+
function EmptyPrompt({ title = exports.NEXT, mark, column = COLUMN, level = 1, ...rest }) {
|
|
26
|
+
return ((0, jsx_runtime_1.jsx)(gui_1.YStack, { ...(0, slot_1.slot)('empty-prompt'), width: "100%", items: "center", px: "$4", pt: "$2.5", ...rest, children: (0, jsx_runtime_1.jsxs)(gui_1.XStack, { width: "100%", maxW: column, items: "center", gap: "$2", children: [mark ? ((0, jsx_runtime_1.jsx)(gui_1.XStack, { ...(0, slot_1.slot)('empty-prompt-mark'), shrink: 0, items: "center", "aria-hidden": true, children: mark })) : null, (0, jsx_runtime_1.jsx)(gui_1.SizableText, { ...(0, slot_1.slot)('empty-prompt-title'), role: "heading", "aria-level": level, size: "$7", color: "$ink", children: title })] }) }));
|
|
27
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EmptyPrompt — what an empty conversation pane says before anything is asked.
|
|
3
|
+
*
|
|
4
|
+
* One line at the top of the pane: a small mark and a question. It is aligned
|
|
5
|
+
* to the COLUMN the composer sits in, not centred on the pane, so the question
|
|
6
|
+
* and the field that answers it start at the same left edge — the eye reads
|
|
7
|
+
* down one line into the other.
|
|
8
|
+
*
|
|
9
|
+
* The mark is a slot, never a brand this package picks: a surface passes its
|
|
10
|
+
* own (`BrandMark`, an org mark, nothing), and the heading is the same either
|
|
11
|
+
* way.
|
|
12
|
+
*/
|
|
13
|
+
import { YStack } from '@hanzo/gui';
|
|
14
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
15
|
+
type Col = Omit<ComponentProps<typeof YStack>, 'children'>;
|
|
16
|
+
/** What an empty pane asks when the surface says nothing else. */
|
|
17
|
+
export declare const NEXT = "What\u2019s up next?";
|
|
18
|
+
export interface EmptyPromptProps extends Col {
|
|
19
|
+
/** The question. */
|
|
20
|
+
title?: ReactNode;
|
|
21
|
+
/** Drawn before the question — a surface's own mark, ~20px. */
|
|
22
|
+
mark?: ReactNode;
|
|
23
|
+
/** The column the heading aligns to, px. Match the composer's. */
|
|
24
|
+
column?: number;
|
|
25
|
+
/** The heading's outline level; a pane with a page title above it passes 2. */
|
|
26
|
+
level?: 1 | 2 | 3;
|
|
27
|
+
}
|
|
28
|
+
export declare function EmptyPrompt({ title, mark, column, level, ...rest }: EmptyPromptProps): import("react").JSX.Element;
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=EmptyPrompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmptyPrompt.d.ts","sourceRoot":"","sources":["../../src/chat/EmptyPrompt.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,OAAO,EAAuB,MAAM,EAAE,MAAM,YAAY,CAAA;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItD,KAAK,GAAG,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,EAAE,UAAU,CAAC,CAAA;AAK1D,kEAAkE;AAClE,eAAO,MAAM,IAAI,yBAAoB,CAAA;AAErC,MAAM,WAAW,gBAAiB,SAAQ,GAAG;IAC3C,oBAAoB;IACpB,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,+DAA+D;IAC/D,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,+EAA+E;IAC/E,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;CAClB;AAED,wBAAgB,WAAW,CAAC,EAC1B,KAAY,EACZ,IAAI,EACJ,MAAe,EACf,KAAS,EACT,GAAG,IAAI,EACR,EAAE,gBAAgB,+BAqBlB"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* EmptyPrompt — what an empty conversation pane says before anything is asked.
|
|
5
|
+
*
|
|
6
|
+
* One line at the top of the pane: a small mark and a question. It is aligned
|
|
7
|
+
* to the COLUMN the composer sits in, not centred on the pane, so the question
|
|
8
|
+
* and the field that answers it start at the same left edge — the eye reads
|
|
9
|
+
* down one line into the other.
|
|
10
|
+
*
|
|
11
|
+
* The mark is a slot, never a brand this package picks: a surface passes its
|
|
12
|
+
* own (`BrandMark`, an org mark, nothing), and the heading is the same either
|
|
13
|
+
* way.
|
|
14
|
+
*/
|
|
15
|
+
import { SizableText, XStack, YStack } from '@hanzo/gui';
|
|
16
|
+
import { slot } from '../backends/gui/slot.js';
|
|
17
|
+
/** The composer column's width, so the two line up by default. */
|
|
18
|
+
const COLUMN = 768;
|
|
19
|
+
/** What an empty pane asks when the surface says nothing else. */
|
|
20
|
+
export const NEXT = 'What’s up next?';
|
|
21
|
+
export function EmptyPrompt({ title = NEXT, mark, column = COLUMN, level = 1, ...rest }) {
|
|
22
|
+
return (_jsx(YStack, { ...slot('empty-prompt'), width: "100%", items: "center", px: "$4", pt: "$2.5", ...rest, children: _jsxs(XStack, { width: "100%", maxW: column, items: "center", gap: "$2", children: [mark ? (_jsx(XStack, { ...slot('empty-prompt-mark'), shrink: 0, items: "center", "aria-hidden": true, children: mark })) : null, _jsx(SizableText, { ...slot('empty-prompt-title'), role: "heading", "aria-level": level, size: "$7", color: "$ink", children: title })] }) }));
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=EmptyPrompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmptyPrompt.js","sourceRoot":"","sources":["../../src/chat/EmptyPrompt.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAGxD,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAA;AAI3C,kEAAkE;AAClE,MAAM,MAAM,GAAG,GAAG,CAAA;AAElB,kEAAkE;AAClE,MAAM,CAAC,MAAM,IAAI,GAAG,iBAAiB,CAAA;AAarC,MAAM,UAAU,WAAW,CAAC,EAC1B,KAAK,GAAG,IAAI,EACZ,IAAI,EACJ,MAAM,GAAG,MAAM,EACf,KAAK,GAAG,CAAC,EACT,GAAG,IAAI,EACU;IACjB,OAAO,CACL,KAAC,MAAM,OAAK,IAAI,CAAC,cAAc,CAAC,EAAE,KAAK,EAAC,MAAM,EAAC,KAAK,EAAC,QAAQ,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,MAAM,KAAK,IAAI,YACtF,MAAC,MAAM,IAAC,KAAK,EAAC,MAAM,EAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAC,QAAQ,EAAC,GAAG,EAAC,IAAI,aACvD,IAAI,CAAC,CAAC,CAAC,CACN,KAAC,MAAM,OAAK,IAAI,CAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAC,QAAQ,iCAC7D,IAAI,GACE,CACV,CAAC,CAAC,CAAC,IAAI,EACR,KAAC,WAAW,OACN,IAAI,CAAC,oBAAoB,CAAC,EAC9B,IAAI,EAAC,SAAS,gBACF,KAAK,EACjB,IAAI,EAAC,IAAI,EACT,KAAK,EAAC,MAAM,YAEX,KAAK,GACM,IACP,GACF,CACV,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
'use client';"use strict";
|
|
2
|
+
'use client';
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.StatusDot = StatusDot;
|
|
5
|
+
exports.SessionRail = SessionRail;
|
|
6
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
7
|
+
/**
|
|
8
|
+
* SessionRail — the left rail of a sessions surface: start one, go somewhere,
|
|
9
|
+
* reopen a recent one, and who you are.
|
|
10
|
+
*
|
|
11
|
+
* + New the primary row; the current view on a fresh pane
|
|
12
|
+
* Artifacts · Customize … the surface's own places, as `links`
|
|
13
|
+
* More ⌄ a disclosure over `more`, when there are more
|
|
14
|
+
* Recents ⇅ the sessions, newest first, each with a status dot
|
|
15
|
+
* (z) z@hanzo.ai ⌄ ⚙ ⌕ the account, then settings and search
|
|
16
|
+
*
|
|
17
|
+
* Presentational: no routing, no fetching. `active` comes in, `onOpen` goes out.
|
|
18
|
+
*
|
|
19
|
+
* THE SIDEBAR CANON (console, hanzo.app, hanzo.chat, the extension):
|
|
20
|
+
* - Collapse is an EXPLICIT toggle and the host persists it. `collapsed` in,
|
|
21
|
+
* `onCollapse` out. There is no hover-to-expand and no pin.
|
|
22
|
+
* - Collapsed is a narrow RAIL that stays on screen — icons only, labels as
|
|
23
|
+
* tooltips — and its top row is the expand control.
|
|
24
|
+
* - Below `md` there is no rail at all. The column hides, and the same
|
|
25
|
+
* contents open as a drawer from the left when the host says so (`open`,
|
|
26
|
+
* `onOpenChange`) — typically from a menu button only a phone shows.
|
|
27
|
+
*
|
|
28
|
+
* Built from the chat `Sidebar` column and its icon button, so the rail is the
|
|
29
|
+
* same material as every other chat surface's.
|
|
30
|
+
*/
|
|
31
|
+
const gui_1 = require("@hanzo/gui");
|
|
32
|
+
const lucide_icons_2_1 = require("@hanzogui/lucide-icons-2");
|
|
33
|
+
const react_1 = require("react");
|
|
34
|
+
const sheet_1 = require("../backends/gui/sheet.cjs");
|
|
35
|
+
const slot_1 = require("../backends/gui/slot.cjs");
|
|
36
|
+
const Sidebar_1 = require("./Sidebar.cjs");
|
|
37
|
+
/** Expanded width, px — the column's own width, its hairline outside it. */
|
|
38
|
+
const WIDTH = 272;
|
|
39
|
+
/** Collapsed width, px. The same rail width every chat surface collapses to. */
|
|
40
|
+
const RAIL = 56;
|
|
41
|
+
/** The keyboard focus ring every control in the package draws. */
|
|
42
|
+
const RING = { outlineColor: '$outlineColor', outlineWidth: 2, outlineStyle: 'solid' };
|
|
43
|
+
/** One row: 32px, the 8px radius, icon then label. */
|
|
44
|
+
const ROW = { minH: 32, px: '$2', rounded: '$3', gap: '$2.5' };
|
|
45
|
+
/** The status mark: a 6px dot, filled while something is happening. */
|
|
46
|
+
function StatusDot({ status = 'idle' }) {
|
|
47
|
+
const filled = status === 'running' || status === 'paused' || status === 'error';
|
|
48
|
+
return ((0, jsx_runtime_1.jsx)(gui_1.XStack, { ...(0, slot_1.slot)('status-dot'), "data-status": status,
|
|
49
|
+
// The pulse is a class the package's own sheet owns (styles/motion.css),
|
|
50
|
+
// opacity only — nothing reflows for a dot nobody is reading.
|
|
51
|
+
className: status === 'running' ? 'hz-pulse' : undefined, width: 6, height: 6, rounded: 9999, shrink: 0, bg: filled ? (status === 'error' ? '$bad' : status === 'paused' ? '$faint' : '$quiet') : 'transparent', borderWidth: filled ? 0 : 1, borderColor: "$faint", "aria-hidden": true }));
|
|
52
|
+
}
|
|
53
|
+
/** Where a row starts: the 16px column every icon and dot sits centred in. */
|
|
54
|
+
const Lead = ({ children }) => ((0, jsx_runtime_1.jsx)(gui_1.XStack, { width: 16, height: 16, shrink: 0, items: "center", justify: "center", children: children }));
|
|
55
|
+
/** One nav row. On the rail it is the icon alone, the label its tooltip and name. */
|
|
56
|
+
function Row({ label, icon, onPress, active, rail, quiet, expanded, controls, data = 'rail-row' }) {
|
|
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", role: "button", tabIndex: 0, "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: RING, onPress: onPress, onKeyDown: (e) => {
|
|
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 }))] }));
|
|
63
|
+
}
|
|
64
|
+
/** The account line: avatar, the name clamped, the caret. */
|
|
65
|
+
function Account({ account, rail }) {
|
|
66
|
+
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, children: account.avatar ?? ((0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$1", fontWeight: "600", color: "$ink", children: account.name.charAt(0).toUpperCase() })) }));
|
|
67
|
+
return ((0, jsx_runtime_1.jsxs)(gui_1.XStack, { ...(0, slot_1.slot)('rail-account'), ...(rail ? (0, slot_1.tip)(account.name) : null), ...ROW, gap: "$2", px: "$1", flex: rail ? undefined : 1, minW: 0, items: "center", justify: rail ? 'center' : 'flex-start', cursor: account.onPress ? 'pointer' : undefined, role: account.onPress ? 'button' : undefined, tabIndex: account.onPress ? 0 : undefined, "aria-label": account.onPress ? `Account: ${account.name}` : undefined, "aria-haspopup": account.onPress ? 'menu' : undefined, hoverStyle: account.onPress ? { bg: '$hover' } : undefined, onPress: account.onPress, onKeyDown: (e) => {
|
|
68
|
+
if (!account.onPress || (e?.key !== 'Enter' && e?.key !== ' '))
|
|
69
|
+
return;
|
|
70
|
+
e.preventDefault?.();
|
|
71
|
+
account.onPress();
|
|
72
|
+
}, children: [face, rail ? null : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$3", numberOfLines: 1, flex: 1, minW: 0, color: "$ink", children: account.name }), account.onPress ? (0, jsx_runtime_1.jsx)(lucide_icons_2_1.ChevronDown, { size: 14, color: "$soft" }) : null] }))] }));
|
|
73
|
+
}
|
|
74
|
+
/** 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, onSettings, onSearch, collapsed = false, onCollapse, mark, rail, }) {
|
|
76
|
+
const [unfolded, setUnfolded] = (0, react_1.useState)(false);
|
|
77
|
+
const id = (0, react_1.useId)();
|
|
78
|
+
const moreId = `${id}-more`;
|
|
79
|
+
const headId = `${id}-recents`;
|
|
80
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [rail ? ((0, jsx_runtime_1.jsx)(gui_1.XStack, { justify: "center", 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 }) }) })) : 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)(Row, { 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)(Row, { 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)(Row, { 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)(Row, { 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
|
+
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", role: "button", tabIndex: 0, "aria-current": on ? 'page' : undefined, bg: on ? '$raised' : undefined, hoverStyle: { bg: on ? '$raised' : '$hover' }, pressStyle: { bg: '$raised' }, focusVisibleStyle: RING, onPress: () => onOpen(s.id), onKeyDown: (e) => {
|
|
83
|
+
if (e?.key !== 'Enter' && e?.key !== ' ')
|
|
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] })] }));
|
|
89
|
+
}
|
|
90
|
+
function SessionRail(props) {
|
|
91
|
+
const {
|
|
92
|
+
// Everything the contents read is named here, so none of it reaches the
|
|
93
|
+
// column as a stray DOM attribute through `rest`.
|
|
94
|
+
onNew, newLabel, fresh, links, more, moreLabel, recents, recentsLabel, active, onOpen, onSort, sortLabel, empty, notice, account, onSettings, onSearch, collapsed = false, onCollapse, mark, open = false, onOpenChange, label = 'Sessions', width = WIDTH, ...rest } = props;
|
|
95
|
+
const rail = collapsed;
|
|
96
|
+
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: onOpenChange, children: (0, jsx_runtime_1.jsxs)(sheet_1.SheetContent, { side: "left", width: width, maxW: "86%", p: "$2", gap: "$0", bg: "$panel", 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, onNew: onNew ? () => (onOpenChange?.(false), onNew()) : undefined, onOpen: (sid) => (onOpenChange?.(false), onOpen(sid)) }) })] }) })) : null] }));
|
|
97
|
+
}
|