@sensiblestats/widget-react 0.0.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/dist/index.cjs +479 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +34 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +441 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +102 -0
- package/package.json +63 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
StatsWidget: () => StatsWidget,
|
|
34
|
+
WIDGET_CSS: () => WIDGET_CSS
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(index_exports);
|
|
37
|
+
|
|
38
|
+
// src/StatsWidget.tsx
|
|
39
|
+
var import_react5 = require("react");
|
|
40
|
+
var import_widget_sdk3 = require("@sensiblestats/widget-sdk");
|
|
41
|
+
|
|
42
|
+
// src/config.ts
|
|
43
|
+
function normalizeUi(cfg) {
|
|
44
|
+
return {
|
|
45
|
+
theme: cfg.theme ?? "auto",
|
|
46
|
+
accent: cfg.accent,
|
|
47
|
+
position: cfg.position ?? "right",
|
|
48
|
+
offset: { x: cfg.offset?.x ?? 20, y: cfg.offset?.y ?? 20 },
|
|
49
|
+
radius: cfg.radius ?? 16,
|
|
50
|
+
launcherLabel: cfg.launcherLabel ?? "Chat with SensibleStats",
|
|
51
|
+
greeting: cfg.greeting,
|
|
52
|
+
placeholder: cfg.placeholder ?? "Ask about a team, player or match\u2026",
|
|
53
|
+
starters: cfg.starters ?? [],
|
|
54
|
+
injectStyles: cfg.injectStyles ?? true
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function toClientOptions(cfg) {
|
|
58
|
+
const opts = { operatorId: cfg.operatorId, publicKey: cfg.publicKey };
|
|
59
|
+
if (cfg.baseUrl !== void 0) opts.baseUrl = cfg.baseUrl;
|
|
60
|
+
return opts;
|
|
61
|
+
}
|
|
62
|
+
function toUserContext(cfg) {
|
|
63
|
+
return cfg.userContext && Object.keys(cfg.userContext).length > 0 ? cfg.userContext : void 0;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/theme.ts
|
|
67
|
+
function themeAttrs(ui) {
|
|
68
|
+
const style = {
|
|
69
|
+
"--ss-w-offset-x": `${ui.offset.x}px`,
|
|
70
|
+
"--ss-w-offset-y": `${ui.offset.y}px`,
|
|
71
|
+
"--ss-w-radius": `${ui.radius}px`
|
|
72
|
+
};
|
|
73
|
+
if (ui.accent) style["--ss-w-accent"] = ui.accent;
|
|
74
|
+
return { "data-ss-w-theme": ui.theme, "data-ss-w-pos": ui.position, style };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/useChatStream.ts
|
|
78
|
+
var import_react = require("react");
|
|
79
|
+
var import_widget_sdk2 = require("@sensiblestats/widget-sdk");
|
|
80
|
+
|
|
81
|
+
// src/reducer.ts
|
|
82
|
+
var import_widget_sdk = require("@sensiblestats/widget-sdk");
|
|
83
|
+
|
|
84
|
+
// src/model.ts
|
|
85
|
+
function str(v) {
|
|
86
|
+
return typeof v === "string" && v.length > 0 ? v : void 0;
|
|
87
|
+
}
|
|
88
|
+
function num(v) {
|
|
89
|
+
return typeof v === "number" && Number.isFinite(v) ? String(v) : void 0;
|
|
90
|
+
}
|
|
91
|
+
var STAT_KEYS = [
|
|
92
|
+
["goals", "Goals"],
|
|
93
|
+
["assists", "Assists"],
|
|
94
|
+
["appearances", "Apps"],
|
|
95
|
+
["xg", "xG"],
|
|
96
|
+
["form", "Form"],
|
|
97
|
+
["rating", "Rating"]
|
|
98
|
+
];
|
|
99
|
+
function readStats(card) {
|
|
100
|
+
const cells = [];
|
|
101
|
+
for (const [key, label] of STAT_KEYS) {
|
|
102
|
+
const value = num(card[key]) ?? str(card[key]);
|
|
103
|
+
if (value !== void 0) cells.push({ label, value });
|
|
104
|
+
}
|
|
105
|
+
return cells;
|
|
106
|
+
}
|
|
107
|
+
function toCardVM(card) {
|
|
108
|
+
const kind = card.entityType === "Player" ? "player" : card.entityType === "Team" ? "team" : "generic";
|
|
109
|
+
return {
|
|
110
|
+
id: String(card.entityId),
|
|
111
|
+
kind,
|
|
112
|
+
name: card.canonicalName,
|
|
113
|
+
image: str(card.imageUrl) ?? str(card.image_url) ?? str(card.logoUrl) ?? str(card.logo),
|
|
114
|
+
sub: str(card.subtitle) ?? str(card.teamName) ?? str(card.leagueName) ?? str(card.position),
|
|
115
|
+
stats: readStats(card),
|
|
116
|
+
query: card.canonicalName
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function toActionVM(action) {
|
|
120
|
+
const label = str(action.label) ?? str(action.text) ?? str(action.title) ?? "Continue";
|
|
121
|
+
const actionId = str(action.id) ?? str(action.actionId);
|
|
122
|
+
const message = str(action.message) ?? str(action.query) ?? label;
|
|
123
|
+
return { label, actionId, message };
|
|
124
|
+
}
|
|
125
|
+
function toChipVM(intent) {
|
|
126
|
+
const text = str(intent.text) ?? str(intent.label) ?? str(intent.title);
|
|
127
|
+
return text ? { text } : null;
|
|
128
|
+
}
|
|
129
|
+
function chipFromText(text) {
|
|
130
|
+
return { text };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// src/reducer.ts
|
|
134
|
+
function initialState(starters) {
|
|
135
|
+
return { isOpen: false, messages: [], isStreaming: false, status: null, actionsLoading: false, starters, error: null, lastUserInput: null };
|
|
136
|
+
}
|
|
137
|
+
function mapActive(state, fn) {
|
|
138
|
+
const last = state.messages[state.messages.length - 1];
|
|
139
|
+
if (!last || last.role !== "assistant" || last.done) return state.messages;
|
|
140
|
+
return [...state.messages.slice(0, -1), fn(last)];
|
|
141
|
+
}
|
|
142
|
+
function applyEvent(state, event) {
|
|
143
|
+
switch (event.type) {
|
|
144
|
+
case "progress":
|
|
145
|
+
return { ...state, status: event.data.message };
|
|
146
|
+
case "answer":
|
|
147
|
+
return { ...state, messages: mapActive(state, (t) => ({ ...t, text: t.text + event.data.text })) };
|
|
148
|
+
case "entity_card":
|
|
149
|
+
return { ...state, messages: mapActive(state, (t) => ({ ...t, cards: [...t.cards, toCardVM(event.data.card)] })) };
|
|
150
|
+
case "action_button":
|
|
151
|
+
return { ...state, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, actions: [...t.actions, toActionVM(event.data.action)] })) };
|
|
152
|
+
case "intent_chip": {
|
|
153
|
+
const chip = toChipVM(event.data.intent);
|
|
154
|
+
return chip ? { ...state, starters: [...state.starters, chip] } : state;
|
|
155
|
+
}
|
|
156
|
+
case "actions_loading":
|
|
157
|
+
return { ...state, actionsLoading: true, status: event.data.message };
|
|
158
|
+
case "turn_complete":
|
|
159
|
+
return { ...state, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) };
|
|
160
|
+
case "error":
|
|
161
|
+
return { ...state, error: event.data, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) };
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
function reducer(state, action) {
|
|
165
|
+
switch (action.kind) {
|
|
166
|
+
case "OPEN":
|
|
167
|
+
return { ...state, isOpen: true };
|
|
168
|
+
case "CLOSE":
|
|
169
|
+
return { ...state, isOpen: false, isStreaming: false, status: null, actionsLoading: false };
|
|
170
|
+
case "USER_SENT": {
|
|
171
|
+
const user = { role: "user", id: action.userId, text: action.input.message };
|
|
172
|
+
const assistant = { role: "assistant", id: action.assistantId, text: "", cards: [], actions: [], done: false };
|
|
173
|
+
return { ...state, messages: [...state.messages, user, assistant], isStreaming: true, status: null, actionsLoading: false, starters: [], error: null, lastUserInput: action.input };
|
|
174
|
+
}
|
|
175
|
+
case "EVENT":
|
|
176
|
+
return applyEvent(state, action.event);
|
|
177
|
+
case "STREAM_ERROR":
|
|
178
|
+
return { ...state, error: action.error, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) };
|
|
179
|
+
case "STOP":
|
|
180
|
+
return { ...state, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) };
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// src/useChatStream.ts
|
|
185
|
+
function useChatStream(conversation, starterTexts) {
|
|
186
|
+
const seed = (0, import_react.useMemo)(() => initialState(starterTexts.map(chipFromText)), []);
|
|
187
|
+
const [state, dispatch] = (0, import_react.useReducer)(reducer, seed);
|
|
188
|
+
const idRef = (0, import_react.useRef)(0);
|
|
189
|
+
const handleRef = (0, import_react.useRef)(null);
|
|
190
|
+
const stateRef = (0, import_react.useRef)(state);
|
|
191
|
+
stateRef.current = state;
|
|
192
|
+
const nextId = () => `m${idRef.current++}`;
|
|
193
|
+
const run = (0, import_react.useCallback)((input) => {
|
|
194
|
+
handleRef.current?.cancel();
|
|
195
|
+
dispatch({ kind: "USER_SENT", input, userId: nextId(), assistantId: nextId() });
|
|
196
|
+
const handle = conversation.send(input);
|
|
197
|
+
handleRef.current = handle;
|
|
198
|
+
(async () => {
|
|
199
|
+
try {
|
|
200
|
+
for await (const event of handle) dispatch({ kind: "EVENT", event });
|
|
201
|
+
} catch (err) {
|
|
202
|
+
if (err instanceof import_widget_sdk2.WidgetSdkError) dispatch({ kind: "STREAM_ERROR", error: err });
|
|
203
|
+
else if (err?.name === "AbortError") {
|
|
204
|
+
} else throw err;
|
|
205
|
+
} finally {
|
|
206
|
+
if (handleRef.current === handle) handleRef.current = null;
|
|
207
|
+
}
|
|
208
|
+
})();
|
|
209
|
+
}, [conversation]);
|
|
210
|
+
const send = (0, import_react.useCallback)((text, actionId) => {
|
|
211
|
+
const trimmed = text.trim();
|
|
212
|
+
if (!trimmed) return;
|
|
213
|
+
run({ message: trimmed, actionId });
|
|
214
|
+
}, [run]);
|
|
215
|
+
const retry = (0, import_react.useCallback)(() => {
|
|
216
|
+
const last = stateRef.current.lastUserInput;
|
|
217
|
+
if (last) run(last);
|
|
218
|
+
}, [run]);
|
|
219
|
+
const open = (0, import_react.useCallback)(() => dispatch({ kind: "OPEN" }), []);
|
|
220
|
+
const close = (0, import_react.useCallback)(() => {
|
|
221
|
+
handleRef.current?.cancel();
|
|
222
|
+
handleRef.current = null;
|
|
223
|
+
dispatch({ kind: "CLOSE" });
|
|
224
|
+
}, []);
|
|
225
|
+
const stop = (0, import_react.useCallback)(() => {
|
|
226
|
+
handleRef.current?.cancel();
|
|
227
|
+
handleRef.current = null;
|
|
228
|
+
dispatch({ kind: "STOP" });
|
|
229
|
+
}, []);
|
|
230
|
+
const toggle = (0, import_react.useCallback)(() => {
|
|
231
|
+
if (stateRef.current.isOpen) close();
|
|
232
|
+
else open();
|
|
233
|
+
}, [close, open]);
|
|
234
|
+
return { state, open, close, stop, toggle, send, retry };
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// src/components/Icons.tsx
|
|
238
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
239
|
+
function SsMark({ className }) {
|
|
240
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { className, viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "#00F400", d: "M12 2l2.5 6.5L21 11l-6.5 2.5L12 20l-2.5-6.5L3 11l6.5-2.5z" }) });
|
|
241
|
+
}
|
|
242
|
+
function SendIcon() {
|
|
243
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "currentColor", d: "M3 20l18-8L3 4v6l12 2-12 2z" }) });
|
|
244
|
+
}
|
|
245
|
+
function CloseIcon() {
|
|
246
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "none", d: "M18 6L6 18M6 6l12 12", stroke: "currentColor", strokeWidth: "2" }) });
|
|
247
|
+
}
|
|
248
|
+
function ChevronIcon() {
|
|
249
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "none", stroke: "currentColor", strokeWidth: "2", d: "M9 6l6 6-6 6" }) });
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// src/components/GreetingBubble.tsx
|
|
253
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
254
|
+
function GreetingBubble({ text }) {
|
|
255
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "ss-w-greeting", role: "note", children: text });
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// src/components/ChatFab.tsx
|
|
259
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
260
|
+
function ChatFab({ label, open, greeting, onToggle }) {
|
|
261
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ss-w-fab-wrap", children: [
|
|
262
|
+
!open && greeting ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(GreetingBubble, { text: greeting }) : null,
|
|
263
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "ss-w-fab", "aria-label": label, "aria-expanded": open, onClick: onToggle, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SsMark, { className: "ss-w-fab-mark" }) })
|
|
264
|
+
] });
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// src/components/ChatPanel.tsx
|
|
268
|
+
var import_react4 = require("react");
|
|
269
|
+
|
|
270
|
+
// src/components/ChatHeader.tsx
|
|
271
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
272
|
+
function ChatHeader({ onClose }) {
|
|
273
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("header", { className: "ss-w-header", children: [
|
|
274
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(SsMark, { className: "ss-w-header-mark" }),
|
|
275
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-w-header-title", children: "SensibleStats" }),
|
|
276
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "ss-w-close", "aria-label": "Close chat", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CloseIcon, {}) })
|
|
277
|
+
] });
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// src/components/MessageList.tsx
|
|
281
|
+
var import_react2 = require("react");
|
|
282
|
+
|
|
283
|
+
// src/components/Markdown.tsx
|
|
284
|
+
var import_react_markdown = __toESM(require("react-markdown"), 1);
|
|
285
|
+
var import_remark_gfm = __toESM(require("remark-gfm"), 1);
|
|
286
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
287
|
+
var components = {
|
|
288
|
+
a: ({ children, href }) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", className: "ss-w-md-link", children }),
|
|
289
|
+
table: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ss-w-table-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("table", { className: "ss-w-md-table", children }) }),
|
|
290
|
+
ul: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { className: "ss-w-md-ul", children }),
|
|
291
|
+
ol: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ol", { className: "ss-w-md-ol", children }),
|
|
292
|
+
code: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { className: "ss-w-md-code", children })
|
|
293
|
+
};
|
|
294
|
+
function Markdown({ text }) {
|
|
295
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ss-w-md", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_markdown.default, { remarkPlugins: [import_remark_gfm.default], components, children: text }) });
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// src/components/EntityCardList.tsx
|
|
299
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
300
|
+
function initials(name) {
|
|
301
|
+
return name.split(/\s+/).slice(0, 2).map((w) => w[0] ?? "").join("").toUpperCase();
|
|
302
|
+
}
|
|
303
|
+
function EntityCardList({ cards, onSelect }) {
|
|
304
|
+
if (cards.length === 0) return null;
|
|
305
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "ss-w-cards", children: cards.map((c) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("button", { type: "button", className: "ss-w-ecard", onClick: () => onSelect(c.query), children: [
|
|
306
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
307
|
+
"span",
|
|
308
|
+
{
|
|
309
|
+
className: c.kind === "team" ? "ss-w-thumb ss-w-team" : "ss-w-thumb",
|
|
310
|
+
style: c.image ? { backgroundImage: `url(${c.image})` } : void 0,
|
|
311
|
+
children: c.image ? "" : initials(c.name)
|
|
312
|
+
}
|
|
313
|
+
),
|
|
314
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ss-w-meta", children: [
|
|
315
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-nm", children: c.name }),
|
|
316
|
+
c.sub ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-sub", children: c.sub }) : null
|
|
317
|
+
] }),
|
|
318
|
+
c.stats.map((s) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ss-w-stat", children: [
|
|
319
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("b", { children: s.value }),
|
|
320
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: s.label })
|
|
321
|
+
] }, s.label)),
|
|
322
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-chev", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChevronIcon, {}) })
|
|
323
|
+
] }, c.id)) });
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// src/components/ActionButtons.tsx
|
|
327
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
328
|
+
function ActionButtons({ actions, loading, onAct }) {
|
|
329
|
+
if (actions.length === 0 && !loading) return null;
|
|
330
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "ss-w-actions", children: [
|
|
331
|
+
actions.map((a, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "ss-w-abtn", onClick: () => onAct(a.message, a.actionId), children: a.label }, `${a.label}-${i}`)),
|
|
332
|
+
actions.length === 0 && loading ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
333
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ss-w-abtn-shimmer" }),
|
|
334
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ss-w-abtn-shimmer" })
|
|
335
|
+
] }) : null
|
|
336
|
+
] });
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// src/components/ChatMessage.tsx
|
|
340
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
341
|
+
function ChatMessage({ message, onAct, onSelect }) {
|
|
342
|
+
if (message.role === "user") {
|
|
343
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "ss-w-bubble", children: message.text }) });
|
|
344
|
+
}
|
|
345
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "ss-w-msg ss-w-bot", children: [
|
|
346
|
+
message.text ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Markdown, { text: message.text }) : null,
|
|
347
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(EntityCardList, { cards: message.cards, onSelect }),
|
|
348
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ActionButtons, { actions: message.actions, loading: false, onAct })
|
|
349
|
+
] });
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// src/components/IntentChips.tsx
|
|
353
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
354
|
+
function IntentChips({ chips, onPick }) {
|
|
355
|
+
if (chips.length === 0) return null;
|
|
356
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// src/components/MessageList.tsx
|
|
360
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
361
|
+
function MessageList({ controller, ui }) {
|
|
362
|
+
void ui;
|
|
363
|
+
const { state, send } = controller;
|
|
364
|
+
const endRef = (0, import_react2.useRef)(null);
|
|
365
|
+
(0, import_react2.useEffect)(() => {
|
|
366
|
+
endRef.current?.scrollIntoView({ block: "end" });
|
|
367
|
+
}, [state.messages, state.status]);
|
|
368
|
+
const empty = state.messages.length === 0;
|
|
369
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ss-w-list", "aria-live": "polite", children: [
|
|
370
|
+
state.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ChatMessage, { message: m, onAct: (msg, id) => send(msg, id), onSelect: (q) => send(q) }, m.id)),
|
|
371
|
+
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ActionButtons, { actions: [], loading: true, onAct: () => {
|
|
372
|
+
} }) : null,
|
|
373
|
+
state.status ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "ss-w-status", children: state.status }) : null,
|
|
374
|
+
state.error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ss-w-error", role: "alert", children: [
|
|
375
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "message" in state.error ? state.error.message : "Something went wrong." }),
|
|
376
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: "Retry" })
|
|
377
|
+
] }) : null,
|
|
378
|
+
empty ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
|
|
379
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { ref: endRef })
|
|
380
|
+
] });
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// src/components/ChatInput.tsx
|
|
384
|
+
var import_react3 = require("react");
|
|
385
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
386
|
+
function ChatInput({ placeholder, streaming, onSend, onStop }) {
|
|
387
|
+
const [value, setValue] = (0, import_react3.useState)("");
|
|
388
|
+
const submit = () => {
|
|
389
|
+
const t = value.trim();
|
|
390
|
+
if (!t) return;
|
|
391
|
+
onSend(t);
|
|
392
|
+
setValue("");
|
|
393
|
+
};
|
|
394
|
+
const onKeyDown = (e) => {
|
|
395
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
396
|
+
e.preventDefault();
|
|
397
|
+
submit();
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ss-w-input", children: [
|
|
401
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, onChange: (e) => setValue(e.target.value), onKeyDown }),
|
|
402
|
+
streaming ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": "Stop response", onClick: onStop, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "ss-w-send", "aria-label": "Send message", onClick: submit, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SendIcon, {}) })
|
|
403
|
+
] });
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// src/components/ChatPanel.tsx
|
|
407
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
408
|
+
function ChatPanel({ controller, ui }) {
|
|
409
|
+
const { state, close, stop, send } = controller;
|
|
410
|
+
(0, import_react4.useEffect)(() => {
|
|
411
|
+
const onKey = (e) => {
|
|
412
|
+
if (e.key === "Escape") close();
|
|
413
|
+
};
|
|
414
|
+
window.addEventListener("keydown", onKey);
|
|
415
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
416
|
+
}, [close]);
|
|
417
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": "true", "aria-label": "SensibleStats chat", children: [
|
|
418
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ChatHeader, { onClose: close }),
|
|
419
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MessageList, { controller, ui }),
|
|
420
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop })
|
|
421
|
+
] });
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// src/styles/css.generated.ts
|
|
425
|
+
var WIDGET_CSS = '.ss-w-root { all: revert; }\n.ss-w-root, .ss-w-root * { box-sizing: border-box; margin: 0; padding: 0; }\n.ss-w-root {\n --ss-w-accent: #17936a;\n --ss-w-ink: #14181d; --ss-w-faint: #6b7580; --ss-w-line: #e4e8ec;\n --ss-w-panel: #ffffff; --ss-w-bubble: #f3f5f7; --ss-w-nav: #0e1622;\n --ss-w-radius: 16px; --ss-w-offset-x: 20px; --ss-w-offset-y: 20px;\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;\n font-size: 13px; line-height: 1.5; color: var(--ss-w-ink);\n}\n@media (prefers-color-scheme: dark) {\n .ss-w-root[data-ss-w-theme="auto"] {\n --ss-w-accent: #37c891; --ss-w-ink: #e8edf2; --ss-w-faint: #8b95a1;\n --ss-w-line: #2a3441; --ss-w-panel: #141b24; --ss-w-bubble: #1e2732; --ss-w-nav: #0a0f16;\n }\n}\n.ss-w-root[data-ss-w-theme="dark"] {\n --ss-w-accent: #37c891; --ss-w-ink: #e8edf2; --ss-w-faint: #8b95a1;\n --ss-w-line: #2a3441; --ss-w-panel: #141b24; --ss-w-bubble: #1e2732; --ss-w-nav: #0a0f16;\n}\n.ss-w-root[data-ss-w-theme="light"] {\n --ss-w-accent: #17936a; --ss-w-ink: #14181d; --ss-w-faint: #6b7580;\n --ss-w-line: #e4e8ec; --ss-w-panel: #ffffff; --ss-w-bubble: #f3f5f7; --ss-w-nav: #0e1622;\n}\n\n/* launcher */\n.ss-w-fab-wrap { position: fixed; bottom: var(--ss-w-offset-y); z-index: 2147483000; display: flex; flex-direction: column; align-items: flex-end; gap: 10px; }\n.ss-w-root[data-ss-w-pos="right"] .ss-w-fab-wrap { right: var(--ss-w-offset-x); }\n.ss-w-root[data-ss-w-pos="left"] .ss-w-fab-wrap { left: var(--ss-w-offset-x); align-items: flex-start; }\n.ss-w-fab { width: 56px; height: 56px; border: none; border-radius: 50%; background: var(--ss-w-nav); color: #fff; cursor: pointer; display: grid; place-items: center; box-shadow: 0 6px 20px rgba(0,0,0,.28); }\n.ss-w-fab-mark { font-size: 30px; }\n.ss-w-greeting { max-width: 220px; background: var(--ss-w-panel); color: var(--ss-w-ink); border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 9px 12px; box-shadow: 0 4px 14px rgba(0,0,0,.14); }\n\n/* panel */\n.ss-w-panel { position: fixed; bottom: calc(var(--ss-w-offset-y) + 72px); z-index: 2147483000; display: flex; flex-direction: column; width: min(400px, calc(100vw - 40px)); height: min(620px, calc(100vh - 120px)); background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: var(--ss-w-radius); overflow: hidden; box-shadow: 0 12px 40px rgba(0,0,0,.24); }\n.ss-w-root[data-ss-w-pos="right"] .ss-w-panel { right: var(--ss-w-offset-x); }\n.ss-w-root[data-ss-w-pos="left"] .ss-w-panel { left: var(--ss-w-offset-x); }\n@media (max-width: 639px) {\n .ss-w-panel { inset: 0; width: 100vw; height: 100vh; border: none; border-radius: 0; }\n}\n.ss-w-header { display: flex; align-items: center; gap: 8px; padding: 12px 14px; border-bottom: 1px solid var(--ss-w-line); }\n.ss-w-header-mark { font-size: 18px; }\n.ss-w-header-title { font-weight: 660; }\n.ss-w-close { margin-left: auto; background: none; border: none; color: var(--ss-w-faint); cursor: pointer; font-size: 16px; display: grid; place-items: center; }\n\n/* messages */\n.ss-w-list { flex: 1; overflow-y: auto; padding: 14px; display: flex; flex-direction: column; gap: 12px; }\n.ss-w-msg { display: flex; }\n.ss-w-user { justify-content: flex-end; }\n.ss-w-user .ss-w-bubble { background: color-mix(in srgb, var(--ss-w-accent) 14%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-accent) 30%, var(--ss-w-line)); border-radius: 14px; padding: 8px 12px; max-width: 80%; }\n.ss-w-bot { flex-direction: column; gap: 8px; }\n.ss-w-status { font-size: 11px; color: var(--ss-w-faint); font-style: italic; }\n.ss-w-error { display: flex; align-items: center; gap: 8px; font-size: 12px; color: #c0392b; }\n.ss-w-retry { background: none; border: 1px solid currentColor; border-radius: 10px; padding: 2px 8px; cursor: pointer; color: inherit; }\n\n/* markdown */\n.ss-w-md { display: flex; flex-direction: column; gap: 8px; }\n.ss-w-md :where(p, ul, ol, table, pre, blockquote, h1, h2, h3, h4) { margin: 0; }\n.ss-w-md > *:first-child { margin-top: 0; }\n.ss-w-md > *:last-child { margin-bottom: 0; }\n.ss-w-md-ul { list-style: disc outside; padding-left: 18px; }\n.ss-w-md-ol { list-style: decimal outside; padding-left: 18px; }\n.ss-w-md-ul li::marker, .ss-w-md-ol li::marker { color: var(--ss-w-accent); }\n.ss-w-md-link { color: var(--ss-w-accent); text-decoration: underline; }\n.ss-w-table-wrap { overflow-x: auto; }\n.ss-w-md-table { border-collapse: collapse; width: 100%; font-variant-numeric: tabular-nums; }\n.ss-w-md-table td, .ss-w-md-table th { border: 1px solid var(--ss-w-line); padding: 4px 8px; text-align: left; }\n.ss-w-md-table tr:nth-child(even) { background: var(--ss-w-bubble); }\n.ss-w-md-code { background: var(--ss-w-bubble); border-radius: 5px; padding: 1px 5px; font-family: ui-monospace, monospace; }\n\n/* entity cards */\n.ss-w-cards { display: flex; flex-direction: column; gap: 7px; }\n.ss-w-ecard { display: flex; align-items: center; gap: 11px; width: 100%; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 8px 11px; text-align: left; cursor: pointer; }\n.ss-w-thumb { width: 40px; height: 40px; flex: none; border-radius: 50%; display: grid; place-items: center; font-size: 13px; font-weight: 700; color: #fff; background-color: var(--ss-w-nav); background-size: cover; background-position: center; }\n.ss-w-thumb.ss-w-team { border-radius: 10px; }\n.ss-w-meta { display: flex; flex-direction: column; min-width: 0; }\n.ss-w-nm { font-weight: 660; }\n.ss-w-sub { font-size: 11px; color: var(--ss-w-faint); }\n.ss-w-stat { margin-left: auto; text-align: center; }\n.ss-w-stat b { display: block; font-variant-numeric: tabular-nums; }\n.ss-w-stat span { font-size: 9px; text-transform: uppercase; color: var(--ss-w-faint); }\n.ss-w-chev { color: var(--ss-w-faint); font-size: 16px; display: grid; place-items: center; }\n\n/* action buttons */\n.ss-w-actions { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }\n.ss-w-abtn { font-size: 12px; font-weight: 560; color: var(--ss-w-accent); background: var(--ss-w-panel); border: 1px solid var(--ss-w-accent); border-radius: 16px; padding: 6px 12px; cursor: pointer; }\n.ss-w-abtn-shimmer { width: 140px; height: 30px; border-radius: 16px; background: linear-gradient(90deg, var(--ss-w-bubble), var(--ss-w-line), var(--ss-w-bubble)); background-size: 200% 100%; animation: ss-w-shimmer 1.2s infinite; }\n@keyframes ss-w-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }\n\n/* intent chips */\n.ss-w-chips { display: flex; flex-wrap: wrap; gap: 6px; }\n.ss-w-chip { font-size: 11.5px; font-weight: 550; color: var(--ss-w-ink); background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 14px; padding: 5px 11px; cursor: pointer; }\n\n/* input */\n.ss-w-input { display: flex; align-items: flex-end; gap: 8px; padding: 10px 12px; border-top: 1px solid var(--ss-w-line); }\n.ss-w-textarea { flex: 1; resize: none; border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 8px 10px; font: inherit; color: inherit; background: var(--ss-w-panel); max-height: 96px; }\n.ss-w-send { width: 36px; height: 36px; flex: none; border: none; border-radius: 50%; background: var(--ss-w-accent); color: #fff; cursor: pointer; display: grid; place-items: center; font-size: 16px; }\n.ss-w-stop-glyph { width: 11px; height: 11px; background: currentColor; border-radius: 2px; }\n\n@media (prefers-reduced-motion: reduce) {\n .ss-w-abtn-shimmer { animation: none; }\n}\n';
|
|
426
|
+
|
|
427
|
+
// src/StatsWidget.tsx
|
|
428
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
429
|
+
function buildClient(props) {
|
|
430
|
+
try {
|
|
431
|
+
if ("client" in props && props.client) {
|
|
432
|
+
return { client: props.client, conversation: props.client.conversation() };
|
|
433
|
+
}
|
|
434
|
+
const cfg = props.config;
|
|
435
|
+
const client = new import_widget_sdk3.StatsWidgetClient(toClientOptions(cfg));
|
|
436
|
+
return { client, conversation: client.conversation(toUserContext(cfg)) };
|
|
437
|
+
} catch (err) {
|
|
438
|
+
console.error("[StatsWidget] failed to initialize:", err instanceof Error ? err.message : err);
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
function injectStyles(root) {
|
|
443
|
+
const host = root instanceof ShadowRoot ? root : root.head;
|
|
444
|
+
if (host.querySelector("#ss-w-styles")) return;
|
|
445
|
+
const el = document.createElement("style");
|
|
446
|
+
el.id = "ss-w-styles";
|
|
447
|
+
el.textContent = WIDGET_CSS;
|
|
448
|
+
host.appendChild(el);
|
|
449
|
+
}
|
|
450
|
+
function StatsWidget(props) {
|
|
451
|
+
const injectedClient = "client" in props ? props.client : void 0;
|
|
452
|
+
const cfg = props.config;
|
|
453
|
+
const built = (0, import_react5.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
|
|
454
|
+
const ui = (0, import_react5.useMemo)(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
|
|
455
|
+
const rootRef = (0, import_react5.useRef)(null);
|
|
456
|
+
const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters);
|
|
457
|
+
(0, import_react5.useEffect)(() => {
|
|
458
|
+
if (!built || !ui.injectStyles) return;
|
|
459
|
+
const node = rootRef.current?.getRootNode();
|
|
460
|
+
if (node) injectStyles(node);
|
|
461
|
+
}, [built, ui.injectStyles]);
|
|
462
|
+
if (!built) return null;
|
|
463
|
+
const attrs = themeAttrs(ui);
|
|
464
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { ref: rootRef, className: "ss-w-root", "data-ss-w-theme": attrs["data-ss-w-theme"], "data-ss-w-pos": attrs["data-ss-w-pos"], style: attrs.style, children: [
|
|
465
|
+
controller.state.isOpen ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ChatPanel, { controller, ui }) : null,
|
|
466
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ChatFab, { label: ui.launcherLabel, open: controller.state.isOpen, greeting: ui.greeting, onToggle: controller.toggle })
|
|
467
|
+
] });
|
|
468
|
+
}
|
|
469
|
+
function emptyConversation() {
|
|
470
|
+
return { send: () => {
|
|
471
|
+
throw new Error("widget not initialized");
|
|
472
|
+
} };
|
|
473
|
+
}
|
|
474
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
475
|
+
0 && (module.exports = {
|
|
476
|
+
StatsWidget,
|
|
477
|
+
WIDGET_CSS
|
|
478
|
+
});
|
|
479
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/StatsWidget.tsx","../src/config.ts","../src/theme.ts","../src/useChatStream.ts","../src/reducer.ts","../src/model.ts","../src/components/Icons.tsx","../src/components/GreetingBubble.tsx","../src/components/ChatFab.tsx","../src/components/ChatPanel.tsx","../src/components/ChatHeader.tsx","../src/components/MessageList.tsx","../src/components/Markdown.tsx","../src/components/EntityCardList.tsx","../src/components/ActionButtons.tsx","../src/components/ChatMessage.tsx","../src/components/IntentChips.tsx","../src/components/ChatInput.tsx","../src/styles/css.generated.ts"],"sourcesContent":["export { StatsWidget } from './StatsWidget'\nexport type { StatsWidgetProps } from './StatsWidget'\nexport type { StatsWidgetConfig } from './config'\nexport { WIDGET_CSS } from './styles/css.generated'\n","import { useEffect, useMemo, useRef, type CSSProperties } from 'react'\nimport { StatsWidgetClient, type Conversation } from '@sensiblestats/widget-sdk'\nimport { normalizeUi, toClientOptions, toUserContext, type StatsWidgetConfig } from './config'\nimport { themeAttrs } from './theme'\nimport { useChatStream } from './useChatStream'\nimport { ChatFab } from './components/ChatFab'\nimport { ChatPanel } from './components/ChatPanel'\nimport { WIDGET_CSS } from './styles/css.generated'\n\nexport type StatsWidgetProps =\n | { config: StatsWidgetConfig; client?: never }\n | { client: StatsWidgetClient; config?: Omit<StatsWidgetConfig, 'operatorId' | 'publicKey' | 'baseUrl' | 'userContext'> }\n\nfunction buildClient(props: StatsWidgetProps): { client: StatsWidgetClient; conversation: Conversation } | null {\n try {\n if ('client' in props && props.client) {\n return { client: props.client, conversation: props.client.conversation() }\n }\n const cfg = props.config as StatsWidgetConfig\n const client = new StatsWidgetClient(toClientOptions(cfg))\n return { client, conversation: client.conversation(toUserContext(cfg)) }\n } catch (err) {\n console.error('[StatsWidget] failed to initialize:', err instanceof Error ? err.message : err)\n return null\n }\n}\n\nfunction injectStyles(root: Document | ShadowRoot): void {\n const host: ParentNode = root instanceof ShadowRoot ? root : root.head\n if (host.querySelector('#ss-w-styles')) return\n const el = document.createElement('style')\n el.id = 'ss-w-styles'\n el.textContent = WIDGET_CSS\n host.appendChild(el)\n}\n\nexport function StatsWidget(props: StatsWidgetProps): JSX.Element | null {\n const injectedClient = 'client' in props ? props.client : undefined\n const cfg = props.config as Partial<StatsWidgetConfig> | undefined\n const built = useMemo(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl])\n const ui = useMemo(() => normalizeUi((props.config ?? { operatorId: '', publicKey: '' }) as StatsWidgetConfig), [props.config])\n const rootRef = useRef<HTMLDivElement>(null)\n const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters)\n\n useEffect(() => {\n if (!built || !ui.injectStyles) return\n const node = rootRef.current?.getRootNode()\n if (node) injectStyles(node as Document | ShadowRoot)\n }, [built, ui.injectStyles])\n\n if (!built) return null\n const attrs = themeAttrs(ui)\n return (\n <div ref={rootRef} className=\"ss-w-root\" data-ss-w-theme={attrs['data-ss-w-theme']} data-ss-w-pos={attrs['data-ss-w-pos']} style={attrs.style as CSSProperties}>\n {controller.state.isOpen ? <ChatPanel controller={controller} ui={ui} /> : null}\n <ChatFab label={ui.launcherLabel} open={controller.state.isOpen} greeting={ui.greeting} onToggle={controller.toggle} />\n </div>\n )\n}\n\n// Hooks must run unconditionally; when the client failed to build we still need a Conversation-shaped stub for the hook.\nfunction emptyConversation(): Conversation {\n return { send: () => { throw new Error('widget not initialized') } } as unknown as Conversation\n}\n","import type { StatsWidgetClientOptions, UserContext } from '@sensiblestats/widget-sdk'\n\nexport interface StatsWidgetConfig {\n operatorId: string\n publicKey: string\n baseUrl?: string\n userContext?: UserContext\n theme?: 'light' | 'dark' | 'auto'\n accent?: string\n position?: 'left' | 'right'\n offset?: { x?: number; y?: number }\n radius?: number\n launcherLabel?: string\n greeting?: string\n placeholder?: string\n starters?: string[]\n injectStyles?: boolean\n}\n\ntype UiKeys =\n | 'theme' | 'accent' | 'position' | 'offset' | 'radius'\n | 'launcherLabel' | 'greeting' | 'placeholder' | 'starters' | 'injectStyles'\n\nexport interface UiConfig {\n theme: 'light' | 'dark' | 'auto'\n accent?: string\n position: 'left' | 'right'\n offset: { x: number; y: number }\n radius: number\n launcherLabel: string\n greeting?: string\n placeholder: string\n starters: string[]\n injectStyles: boolean\n}\n\nexport function normalizeUi(cfg: Pick<StatsWidgetConfig, UiKeys>): UiConfig {\n return {\n theme: cfg.theme ?? 'auto',\n accent: cfg.accent,\n position: cfg.position ?? 'right',\n offset: { x: cfg.offset?.x ?? 20, y: cfg.offset?.y ?? 20 },\n radius: cfg.radius ?? 16,\n launcherLabel: cfg.launcherLabel ?? 'Chat with SensibleStats',\n greeting: cfg.greeting,\n placeholder: cfg.placeholder ?? 'Ask about a team, player or match…',\n starters: cfg.starters ?? [],\n injectStyles: cfg.injectStyles ?? true,\n }\n}\n\nexport function toClientOptions(cfg: StatsWidgetConfig): StatsWidgetClientOptions {\n const opts: StatsWidgetClientOptions = { operatorId: cfg.operatorId, publicKey: cfg.publicKey }\n if (cfg.baseUrl !== undefined) opts.baseUrl = cfg.baseUrl\n return opts\n}\n\nexport function toUserContext(cfg: StatsWidgetConfig): UserContext | undefined {\n return cfg.userContext && Object.keys(cfg.userContext).length > 0 ? cfg.userContext : undefined\n}\n","import type { UiConfig } from './config'\n\nexport interface ThemeAttrs {\n 'data-ss-w-theme': string\n 'data-ss-w-pos': string\n style: Record<string, string>\n}\n\nexport function themeAttrs(ui: UiConfig): ThemeAttrs {\n const style: Record<string, string> = {\n '--ss-w-offset-x': `${ui.offset.x}px`,\n '--ss-w-offset-y': `${ui.offset.y}px`,\n '--ss-w-radius': `${ui.radius}px`,\n }\n if (ui.accent) style['--ss-w-accent'] = ui.accent\n return { 'data-ss-w-theme': ui.theme, 'data-ss-w-pos': ui.position, style }\n}\n","import { useCallback, useMemo, useReducer, useRef } from 'react'\nimport type { ChatHandle, ChatInput, Conversation } from '@sensiblestats/widget-sdk'\nimport { WidgetSdkError } from '@sensiblestats/widget-sdk'\nimport { reducer, initialState, type WidgetState } from './reducer'\nimport { chipFromText } from './model'\n\nexport interface ChatController {\n state: WidgetState\n open(): void\n close(): void\n stop(): void\n toggle(): void\n send(text: string, actionId?: string): void\n retry(): void\n}\n\nexport function useChatStream(conversation: Conversation, starterTexts: string[]): ChatController {\n const seed = useMemo(() => initialState(starterTexts.map(chipFromText)), [])\n const [state, dispatch] = useReducer(reducer, seed)\n const idRef = useRef(0)\n const handleRef = useRef<ChatHandle | null>(null)\n const stateRef = useRef(state)\n stateRef.current = state\n\n const nextId = () => `m${idRef.current++}`\n\n const run = useCallback((input: ChatInput) => {\n handleRef.current?.cancel()\n dispatch({ kind: 'USER_SENT', input, userId: nextId(), assistantId: nextId() })\n const handle = conversation.send(input)\n handleRef.current = handle\n ;(async () => {\n try {\n for await (const event of handle) dispatch({ kind: 'EVENT', event })\n } catch (err) {\n if (err instanceof WidgetSdkError) dispatch({ kind: 'STREAM_ERROR', error: err })\n else if ((err as { name?: string } | null)?.name === 'AbortError') { /* expected on cancel/close — ignore */ }\n else throw err\n } finally {\n if (handleRef.current === handle) handleRef.current = null\n }\n })()\n }, [conversation])\n\n const send = useCallback((text: string, actionId?: string) => {\n const trimmed = text.trim()\n if (!trimmed) return\n run({ message: trimmed, actionId })\n }, [run])\n\n const retry = useCallback(() => {\n const last = stateRef.current.lastUserInput\n if (last) run(last)\n }, [run])\n\n const open = useCallback(() => dispatch({ kind: 'OPEN' }), [])\n const close = useCallback(() => { handleRef.current?.cancel(); handleRef.current = null; dispatch({ kind: 'CLOSE' }) }, [])\n const stop = useCallback(() => { handleRef.current?.cancel(); handleRef.current = null; dispatch({ kind: 'STOP' }) }, [])\n const toggle = useCallback(() => { if (stateRef.current.isOpen) close(); else open() }, [close, open])\n\n return { state, open, close, stop, toggle, send, retry }\n}\n","import type { ChatEvent, ChatInput, StreamErrorEventData } from '@sensiblestats/widget-sdk'\nimport { WidgetSdkError } from '@sensiblestats/widget-sdk'\nimport { toActionVM, toCardVM, toChipVM, type ActionVM, type CardVM, type ChipVM } from './model'\n\nexport interface UserMessage { role: 'user'; id: string; text: string }\nexport interface AssistantTurn { role: 'assistant'; id: string; text: string; cards: CardVM[]; actions: ActionVM[]; done: boolean }\nexport type Message = UserMessage | AssistantTurn\n\nexport interface WidgetState {\n isOpen: boolean\n messages: Message[]\n isStreaming: boolean\n status: string | null\n actionsLoading: boolean\n starters: ChipVM[]\n error: StreamErrorEventData | WidgetSdkError | null\n lastUserInput: ChatInput | null\n}\n\nexport type Action =\n | { kind: 'OPEN' }\n | { kind: 'CLOSE' }\n | { kind: 'USER_SENT'; input: ChatInput; userId: string; assistantId: string }\n | { kind: 'EVENT'; event: ChatEvent }\n | { kind: 'STREAM_ERROR'; error: WidgetSdkError }\n | { kind: 'STOP' }\n\nexport function initialState(starters: ChipVM[]): WidgetState {\n return { isOpen: false, messages: [], isStreaming: false, status: null, actionsLoading: false, starters, error: null, lastUserInput: null }\n}\n\nfunction mapActive(state: WidgetState, fn: (t: AssistantTurn) => AssistantTurn): Message[] {\n const last = state.messages[state.messages.length - 1]\n if (!last || last.role !== 'assistant' || last.done) return state.messages\n return [...state.messages.slice(0, -1), fn(last)]\n}\n\nfunction applyEvent(state: WidgetState, event: ChatEvent): WidgetState {\n switch (event.type) {\n case 'progress':\n return { ...state, status: event.data.message }\n case 'answer':\n return { ...state, messages: mapActive(state, (t) => ({ ...t, text: t.text + event.data.text })) }\n case 'entity_card':\n return { ...state, messages: mapActive(state, (t) => ({ ...t, cards: [...t.cards, toCardVM(event.data.card)] })) }\n case 'action_button':\n return { ...state, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, actions: [...t.actions, toActionVM(event.data.action)] })) }\n case 'intent_chip': {\n const chip = toChipVM(event.data.intent)\n return chip ? { ...state, starters: [...state.starters, chip] } : state\n }\n case 'actions_loading':\n return { ...state, actionsLoading: true, status: event.data.message }\n case 'turn_complete':\n return { ...state, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) }\n case 'error':\n return { ...state, error: event.data, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) }\n }\n}\n\nexport function reducer(state: WidgetState, action: Action): WidgetState {\n switch (action.kind) {\n case 'OPEN':\n return { ...state, isOpen: true }\n case 'CLOSE':\n return { ...state, isOpen: false, isStreaming: false, status: null, actionsLoading: false }\n case 'USER_SENT': {\n const user: UserMessage = { role: 'user', id: action.userId, text: action.input.message }\n const assistant: AssistantTurn = { role: 'assistant', id: action.assistantId, text: '', cards: [], actions: [], done: false }\n return { ...state, messages: [...state.messages, user, assistant], isStreaming: true, status: null, actionsLoading: false, starters: [], error: null, lastUserInput: action.input }\n }\n case 'EVENT':\n return applyEvent(state, action.event)\n case 'STREAM_ERROR':\n return { ...state, error: action.error, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) }\n case 'STOP':\n return { ...state, isStreaming: false, status: null, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, done: true })) }\n }\n}\n","import type { EntityCard } from '@sensiblestats/widget-sdk'\n\nexport type CardKind = 'player' | 'team' | 'generic'\nexport interface StatCell { label: string; value: string }\nexport interface CardVM { id: string; kind: CardKind; name: string; image?: string; sub?: string; stats: StatCell[]; query: string }\nexport interface ActionVM { label: string; actionId?: string; message: string }\nexport interface ChipVM { text: string }\n\nfunction str(v: unknown): string | undefined {\n return typeof v === 'string' && v.length > 0 ? v : undefined\n}\nfunction num(v: unknown): string | undefined {\n return typeof v === 'number' && Number.isFinite(v) ? String(v) : undefined\n}\n\nconst STAT_KEYS: Array<[string, string]> = [\n ['goals', 'Goals'], ['assists', 'Assists'], ['appearances', 'Apps'],\n ['xg', 'xG'], ['form', 'Form'], ['rating', 'Rating'],\n]\n\nfunction readStats(card: EntityCard): StatCell[] {\n const cells: StatCell[] = []\n for (const [key, label] of STAT_KEYS) {\n const value = num(card[key]) ?? str(card[key])\n if (value !== undefined) cells.push({ label, value })\n }\n return cells\n}\n\nexport function toCardVM(card: EntityCard): CardVM {\n const kind: CardKind = card.entityType === 'Player' ? 'player' : card.entityType === 'Team' ? 'team' : 'generic'\n return {\n id: String(card.entityId),\n kind,\n name: card.canonicalName,\n image: str(card.imageUrl) ?? str(card.image_url) ?? str(card.logoUrl) ?? str(card.logo),\n sub: str(card.subtitle) ?? str(card.teamName) ?? str(card.leagueName) ?? str(card.position),\n stats: readStats(card),\n query: card.canonicalName,\n }\n}\n\nexport function toActionVM(action: Record<string, unknown>): ActionVM {\n const label = str(action.label) ?? str(action.text) ?? str(action.title) ?? 'Continue'\n const actionId = str(action.id) ?? str(action.actionId)\n const message = str(action.message) ?? str(action.query) ?? label\n return { label, actionId, message }\n}\n\nexport function toChipVM(intent: Record<string, unknown>): ChipVM | null {\n const text = str(intent.text) ?? str(intent.label) ?? str(intent.title)\n return text ? { text } : null\n}\n\nexport function chipFromText(text: string): ChipVM {\n return { text }\n}\n","// Bright SS mark green is used ONLY here for the mark, never as UI accent.\nexport function SsMark({ className }: { className?: string }): JSX.Element {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" width=\"1em\" height=\"1em\" aria-hidden=\"true\">\n <path fill=\"#00F400\" d=\"M12 2l2.5 6.5L21 11l-6.5 2.5L12 20l-2.5-6.5L3 11l6.5-2.5z\" />\n </svg>\n )\n}\nexport function SendIcon(): JSX.Element {\n return <svg viewBox=\"0 0 24 24\" width=\"1em\" height=\"1em\" aria-hidden=\"true\"><path fill=\"currentColor\" d=\"M3 20l18-8L3 4v6l12 2-12 2z\" /></svg>\n}\nexport function CloseIcon(): JSX.Element {\n return <svg viewBox=\"0 0 24 24\" width=\"1em\" height=\"1em\" aria-hidden=\"true\"><path fill=\"none\" d=\"M18 6L6 18M6 6l12 12\" stroke=\"currentColor\" strokeWidth=\"2\" /></svg>\n}\nexport function ChevronIcon(): JSX.Element {\n return <svg viewBox=\"0 0 24 24\" width=\"1em\" height=\"1em\" aria-hidden=\"true\"><path fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" d=\"M9 6l6 6-6 6\" /></svg>\n}\n","export function GreetingBubble({ text }: { text: string }): JSX.Element {\n return <div className=\"ss-w-greeting\" role=\"note\">{text}</div>\n}\n","import { SsMark } from './Icons'\nimport { GreetingBubble } from './GreetingBubble'\n\nexport function ChatFab({ label, open, greeting, onToggle }: { label: string; open: boolean; greeting?: string; onToggle: () => void }): JSX.Element {\n return (\n <div className=\"ss-w-fab-wrap\">\n {!open && greeting ? <GreetingBubble text={greeting} /> : null}\n <button type=\"button\" className=\"ss-w-fab\" aria-label={label} aria-expanded={open} onClick={onToggle}>\n <SsMark className=\"ss-w-fab-mark\" />\n </button>\n </div>\n )\n}\n","import { useEffect } from 'react'\nimport type { ChatController } from '../useChatStream'\nimport type { UiConfig } from '../config'\nimport { ChatHeader } from './ChatHeader'\nimport { MessageList } from './MessageList'\nimport { ChatInput } from './ChatInput'\n\nexport function ChatPanel({ controller, ui }: { controller: ChatController; ui: UiConfig }): JSX.Element {\n const { state, close, stop, send } = controller\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') close() }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [close])\n\n return (\n <div className=\"ss-w-panel\" role=\"dialog\" aria-modal=\"true\" aria-label=\"SensibleStats chat\">\n <ChatHeader onClose={close} />\n <MessageList controller={controller} ui={ui} />\n <ChatInput placeholder={ui.placeholder} streaming={state.isStreaming} onSend={(t) => send(t)} onStop={stop} />\n </div>\n )\n}\n","import { SsMark, CloseIcon } from './Icons'\n\nexport function ChatHeader({ onClose }: { onClose: () => void }): JSX.Element {\n return (\n <header className=\"ss-w-header\">\n <SsMark className=\"ss-w-header-mark\" />\n <span className=\"ss-w-header-title\">SensibleStats</span>\n <button type=\"button\" className=\"ss-w-close\" aria-label=\"Close chat\" onClick={onClose}><CloseIcon /></button>\n </header>\n )\n}\n","import { useEffect, useRef } from 'react'\nimport type { ChatController } from '../useChatStream'\nimport type { UiConfig } from '../config'\nimport { ChatMessage } from './ChatMessage'\nimport { IntentChips } from './IntentChips'\nimport { ActionButtons } from './ActionButtons'\n\nexport function MessageList({ controller, ui }: { controller: ChatController; ui: UiConfig }): JSX.Element {\n void ui\n const { state, send } = controller\n const endRef = useRef<HTMLDivElement>(null)\n useEffect(() => { endRef.current?.scrollIntoView({ block: 'end' }) }, [state.messages, state.status])\n\n const empty = state.messages.length === 0\n return (\n <div className=\"ss-w-list\" aria-live=\"polite\">\n {state.messages.map((m) => (\n <ChatMessage key={m.id} message={m} onAct={(msg, id) => send(msg, id)} onSelect={(q) => send(q)} />\n ))}\n {state.isStreaming && state.actionsLoading ? <ActionButtons actions={[]} loading onAct={() => {}} /> : null}\n {state.status ? <div className=\"ss-w-status\">{state.status}</div> : null}\n {state.error ? (\n <div className=\"ss-w-error\" role=\"alert\">\n <span>{'message' in state.error ? state.error.message : 'Something went wrong.'}</span>\n <button type=\"button\" className=\"ss-w-retry\" onClick={() => controller.retry()}>Retry</button>\n </div>\n ) : null}\n {empty ? <IntentChips chips={state.starters} onPick={(t) => send(t)} /> : null}\n <div ref={endRef} />\n </div>\n )\n}\n","import ReactMarkdown, { type Components } from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\n\nconst components: Components = {\n a: ({ children, href }) => (\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer\" className=\"ss-w-md-link\">{children}</a>\n ),\n table: ({ children }) => (\n <div className=\"ss-w-table-wrap\"><table className=\"ss-w-md-table\">{children}</table></div>\n ),\n ul: ({ children }) => <ul className=\"ss-w-md-ul\">{children}</ul>,\n ol: ({ children }) => <ol className=\"ss-w-md-ol\">{children}</ol>,\n code: ({ children }) => <code className=\"ss-w-md-code\">{children}</code>,\n}\n\nexport function Markdown({ text }: { text: string }): JSX.Element {\n return (\n <div className=\"ss-w-md\">\n <ReactMarkdown remarkPlugins={[remarkGfm]} components={components}>{text}</ReactMarkdown>\n </div>\n )\n}\n","import type { CardVM } from '../model'\nimport { ChevronIcon } from './Icons'\n\nfunction initials(name: string): string {\n return name.split(/\\s+/).slice(0, 2).map((w) => w[0] ?? '').join('').toUpperCase()\n}\n\nexport function EntityCardList({ cards, onSelect }: { cards: CardVM[]; onSelect: (query: string) => void }): JSX.Element | null {\n if (cards.length === 0) return null\n return (\n <div className=\"ss-w-cards\">\n {cards.map((c) => (\n <button key={c.id} type=\"button\" className=\"ss-w-ecard\" onClick={() => onSelect(c.query)}>\n <span\n className={c.kind === 'team' ? 'ss-w-thumb ss-w-team' : 'ss-w-thumb'}\n style={c.image ? { backgroundImage: `url(${c.image})` } : undefined}\n >\n {c.image ? '' : initials(c.name)}\n </span>\n <span className=\"ss-w-meta\">\n <span className=\"ss-w-nm\">{c.name}</span>\n {c.sub ? <span className=\"ss-w-sub\">{c.sub}</span> : null}\n </span>\n {c.stats.map((s) => (\n <span key={s.label} className=\"ss-w-stat\"><b>{s.value}</b><span>{s.label}</span></span>\n ))}\n <span className=\"ss-w-chev\"><ChevronIcon /></span>\n </button>\n ))}\n </div>\n )\n}\n","import type { ActionVM } from '../model'\n\nexport function ActionButtons({ actions, loading, onAct }: { actions: ActionVM[]; loading: boolean; onAct: (message: string, actionId?: string) => void }): JSX.Element | null {\n if (actions.length === 0 && !loading) return null\n return (\n <div className=\"ss-w-actions\">\n {actions.map((a, i) => (\n <button key={`${a.label}-${i}`} type=\"button\" className=\"ss-w-abtn\" onClick={() => onAct(a.message, a.actionId)}>{a.label}</button>\n ))}\n {actions.length === 0 && loading ? (\n <>\n <span className=\"ss-w-abtn-shimmer\" />\n <span className=\"ss-w-abtn-shimmer\" />\n </>\n ) : null}\n </div>\n )\n}\n","import type { Message } from '../reducer'\nimport { Markdown } from './Markdown'\nimport { EntityCardList } from './EntityCardList'\nimport { ActionButtons } from './ActionButtons'\n\nexport function ChatMessage({ message, onAct, onSelect }: { message: Message; onAct: (m: string, id?: string) => void; onSelect: (q: string) => void }): JSX.Element {\n if (message.role === 'user') {\n return <div className=\"ss-w-msg ss-w-user\"><div className=\"ss-w-bubble\">{message.text}</div></div>\n }\n return (\n <div className=\"ss-w-msg ss-w-bot\">\n {message.text ? <Markdown text={message.text} /> : null}\n <EntityCardList cards={message.cards} onSelect={onSelect} />\n <ActionButtons actions={message.actions} loading={false} onAct={onAct} />\n </div>\n )\n}\n","import type { ChipVM } from '../model'\n\nexport function IntentChips({ chips, onPick }: { chips: ChipVM[]; onPick: (text: string) => void }): JSX.Element | null {\n if (chips.length === 0) return null\n return (\n <div className=\"ss-w-chips\">\n {chips.map((c, i) => (\n <button key={`${c.text}-${i}`} type=\"button\" className=\"ss-w-chip\" onClick={() => onPick(c.text)}>{c.text}</button>\n ))}\n </div>\n )\n}\n","import { useState, type KeyboardEvent } from 'react'\nimport { SendIcon } from './Icons'\n\nexport function ChatInput({ placeholder, streaming, onSend, onStop }: { placeholder: string; streaming: boolean; onSend: (t: string) => void; onStop: () => void }): JSX.Element {\n const [value, setValue] = useState('')\n const submit = () => { const t = value.trim(); if (!t) return; onSend(t); setValue('') }\n const onKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); submit() }\n }\n return (\n <div className=\"ss-w-input\">\n <textarea className=\"ss-w-textarea\" rows={1} placeholder={placeholder} value={value} onChange={(e) => setValue(e.target.value)} onKeyDown={onKeyDown} />\n {streaming ? (\n <button type=\"button\" className=\"ss-w-send ss-w-stop\" aria-label=\"Stop response\" onClick={onStop}><span className=\"ss-w-stop-glyph\" /></button>\n ) : (\n <button type=\"button\" className=\"ss-w-send\" aria-label=\"Send message\" onClick={submit}><SendIcon /></button>\n )}\n </div>\n )\n}\n","// AUTO-GENERATED by scripts/gen-css.mjs from widget.css. Do not edit.\nexport const WIDGET_CSS = \".ss-w-root { all: revert; }\\n.ss-w-root, .ss-w-root * { box-sizing: border-box; margin: 0; padding: 0; }\\n.ss-w-root {\\n --ss-w-accent: #17936a;\\n --ss-w-ink: #14181d; --ss-w-faint: #6b7580; --ss-w-line: #e4e8ec;\\n --ss-w-panel: #ffffff; --ss-w-bubble: #f3f5f7; --ss-w-nav: #0e1622;\\n --ss-w-radius: 16px; --ss-w-offset-x: 20px; --ss-w-offset-y: 20px;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, Helvetica, Arial, sans-serif;\\n font-size: 13px; line-height: 1.5; color: var(--ss-w-ink);\\n}\\n@media (prefers-color-scheme: dark) {\\n .ss-w-root[data-ss-w-theme=\\\"auto\\\"] {\\n --ss-w-accent: #37c891; --ss-w-ink: #e8edf2; --ss-w-faint: #8b95a1;\\n --ss-w-line: #2a3441; --ss-w-panel: #141b24; --ss-w-bubble: #1e2732; --ss-w-nav: #0a0f16;\\n }\\n}\\n.ss-w-root[data-ss-w-theme=\\\"dark\\\"] {\\n --ss-w-accent: #37c891; --ss-w-ink: #e8edf2; --ss-w-faint: #8b95a1;\\n --ss-w-line: #2a3441; --ss-w-panel: #141b24; --ss-w-bubble: #1e2732; --ss-w-nav: #0a0f16;\\n}\\n.ss-w-root[data-ss-w-theme=\\\"light\\\"] {\\n --ss-w-accent: #17936a; --ss-w-ink: #14181d; --ss-w-faint: #6b7580;\\n --ss-w-line: #e4e8ec; --ss-w-panel: #ffffff; --ss-w-bubble: #f3f5f7; --ss-w-nav: #0e1622;\\n}\\n\\n/* launcher */\\n.ss-w-fab-wrap { position: fixed; bottom: var(--ss-w-offset-y); z-index: 2147483000; display: flex; flex-direction: column; align-items: flex-end; gap: 10px; }\\n.ss-w-root[data-ss-w-pos=\\\"right\\\"] .ss-w-fab-wrap { right: var(--ss-w-offset-x); }\\n.ss-w-root[data-ss-w-pos=\\\"left\\\"] .ss-w-fab-wrap { left: var(--ss-w-offset-x); align-items: flex-start; }\\n.ss-w-fab { width: 56px; height: 56px; border: none; border-radius: 50%; background: var(--ss-w-nav); color: #fff; cursor: pointer; display: grid; place-items: center; box-shadow: 0 6px 20px rgba(0,0,0,.28); }\\n.ss-w-fab-mark { font-size: 30px; }\\n.ss-w-greeting { max-width: 220px; background: var(--ss-w-panel); color: var(--ss-w-ink); border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 9px 12px; box-shadow: 0 4px 14px rgba(0,0,0,.14); }\\n\\n/* panel */\\n.ss-w-panel { position: fixed; bottom: calc(var(--ss-w-offset-y) + 72px); z-index: 2147483000; display: flex; flex-direction: column; width: min(400px, calc(100vw - 40px)); height: min(620px, calc(100vh - 120px)); background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: var(--ss-w-radius); overflow: hidden; box-shadow: 0 12px 40px rgba(0,0,0,.24); }\\n.ss-w-root[data-ss-w-pos=\\\"right\\\"] .ss-w-panel { right: var(--ss-w-offset-x); }\\n.ss-w-root[data-ss-w-pos=\\\"left\\\"] .ss-w-panel { left: var(--ss-w-offset-x); }\\n@media (max-width: 639px) {\\n .ss-w-panel { inset: 0; width: 100vw; height: 100vh; border: none; border-radius: 0; }\\n}\\n.ss-w-header { display: flex; align-items: center; gap: 8px; padding: 12px 14px; border-bottom: 1px solid var(--ss-w-line); }\\n.ss-w-header-mark { font-size: 18px; }\\n.ss-w-header-title { font-weight: 660; }\\n.ss-w-close { margin-left: auto; background: none; border: none; color: var(--ss-w-faint); cursor: pointer; font-size: 16px; display: grid; place-items: center; }\\n\\n/* messages */\\n.ss-w-list { flex: 1; overflow-y: auto; padding: 14px; display: flex; flex-direction: column; gap: 12px; }\\n.ss-w-msg { display: flex; }\\n.ss-w-user { justify-content: flex-end; }\\n.ss-w-user .ss-w-bubble { background: color-mix(in srgb, var(--ss-w-accent) 14%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-accent) 30%, var(--ss-w-line)); border-radius: 14px; padding: 8px 12px; max-width: 80%; }\\n.ss-w-bot { flex-direction: column; gap: 8px; }\\n.ss-w-status { font-size: 11px; color: var(--ss-w-faint); font-style: italic; }\\n.ss-w-error { display: flex; align-items: center; gap: 8px; font-size: 12px; color: #c0392b; }\\n.ss-w-retry { background: none; border: 1px solid currentColor; border-radius: 10px; padding: 2px 8px; cursor: pointer; color: inherit; }\\n\\n/* markdown */\\n.ss-w-md { display: flex; flex-direction: column; gap: 8px; }\\n.ss-w-md :where(p, ul, ol, table, pre, blockquote, h1, h2, h3, h4) { margin: 0; }\\n.ss-w-md > *:first-child { margin-top: 0; }\\n.ss-w-md > *:last-child { margin-bottom: 0; }\\n.ss-w-md-ul { list-style: disc outside; padding-left: 18px; }\\n.ss-w-md-ol { list-style: decimal outside; padding-left: 18px; }\\n.ss-w-md-ul li::marker, .ss-w-md-ol li::marker { color: var(--ss-w-accent); }\\n.ss-w-md-link { color: var(--ss-w-accent); text-decoration: underline; }\\n.ss-w-table-wrap { overflow-x: auto; }\\n.ss-w-md-table { border-collapse: collapse; width: 100%; font-variant-numeric: tabular-nums; }\\n.ss-w-md-table td, .ss-w-md-table th { border: 1px solid var(--ss-w-line); padding: 4px 8px; text-align: left; }\\n.ss-w-md-table tr:nth-child(even) { background: var(--ss-w-bubble); }\\n.ss-w-md-code { background: var(--ss-w-bubble); border-radius: 5px; padding: 1px 5px; font-family: ui-monospace, monospace; }\\n\\n/* entity cards */\\n.ss-w-cards { display: flex; flex-direction: column; gap: 7px; }\\n.ss-w-ecard { display: flex; align-items: center; gap: 11px; width: 100%; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 8px 11px; text-align: left; cursor: pointer; }\\n.ss-w-thumb { width: 40px; height: 40px; flex: none; border-radius: 50%; display: grid; place-items: center; font-size: 13px; font-weight: 700; color: #fff; background-color: var(--ss-w-nav); background-size: cover; background-position: center; }\\n.ss-w-thumb.ss-w-team { border-radius: 10px; }\\n.ss-w-meta { display: flex; flex-direction: column; min-width: 0; }\\n.ss-w-nm { font-weight: 660; }\\n.ss-w-sub { font-size: 11px; color: var(--ss-w-faint); }\\n.ss-w-stat { margin-left: auto; text-align: center; }\\n.ss-w-stat b { display: block; font-variant-numeric: tabular-nums; }\\n.ss-w-stat span { font-size: 9px; text-transform: uppercase; color: var(--ss-w-faint); }\\n.ss-w-chev { color: var(--ss-w-faint); font-size: 16px; display: grid; place-items: center; }\\n\\n/* action buttons */\\n.ss-w-actions { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }\\n.ss-w-abtn { font-size: 12px; font-weight: 560; color: var(--ss-w-accent); background: var(--ss-w-panel); border: 1px solid var(--ss-w-accent); border-radius: 16px; padding: 6px 12px; cursor: pointer; }\\n.ss-w-abtn-shimmer { width: 140px; height: 30px; border-radius: 16px; background: linear-gradient(90deg, var(--ss-w-bubble), var(--ss-w-line), var(--ss-w-bubble)); background-size: 200% 100%; animation: ss-w-shimmer 1.2s infinite; }\\n@keyframes ss-w-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }\\n\\n/* intent chips */\\n.ss-w-chips { display: flex; flex-wrap: wrap; gap: 6px; }\\n.ss-w-chip { font-size: 11.5px; font-weight: 550; color: var(--ss-w-ink); background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 14px; padding: 5px 11px; cursor: pointer; }\\n\\n/* input */\\n.ss-w-input { display: flex; align-items: flex-end; gap: 8px; padding: 10px 12px; border-top: 1px solid var(--ss-w-line); }\\n.ss-w-textarea { flex: 1; resize: none; border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 8px 10px; font: inherit; color: inherit; background: var(--ss-w-panel); max-height: 96px; }\\n.ss-w-send { width: 36px; height: 36px; flex: none; border: none; border-radius: 50%; background: var(--ss-w-accent); color: #fff; cursor: pointer; display: grid; place-items: center; font-size: 16px; }\\n.ss-w-stop-glyph { width: 11px; height: 11px; background: currentColor; border-radius: 2px; }\\n\\n@media (prefers-reduced-motion: reduce) {\\n .ss-w-abtn-shimmer { animation: none; }\\n}\\n\"\n"],"mappings":"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","names":["import_react","import_widget_sdk","import_widget_sdk","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime","ReactMarkdown","remarkGfm","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}
|