@intentface/ui 0.0.0-stage → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +147 -2
- package/dist/ask-user/ask-user.d.ts +104 -0
- package/dist/ask-user/ask-user.js +245 -0
- package/dist/ask-user/index.d.ts +3 -0
- package/dist/ask-user/index.js +3 -0
- package/dist/ask-user/index.parts.d.ts +1 -0
- package/dist/ask-user/index.parts.js +5 -0
- package/dist/attachments/attachments.d.ts +73 -0
- package/dist/attachments/attachments.js +121 -0
- package/dist/attachments/index.d.ts +3 -0
- package/dist/attachments/index.js +3 -0
- package/dist/attachments/index.parts.d.ts +1 -0
- package/dist/attachments/index.parts.js +5 -0
- package/dist/chip/chip.d.ts +45 -0
- package/dist/chip/chip.js +43 -0
- package/dist/chip/index.d.ts +2 -0
- package/dist/chip/index.js +2 -0
- package/dist/chip/index.parts.d.ts +1 -0
- package/dist/chip/index.parts.js +5 -0
- package/dist/chip-markdown.d.ts +25 -0
- package/dist/chip-markdown.js +54 -0
- package/dist/composer/actions.d.ts +35 -0
- package/dist/composer/actions.js +76 -0
- package/dist/composer/ask-user-machine.d.ts +52 -0
- package/dist/composer/ask-user-machine.js +164 -0
- package/dist/composer/attachments-machine.d.ts +34 -0
- package/dist/composer/attachments-machine.js +91 -0
- package/dist/composer/attachments.d.ts +16 -0
- package/dist/composer/attachments.js +32 -0
- package/dist/composer/command-list.d.ts +49 -0
- package/dist/composer/command-list.js +360 -0
- package/dist/composer/commands.d.ts +28 -0
- package/dist/composer/commands.js +56 -0
- package/dist/composer/container.d.ts +3 -0
- package/dist/composer/container.js +32 -0
- package/dist/composer/controller.d.ts +3 -0
- package/dist/composer/controller.js +6 -0
- package/dist/composer/editor-dom.d.ts +57 -0
- package/dist/composer/editor-dom.js +517 -0
- package/dist/composer/fuzzy.d.ts +4 -0
- package/dist/composer/fuzzy.js +49 -0
- package/dist/composer/index.d.ts +25 -0
- package/dist/composer/index.js +13 -0
- package/dist/composer/index.parts.d.ts +11 -0
- package/dist/composer/index.parts.js +15 -0
- package/dist/composer/internals.d.ts +30 -0
- package/dist/composer/internals.js +102 -0
- package/dist/composer/keyboard.d.ts +61 -0
- package/dist/composer/keyboard.js +75 -0
- package/dist/composer/panel.d.ts +28 -0
- package/dist/composer/panel.js +76 -0
- package/dist/composer/placeholder.d.ts +10 -0
- package/dist/composer/placeholder.js +8 -0
- package/dist/composer/popover.d.ts +12 -0
- package/dist/composer/popover.js +62 -0
- package/dist/composer/prefix-detection.d.ts +23 -0
- package/dist/composer/prefix-detection.js +67 -0
- package/dist/composer/root.d.ts +21 -0
- package/dist/composer/root.js +124 -0
- package/dist/composer/segments.d.ts +108 -0
- package/dist/composer/segments.js +366 -0
- package/dist/composer/store.d.ts +98 -0
- package/dist/composer/store.js +457 -0
- package/dist/composer/textarea.d.ts +39 -0
- package/dist/composer/textarea.js +64 -0
- package/dist/composer/trigger-tracker.d.ts +12 -0
- package/dist/composer/trigger-tracker.js +90 -0
- package/dist/composer/types.d.ts +127 -0
- package/dist/composer/types.js +4 -0
- package/dist/composer/use-composer-editor.d.ts +43 -0
- package/dist/composer/use-composer-editor.js +653 -0
- package/dist/generative/catalog.d.ts +177 -0
- package/dist/generative/catalog.js +20 -0
- package/dist/generative/index.d.ts +26 -0
- package/dist/generative/index.js +20 -0
- package/dist/generative/json-schema.d.ts +45 -0
- package/dist/generative/json-schema.js +216 -0
- package/dist/generative/markdown.d.ts +21 -0
- package/dist/generative/markdown.js +76 -0
- package/dist/generative/tree.d.ts +56 -0
- package/dist/generative/tree.js +365 -0
- package/dist/generative/use-tree.d.ts +12 -0
- package/dist/generative/use-tree.js +64 -0
- package/dist/internal/change-event-details.d.ts +12 -0
- package/dist/internal/change-event-details.js +16 -0
- package/dist/internal/collapsible.d.ts +22 -0
- package/dist/internal/collapsible.js +94 -0
- package/dist/internal/collection.d.ts +32 -0
- package/dist/internal/collection.js +72 -0
- package/dist/internal/iso-layout-effect.d.ts +2 -0
- package/dist/internal/iso-layout-effect.js +6 -0
- package/dist/internal/portal.d.ts +6 -0
- package/dist/internal/portal.js +18 -0
- package/dist/internal/primitive-props.d.ts +4 -0
- package/dist/internal/primitive-props.js +3 -0
- package/dist/internal/render/baseTypes.d.ts +18 -0
- package/dist/internal/render/baseTypes.js +4 -0
- package/dist/internal/render/empty.d.ts +3 -0
- package/dist/internal/render/empty.js +5 -0
- package/dist/internal/render/getReactElementRef.d.ts +5 -0
- package/dist/internal/render/getReactElementRef.js +15 -0
- package/dist/internal/render/getStateAttributesProps.d.ts +4 -0
- package/dist/internal/render/getStateAttributesProps.js +23 -0
- package/dist/internal/render/mergeObjects.d.ts +1 -0
- package/dist/internal/render/mergeObjects.js +14 -0
- package/dist/internal/render/mergeProps.d.ts +55 -0
- package/dist/internal/render/mergeProps.js +183 -0
- package/dist/internal/render/positioning.d.ts +33 -0
- package/dist/internal/render/positioning.js +112 -0
- package/dist/internal/render/reactVersion.d.ts +3 -0
- package/dist/internal/render/reactVersion.js +7 -0
- package/dist/internal/render/resolveClassName.d.ts +8 -0
- package/dist/internal/render/resolveClassName.js +12 -0
- package/dist/internal/render/resolveStyle.d.ts +8 -0
- package/dist/internal/render/resolveStyle.js +12 -0
- package/dist/internal/render/transition.d.ts +47 -0
- package/dist/internal/render/transition.js +259 -0
- package/dist/internal/render/types.d.ts +74 -0
- package/dist/internal/render/types.js +3 -0
- package/dist/internal/render/useMergedRefs.d.ts +21 -0
- package/dist/internal/render/useMergedRefs.js +102 -0
- package/dist/internal/render/useRefWithInit.d.ts +10 -0
- package/dist/internal/render/useRefWithInit.js +12 -0
- package/dist/internal/render/useRender.d.ts +71 -0
- package/dist/internal/render/useRender.js +12 -0
- package/dist/internal/render/useRenderElement.d.ts +62 -0
- package/dist/internal/render/useRenderElement.js +157 -0
- package/dist/internal/render/warn.d.ts +1 -0
- package/dist/internal/render/warn.js +15 -0
- package/dist/internal/safe-polygon.d.ts +21 -0
- package/dist/internal/safe-polygon.js +179 -0
- package/dist/internal/scroll-into-view-within.d.ts +1 -0
- package/dist/internal/scroll-into-view-within.js +26 -0
- package/dist/internal/standard-schema.d.ts +38 -0
- package/dist/internal/standard-schema.js +4 -0
- package/dist/internal/state-mappings.d.ts +8 -0
- package/dist/internal/state-mappings.js +17 -0
- package/dist/internal/use-controlled.d.ts +19 -0
- package/dist/internal/use-controlled.js +33 -0
- package/dist/message/index.d.ts +3 -0
- package/dist/message/index.js +3 -0
- package/dist/message/index.parts.d.ts +1 -0
- package/dist/message/index.parts.js +5 -0
- package/dist/message/message.d.ts +58 -0
- package/dist/message/message.js +93 -0
- package/dist/message-utils.d.ts +55 -0
- package/dist/message-utils.js +79 -0
- package/dist/nav/index.d.ts +4 -0
- package/dist/nav/index.js +5 -0
- package/dist/nav/index.parts.d.ts +3 -0
- package/dist/nav/index.parts.js +7 -0
- package/dist/nav/nav.d.ts +152 -0
- package/dist/nav/nav.js +660 -0
- package/dist/nav/store.d.ts +50 -0
- package/dist/nav/store.js +95 -0
- package/dist/reasoning/index.d.ts +3 -0
- package/dist/reasoning/index.js +3 -0
- package/dist/reasoning/index.parts.d.ts +1 -0
- package/dist/reasoning/index.parts.js +5 -0
- package/dist/reasoning/reasoning.d.ts +38 -0
- package/dist/reasoning/reasoning.js +67 -0
- package/dist/shell/index.d.ts +5 -0
- package/dist/shell/index.js +5 -0
- package/dist/shell/index.parts.d.ts +3 -0
- package/dist/shell/index.parts.js +7 -0
- package/dist/shell/shell.d.ts +108 -0
- package/dist/shell/shell.js +390 -0
- package/dist/shell/store.d.ts +112 -0
- package/dist/shell/store.js +134 -0
- package/dist/steps/index.d.ts +2 -0
- package/dist/steps/index.js +2 -0
- package/dist/steps/index.parts.d.ts +1 -0
- package/dist/steps/index.parts.js +5 -0
- package/dist/steps/steps.d.ts +90 -0
- package/dist/steps/steps.js +116 -0
- package/dist/tabs/anchored.d.ts +59 -0
- package/dist/tabs/anchored.js +109 -0
- package/dist/tabs/hover.d.ts +33 -0
- package/dist/tabs/hover.js +169 -0
- package/dist/tabs/index.d.ts +5 -0
- package/dist/tabs/index.js +4 -0
- package/dist/tabs/index.parts.d.ts +4 -0
- package/dist/tabs/index.parts.js +8 -0
- package/dist/tabs/store.d.ts +131 -0
- package/dist/tabs/store.js +248 -0
- package/dist/tabs/tabs.d.ts +217 -0
- package/dist/tabs/tabs.js +458 -0
- package/dist/thread/geometry.d.ts +23 -0
- package/dist/thread/geometry.js +48 -0
- package/dist/thread/index.d.ts +4 -0
- package/dist/thread/index.js +3 -0
- package/dist/thread/index.parts.d.ts +1 -0
- package/dist/thread/index.parts.js +5 -0
- package/dist/thread/stores.d.ts +21 -0
- package/dist/thread/stores.js +63 -0
- package/dist/thread/thread.d.ts +57 -0
- package/dist/thread/thread.js +663 -0
- package/dist/types.d.ts +58 -0
- package/dist/types.js +17 -0
- package/package.json +125 -4
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { type ChipSegment } from "../chip-markdown.js";
|
|
3
|
+
import type { PrimitiveProps } from "../internal/primitive-props.js";
|
|
4
|
+
export type MessageState = {
|
|
5
|
+
/** Opaque role string; the consumer owns the concrete set. Surfaced as data-role. */
|
|
6
|
+
role: string;
|
|
7
|
+
/** Present as data-error when true. */
|
|
8
|
+
error: boolean;
|
|
9
|
+
/** Present as data-last when true. */
|
|
10
|
+
last: boolean;
|
|
11
|
+
};
|
|
12
|
+
export type MessageRootProps = Omit<PrimitiveProps<"div", MessageState>, "role"> & {
|
|
13
|
+
role: string;
|
|
14
|
+
isLast?: boolean;
|
|
15
|
+
isError?: boolean;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* One turn's container. Reports the role and position as data attributes and
|
|
19
|
+
* renders no layout of its own, so the bubble, avatar and actions around it
|
|
20
|
+
* stay yours.
|
|
21
|
+
* Renders a `<div>` element.
|
|
22
|
+
*/
|
|
23
|
+
export declare const MessageRoot: ({ role, isLast, isError, className, render, style, ...elementProps }: MessageRootProps) => import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
24
|
+
export type MessageTurnProps = PrimitiveProps<"div">;
|
|
25
|
+
/**
|
|
26
|
+
* Groups consecutive messages from one role into a single visual turn.
|
|
27
|
+
* Renders a `<div>` element.
|
|
28
|
+
*/
|
|
29
|
+
export declare const MessageTurn: ({ className, render, style, ...elementProps }: MessageTurnProps) => import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
30
|
+
export type MessageChipSegment = Extract<ChipSegment, {
|
|
31
|
+
type: "chip";
|
|
32
|
+
}>;
|
|
33
|
+
export type MessageTextProps = Omit<PrimitiveProps<"span">, "children"> & {
|
|
34
|
+
children: string;
|
|
35
|
+
renderText?: (text: string, index: number) => ReactNode;
|
|
36
|
+
renderChip?: (chip: MessageChipSegment, index: number) => ReactNode;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Message text with inline chips reconstructed from the wire format, so a
|
|
40
|
+
* stored message rebuilds its own chips with no sidecar metadata.
|
|
41
|
+
* Renders a `<span>` element.
|
|
42
|
+
*/
|
|
43
|
+
export declare const MessageText: ({ children, className, render, style, renderText, renderChip, ...elementProps }: MessageTextProps) => import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
44
|
+
export type MessageSelection = {
|
|
45
|
+
text: string;
|
|
46
|
+
range: Range;
|
|
47
|
+
};
|
|
48
|
+
export declare const readMessageSelection: (scope: HTMLElement) => MessageSelection | null;
|
|
49
|
+
export declare const useMessageSelection: (scope: HTMLElement | null) => MessageSelection | null;
|
|
50
|
+
/**
|
|
51
|
+
* Resolves the owning message's content element from an invisible anchor node
|
|
52
|
+
* rendered anywhere inside the message. Scoping to message-content keeps the
|
|
53
|
+
* toolbar off markers, sources, and actions elsewhere in the message.
|
|
54
|
+
*/
|
|
55
|
+
export declare const useMessageSelectionScope: () => {
|
|
56
|
+
anchorRef: (node: HTMLElement | null) => void;
|
|
57
|
+
contentElement: HTMLElement | null;
|
|
58
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
// Headless message parts. Owns the role/error/last data-attribute contract,
|
|
4
|
+
// chip-segment text parsing (with render inversion for markdown/styled chips),
|
|
5
|
+
// timestamp formatting, and the text-selection subsystem. Entrance animation,
|
|
6
|
+
// popovers, tooltips, icons, and thumbnails belong to the styled layer.
|
|
7
|
+
//
|
|
8
|
+
// Every part supports the Base UI render prop: pass a ReactElement to swap the
|
|
9
|
+
// underlying element (props are merged onto it), or a function `(props, state)`
|
|
10
|
+
// for full control. The root's data attributes (data-role, data-error,
|
|
11
|
+
// data-last) are generated from its state object, so the render callback and
|
|
12
|
+
// CSS consumers see the same state.
|
|
13
|
+
import { Fragment, useCallback, useEffect, useMemo, useState } from "react";
|
|
14
|
+
import { parseChipSegments } from "../chip-markdown.js";
|
|
15
|
+
import { useRenderElement } from "../internal/render/useRenderElement.js";
|
|
16
|
+
/**
|
|
17
|
+
* One turn's container. Reports the role and position as data attributes and
|
|
18
|
+
* renders no layout of its own, so the bubble, avatar and actions around it
|
|
19
|
+
* stay yours.
|
|
20
|
+
* Renders a `<div>` element.
|
|
21
|
+
*/
|
|
22
|
+
export const MessageRoot = ({ role, isLast = false, isError = false, className, render, style, ...elementProps }) => {
|
|
23
|
+
const state = useMemo(() => ({ role, error: isError, last: isLast }), [role, isError, isLast]);
|
|
24
|
+
return useRenderElement("div", { className, render, style }, { state, props: [{ "data-message": "" }, elementProps] });
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Groups consecutive messages from one role into a single visual turn.
|
|
28
|
+
* Renders a `<div>` element.
|
|
29
|
+
*/
|
|
30
|
+
export const MessageTurn = ({ className, render, style, ...elementProps }) => useRenderElement("div", { className, render, style }, { props: [{ "data-message-turn": "" }, elementProps] });
|
|
31
|
+
/**
|
|
32
|
+
* Message text with inline chips reconstructed from the wire format, so a
|
|
33
|
+
* stored message rebuilds its own chips with no sidecar metadata.
|
|
34
|
+
* Renders a `<span>` element.
|
|
35
|
+
*/
|
|
36
|
+
export const MessageText = ({ children, className, render, style, renderText, renderChip, ...elementProps }) => {
|
|
37
|
+
const segments = parseChipSegments(children);
|
|
38
|
+
const segmentNodes = segments.map((segment, index) => segment.type === "text" ? (_jsx(Fragment, { children: renderText ? renderText(segment.text, index) : segment.text }, index)) : (_jsx(Fragment, { children: renderChip ? (renderChip(segment, index)) : (_jsx("span", { "data-message-chip": "", children: segment.label })) }, index)));
|
|
39
|
+
return useRenderElement("span", { className, render, style }, { props: [{ "data-message-text": "", children: segmentNodes }, elementProps] });
|
|
40
|
+
};
|
|
41
|
+
export const readMessageSelection = (scope) => {
|
|
42
|
+
const selection = window.getSelection();
|
|
43
|
+
if (!selection || selection.isCollapsed || selection.rangeCount === 0)
|
|
44
|
+
return null;
|
|
45
|
+
const text = selection.toString();
|
|
46
|
+
if (text.trim().length === 0)
|
|
47
|
+
return null;
|
|
48
|
+
// Both endpoints must sit inside this message — a cross-message selection
|
|
49
|
+
// has its common ancestor outside the scope and resolves to null.
|
|
50
|
+
const range = selection.getRangeAt(0);
|
|
51
|
+
if (!scope.contains(range.commonAncestorContainer))
|
|
52
|
+
return null;
|
|
53
|
+
// Clone so later mutations of the live selection don't move our anchor.
|
|
54
|
+
return { text, range: range.cloneRange() };
|
|
55
|
+
};
|
|
56
|
+
// Subscribe to the document selection, scoped to `scope`. Samples when the
|
|
57
|
+
// gesture settles (mouseup / keyup) instead of on every selectionchange drag
|
|
58
|
+
// tick; selectionchange only clears the value once the selection collapses.
|
|
59
|
+
export const useMessageSelection = (scope) => {
|
|
60
|
+
const [selection, setSelection] = useState(null);
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (!scope)
|
|
63
|
+
return;
|
|
64
|
+
const readSelection = () => setSelection(readMessageSelection(scope));
|
|
65
|
+
const hideWhenCollapsed = () => {
|
|
66
|
+
const current = window.getSelection();
|
|
67
|
+
if (!current || current.isCollapsed)
|
|
68
|
+
setSelection(null);
|
|
69
|
+
};
|
|
70
|
+
document.addEventListener("mouseup", readSelection);
|
|
71
|
+
document.addEventListener("keyup", readSelection);
|
|
72
|
+
document.addEventListener("selectionchange", hideWhenCollapsed);
|
|
73
|
+
return () => {
|
|
74
|
+
document.removeEventListener("mouseup", readSelection);
|
|
75
|
+
document.removeEventListener("keyup", readSelection);
|
|
76
|
+
document.removeEventListener("selectionchange", hideWhenCollapsed);
|
|
77
|
+
};
|
|
78
|
+
}, [scope]);
|
|
79
|
+
return selection;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Resolves the owning message's content element from an invisible anchor node
|
|
83
|
+
* rendered anywhere inside the message. Scoping to message-content keeps the
|
|
84
|
+
* toolbar off markers, sources, and actions elsewhere in the message.
|
|
85
|
+
*/
|
|
86
|
+
export const useMessageSelectionScope = () => {
|
|
87
|
+
const [contentElement, setContentElement] = useState(null);
|
|
88
|
+
const anchorRef = useCallback((node) => {
|
|
89
|
+
const messageRoot = node?.closest("[data-message]");
|
|
90
|
+
setContentElement(messageRoot?.querySelector("[data-message-content]") ?? null);
|
|
91
|
+
}, []);
|
|
92
|
+
return { anchorRef, contentElement };
|
|
93
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type ChatMessage, type FilePart, type ReasoningPart, type TextPart, type ToolPart, type UnknownPart } from "./types.js";
|
|
2
|
+
/** Classifies message parts into coarse groups for chronological rendering. */
|
|
3
|
+
export type SegmentType = "reasoning" | "tool" | "text" | "file";
|
|
4
|
+
/**
|
|
5
|
+
* A contiguous run of same-typed message parts. Used by message renderers to
|
|
6
|
+
* group reasoning blocks, tool calls, text chunks, etc.
|
|
7
|
+
*/
|
|
8
|
+
export type MessageSegment = {
|
|
9
|
+
type: "reasoning";
|
|
10
|
+
parts: ReasoningPart[];
|
|
11
|
+
} | {
|
|
12
|
+
type: "tool";
|
|
13
|
+
parts: ToolPart[];
|
|
14
|
+
} | {
|
|
15
|
+
type: "text";
|
|
16
|
+
parts: TextPart[];
|
|
17
|
+
} | {
|
|
18
|
+
type: "file";
|
|
19
|
+
parts: FilePart[];
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Maps a single message part to its segment type.
|
|
23
|
+
* Returns `null` for parts that are not rendered chronologically.
|
|
24
|
+
*/
|
|
25
|
+
export declare const partSegmentType: (part: UnknownPart) => SegmentType | null;
|
|
26
|
+
/**
|
|
27
|
+
* Groups an array of message parts into contiguous segments of the same type.
|
|
28
|
+
* Adjacent parts with the same type are merged into a single segment. This
|
|
29
|
+
* preserves chronological order for interleaved rendering (e.g. reasoning
|
|
30
|
+
* interspersed with tool calls).
|
|
31
|
+
*/
|
|
32
|
+
export declare const getSegmentedParts: (parts: readonly UnknownPart[]) => MessageSegment[];
|
|
33
|
+
/** A conversational turn: a user message plus its trailing assistant/tool replies. */
|
|
34
|
+
export type Turn<Message extends ChatMessage<unknown, UnknownPart> = ChatMessage> = {
|
|
35
|
+
key: string;
|
|
36
|
+
messages: Message[];
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Groups messages into turns. A new turn starts at every user message;
|
|
40
|
+
* non-user messages attach to the current turn. A conversation that opens with
|
|
41
|
+
* a non-user message still gets a leading turn so nothing is dropped. The turn
|
|
42
|
+
* key is the first message's id — stable while the trailing assistant message
|
|
43
|
+
* streams, so React keys and entrance animations stay put.
|
|
44
|
+
*/
|
|
45
|
+
export declare const groupTurns: <Message extends ChatMessage<unknown, UnknownPart>>(messages: readonly Message[], turnStartRole?: string) => Turn<Message>[];
|
|
46
|
+
/** Aggregated text content from all text segments in a message. */
|
|
47
|
+
export type TextInfo = {
|
|
48
|
+
parts: TextPart[];
|
|
49
|
+
/** Concatenated text content of all text parts. */
|
|
50
|
+
text: string;
|
|
51
|
+
};
|
|
52
|
+
/** Extracts all text parts from a message and concatenates their content. */
|
|
53
|
+
export declare const getTextInfo: (segments: readonly MessageSegment[]) => TextInfo;
|
|
54
|
+
/** Extracts all file attachment parts from segments. */
|
|
55
|
+
export declare const getFileParts: (segments: readonly MessageSegment[]) => FilePart[];
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Derivation helpers over the structural message contract in types.ts.
|
|
2
|
+
// Pure functions — no React, no styling. Renderers and panel-state hooks share
|
|
3
|
+
// these so they stay decoupled from concrete part shapes.
|
|
4
|
+
import { isFilePart, isReasoningPart, isTextPart, isToolPart, } from "./types.js";
|
|
5
|
+
/**
|
|
6
|
+
* Maps a single message part to its segment type.
|
|
7
|
+
* Returns `null` for parts that are not rendered chronologically.
|
|
8
|
+
*/
|
|
9
|
+
export const partSegmentType = (part) => {
|
|
10
|
+
if (isReasoningPart(part))
|
|
11
|
+
return "reasoning";
|
|
12
|
+
if (isTextPart(part))
|
|
13
|
+
return "text";
|
|
14
|
+
if (isFilePart(part))
|
|
15
|
+
return "file";
|
|
16
|
+
if (isToolPart(part))
|
|
17
|
+
return "tool";
|
|
18
|
+
return null;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Groups an array of message parts into contiguous segments of the same type.
|
|
22
|
+
* Adjacent parts with the same type are merged into a single segment. This
|
|
23
|
+
* preserves chronological order for interleaved rendering (e.g. reasoning
|
|
24
|
+
* interspersed with tool calls).
|
|
25
|
+
*/
|
|
26
|
+
export const getSegmentedParts = (parts) => {
|
|
27
|
+
const segments = [];
|
|
28
|
+
for (const part of parts) {
|
|
29
|
+
const segType = partSegmentType(part);
|
|
30
|
+
if (!segType)
|
|
31
|
+
continue;
|
|
32
|
+
const last = segments.at(-1);
|
|
33
|
+
if (last && last.type === segType) {
|
|
34
|
+
last.parts.push(part);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
segments.push({ type: segType, parts: [part] });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return segments;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Groups messages into turns. A new turn starts at every user message;
|
|
44
|
+
* non-user messages attach to the current turn. A conversation that opens with
|
|
45
|
+
* a non-user message still gets a leading turn so nothing is dropped. The turn
|
|
46
|
+
* key is the first message's id — stable while the trailing assistant message
|
|
47
|
+
* streams, so React keys and entrance animations stay put.
|
|
48
|
+
*/
|
|
49
|
+
export const groupTurns = (messages,
|
|
50
|
+
// The role that starts a new turn — opaque, so consumers with a different
|
|
51
|
+
// role set can group correctly.
|
|
52
|
+
turnStartRole = "user") => {
|
|
53
|
+
const turns = [];
|
|
54
|
+
for (const message of messages) {
|
|
55
|
+
const currentTurn = turns.at(-1);
|
|
56
|
+
if (message.role === turnStartRole || !currentTurn) {
|
|
57
|
+
turns.push({ key: message.id, messages: [message] });
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
currentTurn.messages.push(message);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return turns;
|
|
64
|
+
};
|
|
65
|
+
/** Extracts all text parts from a message and concatenates their content. */
|
|
66
|
+
export const getTextInfo = (segments) => {
|
|
67
|
+
const parts = segments
|
|
68
|
+
.filter((s) => s.type === "text")
|
|
69
|
+
.flatMap((s) => s.parts);
|
|
70
|
+
const text = parts.map((p) => p.text).join("");
|
|
71
|
+
return { parts, text };
|
|
72
|
+
};
|
|
73
|
+
/** Extracts all file attachment parts from segments. */
|
|
74
|
+
export const getFileParts = (segments) => segments
|
|
75
|
+
.filter((s) => s.type === "file")
|
|
76
|
+
.flatMap((s) => s.parts);
|
|
77
|
+
// Chain/reasoning/source extraction (and ask-user extraction) is the consuming
|
|
78
|
+
// app's concern — grouping conventions, header formats, and dedup rules are
|
|
79
|
+
// product policy. This package ships only the generic segmentation above.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export * as Nav from "./index.parts.js";
|
|
2
|
+
export type { NavActionProps, NavGroupProps, NavGroupState, NavGuide, NavIconProps, NavItemProps, NavItemState, NavLabelProps, NavListProps, NavListState, NavPartState, NavRootProps, NavToggleProps, NavToggleState, NavTriggerProps, NavTriggerState, } from "./nav.js";
|
|
3
|
+
export type { NavState, NavStore } from "./store.js";
|
|
4
|
+
export { useNav, useNavStore } from "./store.js";
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { NavAction as Action, NavGroup as Group, NavIcon as Icon, NavItem as Item, NavLabel as Label, NavList as List, NavRoot as Root, NavToggle as Toggle, NavTrigger as Trigger, } from "./nav.js";
|
|
2
|
+
/** Create a standalone store handle: `<Nav.Root store={…}>` plus `useNavStore(store, selector)` for reading it from outside the tree. */
|
|
3
|
+
export { createNavStore as createStore } from "./store.js";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Part names for the `Nav` namespace. Deliberately carries no "use client"
|
|
2
|
+
// directive: this module and index.ts must stay server-resolvable so a React
|
|
3
|
+
// Server Component can reach Nav.Root and its siblings through them. Each part
|
|
4
|
+
// module carries the directive itself.
|
|
5
|
+
export { NavAction as Action, NavGroup as Group, NavIcon as Icon, NavItem as Item, NavLabel as Label, NavList as List, NavRoot as Root, NavToggle as Toggle, NavTrigger as Trigger, } from "./nav.js";
|
|
6
|
+
/** Create a standalone store handle: `<Nav.Root store={…}>` plus `useNavStore(store, selector)` for reading it from outside the tree. */
|
|
7
|
+
export { createNavStore as createStore } from "./store.js";
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { PrimitiveProps } from "../internal/primitive-props.js";
|
|
3
|
+
import { type TransitionStatus } from "../internal/render/transition.js";
|
|
4
|
+
import type { NavStore } from "./store.js";
|
|
5
|
+
/**
|
|
6
|
+
* What a list draws down its left edge, as a ladder rather than three flags.
|
|
7
|
+
*
|
|
8
|
+
* Each rung implies the one before it — a rail lives in the indent lane, an
|
|
9
|
+
* elbow needs a rail to turn off — so they were never independent, and
|
|
10
|
+
* expressing them as booleans meant guarding against combinations that mean
|
|
11
|
+
* nothing.
|
|
12
|
+
*/
|
|
13
|
+
export type NavGuide = "none" | "indent" | "rail" | "branches";
|
|
14
|
+
export type NavPartState = {
|
|
15
|
+
/** How deeply nested this part's list is. 0 is the top level. */
|
|
16
|
+
depth: number;
|
|
17
|
+
nested: boolean;
|
|
18
|
+
};
|
|
19
|
+
export type NavListState = NavPartState & {
|
|
20
|
+
guide: NavGuide;
|
|
21
|
+
/** Always true for a top-level list — only a group's list collapses. */
|
|
22
|
+
open: boolean;
|
|
23
|
+
transitionStatus: TransitionStatus;
|
|
24
|
+
};
|
|
25
|
+
export type NavItemState = NavPartState & {
|
|
26
|
+
active: boolean;
|
|
27
|
+
disabled: boolean;
|
|
28
|
+
};
|
|
29
|
+
export type NavGroupState = NavPartState & {
|
|
30
|
+
open: boolean;
|
|
31
|
+
};
|
|
32
|
+
export type NavTriggerState = NavGroupState & {
|
|
33
|
+
active: boolean;
|
|
34
|
+
disabled: boolean;
|
|
35
|
+
};
|
|
36
|
+
export type NavRootProps = PrimitiveProps<"div", NavPartState> & {
|
|
37
|
+
/** Groups open when nothing controls them. Read it from the request on the
|
|
38
|
+
* server, if you persist it, so the first paint is already right. Nothing
|
|
39
|
+
* here reads storage — `onExpandedChange` is the other half. */
|
|
40
|
+
defaultExpanded?: string[];
|
|
41
|
+
expanded?: string[];
|
|
42
|
+
onExpandedChange?: (expanded: string[]) => void;
|
|
43
|
+
/** An explicit `Nav.createStore()` handle. Must be stable for the Root's life. */
|
|
44
|
+
store?: NavStore;
|
|
45
|
+
/** What every list draws down its left edge, unless it says otherwise. */
|
|
46
|
+
guide?: NavGuide;
|
|
47
|
+
/** Wrap at the ends when arrowing past the first or last row. */
|
|
48
|
+
loop?: boolean;
|
|
49
|
+
/** Disables every row at once — a read-only view of the tree. */
|
|
50
|
+
disabled?: boolean;
|
|
51
|
+
/** Seek a row by typing its label. */
|
|
52
|
+
typeahead?: boolean;
|
|
53
|
+
children?: ReactNode;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* The provider and container. Owns the keyboard handling for the whole tree,
|
|
57
|
+
* so roving focus and typeahead work without any row registering itself.
|
|
58
|
+
* Renders a `<div>` element.
|
|
59
|
+
*/
|
|
60
|
+
export declare const NavRoot: ({ defaultExpanded, expanded, onExpandedChange, store: storeProp, guide, loop, disabled, typeahead, className, render, style, ...elementProps }: NavRootProps) => import("react").JSX.Element;
|
|
61
|
+
export type NavListProps = PrimitiveProps<"div", NavListState> & {
|
|
62
|
+
/**
|
|
63
|
+
* What this list draws down its left edge, overriding the Root's default:
|
|
64
|
+
* `"indent"` for space alone, `"rail"` for a line down it, `"branches"` to
|
|
65
|
+
* turn that line into each row that forks.
|
|
66
|
+
*
|
|
67
|
+
* Draw them yourself from `data-indent` / `data-rail` / `data-branches` — the
|
|
68
|
+
* package publishes the signal, never the geometry.
|
|
69
|
+
*/
|
|
70
|
+
guide?: NavGuide;
|
|
71
|
+
/** Keep a collapsed list in the DOM behind `hidden="until-found"`, so the
|
|
72
|
+
* browser's find-in-page can reveal it. Costs the rows staying mounted. */
|
|
73
|
+
keepMounted?: boolean;
|
|
74
|
+
children?: ReactNode;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* A level of the tree. A list inside a group is that group's collapsible
|
|
78
|
+
* panel; a top-level list is not collapsible, having no trigger above it.
|
|
79
|
+
* Renders a `<div>` element.
|
|
80
|
+
*/
|
|
81
|
+
export declare const NavList: ({ guide, keepMounted, className, render, style, ...elementProps }: NavListProps) => import("react").JSX.Element | null;
|
|
82
|
+
export type NavGroupProps = PrimitiveProps<"div", NavGroupState> & {
|
|
83
|
+
/** Identifies the group in the expanded set, and in persistence. */
|
|
84
|
+
value: string;
|
|
85
|
+
disabled?: boolean;
|
|
86
|
+
children?: ReactNode;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* A collapsible branch. Recursive by construction — a group's list may hold
|
|
90
|
+
* further groups, to any depth, with no second set of parts for the nesting.
|
|
91
|
+
*/
|
|
92
|
+
export declare const NavGroup: ({ value, disabled, className, render, style, ...elementProps }: NavGroupProps) => import("react").JSX.Element;
|
|
93
|
+
export type NavItemProps = PrimitiveProps<"div", NavItemState> & {
|
|
94
|
+
/** Identifies the row for roving focus and typeahead. */
|
|
95
|
+
value: string;
|
|
96
|
+
/** The route this row points at is the one being shown. */
|
|
97
|
+
active?: boolean;
|
|
98
|
+
disabled?: boolean;
|
|
99
|
+
children?: ReactNode;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* A leaf row. A `div[role="button"]` rather than an anchor, so an action can
|
|
103
|
+
* sit inside it — swap the element with `render={<Link href="…" />}` when you
|
|
104
|
+
* want a real navigation, or handle `onClick` and route yourself.
|
|
105
|
+
*/
|
|
106
|
+
export declare const NavItem: ({ value, active, disabled, className, render, style, ...elementProps }: NavItemProps) => import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
107
|
+
export type NavTriggerProps = PrimitiveProps<"div", NavTriggerState> & {
|
|
108
|
+
active?: boolean;
|
|
109
|
+
disabled?: boolean;
|
|
110
|
+
children?: ReactNode;
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* The row that opens a group — its heading and its disclosure in one, because
|
|
114
|
+
* in a sidebar they are the same thing you click. Takes no `value`: it belongs
|
|
115
|
+
* to the group it is written inside.
|
|
116
|
+
*
|
|
117
|
+
* Put a `Nav.Toggle` inside it and the two come apart: pressing the row
|
|
118
|
+
* activates it like `Nav.Item`, and the caret opens the group and carries
|
|
119
|
+
* `aria-expanded`. The arrow keys open and close it from the row either way.
|
|
120
|
+
*/
|
|
121
|
+
export declare const NavTrigger: ({ active, disabled, className, render, style, ...elementProps }: NavTriggerProps) => import("react").JSX.Element;
|
|
122
|
+
export type NavToggleState = NavPartState & {
|
|
123
|
+
open: boolean;
|
|
124
|
+
disabled: boolean;
|
|
125
|
+
};
|
|
126
|
+
export type NavToggleProps = PrimitiveProps<"div", NavToggleState> & {
|
|
127
|
+
children?: ReactNode;
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* The caret inside a row — the control that opens a branch whose row is also a
|
|
131
|
+
* page. Mounting it makes pressing the row activate the page. Out of the roving
|
|
132
|
+
* order, like `Nav.Action`, since the arrow keys already open the group from
|
|
133
|
+
* the row, and it stops every event it handles: anything that escaped would
|
|
134
|
+
* activate the row, or follow its link, on its way out of opening the group.
|
|
135
|
+
*/
|
|
136
|
+
export declare const NavToggle: ({ className, render, style, ...elementProps }: NavToggleProps) => import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
137
|
+
export type NavLabelProps = PrimitiveProps<"span", NavPartState>;
|
|
138
|
+
/** The row's text. Its own element so it can truncate while the row does not. */
|
|
139
|
+
export declare const NavLabel: ({ className, render, style, ...elementProps }: NavLabelProps) => import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
140
|
+
export type NavIconProps = PrimitiveProps<"span", NavPartState>;
|
|
141
|
+
/** Decoration. `aria-hidden`, so it stays out of the row's accessible name. */
|
|
142
|
+
export declare const NavIcon: ({ className, render, style, ...elementProps }: NavIconProps) => import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
143
|
+
export type NavActionProps = PrimitiveProps<"div", NavPartState> & {
|
|
144
|
+
children?: ReactNode;
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* A control inside a row — the "…" that opens a menu. Out of the roving order,
|
|
148
|
+
* so arrowing walks rows rather than stopping at every affordance, and it stops
|
|
149
|
+
* every event it handles: anything that escaped would activate the row on its
|
|
150
|
+
* way out of opening the menu.
|
|
151
|
+
*/
|
|
152
|
+
export declare const NavAction: ({ className, render, style, ...elementProps }: NavActionProps) => import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|