@hanzo/ui 8.1.4 → 8.1.5
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/chat/Code.cjs +2 -2
- package/dist/chat/Code.d.ts +16 -3
- package/dist/chat/Code.d.ts.map +1 -1
- package/dist/chat/Code.js +2 -2
- package/dist/chat/Code.js.map +1 -1
- package/dist/chat/Composer.cjs +16 -10
- package/dist/chat/Composer.d.ts +59 -3
- package/dist/chat/Composer.d.ts.map +1 -1
- package/dist/chat/Composer.js +16 -10
- package/dist/chat/Composer.js.map +1 -1
- package/dist/chat/Failure.cjs +2 -2
- package/dist/chat/Failure.d.ts +29 -3
- package/dist/chat/Failure.d.ts.map +1 -1
- package/dist/chat/Failure.js +2 -2
- package/dist/chat/Failure.js.map +1 -1
- package/dist/chat/Header.cjs +2 -2
- package/dist/chat/Header.d.ts +20 -3
- package/dist/chat/Header.d.ts.map +1 -1
- package/dist/chat/Header.js +2 -2
- package/dist/chat/Header.js.map +1 -1
- package/dist/chat/Message.cjs +10 -4
- package/dist/chat/Message.d.ts +42 -3
- package/dist/chat/Message.d.ts.map +1 -1
- package/dist/chat/Message.js +10 -4
- package/dist/chat/Message.js.map +1 -1
- package/dist/chat/Sources.cjs +33 -10
- package/dist/chat/Sources.d.ts +46 -6
- package/dist/chat/Sources.d.ts.map +1 -1
- package/dist/chat/Sources.js +32 -9
- package/dist/chat/Sources.js.map +1 -1
- package/dist/chat/Step.cjs +2 -2
- package/dist/chat/Step.d.ts +4 -3
- package/dist/chat/Step.d.ts.map +1 -1
- package/dist/chat/Step.js +2 -2
- package/dist/chat/Step.js.map +1 -1
- package/dist/chat/Thread.cjs +38 -13
- package/dist/chat/Thread.d.ts +55 -3
- package/dist/chat/Thread.d.ts.map +1 -1
- package/dist/chat/Thread.js +38 -13
- package/dist/chat/Thread.js.map +1 -1
- package/dist/chat/index.cjs +19 -2
- package/dist/chat/index.d.ts +18 -1
- package/dist/chat/index.d.ts.map +1 -1
- package/dist/chat/index.js +18 -1
- package/dist/chat/index.js.map +1 -1
- package/dist/chat/pure.cjs +41 -0
- package/dist/chat/pure.d.ts +3 -0
- package/dist/chat/pure.d.ts.map +1 -0
- package/dist/chat/pure.js +35 -0
- package/dist/chat/pure.js.map +1 -0
- package/dist/chat/send.cjs +10 -1
- package/dist/chat/send.d.ts +9 -0
- package/dist/chat/send.d.ts.map +1 -1
- package/dist/chat/send.js +10 -1
- package/dist/chat/send.js.map +1 -1
- package/dist/chat/stick.cjs +1 -1
- package/dist/chat/stick.js +1 -1
- package/dist/gallery.cjs +5 -4
- package/dist/gallery.d.ts.map +1 -1
- package/dist/gallery.js +5 -4
- package/dist/gallery.js.map +1 -1
- package/dist/product/CopyButton.cjs +2 -2
- package/dist/product/CopyButton.d.ts +12 -2
- package/dist/product/CopyButton.d.ts.map +1 -1
- package/dist/product/CopyButton.js +2 -2
- package/dist/product/CopyButton.js.map +1 -1
- package/dist/product/pure.cjs +12 -1
- package/dist/product/pure.d.ts +2 -0
- package/dist/product/pure.d.ts.map +1 -1
- package/dist/product/pure.js +7 -0
- package/dist/product/pure.js.map +1 -1
- package/dist/styles.css +14 -2
- package/package.json +7 -1
package/dist/chat/Code.cjs
CHANGED
|
@@ -30,7 +30,7 @@ const CopyButton_1 = require("../product/CopyButton.cjs");
|
|
|
30
30
|
const MONO = {
|
|
31
31
|
fontFamily: 'var(--font-geist-mono, ui-monospace, SFMono-Regular, Menlo, monospace)',
|
|
32
32
|
};
|
|
33
|
-
function Code({ children, language = 'text', value, actions }) {
|
|
33
|
+
function Code({ children, language = 'text', value, actions, ...props }) {
|
|
34
34
|
const text = value ?? (typeof children === 'string' ? children : '');
|
|
35
|
-
return ((0, jsx_runtime_1.jsxs)(gui_1.YStack, { ...(0, slot_1.slot)('code'), width: "100%", rounded: "$4", borderWidth: 1, borderColor: "$borderColor", bg: "$color2", overflow: "hidden", children: [(0, jsx_runtime_1.jsxs)(gui_1.XStack, { items: "center", gap: "$1", px: "$3", py: "$1.5", borderBottomWidth: 1, borderColor: "$borderColor", children: [(0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$1", style: MONO, color: "$color11", children: language }), (0, jsx_runtime_1.jsx)(gui_1.XStack, { flex: 1 }), actions, text ? (0, jsx_runtime_1.jsx)(CopyButton_1.CopyButton, { value: text }) : null] }), (0, jsx_runtime_1.jsx)(gui_1.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, children: (0, jsx_runtime_1.jsx)(gui_1.YStack, { px: "$3", py: "$2.5", children: (0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$1", style: MONO, lineHeight: 20, children: children }) }) })] }));
|
|
35
|
+
return ((0, jsx_runtime_1.jsxs)(gui_1.YStack, { ...(0, slot_1.slot)('code'), width: "100%", rounded: "$4", borderWidth: 1, borderColor: "$borderColor", bg: "$color2", overflow: "hidden", ...props, children: [(0, jsx_runtime_1.jsxs)(gui_1.XStack, { items: "center", gap: "$1", px: "$3", py: "$1.5", borderBottomWidth: 1, borderColor: "$borderColor", children: [(0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$1", style: MONO, color: "$color11", children: language }), (0, jsx_runtime_1.jsx)(gui_1.XStack, { flex: 1 }), actions, text ? (0, jsx_runtime_1.jsx)(CopyButton_1.CopyButton, { value: text }) : null] }), (0, jsx_runtime_1.jsx)(gui_1.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, children: (0, jsx_runtime_1.jsx)(gui_1.YStack, { px: "$3", py: "$2.5", children: (0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$1", style: MONO, lineHeight: 20, children: children }) }) })] }));
|
|
36
36
|
}
|
package/dist/chat/Code.d.ts
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Code — a labelled, copyable code region.
|
|
3
|
+
*
|
|
4
|
+
* The language label and the controls live in a bar above the code, never
|
|
5
|
+
* floating over it: an overlaid copy button covers the first line, which is
|
|
6
|
+
* where the prompt or the import sits and the part most often being read.
|
|
7
|
+
*
|
|
8
|
+
* Highlighting is not here. Surfaces disagree on the highlighter (and on whether
|
|
9
|
+
* they want one at all), and a package that picked would either impose a large
|
|
10
|
+
* dependency or be bypassed. `children` is rendered as-is, so a surface can pass
|
|
11
|
+
* plain text or its own highlighted nodes.
|
|
12
|
+
*/
|
|
13
|
+
import { YStack } from '@hanzo/gui';
|
|
14
|
+
import { type ComponentProps, type ReactNode } from 'react';
|
|
15
|
+
export interface CodeProps extends Omit<ComponentProps<typeof YStack>, 'children'> {
|
|
3
16
|
children?: ReactNode;
|
|
4
17
|
/** Shown in the label bar. */
|
|
5
18
|
language?: string;
|
|
@@ -8,5 +21,5 @@ export interface CodeProps {
|
|
|
8
21
|
/** Extra controls in the label bar, before copy. */
|
|
9
22
|
actions?: ReactNode;
|
|
10
23
|
}
|
|
11
|
-
export declare function Code({ children, language, value, actions }: CodeProps): import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
export declare function Code({ children, language, value, actions, ...props }: CodeProps): import("react/jsx-runtime").JSX.Element;
|
|
12
25
|
//# sourceMappingURL=Code.d.ts.map
|
package/dist/chat/Code.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Code.d.ts","sourceRoot":"","sources":["../../src/chat/Code.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Code.d.ts","sourceRoot":"","sources":["../../src/chat/Code.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,OAAO,EAAmC,MAAM,EAAE,MAAM,YAAY,CAAA;AACpE,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAkB3D,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,EAAE,UAAU,CAAC;IAChF,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,mFAAmF;IACnF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,oDAAoD;IACpD,OAAO,CAAC,EAAE,SAAS,CAAA;CACpB;AAED,wBAAgB,IAAI,CAAC,EAAE,QAAQ,EAAE,QAAiB,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,EAAE,SAAS,2CA0DxF"}
|
package/dist/chat/Code.js
CHANGED
|
@@ -27,8 +27,8 @@ import { CopyButton } from '../product/CopyButton.js';
|
|
|
27
27
|
const MONO = {
|
|
28
28
|
fontFamily: 'var(--font-geist-mono, ui-monospace, SFMono-Regular, Menlo, monospace)',
|
|
29
29
|
};
|
|
30
|
-
export function Code({ children, language = 'text', value, actions }) {
|
|
30
|
+
export function Code({ children, language = 'text', value, actions, ...props }) {
|
|
31
31
|
const text = value ?? (typeof children === 'string' ? children : '');
|
|
32
|
-
return (_jsxs(YStack, { ...slot('code'), width: "100%", rounded: "$4", borderWidth: 1, borderColor: "$borderColor", bg: "$color2", overflow: "hidden", children: [_jsxs(XStack, { items: "center", gap: "$1", px: "$3", py: "$1.5", borderBottomWidth: 1, borderColor: "$borderColor", children: [_jsx(SizableText, { size: "$1", style: MONO, color: "$color11", children: language }), _jsx(XStack, { flex: 1 }), actions, text ? _jsx(CopyButton, { value: text }) : null] }), _jsx(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, children: _jsx(YStack, { px: "$3", py: "$2.5", children: _jsx(SizableText, { size: "$1", style: MONO, lineHeight: 20, children: children }) }) })] }));
|
|
32
|
+
return (_jsxs(YStack, { ...slot('code'), width: "100%", rounded: "$4", borderWidth: 1, borderColor: "$borderColor", bg: "$color2", overflow: "hidden", ...props, children: [_jsxs(XStack, { items: "center", gap: "$1", px: "$3", py: "$1.5", borderBottomWidth: 1, borderColor: "$borderColor", children: [_jsx(SizableText, { size: "$1", style: MONO, color: "$color11", children: language }), _jsx(XStack, { flex: 1 }), actions, text ? _jsx(CopyButton, { value: text }) : null] }), _jsx(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, children: _jsx(YStack, { px: "$3", py: "$2.5", children: _jsx(SizableText, { size: "$1", style: MONO, lineHeight: 20, children: children }) }) })] }));
|
|
33
33
|
}
|
|
34
34
|
//# sourceMappingURL=Code.js.map
|
package/dist/chat/Code.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Code.js","sourceRoot":"","sources":["../../src/chat/Code.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;;;;;;GAWG;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,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAElD;;;;;;;;GAQG;AACH,MAAM,IAAI,GAAG;IACX,UAAU,EAAE,wEAAwE;CAC5E,CAAA;AAYV,MAAM,UAAU,IAAI,CAAC,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,EAAE,KAAK,EAAE,OAAO,EAAa;
|
|
1
|
+
{"version":3,"file":"Code.js","sourceRoot":"","sources":["../../src/chat/Code.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;;;;;;GAWG;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,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAElD;;;;;;;;GAQG;AACH,MAAM,IAAI,GAAG;IACX,UAAU,EAAE,wEAAwE;CAC5E,CAAA;AAYV,MAAM,UAAU,IAAI,CAAC,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,KAAK,EAAa;IACvF,MAAM,IAAI,GAAG,KAAK,IAAI,CAAC,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IAEpE,OAAO,CACL,MAAC,MAAM,OACD,IAAI,CAAC,MAAM,CAAC,EAChB,KAAK,EAAC,MAAM,EACZ,OAAO,EAAC,IAAI,EACZ,WAAW,EAAE,CAAC,EACd,WAAW,EAAC,cAAc,EAC1B,EAAE,EAAC,SAAS,EACZ,QAAQ,EAAC,QAAQ,KACb,KAAK,aAET,MAAC,MAAM,IACL,KAAK,EAAC,QAAQ,EACd,GAAG,EAAC,IAAI,EACR,EAAE,EAAC,IAAI,EACP,EAAE,EAAC,MAAM,EACT,iBAAiB,EAAE,CAAC,EACpB,WAAW,EAAC,cAAc,aAQ1B,KAAC,WAAW,IAAC,IAAI,EAAC,IAAI,EAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAC,UAAU,YACjD,QAAQ,GACG,EACd,KAAC,MAAM,IAAC,IAAI,EAAE,CAAC,GAAI,EAClB,OAAO,EACP,IAAI,CAAC,CAAC,CAAC,KAAC,UAAU,IAAC,KAAK,EAAE,IAAI,GAAI,CAAC,CAAC,CAAC,IAAI,IACnC,EAeT,KAAC,UAAU,IAAC,UAAU,QAAC,8BAA8B,EAAE,KAAK,YAC1D,KAAC,MAAM,IAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,MAAM,YACvB,KAAC,WAAW,IAAC,IAAI,EAAC,IAAI,EAAC,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,YAC/C,QAAQ,GACG,GACP,GACE,IACN,CACV,CAAA;AACH,CAAC"}
|
package/dist/chat/Composer.cjs
CHANGED
|
@@ -27,14 +27,10 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
27
27
|
* nothing here for it to reach. Adding either would be inventing an interaction
|
|
28
28
|
* and then asking three surfaces to adopt it.
|
|
29
29
|
*
|
|
30
|
-
* Growth is `Textarea`'s and it
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* count, so a long unbroken paragraph scrolls inside the floor instead of
|
|
35
|
-
* growing the field. Fixing that means measuring `scrollHeight`, which is the
|
|
36
|
-
* DOM-only path the five hand-rolled composers each took and the reason none of
|
|
37
|
-
* them runs on native. It is a `Textarea` decision, not a chat one.
|
|
30
|
+
* Growth is `Textarea`'s, and since 8.1.4 it follows the CONTENT rather than the
|
|
31
|
+
* newline count — so a long paragraph that wraps without ever containing a `\n`
|
|
32
|
+
* raises the field instead of scrolling inside it. `rows` is the floor and
|
|
33
|
+
* `maxHeight` the ceiling; both are bounds, and neither is re-implemented here.
|
|
38
34
|
*/
|
|
39
35
|
const gui_1 = require("@hanzo/gui");
|
|
40
36
|
const lucide_icons_2_1 = require("@hanzogui/lucide-icons-2");
|
|
@@ -81,7 +77,7 @@ const FLOOR = 44;
|
|
|
81
77
|
* changes — which is what a model-named placeholder forces a surface to do.
|
|
82
78
|
*/
|
|
83
79
|
exports.ASK = 'Ask anything';
|
|
84
|
-
function Composer({ value, onChange, onSend, onStop, busy = false, disabled = false, placeholder = exports.ASK, rows = MIN_ROWS, maxHeight = CEILING, children, hint, }) {
|
|
80
|
+
function Composer({ value, onChange, onSend, onStop, busy = false, disabled = false, placeholder = exports.ASK, rows = MIN_ROWS, maxHeight = CEILING, children, hint, label, field, send, ...props }) {
|
|
85
81
|
const sendable = (0, send_1.ready)(value, busy, disabled);
|
|
86
82
|
const keyed = (e) => {
|
|
87
83
|
const key = e.key ?? e.nativeEvent?.key ?? '';
|
|
@@ -101,5 +97,15 @@ function Composer({ value, onChange, onSend, onStop, busy = false, disabled = fa
|
|
|
101
97
|
if (sendable)
|
|
102
98
|
onSend();
|
|
103
99
|
};
|
|
104
|
-
return ((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, children: [(0, jsx_runtime_1.jsx)(gui_2.Textarea, { ...(0, slot_1.slot)('composer-field'), rows: rows,
|
|
100
|
+
return ((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: [(0, jsx_runtime_1.jsx)(gui_2.Textarea, { ...(0, slot_1.slot)('composer-field'), rows: rows, placeholder: placeholder, disabled: disabled, borderWidth: 0, minH: FLOOR, maxH: maxHeight, "aria-label": label ?? placeholder, ...field,
|
|
101
|
+
// After `field`, and deliberately. These four ARE the composer; a
|
|
102
|
+
// caller's `onKeyDown` landing on top of `keyed` would take the Enter
|
|
103
|
+
// rule and the IME guard with it, type-check, and go on looking
|
|
104
|
+
// correct until a Japanese writer typed into it. So the caller's runs
|
|
105
|
+
// FIRST and this one defers to it if it claimed the key.
|
|
106
|
+
value: value, onChangeText: onChange, onKeyDown: (e) => {
|
|
107
|
+
field?.onKeyDown?.(e);
|
|
108
|
+
if (!e?.defaultPrevented)
|
|
109
|
+
keyed(e);
|
|
110
|
+
} }), (0, jsx_runtime_1.jsxs)(gui_1.XStack, { items: "center", gap: PAD, children: [children, (0, jsx_runtime_1.jsx)(gui_1.XStack, { flex: 1 }), hint ? ((0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$1", color: "$color10", children: hint })) : null, 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 }) }))] })] }));
|
|
105
111
|
}
|
package/dist/chat/Composer.d.ts
CHANGED
|
@@ -1,4 +1,38 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Composer — the one chat input for every Hanzo surface.
|
|
3
|
+
*
|
|
4
|
+
* Presentational and controlled: it owns no draft, no transport and no model
|
|
5
|
+
* state. `children` is the toolbar slot, which is where a surface puts its
|
|
6
|
+
* `ModelSelector`, attachment control or mode chips — that keeps the shell the
|
|
7
|
+
* same everywhere while the affordances stay per-surface.
|
|
8
|
+
*
|
|
9
|
+
* The send control is the same button in both states: it submits, and while a
|
|
10
|
+
* turn is in flight it stops. Two buttons in one place was the thing every
|
|
11
|
+
* surface got subtly different.
|
|
12
|
+
*
|
|
13
|
+
* Two keys are deliberately absent, because the surfaces do not agree that they
|
|
14
|
+
* exist. ESCAPE is bound in none of the three main composers — only in chat's
|
|
15
|
+
* two SUB-composers, where it dismisses the thing they float over
|
|
16
|
+
* (`SelectionAsk.tsx:85`, `EditMessage.tsx:124`), which is the host's concern
|
|
17
|
+
* and not the field's. ARROWUP recalls the last turn in exactly one composer,
|
|
18
|
+
* chat's (`useHandleKeyUp.ts:117`), and it does it by finding
|
|
19
|
+
* `document.getElementById('edit-' + parentMessageId)` and clicking it — it is
|
|
20
|
+
* a binding to their edit-in-place, not a general history recall, and there is
|
|
21
|
+
* nothing here for it to reach. Adding either would be inventing an interaction
|
|
22
|
+
* and then asking three surfaces to adopt it.
|
|
23
|
+
*
|
|
24
|
+
* Growth is `Textarea`'s, and since 8.1.4 it follows the CONTENT rather than the
|
|
25
|
+
* newline count — so a long paragraph that wraps without ever containing a `\n`
|
|
26
|
+
* raises the field instead of scrolling inside it. `rows` is the floor and
|
|
27
|
+
* `maxHeight` the ceiling; both are bounds, and neither is re-implemented here.
|
|
28
|
+
*/
|
|
29
|
+
import { YStack } from '@hanzo/gui';
|
|
30
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
31
|
+
import { Textarea } from '../backends/gui/index.js';
|
|
32
|
+
/** `onChange` is dropped: this component already has one and it carries the
|
|
33
|
+
* draft, not a DOM change event. */
|
|
34
|
+
type Stack = Omit<ComponentProps<typeof YStack>, 'children' | 'onChange'>;
|
|
35
|
+
type FieldProps = Omit<ComponentProps<typeof Textarea>, 'value' | 'onChangeText'>;
|
|
2
36
|
/**
|
|
3
37
|
* The resting placeholder.
|
|
4
38
|
*
|
|
@@ -8,7 +42,7 @@ import type { ReactNode } from 'react';
|
|
|
8
42
|
* changes — which is what a model-named placeholder forces a surface to do.
|
|
9
43
|
*/
|
|
10
44
|
export declare const ASK = "Ask anything";
|
|
11
|
-
export interface ComposerProps {
|
|
45
|
+
export interface ComposerProps extends Stack {
|
|
12
46
|
value: string;
|
|
13
47
|
onChange: (value: string) => void;
|
|
14
48
|
/** Called when the draft is submitted. Clearing `value` is the host's job. */
|
|
@@ -27,6 +61,28 @@ export interface ComposerProps {
|
|
|
27
61
|
children?: ReactNode;
|
|
28
62
|
/** Hint shown at the end of the footer row. */
|
|
29
63
|
hint?: string;
|
|
64
|
+
/**
|
|
65
|
+
* The accessible name of the field.
|
|
66
|
+
*
|
|
67
|
+
* Distinct from `placeholder`, which it used to be derived from. A surface
|
|
68
|
+
* whose placeholder rotates on a timer — hanzo.app's does — renamed the
|
|
69
|
+
* control on every tick, so a screen reader re-announced the field while the
|
|
70
|
+
* writer was typing into it. The name is stable and the placeholder is
|
|
71
|
+
* decoration; deriving one from the other conflates them.
|
|
72
|
+
*/
|
|
73
|
+
label?: string;
|
|
74
|
+
/** The field's own props — a ref, a testid, focus handlers, a paste handler. */
|
|
75
|
+
field?: FieldProps;
|
|
76
|
+
/**
|
|
77
|
+
* Replaces the send control entirely.
|
|
78
|
+
*
|
|
79
|
+
* The default is the right one — one button that submits and stops, which is
|
|
80
|
+
* what every surface got subtly different — but a surface with a second
|
|
81
|
+
* commit mode has nowhere else to put it, and `children` is the START of the
|
|
82
|
+
* footer row.
|
|
83
|
+
*/
|
|
84
|
+
send?: ReactNode;
|
|
30
85
|
}
|
|
31
|
-
export declare function Composer({ value, onChange, onSend, onStop, busy, disabled, placeholder, rows, maxHeight, children, hint, }: ComposerProps): import("react/jsx-runtime").JSX.Element;
|
|
86
|
+
export declare function Composer({ value, onChange, onSend, onStop, busy, disabled, placeholder, rows, maxHeight, children, hint, label, field, send, ...props }: ComposerProps): import("react/jsx-runtime").JSX.Element;
|
|
87
|
+
export {};
|
|
32
88
|
//# sourceMappingURL=Composer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Composer.d.ts","sourceRoot":"","sources":["../../src/chat/Composer.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Composer.d.ts","sourceRoot":"","sources":["../../src/chat/Composer.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,EAAuB,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;qCACqC;AACrC,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;AAoCjF;;;;;;;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;;;;;;;;OAQG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,gFAAgF;IAChF,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,SAAS,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,GAAG,KAAK,EACT,EAAE,aAAa,2CA4Ef"}
|
package/dist/chat/Composer.js
CHANGED
|
@@ -23,14 +23,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
23
23
|
* nothing here for it to reach. Adding either would be inventing an interaction
|
|
24
24
|
* and then asking three surfaces to adopt it.
|
|
25
25
|
*
|
|
26
|
-
* Growth is `Textarea`'s and it
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* count, so a long unbroken paragraph scrolls inside the floor instead of
|
|
31
|
-
* growing the field. Fixing that means measuring `scrollHeight`, which is the
|
|
32
|
-
* DOM-only path the five hand-rolled composers each took and the reason none of
|
|
33
|
-
* them runs on native. It is a `Textarea` decision, not a chat one.
|
|
26
|
+
* Growth is `Textarea`'s, and since 8.1.4 it follows the CONTENT rather than the
|
|
27
|
+
* newline count — so a long paragraph that wraps without ever containing a `\n`
|
|
28
|
+
* raises the field instead of scrolling inside it. `rows` is the floor and
|
|
29
|
+
* `maxHeight` the ceiling; both are bounds, and neither is re-implemented here.
|
|
34
30
|
*/
|
|
35
31
|
import { SizableText, XStack, YStack } from '@hanzo/gui';
|
|
36
32
|
import { ArrowUp, Square } from '@hanzogui/lucide-icons-2';
|
|
@@ -77,7 +73,7 @@ const FLOOR = 44;
|
|
|
77
73
|
* changes — which is what a model-named placeholder forces a surface to do.
|
|
78
74
|
*/
|
|
79
75
|
export const ASK = 'Ask anything';
|
|
80
|
-
export function Composer({ value, onChange, onSend, onStop, busy = false, disabled = false, placeholder = ASK, rows = MIN_ROWS, maxHeight = CEILING, children, hint, }) {
|
|
76
|
+
export function Composer({ value, onChange, onSend, onStop, busy = false, disabled = false, placeholder = ASK, rows = MIN_ROWS, maxHeight = CEILING, children, hint, label, field, send, ...props }) {
|
|
81
77
|
const sendable = ready(value, busy, disabled);
|
|
82
78
|
const keyed = (e) => {
|
|
83
79
|
const key = e.key ?? e.nativeEvent?.key ?? '';
|
|
@@ -97,6 +93,16 @@ export function Composer({ value, onChange, onSend, onStop, busy = false, disabl
|
|
|
97
93
|
if (sendable)
|
|
98
94
|
onSend();
|
|
99
95
|
};
|
|
100
|
-
return (_jsxs(YStack, { ...slot('composer'), width: "100%", rounded: "$5", borderWidth: 1, borderColor: "$borderColor", bg: "$background", p: PAD, gap: PAD, children: [_jsx(Textarea, { ...slot('composer-field'), rows: rows,
|
|
96
|
+
return (_jsxs(YStack, { ...slot('composer'), width: "100%", rounded: "$5", borderWidth: 1, borderColor: "$borderColor", bg: "$background", p: PAD, gap: PAD, ...props, children: [_jsx(Textarea, { ...slot('composer-field'), rows: rows, placeholder: placeholder, disabled: disabled, borderWidth: 0, minH: FLOOR, maxH: maxHeight, "aria-label": label ?? placeholder, ...field,
|
|
97
|
+
// After `field`, and deliberately. These four ARE the composer; a
|
|
98
|
+
// caller's `onKeyDown` landing on top of `keyed` would take the Enter
|
|
99
|
+
// rule and the IME guard with it, type-check, and go on looking
|
|
100
|
+
// correct until a Japanese writer typed into it. So the caller's runs
|
|
101
|
+
// FIRST and this one defers to it if it claimed the key.
|
|
102
|
+
value: value, onChangeText: onChange, onKeyDown: (e) => {
|
|
103
|
+
field?.onKeyDown?.(e);
|
|
104
|
+
if (!e?.defaultPrevented)
|
|
105
|
+
keyed(e);
|
|
106
|
+
} }), _jsxs(XStack, { items: "center", gap: PAD, children: [children, _jsx(XStack, { flex: 1 }), hint ? (_jsx(SizableText, { size: "$1", color: "$color10", children: hint })) : null, 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
107
|
}
|
|
102
108
|
//# sourceMappingURL=Composer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Composer.js","sourceRoot":"","sources":["../../src/chat/Composer.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ
|
|
1
|
+
{"version":3,"file":"Composer.js","sourceRoot":"","sources":["../../src/chat/Composer.tsx"],"names":[],"mappings":"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"}
|
package/dist/chat/Failure.cjs
CHANGED
|
@@ -33,12 +33,12 @@ const lucide_icons_2_1 = require("@hanzogui/lucide-icons-2");
|
|
|
33
33
|
const gui_2 = require("../backends/gui/index.cjs");
|
|
34
34
|
const ink_1 = require("../backends/gui/ink.cjs");
|
|
35
35
|
const slot_1 = require("../backends/gui/slot.cjs");
|
|
36
|
-
function Failure({ children, onRetry, retryLabel = 'Try again' }) {
|
|
36
|
+
function Failure({ children, onRetry, retryLabel = 'Try again', ...props }) {
|
|
37
37
|
return ((0, jsx_runtime_1.jsxs)(gui_1.YStack, { ...(0, slot_1.slot)('failure'), role: "alert", "aria-live": "assertive", width: "100%", gap: "$2", px: "$3", py: "$2.5", rounded: "$4", borderWidth: 1,
|
|
38
38
|
// The edge again — see `product/tone.ts`. Its `stopped` register is
|
|
39
39
|
// `$color4` behind a `$color9` border for exactly this: with no hue to
|
|
40
40
|
// spend, an outline is what separates "this one" from its neighbours.
|
|
41
|
-
borderColor: "$color9", bg: "$color4", children: [(0, ink_1.ink)(children, undefined, { size: '$2', color: '$color12' }), onRetry ? (
|
|
41
|
+
borderColor: "$color9", bg: "$color4", ...props, children: [(0, ink_1.ink)(children, undefined, { size: '$2', color: '$color12' }), onRetry ? (
|
|
42
42
|
// The real Button, not a `role="button"` box with an `onPress`. A View
|
|
43
43
|
// wearing the role takes focus and then does nothing on Enter or Space,
|
|
44
44
|
// because the activation behaviour belongs to the element and not to
|
package/dist/chat/Failure.d.ts
CHANGED
|
@@ -1,10 +1,36 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Failure — the turn did not complete, and what to do about it.
|
|
3
|
+
*
|
|
4
|
+
* Distinct from a `Step` that errored: a step can fail inside an answer that
|
|
5
|
+
* still arrives, this is the answer not arriving. hanzo/chat keeps the same
|
|
6
|
+
* separation — `ToolCall`'s error state, and separately `MessageContent.tsx:153`
|
|
7
|
+
* swapping the whole body for `ErrorMessage`.
|
|
8
|
+
*
|
|
9
|
+
* Four surfaces draw this line and no two draw it the same way: chat's
|
|
10
|
+
* `ErrorBox` (`components/Messages/Content/Error.tsx`), the app builder's
|
|
11
|
+
* `$red8` text with the prose instruction "Something went wrong — please try
|
|
12
|
+
* again" (`ask-ai/chat-thread.tsx:258`), the extension's `.ae-error` div
|
|
13
|
+
* (`AnswerEngine.tsx:336`), and hanzo.app `/chat`, which is the interesting
|
|
14
|
+
* one: it sets `Message.error` at `app/chat/page.tsx:292` and never reads it
|
|
15
|
+
* anywhere in the render, so a stream that dies reports through a detached
|
|
16
|
+
* banner and the turn itself says nothing.
|
|
17
|
+
*
|
|
18
|
+
* Two of the four offer a way to try again. Both put it next to the message
|
|
19
|
+
* rather than in the hover strip, because a hover affordance on the thing that
|
|
20
|
+
* just failed is not reachable on a touch device.
|
|
21
|
+
*
|
|
22
|
+
* `role="alert"` with `aria-live="assertive"` is chat's, and it is right: a
|
|
23
|
+
* turn failing is the one event in a conversation that has to interrupt, since
|
|
24
|
+
* the reader is waiting on prose that is never going to come.
|
|
25
|
+
*/
|
|
26
|
+
import { YStack } from '@hanzo/gui';
|
|
27
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
28
|
+
export interface FailureProps extends Omit<ComponentProps<typeof YStack>, 'children'> {
|
|
3
29
|
/** What went wrong, in the surface's own words. */
|
|
4
30
|
children?: ReactNode;
|
|
5
31
|
/** Offer to run the turn again. Omit and no control renders. */
|
|
6
32
|
onRetry?: () => void;
|
|
7
33
|
retryLabel?: string;
|
|
8
34
|
}
|
|
9
|
-
export declare function Failure({ children, onRetry, retryLabel }: FailureProps): import("react/jsx-runtime").JSX.Element;
|
|
35
|
+
export declare function Failure({ children, onRetry, retryLabel, ...props }: FailureProps): import("react/jsx-runtime").JSX.Element;
|
|
10
36
|
//# sourceMappingURL=Failure.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Failure.d.ts","sourceRoot":"","sources":["../../src/chat/Failure.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Failure.d.ts","sourceRoot":"","sources":["../../src/chat/Failure.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAU,MAAM,EAAE,MAAM,YAAY,CAAA;AAE3C,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAMtD,MAAM,WAAW,YAAa,SAAQ,IAAI,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,EAAE,UAAU,CAAC;IACnF,mDAAmD;IACnD,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,wBAAgB,OAAO,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAwB,EAAE,GAAG,KAAK,EAAE,EAAE,YAAY,2CAmC9F"}
|
package/dist/chat/Failure.js
CHANGED
|
@@ -30,12 +30,12 @@ import { RefreshCw } from '@hanzogui/lucide-icons-2';
|
|
|
30
30
|
import { Button } from '../backends/gui/index.js';
|
|
31
31
|
import { ink } from '../backends/gui/ink.js';
|
|
32
32
|
import { slot } from '../backends/gui/slot.js';
|
|
33
|
-
export function Failure({ children, onRetry, retryLabel = 'Try again' }) {
|
|
33
|
+
export function Failure({ children, onRetry, retryLabel = 'Try again', ...props }) {
|
|
34
34
|
return (_jsxs(YStack, { ...slot('failure'), role: "alert", "aria-live": "assertive", width: "100%", gap: "$2", px: "$3", py: "$2.5", rounded: "$4", borderWidth: 1,
|
|
35
35
|
// The edge again — see `product/tone.ts`. Its `stopped` register is
|
|
36
36
|
// `$color4` behind a `$color9` border for exactly this: with no hue to
|
|
37
37
|
// spend, an outline is what separates "this one" from its neighbours.
|
|
38
|
-
borderColor: "$color9", bg: "$color4", children: [ink(children, undefined, { size: '$2', color: '$color12' }), onRetry ? (
|
|
38
|
+
borderColor: "$color9", bg: "$color4", ...props, children: [ink(children, undefined, { size: '$2', color: '$color12' }), onRetry ? (
|
|
39
39
|
// The real Button, not a `role="button"` box with an `onPress`. A View
|
|
40
40
|
// wearing the role takes focus and then does nothing on Enter or Space,
|
|
41
41
|
// because the activation behaviour belongs to the element and not to
|
package/dist/chat/Failure.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Failure.js","sourceRoot":"","sources":["../../src/chat/Failure.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AAGpD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAA;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAA;AAU3C,MAAM,UAAU,OAAO,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,GAAG,WAAW,EAAgB;
|
|
1
|
+
{"version":3,"file":"Failure.js","sourceRoot":"","sources":["../../src/chat/Failure.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AAGpD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAA;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAA;AAU3C,MAAM,UAAU,OAAO,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,GAAG,WAAW,EAAE,GAAG,KAAK,EAAgB;IAC7F,OAAO,CACL,MAAC,MAAM,OACD,IAAI,CAAC,SAAS,CAAC,EACnB,IAAI,EAAC,OAAO,eACF,WAAW,EACrB,KAAK,EAAC,MAAM,EACZ,GAAG,EAAC,IAAI,EACR,EAAE,EAAC,IAAI,EACP,EAAE,EAAC,MAAM,EACT,OAAO,EAAC,IAAI,EACZ,WAAW,EAAE,CAAC;QACd,oEAAoE;QACpE,uEAAuE;QACvE,sEAAsE;QACtE,WAAW,EAAC,SAAS,EACrB,EAAE,EAAC,SAAS,KACR,KAAK,aAER,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAC3D,OAAO,CAAC,CAAC,CAAC;YACT,uEAAuE;YACvE,wEAAwE;YACxE,qEAAqE;YACrE,uEAAuE;YACvE,+BAA+B;YAC/B,KAAC,MAAM,IAAC,IAAI,EAAC,YAAY,YACvB,MAAC,MAAM,OAAK,IAAI,CAAC,eAAe,CAAC,EAAE,OAAO,EAAC,SAAS,EAAC,IAAI,EAAC,IAAI,EAAC,OAAO,EAAE,OAAO,aAC7E,KAAC,SAAS,IAAC,IAAI,EAAE,EAAE,GAAI,EACtB,UAAU,IACJ,GACF,CACV,CAAC,CAAC,CAAC,IAAI,IACD,CACV,CAAA;AACH,CAAC"}
|
package/dist/chat/Header.cjs
CHANGED
|
@@ -18,8 +18,8 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
18
18
|
const gui_1 = require("@hanzo/gui");
|
|
19
19
|
const lucide_icons_2_1 = require("@hanzogui/lucide-icons-2");
|
|
20
20
|
const slot_1 = require("../backends/gui/slot.cjs");
|
|
21
|
-
function Header({ title, onOpenMenu, children }) {
|
|
22
|
-
return ((0, jsx_runtime_1.jsxs)(gui_1.XStack, { ...(0, slot_1.slot)('chat-header'), width: "100%", height: 48, shrink: 0, items: "center", gap: "$2", px: "$3", borderBottomWidth: 1, borderColor: "$borderColor", bg: "$background", children: [(0, jsx_runtime_1.jsxs)(gui_1.XStack, { items: "center", gap: "$1", shrink: 1, children: [(0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$2", fontWeight: "500", numberOfLines: 1, children: title }), onOpenMenu ? ((0, jsx_runtime_1.jsx)(HeaderButton, { label: "Conversation options", onPress: onOpenMenu, children: (0, jsx_runtime_1.jsx)(lucide_icons_2_1.Ellipsis, { size: 16 }) })) : null] }), (0, jsx_runtime_1.jsx)(gui_1.XStack, { flex: 1 }), children] }));
|
|
21
|
+
function Header({ title, onOpenMenu, children, leading, ...props }) {
|
|
22
|
+
return ((0, jsx_runtime_1.jsxs)(gui_1.XStack, { ...(0, slot_1.slot)('chat-header'), width: "100%", height: 48, shrink: 0, items: "center", gap: "$2", px: "$3", borderBottomWidth: 1, borderColor: "$borderColor", bg: "$background", ...props, children: [leading, (0, jsx_runtime_1.jsxs)(gui_1.XStack, { items: "center", gap: "$1", shrink: 1, children: [(0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$2", fontWeight: "500", numberOfLines: 1, children: title }), onOpenMenu ? ((0, jsx_runtime_1.jsx)(HeaderButton, { label: "Conversation options", onPress: onOpenMenu, children: (0, jsx_runtime_1.jsx)(lucide_icons_2_1.Ellipsis, { size: 16 }) })) : null] }), (0, jsx_runtime_1.jsx)(gui_1.XStack, { flex: 1 }), children] }));
|
|
23
23
|
}
|
|
24
24
|
function HeaderButton({ label, onPress, children }) {
|
|
25
25
|
return ((0, jsx_runtime_1.jsx)(gui_1.XStack, { width: 32, height: 32, items: "center", justify: "center", rounded: "$3", cursor: "pointer", opacity: 0.7, onPress: onPress, role: "button", tabIndex: 0, "aria-label": label, ...(0, slot_1.tip)(label), hoverStyle: { bg: '$color4', opacity: 1 }, pressStyle: { bg: '$color5' }, children: children }));
|
package/dist/chat/Header.d.ts
CHANGED
|
@@ -1,12 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Header — the conversation title bar.
|
|
3
|
+
*
|
|
4
|
+
* Title on the left, `children` as the action slot on the right. The actions are
|
|
5
|
+
* a slot rather than a fixed set because what belongs there is per-surface:
|
|
6
|
+
* hanzo.chat shares and opens a details rail, the console shows the owning
|
|
7
|
+
* project, hanzo.app shows neither.
|
|
8
|
+
*/
|
|
9
|
+
import { XStack } from '@hanzo/gui';
|
|
10
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
11
|
+
export interface HeaderProps extends Omit<ComponentProps<typeof XStack>, 'children'> {
|
|
3
12
|
title: string;
|
|
4
13
|
/** Overflow menu next to the title. Omit to hide it. */
|
|
5
14
|
onOpenMenu?: () => void;
|
|
6
15
|
/** Action slot, rendered at the end of the row. */
|
|
7
16
|
children?: ReactNode;
|
|
17
|
+
/**
|
|
18
|
+
* Slot BEFORE the title — a rail toggle, a back arrow.
|
|
19
|
+
*
|
|
20
|
+
* hanzo.app `/chat` leads with a sidebar toggle and kept its own header
|
|
21
|
+
* rather than adopt this one, because the row began at the title and there
|
|
22
|
+
* was nowhere to put it.
|
|
23
|
+
*/
|
|
24
|
+
leading?: ReactNode;
|
|
8
25
|
}
|
|
9
|
-
export declare function Header({ title, onOpenMenu, children }: HeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
26
|
+
export declare function Header({ title, onOpenMenu, children, leading, ...props }: HeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
10
27
|
export interface HeaderButtonProps {
|
|
11
28
|
/** Required — the accessible name for an icon-only control. */
|
|
12
29
|
label: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Header.d.ts","sourceRoot":"","sources":["../../src/chat/Header.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Header.d.ts","sourceRoot":"","sources":["../../src/chat/Header.tsx"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,OAAO,EAAe,MAAM,EAAU,MAAM,YAAY,CAAA;AAExD,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItD,MAAM,WAAW,WAAY,SAAQ,IAAI,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,EAAE,UAAU,CAAC;IAClF,KAAK,EAAE,MAAM,CAAA;IACb,wDAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;IACvB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,SAAS,CAAA;CACpB;AAED,wBAAgB,MAAM,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,EAAE,WAAW,2CAmCrF;AAED,MAAM,WAAW,iBAAiB;IAChC,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAA;CACrB;AAED,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,iBAAiB,2CAqB3E;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,EAAE,KAAe,EAAE,OAAO,EAAE,EAAE,gBAAgB,2CAuBzE;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB;AAED,wBAAgB,WAAW,CAAC,EAAE,KAA8B,EAAE,OAAO,EAAE,EAAE,gBAAgB,2CAMxF;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;;;;GAMG;AACH,wBAAgB,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAW,EAAE,EAAE,UAAU,2CAe1D"}
|
package/dist/chat/Header.js
CHANGED
|
@@ -11,8 +11,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
11
11
|
import { SizableText, XStack, YStack } from '@hanzo/gui';
|
|
12
12
|
import { Ellipsis, PanelRight, Share2 } from '@hanzogui/lucide-icons-2';
|
|
13
13
|
import { slot, tip } from '../backends/gui/slot.js';
|
|
14
|
-
export function Header({ title, onOpenMenu, children }) {
|
|
15
|
-
return (_jsxs(XStack, { ...slot('chat-header'), width: "100%", height: 48, shrink: 0, items: "center", gap: "$2", px: "$3", borderBottomWidth: 1, borderColor: "$borderColor", bg: "$background", children: [_jsxs(XStack, { items: "center", gap: "$1", shrink: 1, children: [_jsx(SizableText, { size: "$2", fontWeight: "500", numberOfLines: 1, children: title }), onOpenMenu ? (_jsx(HeaderButton, { label: "Conversation options", onPress: onOpenMenu, children: _jsx(Ellipsis, { size: 16 }) })) : null] }), _jsx(XStack, { flex: 1 }), children] }));
|
|
14
|
+
export function Header({ title, onOpenMenu, children, leading, ...props }) {
|
|
15
|
+
return (_jsxs(XStack, { ...slot('chat-header'), width: "100%", height: 48, shrink: 0, items: "center", gap: "$2", px: "$3", borderBottomWidth: 1, borderColor: "$borderColor", bg: "$background", ...props, children: [leading, _jsxs(XStack, { items: "center", gap: "$1", shrink: 1, children: [_jsx(SizableText, { size: "$2", fontWeight: "500", numberOfLines: 1, children: title }), onOpenMenu ? (_jsx(HeaderButton, { label: "Conversation options", onPress: onOpenMenu, children: _jsx(Ellipsis, { size: 16 }) })) : null] }), _jsx(XStack, { flex: 1 }), children] }));
|
|
16
16
|
}
|
|
17
17
|
export function HeaderButton({ label, onPress, children }) {
|
|
18
18
|
return (_jsx(XStack, { width: 32, height: 32, items: "center", justify: "center", rounded: "$3", cursor: "pointer", opacity: 0.7, onPress: onPress, role: "button", tabIndex: 0, "aria-label": label, ...tip(label), hoverStyle: { bg: '$color4', opacity: 1 }, pressStyle: { bg: '$color5' }, children: children }));
|
package/dist/chat/Header.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Header.js","sourceRoot":"","sources":["../../src/chat/Header.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;;GAOG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACxD,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAA;AAGvE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"Header.js","sourceRoot":"","sources":["../../src/chat/Header.tsx"],"names":[],"mappings":"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"}
|
package/dist/chat/Message.cjs
CHANGED
|
@@ -43,11 +43,17 @@ const slot_1 = require("../backends/gui/slot.cjs");
|
|
|
43
43
|
function Caret() {
|
|
44
44
|
return (0, jsx_runtime_1.jsx)(gui_1.YStack, { ...(0, slot_1.slot)('caret'), width: 2, height: 15, rounded: 1, bg: "$color12", "aria-hidden": true });
|
|
45
45
|
}
|
|
46
|
-
function Message({ role, children, actions, busy = false, icon }) {
|
|
46
|
+
function Message({ role, children, actions, busy = false, icon, body, ...props }) {
|
|
47
47
|
if (role === 'system')
|
|
48
|
-
return ((0, jsx_runtime_1.jsx)(gui_1.XStack, { ...(0, slot_1.slot)('message'), "data-role": "system", width: "100%", justify: "center", py: "$2", children: (0, jsx_runtime_1.jsx)(gui_1.Text, { fontSize: "$1", color: "$color10", text: "center", children: children }) }));
|
|
48
|
+
return ((0, jsx_runtime_1.jsx)(gui_1.XStack, { ...(0, slot_1.slot)('message'), "data-role": "system", width: "100%", justify: "center", py: "$2", ...props, children: (0, jsx_runtime_1.jsx)(gui_1.Text, { fontSize: "$1", color: "$color10", text: "center", children: children }) }));
|
|
49
49
|
const mine = role === 'user';
|
|
50
|
-
return ((0, jsx_runtime_1.jsxs)(gui_1.XStack, { ...(0, slot_1.slot)('message'), "data-role": role, width: "100%", justify: mine ? 'flex-end' : 'flex-start', gap: "$2",
|
|
50
|
+
return ((0, jsx_runtime_1.jsxs)(gui_1.XStack, { ...(0, slot_1.slot)('message'), "data-role": role, width: "100%", justify: mine ? 'flex-end' : 'flex-start', gap: "$2",
|
|
51
|
+
// The row is a hover group, so an action strip can be revealed with
|
|
52
|
+
// `$group-hover` instead of by a wrapper each surface adds itself. Both
|
|
53
|
+
// hanzo/chat and hanzo.app reveal theirs on hover and both had to supply
|
|
54
|
+
// the group. Unnamed on purpose: gui types `group` as a BOOLEAN here, so
|
|
55
|
+
// `group="turn"` type-errors rather than registering a named group.
|
|
56
|
+
group: true, ...props, children: [icon && !mine ? (0, jsx_runtime_1.jsx)(gui_1.YStack, { pt: "$1", children: icon }) : null, (0, jsx_runtime_1.jsxs)(gui_1.YStack, { ...(0, slot_1.slot)('message-body'), "data-bubble": mine ? 'true' : undefined, gap: "$2",
|
|
51
57
|
// 85%, because that is the number three independent implementations
|
|
52
58
|
// reached: hanzo/chat's `USER_TURN` (`common/turn.ts:17`,
|
|
53
59
|
// `max-w-[85%]`), hanzo.app `/chat` (`app/chat/page.tsx:521`,
|
|
@@ -59,5 +65,5 @@ function Message({ role, children, actions, busy = false, icon }) {
|
|
|
59
65
|
rounded: '$5',
|
|
60
66
|
px: '$3',
|
|
61
67
|
py: '$2',
|
|
62
|
-
}), children: [(0, ink_1.ink)(children), busy ? (0, jsx_runtime_1.jsx)(Caret, {}) : null, actions ? (0, jsx_runtime_1.jsx)(gui_1.XStack, { gap: "$1", items: "center", children: actions }) : null] })] }));
|
|
68
|
+
}), ...body, children: [(0, ink_1.ink)(children), busy ? (0, jsx_runtime_1.jsx)(Caret, {}) : null, actions ? (0, jsx_runtime_1.jsx)(gui_1.XStack, { gap: "$1", items: "center", children: actions }) : null] })] }));
|
|
63
69
|
}
|
package/dist/chat/Message.d.ts
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Message — one turn in a thread.
|
|
3
|
+
*
|
|
4
|
+
* Role drives presentation and nothing else: a user turn is a contained bubble
|
|
5
|
+
* that shrinks to its content, an assistant turn is full-bleed prose, a system
|
|
6
|
+
* turn is a muted aside. Content is `children`, so the surface keeps its own
|
|
7
|
+
* markdown pipeline — the surfaces disagree on remark plugins and none of that
|
|
8
|
+
* belongs in a presentational package.
|
|
9
|
+
*
|
|
10
|
+
* That arrangement is not this package's taste; it is what all six turn
|
|
11
|
+
* renderers across the estate independently arrived at. hanzo/chat states it
|
|
12
|
+
* outright in `client/src/components/Chat/Messages/ui/MessageRender.tsx:131`:
|
|
13
|
+
* "the user's turn is a glass bubble on the right, the reply plain and full
|
|
14
|
+
* width — the contrast is what says who is speaking." No avatar, no sender
|
|
15
|
+
* name, no timestamp — which is why `icon` is opt-in and there is no `name`
|
|
16
|
+
* prop. Only the read-only share view renders a name, and only one surface
|
|
17
|
+
* renders a timestamp.
|
|
18
|
+
*/
|
|
19
|
+
import { XStack } from '@hanzo/gui';
|
|
20
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
2
21
|
export type Role = 'user' | 'assistant' | 'system';
|
|
22
|
+
/**
|
|
23
|
+
* What a gui stack accepts — id, className, style, the `$` style props.
|
|
24
|
+
*
|
|
25
|
+
* `role` is dropped because this component already has one and means something
|
|
26
|
+
* else by it: the ARIA role of the row is not the speaker of the turn. The row
|
|
27
|
+
* needs no ARIA role, and `aria-label` is still reachable for the name.
|
|
28
|
+
*/
|
|
29
|
+
type Stack = Omit<ComponentProps<typeof XStack>, 'children' | 'role'>;
|
|
3
30
|
/**
|
|
4
31
|
* The mark that says a turn is still arriving.
|
|
5
32
|
*
|
|
@@ -16,7 +43,7 @@ export type Role = 'user' | 'assistant' | 'system';
|
|
|
16
43
|
* noise on every token.
|
|
17
44
|
*/
|
|
18
45
|
export declare function Caret(): import("react/jsx-runtime").JSX.Element;
|
|
19
|
-
export interface MessageProps {
|
|
46
|
+
export interface MessageProps extends Stack {
|
|
20
47
|
role: Role;
|
|
21
48
|
children?: ReactNode;
|
|
22
49
|
/** Row rendered under the turn — copy, retry, feedback. */
|
|
@@ -25,6 +52,18 @@ export interface MessageProps {
|
|
|
25
52
|
busy?: boolean;
|
|
26
53
|
/** Leading affordance for an assistant turn: avatar or model mark. */
|
|
27
54
|
icon?: ReactNode;
|
|
55
|
+
/**
|
|
56
|
+
* The bubble's own props — the inner box, not the row.
|
|
57
|
+
*
|
|
58
|
+
* The same reason `DialogContent` grew `overlay`: this component owns the
|
|
59
|
+
* body so a caller never has to assemble one, but owning is not hiding, and
|
|
60
|
+
* with nothing through, the fill, the corner and the width cap were
|
|
61
|
+
* unreachable from outside the package. hanzo/chat's turn is `glass hz-turn`
|
|
62
|
+
* with a `color-mix` fill it applies fleet-wide (`style.css:389`); it cannot
|
|
63
|
+
* adopt a bubble welded to `$color3`. Absent, nothing changes.
|
|
64
|
+
*/
|
|
65
|
+
body?: Stack;
|
|
28
66
|
}
|
|
29
|
-
export declare function Message({ role, children, actions, busy, icon }: MessageProps): import("react/jsx-runtime").JSX.Element;
|
|
67
|
+
export declare function Message({ role, children, actions, busy, icon, body, ...props }: MessageProps): import("react/jsx-runtime").JSX.Element;
|
|
68
|
+
export {};
|
|
30
69
|
//# sourceMappingURL=Message.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Message.d.ts","sourceRoot":"","sources":["../../src/chat/Message.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Message.d.ts","sourceRoot":"","sources":["../../src/chat/Message.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAQ,MAAM,EAAU,MAAM,YAAY,CAAA;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAKtD,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAA;AAElD;;;;;;GAMG;AACH,KAAK,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC,CAAA;AAErE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,KAAK,4CAEpB;AAED,MAAM,WAAW,YAAa,SAAQ,KAAK;IACzC,IAAI,EAAE,IAAI,CAAA;IACV,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB,8DAA8D;IAC9D,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,sEAAsE;IACtE,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;;;;;;;;;OASG;IACH,IAAI,CAAC,EAAE,KAAK,CAAA;CACb;AAED,wBAAgB,OAAO,CAAC,EACtB,IAAI,EACJ,QAAQ,EACR,OAAO,EACP,IAAY,EACZ,IAAI,EACJ,IAAI,EACJ,GAAG,KAAK,EACT,EAAE,YAAY,2CA4Dd"}
|
package/dist/chat/Message.js
CHANGED
|
@@ -39,11 +39,17 @@ import { slot } from '../backends/gui/slot.js';
|
|
|
39
39
|
export function Caret() {
|
|
40
40
|
return _jsx(YStack, { ...slot('caret'), width: 2, height: 15, rounded: 1, bg: "$color12", "aria-hidden": true });
|
|
41
41
|
}
|
|
42
|
-
export function Message({ role, children, actions, busy = false, icon }) {
|
|
42
|
+
export function Message({ role, children, actions, busy = false, icon, body, ...props }) {
|
|
43
43
|
if (role === 'system')
|
|
44
|
-
return (_jsx(XStack, { ...slot('message'), "data-role": "system", width: "100%", justify: "center", py: "$2", children: _jsx(Text, { fontSize: "$1", color: "$color10", text: "center", children: children }) }));
|
|
44
|
+
return (_jsx(XStack, { ...slot('message'), "data-role": "system", width: "100%", justify: "center", py: "$2", ...props, children: _jsx(Text, { fontSize: "$1", color: "$color10", text: "center", children: children }) }));
|
|
45
45
|
const mine = role === 'user';
|
|
46
|
-
return (_jsxs(XStack, { ...slot('message'), "data-role": role, width: "100%", justify: mine ? 'flex-end' : 'flex-start', gap: "$2",
|
|
46
|
+
return (_jsxs(XStack, { ...slot('message'), "data-role": role, width: "100%", justify: mine ? 'flex-end' : 'flex-start', gap: "$2",
|
|
47
|
+
// The row is a hover group, so an action strip can be revealed with
|
|
48
|
+
// `$group-hover` instead of by a wrapper each surface adds itself. Both
|
|
49
|
+
// hanzo/chat and hanzo.app reveal theirs on hover and both had to supply
|
|
50
|
+
// the group. Unnamed on purpose: gui types `group` as a BOOLEAN here, so
|
|
51
|
+
// `group="turn"` type-errors rather than registering a named group.
|
|
52
|
+
group: true, ...props, children: [icon && !mine ? _jsx(YStack, { pt: "$1", children: icon }) : null, _jsxs(YStack, { ...slot('message-body'), "data-bubble": mine ? 'true' : undefined, gap: "$2",
|
|
47
53
|
// 85%, because that is the number three independent implementations
|
|
48
54
|
// reached: hanzo/chat's `USER_TURN` (`common/turn.ts:17`,
|
|
49
55
|
// `max-w-[85%]`), hanzo.app `/chat` (`app/chat/page.tsx:521`,
|
|
@@ -55,6 +61,6 @@ export function Message({ role, children, actions, busy = false, icon }) {
|
|
|
55
61
|
rounded: '$5',
|
|
56
62
|
px: '$3',
|
|
57
63
|
py: '$2',
|
|
58
|
-
}), children: [ink(children), busy ? _jsx(Caret, {}) : null, actions ? _jsx(XStack, { gap: "$1", items: "center", children: actions }) : null] })] }));
|
|
64
|
+
}), ...body, children: [ink(children), busy ? _jsx(Caret, {}) : null, actions ? _jsx(XStack, { gap: "$1", items: "center", children: actions }) : null] })] }));
|
|
59
65
|
}
|
|
60
66
|
//# sourceMappingURL=Message.js.map
|