@particle-academy/react-fancy 5.70.0 → 5.71.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 +49 -0
- package/README.md +1 -0
- package/dist/autocomplete.cjs +3 -3
- package/dist/autocomplete.js +2 -2
- package/dist/chat-thread.cjs +27 -0
- package/dist/chat-thread.cjs.map +1 -0
- package/dist/chat-thread.d.cts +260 -0
- package/dist/chat-thread.d.ts +260 -0
- package/dist/chat-thread.js +14 -0
- package/dist/chat-thread.js.map +1 -0
- package/dist/chunk-5IE65DIH.cjs +623 -0
- package/dist/chunk-5IE65DIH.cjs.map +1 -0
- package/dist/{chunk-6QAF35AJ.cjs → chunk-7JLKOVHX.cjs} +3 -3
- package/dist/{chunk-6QAF35AJ.cjs.map → chunk-7JLKOVHX.cjs.map} +1 -1
- package/dist/{chunk-TCMOD3WW.js → chunk-A6NYZ3F5.js} +3 -3
- package/dist/{chunk-TCMOD3WW.js.map → chunk-A6NYZ3F5.js.map} +1 -1
- package/dist/{chunk-6EA3DSPT.cjs → chunk-FGOFG2UZ.cjs} +5 -5
- package/dist/{chunk-6EA3DSPT.cjs.map → chunk-FGOFG2UZ.cjs.map} +1 -1
- package/dist/{chunk-J7S42MJP.js → chunk-FYUEDPST.js} +39 -20
- package/dist/chunk-FYUEDPST.js.map +1 -0
- package/dist/{chunk-HN5J7TK6.js → chunk-GDH43QH6.js} +21 -8
- package/dist/chunk-GDH43QH6.js.map +1 -0
- package/dist/{chunk-AC3W3TIV.js → chunk-J6IQHJET.js} +14 -5
- package/dist/chunk-J6IQHJET.js.map +1 -0
- package/dist/{chunk-XNHAJQRF.cjs → chunk-JKD6CFIP.cjs} +14 -5
- package/dist/chunk-JKD6CFIP.cjs.map +1 -0
- package/dist/{chunk-FHRVSYJU.cjs → chunk-MP55W37V.cjs} +3 -3
- package/dist/{chunk-FHRVSYJU.cjs.map → chunk-MP55W37V.cjs.map} +1 -1
- package/dist/{chunk-LBSAWRFT.cjs → chunk-NPSKZ7ZB.cjs} +22 -9
- package/dist/chunk-NPSKZ7ZB.cjs.map +1 -0
- package/dist/{chunk-EZL5DILH.js → chunk-OPDHSOUN.js} +3 -3
- package/dist/{chunk-EZL5DILH.js.map → chunk-OPDHSOUN.js.map} +1 -1
- package/dist/{chunk-XAKZ6VBP.cjs → chunk-PS7C6GKI.cjs} +40 -21
- package/dist/chunk-PS7C6GKI.cjs.map +1 -0
- package/dist/chunk-UWYSJARZ.js +620 -0
- package/dist/chunk-UWYSJARZ.js.map +1 -0
- package/dist/{chunk-M6UAVA2I.js → chunk-XIA2UAVO.js} +3 -3
- package/dist/{chunk-M6UAVA2I.js.map → chunk-XIA2UAVO.js.map} +1 -1
- package/dist/composer.cjs +3 -3
- package/dist/composer.d.cts +3 -2
- package/dist/composer.d.ts +3 -2
- package/dist/composer.js +2 -2
- package/dist/editor.cjs +3 -3
- package/dist/editor.js +3 -3
- package/dist/{index-BAtF94lw.d.ts → index-B8OkuYSt.d.ts} +3 -2
- package/dist/{index-xwL2MACB.d.cts → index-BMVQnKTH.d.cts} +3 -2
- package/dist/index.cjs +170 -161
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +26 -25
- package/dist/index.js.map +1 -1
- package/dist/input.cjs +1 -1
- package/dist/input.js +1 -1
- package/dist/inputs.cjs +7 -7
- package/dist/inputs.js +3 -3
- package/dist/json-editor.cjs +16 -16
- package/dist/json-editor.js +5 -5
- package/dist/prompt-input.cjs +6 -6
- package/dist/prompt-input.d.cts +1 -1
- package/dist/prompt-input.d.ts +1 -1
- package/dist/prompt-input.js +3 -3
- package/dist/select.cjs +3 -3
- package/dist/select.js +2 -2
- package/docs/ChatThread.md +318 -0
- package/docs/Composer.md +5 -2
- package/docs/PromptInput.md +8 -2
- package/package.json +11 -1
- package/dist/chunk-AC3W3TIV.js.map +0 -1
- package/dist/chunk-HN5J7TK6.js.map +0 -1
- package/dist/chunk-J7S42MJP.js.map +0 -1
- package/dist/chunk-LBSAWRFT.cjs.map +0 -1
- package/dist/chunk-XAKZ6VBP.cjs.map +0 -1
- package/dist/chunk-XNHAJQRF.cjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,55 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
11
11
|
|
|
12
12
|
## [Unreleased]
|
|
13
13
|
|
|
14
|
+
## [5.71.0] - 2026-10-27
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **`ChatThread` and `ChatMessage`**: a controlled message list for agent and
|
|
19
|
+
support conversations, built for charlotte-ui's side panel and
|
|
20
|
+
fancy-support's admin chat and ticket thread. Messages are JSON
|
|
21
|
+
(`ChatMessageData`: `id`, `role`, `author`, markdown `content`, `createdAt`,
|
|
22
|
+
`status`, `visibility`, `attachments`, `proposal`, `meta`). Content renders
|
|
23
|
+
through `ContentRenderer`, always sanitised (there is no `unsafe` prop), and a
|
|
24
|
+
`streaming` message uses its `streaming` / `"progressive"` mode and is
|
|
25
|
+
`aria-busy`. The log follows new messages only while the reader is at the
|
|
26
|
+
bottom; a reader who scrolled up stays put and gets an "N new messages" jump
|
|
27
|
+
control, and prepended history keeps their place. Only the log's own
|
|
28
|
+
`scrollTop` is set and focus uses `preventScroll`, so nothing outside the log
|
|
29
|
+
scrolls. `visibility: "internal"` is labelled and styled, never filtered: the
|
|
30
|
+
host passes only what the viewer may see. A message with a `proposal` is an
|
|
31
|
+
approval card (`data-chat-proposal`) with accept / reject callbacks; it never
|
|
32
|
+
acts on its own, and a returned Promise disables both decisions until it
|
|
33
|
+
settles. Also: `onLoadEarlier`, day separators, consecutive grouping, a
|
|
34
|
+
per-message actions slot, a composer slot (for `Composer` / `PromptInput`;
|
|
35
|
+
no new input), `onActivity` for every interaction, `role="log"` with polite
|
|
36
|
+
updates, and a `ref` handle with `scrollToLatest` / `scrollToMessage`. New
|
|
37
|
+
subpath `@particle-academy/react-fancy/chat-thread`. Nothing to do on upgrade.
|
|
38
|
+
|
|
39
|
+
## [5.70.1] - 2026-10-27
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
|
|
43
|
+
- **An acknowledged send no longer clears a newer draft that happens to read
|
|
44
|
+
the same** (`Composer`, `PromptInput`, from 5.70.0). When an async `onSubmit`
|
|
45
|
+
resolved, the draft was cleared if its text and the ids of its pills and
|
|
46
|
+
attachments still matched what was sent. A newer draft that compared equal was
|
|
47
|
+
therefore thrown away: an edit typed and then deleted during the send, a host
|
|
48
|
+
`setDraft` that restored the same draft, or a pill's text or an attachment
|
|
49
|
+
changed under the same id. The clear is now tied to the draft revision that
|
|
50
|
+
was sent. Anything that changes the draft after the send (the person, the
|
|
51
|
+
host's `setDraft`, a controlled `draft` / `value` / `heldPastes` /
|
|
52
|
+
`heldImages` that now says something different) makes it newer, and a newer
|
|
53
|
+
draft is kept whole. A `ref` arriving from `persistAttachment` mid-send is not
|
|
54
|
+
a change, so it does not block the clear. A controlled host that echoes a
|
|
55
|
+
copy of each draft is still cleared, because an echo that says the same thing
|
|
56
|
+
is not a new revision. Nothing to do on upgrade.
|
|
57
|
+
- **Only the newest send can acknowledge.** Both components refuse a second
|
|
58
|
+
send while one is pending, and nothing turns that off. If two ever overlapped,
|
|
59
|
+
the older one settling would have cleared the draft and ended the newer one's
|
|
60
|
+
`submitting` state. It is now ignored, except that its failure still reaches
|
|
61
|
+
`onSubmitError`.
|
|
62
|
+
|
|
14
63
|
## [5.70.0] - 2026-10-27
|
|
15
64
|
|
|
16
65
|
### Added
|
package/README.md
CHANGED
|
@@ -161,6 +161,7 @@ npx vite build # Build demo app (verifies imports work)
|
|
|
161
161
|
| Component | Description | Docs |
|
|
162
162
|
|-----------|-------------|------|
|
|
163
163
|
| Composer | Chat-style message input composing textarea + actions | [docs](docs/Composer.md) |
|
|
164
|
+
| ChatThread | Controlled message list for agent and support chat: sanitised markdown, streaming, internal notes, approval cards, stick-to-bottom without yanking | [docs](docs/ChatThread.md) |
|
|
164
165
|
| Chart | SVG-based Bar, Line, Area, Pie, Donut, and Sparkline charts | [docs](docs/Chart.md) |
|
|
165
166
|
| Editor | Toolbar chrome wrapper for contentEditable, with a Source toggle to edit raw HTML/Markdown | [docs](docs/Editor.md) |
|
|
166
167
|
| CodeView | Lightweight syntax-highlighted source view (HTML highlighted; fills height) | [docs](docs/CodeView.md) |
|
package/dist/autocomplete.cjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkMP55W37V_cjs = require('./chunk-MP55W37V.cjs');
|
|
4
|
+
require('./chunk-J2DI6RMR.cjs');
|
|
4
5
|
require('./chunk-KJ22KE56.cjs');
|
|
5
6
|
require('./chunk-L3V3BYVS.cjs');
|
|
6
|
-
require('./chunk-J2DI6RMR.cjs');
|
|
7
7
|
require('./chunk-6V44RRSB.cjs');
|
|
8
8
|
require('./chunk-MKHYENKR.cjs');
|
|
9
9
|
require('./chunk-TI7D4QDM.cjs');
|
|
@@ -16,7 +16,7 @@ require('./chunk-ZU5Q77OT.cjs');
|
|
|
16
16
|
|
|
17
17
|
Object.defineProperty(exports, "Autocomplete", {
|
|
18
18
|
enumerable: true,
|
|
19
|
-
get: function () { return
|
|
19
|
+
get: function () { return chunkMP55W37V_cjs.Autocomplete; }
|
|
20
20
|
});
|
|
21
21
|
//# sourceMappingURL=autocomplete.cjs.map
|
|
22
22
|
//# sourceMappingURL=autocomplete.cjs.map
|
package/dist/autocomplete.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { Autocomplete } from './chunk-
|
|
1
|
+
export { Autocomplete } from './chunk-A6NYZ3F5.js';
|
|
2
|
+
import './chunk-MQ6VGG62.js';
|
|
2
3
|
import './chunk-OL53XYHF.js';
|
|
3
4
|
import './chunk-NRXK42LO.js';
|
|
4
|
-
import './chunk-MQ6VGG62.js';
|
|
5
5
|
import './chunk-S42OGG43.js';
|
|
6
6
|
import './chunk-5VMILVWD.js';
|
|
7
7
|
import './chunk-RBCMKPBX.js';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunk5IE65DIH_cjs = require('./chunk-5IE65DIH.cjs');
|
|
4
|
+
require('./chunk-S3TRSECD.cjs');
|
|
5
|
+
require('./chunk-R3EJNGJV.cjs');
|
|
6
|
+
require('./chunk-2C64OVOZ.cjs');
|
|
7
|
+
require('./chunk-BJL3VDRK.cjs');
|
|
8
|
+
require('./chunk-VBWRH4UW.cjs');
|
|
9
|
+
require('./chunk-MOU6O324.cjs');
|
|
10
|
+
require('./chunk-M5MUGSON.cjs');
|
|
11
|
+
require('./chunk-3U7PUZLI.cjs');
|
|
12
|
+
require('./chunk-XCZZVRBY.cjs');
|
|
13
|
+
require('./chunk-MXWR3T3N.cjs');
|
|
14
|
+
require('./chunk-ZU5Q77OT.cjs');
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
Object.defineProperty(exports, "ChatMessage", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function () { return chunk5IE65DIH_cjs.ChatMessage; }
|
|
21
|
+
});
|
|
22
|
+
Object.defineProperty(exports, "ChatThread", {
|
|
23
|
+
enumerable: true,
|
|
24
|
+
get: function () { return chunk5IE65DIH_cjs.ChatThread; }
|
|
25
|
+
});
|
|
26
|
+
//# sourceMappingURL=chat-thread.cjs.map
|
|
27
|
+
//# sourceMappingURL=chat-thread.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"chat-thread.cjs"}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode, HTMLAttributes, Ref } from 'react';
|
|
3
|
+
import { d as ContentRendererProps } from './ContentRenderer.types-RO_l7_6N.cjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Who a message is from. The named roles get default labels and styling; any
|
|
7
|
+
* other string is carried verbatim (`data-chat-role`) and rendered neutrally.
|
|
8
|
+
*/
|
|
9
|
+
type ChatRole = "user" | "assistant" | "system" | "agent" | "staff" | "customer" | (string & {});
|
|
10
|
+
type ChatMessageStatus = "pending" | "streaming" | "sent" | "failed";
|
|
11
|
+
/**
|
|
12
|
+
* `internal` is a staff-only note. The component LABELS it; it never decides
|
|
13
|
+
* who sees it. Pass only the messages the viewer is allowed to see.
|
|
14
|
+
*/
|
|
15
|
+
type ChatMessageVisibility = "public" | "internal";
|
|
16
|
+
interface ChatAuthor {
|
|
17
|
+
name: string;
|
|
18
|
+
/** Image URL for the avatar. Without it, initials are shown. */
|
|
19
|
+
avatar?: string;
|
|
20
|
+
}
|
|
21
|
+
/** A file on a message. Rendered as a link, never auto-loaded inline. */
|
|
22
|
+
interface ChatAttachment {
|
|
23
|
+
id: string;
|
|
24
|
+
name: string;
|
|
25
|
+
/** Unsafe schemes (`javascript:`, `data:`, ...) render the name without a link. */
|
|
26
|
+
url?: string;
|
|
27
|
+
mimeType?: string;
|
|
28
|
+
/** Bytes. */
|
|
29
|
+
size?: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* An agent's suggested action awaiting a human: an approval card. The message
|
|
33
|
+
* `content` is the draft (a reply, a field change, a page edit). The state is
|
|
34
|
+
* the HOST's: the component shows decision buttons only while `pending`, and
|
|
35
|
+
* never changes the state itself.
|
|
36
|
+
*/
|
|
37
|
+
interface ChatProposal {
|
|
38
|
+
/** Stable id, rendered as `data-chat-proposal`. Usually the card id. */
|
|
39
|
+
id: string;
|
|
40
|
+
title?: string;
|
|
41
|
+
/** @default "pending" */
|
|
42
|
+
state?: "pending" | "accepted" | "rejected" | "withdrawn";
|
|
43
|
+
/** Overrides the thread's accept / reject labels for this card. */
|
|
44
|
+
acceptLabel?: string;
|
|
45
|
+
rejectLabel?: string;
|
|
46
|
+
}
|
|
47
|
+
/** One message. Plain JSON: an agent can emit it, a server can send it. */
|
|
48
|
+
interface ChatMessageData {
|
|
49
|
+
/** Stable id, rendered as `data-chat-message`. */
|
|
50
|
+
id: string;
|
|
51
|
+
role: ChatRole;
|
|
52
|
+
author?: ChatAuthor;
|
|
53
|
+
/** Markdown by default; see `format`. Always sanitised. */
|
|
54
|
+
content: string;
|
|
55
|
+
/** `"text"` renders the content literally (no markdown, no HTML). @default "markdown" */
|
|
56
|
+
format?: "markdown" | "text";
|
|
57
|
+
/** ISO 8601 string or epoch milliseconds. */
|
|
58
|
+
createdAt: string | number;
|
|
59
|
+
/** @default "sent" */
|
|
60
|
+
status?: ChatMessageStatus;
|
|
61
|
+
/** @default "public" */
|
|
62
|
+
visibility?: ChatMessageVisibility;
|
|
63
|
+
attachments?: ChatAttachment[];
|
|
64
|
+
/** Makes this message an approval card. */
|
|
65
|
+
proposal?: ChatProposal;
|
|
66
|
+
/**
|
|
67
|
+
* Align as the viewer's own message. Defaults to `ownRoles` containing
|
|
68
|
+
* `role`.
|
|
69
|
+
*/
|
|
70
|
+
own?: boolean;
|
|
71
|
+
/** Anything the host wants carried along (card version, ticket ref, ...). Not rendered. */
|
|
72
|
+
meta?: Record<string, unknown>;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Every human interaction the thread hands to a callback, as one event stream
|
|
76
|
+
* for presence, undo and coaching layers. Map it onto fancy-auto-common's
|
|
77
|
+
* `AutoActivityEvent` (or anything else) in the host.
|
|
78
|
+
*/
|
|
79
|
+
type ChatThreadActivity = {
|
|
80
|
+
type: "load-earlier";
|
|
81
|
+
} | {
|
|
82
|
+
type: "proposal-accept";
|
|
83
|
+
messageId: string;
|
|
84
|
+
proposalId: string;
|
|
85
|
+
} | {
|
|
86
|
+
type: "proposal-reject";
|
|
87
|
+
messageId: string;
|
|
88
|
+
proposalId: string;
|
|
89
|
+
} | {
|
|
90
|
+
type: "jump-to-latest";
|
|
91
|
+
unseen: number;
|
|
92
|
+
};
|
|
93
|
+
/** What `onActionError` is told about: the action whose Promise rejected. */
|
|
94
|
+
type ChatThreadActionContext = Exclude<ChatThreadActivity, {
|
|
95
|
+
type: "jump-to-latest";
|
|
96
|
+
}>;
|
|
97
|
+
/** A callback that may be acknowledged: return a Promise to disable the control until it settles. */
|
|
98
|
+
type ChatAction<A extends unknown[] = []> = (...args: A) => void | Promise<unknown>;
|
|
99
|
+
/** Every visible string, for translation. */
|
|
100
|
+
interface ChatThreadLabels {
|
|
101
|
+
/** The log's `aria-label` when there is no `heading`. */
|
|
102
|
+
log: string;
|
|
103
|
+
loadEarlier: string;
|
|
104
|
+
loadingEarlier: string;
|
|
105
|
+
/** The jump control's text. */
|
|
106
|
+
newMessages: (count: number) => string;
|
|
107
|
+
internal: string;
|
|
108
|
+
pending: string;
|
|
109
|
+
failed: string;
|
|
110
|
+
proposal: string;
|
|
111
|
+
accept: string;
|
|
112
|
+
reject: string;
|
|
113
|
+
accepted: string;
|
|
114
|
+
rejected: string;
|
|
115
|
+
withdrawn: string;
|
|
116
|
+
attachments: string;
|
|
117
|
+
/** Role names shown when a message has no `author`. */
|
|
118
|
+
roles: Record<string, string>;
|
|
119
|
+
}
|
|
120
|
+
/** Content options passed to every message's `ContentRenderer`. `unsafe` is deliberately absent. */
|
|
121
|
+
type ChatContentOptions = Pick<ContentRendererProps, "extensions" | "copyButtons" | "onCopy" | "clipboardWriter" | "lineSpacing">;
|
|
122
|
+
interface ChatMessageClassNames {
|
|
123
|
+
message?: string;
|
|
124
|
+
bubble?: string;
|
|
125
|
+
header?: string;
|
|
126
|
+
actions?: string;
|
|
127
|
+
proposal?: string;
|
|
128
|
+
}
|
|
129
|
+
/** Display options shared by `ChatThread` and a standalone `ChatMessage`. */
|
|
130
|
+
interface ChatMessageDisplayProps {
|
|
131
|
+
/** Roles aligned as the viewer's own. @default ["user"] */
|
|
132
|
+
ownRoles?: string[];
|
|
133
|
+
/**
|
|
134
|
+
* How a message with `status: "streaming"` renders its unfinished tail
|
|
135
|
+
* (`ContentRenderer`'s `streaming`). `true` holds back an open fence or tag;
|
|
136
|
+
* `"progressive"` shows it as it fills. @default true
|
|
137
|
+
*/
|
|
138
|
+
streaming?: true | "progressive";
|
|
139
|
+
contentOptions?: ChatContentOptions;
|
|
140
|
+
labels?: Partial<ChatThreadLabels>;
|
|
141
|
+
/** Formats a message time. Default: locale time, hours and minutes. */
|
|
142
|
+
formatTime?: (date: Date) => string;
|
|
143
|
+
/** Replace how one attachment renders (it is still wrapped in `[data-chat-attachment]`). */
|
|
144
|
+
renderAttachment?: (attachment: ChatAttachment, message: ChatMessageData) => ReactNode;
|
|
145
|
+
onProposalAccept?: ChatAction<[message: ChatMessageData]>;
|
|
146
|
+
onProposalReject?: ChatAction<[message: ChatMessageData]>;
|
|
147
|
+
onActivity?: (event: ChatThreadActivity) => void;
|
|
148
|
+
/**
|
|
149
|
+
* Called when a Promise returned by `onLoadEarlier`, `onProposalAccept` or
|
|
150
|
+
* `onProposalReject` rejects. Without it the rejection is left unhandled,
|
|
151
|
+
* so it still reaches the console rather than vanishing.
|
|
152
|
+
*/
|
|
153
|
+
onActionError?: (error: unknown, action: ChatThreadActionContext) => void;
|
|
154
|
+
classNames?: ChatMessageClassNames;
|
|
155
|
+
}
|
|
156
|
+
interface ChatMessageProps extends ChatMessageDisplayProps {
|
|
157
|
+
message: ChatMessageData;
|
|
158
|
+
/** The per-message actions slot (copy, edit, retry, ...). */
|
|
159
|
+
actions?: ReactNode;
|
|
160
|
+
/** A continuation of the previous message's group: the header is omitted. */
|
|
161
|
+
grouped?: boolean;
|
|
162
|
+
className?: string;
|
|
163
|
+
}
|
|
164
|
+
interface ChatThreadClassNames extends ChatMessageClassNames {
|
|
165
|
+
root?: string;
|
|
166
|
+
heading?: string;
|
|
167
|
+
log?: string;
|
|
168
|
+
composer?: string;
|
|
169
|
+
separator?: string;
|
|
170
|
+
jump?: string;
|
|
171
|
+
}
|
|
172
|
+
/** Imperative handle, for a host or an agent bridge pointing at a message. */
|
|
173
|
+
interface ChatThreadHandle {
|
|
174
|
+
/** Scroll the log (only the log) to the newest message. */
|
|
175
|
+
scrollToLatest(): void;
|
|
176
|
+
/** Scroll the log (only the log) to a message. `false` if no such message is rendered. */
|
|
177
|
+
scrollToMessage(id: string): boolean;
|
|
178
|
+
/** The log element. */
|
|
179
|
+
readonly element: HTMLDivElement | null;
|
|
180
|
+
}
|
|
181
|
+
interface ChatThreadProps extends ChatMessageDisplayProps, Omit<HTMLAttributes<HTMLDivElement>, "children" | "onChange"> {
|
|
182
|
+
ref?: Ref<ChatThreadHandle>;
|
|
183
|
+
/** The messages, oldest first. Controlled: the thread renders exactly these. */
|
|
184
|
+
messages: ChatMessageData[];
|
|
185
|
+
/** Visible title; the log is labelled by it. Without it the log gets `labels.log`. */
|
|
186
|
+
heading?: ReactNode;
|
|
187
|
+
/** @default 2 */
|
|
188
|
+
headingLevel?: 2 | 3 | 4 | 5 | 6;
|
|
189
|
+
/** Shows a "Load earlier messages" control. Return a Promise to disable it until it settles. */
|
|
190
|
+
onLoadEarlier?: ChatAction;
|
|
191
|
+
/** Whether there is anything earlier to load. @default true when `onLoadEarlier` is set */
|
|
192
|
+
hasEarlier?: boolean;
|
|
193
|
+
/** Host-controlled loading state for the load-earlier control. */
|
|
194
|
+
loadingEarlier?: boolean;
|
|
195
|
+
/** Follow new messages while the reader is at the bottom. @default true */
|
|
196
|
+
stickToBottom?: boolean;
|
|
197
|
+
/** How close to the bottom (px) still counts as "at the bottom". @default 48 */
|
|
198
|
+
bottomThreshold?: number;
|
|
199
|
+
/** Called when the reader arrives at or leaves the bottom. */
|
|
200
|
+
onAtBottomChange?: (atBottom: boolean) => void;
|
|
201
|
+
/** `"day"` inserts a separator at each calendar-day change (local time). @default "none" */
|
|
202
|
+
separators?: "none" | "day";
|
|
203
|
+
/** Formats a day separator. Default: locale date, medium style. */
|
|
204
|
+
formatDay?: (date: Date) => string;
|
|
205
|
+
/**
|
|
206
|
+
* Merge consecutive messages from the same author: `true` within 5 minutes,
|
|
207
|
+
* or a window in milliseconds. Internal and public messages never merge.
|
|
208
|
+
* @default false
|
|
209
|
+
*/
|
|
210
|
+
groupConsecutive?: boolean | number;
|
|
211
|
+
/** The per-message actions slot. Return `null` for none. */
|
|
212
|
+
renderActions?: (message: ChatMessageData) => ReactNode;
|
|
213
|
+
/** Rendered below the log: put a `Composer` or `PromptInput` here. */
|
|
214
|
+
composer?: ReactNode;
|
|
215
|
+
/** Shown in the log when there are no messages. */
|
|
216
|
+
empty?: ReactNode;
|
|
217
|
+
classNames?: ChatThreadClassNames;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* ChatThread — a controlled message list for agent and support conversations.
|
|
222
|
+
*
|
|
223
|
+
* - **Controlled.** It renders exactly `messages`, oldest first. Loading
|
|
224
|
+
* earlier history and deciding a proposal go through callbacks; nothing is
|
|
225
|
+
* held internally that an agent would need to read or write.
|
|
226
|
+
* - **Stick to the bottom without yanking.** New messages are followed only
|
|
227
|
+
* while the reader is at the bottom. A reader who scrolled up stays put and
|
|
228
|
+
* gets an "N new messages" jump control. Prepended history keeps the
|
|
229
|
+
* reader's place. Only the log's own `scrollTop` is ever set, and focus moves
|
|
230
|
+
* with `preventScroll`, so no ancestor (or the page) scrolls (the 5.69 rule).
|
|
231
|
+
* - **Visibility is the host's.** `visibility: "internal"` is labelled and
|
|
232
|
+
* styled, never filtered: pass only what the viewer may see.
|
|
233
|
+
* - **Handles:** `data-react-fancy-chat-thread`, `data-chat-message="<id>"`,
|
|
234
|
+
* `data-chat-role`, `data-chat-status`, `data-chat-visibility`,
|
|
235
|
+
* `data-chat-proposal="<id>"`, `data-chat-proposal-action`.
|
|
236
|
+
* - **Observable:** `onActivity` reports every interaction as one stream.
|
|
237
|
+
*
|
|
238
|
+
* Pair it with `Composer` or `PromptInput` in the `composer` slot (both have
|
|
239
|
+
* acknowledged send). It does not ship an input of its own.
|
|
240
|
+
*/
|
|
241
|
+
declare function ChatThread({ ref, messages, heading, headingLevel, onLoadEarlier, hasEarlier, loadingEarlier, stickToBottom, bottomThreshold, onAtBottomChange, separators, formatDay, groupConsecutive, renderActions, composer, empty, classNames, className, ownRoles, streaming, contentOptions, labels: labelsProp, formatTime, renderAttachment, onProposalAccept, onProposalReject, onActivity, onActionError, onScroll: onScrollProp, ...rest }: ChatThreadProps): react.JSX.Element;
|
|
242
|
+
declare namespace ChatThread {
|
|
243
|
+
var displayName: string;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* ChatMessage — one message of a `ChatThread`, usable on its own.
|
|
248
|
+
*
|
|
249
|
+
* Content is markdown through `ContentRenderer`, always sanitised (there is no
|
|
250
|
+
* `unsafe` here on purpose: message bodies are text the host did not author).
|
|
251
|
+
* `format: "text"` renders it literally. A message with a `proposal` is an
|
|
252
|
+
* approval card: the host owns its state and decides it through
|
|
253
|
+
* `onProposalAccept` / `onProposalReject`; the card never acts on its own.
|
|
254
|
+
*/
|
|
255
|
+
declare function ChatMessage({ message, actions, grouped, className, ownRoles, streaming, contentOptions, labels: labelsProp, formatTime, renderAttachment, onProposalAccept, onProposalReject, onActivity, onActionError, classNames, }: ChatMessageProps): react.JSX.Element;
|
|
256
|
+
declare namespace ChatMessage {
|
|
257
|
+
var displayName: string;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export { type ChatAction, type ChatAttachment, type ChatAuthor, type ChatContentOptions, ChatMessage, type ChatMessageClassNames, type ChatMessageData, type ChatMessageDisplayProps, type ChatMessageProps, type ChatMessageStatus, type ChatMessageVisibility, type ChatProposal, type ChatRole, ChatThread, type ChatThreadActionContext, type ChatThreadActivity, type ChatThreadClassNames, type ChatThreadHandle, type ChatThreadLabels, type ChatThreadProps };
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode, HTMLAttributes, Ref } from 'react';
|
|
3
|
+
import { d as ContentRendererProps } from './ContentRenderer.types-RO_l7_6N.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Who a message is from. The named roles get default labels and styling; any
|
|
7
|
+
* other string is carried verbatim (`data-chat-role`) and rendered neutrally.
|
|
8
|
+
*/
|
|
9
|
+
type ChatRole = "user" | "assistant" | "system" | "agent" | "staff" | "customer" | (string & {});
|
|
10
|
+
type ChatMessageStatus = "pending" | "streaming" | "sent" | "failed";
|
|
11
|
+
/**
|
|
12
|
+
* `internal` is a staff-only note. The component LABELS it; it never decides
|
|
13
|
+
* who sees it. Pass only the messages the viewer is allowed to see.
|
|
14
|
+
*/
|
|
15
|
+
type ChatMessageVisibility = "public" | "internal";
|
|
16
|
+
interface ChatAuthor {
|
|
17
|
+
name: string;
|
|
18
|
+
/** Image URL for the avatar. Without it, initials are shown. */
|
|
19
|
+
avatar?: string;
|
|
20
|
+
}
|
|
21
|
+
/** A file on a message. Rendered as a link, never auto-loaded inline. */
|
|
22
|
+
interface ChatAttachment {
|
|
23
|
+
id: string;
|
|
24
|
+
name: string;
|
|
25
|
+
/** Unsafe schemes (`javascript:`, `data:`, ...) render the name without a link. */
|
|
26
|
+
url?: string;
|
|
27
|
+
mimeType?: string;
|
|
28
|
+
/** Bytes. */
|
|
29
|
+
size?: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* An agent's suggested action awaiting a human: an approval card. The message
|
|
33
|
+
* `content` is the draft (a reply, a field change, a page edit). The state is
|
|
34
|
+
* the HOST's: the component shows decision buttons only while `pending`, and
|
|
35
|
+
* never changes the state itself.
|
|
36
|
+
*/
|
|
37
|
+
interface ChatProposal {
|
|
38
|
+
/** Stable id, rendered as `data-chat-proposal`. Usually the card id. */
|
|
39
|
+
id: string;
|
|
40
|
+
title?: string;
|
|
41
|
+
/** @default "pending" */
|
|
42
|
+
state?: "pending" | "accepted" | "rejected" | "withdrawn";
|
|
43
|
+
/** Overrides the thread's accept / reject labels for this card. */
|
|
44
|
+
acceptLabel?: string;
|
|
45
|
+
rejectLabel?: string;
|
|
46
|
+
}
|
|
47
|
+
/** One message. Plain JSON: an agent can emit it, a server can send it. */
|
|
48
|
+
interface ChatMessageData {
|
|
49
|
+
/** Stable id, rendered as `data-chat-message`. */
|
|
50
|
+
id: string;
|
|
51
|
+
role: ChatRole;
|
|
52
|
+
author?: ChatAuthor;
|
|
53
|
+
/** Markdown by default; see `format`. Always sanitised. */
|
|
54
|
+
content: string;
|
|
55
|
+
/** `"text"` renders the content literally (no markdown, no HTML). @default "markdown" */
|
|
56
|
+
format?: "markdown" | "text";
|
|
57
|
+
/** ISO 8601 string or epoch milliseconds. */
|
|
58
|
+
createdAt: string | number;
|
|
59
|
+
/** @default "sent" */
|
|
60
|
+
status?: ChatMessageStatus;
|
|
61
|
+
/** @default "public" */
|
|
62
|
+
visibility?: ChatMessageVisibility;
|
|
63
|
+
attachments?: ChatAttachment[];
|
|
64
|
+
/** Makes this message an approval card. */
|
|
65
|
+
proposal?: ChatProposal;
|
|
66
|
+
/**
|
|
67
|
+
* Align as the viewer's own message. Defaults to `ownRoles` containing
|
|
68
|
+
* `role`.
|
|
69
|
+
*/
|
|
70
|
+
own?: boolean;
|
|
71
|
+
/** Anything the host wants carried along (card version, ticket ref, ...). Not rendered. */
|
|
72
|
+
meta?: Record<string, unknown>;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Every human interaction the thread hands to a callback, as one event stream
|
|
76
|
+
* for presence, undo and coaching layers. Map it onto fancy-auto-common's
|
|
77
|
+
* `AutoActivityEvent` (or anything else) in the host.
|
|
78
|
+
*/
|
|
79
|
+
type ChatThreadActivity = {
|
|
80
|
+
type: "load-earlier";
|
|
81
|
+
} | {
|
|
82
|
+
type: "proposal-accept";
|
|
83
|
+
messageId: string;
|
|
84
|
+
proposalId: string;
|
|
85
|
+
} | {
|
|
86
|
+
type: "proposal-reject";
|
|
87
|
+
messageId: string;
|
|
88
|
+
proposalId: string;
|
|
89
|
+
} | {
|
|
90
|
+
type: "jump-to-latest";
|
|
91
|
+
unseen: number;
|
|
92
|
+
};
|
|
93
|
+
/** What `onActionError` is told about: the action whose Promise rejected. */
|
|
94
|
+
type ChatThreadActionContext = Exclude<ChatThreadActivity, {
|
|
95
|
+
type: "jump-to-latest";
|
|
96
|
+
}>;
|
|
97
|
+
/** A callback that may be acknowledged: return a Promise to disable the control until it settles. */
|
|
98
|
+
type ChatAction<A extends unknown[] = []> = (...args: A) => void | Promise<unknown>;
|
|
99
|
+
/** Every visible string, for translation. */
|
|
100
|
+
interface ChatThreadLabels {
|
|
101
|
+
/** The log's `aria-label` when there is no `heading`. */
|
|
102
|
+
log: string;
|
|
103
|
+
loadEarlier: string;
|
|
104
|
+
loadingEarlier: string;
|
|
105
|
+
/** The jump control's text. */
|
|
106
|
+
newMessages: (count: number) => string;
|
|
107
|
+
internal: string;
|
|
108
|
+
pending: string;
|
|
109
|
+
failed: string;
|
|
110
|
+
proposal: string;
|
|
111
|
+
accept: string;
|
|
112
|
+
reject: string;
|
|
113
|
+
accepted: string;
|
|
114
|
+
rejected: string;
|
|
115
|
+
withdrawn: string;
|
|
116
|
+
attachments: string;
|
|
117
|
+
/** Role names shown when a message has no `author`. */
|
|
118
|
+
roles: Record<string, string>;
|
|
119
|
+
}
|
|
120
|
+
/** Content options passed to every message's `ContentRenderer`. `unsafe` is deliberately absent. */
|
|
121
|
+
type ChatContentOptions = Pick<ContentRendererProps, "extensions" | "copyButtons" | "onCopy" | "clipboardWriter" | "lineSpacing">;
|
|
122
|
+
interface ChatMessageClassNames {
|
|
123
|
+
message?: string;
|
|
124
|
+
bubble?: string;
|
|
125
|
+
header?: string;
|
|
126
|
+
actions?: string;
|
|
127
|
+
proposal?: string;
|
|
128
|
+
}
|
|
129
|
+
/** Display options shared by `ChatThread` and a standalone `ChatMessage`. */
|
|
130
|
+
interface ChatMessageDisplayProps {
|
|
131
|
+
/** Roles aligned as the viewer's own. @default ["user"] */
|
|
132
|
+
ownRoles?: string[];
|
|
133
|
+
/**
|
|
134
|
+
* How a message with `status: "streaming"` renders its unfinished tail
|
|
135
|
+
* (`ContentRenderer`'s `streaming`). `true` holds back an open fence or tag;
|
|
136
|
+
* `"progressive"` shows it as it fills. @default true
|
|
137
|
+
*/
|
|
138
|
+
streaming?: true | "progressive";
|
|
139
|
+
contentOptions?: ChatContentOptions;
|
|
140
|
+
labels?: Partial<ChatThreadLabels>;
|
|
141
|
+
/** Formats a message time. Default: locale time, hours and minutes. */
|
|
142
|
+
formatTime?: (date: Date) => string;
|
|
143
|
+
/** Replace how one attachment renders (it is still wrapped in `[data-chat-attachment]`). */
|
|
144
|
+
renderAttachment?: (attachment: ChatAttachment, message: ChatMessageData) => ReactNode;
|
|
145
|
+
onProposalAccept?: ChatAction<[message: ChatMessageData]>;
|
|
146
|
+
onProposalReject?: ChatAction<[message: ChatMessageData]>;
|
|
147
|
+
onActivity?: (event: ChatThreadActivity) => void;
|
|
148
|
+
/**
|
|
149
|
+
* Called when a Promise returned by `onLoadEarlier`, `onProposalAccept` or
|
|
150
|
+
* `onProposalReject` rejects. Without it the rejection is left unhandled,
|
|
151
|
+
* so it still reaches the console rather than vanishing.
|
|
152
|
+
*/
|
|
153
|
+
onActionError?: (error: unknown, action: ChatThreadActionContext) => void;
|
|
154
|
+
classNames?: ChatMessageClassNames;
|
|
155
|
+
}
|
|
156
|
+
interface ChatMessageProps extends ChatMessageDisplayProps {
|
|
157
|
+
message: ChatMessageData;
|
|
158
|
+
/** The per-message actions slot (copy, edit, retry, ...). */
|
|
159
|
+
actions?: ReactNode;
|
|
160
|
+
/** A continuation of the previous message's group: the header is omitted. */
|
|
161
|
+
grouped?: boolean;
|
|
162
|
+
className?: string;
|
|
163
|
+
}
|
|
164
|
+
interface ChatThreadClassNames extends ChatMessageClassNames {
|
|
165
|
+
root?: string;
|
|
166
|
+
heading?: string;
|
|
167
|
+
log?: string;
|
|
168
|
+
composer?: string;
|
|
169
|
+
separator?: string;
|
|
170
|
+
jump?: string;
|
|
171
|
+
}
|
|
172
|
+
/** Imperative handle, for a host or an agent bridge pointing at a message. */
|
|
173
|
+
interface ChatThreadHandle {
|
|
174
|
+
/** Scroll the log (only the log) to the newest message. */
|
|
175
|
+
scrollToLatest(): void;
|
|
176
|
+
/** Scroll the log (only the log) to a message. `false` if no such message is rendered. */
|
|
177
|
+
scrollToMessage(id: string): boolean;
|
|
178
|
+
/** The log element. */
|
|
179
|
+
readonly element: HTMLDivElement | null;
|
|
180
|
+
}
|
|
181
|
+
interface ChatThreadProps extends ChatMessageDisplayProps, Omit<HTMLAttributes<HTMLDivElement>, "children" | "onChange"> {
|
|
182
|
+
ref?: Ref<ChatThreadHandle>;
|
|
183
|
+
/** The messages, oldest first. Controlled: the thread renders exactly these. */
|
|
184
|
+
messages: ChatMessageData[];
|
|
185
|
+
/** Visible title; the log is labelled by it. Without it the log gets `labels.log`. */
|
|
186
|
+
heading?: ReactNode;
|
|
187
|
+
/** @default 2 */
|
|
188
|
+
headingLevel?: 2 | 3 | 4 | 5 | 6;
|
|
189
|
+
/** Shows a "Load earlier messages" control. Return a Promise to disable it until it settles. */
|
|
190
|
+
onLoadEarlier?: ChatAction;
|
|
191
|
+
/** Whether there is anything earlier to load. @default true when `onLoadEarlier` is set */
|
|
192
|
+
hasEarlier?: boolean;
|
|
193
|
+
/** Host-controlled loading state for the load-earlier control. */
|
|
194
|
+
loadingEarlier?: boolean;
|
|
195
|
+
/** Follow new messages while the reader is at the bottom. @default true */
|
|
196
|
+
stickToBottom?: boolean;
|
|
197
|
+
/** How close to the bottom (px) still counts as "at the bottom". @default 48 */
|
|
198
|
+
bottomThreshold?: number;
|
|
199
|
+
/** Called when the reader arrives at or leaves the bottom. */
|
|
200
|
+
onAtBottomChange?: (atBottom: boolean) => void;
|
|
201
|
+
/** `"day"` inserts a separator at each calendar-day change (local time). @default "none" */
|
|
202
|
+
separators?: "none" | "day";
|
|
203
|
+
/** Formats a day separator. Default: locale date, medium style. */
|
|
204
|
+
formatDay?: (date: Date) => string;
|
|
205
|
+
/**
|
|
206
|
+
* Merge consecutive messages from the same author: `true` within 5 minutes,
|
|
207
|
+
* or a window in milliseconds. Internal and public messages never merge.
|
|
208
|
+
* @default false
|
|
209
|
+
*/
|
|
210
|
+
groupConsecutive?: boolean | number;
|
|
211
|
+
/** The per-message actions slot. Return `null` for none. */
|
|
212
|
+
renderActions?: (message: ChatMessageData) => ReactNode;
|
|
213
|
+
/** Rendered below the log: put a `Composer` or `PromptInput` here. */
|
|
214
|
+
composer?: ReactNode;
|
|
215
|
+
/** Shown in the log when there are no messages. */
|
|
216
|
+
empty?: ReactNode;
|
|
217
|
+
classNames?: ChatThreadClassNames;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* ChatThread — a controlled message list for agent and support conversations.
|
|
222
|
+
*
|
|
223
|
+
* - **Controlled.** It renders exactly `messages`, oldest first. Loading
|
|
224
|
+
* earlier history and deciding a proposal go through callbacks; nothing is
|
|
225
|
+
* held internally that an agent would need to read or write.
|
|
226
|
+
* - **Stick to the bottom without yanking.** New messages are followed only
|
|
227
|
+
* while the reader is at the bottom. A reader who scrolled up stays put and
|
|
228
|
+
* gets an "N new messages" jump control. Prepended history keeps the
|
|
229
|
+
* reader's place. Only the log's own `scrollTop` is ever set, and focus moves
|
|
230
|
+
* with `preventScroll`, so no ancestor (or the page) scrolls (the 5.69 rule).
|
|
231
|
+
* - **Visibility is the host's.** `visibility: "internal"` is labelled and
|
|
232
|
+
* styled, never filtered: pass only what the viewer may see.
|
|
233
|
+
* - **Handles:** `data-react-fancy-chat-thread`, `data-chat-message="<id>"`,
|
|
234
|
+
* `data-chat-role`, `data-chat-status`, `data-chat-visibility`,
|
|
235
|
+
* `data-chat-proposal="<id>"`, `data-chat-proposal-action`.
|
|
236
|
+
* - **Observable:** `onActivity` reports every interaction as one stream.
|
|
237
|
+
*
|
|
238
|
+
* Pair it with `Composer` or `PromptInput` in the `composer` slot (both have
|
|
239
|
+
* acknowledged send). It does not ship an input of its own.
|
|
240
|
+
*/
|
|
241
|
+
declare function ChatThread({ ref, messages, heading, headingLevel, onLoadEarlier, hasEarlier, loadingEarlier, stickToBottom, bottomThreshold, onAtBottomChange, separators, formatDay, groupConsecutive, renderActions, composer, empty, classNames, className, ownRoles, streaming, contentOptions, labels: labelsProp, formatTime, renderAttachment, onProposalAccept, onProposalReject, onActivity, onActionError, onScroll: onScrollProp, ...rest }: ChatThreadProps): react.JSX.Element;
|
|
242
|
+
declare namespace ChatThread {
|
|
243
|
+
var displayName: string;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* ChatMessage — one message of a `ChatThread`, usable on its own.
|
|
248
|
+
*
|
|
249
|
+
* Content is markdown through `ContentRenderer`, always sanitised (there is no
|
|
250
|
+
* `unsafe` here on purpose: message bodies are text the host did not author).
|
|
251
|
+
* `format: "text"` renders it literally. A message with a `proposal` is an
|
|
252
|
+
* approval card: the host owns its state and decides it through
|
|
253
|
+
* `onProposalAccept` / `onProposalReject`; the card never acts on its own.
|
|
254
|
+
*/
|
|
255
|
+
declare function ChatMessage({ message, actions, grouped, className, ownRoles, streaming, contentOptions, labels: labelsProp, formatTime, renderAttachment, onProposalAccept, onProposalReject, onActivity, onActionError, classNames, }: ChatMessageProps): react.JSX.Element;
|
|
256
|
+
declare namespace ChatMessage {
|
|
257
|
+
var displayName: string;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export { type ChatAction, type ChatAttachment, type ChatAuthor, type ChatContentOptions, ChatMessage, type ChatMessageClassNames, type ChatMessageData, type ChatMessageDisplayProps, type ChatMessageProps, type ChatMessageStatus, type ChatMessageVisibility, type ChatProposal, type ChatRole, ChatThread, type ChatThreadActionContext, type ChatThreadActivity, type ChatThreadClassNames, type ChatThreadHandle, type ChatThreadLabels, type ChatThreadProps };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { ChatMessage, ChatThread } from './chunk-UWYSJARZ.js';
|
|
2
|
+
import './chunk-AUTW5O4W.js';
|
|
3
|
+
import './chunk-NAYXNVNU.js';
|
|
4
|
+
import './chunk-I3LAFKJU.js';
|
|
5
|
+
import './chunk-UZCR7DK5.js';
|
|
6
|
+
import './chunk-IQ4KQJAO.js';
|
|
7
|
+
import './chunk-6FCQD2KQ.js';
|
|
8
|
+
import './chunk-LQ4ICCN2.js';
|
|
9
|
+
import './chunk-OXERDFFF.js';
|
|
10
|
+
import './chunk-45BBNJQD.js';
|
|
11
|
+
import './chunk-J3A4Z2P7.js';
|
|
12
|
+
import './chunk-MMW2JGKZ.js';
|
|
13
|
+
//# sourceMappingURL=chat-thread.js.map
|
|
14
|
+
//# sourceMappingURL=chat-thread.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"chat-thread.js"}
|