@seed-ship/mcp-ui-solid 2.5.3 → 2.6.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/components/ChatPrompt.cjs +16 -75
- package/dist/components/ChatPrompt.cjs.map +1 -1
- package/dist/components/ChatPrompt.d.ts.map +1 -1
- package/dist/components/ChatPrompt.js +16 -75
- package/dist/components/ChatPrompt.js.map +1 -1
- package/dist/components/FormFieldRenderer.cjs +232 -3
- package/dist/components/FormFieldRenderer.cjs.map +1 -1
- package/dist/components/FormFieldRenderer.d.ts.map +1 -1
- package/dist/components/FormFieldRenderer.js +233 -4
- package/dist/components/FormFieldRenderer.js.map +1 -1
- package/dist/types/chat-bus.d.ts +21 -1
- package/dist/types/chat-bus.d.ts.map +1 -1
- package/dist/types/index.d.ts +17 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types.d.cts +17 -1
- package/dist/types.d.ts +17 -1
- package/package.json +1 -1
- package/src/components/ChatPrompt.tsx +19 -47
- package/src/components/FormFieldRenderer.tsx +218 -3
- package/src/types/chat-bus.ts +21 -1
- package/src/types/index.ts +19 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const web = require("solid-js/web");
|
|
4
4
|
const solidJs = require("solid-js");
|
|
5
|
+
const FormFieldRenderer = require("./FormFieldRenderer.cjs");
|
|
5
6
|
var _tmpl$ = /* @__PURE__ */ web.template(`<div class="w-full max-w-2xl mx-auto mb-2 bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 shadow-lg overflow-hidden"role=dialog style="animation:chat-prompt-slide-up 0.2s ease-out"><div class="flex items-center justify-between px-4 py-2.5 border-b border-gray-100 dark:border-gray-700"><p class="text-sm font-medium text-gray-900 dark:text-white"></p><button></button></div><div class="px-4 py-3"></div><style>
|
|
6
7
|
@keyframes chat-prompt-slide-up {
|
|
7
8
|
from { opacity: 0; transform: translateY(8px); }
|
|
8
9
|
to { opacity: 1; transform: translateY(0); }
|
|
9
10
|
}
|
|
10
|
-
`), _tmpl$2 = /* @__PURE__ */ web.template(`<svg class="w-4 h-4"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M6 18L18 6M6 6l12 12">`), _tmpl$3 = /* @__PURE__ */ web.template(`<div>`), _tmpl$4 = /* @__PURE__ */ web.template(`<span class=mr-2>`), _tmpl$5 = /* @__PURE__ */ web.template(`<span class="block text-xs text-gray-500 dark:text-gray-400 mt-0.5 font-normal">`), _tmpl$6 = /* @__PURE__ */ web.template(`<button class="px-4 py-2 text-sm font-medium rounded-lg border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-900 dark:text-white hover:bg-blue-50 hover:border-blue-300 dark:hover:bg-blue-900/30 dark:hover:border-blue-600 transition-colors text-left"><!$><!/><!$><!/><!$><!/>`), _tmpl$7 = /* @__PURE__ */ web.template(`<p class="text-sm text-gray-600 dark:text-gray-400 mb-3">`), _tmpl$8 = /* @__PURE__ */ web.template(`<div><!$><!/><div class="flex gap-2 justify-end"><button class="px-4 py-2 text-sm font-medium rounded-lg border border-gray-200 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"></button><button>`), _tmpl$9 = /* @__PURE__ */ web.template(`<form class="flex flex-col gap-3"><!$><!/><div class="flex justify-end"><button type=submit class="px-4 py-2 text-sm font-medium rounded-lg text-white bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors">`)
|
|
11
|
+
`), _tmpl$2 = /* @__PURE__ */ web.template(`<svg class="w-4 h-4"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M6 18L18 6M6 6l12 12">`), _tmpl$3 = /* @__PURE__ */ web.template(`<div>`), _tmpl$4 = /* @__PURE__ */ web.template(`<span class=mr-2>`), _tmpl$5 = /* @__PURE__ */ web.template(`<span class="block text-xs text-gray-500 dark:text-gray-400 mt-0.5 font-normal">`), _tmpl$6 = /* @__PURE__ */ web.template(`<button class="px-4 py-2 text-sm font-medium rounded-lg border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-900 dark:text-white hover:bg-blue-50 hover:border-blue-300 dark:hover:bg-blue-900/30 dark:hover:border-blue-600 transition-colors text-left"><!$><!/><!$><!/><!$><!/>`), _tmpl$7 = /* @__PURE__ */ web.template(`<p class="text-sm text-gray-600 dark:text-gray-400 mb-3">`), _tmpl$8 = /* @__PURE__ */ web.template(`<div><!$><!/><div class="flex gap-2 justify-end"><button class="px-4 py-2 text-sm font-medium rounded-lg border border-gray-200 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"></button><button>`), _tmpl$9 = /* @__PURE__ */ web.template(`<form class="flex flex-col gap-3"><!$><!/><div class="flex justify-end"><button type=submit class="px-4 py-2 text-sm font-medium rounded-lg text-white bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors">`);
|
|
11
12
|
const ChatPrompt = (props) => {
|
|
12
13
|
if (!props.config) return null;
|
|
13
14
|
return (() => {
|
|
@@ -195,14 +196,16 @@ const FormBody = (props) => {
|
|
|
195
196
|
const handleSubmit = (e) => {
|
|
196
197
|
e.preventDefault();
|
|
197
198
|
const data = formData();
|
|
198
|
-
const label = Object.entries(data).filter(([, v]) => v).map(([k, v]) => `${k}: ${v}`).join(", ");
|
|
199
|
+
const label = Object.entries(data).filter(([, v]) => v !== void 0 && v !== "" && !(Array.isArray(v) && v.length === 0)).map(([k, v]) => `${k}: ${Array.isArray(v) ? v.join(", ") : v}`).join(", ");
|
|
199
200
|
props.onSubmit(data, label || "Form submitted");
|
|
200
201
|
};
|
|
201
202
|
const isValid = () => {
|
|
202
203
|
const data = formData();
|
|
203
204
|
return (props.config.fields || []).filter((f) => f.required).every((f) => {
|
|
204
|
-
|
|
205
|
-
|
|
205
|
+
const val = data[f.name];
|
|
206
|
+
if (Array.isArray(val)) return val.length > 0;
|
|
207
|
+
if (typeof val === "boolean") return true;
|
|
208
|
+
return val !== void 0 && val !== "";
|
|
206
209
|
});
|
|
207
210
|
};
|
|
208
211
|
return (() => {
|
|
@@ -212,82 +215,20 @@ const FormBody = (props) => {
|
|
|
212
215
|
get each() {
|
|
213
216
|
return props.config.fields;
|
|
214
217
|
},
|
|
215
|
-
children: (field) => (
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
return web.getNextElement(_tmpl$0);
|
|
224
|
-
}
|
|
225
|
-
}), _el$33, _co$7);
|
|
226
|
-
web.insert(_el$27, web.createComponent(solidJs.Switch, {
|
|
227
|
-
get children() {
|
|
228
|
-
return [web.createComponent(solidJs.Match, {
|
|
229
|
-
get when() {
|
|
230
|
-
return field.type === "textarea";
|
|
231
|
-
},
|
|
232
|
-
get children() {
|
|
233
|
-
var _el$34 = web.getNextElement(_tmpl$1);
|
|
234
|
-
_el$34.$$input = (e) => updateField(field.name, e.currentTarget.value);
|
|
235
|
-
web.effect(() => web.setAttribute(_el$34, "placeholder", field.placeholder));
|
|
236
|
-
web.effect(() => web.setProperty(_el$34, "value", formData()[field.name] || ""));
|
|
237
|
-
web.runHydrationEvents();
|
|
238
|
-
return _el$34;
|
|
239
|
-
}
|
|
240
|
-
}), web.createComponent(solidJs.Match, {
|
|
241
|
-
get when() {
|
|
242
|
-
return field.type === "select";
|
|
243
|
-
},
|
|
244
|
-
get children() {
|
|
245
|
-
var _el$35 = web.getNextElement(_tmpl$10), _el$36 = _el$35.firstChild, _el$37 = _el$36.nextSibling, [_el$38, _co$8] = web.getNextMarker(_el$37.nextSibling);
|
|
246
|
-
_el$35.addEventListener("change", (e) => updateField(field.name, e.currentTarget.value));
|
|
247
|
-
web.insert(_el$36, () => field.placeholder || "Select...");
|
|
248
|
-
web.insert(_el$35, web.createComponent(solidJs.For, {
|
|
249
|
-
get each() {
|
|
250
|
-
return field.options;
|
|
251
|
-
},
|
|
252
|
-
children: (opt) => (() => {
|
|
253
|
-
var _el$42 = web.getNextElement(_tmpl$13);
|
|
254
|
-
web.insert(_el$42, () => opt.label);
|
|
255
|
-
web.effect(() => web.setProperty(_el$42, "value", opt.value));
|
|
256
|
-
return _el$42;
|
|
257
|
-
})()
|
|
258
|
-
}), _el$38, _co$8);
|
|
259
|
-
web.effect(() => web.setProperty(_el$35, "value", formData()[field.name] || ""));
|
|
260
|
-
return _el$35;
|
|
261
|
-
}
|
|
262
|
-
}), web.createComponent(solidJs.Match, {
|
|
263
|
-
when: true,
|
|
264
|
-
get children() {
|
|
265
|
-
var _el$39 = web.getNextElement(_tmpl$11);
|
|
266
|
-
_el$39.$$input = (e) => updateField(field.name, e.currentTarget.value);
|
|
267
|
-
web.effect((_p$) => {
|
|
268
|
-
var _v$4 = field.type === "number" ? "number" : "text", _v$5 = field.placeholder;
|
|
269
|
-
_v$4 !== _p$.e && web.setAttribute(_el$39, "type", _p$.e = _v$4);
|
|
270
|
-
_v$5 !== _p$.t && web.setAttribute(_el$39, "placeholder", _p$.t = _v$5);
|
|
271
|
-
return _p$;
|
|
272
|
-
}, {
|
|
273
|
-
e: void 0,
|
|
274
|
-
t: void 0
|
|
275
|
-
});
|
|
276
|
-
web.effect(() => web.setProperty(_el$39, "value", formData()[field.name] || ""));
|
|
277
|
-
web.runHydrationEvents();
|
|
278
|
-
return _el$39;
|
|
279
|
-
}
|
|
280
|
-
})];
|
|
281
|
-
}
|
|
282
|
-
}), _el$41, _co$9);
|
|
283
|
-
return _el$27;
|
|
284
|
-
})()
|
|
218
|
+
children: (field) => web.createComponent(FormFieldRenderer.FormFieldRenderer, {
|
|
219
|
+
field,
|
|
220
|
+
get value() {
|
|
221
|
+
return formData()[field.name];
|
|
222
|
+
},
|
|
223
|
+
onChange: (val) => updateField(field.name, val),
|
|
224
|
+
formData
|
|
225
|
+
})
|
|
285
226
|
}), _el$26, _co$5);
|
|
286
227
|
web.insert(_el$24, () => props.config.submitLabel || "Submit");
|
|
287
228
|
web.effect(() => web.setProperty(_el$24, "disabled", !isValid()));
|
|
288
229
|
return _el$22;
|
|
289
230
|
})();
|
|
290
231
|
};
|
|
291
|
-
web.delegateEvents(["click"
|
|
232
|
+
web.delegateEvents(["click"]);
|
|
292
233
|
exports.ChatPrompt = ChatPrompt;
|
|
293
234
|
//# sourceMappingURL=ChatPrompt.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatPrompt.cjs","sources":["../../src/components/ChatPrompt.tsx"],"sourcesContent":["/**\n * ChatPrompt — Ephemeral structured interaction above chat input\n * v2.4.0: choice, confirm, form subtypes\n *\n * @experimental — This component may change without major bump until v2.5.0.\n *\n * Renders above the chat input. User responds → Promise resolves → prompt disappears.\n * Supports AbortSignal for cleanup on navigation (C4).\n */\n\nimport { Component, Show, For, createSignal, onCleanup, Switch, Match } from 'solid-js'\nimport type {\n ChatPromptConfig,\n ChatPromptResponse,\n ChoicePromptConfig,\n ConfirmPromptConfig,\n FormPromptConfig,\n} from '../types/chat-bus'\n\nexport interface ChatPromptProps {\n /** Prompt configuration */\n config: ChatPromptConfig\n /** Called when user responds */\n onSubmit: (response: ChatPromptResponse) => void\n /** Called when user dismisses (e.g. \"send as-is\") */\n onDismiss?: () => void\n /** Label for the dismiss button (replaces X icon). Default: shows X icon. */\n dismissLabel?: string\n}\n\n/**\n * @experimental\n * Ephemeral interaction component — choice buttons, confirmation dialog, or quick form.\n * Designed to sit between the chat messages and the input area.\n *\n * @example\n * <ChatPrompt\n * config={{ type: 'choice', title: 'Format?', config: { options: [...] } }}\n * onSubmit={(r) => bus.events.emit('onChatPromptResponse', { streamKey, response: r })}\n * onDismiss={() => setActivePrompt(null)}\n * />\n */\nexport const ChatPrompt: Component<ChatPromptProps> = (props) => {\n // F1: Guard against null/undefined config (e.g. after dismiss clears state)\n if (!props.config) return null\n\n return (\n <div\n class=\"w-full max-w-2xl mx-auto mb-2 bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 shadow-lg overflow-hidden\"\n style={{ animation: 'chat-prompt-slide-up 0.2s ease-out' }}\n role=\"dialog\"\n aria-label={props.config.title}\n >\n {/* Header */}\n <div class=\"flex items-center justify-between px-4 py-2.5 border-b border-gray-100 dark:border-gray-700\">\n <p class=\"text-sm font-medium text-gray-900 dark:text-white\">{props.config.title}</p>\n <button\n onClick={() => {\n props.onDismiss?.()\n props.onSubmit({ type: props.config.type, value: '', label: '', dismissed: true })\n }}\n class={props.dismissLabel\n ? 'px-3 py-1 text-xs font-medium text-blue-600 dark:text-blue-400 hover:bg-blue-50 dark:hover:bg-blue-900/20 rounded-lg transition-colors'\n : 'p-1 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors'\n }\n aria-label={props.dismissLabel || 'Dismiss'}\n >\n <Show when={props.dismissLabel} fallback={\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n }>\n {props.dismissLabel}\n </Show>\n </button>\n </div>\n\n {/* Body — type-specific */}\n <div class=\"px-4 py-3\">\n <Switch>\n <Match when={props.config.type === 'choice'}>\n <ChoiceBody\n config={props.config.config as ChoicePromptConfig}\n onSelect={(value, label) => props.onSubmit({ type: 'choice', value, label })}\n />\n </Match>\n <Match when={props.config.type === 'confirm'}>\n <ConfirmBody\n config={props.config.config as ConfirmPromptConfig}\n onConfirm={() => props.onSubmit({ type: 'confirm', value: 'confirmed', label: (props.config.config as ConfirmPromptConfig).confirmLabel || 'Confirmed' })}\n onCancel={() => {\n props.onDismiss?.()\n props.onSubmit({ type: 'confirm', value: 'cancelled', label: (props.config.config as ConfirmPromptConfig).cancelLabel || 'Cancelled', dismissed: true })\n }}\n />\n </Match>\n <Match when={props.config.type === 'form'}>\n <FormBody\n config={props.config.config as FormPromptConfig}\n onSubmit={(data, label) => props.onSubmit({ type: 'form', value: data, label })}\n />\n </Match>\n </Switch>\n </div>\n\n <style>{`\n @keyframes chat-prompt-slide-up {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n }\n `}</style>\n </div>\n )\n}\n\n// ─── Choice ──────────────────────────────────────────────────\n\nconst ChoiceBody: Component<{\n config: ChoicePromptConfig\n onSelect: (value: string, label: string) => void\n}> = (props) => {\n const layoutClass = () => {\n switch (props.config.layout) {\n case 'vertical': return 'flex flex-col gap-2'\n case 'grid': return 'grid grid-cols-2 gap-2'\n default: return 'flex flex-wrap gap-2'\n }\n }\n\n return (\n <div class={layoutClass()}>\n <For each={props.config.options}>\n {(option) => (\n <button\n onClick={() => props.onSelect(option.value, option.label)}\n class=\"px-4 py-2 text-sm font-medium rounded-lg border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-900 dark:text-white hover:bg-blue-50 hover:border-blue-300 dark:hover:bg-blue-900/30 dark:hover:border-blue-600 transition-colors text-left\"\n >\n <Show when={option.icon}>\n <span class=\"mr-2\">{option.icon}</span>\n </Show>\n {option.label}\n <Show when={option.description}>\n <span class=\"block text-xs text-gray-500 dark:text-gray-400 mt-0.5 font-normal\">{option.description}</span>\n </Show>\n </button>\n )}\n </For>\n </div>\n )\n}\n\n// ─── Confirm ─────────────────────────────────────────────────\n\nconst ConfirmBody: Component<{\n config: ConfirmPromptConfig\n onConfirm: () => void\n onCancel: () => void\n}> = (props) => {\n const isDanger = () => props.config.variant === 'danger'\n\n return (\n <div>\n <Show when={props.config.message}>\n <p class=\"text-sm text-gray-600 dark:text-gray-400 mb-3\">{props.config.message}</p>\n </Show>\n <div class=\"flex gap-2 justify-end\">\n <button\n onClick={props.onCancel}\n class=\"px-4 py-2 text-sm font-medium rounded-lg border border-gray-200 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors\"\n >\n {props.config.cancelLabel || 'Cancel'}\n </button>\n <button\n onClick={props.onConfirm}\n class={`px-4 py-2 text-sm font-medium rounded-lg text-white transition-colors ${\n isDanger()\n ? 'bg-red-600 hover:bg-red-700'\n : 'bg-blue-600 hover:bg-blue-700'\n }`}\n >\n {props.config.confirmLabel || 'Confirm'}\n </button>\n </div>\n </div>\n )\n}\n\n// ─── Form ────────────────────────────────────────────────────\n\nconst FormBody: Component<{\n config: FormPromptConfig\n onSubmit: (data: Record<string, unknown>, label: string) => void\n}> = (props) => {\n const [formData, setFormData] = createSignal<Record<string, string>>({})\n\n const updateField = (name: string, value: string) => {\n setFormData((prev) => ({ ...prev, [name]: value }))\n }\n\n const handleSubmit = (e: Event) => {\n e.preventDefault()\n const data = formData()\n // Build a human-readable label from the form values\n const label = Object.entries(data)\n .filter(([, v]) => v)\n .map(([k, v]) => `${k}: ${v}`)\n .join(', ')\n props.onSubmit(data, label || 'Form submitted')\n }\n\n const isValid = () => {\n const data = formData()\n return (props.config.fields || [])\n .filter((f) => f.required)\n .every((f) => data[f.name]?.trim())\n }\n\n return (\n <form onSubmit={handleSubmit} class=\"flex flex-col gap-3\">\n <For each={props.config.fields}>\n {(field) => (\n <div>\n <label class=\"block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1\">\n {field.label}\n <Show when={field.required}>\n <span class=\"text-red-500 ml-0.5\">*</span>\n </Show>\n </label>\n <Switch>\n <Match when={field.type === 'textarea'}>\n <textarea\n value={formData()[field.name] || ''}\n onInput={(e) => updateField(field.name, e.currentTarget.value)}\n placeholder={field.placeholder}\n rows={3}\n class=\"w-full px-3 py-2 text-sm rounded-lg border border-gray-200 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:border-blue-400 focus:ring-1 focus:ring-blue-400 outline-none transition-colors\"\n />\n </Match>\n <Match when={field.type === 'select'}>\n <select\n value={formData()[field.name] || ''}\n onChange={(e) => updateField(field.name, e.currentTarget.value)}\n class=\"w-full px-3 py-2 text-sm rounded-lg border border-gray-200 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:border-blue-400 focus:ring-1 focus:ring-blue-400 outline-none transition-colors\"\n >\n <option value=\"\">{field.placeholder || 'Select...'}</option>\n <For each={field.options}>\n {(opt) => <option value={opt.value}>{opt.label}</option>}\n </For>\n </select>\n </Match>\n <Match when={true}>\n <input\n type={field.type === 'number' ? 'number' : 'text'}\n value={formData()[field.name] || ''}\n onInput={(e) => updateField(field.name, e.currentTarget.value)}\n placeholder={field.placeholder}\n class=\"w-full px-3 py-2 text-sm rounded-lg border border-gray-200 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:border-blue-400 focus:ring-1 focus:ring-blue-400 outline-none transition-colors\"\n />\n </Match>\n </Switch>\n </div>\n )}\n </For>\n <div class=\"flex justify-end\">\n <button\n type=\"submit\"\n disabled={!isValid()}\n class=\"px-4 py-2 text-sm font-medium rounded-lg text-white bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors\"\n >\n {props.config.submitLabel || 'Submit'}\n </button>\n </div>\n </form>\n )\n}\n"],"names":["ChatPrompt","props","config","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$5","_$insert","title","$$click","onDismiss","onSubmit","type","value","label","dismissed","_$createComponent","Show","when","dismissLabel","fallback","_tmpl$2","children","Switch","Match","ChoiceBody","onSelect","ConfirmBody","onConfirm","confirmLabel","onCancel","cancelLabel","FormBody","data","_$effect","_p$","_v$","_v$2","_v$3","e","_$setAttribute","t","_$className","a","undefined","_$runHydrationEvents","layoutClass","layout","_el$7","_tmpl$3","For","each","options","option","_el$8","_tmpl$6","_el$1","_el$10","_co$","_$getNextMarker","_el$11","_el$12","_co$2","_el$13","_el$14","_co$3","icon","_el$9","_tmpl$4","description","_el$0","_tmpl$5","isDanger","variant","_el$15","_tmpl$8","_el$20","_el$21","_co$4","_el$17","_el$18","_el$19","message","_el$16","_tmpl$7","_$addEventListener","formData","setFormData","createSignal","updateField","name","prev","handleSubmit","preventDefault","Object","entries","filter","v","map","k","join","isValid","fields","f","required","every","trim","_el$22","_tmpl$9","_el$25","_el$26","_co$5","_el$23","_el$24","addEventListener","field","_el$27","_tmpl$12","_el$28","_el$30","_el$31","_co$6","_el$32","_el$33","_co$7","_el$40","_el$41","_co$9","_tmpl$0","_el$34","_tmpl$1","$$input","currentTarget","placeholder","_$setProperty","_el$35","_tmpl$10","_el$36","_el$37","_el$38","_co$8","opt","_el$42","_tmpl$13","_el$39","_tmpl$11","_v$4","_v$5","submitLabel","_$delegateEvents"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ChatPrompt.cjs","sources":["../../src/components/ChatPrompt.tsx"],"sourcesContent":["/**\n * ChatPrompt — Ephemeral structured interaction above chat input\n * v2.4.0: choice, confirm, form subtypes\n *\n * @experimental — This component may change without major bump until v2.5.0.\n *\n * Renders above the chat input. User responds → Promise resolves → prompt disappears.\n * Supports AbortSignal for cleanup on navigation (C4).\n */\n\nimport { Component, Show, For, createSignal, onCleanup, Switch, Match } from 'solid-js'\nimport type {\n ChatPromptConfig,\n ChatPromptResponse,\n ChoicePromptConfig,\n ConfirmPromptConfig,\n FormPromptConfig,\n} from '../types/chat-bus'\nimport { FormFieldRenderer } from './FormFieldRenderer'\nimport type { FormFieldParams } from '../types'\n\nexport interface ChatPromptProps {\n /** Prompt configuration */\n config: ChatPromptConfig\n /** Called when user responds */\n onSubmit: (response: ChatPromptResponse) => void\n /** Called when user dismisses (e.g. \"send as-is\") */\n onDismiss?: () => void\n /** Label for the dismiss button (replaces X icon). Default: shows X icon. */\n dismissLabel?: string\n}\n\n/**\n * @experimental\n * Ephemeral interaction component — choice buttons, confirmation dialog, or quick form.\n * Designed to sit between the chat messages and the input area.\n *\n * @example\n * <ChatPrompt\n * config={{ type: 'choice', title: 'Format?', config: { options: [...] } }}\n * onSubmit={(r) => bus.events.emit('onChatPromptResponse', { streamKey, response: r })}\n * onDismiss={() => setActivePrompt(null)}\n * />\n */\nexport const ChatPrompt: Component<ChatPromptProps> = (props) => {\n // F1: Guard against null/undefined config (e.g. after dismiss clears state)\n if (!props.config) return null\n\n return (\n <div\n class=\"w-full max-w-2xl mx-auto mb-2 bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 shadow-lg overflow-hidden\"\n style={{ animation: 'chat-prompt-slide-up 0.2s ease-out' }}\n role=\"dialog\"\n aria-label={props.config.title}\n >\n {/* Header */}\n <div class=\"flex items-center justify-between px-4 py-2.5 border-b border-gray-100 dark:border-gray-700\">\n <p class=\"text-sm font-medium text-gray-900 dark:text-white\">{props.config.title}</p>\n <button\n onClick={() => {\n props.onDismiss?.()\n props.onSubmit({ type: props.config.type, value: '', label: '', dismissed: true })\n }}\n class={props.dismissLabel\n ? 'px-3 py-1 text-xs font-medium text-blue-600 dark:text-blue-400 hover:bg-blue-50 dark:hover:bg-blue-900/20 rounded-lg transition-colors'\n : 'p-1 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors'\n }\n aria-label={props.dismissLabel || 'Dismiss'}\n >\n <Show when={props.dismissLabel} fallback={\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n }>\n {props.dismissLabel}\n </Show>\n </button>\n </div>\n\n {/* Body — type-specific */}\n <div class=\"px-4 py-3\">\n <Switch>\n <Match when={props.config.type === 'choice'}>\n <ChoiceBody\n config={props.config.config as ChoicePromptConfig}\n onSelect={(value, label) => props.onSubmit({ type: 'choice', value, label })}\n />\n </Match>\n <Match when={props.config.type === 'confirm'}>\n <ConfirmBody\n config={props.config.config as ConfirmPromptConfig}\n onConfirm={() => props.onSubmit({ type: 'confirm', value: 'confirmed', label: (props.config.config as ConfirmPromptConfig).confirmLabel || 'Confirmed' })}\n onCancel={() => {\n props.onDismiss?.()\n props.onSubmit({ type: 'confirm', value: 'cancelled', label: (props.config.config as ConfirmPromptConfig).cancelLabel || 'Cancelled', dismissed: true })\n }}\n />\n </Match>\n <Match when={props.config.type === 'form'}>\n <FormBody\n config={props.config.config as FormPromptConfig}\n onSubmit={(data, label) => props.onSubmit({ type: 'form', value: data, label })}\n />\n </Match>\n </Switch>\n </div>\n\n <style>{`\n @keyframes chat-prompt-slide-up {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n }\n `}</style>\n </div>\n )\n}\n\n// ─── Choice ──────────────────────────────────────────────────\n\nconst ChoiceBody: Component<{\n config: ChoicePromptConfig\n onSelect: (value: string, label: string) => void\n}> = (props) => {\n const layoutClass = () => {\n switch (props.config.layout) {\n case 'vertical': return 'flex flex-col gap-2'\n case 'grid': return 'grid grid-cols-2 gap-2'\n default: return 'flex flex-wrap gap-2'\n }\n }\n\n return (\n <div class={layoutClass()}>\n <For each={props.config.options}>\n {(option) => (\n <button\n onClick={() => props.onSelect(option.value, option.label)}\n class=\"px-4 py-2 text-sm font-medium rounded-lg border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-900 dark:text-white hover:bg-blue-50 hover:border-blue-300 dark:hover:bg-blue-900/30 dark:hover:border-blue-600 transition-colors text-left\"\n >\n <Show when={option.icon}>\n <span class=\"mr-2\">{option.icon}</span>\n </Show>\n {option.label}\n <Show when={option.description}>\n <span class=\"block text-xs text-gray-500 dark:text-gray-400 mt-0.5 font-normal\">{option.description}</span>\n </Show>\n </button>\n )}\n </For>\n </div>\n )\n}\n\n// ─── Confirm ─────────────────────────────────────────────────\n\nconst ConfirmBody: Component<{\n config: ConfirmPromptConfig\n onConfirm: () => void\n onCancel: () => void\n}> = (props) => {\n const isDanger = () => props.config.variant === 'danger'\n\n return (\n <div>\n <Show when={props.config.message}>\n <p class=\"text-sm text-gray-600 dark:text-gray-400 mb-3\">{props.config.message}</p>\n </Show>\n <div class=\"flex gap-2 justify-end\">\n <button\n onClick={props.onCancel}\n class=\"px-4 py-2 text-sm font-medium rounded-lg border border-gray-200 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors\"\n >\n {props.config.cancelLabel || 'Cancel'}\n </button>\n <button\n onClick={props.onConfirm}\n class={`px-4 py-2 text-sm font-medium rounded-lg text-white transition-colors ${\n isDanger()\n ? 'bg-red-600 hover:bg-red-700'\n : 'bg-blue-600 hover:bg-blue-700'\n }`}\n >\n {props.config.confirmLabel || 'Confirm'}\n </button>\n </div>\n </div>\n )\n}\n\n// ─── Form (delegates to FormFieldRenderer for all field types) ───\n\nconst FormBody: Component<{\n config: FormPromptConfig\n onSubmit: (data: Record<string, unknown>, label: string) => void\n}> = (props) => {\n const [formData, setFormData] = createSignal<Record<string, any>>({})\n\n const updateField = (name: string, value: any) => {\n setFormData((prev) => ({ ...prev, [name]: value }))\n }\n\n const handleSubmit = (e: Event) => {\n e.preventDefault()\n const data = formData()\n const label = Object.entries(data)\n .filter(([, v]) => v !== undefined && v !== '' && !(Array.isArray(v) && v.length === 0))\n .map(([k, v]) => `${k}: ${Array.isArray(v) ? v.join(', ') : v}`)\n .join(', ')\n props.onSubmit(data, label || 'Form submitted')\n }\n\n const isValid = () => {\n const data = formData()\n return (props.config.fields || [])\n .filter((f) => f.required)\n .every((f) => {\n const val = data[f.name]\n if (Array.isArray(val)) return val.length > 0\n if (typeof val === 'boolean') return true\n return val !== undefined && val !== ''\n })\n }\n\n return (\n <form onSubmit={handleSubmit} class=\"flex flex-col gap-3\">\n <For each={props.config.fields}>\n {(field) => (\n <FormFieldRenderer\n field={field as FormFieldParams}\n value={formData()[field.name]}\n onChange={(val) => updateField(field.name, val)}\n formData={formData}\n />\n )}\n </For>\n <div class=\"flex justify-end\">\n <button\n type=\"submit\"\n disabled={!isValid()}\n class=\"px-4 py-2 text-sm font-medium rounded-lg text-white bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors\"\n >\n {props.config.submitLabel || 'Submit'}\n </button>\n </div>\n </form>\n )\n}\n"],"names":["ChatPrompt","props","config","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$5","_$insert","title","$$click","onDismiss","onSubmit","type","value","label","dismissed","_$createComponent","Show","when","dismissLabel","fallback","_tmpl$2","children","Switch","Match","ChoiceBody","onSelect","ConfirmBody","onConfirm","confirmLabel","onCancel","cancelLabel","FormBody","data","_$effect","_p$","_v$","_v$2","_v$3","e","_$setAttribute","t","_$className","a","undefined","_$runHydrationEvents","layoutClass","layout","_el$7","_tmpl$3","For","each","options","option","_el$8","_tmpl$6","_el$1","_el$10","_co$","_$getNextMarker","_el$11","_el$12","_co$2","_el$13","_el$14","_co$3","icon","_el$9","_tmpl$4","description","_el$0","_tmpl$5","isDanger","variant","_el$15","_tmpl$8","_el$20","_el$21","_co$4","_el$17","_el$18","_el$19","message","_el$16","_tmpl$7","_$addEventListener","formData","setFormData","createSignal","updateField","name","prev","handleSubmit","preventDefault","Object","entries","filter","v","Array","isArray","length","map","k","join","isValid","fields","f","required","every","val","_el$22","_tmpl$9","_el$25","_el$26","_co$5","_el$23","_el$24","addEventListener","field","FormFieldRenderer","onChange","submitLabel","_$setProperty","_$delegateEvents"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatPrompt.d.ts","sourceRoot":"","sources":["../../src/components/ChatPrompt.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAqD,MAAM,UAAU,CAAA;AACvF,OAAO,KAAK,EACV,gBAAgB,EAChB,kBAAkB,EAInB,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"ChatPrompt.d.ts","sourceRoot":"","sources":["../../src/components/ChatPrompt.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAqD,MAAM,UAAU,CAAA;AACvF,OAAO,KAAK,EACV,gBAAgB,EAChB,kBAAkB,EAInB,MAAM,mBAAmB,CAAA;AAI1B,MAAM,WAAW,eAAe;IAC9B,2BAA2B;IAC3B,MAAM,EAAE,gBAAgB,CAAA;IACxB,gCAAgC;IAChC,QAAQ,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,CAAA;IAChD,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,UAAU,EAAE,SAAS,CAAC,eAAe,CAuEjD,CAAA"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { delegateEvents, getNextElement, template, insert, createComponent, effect, setAttribute, className, runHydrationEvents, getNextMarker, addEventListener, setProperty } from "solid-js/web";
|
|
2
2
|
import { Show, Switch, Match, For, createSignal } from "solid-js";
|
|
3
|
+
import { FormFieldRenderer } from "./FormFieldRenderer.js";
|
|
3
4
|
var _tmpl$ = /* @__PURE__ */ template(`<div class="w-full max-w-2xl mx-auto mb-2 bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 shadow-lg overflow-hidden"role=dialog style="animation:chat-prompt-slide-up 0.2s ease-out"><div class="flex items-center justify-between px-4 py-2.5 border-b border-gray-100 dark:border-gray-700"><p class="text-sm font-medium text-gray-900 dark:text-white"></p><button></button></div><div class="px-4 py-3"></div><style>
|
|
4
5
|
@keyframes chat-prompt-slide-up {
|
|
5
6
|
from { opacity: 0; transform: translateY(8px); }
|
|
6
7
|
to { opacity: 1; transform: translateY(0); }
|
|
7
8
|
}
|
|
8
|
-
`), _tmpl$2 = /* @__PURE__ */ template(`<svg class="w-4 h-4"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M6 18L18 6M6 6l12 12">`), _tmpl$3 = /* @__PURE__ */ template(`<div>`), _tmpl$4 = /* @__PURE__ */ template(`<span class=mr-2>`), _tmpl$5 = /* @__PURE__ */ template(`<span class="block text-xs text-gray-500 dark:text-gray-400 mt-0.5 font-normal">`), _tmpl$6 = /* @__PURE__ */ template(`<button class="px-4 py-2 text-sm font-medium rounded-lg border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-900 dark:text-white hover:bg-blue-50 hover:border-blue-300 dark:hover:bg-blue-900/30 dark:hover:border-blue-600 transition-colors text-left"><!$><!/><!$><!/><!$><!/>`), _tmpl$7 = /* @__PURE__ */ template(`<p class="text-sm text-gray-600 dark:text-gray-400 mb-3">`), _tmpl$8 = /* @__PURE__ */ template(`<div><!$><!/><div class="flex gap-2 justify-end"><button class="px-4 py-2 text-sm font-medium rounded-lg border border-gray-200 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"></button><button>`), _tmpl$9 = /* @__PURE__ */ template(`<form class="flex flex-col gap-3"><!$><!/><div class="flex justify-end"><button type=submit class="px-4 py-2 text-sm font-medium rounded-lg text-white bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors">`)
|
|
9
|
+
`), _tmpl$2 = /* @__PURE__ */ template(`<svg class="w-4 h-4"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M6 18L18 6M6 6l12 12">`), _tmpl$3 = /* @__PURE__ */ template(`<div>`), _tmpl$4 = /* @__PURE__ */ template(`<span class=mr-2>`), _tmpl$5 = /* @__PURE__ */ template(`<span class="block text-xs text-gray-500 dark:text-gray-400 mt-0.5 font-normal">`), _tmpl$6 = /* @__PURE__ */ template(`<button class="px-4 py-2 text-sm font-medium rounded-lg border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-900 dark:text-white hover:bg-blue-50 hover:border-blue-300 dark:hover:bg-blue-900/30 dark:hover:border-blue-600 transition-colors text-left"><!$><!/><!$><!/><!$><!/>`), _tmpl$7 = /* @__PURE__ */ template(`<p class="text-sm text-gray-600 dark:text-gray-400 mb-3">`), _tmpl$8 = /* @__PURE__ */ template(`<div><!$><!/><div class="flex gap-2 justify-end"><button class="px-4 py-2 text-sm font-medium rounded-lg border border-gray-200 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"></button><button>`), _tmpl$9 = /* @__PURE__ */ template(`<form class="flex flex-col gap-3"><!$><!/><div class="flex justify-end"><button type=submit class="px-4 py-2 text-sm font-medium rounded-lg text-white bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors">`);
|
|
9
10
|
const ChatPrompt = (props) => {
|
|
10
11
|
if (!props.config) return null;
|
|
11
12
|
return (() => {
|
|
@@ -193,14 +194,16 @@ const FormBody = (props) => {
|
|
|
193
194
|
const handleSubmit = (e) => {
|
|
194
195
|
e.preventDefault();
|
|
195
196
|
const data = formData();
|
|
196
|
-
const label = Object.entries(data).filter(([, v]) => v).map(([k, v]) => `${k}: ${v}`).join(", ");
|
|
197
|
+
const label = Object.entries(data).filter(([, v]) => v !== void 0 && v !== "" && !(Array.isArray(v) && v.length === 0)).map(([k, v]) => `${k}: ${Array.isArray(v) ? v.join(", ") : v}`).join(", ");
|
|
197
198
|
props.onSubmit(data, label || "Form submitted");
|
|
198
199
|
};
|
|
199
200
|
const isValid = () => {
|
|
200
201
|
const data = formData();
|
|
201
202
|
return (props.config.fields || []).filter((f) => f.required).every((f) => {
|
|
202
|
-
|
|
203
|
-
|
|
203
|
+
const val = data[f.name];
|
|
204
|
+
if (Array.isArray(val)) return val.length > 0;
|
|
205
|
+
if (typeof val === "boolean") return true;
|
|
206
|
+
return val !== void 0 && val !== "";
|
|
204
207
|
});
|
|
205
208
|
};
|
|
206
209
|
return (() => {
|
|
@@ -210,83 +213,21 @@ const FormBody = (props) => {
|
|
|
210
213
|
get each() {
|
|
211
214
|
return props.config.fields;
|
|
212
215
|
},
|
|
213
|
-
children: (field) => (
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
return getNextElement(_tmpl$0);
|
|
222
|
-
}
|
|
223
|
-
}), _el$33, _co$7);
|
|
224
|
-
insert(_el$27, createComponent(Switch, {
|
|
225
|
-
get children() {
|
|
226
|
-
return [createComponent(Match, {
|
|
227
|
-
get when() {
|
|
228
|
-
return field.type === "textarea";
|
|
229
|
-
},
|
|
230
|
-
get children() {
|
|
231
|
-
var _el$34 = getNextElement(_tmpl$1);
|
|
232
|
-
_el$34.$$input = (e) => updateField(field.name, e.currentTarget.value);
|
|
233
|
-
effect(() => setAttribute(_el$34, "placeholder", field.placeholder));
|
|
234
|
-
effect(() => setProperty(_el$34, "value", formData()[field.name] || ""));
|
|
235
|
-
runHydrationEvents();
|
|
236
|
-
return _el$34;
|
|
237
|
-
}
|
|
238
|
-
}), createComponent(Match, {
|
|
239
|
-
get when() {
|
|
240
|
-
return field.type === "select";
|
|
241
|
-
},
|
|
242
|
-
get children() {
|
|
243
|
-
var _el$35 = getNextElement(_tmpl$10), _el$36 = _el$35.firstChild, _el$37 = _el$36.nextSibling, [_el$38, _co$8] = getNextMarker(_el$37.nextSibling);
|
|
244
|
-
_el$35.addEventListener("change", (e) => updateField(field.name, e.currentTarget.value));
|
|
245
|
-
insert(_el$36, () => field.placeholder || "Select...");
|
|
246
|
-
insert(_el$35, createComponent(For, {
|
|
247
|
-
get each() {
|
|
248
|
-
return field.options;
|
|
249
|
-
},
|
|
250
|
-
children: (opt) => (() => {
|
|
251
|
-
var _el$42 = getNextElement(_tmpl$13);
|
|
252
|
-
insert(_el$42, () => opt.label);
|
|
253
|
-
effect(() => setProperty(_el$42, "value", opt.value));
|
|
254
|
-
return _el$42;
|
|
255
|
-
})()
|
|
256
|
-
}), _el$38, _co$8);
|
|
257
|
-
effect(() => setProperty(_el$35, "value", formData()[field.name] || ""));
|
|
258
|
-
return _el$35;
|
|
259
|
-
}
|
|
260
|
-
}), createComponent(Match, {
|
|
261
|
-
when: true,
|
|
262
|
-
get children() {
|
|
263
|
-
var _el$39 = getNextElement(_tmpl$11);
|
|
264
|
-
_el$39.$$input = (e) => updateField(field.name, e.currentTarget.value);
|
|
265
|
-
effect((_p$) => {
|
|
266
|
-
var _v$4 = field.type === "number" ? "number" : "text", _v$5 = field.placeholder;
|
|
267
|
-
_v$4 !== _p$.e && setAttribute(_el$39, "type", _p$.e = _v$4);
|
|
268
|
-
_v$5 !== _p$.t && setAttribute(_el$39, "placeholder", _p$.t = _v$5);
|
|
269
|
-
return _p$;
|
|
270
|
-
}, {
|
|
271
|
-
e: void 0,
|
|
272
|
-
t: void 0
|
|
273
|
-
});
|
|
274
|
-
effect(() => setProperty(_el$39, "value", formData()[field.name] || ""));
|
|
275
|
-
runHydrationEvents();
|
|
276
|
-
return _el$39;
|
|
277
|
-
}
|
|
278
|
-
})];
|
|
279
|
-
}
|
|
280
|
-
}), _el$41, _co$9);
|
|
281
|
-
return _el$27;
|
|
282
|
-
})()
|
|
216
|
+
children: (field) => createComponent(FormFieldRenderer, {
|
|
217
|
+
field,
|
|
218
|
+
get value() {
|
|
219
|
+
return formData()[field.name];
|
|
220
|
+
},
|
|
221
|
+
onChange: (val) => updateField(field.name, val),
|
|
222
|
+
formData
|
|
223
|
+
})
|
|
283
224
|
}), _el$26, _co$5);
|
|
284
225
|
insert(_el$24, () => props.config.submitLabel || "Submit");
|
|
285
226
|
effect(() => setProperty(_el$24, "disabled", !isValid()));
|
|
286
227
|
return _el$22;
|
|
287
228
|
})();
|
|
288
229
|
};
|
|
289
|
-
delegateEvents(["click"
|
|
230
|
+
delegateEvents(["click"]);
|
|
290
231
|
export {
|
|
291
232
|
ChatPrompt
|
|
292
233
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatPrompt.js","sources":["../../src/components/ChatPrompt.tsx"],"sourcesContent":["/**\n * ChatPrompt — Ephemeral structured interaction above chat input\n * v2.4.0: choice, confirm, form subtypes\n *\n * @experimental — This component may change without major bump until v2.5.0.\n *\n * Renders above the chat input. User responds → Promise resolves → prompt disappears.\n * Supports AbortSignal for cleanup on navigation (C4).\n */\n\nimport { Component, Show, For, createSignal, onCleanup, Switch, Match } from 'solid-js'\nimport type {\n ChatPromptConfig,\n ChatPromptResponse,\n ChoicePromptConfig,\n ConfirmPromptConfig,\n FormPromptConfig,\n} from '../types/chat-bus'\n\nexport interface ChatPromptProps {\n /** Prompt configuration */\n config: ChatPromptConfig\n /** Called when user responds */\n onSubmit: (response: ChatPromptResponse) => void\n /** Called when user dismisses (e.g. \"send as-is\") */\n onDismiss?: () => void\n /** Label for the dismiss button (replaces X icon). Default: shows X icon. */\n dismissLabel?: string\n}\n\n/**\n * @experimental\n * Ephemeral interaction component — choice buttons, confirmation dialog, or quick form.\n * Designed to sit between the chat messages and the input area.\n *\n * @example\n * <ChatPrompt\n * config={{ type: 'choice', title: 'Format?', config: { options: [...] } }}\n * onSubmit={(r) => bus.events.emit('onChatPromptResponse', { streamKey, response: r })}\n * onDismiss={() => setActivePrompt(null)}\n * />\n */\nexport const ChatPrompt: Component<ChatPromptProps> = (props) => {\n // F1: Guard against null/undefined config (e.g. after dismiss clears state)\n if (!props.config) return null\n\n return (\n <div\n class=\"w-full max-w-2xl mx-auto mb-2 bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 shadow-lg overflow-hidden\"\n style={{ animation: 'chat-prompt-slide-up 0.2s ease-out' }}\n role=\"dialog\"\n aria-label={props.config.title}\n >\n {/* Header */}\n <div class=\"flex items-center justify-between px-4 py-2.5 border-b border-gray-100 dark:border-gray-700\">\n <p class=\"text-sm font-medium text-gray-900 dark:text-white\">{props.config.title}</p>\n <button\n onClick={() => {\n props.onDismiss?.()\n props.onSubmit({ type: props.config.type, value: '', label: '', dismissed: true })\n }}\n class={props.dismissLabel\n ? 'px-3 py-1 text-xs font-medium text-blue-600 dark:text-blue-400 hover:bg-blue-50 dark:hover:bg-blue-900/20 rounded-lg transition-colors'\n : 'p-1 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors'\n }\n aria-label={props.dismissLabel || 'Dismiss'}\n >\n <Show when={props.dismissLabel} fallback={\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n }>\n {props.dismissLabel}\n </Show>\n </button>\n </div>\n\n {/* Body — type-specific */}\n <div class=\"px-4 py-3\">\n <Switch>\n <Match when={props.config.type === 'choice'}>\n <ChoiceBody\n config={props.config.config as ChoicePromptConfig}\n onSelect={(value, label) => props.onSubmit({ type: 'choice', value, label })}\n />\n </Match>\n <Match when={props.config.type === 'confirm'}>\n <ConfirmBody\n config={props.config.config as ConfirmPromptConfig}\n onConfirm={() => props.onSubmit({ type: 'confirm', value: 'confirmed', label: (props.config.config as ConfirmPromptConfig).confirmLabel || 'Confirmed' })}\n onCancel={() => {\n props.onDismiss?.()\n props.onSubmit({ type: 'confirm', value: 'cancelled', label: (props.config.config as ConfirmPromptConfig).cancelLabel || 'Cancelled', dismissed: true })\n }}\n />\n </Match>\n <Match when={props.config.type === 'form'}>\n <FormBody\n config={props.config.config as FormPromptConfig}\n onSubmit={(data, label) => props.onSubmit({ type: 'form', value: data, label })}\n />\n </Match>\n </Switch>\n </div>\n\n <style>{`\n @keyframes chat-prompt-slide-up {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n }\n `}</style>\n </div>\n )\n}\n\n// ─── Choice ──────────────────────────────────────────────────\n\nconst ChoiceBody: Component<{\n config: ChoicePromptConfig\n onSelect: (value: string, label: string) => void\n}> = (props) => {\n const layoutClass = () => {\n switch (props.config.layout) {\n case 'vertical': return 'flex flex-col gap-2'\n case 'grid': return 'grid grid-cols-2 gap-2'\n default: return 'flex flex-wrap gap-2'\n }\n }\n\n return (\n <div class={layoutClass()}>\n <For each={props.config.options}>\n {(option) => (\n <button\n onClick={() => props.onSelect(option.value, option.label)}\n class=\"px-4 py-2 text-sm font-medium rounded-lg border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-900 dark:text-white hover:bg-blue-50 hover:border-blue-300 dark:hover:bg-blue-900/30 dark:hover:border-blue-600 transition-colors text-left\"\n >\n <Show when={option.icon}>\n <span class=\"mr-2\">{option.icon}</span>\n </Show>\n {option.label}\n <Show when={option.description}>\n <span class=\"block text-xs text-gray-500 dark:text-gray-400 mt-0.5 font-normal\">{option.description}</span>\n </Show>\n </button>\n )}\n </For>\n </div>\n )\n}\n\n// ─── Confirm ─────────────────────────────────────────────────\n\nconst ConfirmBody: Component<{\n config: ConfirmPromptConfig\n onConfirm: () => void\n onCancel: () => void\n}> = (props) => {\n const isDanger = () => props.config.variant === 'danger'\n\n return (\n <div>\n <Show when={props.config.message}>\n <p class=\"text-sm text-gray-600 dark:text-gray-400 mb-3\">{props.config.message}</p>\n </Show>\n <div class=\"flex gap-2 justify-end\">\n <button\n onClick={props.onCancel}\n class=\"px-4 py-2 text-sm font-medium rounded-lg border border-gray-200 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors\"\n >\n {props.config.cancelLabel || 'Cancel'}\n </button>\n <button\n onClick={props.onConfirm}\n class={`px-4 py-2 text-sm font-medium rounded-lg text-white transition-colors ${\n isDanger()\n ? 'bg-red-600 hover:bg-red-700'\n : 'bg-blue-600 hover:bg-blue-700'\n }`}\n >\n {props.config.confirmLabel || 'Confirm'}\n </button>\n </div>\n </div>\n )\n}\n\n// ─── Form ────────────────────────────────────────────────────\n\nconst FormBody: Component<{\n config: FormPromptConfig\n onSubmit: (data: Record<string, unknown>, label: string) => void\n}> = (props) => {\n const [formData, setFormData] = createSignal<Record<string, string>>({})\n\n const updateField = (name: string, value: string) => {\n setFormData((prev) => ({ ...prev, [name]: value }))\n }\n\n const handleSubmit = (e: Event) => {\n e.preventDefault()\n const data = formData()\n // Build a human-readable label from the form values\n const label = Object.entries(data)\n .filter(([, v]) => v)\n .map(([k, v]) => `${k}: ${v}`)\n .join(', ')\n props.onSubmit(data, label || 'Form submitted')\n }\n\n const isValid = () => {\n const data = formData()\n return (props.config.fields || [])\n .filter((f) => f.required)\n .every((f) => data[f.name]?.trim())\n }\n\n return (\n <form onSubmit={handleSubmit} class=\"flex flex-col gap-3\">\n <For each={props.config.fields}>\n {(field) => (\n <div>\n <label class=\"block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1\">\n {field.label}\n <Show when={field.required}>\n <span class=\"text-red-500 ml-0.5\">*</span>\n </Show>\n </label>\n <Switch>\n <Match when={field.type === 'textarea'}>\n <textarea\n value={formData()[field.name] || ''}\n onInput={(e) => updateField(field.name, e.currentTarget.value)}\n placeholder={field.placeholder}\n rows={3}\n class=\"w-full px-3 py-2 text-sm rounded-lg border border-gray-200 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:border-blue-400 focus:ring-1 focus:ring-blue-400 outline-none transition-colors\"\n />\n </Match>\n <Match when={field.type === 'select'}>\n <select\n value={formData()[field.name] || ''}\n onChange={(e) => updateField(field.name, e.currentTarget.value)}\n class=\"w-full px-3 py-2 text-sm rounded-lg border border-gray-200 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:border-blue-400 focus:ring-1 focus:ring-blue-400 outline-none transition-colors\"\n >\n <option value=\"\">{field.placeholder || 'Select...'}</option>\n <For each={field.options}>\n {(opt) => <option value={opt.value}>{opt.label}</option>}\n </For>\n </select>\n </Match>\n <Match when={true}>\n <input\n type={field.type === 'number' ? 'number' : 'text'}\n value={formData()[field.name] || ''}\n onInput={(e) => updateField(field.name, e.currentTarget.value)}\n placeholder={field.placeholder}\n class=\"w-full px-3 py-2 text-sm rounded-lg border border-gray-200 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:border-blue-400 focus:ring-1 focus:ring-blue-400 outline-none transition-colors\"\n />\n </Match>\n </Switch>\n </div>\n )}\n </For>\n <div class=\"flex justify-end\">\n <button\n type=\"submit\"\n disabled={!isValid()}\n class=\"px-4 py-2 text-sm font-medium rounded-lg text-white bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors\"\n >\n {props.config.submitLabel || 'Submit'}\n </button>\n </div>\n </form>\n )\n}\n"],"names":["ChatPrompt","props","config","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$5","_$insert","title","$$click","onDismiss","onSubmit","type","value","label","dismissed","_$createComponent","Show","when","dismissLabel","fallback","_tmpl$2","children","Switch","Match","ChoiceBody","onSelect","ConfirmBody","onConfirm","confirmLabel","onCancel","cancelLabel","FormBody","data","_$effect","_p$","_v$","_v$2","_v$3","e","_$setAttribute","t","_$className","a","undefined","_$runHydrationEvents","layoutClass","layout","_el$7","_tmpl$3","For","each","options","option","_el$8","_tmpl$6","_el$1","_el$10","_co$","_$getNextMarker","_el$11","_el$12","_co$2","_el$13","_el$14","_co$3","icon","_el$9","_tmpl$4","description","_el$0","_tmpl$5","isDanger","variant","_el$15","_tmpl$8","_el$20","_el$21","_co$4","_el$17","_el$18","_el$19","message","_el$16","_tmpl$7","_$addEventListener","formData","setFormData","createSignal","updateField","name","prev","handleSubmit","preventDefault","Object","entries","filter","v","map","k","join","isValid","fields","f","required","every","trim","_el$22","_tmpl$9","_el$25","_el$26","_co$5","_el$23","_el$24","addEventListener","field","_el$27","_tmpl$12","_el$28","_el$30","_el$31","_co$6","_el$32","_el$33","_co$7","_el$40","_el$41","_co$9","_tmpl$0","_el$34","_tmpl$1","$$input","currentTarget","placeholder","_$setProperty","_el$35","_tmpl$10","_el$36","_el$37","_el$38","_co$8","opt","_el$42","_tmpl$13","_el$39","_tmpl$11","_v$4","_v$5","submitLabel","_$delegateEvents"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ChatPrompt.js","sources":["../../src/components/ChatPrompt.tsx"],"sourcesContent":["/**\n * ChatPrompt — Ephemeral structured interaction above chat input\n * v2.4.0: choice, confirm, form subtypes\n *\n * @experimental — This component may change without major bump until v2.5.0.\n *\n * Renders above the chat input. User responds → Promise resolves → prompt disappears.\n * Supports AbortSignal for cleanup on navigation (C4).\n */\n\nimport { Component, Show, For, createSignal, onCleanup, Switch, Match } from 'solid-js'\nimport type {\n ChatPromptConfig,\n ChatPromptResponse,\n ChoicePromptConfig,\n ConfirmPromptConfig,\n FormPromptConfig,\n} from '../types/chat-bus'\nimport { FormFieldRenderer } from './FormFieldRenderer'\nimport type { FormFieldParams } from '../types'\n\nexport interface ChatPromptProps {\n /** Prompt configuration */\n config: ChatPromptConfig\n /** Called when user responds */\n onSubmit: (response: ChatPromptResponse) => void\n /** Called when user dismisses (e.g. \"send as-is\") */\n onDismiss?: () => void\n /** Label for the dismiss button (replaces X icon). Default: shows X icon. */\n dismissLabel?: string\n}\n\n/**\n * @experimental\n * Ephemeral interaction component — choice buttons, confirmation dialog, or quick form.\n * Designed to sit between the chat messages and the input area.\n *\n * @example\n * <ChatPrompt\n * config={{ type: 'choice', title: 'Format?', config: { options: [...] } }}\n * onSubmit={(r) => bus.events.emit('onChatPromptResponse', { streamKey, response: r })}\n * onDismiss={() => setActivePrompt(null)}\n * />\n */\nexport const ChatPrompt: Component<ChatPromptProps> = (props) => {\n // F1: Guard against null/undefined config (e.g. after dismiss clears state)\n if (!props.config) return null\n\n return (\n <div\n class=\"w-full max-w-2xl mx-auto mb-2 bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 shadow-lg overflow-hidden\"\n style={{ animation: 'chat-prompt-slide-up 0.2s ease-out' }}\n role=\"dialog\"\n aria-label={props.config.title}\n >\n {/* Header */}\n <div class=\"flex items-center justify-between px-4 py-2.5 border-b border-gray-100 dark:border-gray-700\">\n <p class=\"text-sm font-medium text-gray-900 dark:text-white\">{props.config.title}</p>\n <button\n onClick={() => {\n props.onDismiss?.()\n props.onSubmit({ type: props.config.type, value: '', label: '', dismissed: true })\n }}\n class={props.dismissLabel\n ? 'px-3 py-1 text-xs font-medium text-blue-600 dark:text-blue-400 hover:bg-blue-50 dark:hover:bg-blue-900/20 rounded-lg transition-colors'\n : 'p-1 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors'\n }\n aria-label={props.dismissLabel || 'Dismiss'}\n >\n <Show when={props.dismissLabel} fallback={\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n }>\n {props.dismissLabel}\n </Show>\n </button>\n </div>\n\n {/* Body — type-specific */}\n <div class=\"px-4 py-3\">\n <Switch>\n <Match when={props.config.type === 'choice'}>\n <ChoiceBody\n config={props.config.config as ChoicePromptConfig}\n onSelect={(value, label) => props.onSubmit({ type: 'choice', value, label })}\n />\n </Match>\n <Match when={props.config.type === 'confirm'}>\n <ConfirmBody\n config={props.config.config as ConfirmPromptConfig}\n onConfirm={() => props.onSubmit({ type: 'confirm', value: 'confirmed', label: (props.config.config as ConfirmPromptConfig).confirmLabel || 'Confirmed' })}\n onCancel={() => {\n props.onDismiss?.()\n props.onSubmit({ type: 'confirm', value: 'cancelled', label: (props.config.config as ConfirmPromptConfig).cancelLabel || 'Cancelled', dismissed: true })\n }}\n />\n </Match>\n <Match when={props.config.type === 'form'}>\n <FormBody\n config={props.config.config as FormPromptConfig}\n onSubmit={(data, label) => props.onSubmit({ type: 'form', value: data, label })}\n />\n </Match>\n </Switch>\n </div>\n\n <style>{`\n @keyframes chat-prompt-slide-up {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n }\n `}</style>\n </div>\n )\n}\n\n// ─── Choice ──────────────────────────────────────────────────\n\nconst ChoiceBody: Component<{\n config: ChoicePromptConfig\n onSelect: (value: string, label: string) => void\n}> = (props) => {\n const layoutClass = () => {\n switch (props.config.layout) {\n case 'vertical': return 'flex flex-col gap-2'\n case 'grid': return 'grid grid-cols-2 gap-2'\n default: return 'flex flex-wrap gap-2'\n }\n }\n\n return (\n <div class={layoutClass()}>\n <For each={props.config.options}>\n {(option) => (\n <button\n onClick={() => props.onSelect(option.value, option.label)}\n class=\"px-4 py-2 text-sm font-medium rounded-lg border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-900 dark:text-white hover:bg-blue-50 hover:border-blue-300 dark:hover:bg-blue-900/30 dark:hover:border-blue-600 transition-colors text-left\"\n >\n <Show when={option.icon}>\n <span class=\"mr-2\">{option.icon}</span>\n </Show>\n {option.label}\n <Show when={option.description}>\n <span class=\"block text-xs text-gray-500 dark:text-gray-400 mt-0.5 font-normal\">{option.description}</span>\n </Show>\n </button>\n )}\n </For>\n </div>\n )\n}\n\n// ─── Confirm ─────────────────────────────────────────────────\n\nconst ConfirmBody: Component<{\n config: ConfirmPromptConfig\n onConfirm: () => void\n onCancel: () => void\n}> = (props) => {\n const isDanger = () => props.config.variant === 'danger'\n\n return (\n <div>\n <Show when={props.config.message}>\n <p class=\"text-sm text-gray-600 dark:text-gray-400 mb-3\">{props.config.message}</p>\n </Show>\n <div class=\"flex gap-2 justify-end\">\n <button\n onClick={props.onCancel}\n class=\"px-4 py-2 text-sm font-medium rounded-lg border border-gray-200 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors\"\n >\n {props.config.cancelLabel || 'Cancel'}\n </button>\n <button\n onClick={props.onConfirm}\n class={`px-4 py-2 text-sm font-medium rounded-lg text-white transition-colors ${\n isDanger()\n ? 'bg-red-600 hover:bg-red-700'\n : 'bg-blue-600 hover:bg-blue-700'\n }`}\n >\n {props.config.confirmLabel || 'Confirm'}\n </button>\n </div>\n </div>\n )\n}\n\n// ─── Form (delegates to FormFieldRenderer for all field types) ───\n\nconst FormBody: Component<{\n config: FormPromptConfig\n onSubmit: (data: Record<string, unknown>, label: string) => void\n}> = (props) => {\n const [formData, setFormData] = createSignal<Record<string, any>>({})\n\n const updateField = (name: string, value: any) => {\n setFormData((prev) => ({ ...prev, [name]: value }))\n }\n\n const handleSubmit = (e: Event) => {\n e.preventDefault()\n const data = formData()\n const label = Object.entries(data)\n .filter(([, v]) => v !== undefined && v !== '' && !(Array.isArray(v) && v.length === 0))\n .map(([k, v]) => `${k}: ${Array.isArray(v) ? v.join(', ') : v}`)\n .join(', ')\n props.onSubmit(data, label || 'Form submitted')\n }\n\n const isValid = () => {\n const data = formData()\n return (props.config.fields || [])\n .filter((f) => f.required)\n .every((f) => {\n const val = data[f.name]\n if (Array.isArray(val)) return val.length > 0\n if (typeof val === 'boolean') return true\n return val !== undefined && val !== ''\n })\n }\n\n return (\n <form onSubmit={handleSubmit} class=\"flex flex-col gap-3\">\n <For each={props.config.fields}>\n {(field) => (\n <FormFieldRenderer\n field={field as FormFieldParams}\n value={formData()[field.name]}\n onChange={(val) => updateField(field.name, val)}\n formData={formData}\n />\n )}\n </For>\n <div class=\"flex justify-end\">\n <button\n type=\"submit\"\n disabled={!isValid()}\n class=\"px-4 py-2 text-sm font-medium rounded-lg text-white bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors\"\n >\n {props.config.submitLabel || 'Submit'}\n </button>\n </div>\n </form>\n )\n}\n"],"names":["ChatPrompt","props","config","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$5","_$insert","title","$$click","onDismiss","onSubmit","type","value","label","dismissed","_$createComponent","Show","when","dismissLabel","fallback","_tmpl$2","children","Switch","Match","ChoiceBody","onSelect","ConfirmBody","onConfirm","confirmLabel","onCancel","cancelLabel","FormBody","data","_$effect","_p$","_v$","_v$2","_v$3","e","_$setAttribute","t","_$className","a","undefined","_$runHydrationEvents","layoutClass","layout","_el$7","_tmpl$3","For","each","options","option","_el$8","_tmpl$6","_el$1","_el$10","_co$","_$getNextMarker","_el$11","_el$12","_co$2","_el$13","_el$14","_co$3","icon","_el$9","_tmpl$4","description","_el$0","_tmpl$5","isDanger","variant","_el$15","_tmpl$8","_el$20","_el$21","_co$4","_el$17","_el$18","_el$19","message","_el$16","_tmpl$7","_$addEventListener","formData","setFormData","createSignal","updateField","name","prev","handleSubmit","preventDefault","Object","entries","filter","v","Array","isArray","length","map","k","join","isValid","fields","f","required","every","val","_el$22","_tmpl$9","_el$25","_el$26","_co$5","_el$23","_el$24","addEventListener","field","FormFieldRenderer","onChange","submitLabel","_$setProperty","_$delegateEvents"],"mappings":";;;;;;;;;AA4CO,MAAMA,aAA0CC,CAAAA,UAAU;AAE/D,MAAI,CAACA,MAAMC,OAAQ,QAAO;AAE1B,UAAA,MAAA;AAAA,QAAAC,OAAAC,eAAAC,MAAA,GAAAC,QAAAH,KAAAI,YAAAC,QAAAF,MAAAC,YAAAE,QAAAD,MAAAE,aAAAC,QAAAL,MAAAI;AAAAE,WAAAJ,OAAA,MASoEP,MAAMC,OAAOW,KAAK;AAAAJ,UAAAK,UAErE,MAAM;;AACbb,kBAAMc,cAANd;AACAA,YAAMe,SAAS;AAAA,QAAEC,MAAMhB,MAAMC,OAAOe;AAAAA,QAAMC,OAAO;AAAA,QAAIC,OAAO;AAAA,QAAIC,WAAW;AAAA,MAAA,CAAM;AAAA,IACnF;AAACR,WAAAH,OAAAY,gBAOAC,MAAI;AAAA,MAAA,IAACC,OAAI;AAAA,eAAEtB,MAAMuB;AAAAA,MAAY;AAAA,MAAA,IAAEC,WAAQ;AAAA,eAAArB,eAAAsB,OAAA;AAAA,MAAA;AAAA,MAAA,IAAAC,WAAA;AAAA,eAKrC1B,MAAMuB;AAAAA,MAAY;AAAA,IAAA,CAAA,CAAA;AAAAZ,WAAAD,OAAAU,gBAOtBO,QAAM;AAAA,MAAA,IAAAD,WAAA;AAAA,eAAA,CAAAN,gBACJQ,OAAK;AAAA,UAAA,IAACN,OAAI;AAAA,mBAAEtB,MAAMC,OAAOe,SAAS;AAAA,UAAQ;AAAA,UAAA,IAAAU,WAAA;AAAA,mBAAAN,gBACxCS,YAAU;AAAA,cAAA,IACT5B,SAAM;AAAA,uBAAED,MAAMC,OAAOA;AAAAA,cAA4B;AAAA,cACjD6B,UAAUA,CAACb,OAAOC,UAAUlB,MAAMe,SAAS;AAAA,gBAAEC,MAAM;AAAA,gBAAUC;AAAAA,gBAAOC;AAAAA,cAAAA,CAAO;AAAA,YAAA,CAAC;AAAA,UAAA;AAAA,QAAA,CAAA,GAAAE,gBAG/EQ,OAAK;AAAA,UAAA,IAACN,OAAI;AAAA,mBAAEtB,MAAMC,OAAOe,SAAS;AAAA,UAAS;AAAA,UAAA,IAAAU,WAAA;AAAA,mBAAAN,gBACzCW,aAAW;AAAA,cAAA,IACV9B,SAAM;AAAA,uBAAED,MAAMC,OAAOA;AAAAA,cAA6B;AAAA,cAClD+B,WAAWA,MAAMhC,MAAMe,SAAS;AAAA,gBAAEC,MAAM;AAAA,gBAAWC,OAAO;AAAA,gBAAaC,OAAQlB,MAAMC,OAAOA,OAA+BgC,gBAAgB;AAAA,cAAA,CAAa;AAAA,cACxJC,UAAUA,MAAM;;AACdlC,4BAAMc,cAANd;AACAA,sBAAMe,SAAS;AAAA,kBAAEC,MAAM;AAAA,kBAAWC,OAAO;AAAA,kBAAaC,OAAQlB,MAAMC,OAAOA,OAA+BkC,eAAe;AAAA,kBAAahB,WAAW;AAAA,gBAAA,CAAM;AAAA,cACzJ;AAAA,YAAA,CAAC;AAAA,UAAA;AAAA,QAAA,CAAA,GAAAC,gBAGJQ,OAAK;AAAA,UAAA,IAACN,OAAI;AAAA,mBAAEtB,MAAMC,OAAOe,SAAS;AAAA,UAAM;AAAA,UAAA,IAAAU,WAAA;AAAA,mBAAAN,gBACtCgB,UAAQ;AAAA,cAAA,IACPnC,SAAM;AAAA,uBAAED,MAAMC,OAAOA;AAAAA,cAA0B;AAAA,cAC/Cc,UAAUA,CAACsB,MAAMnB,UAAUlB,MAAMe,SAAS;AAAA,gBAAEC,MAAM;AAAA,gBAAQC,OAAOoB;AAAAA,gBAAMnB;AAAAA,cAAAA,CAAO;AAAA,YAAA,CAAC;AAAA,UAAA;AAAA,QAAA,CAAA,CAAA;AAAA,MAAA;AAAA,IAAA,CAAA,CAAA;AAAAoB,WAAAC,CAAAA,QAAA;AAAA,UAAAC,MAhD3ExC,MAAMC,OAAOW,OAAK6B,OAUnBzC,MAAMuB,eACT,2IACA,0IAAwImB,OAEhI1C,MAAMuB,gBAAgB;AAASiB,cAAAD,IAAAI,KAAAC,aAAA1C,MAAA,cAAAqC,IAAAI,IAAAH,GAAA;AAAAC,eAAAF,IAAAM,KAAAC,UAAAtC,OAAA+B,IAAAM,IAAAJ,IAAA;AAAAC,eAAAH,IAAAQ,KAAAH,aAAApC,OAAA,cAAA+B,IAAAQ,IAAAL,IAAA;AAAA,aAAAH;AAAAA,IAAA,GAAA;AAAA,MAAAI,GAAAK;AAAAA,MAAAH,GAAAG;AAAAA,MAAAD,GAAAC;AAAAA,IAAAA,CAAA;AAAAC,uBAAAA;AAAA,WAAA/C;AAAAA,EAAA,GAAA;AAgDrD;AAIA,MAAM2B,aAGA7B,CAAAA,UAAU;AACd,QAAMkD,cAAcA,MAAM;AACxB,YAAQlD,MAAMC,OAAOkD,QAAAA;AAAAA,MACnB,KAAK;AAAY,eAAO;AAAA,MACxB,KAAK;AAAQ,eAAO;AAAA,MACpB;AAAS,eAAO;AAAA,IAAA;AAAA,EAEpB;AAEA,UAAA,MAAA;AAAA,QAAAC,QAAAjD,eAAAkD,OAAA;AAAA1C,WAAAyC,OAAAhC,gBAEKkC,KAAG;AAAA,MAAA,IAACC,OAAI;AAAA,eAAEvD,MAAMC,OAAOuD;AAAAA,MAAO;AAAA,MAAA9B,UAC3B+B,aAAM,MAAA;AAAA,YAAAC,QAAAvD,eAAAwD,OAAA,GAAAC,QAAAF,MAAApD,YAAA,CAAAuD,QAAAC,IAAA,IAAAC,cAAAH,MAAAnD,WAAA,GAAAuD,SAAAH,OAAApD,aAAA,CAAAwD,QAAAC,KAAA,IAAAH,cAAAC,OAAAvD,WAAA,GAAA0D,SAAAF,OAAAxD,aAAA,CAAA2D,QAAAC,KAAA,IAAAN,cAAAI,OAAA1D,WAAA;AAAAiD,cAAA7C,UAEK,MAAMb,MAAM8B,SAAS2B,OAAOxC,OAAOwC,OAAOvC,KAAK;AAACP,eAAA+C,OAAAtC,gBAGxDC,MAAI;AAAA,UAAA,IAACC,OAAI;AAAA,mBAAEmC,OAAOa;AAAAA,UAAI;AAAA,UAAA,IAAA5C,WAAA;AAAA,gBAAA6C,QAAApE,eAAAqE,OAAA;AAAA7D,mBAAA4D,OAAA,MACDd,OAAOa,IAAI;AAAA,mBAAAC;AAAAA,UAAA;AAAA,QAAA,CAAA,GAAAV,QAAAC,IAAA;AAAAnD,eAAA+C,OAAA,MAEhCD,OAAOvC,OAAK+C,QAAAC,KAAA;AAAAvD,eAAA+C,OAAAtC,gBACZC,MAAI;AAAA,UAAA,IAACC,OAAI;AAAA,mBAAEmC,OAAOgB;AAAAA,UAAW;AAAA,UAAA,IAAA/C,WAAA;AAAA,gBAAAgD,QAAAvE,eAAAwE,OAAA;AAAAhE,mBAAA+D,OAAA,MACqDjB,OAAOgB,WAAW;AAAA,mBAAAC;AAAAA,UAAA;AAAA,QAAA,CAAA,GAAAN,QAAAC,KAAA;AAAApB,2BAAAA;AAAA,eAAAS;AAAAA,MAAA,GAAA;AAAA,IAAA,CAGxG,CAAA;AAAApB,iBAAAQ,UAAAM,OAfOF,YAAAA,CAAa,CAAA;AAAA,WAAAE;AAAAA,EAAA,GAAA;AAmB7B;AAIA,MAAMrB,cAIA/B,CAAAA,UAAU;AACd,QAAM4E,WAAWA,MAAM5E,MAAMC,OAAO4E,YAAY;AAEhD,UAAA,MAAA;AAAA,QAAAC,SAAA3E,eAAA4E,OAAA,GAAAC,SAAAF,OAAAxE,YAAA,CAAA2E,QAAAC,KAAA,IAAAnB,cAAAiB,OAAAvE,WAAA,GAAA0E,SAAAF,OAAAxE,aAAA2E,SAAAD,OAAA7E,YAAA+E,SAAAD,OAAA3E;AAAAE,WAAAmE,QAAA1D,gBAEKC,MAAI;AAAA,MAAA,IAACC,OAAI;AAAA,eAAEtB,MAAMC,OAAOqF;AAAAA,MAAO;AAAA,MAAA,IAAA5D,WAAA;AAAA,YAAA6D,SAAApF,eAAAqF,OAAA;AAAA7E,eAAA4E,QAAA,MAC4BvF,MAAMC,OAAOqF,OAAO;AAAA,eAAAC;AAAAA,MAAA;AAAA,IAAA,CAAA,GAAAN,QAAAC,KAAA;AAAAO,qBAAAL,QAAA,SAInEpF,MAAMkC,UAAQ,IAAA;AAAAvB,WAAAyE,QAAA,MAGtBpF,MAAMC,OAAOkC,eAAe,QAAQ;AAAAsD,qBAAAJ,QAAA,SAG5BrF,MAAMgC,WAAS,IAAA;AAAArB,WAAA0E,QAAA,MAOvBrF,MAAMC,OAAOgC,gBAAgB,SAAS;AAAAK,WAAA,MAAAQ,UAAAuC,QANhC,yEACLT,aACI,gCACA,+BAA+B,EACnC,CAAA;AAAA3B,uBAAAA;AAAA,WAAA6B;AAAAA,EAAA,GAAA;AAOZ;AAIA,MAAM1C,WAGApC,CAAAA,UAAU;AACd,QAAM,CAAC0F,UAAUC,WAAW,IAAIC,aAAkC,CAAA,CAAE;AAEpE,QAAMC,cAAcA,CAACC,MAAc7E,UAAe;AAChD0E,gBAAaI,CAAAA,UAAU;AAAA,MAAE,GAAGA;AAAAA,MAAM,CAACD,IAAI,GAAG7E;AAAAA,IAAAA,EAAQ;AAAA,EACpD;AAEA,QAAM+E,eAAeA,CAACrD,MAAa;AACjCA,MAAEsD,eAAAA;AACF,UAAM5D,OAAOqD,SAAAA;AACb,UAAMxE,QAAQgF,OAAOC,QAAQ9D,IAAI,EAC9B+D,OAAO,CAAC,CAAA,EAAGC,CAAC,MAAMA,MAAMrD,UAAaqD,MAAM,MAAM,EAAEC,MAAMC,QAAQF,CAAC,KAAKA,EAAEG,WAAW,EAAE,EACtFC,IAAI,CAAC,CAACC,GAAGL,CAAC,MAAM,GAAGK,CAAC,KAAKJ,MAAMC,QAAQF,CAAC,IAAIA,EAAEM,KAAK,IAAI,IAAIN,CAAC,EAAE,EAC9DM,KAAK,IAAI;AACZ3G,UAAMe,SAASsB,MAAMnB,SAAS,gBAAgB;AAAA,EAChD;AAEA,QAAM0F,UAAUA,MAAM;AACpB,UAAMvE,OAAOqD,SAAAA;AACb,YAAQ1F,MAAMC,OAAO4G,UAAU,CAAA,GAC5BT,OAAQU,CAAAA,MAAMA,EAAEC,QAAQ,EACxBC,MAAOF,CAAAA,MAAM;AACZ,YAAMG,MAAM5E,KAAKyE,EAAEhB,IAAI;AACvB,UAAIQ,MAAMC,QAAQU,GAAG,EAAG,QAAOA,IAAIT,SAAS;AAC5C,UAAI,OAAOS,QAAQ,UAAW,QAAO;AACrC,aAAOA,QAAQjE,UAAaiE,QAAQ;AAAA,IACtC,CAAC;AAAA,EACL;AAEA,UAAA,MAAA;AAAA,QAAAC,SAAA/G,eAAAgH,OAAA,GAAAC,SAAAF,OAAA5G,YAAA,CAAA+G,QAAAC,KAAA,IAAAvD,cAAAqD,OAAA3G,WAAA,GAAA8G,SAAAF,OAAA5G,aAAA+G,SAAAD,OAAAjH;AAAA4G,WAAAO,iBAAA,UACkBzB,YAAY;AAAArF,WAAAuG,QAAA9F,gBACzBkC,KAAG;AAAA,MAAA,IAACC,OAAI;AAAA,eAAEvD,MAAMC,OAAO4G;AAAAA,MAAM;AAAA,MAAAnF,UAC1BgG,CAAAA,UAAKtG,gBACJuG,mBAAiB;AAAA,QAChBD;AAAAA,QAA+B,IAC/BzG,QAAK;AAAA,iBAAEyE,SAAAA,EAAWgC,MAAM5B,IAAI;AAAA,QAAC;AAAA,QAC7B8B,UAAWX,CAAAA,QAAQpB,YAAY6B,MAAM5B,MAAMmB,GAAG;AAAA,QAC9CvB;AAAAA,MAAAA,CAAkB;AAAA,IAAA,CAErB,GAAA2B,QAAAC,KAAA;AAAA3G,WAAA6G,QAAA,MAQExH,MAAMC,OAAO4H,eAAe,QAAQ;AAAAvF,WAAA,MAAAwF,YAAAN,oBAH3B,CAACZ,QAAAA,CAAS,CAAA;AAAA,WAAAM;AAAAA,EAAA,GAAA;AAQ9B;AAACa,eAAA,CAAA,OAAA,CAAA;"}
|