inline-chat-kit 0.49.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/CHANGELOG.md +2111 -0
- package/LICENSE +21 -0
- package/README.md +1430 -0
- package/dist/AnswerActions/AnswerActions.d.ts +35 -0
- package/dist/Approval/Approval.d.ts +42 -0
- package/dist/Artifact/ArtifactCard.d.ts +45 -0
- package/dist/Artifact/ArtifactPane.d.ts +50 -0
- package/dist/Artifact/ChatLayout.d.ts +35 -0
- package/dist/Artifact/useArtifacts.d.ts +21 -0
- package/dist/Attachments/Attachments.d.ts +50 -0
- package/dist/Branch/Branch.d.ts +28 -0
- package/dist/Button/Button.d.ts +23 -0
- package/dist/ChainOfThought/ChainOfThought.d.ts +49 -0
- package/dist/ChatHeader/ChatHeader.d.ts +89 -0
- package/dist/ChatInput/AddCardsOverlay.d.ts +11 -0
- package/dist/ChatInput/ChatInput.d.ts +118 -0
- package/dist/ChatInput/HoverActionsRow.d.ts +13 -0
- package/dist/ChatInput/MorphGlyph.d.ts +15 -0
- package/dist/ChatTurnRow/ChatTurnRow.d.ts +115 -0
- package/dist/Chip/Chip.d.ts +7 -0
- package/dist/CodeBlock/CodeBlock.d.ts +24 -0
- package/dist/CodeBlock/grammars.d.ts +16 -0
- package/dist/CodeBlock/highlight.d.ts +38 -0
- package/dist/Context/Context.d.ts +36 -0
- package/dist/Conversation/Conversation.d.ts +64 -0
- package/dist/CustomCursor/CustomCursor.d.ts +1 -0
- package/dist/EmptyState/EmptyState.d.ts +24 -0
- package/dist/GlassButton/GlassButton.d.ts +19 -0
- package/dist/InlineCitation/InlineCitation.d.ts +30 -0
- package/dist/Loader/Loader.d.ts +23 -0
- package/dist/QuestionCard/QuestionCard.d.ts +32 -0
- package/dist/QuestionCard/parts.d.ts +84 -0
- package/dist/QuestionCard/types.d.ts +54 -0
- package/dist/QuestionGroup/QuestionGroup.d.ts +87 -0
- package/dist/Reasoning/Reasoning.d.ts +37 -0
- package/dist/ReplyThreadPopup/ReplyThreadPopup.d.ts +18 -0
- package/dist/Sources/Sources.d.ts +46 -0
- package/dist/SystemMessage/SystemMessage.d.ts +39 -0
- package/dist/TaskList/TaskList.d.ts +42 -0
- package/dist/TextHighlighter/TextHighlighter.d.ts +17 -0
- package/dist/Tool/Tool.d.ts +41 -0
- package/dist/announce/announce.d.ts +27 -0
- package/dist/disclosure/DisclosureBody.d.ts +22 -0
- package/dist/disclosure/DisclosureHeader.d.ts +42 -0
- package/dist/disclosure/useDisclosure.d.ts +30 -0
- package/dist/duration/formatDuration.d.ts +9 -0
- package/dist/grammars-B19jp7qm.js +3181 -0
- package/dist/grammars-B19jp7qm.js.map +1 -0
- package/dist/index.d.ts +80 -0
- package/dist/inline-chat-kit.css +2 -0
- package/dist/inline-chat-kit.js +5314 -0
- package/dist/inline-chat-kit.js.map +1 -0
- package/dist/markdown/parse.d.ts +105 -0
- package/dist/markdown/parseMarkdown.d.ts +47 -0
- package/dist/radiusCorrection/useCorrectedRadius.d.ts +24 -0
- package/dist/reducedMotion/reducedMotion.d.ts +3 -0
- package/dist/stateGlyph/StateGlyph.d.ts +23 -0
- package/dist/turnParts/turnParts.d.ts +156 -0
- package/dist/useChatTurns/useChatTurns.d.ts +127 -0
- package/dist/voice/useVoiceInput.d.ts +79 -0
- package/package.json +95 -0
- package/theming.md +234 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Ref } from 'react';
|
|
2
|
+
import { Verdict } from '../AnswerActions/AnswerActions';
|
|
3
|
+
import { ChatInputHandle, InlineAnimConfig } from '../ChatInput/ChatInput';
|
|
4
|
+
import { Attachment } from '../Attachments/Attachments';
|
|
5
|
+
import { TranscribeHandler } from '../voice/useVoiceInput';
|
|
6
|
+
import { Decision } from '../Approval/Approval';
|
|
7
|
+
import { FoldMotion } from '../QuestionGroup/QuestionGroup';
|
|
8
|
+
import { Answer } from '../QuestionCard/types';
|
|
9
|
+
import { ChatTurn } from '../useChatTurns/useChatTurns';
|
|
10
|
+
export interface ChatTurnRowProps {
|
|
11
|
+
turn: ChatTurn;
|
|
12
|
+
/** This row owns the live composer: the one the reader types the next question into. */
|
|
13
|
+
isActiveInput?: boolean;
|
|
14
|
+
inputRef?: Ref<ChatInputHandle> | null;
|
|
15
|
+
placeholder?: string;
|
|
16
|
+
animationConfig?: InlineAnimConfig;
|
|
17
|
+
/** Overrides for a question group's fold timing. See `defaultFoldMotion`. */
|
|
18
|
+
foldMotion?: Partial<FoldMotion>;
|
|
19
|
+
/**
|
|
20
|
+
* Which artifact the pane is showing, so the card that opened it can say so.
|
|
21
|
+
* Held by `useArtifacts`, above both of them.
|
|
22
|
+
*/
|
|
23
|
+
openArtifactId?: string | null;
|
|
24
|
+
onOpenArtifact?: (turnId: string, artifactId: string) => void;
|
|
25
|
+
/** Stagger for the entrance, in seconds. */
|
|
26
|
+
entranceDelay?: number;
|
|
27
|
+
/** Passed through to the highlighter over the answer. */
|
|
28
|
+
selectionMode?: "marker" | "precise";
|
|
29
|
+
/**
|
|
30
|
+
* Passed through to the composer. Given, this row's live input offers a
|
|
31
|
+
* microphone; left out, it does not. See `ChatInput`.
|
|
32
|
+
*/
|
|
33
|
+
onTranscribe?: TranscribeHandler;
|
|
34
|
+
/**
|
|
35
|
+
* Where the composer sits in the row.
|
|
36
|
+
*
|
|
37
|
+
* `end` by default, because it is about to become the reader's own bubble
|
|
38
|
+
* and those sit right. `stretch` fills the row instead, which is what an
|
|
39
|
+
* *opening* composer wants: on an empty conversation it is not a message
|
|
40
|
+
* yet, it is the thing under the openers — and a pill floating at the right
|
|
41
|
+
* edge of a centred block reads as unrelated to the block.
|
|
42
|
+
*/
|
|
43
|
+
questionAlign?: "end" | "stretch";
|
|
44
|
+
/**
|
|
45
|
+
* Every callback takes the turn's id rather than being closed over per row.
|
|
46
|
+
*
|
|
47
|
+
* Not a style choice. An inline arrow is a new function on every render, and
|
|
48
|
+
* a new function prop is what makes `memo` give up — see the note on the
|
|
49
|
+
* component below. Taking the id lets a consumer hoist these once.
|
|
50
|
+
*/
|
|
51
|
+
onDraft?: (id: string, value: string) => void;
|
|
52
|
+
onSubmit?: (id: string, value: string, attachments: Attachment[]) => void;
|
|
53
|
+
onStop?: () => void;
|
|
54
|
+
onEdit?: (id: string) => void;
|
|
55
|
+
onCancelEdit?: (id: string) => void;
|
|
56
|
+
/** Defaults to writing to the clipboard. */
|
|
57
|
+
onCopy?: (value: string) => void;
|
|
58
|
+
onHighlight?: (turnId: string, text: string) => void;
|
|
59
|
+
onReplyInThread?: (text: string, rect: DOMRect) => void;
|
|
60
|
+
/**
|
|
61
|
+
* The row of actions under a settled answer.
|
|
62
|
+
*
|
|
63
|
+
* Copy is always offered once there is something to copy. Regenerate and the
|
|
64
|
+
* thumbs are drawn only when there is somewhere for them to report to, so a
|
|
65
|
+
* host that has no use for them is not showing a button that does nothing.
|
|
66
|
+
*
|
|
67
|
+
* They appear when the answer *settles*, not while it arrives: offering to
|
|
68
|
+
* copy a half-written answer, or to rate one, is offering the wrong thing.
|
|
69
|
+
*/
|
|
70
|
+
onRegenerate?: (id: string) => void;
|
|
71
|
+
/** Show another of this turn's answers. Without it the control is inert, so
|
|
72
|
+
it is not drawn. */
|
|
73
|
+
onShowVersion?: (id: string, index: number) => void;
|
|
74
|
+
onFeedback?: (id: string, verdict: Verdict | null) => void;
|
|
75
|
+
feedback?: Verdict | null;
|
|
76
|
+
/** Leave the row out entirely. */
|
|
77
|
+
answerActions?: boolean;
|
|
78
|
+
/**
|
|
79
|
+
* A question the assistant asked, answered.
|
|
80
|
+
*
|
|
81
|
+
* The row does not keep the answer — `turn.parts` is the host's, and this is
|
|
82
|
+
* how it hears that one of them changed. `useChatTurns` gives you
|
|
83
|
+
* `updatePart` to write it back.
|
|
84
|
+
*/
|
|
85
|
+
onAnswerQuestion?: (turnId: string, partId: string, questionId: string, answer: Answer) => void;
|
|
86
|
+
/** Somebody asked to change an answer already given. */
|
|
87
|
+
onEditQuestion?: (turnId: string, partId: string, index: number) => void;
|
|
88
|
+
/**
|
|
89
|
+
* Something the agent asked to do, decided.
|
|
90
|
+
*
|
|
91
|
+
* Same shape as the question callbacks and for the same reason: the row does
|
|
92
|
+
* not keep the decision, it reports it. Write it back with `updatePart`.
|
|
93
|
+
*/
|
|
94
|
+
onDecideApproval?: (turnId: string, partId: string, decision: Decision) => void;
|
|
95
|
+
className?: string;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* One turn: the question as a composer that has become a bubble, and the
|
|
99
|
+
* answer beneath it.
|
|
100
|
+
*
|
|
101
|
+
* Not `Message`, because it is not one. The user half is a live input that
|
|
102
|
+
* morphs into its own bubble rather than a rendered record of what was typed
|
|
103
|
+
* — which is the whole idea, and the reason the row is a turn.
|
|
104
|
+
*
|
|
105
|
+
* **Memoised, and the memo is load-bearing.** `useChatTurns` already leaves
|
|
106
|
+
* untouched turns referentially identical when it rewrites one of them, but
|
|
107
|
+
* that only pays off if the rows can act on it. Left inline in a `.map()`,
|
|
108
|
+
* every row re-renders on every flush anyway, because the parent re-rendered.
|
|
109
|
+
* Measured before this existed: streaming a second answer produced 366 DOM
|
|
110
|
+
* mutations inside the first, already-finished turn.
|
|
111
|
+
*
|
|
112
|
+
* The two halves have to be in place together. Stable objects give React the
|
|
113
|
+
* grounds to skip; `memo` is what makes it skip.
|
|
114
|
+
*/
|
|
115
|
+
export declare const ChatTurnRow: import('react').MemoExoticComponent<({ turn, isActiveInput, inputRef, placeholder, animationConfig, foldMotion, openArtifactId, onOpenArtifact, entranceDelay, selectionMode, questionAlign, onDraft, onSubmit, onStop, onEdit, onCancelEdit, onCopy, onHighlight, onReplyInThread, onRegenerate, onShowVersion, onFeedback, feedback, answerActions, onAnswerQuestion, onEditQuestion, onDecideApproval, className, onTranscribe, }: ChatTurnRowProps) => import("react").JSX.Element>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export interface ChipProps {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
className?: string;
|
|
5
|
+
}
|
|
6
|
+
/** A small, self-contained value — an answer given, a count, a tag. */
|
|
7
|
+
export declare function Chip({ children, className }: ChipProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { HTMLAttributes } from 'react';
|
|
2
|
+
export interface CodeBlockProps extends Omit<HTMLAttributes<HTMLDivElement>, "children" | "onCopy"> {
|
|
3
|
+
code: string;
|
|
4
|
+
/** The fence's language. Unknown ones render unhighlighted. */
|
|
5
|
+
lang?: string;
|
|
6
|
+
/** Shown top-left. Defaults to the language; pass `false` for no bar at all. */
|
|
7
|
+
label?: string | false;
|
|
8
|
+
/** Set false for a block nobody is meant to take away. */
|
|
9
|
+
copyable?: boolean;
|
|
10
|
+
/** Defaults to the clipboard. */
|
|
11
|
+
onCopy?: (code: string) => void;
|
|
12
|
+
/** How long the button stays confirmed, in ms. */
|
|
13
|
+
copiedFor?: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A fenced block: language, a copy button, and code that scrolls sideways
|
|
17
|
+
* rather than widening the answer.
|
|
18
|
+
*
|
|
19
|
+
* Deliberately not markable. The rest of an answer is split into word tokens
|
|
20
|
+
* so a marker can be drawn over it; preformatted text split on whitespace
|
|
21
|
+
* stops being preformatted, so this renders whole and the highlighter skips
|
|
22
|
+
* it. Copy is what people want from code anyway.
|
|
23
|
+
*/
|
|
24
|
+
export declare function CodeBlock({ code, lang, label, copyable, onCopy, copiedFor, className, ...rest }: CodeBlockProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Registered under the names `highlight.ts` claims. A test holds the two
|
|
2
|
+
lists against each other, since one is written out and one is not. */
|
|
3
|
+
export declare const createHighlighter: () => {
|
|
4
|
+
highlight: (language: string, value: string, options?: Readonly<import('lowlight').Options> | null | undefined) => import('hast').Root;
|
|
5
|
+
highlightAuto: (value: string, options?: Readonly<import('lowlight').AutoOptions> | null | undefined) => import('hast').Root;
|
|
6
|
+
listLanguages: () => Array<string>;
|
|
7
|
+
register: {
|
|
8
|
+
(grammars: Readonly<Record<string, import('highlight.js').LanguageFn>>): undefined;
|
|
9
|
+
(name: string, grammar: import('highlight.js').LanguageFn): undefined;
|
|
10
|
+
};
|
|
11
|
+
registerAlias: {
|
|
12
|
+
(aliases: Readonly<Record<string, ReadonlyArray<string> | string>>): undefined;
|
|
13
|
+
(language: string, alias: ReadonlyArray<string> | string): undefined;
|
|
14
|
+
};
|
|
15
|
+
registered: (aliasOrName: string) => boolean;
|
|
16
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Syntax highlighting, loaded only once something needs it.
|
|
3
|
+
*
|
|
4
|
+
* `lowlight` and eleven grammars are **22.4 kB gzipped** — more than a third
|
|
5
|
+
* of this package, for a thing most conversations never show. Imported at the
|
|
6
|
+
* top of the module they were in everybody's bundle whether or not an answer
|
|
7
|
+
* ever contained a fence.
|
|
8
|
+
*
|
|
9
|
+
* So the grammars sit behind a dynamic `import()` and the module itself keeps
|
|
10
|
+
* only the names. A block renders its code unhighlighted on the first paint
|
|
11
|
+
* and colours in when the chunk lands; every block after that is highlighted
|
|
12
|
+
* from the first paint, because the loaded highlighter is kept.
|
|
13
|
+
*
|
|
14
|
+
* What is *not* deferred is knowing whether a language can be highlighted at
|
|
15
|
+
* all — `canHighlight` answers off the list below, so a caller can decide what
|
|
16
|
+
* to draw without pulling 22 kB to find out.
|
|
17
|
+
*/
|
|
18
|
+
/** A run of code with one highlight class, or none. */
|
|
19
|
+
export interface CodeToken {
|
|
20
|
+
value: string;
|
|
21
|
+
/** The `hljs-` class, without the prefix. `null` for plain text. */
|
|
22
|
+
kind: string | null;
|
|
23
|
+
}
|
|
24
|
+
/** The whole block, one run, no colour. What a block shows before the chunk
|
|
25
|
+
arrives and what it keeps for a language nothing here can read. */
|
|
26
|
+
export declare const plain: (code: string) => CodeToken[];
|
|
27
|
+
/** Whether the fence's language is one we can actually colour. */
|
|
28
|
+
export declare const canHighlight: (lang?: string) => boolean;
|
|
29
|
+
export type Highlighter = (code: string, lang?: string) => CodeToken[];
|
|
30
|
+
/** The highlighter, if some block has already paid for it. */
|
|
31
|
+
export declare const loaded: () => Highlighter | null;
|
|
32
|
+
/**
|
|
33
|
+
* Fetch the grammars, once.
|
|
34
|
+
*
|
|
35
|
+
* Concurrent callers share the one promise: three code blocks in an answer
|
|
36
|
+
* arrive together, and three requests for the same chunk is two too many.
|
|
37
|
+
*/
|
|
38
|
+
export declare function loadHighlighter(): Promise<Highlighter>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
type Labels = {
|
|
3
|
+
name: string;
|
|
4
|
+
/** Between the two numbers: "128k of 1M". */
|
|
5
|
+
of: string;
|
|
6
|
+
tokens: string;
|
|
7
|
+
/** Said once it is past `warnAt`, and it should say what happens next. */
|
|
8
|
+
nearlyFull: string;
|
|
9
|
+
};
|
|
10
|
+
export interface ContextProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
|
|
11
|
+
used: number;
|
|
12
|
+
total: number;
|
|
13
|
+
/** Where it stops being quiet. A fraction, default `0.8`. */
|
|
14
|
+
warnAt?: number;
|
|
15
|
+
/**
|
|
16
|
+
* Drawn beside the ring. The percentage by default; `false` for the ring on
|
|
17
|
+
* its own, which is what a header usually wants.
|
|
18
|
+
*/
|
|
19
|
+
label?: ReactNode | false;
|
|
20
|
+
labels?: Partial<Labels>;
|
|
21
|
+
}
|
|
22
|
+
/** `128000` → `128k`, `1000000` → `1M`. Nobody reads the zeroes. */
|
|
23
|
+
export declare function formatCount(n: number): string;
|
|
24
|
+
/**
|
|
25
|
+
* How full the context window is.
|
|
26
|
+
*
|
|
27
|
+
* Small on purpose. It is a gauge, not a feature, and it earns its place for
|
|
28
|
+
* one reason: it is the only honest way to explain why a long conversation
|
|
29
|
+
* starts forgetting. Without it the forgetting looks like the model being
|
|
30
|
+
* stupid rather than the window being full.
|
|
31
|
+
*
|
|
32
|
+
* Which is why the warning says what happens next rather than only that a
|
|
33
|
+
* number is high. "82%" tells somebody nothing they can act on.
|
|
34
|
+
*/
|
|
35
|
+
export declare function Context({ used, total, warnAt, label, labels, className, ...rest }: ContextProps): import("react").JSX.Element;
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export interface ConversationProps extends HTMLAttributes<HTMLDivElement> {
|
|
3
|
+
children?: ReactNode;
|
|
4
|
+
/**
|
|
5
|
+
* How close to the end still counts as following, in pixels. Below this the
|
|
6
|
+
* view keeps up on its own; above it, the reader is reading and is left
|
|
7
|
+
* alone.
|
|
8
|
+
*/
|
|
9
|
+
threshold?: number;
|
|
10
|
+
/** The button offering a way back. `false` for none. */
|
|
11
|
+
scrollButton?: boolean;
|
|
12
|
+
scrollButtonLabel?: string;
|
|
13
|
+
/**
|
|
14
|
+
* The id of an element to hold at the top of the view — a turn, usually.
|
|
15
|
+
*
|
|
16
|
+
* Without it the view follows the end of the content, which is what a chat
|
|
17
|
+
* that stacks downwards wants. With it, the named element is brought to the
|
|
18
|
+
* top and **held** there while the answer grows underneath, so a reader sees
|
|
19
|
+
* their question and its answer and nothing else. Change the id and the view
|
|
20
|
+
* moves to the new one.
|
|
21
|
+
*
|
|
22
|
+
* This needs room to scroll into: an element cannot be brought to the top of
|
|
23
|
+
* a container that ends just below it. That is what a large bottom padding
|
|
24
|
+
* on the viewport is for.
|
|
25
|
+
*/
|
|
26
|
+
anchorId?: string;
|
|
27
|
+
/**
|
|
28
|
+
* How far below the top edge the anchor sits, in pixels. A fixed header over
|
|
29
|
+
* the conversation is the usual reason — without it the turn is scrolled
|
|
30
|
+
* neatly underneath and out of sight.
|
|
31
|
+
*/
|
|
32
|
+
anchorOffset?: number;
|
|
33
|
+
/** Switch the whole thing off and it is a plain scroll container. */
|
|
34
|
+
follow?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* For the element that actually scrolls, which is not the one `className`
|
|
37
|
+
* lands on.
|
|
38
|
+
*
|
|
39
|
+
* There are three: a root that positions the button, the viewport that
|
|
40
|
+
* scrolls, and a wrapper whose height is what "the end" is measured from.
|
|
41
|
+
* `className` goes to the root, because that is the box a consumer lays out.
|
|
42
|
+
* Padding has to go here instead — on the scroller — or it is not padding
|
|
43
|
+
* inside the scroll at all.
|
|
44
|
+
*/
|
|
45
|
+
viewportClassName?: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The scroll container: it keeps up with an answer as it arrives, and stops
|
|
49
|
+
* the instant the reader scrolls away.
|
|
50
|
+
*
|
|
51
|
+
* **It follows the end of the content, not the bottom of the container**, and
|
|
52
|
+
* those are only the same thing when nothing is padded below. This kit's demo
|
|
53
|
+
* carries a screen-height bottom padding so a turn can be pulled to the top,
|
|
54
|
+
* and scrolling to the true bottom there would push the answer off the screen
|
|
55
|
+
* to sit in front of a blank space. Measuring the content instead makes one
|
|
56
|
+
* behaviour correct for both.
|
|
57
|
+
*
|
|
58
|
+
* The other half is not fighting the reader. A naive version listens to the
|
|
59
|
+
* scroll event, cannot tell its own scrolling from theirs, and either drags
|
|
60
|
+
* them back down while they are reading or lets go entirely. This reads intent
|
|
61
|
+
* from the input — a wheel, a drag, a page key — and uses the scroll event
|
|
62
|
+
* only to measure where things ended up.
|
|
63
|
+
*/
|
|
64
|
+
export declare const Conversation: import('react').ForwardRefExoticComponent<ConversationProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function CustomCursor(): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export interface EmptyStateProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
|
|
3
|
+
icon?: ReactNode;
|
|
4
|
+
title?: ReactNode;
|
|
5
|
+
description?: ReactNode;
|
|
6
|
+
/**
|
|
7
|
+
* Openers. A blank input asks somebody to think of something; these are for
|
|
8
|
+
* the moment before they have.
|
|
9
|
+
*/
|
|
10
|
+
suggestions?: string[];
|
|
11
|
+
/** Given the suggestion's text. Without it, none are drawn. */
|
|
12
|
+
onSuggestion?: (text: string) => void;
|
|
13
|
+
suggestionsLabel?: string;
|
|
14
|
+
children?: ReactNode;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* What is on screen before anybody has asked anything.
|
|
18
|
+
*
|
|
19
|
+
* Not a landmark and not a heading by default — this sits inside a
|
|
20
|
+
* conversation the host already owns, and claiming a level in their document
|
|
21
|
+
* is not ours to do. `title` renders as text; wrap it yourself if it should be
|
|
22
|
+
* a heading.
|
|
23
|
+
*/
|
|
24
|
+
export declare function EmptyState({ icon, title, description, suggestions, onSuggestion, suggestionsLabel, children, className, ...rest }: EmptyStateProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ButtonHTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export type GlassButtonSize = "s" | "m" | "l";
|
|
3
|
+
export interface GlassButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
/** Show loading spinner and disable interaction */
|
|
6
|
+
loading?: boolean;
|
|
7
|
+
/** Leading icon element */
|
|
8
|
+
iconLeft?: ReactNode;
|
|
9
|
+
/** Trailing icon element */
|
|
10
|
+
iconRight?: ReactNode;
|
|
11
|
+
/** Button size: s=32px, m=40px, l=48px */
|
|
12
|
+
size?: GlassButtonSize;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* @deprecated Use `<Button variant="glass">`. Kept so existing installs keep
|
|
16
|
+
* working; it is a thin wrapper, not a second component.
|
|
17
|
+
*/
|
|
18
|
+
declare const GlassButton: import('react').ForwardRefExoticComponent<GlassButtonProps & import('react').RefAttributes<HTMLButtonElement>>;
|
|
19
|
+
export default GlassButton;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import { Source } from '../Sources/Sources';
|
|
3
|
+
export interface InlineCitationProps extends Omit<HTMLAttributes<HTMLElement>, "children" | "onSelect"> {
|
|
4
|
+
/** 1-based, and it has to match the entry's place in `<Sources>`. */
|
|
5
|
+
index: number;
|
|
6
|
+
/** Named in the marker's label, so the marker says more than a number. */
|
|
7
|
+
source?: Source;
|
|
8
|
+
/**
|
|
9
|
+
* The passage this citation is for.
|
|
10
|
+
*
|
|
11
|
+
* Given one, the passage is **marked** — the same yellow the highlighter
|
|
12
|
+
* draws, because it is the same statement: this run of words is spoken for.
|
|
13
|
+
* Left out, the marker stands on its own after whatever precedes it.
|
|
14
|
+
*/
|
|
15
|
+
children?: ReactNode;
|
|
16
|
+
/** Where the reader is taken. Without one the marker is not a control. */
|
|
17
|
+
onSelect?: (index: number, source?: Source) => void;
|
|
18
|
+
labels?: Partial<{
|
|
19
|
+
cite: string;
|
|
20
|
+
}>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The numbered marker in the text, and the passage it speaks for.
|
|
24
|
+
*
|
|
25
|
+
* The kit already had a way of saying "this run of words is picked out" — the
|
|
26
|
+
* marker somebody draws over an answer to ask about it. A citation is that
|
|
27
|
+
* same statement made by the answer rather than by the reader, so it is drawn
|
|
28
|
+
* the same way rather than in a second visual language nobody has learned.
|
|
29
|
+
*/
|
|
30
|
+
export declare function InlineCitation({ index, source, children, onSelect, labels, className, ...rest }: InlineCitationProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { HTMLAttributes } from 'react';
|
|
2
|
+
export type LoaderVariant = "dots" | "shimmer";
|
|
3
|
+
export interface LoaderProps extends HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
variant?: LoaderVariant;
|
|
5
|
+
/** The words the shimmer runs through. Ignored by `dots`. */
|
|
6
|
+
children?: React.ReactNode;
|
|
7
|
+
/**
|
|
8
|
+
* What a screen reader is told, if anything.
|
|
9
|
+
*
|
|
10
|
+
* `null` by default, and that is deliberate: `useChatTurns` already
|
|
11
|
+
* announces that a response is coming, and a second live region saying the
|
|
12
|
+
* same thing means hearing it twice. Pass a string only when nothing else
|
|
13
|
+
* is speaking for you.
|
|
14
|
+
*/
|
|
15
|
+
label?: string | null;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The gap between sending and the first word arriving.
|
|
19
|
+
*
|
|
20
|
+
* `dots` for that gap, when there is nothing to show yet. `shimmer` for words
|
|
21
|
+
* that are standing in for something — a status line that has not settled.
|
|
22
|
+
*/
|
|
23
|
+
export declare function Loader({ variant, children, label, className, ...rest }: LoaderProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Answer, Question, QuestionState } from './types';
|
|
2
|
+
export interface QuestionCardProps {
|
|
3
|
+
question: Question;
|
|
4
|
+
/** Shown in the badge. 1-based. */
|
|
5
|
+
number: number;
|
|
6
|
+
state: QuestionState;
|
|
7
|
+
answer?: Answer;
|
|
8
|
+
onCommit?: (answer: Answer) => void;
|
|
9
|
+
/** Called when somebody asks to change an answer already given. */
|
|
10
|
+
onEdit?: () => void;
|
|
11
|
+
/** Answers can be read but not changed. */
|
|
12
|
+
readOnly?: boolean;
|
|
13
|
+
labels?: Partial<Record<"next" | "none" | "edit", string>>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* What an answer looks like once folded into a row.
|
|
17
|
+
*
|
|
18
|
+
* Two at most, then a count. Three chips of unpredictable width in a row that
|
|
19
|
+
* also holds a title is a row that wraps, and a summary that wraps is not a
|
|
20
|
+
* summary.
|
|
21
|
+
*/
|
|
22
|
+
export declare function answerChips(question: Question, answer?: Answer): string[];
|
|
23
|
+
/**
|
|
24
|
+
* One question, in whichever of its three states it is in.
|
|
25
|
+
*
|
|
26
|
+
* The card morphs between them rather than swapping: the box animates with
|
|
27
|
+
* FLIP, and the content inside counter-scales so text keeps its real size
|
|
28
|
+
* instead of stretching on the way. `overflow: hidden` is what makes growing
|
|
29
|
+
* read as a reveal rather than as content spilling out of a box that has not
|
|
30
|
+
* caught up.
|
|
31
|
+
*/
|
|
32
|
+
export declare function QuestionCard({ question, number, state, answer, onCommit, onEdit, readOnly, labels, }: QuestionCardProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export interface QuestionBadgeProps extends Omit<HTMLAttributes<HTMLSpanElement>, "children"> {
|
|
3
|
+
/** The number or the letter. */
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
/** Wearing the accent, because this is the one being answered or chosen. */
|
|
6
|
+
selected?: boolean;
|
|
7
|
+
/** Sitting on a raised card rather than on the group's own surface. */
|
|
8
|
+
onCard?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/** The 24px square carrying a number or a letter. */
|
|
11
|
+
export declare const QuestionBadge: import('react').ForwardRefExoticComponent<QuestionBadgeProps & import('react').RefAttributes<HTMLSpanElement>>;
|
|
12
|
+
type OptionBase = Omit<ComponentPropsWithoutRef<"button">, "title" | "onAnimationStart" | "onAnimationEnd" | "onDrag" | "onDragStart" | "onDragEnd">;
|
|
13
|
+
export interface QuestionOptionRowProps extends OptionBase {
|
|
14
|
+
/** The a/b/c badge. Left out, the row starts at its title. */
|
|
15
|
+
letter?: ReactNode;
|
|
16
|
+
/** Wins the name from the button's own `title` attribute, which is a tooltip. */
|
|
17
|
+
title: ReactNode;
|
|
18
|
+
description?: ReactNode;
|
|
19
|
+
selected?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/** One option, in a single- or multi-select question. */
|
|
22
|
+
export declare const QuestionOptionRow: import('react').ForwardRefExoticComponent<QuestionOptionRowProps & import('react').RefAttributes<HTMLButtonElement>>;
|
|
23
|
+
/** `className` styles the row; everything else lands on the input. */
|
|
24
|
+
type FieldBase = Omit<ComponentPropsWithoutRef<"input">, "value" | "onChange" | "className">;
|
|
25
|
+
export interface QuestionFieldRowProps extends FieldBase {
|
|
26
|
+
/** The a/b/c badge. Left out, the row starts at its label. */
|
|
27
|
+
letter?: ReactNode;
|
|
28
|
+
label: ReactNode;
|
|
29
|
+
value: string;
|
|
30
|
+
/** The value, not the event — the row exists to be typed into. */
|
|
31
|
+
onChange: (value: string) => void;
|
|
32
|
+
/** Enter, which in a question nearly always means "the next one", not "send". */
|
|
33
|
+
onEnter?: () => void;
|
|
34
|
+
/** On the row. Every other prop goes to the input. */
|
|
35
|
+
className?: string;
|
|
36
|
+
}
|
|
37
|
+
/** A free-text row: letter, label, and the field itself. */
|
|
38
|
+
export declare const QuestionFieldRow: import('react').ForwardRefExoticComponent<QuestionFieldRowProps & import('react').RefAttributes<HTMLInputElement>>;
|
|
39
|
+
type OtherBase = Omit<ComponentPropsWithoutRef<"input">, "value" | "onChange" | "className" | "placeholder">;
|
|
40
|
+
export interface QuestionOtherRowProps extends OtherBase {
|
|
41
|
+
/** The a/b/c badge. Left out, the row starts at the field. */
|
|
42
|
+
letter?: ReactNode;
|
|
43
|
+
value: string;
|
|
44
|
+
/** Also the accessible name: the row has no visible label of its own. */
|
|
45
|
+
placeholder: string;
|
|
46
|
+
onChange: (value: string) => void;
|
|
47
|
+
onEnter?: () => void;
|
|
48
|
+
/** On the row. Every other prop goes to the input. */
|
|
49
|
+
className?: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The "something else" row: reads as one more option, but it is a text field.
|
|
53
|
+
*
|
|
54
|
+
* A label rather than a button, and that is not a detail — an input inside a
|
|
55
|
+
* button is not reliably focusable, and the whole row exists to be typed into.
|
|
56
|
+
*/
|
|
57
|
+
export declare const QuestionOtherRow: import('react').ForwardRefExoticComponent<QuestionOtherRowProps & import('react').RefAttributes<HTMLInputElement>>;
|
|
58
|
+
export interface QuestionShellProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
|
|
59
|
+
/** The badge over the question. Left out, the header starts at the title. */
|
|
60
|
+
number?: ReactNode;
|
|
61
|
+
title: ReactNode;
|
|
62
|
+
subtitle?: ReactNode;
|
|
63
|
+
/** The rows this question is made of. */
|
|
64
|
+
children: ReactNode;
|
|
65
|
+
/** Right-aligned under the rows — usually the button that commits. */
|
|
66
|
+
footer?: ReactNode;
|
|
67
|
+
/**
|
|
68
|
+
* Paint the card box: background, radius, shadow.
|
|
69
|
+
*
|
|
70
|
+
* On by default, because a shell used on its own is the reason this is
|
|
71
|
+
* exported. `QuestionCard` turns it off — it brings its own box, which is
|
|
72
|
+
* the one that morphs between the three states.
|
|
73
|
+
*/
|
|
74
|
+
card?: boolean;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* A question laid out: header, rows, footer.
|
|
78
|
+
*
|
|
79
|
+
* The scaffolding, so composing a fourth kind of question is a matter of
|
|
80
|
+
* choosing the rows rather than rebuilding the box, the spacing and the type
|
|
81
|
+
* around them out of numbers that were tokens ten minutes ago.
|
|
82
|
+
*/
|
|
83
|
+
export declare const QuestionShell: import('react').ForwardRefExoticComponent<QuestionShellProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
84
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A structured question inside a conversation.
|
|
3
|
+
*
|
|
4
|
+
* Three shapes, because there are three ways to answer one: type something,
|
|
5
|
+
* pick one, or pick several. Each carries a `shortTitle` for the row it
|
|
6
|
+
* becomes once it is answered — the full question is too long to sit in a
|
|
7
|
+
* summary, and truncating it loses the end, which is where the meaning is.
|
|
8
|
+
*/
|
|
9
|
+
export interface QuestionOption {
|
|
10
|
+
id: string;
|
|
11
|
+
title: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
/** Used when several are chosen and the titles would not fit. */
|
|
14
|
+
short?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface QuestionField {
|
|
17
|
+
id: string;
|
|
18
|
+
label: string;
|
|
19
|
+
placeholder?: string;
|
|
20
|
+
optional?: boolean;
|
|
21
|
+
}
|
|
22
|
+
interface Common {
|
|
23
|
+
id: string;
|
|
24
|
+
title: string;
|
|
25
|
+
subtitle?: string;
|
|
26
|
+
/** What it is called once it is answered and folded into a row. */
|
|
27
|
+
shortTitle: string;
|
|
28
|
+
}
|
|
29
|
+
export type Question = (Common & {
|
|
30
|
+
type: "inputs";
|
|
31
|
+
fields: QuestionField[];
|
|
32
|
+
}) | (Common & {
|
|
33
|
+
type: "single";
|
|
34
|
+
options: QuestionOption[];
|
|
35
|
+
}) | (Common & {
|
|
36
|
+
type: "multi";
|
|
37
|
+
options: QuestionOption[];
|
|
38
|
+
/** Adds a row that is a text field wearing an option's clothes. */
|
|
39
|
+
allowOther?: boolean;
|
|
40
|
+
otherPlaceholder?: string;
|
|
41
|
+
/** Lets somebody answer "none of these" rather than being stuck. */
|
|
42
|
+
allowEmpty?: boolean;
|
|
43
|
+
});
|
|
44
|
+
export type Answer = {
|
|
45
|
+
values: Record<string, string>;
|
|
46
|
+
} | {
|
|
47
|
+
optionId: string;
|
|
48
|
+
} | {
|
|
49
|
+
optionIds: string[];
|
|
50
|
+
other?: string;
|
|
51
|
+
};
|
|
52
|
+
/** Answered, being answered, or still to come. */
|
|
53
|
+
export type QuestionState = "upcoming" | "active" | "collapsed";
|
|
54
|
+
export {};
|