glass-ui-solid 0.3.4 → 0.4.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/Autocomplete/Autocomplete.js +32 -32
- package/dist/components/Autocomplete/Autocomplete.js.map +1 -1
- package/dist/components/Chat/Chat.d.ts.map +1 -1
- package/dist/components/Chat/Chat.js +3 -0
- package/dist/components/Chat/Chat.js.map +1 -1
- package/dist/components/Chat/ChatInput.d.ts.map +1 -1
- package/dist/components/Chat/ChatInput.js +34 -34
- package/dist/components/Chat/ChatInput.js.map +1 -1
- package/dist/components/Chat/ChatMessage.d.ts.map +1 -1
- package/dist/components/Chat/ChatMessage.js +68 -39
- package/dist/components/Chat/ChatMessage.js.map +1 -1
- package/dist/components/Chat/ChatMessageList.d.ts.map +1 -1
- package/dist/components/Chat/ChatMessageList.js +60 -57
- package/dist/components/Chat/ChatMessageList.js.map +1 -1
- package/dist/components/Chat/ChatToolCall.d.ts +7 -0
- package/dist/components/Chat/ChatToolCall.d.ts.map +1 -0
- package/dist/components/Chat/ChatToolCall.js +207 -0
- package/dist/components/Chat/ChatToolCall.js.map +1 -0
- package/dist/components/Chat/icons.d.ts +4 -0
- package/dist/components/Chat/icons.d.ts.map +1 -1
- package/dist/components/Chat/icons.js +33 -19
- package/dist/components/Chat/icons.js.map +1 -1
- package/dist/components/Chat/index.d.ts +2 -1
- package/dist/components/Chat/index.d.ts.map +1 -1
- package/dist/components/Chat/types.d.ts +31 -1
- package/dist/components/Chat/types.d.ts.map +1 -1
- package/dist/components/CommandPalette/CommandPalette.d.ts.map +1 -1
- package/dist/components/CommandPalette/CommandPalette.js +56 -55
- package/dist/components/CommandPalette/CommandPalette.js.map +1 -1
- package/dist/components/ContextMenu/ContextMenuItem.js +13 -13
- package/dist/components/ContextMenu/ContextMenuItem.js.map +1 -1
- package/dist/components/DatePicker/DatePicker.js +28 -28
- package/dist/components/DatePicker/DatePicker.js.map +1 -1
- package/dist/components/DatePicker/DateRangePicker.js +2 -2
- package/dist/components/DatePicker/DateRangePicker.js.map +1 -1
- package/dist/components/ErrorDisplay/ErrorDisplay.js +5 -5
- package/dist/components/ErrorDisplay/ErrorDisplay.js.map +1 -1
- package/dist/components/FileUpload/FileUpload.js +24 -24
- package/dist/components/FileUpload/FileUpload.js.map +1 -1
- package/dist/components/Input/Input.js +2 -2
- package/dist/components/Input/Input.js.map +1 -1
- package/dist/components/Input/Select.js +7 -7
- package/dist/components/Input/Select.js.map +1 -1
- package/dist/components/Input/Textarea.js +18 -18
- package/dist/components/Input/Textarea.js.map +1 -1
- package/dist/components/Markdown/Markdown.d.ts.map +1 -1
- package/dist/components/Markdown/Markdown.js +81 -19
- package/dist/components/Markdown/Markdown.js.map +1 -1
- package/dist/components/Markdown/index.d.ts +1 -1
- package/dist/components/Markdown/index.d.ts.map +1 -1
- package/dist/components/Markdown/types.d.ts +25 -0
- package/dist/components/Markdown/types.d.ts.map +1 -1
- package/dist/components/NumberInput/NumberInput.js +20 -20
- package/dist/components/NumberInput/NumberInput.js.map +1 -1
- package/dist/components/RadioGroup/RadioGroup.js +1 -1
- package/dist/components/RadioGroup/RadioGroup.js.map +1 -1
- package/dist/components/Sheet/Sheet.js +36 -36
- package/dist/components/Sheet/Sheet.js.map +1 -1
- package/dist/components/Snackbar/SnackbarContainer.d.ts.map +1 -1
- package/dist/components/Snackbar/SnackbarContainer.js +17 -26
- package/dist/components/Snackbar/SnackbarContainer.js.map +1 -1
- package/dist/components/index.d.ts +6 -6
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/shared/createNotificationStore.d.ts.map +1 -1
- package/dist/components/shared/createNotificationStore.js +42 -34
- package/dist/components/shared/createNotificationStore.js.map +1 -1
- package/dist/components/virtual/useVirtualizer.d.ts +1 -1
- package/dist/components/virtual/useVirtualizer.d.ts.map +1 -1
- package/dist/components/virtual/useVirtualizer.js +126 -117
- package/dist/components/virtual/useVirtualizer.js.map +1 -1
- package/dist/constants/animations.d.ts +4 -0
- package/dist/constants/animations.d.ts.map +1 -1
- package/dist/constants/animations.js +14 -12
- package/dist/constants/animations.js.map +1 -1
- package/dist/hooks/useBodyScrollLock.d.ts.map +1 -1
- package/dist/hooks/useBodyScrollLock.js +11 -11
- package/dist/hooks/useBodyScrollLock.js.map +1 -1
- package/dist/hooks/useCopyToClipboard.d.ts.map +1 -1
- package/dist/hooks/useCopyToClipboard.js +10 -7
- package/dist/hooks/useCopyToClipboard.js.map +1 -1
- package/dist/index.js +61 -59
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { template as b, insert as s, createComponent as u, effect as I, setAttribute as _, use as R, memo as ae, className as A, style as ie, delegateEvents as oe } from "solid-js/web";
|
|
2
|
-
import { createSignal as M, createEffect as V, createMemo as z, on as se, onCleanup as
|
|
3
|
-
import { useClickOutside as
|
|
2
|
+
import { createSignal as M, createEffect as V, createMemo as z, on as se, onCleanup as ce, Show as C, For as K } from "solid-js";
|
|
3
|
+
import { useClickOutside as de } from "../../hooks/useClickOutside.js";
|
|
4
4
|
import { Spinner as ue } from "../Spinner/Spinner.js";
|
|
5
5
|
import { CloseIcon as fe } from "../shared/icons/CloseIcon.js";
|
|
6
6
|
import { ChevronDownIcon as he } from "../shared/icons/ChevronIcon.js";
|
|
7
7
|
import { PortalWithDarkMode as ve } from "../shared/PortalWithDarkMode/PortalWithDarkMode.js";
|
|
8
8
|
import { DROPDOWN_ITEM_SIZE_CLASSES as ge, INPUT_SIZE_CLASSES as me } from "../../constants/styles.js";
|
|
9
|
-
var q = /* @__PURE__ */ b("<span>"), be = /* @__PURE__ */ b('<mark class="bg-primary-200 dark:bg-primary-700/50 text-inherit rounded-sm px-0.5">'), xe = /* @__PURE__ */ b('<label class="block text-sm font-medium text-surface-700 dark:text-surface-300 mb-1.5">'), we = /* @__PURE__ */ b("<div class=pointer-events-none>"), $e = /* @__PURE__ */ b('<button type=button class="p-1 rounded-full text-surface-400 hover:text-surface-600 dark:hover:text-surface-300 hover:bg-surface-200/50 dark:hover:bg-surface-700/50 transition-colors"tabindex=-1 aria-label="Clear selection">'), ke = /* @__PURE__ */ b('<button type=button class="p-1 text-surface-400 cursor-pointer disabled:cursor-not-allowed"tabindex=-1>'), Ce = /* @__PURE__ */ b('<p class="mt-1.5 text-sm text-
|
|
9
|
+
var q = /* @__PURE__ */ b("<span>"), be = /* @__PURE__ */ b('<mark class="bg-primary-200 dark:bg-primary-700/50 text-inherit rounded-sm px-0.5">'), xe = /* @__PURE__ */ b('<label class="block text-sm font-medium text-surface-700 dark:text-surface-300 mb-1.5">'), we = /* @__PURE__ */ b("<div class=pointer-events-none>"), $e = /* @__PURE__ */ b('<button type=button class="p-1 rounded-full text-surface-400 hover:text-surface-600 dark:hover:text-surface-300 hover:bg-surface-200/50 dark:hover:bg-surface-700/50 transition-colors"tabindex=-1 aria-label="Clear selection">'), ke = /* @__PURE__ */ b('<button type=button class="p-1 text-surface-400 cursor-pointer disabled:cursor-not-allowed"tabindex=-1>'), Ce = /* @__PURE__ */ b('<p class="mt-1.5 text-sm text-error-500 dark:text-error-400">'), ye = /* @__PURE__ */ b('<div class="fixed z-50 glass-card rounded-xl shadow-lg overflow-hidden animate-in fade-in zoom-in-95 duration-150"role=listbox><div class="max-h-60 overflow-y-auto scrollbar-thin py-1">'), Ie = /* @__PURE__ */ b('<div><div class=relative><input type=text autocomplete=off role=combobox aria-haspopup=listbox aria-autocomplete=list><div class="absolute inset-y-0 right-0 flex items-center gap-1 pr-2">'), _e = /* @__PURE__ */ b("<div>"), Se = /* @__PURE__ */ b("<button type=button data-option role=option tabindex=-1>");
|
|
10
10
|
const Oe = (e, i) => e.label.toLowerCase().includes(i.toLowerCase()), Ee = (e) => {
|
|
11
11
|
const i = z(() => {
|
|
12
12
|
if (!e.highlight.trim())
|
|
@@ -15,15 +15,15 @@ const Oe = (e, i) => e.label.toLowerCase().includes(i.toLowerCase()), Ee = (e) =
|
|
|
15
15
|
match: !1
|
|
16
16
|
}];
|
|
17
17
|
const w = e.text.toLowerCase(), f = e.highlight.toLowerCase(), r = [];
|
|
18
|
-
let g = 0,
|
|
19
|
-
for (;
|
|
20
|
-
|
|
21
|
-
text: e.text.slice(g,
|
|
18
|
+
let g = 0, c = w.indexOf(f, g);
|
|
19
|
+
for (; c !== -1; )
|
|
20
|
+
c > g && r.push({
|
|
21
|
+
text: e.text.slice(g, c),
|
|
22
22
|
match: !1
|
|
23
23
|
}), r.push({
|
|
24
|
-
text: e.text.slice(
|
|
24
|
+
text: e.text.slice(c, c + e.highlight.length),
|
|
25
25
|
match: !0
|
|
26
|
-
}), g =
|
|
26
|
+
}), g = c + e.highlight.length, c = w.indexOf(f, g);
|
|
27
27
|
return g < e.text.length && r.push({
|
|
28
28
|
text: e.text.slice(g),
|
|
29
29
|
match: !1
|
|
@@ -56,7 +56,7 @@ const Oe = (e, i) => e.label.toLowerCase().includes(i.toLowerCase()), Ee = (e) =
|
|
|
56
56
|
})), w;
|
|
57
57
|
})();
|
|
58
58
|
}, Re = (e) => {
|
|
59
|
-
const [i, w] = M(!1), [f, r] = M(""), [g,
|
|
59
|
+
const [i, w] = M(!1), [f, r] = M(""), [g, c] = M(-1);
|
|
60
60
|
let T, O, y, H = !1;
|
|
61
61
|
const G = (t) => {
|
|
62
62
|
T = t, typeof e.ref == "function" ? e.ref(t) : e.ref;
|
|
@@ -72,7 +72,7 @@ const Oe = (e, i) => e.label.toLowerCase().includes(i.toLowerCase()), Ee = (e) =
|
|
|
72
72
|
V(se(() => F(), () => {
|
|
73
73
|
if (i()) {
|
|
74
74
|
const t = E().length > 0 ? 0 : -1;
|
|
75
|
-
|
|
75
|
+
c(t);
|
|
76
76
|
}
|
|
77
77
|
})), V(() => {
|
|
78
78
|
const t = g();
|
|
@@ -88,11 +88,11 @@ const Oe = (e, i) => e.label.toLowerCase().includes(i.toLowerCase()), Ee = (e) =
|
|
|
88
88
|
return;
|
|
89
89
|
w(!0);
|
|
90
90
|
const t = E().length > 0 ? 0 : -1;
|
|
91
|
-
|
|
91
|
+
c(t);
|
|
92
92
|
}, X = () => {
|
|
93
93
|
e.disabled || (i() ? $() : (L(), T?.focus()));
|
|
94
94
|
}, $ = () => {
|
|
95
|
-
w(!1),
|
|
95
|
+
w(!1), c(-1);
|
|
96
96
|
}, N = (t) => {
|
|
97
97
|
t.disabled || (r(t.label), e.onChange(t.value), $(), H = !0, T?.focus());
|
|
98
98
|
}, Y = (t) => {
|
|
@@ -110,48 +110,48 @@ const Oe = (e, i) => e.label.toLowerCase().includes(i.toLowerCase()), Ee = (e) =
|
|
|
110
110
|
y?.contains(o) || setTimeout(() => {
|
|
111
111
|
if (!i())
|
|
112
112
|
return;
|
|
113
|
-
const l = e.options.find((
|
|
113
|
+
const l = e.options.find((d) => d.label.toLowerCase() === f().toLowerCase());
|
|
114
114
|
if (l)
|
|
115
115
|
e.onChange(l.value), r(l.label);
|
|
116
116
|
else if (e.allowCustomValue)
|
|
117
117
|
e.onChange(f());
|
|
118
118
|
else {
|
|
119
|
-
const
|
|
120
|
-
r(
|
|
119
|
+
const d = e.options.find((x) => x.value === e.value);
|
|
120
|
+
r(d?.label ?? "");
|
|
121
121
|
}
|
|
122
122
|
$();
|
|
123
123
|
}, 150);
|
|
124
124
|
}, ne = (t) => {
|
|
125
|
-
const o = E(), l = o.length,
|
|
125
|
+
const o = E(), l = o.length, d = i(), x = g();
|
|
126
126
|
switch (t.key) {
|
|
127
127
|
case "ArrowDown":
|
|
128
|
-
t.preventDefault(),
|
|
128
|
+
t.preventDefault(), d ? l > 0 && c((n) => Math.min(n + 1, l - 1)) : L();
|
|
129
129
|
break;
|
|
130
130
|
case "ArrowUp":
|
|
131
|
-
t.preventDefault(),
|
|
131
|
+
t.preventDefault(), d && l > 0 && c((n) => Math.max(n - 1, 0));
|
|
132
132
|
break;
|
|
133
133
|
case "Enter":
|
|
134
|
-
t.preventDefault(),
|
|
134
|
+
t.preventDefault(), d && x >= 0 && x < l ? N(o[x]) : e.allowCustomValue && f().trim() && (e.onChange(f()), $());
|
|
135
135
|
break;
|
|
136
136
|
case "Escape":
|
|
137
|
-
if (
|
|
137
|
+
if (d) {
|
|
138
138
|
t.preventDefault(), $();
|
|
139
139
|
const n = e.options.find((h) => h.value === e.value);
|
|
140
140
|
r(n?.label ?? (e.allowCustomValue ? e.value : ""));
|
|
141
141
|
}
|
|
142
142
|
break;
|
|
143
143
|
case "Tab":
|
|
144
|
-
|
|
144
|
+
d && $();
|
|
145
145
|
break;
|
|
146
146
|
case "Home":
|
|
147
|
-
|
|
147
|
+
d && l > 0 && (t.preventDefault(), c(0));
|
|
148
148
|
break;
|
|
149
149
|
case "End":
|
|
150
|
-
|
|
150
|
+
d && l > 0 && (t.preventDefault(), c(l - 1));
|
|
151
151
|
break;
|
|
152
152
|
}
|
|
153
153
|
};
|
|
154
|
-
|
|
154
|
+
de({
|
|
155
155
|
refs: () => [O, y],
|
|
156
156
|
onClickOutside: $,
|
|
157
157
|
enabled: i
|
|
@@ -161,7 +161,7 @@ const Oe = (e, i) => e.label.toLowerCase().includes(i.toLowerCase()), Ee = (e) =
|
|
|
161
161
|
const t = (o) => {
|
|
162
162
|
y?.contains(o.target) || $();
|
|
163
163
|
};
|
|
164
|
-
window.addEventListener("scroll", t, !0),
|
|
164
|
+
window.addEventListener("scroll", t, !0), ce(() => window.removeEventListener("scroll", t, !0));
|
|
165
165
|
});
|
|
166
166
|
const le = z(() => {
|
|
167
167
|
if (!i() || !O)
|
|
@@ -178,7 +178,7 @@ const Oe = (e, i) => e.label.toLowerCase().includes(i.toLowerCase()), Ee = (e) =
|
|
|
178
178
|
};
|
|
179
179
|
}), re = () => me[P()], U = () => ge[P()];
|
|
180
180
|
return (() => {
|
|
181
|
-
var t = Ie(), o = t.firstChild, l = o.firstChild,
|
|
181
|
+
var t = Ie(), o = t.firstChild, l = o.firstChild, d = l.nextSibling, x = O;
|
|
182
182
|
return typeof x == "function" ? R(x, t) : O = t, s(t, u(C, {
|
|
183
183
|
get when() {
|
|
184
184
|
return e.label;
|
|
@@ -187,7 +187,7 @@ const Oe = (e, i) => e.label.toLowerCase().includes(i.toLowerCase()), Ee = (e) =
|
|
|
187
187
|
var n = xe();
|
|
188
188
|
return s(n, () => e.label), I(() => _(n, "for", e.id)), n;
|
|
189
189
|
}
|
|
190
|
-
}), o), l.$$click = () => !i() && L(), l.$$keydown = ne, l.addEventListener("blur", te), l.addEventListener("focus", ee), l.$$input = (n) => p(n.currentTarget.value), R(G, l), s(
|
|
190
|
+
}), o), l.$$click = () => !i() && L(), l.$$keydown = ne, l.addEventListener("blur", te), l.addEventListener("focus", ee), l.$$input = (n) => p(n.currentTarget.value), R(G, l), s(d, u(C, {
|
|
191
191
|
get when() {
|
|
192
192
|
return e.loading;
|
|
193
193
|
},
|
|
@@ -197,7 +197,7 @@ const Oe = (e, i) => e.label.toLowerCase().includes(i.toLowerCase()), Ee = (e) =
|
|
|
197
197
|
size: "sm"
|
|
198
198
|
})), n;
|
|
199
199
|
}
|
|
200
|
-
}), null), s(
|
|
200
|
+
}), null), s(d, u(C, {
|
|
201
201
|
get when() {
|
|
202
202
|
return ae(() => !!(!e.loading && B()))() && !e.disabled;
|
|
203
203
|
},
|
|
@@ -207,7 +207,7 @@ const Oe = (e, i) => e.label.toLowerCase().includes(i.toLowerCase()), Ee = (e) =
|
|
|
207
207
|
class: "w-4 h-4"
|
|
208
208
|
})), n;
|
|
209
209
|
}
|
|
210
|
-
}), null), s(
|
|
210
|
+
}), null), s(d, u(C, {
|
|
211
211
|
get when() {
|
|
212
212
|
return !e.loading;
|
|
213
213
|
},
|
|
@@ -263,7 +263,7 @@ const Oe = (e, i) => e.label.toLowerCase().includes(i.toLowerCase()), Ee = (e) =
|
|
|
263
263
|
return m.addEventListener("mouseenter", () => {
|
|
264
264
|
if (!a.disabled) {
|
|
265
265
|
const v = E().indexOf(a);
|
|
266
|
-
|
|
266
|
+
c(v);
|
|
267
267
|
}
|
|
268
268
|
}), m.$$click = () => N(a), s(m, u(Ee, {
|
|
269
269
|
get text() {
|
|
@@ -294,7 +294,7 @@ const Oe = (e, i) => e.label.toLowerCase().includes(i.toLowerCase()), Ee = (e) =
|
|
|
294
294
|
});
|
|
295
295
|
}
|
|
296
296
|
}), null), I((n) => {
|
|
297
|
-
var h = `w-full ${e.class ?? ""}`, k = e.id, a = e.name, D = `w-full glass-input text-surface-900 dark:text-surface-100 focus:outline-none disabled:opacity-50 disabled:cursor-not-allowed ${B() && !e.disabled ? "pr-16" : "pr-10"} ${re()} ${e.error ? "border-
|
|
297
|
+
var h = `w-full ${e.class ?? ""}`, k = e.id, a = e.name, D = `w-full glass-input text-surface-900 dark:text-surface-100 focus:outline-none disabled:opacity-50 disabled:cursor-not-allowed ${B() && !e.disabled ? "pr-16" : "pr-10"} ${re()} ${e.error ? "border-error-500 dark:border-error-400" : ""}`, S = e.placeholder, m = e.disabled, v = i();
|
|
298
298
|
return h !== n.e && A(t, n.e = h), k !== n.t && _(l, "id", n.t = k), a !== n.a && _(l, "name", n.a = a), D !== n.o && A(l, n.o = D), S !== n.i && _(l, "placeholder", n.i = S), m !== n.n && (l.disabled = n.n = m), v !== n.s && _(l, "aria-expanded", n.s = v), n;
|
|
299
299
|
}, {
|
|
300
300
|
e: void 0,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Autocomplete.js","sources":["../../../src/components/Autocomplete/Autocomplete.tsx"],"sourcesContent":["import {\n type Component,\n For,\n Show,\n createEffect,\n createMemo,\n createSignal,\n on,\n onCleanup,\n} from 'solid-js';\nimport {\n DROPDOWN_ITEM_SIZE_CLASSES,\n INPUT_SIZE_CLASSES,\n} from '../../constants';\nimport { useClickOutside } from '../../hooks';\nimport { Spinner } from '../Spinner';\nimport { ChevronDownIcon, CloseIcon, PortalWithDarkMode } from '../shared';\nimport type { AutocompleteOption, AutocompleteProps } from './types';\n\n/**\n * Default filter function - case-insensitive substring match\n */\nconst defaultFilterFn = (\n option: AutocompleteOption,\n inputValue: string,\n): boolean => {\n return option.label.toLowerCase().includes(inputValue.toLowerCase());\n};\n\n/**\n * Highlight matching text in a string\n */\nconst HighlightedText: Component<{ text: string; highlight: string }> = (\n props,\n) => {\n const parts = createMemo(() => {\n if (!props.highlight.trim()) {\n return [{ text: props.text, match: false }];\n }\n\n const lowerText = props.text.toLowerCase();\n const lowerHighlight = props.highlight.toLowerCase();\n const result: { text: string; match: boolean }[] = [];\n let lastIndex = 0;\n\n let index = lowerText.indexOf(lowerHighlight, lastIndex);\n while (index !== -1) {\n if (index > lastIndex) {\n result.push({ text: props.text.slice(lastIndex, index), match: false });\n }\n result.push({\n text: props.text.slice(index, index + props.highlight.length),\n match: true,\n });\n lastIndex = index + props.highlight.length;\n index = lowerText.indexOf(lowerHighlight, lastIndex);\n }\n\n if (lastIndex < props.text.length) {\n result.push({ text: props.text.slice(lastIndex), match: false });\n }\n\n return result.length > 0 ? result : [{ text: props.text, match: false }];\n });\n\n return (\n <span>\n <For each={parts()}>\n {(part) => (\n <Show when={part.match} fallback={<span>{part.text}</span>}>\n <mark class=\"bg-primary-200 dark:bg-primary-700/50 text-inherit rounded-sm px-0.5\">\n {part.text}\n </mark>\n </Show>\n )}\n </For>\n </span>\n );\n};\n\n/**\n * A glassmorphic Autocomplete/Combobox component with dropdown suggestions.\n *\n * @example\n * ```tsx\n * const [value, setValue] = createSignal('');\n *\n * <Autocomplete\n * options={[\n * { value: 'apple', label: 'Apple' },\n * { value: 'banana', label: 'Banana' },\n * { value: 'cherry', label: 'Cherry' },\n * ]}\n * value={value()}\n * onChange={setValue}\n * placeholder=\"Select a fruit...\"\n * />\n * ```\n */\nexport const Autocomplete: Component<AutocompleteProps> = (props) => {\n const [isOpen, setIsOpen] = createSignal(false);\n const [inputValue, setInputValue] = createSignal('');\n const [focusedIndex, setFocusedIndex] = createSignal(-1);\n\n let internalInputRef: HTMLInputElement | undefined;\n let containerRef: HTMLDivElement | undefined;\n let dropdownRef: HTMLDivElement | undefined;\n let justSelected = false;\n\n // Combine internal ref with user-provided ref\n const setInputRef = (el: HTMLInputElement) => {\n internalInputRef = el;\n if (typeof props.ref === 'function') {\n props.ref(el);\n } else if (props.ref !== undefined) {\n // For direct assignment refs, we can't set them directly\n // but SolidJS handles this case automatically\n }\n };\n\n const size = () => props.size ?? 'md';\n const emptyText = () => props.emptyText ?? 'No options found';\n const filterFn = () => props.filterFn ?? defaultFilterFn;\n\n // Sync input value with selected value\n createEffect(() => {\n const selectedOption = props.options.find(\n (opt) => opt.value === props.value,\n );\n if (selectedOption) {\n setInputValue(selectedOption.label);\n } else if (props.allowCustomValue) {\n setInputValue(props.value);\n } else {\n setInputValue('');\n }\n });\n\n // Filtered options based on input\n const filteredOptions = createMemo(() => {\n const input = inputValue().trim();\n if (!input) {\n return props.options;\n }\n return props.options.filter((opt) => filterFn()(opt, input));\n });\n\n // Focusable options (non-disabled)\n const focusableOptions = createMemo(() => {\n return filteredOptions().filter((opt) => !opt.disabled);\n });\n\n // Reset focused index when options change (keep first item highlighted)\n createEffect(\n on(\n () => filteredOptions(),\n () => {\n if (isOpen()) {\n const firstFocusable = focusableOptions().length > 0 ? 0 : -1;\n setFocusedIndex(firstFocusable);\n }\n },\n ),\n );\n\n // Scroll focused item into view\n createEffect(() => {\n const idx = focusedIndex();\n if (idx >= 0 && dropdownRef) {\n const items = dropdownRef.querySelectorAll('[data-option]');\n const item = items[idx];\n if (item) {\n item.scrollIntoView({ block: 'nearest' });\n }\n }\n });\n\n const handleOpen = () => {\n if (props.disabled) {\n return;\n }\n setIsOpen(true);\n // Pre-select first focusable option\n const firstFocusable = focusableOptions().length > 0 ? 0 : -1;\n setFocusedIndex(firstFocusable);\n };\n\n const handleToggle = () => {\n if (props.disabled) {\n return;\n }\n if (isOpen()) {\n handleClose();\n } else {\n handleOpen();\n internalInputRef?.focus();\n }\n };\n\n const handleClose = () => {\n setIsOpen(false);\n setFocusedIndex(-1);\n };\n\n const handleSelect = (option: AutocompleteOption) => {\n if (option.disabled) {\n return;\n }\n setInputValue(option.label);\n props.onChange(option.value);\n handleClose();\n justSelected = true;\n internalInputRef?.focus();\n };\n\n const handleClear = (e: MouseEvent) => {\n e.stopPropagation();\n setInputValue('');\n props.onChange('');\n props.onInputChange?.('');\n internalInputRef?.focus();\n };\n\n const hasValue = () => !!props.value;\n\n const handleInputChange = (value: string) => {\n setInputValue(value);\n props.onInputChange?.(value);\n if (!isOpen()) {\n handleOpen();\n }\n };\n\n const handleInputFocus = () => {\n if (justSelected) {\n justSelected = false;\n return;\n }\n handleOpen();\n };\n\n const handleInputBlur = (e: FocusEvent) => {\n // Delay close to allow click on option to register\n const relatedTarget = e.relatedTarget as Node | null;\n if (dropdownRef?.contains(relatedTarget)) {\n return;\n }\n\n // On blur, validate the input\n setTimeout(() => {\n if (!isOpen()) {\n return;\n }\n\n const matchingOption = props.options.find(\n (opt) => opt.label.toLowerCase() === inputValue().toLowerCase(),\n );\n\n if (matchingOption) {\n props.onChange(matchingOption.value);\n setInputValue(matchingOption.label);\n } else if (props.allowCustomValue) {\n props.onChange(inputValue());\n } else {\n // Reset to current value\n const selectedOption = props.options.find(\n (opt) => opt.value === props.value,\n );\n setInputValue(selectedOption?.label ?? '');\n }\n\n handleClose();\n }, 150);\n };\n\n const handleKeyDown = (e: KeyboardEvent) => {\n const options = focusableOptions();\n const len = options.length;\n const open = isOpen();\n const idx = focusedIndex();\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n if (!open) {\n handleOpen();\n } else if (len > 0) {\n setFocusedIndex((prev) => Math.min(prev + 1, len - 1));\n }\n break;\n\n case 'ArrowUp':\n e.preventDefault();\n if (open && len > 0) {\n setFocusedIndex((prev) => Math.max(prev - 1, 0));\n }\n break;\n\n case 'Enter':\n e.preventDefault();\n if (open && idx >= 0 && idx < len) {\n handleSelect(options[idx]);\n } else if (props.allowCustomValue && inputValue().trim()) {\n props.onChange(inputValue());\n handleClose();\n }\n break;\n\n case 'Escape':\n if (open) {\n e.preventDefault();\n handleClose();\n const selected = props.options.find(\n (opt) => opt.value === props.value,\n );\n setInputValue(\n selected?.label ?? (props.allowCustomValue ? props.value : ''),\n );\n }\n break;\n\n case 'Tab':\n if (open) {\n handleClose();\n }\n break;\n\n case 'Home':\n if (open && len > 0) {\n e.preventDefault();\n setFocusedIndex(0);\n }\n break;\n\n case 'End':\n if (open && len > 0) {\n e.preventDefault();\n setFocusedIndex(len - 1);\n }\n break;\n }\n };\n\n // Click outside to close\n useClickOutside({\n refs: () => [containerRef, dropdownRef],\n onClickOutside: handleClose,\n enabled: isOpen,\n });\n\n // Close on scroll (any scrollable container, but not internal scroll)\n createEffect(() => {\n if (!isOpen()) {\n return;\n }\n\n const handleScroll = (e: Event) => {\n // Ignore scroll events from inside the dropdown\n if (dropdownRef?.contains(e.target as Node)) {\n return;\n }\n handleClose();\n };\n\n // Use capture to catch scroll events on any scrollable ancestor\n window.addEventListener('scroll', handleScroll, true);\n onCleanup(() => window.removeEventListener('scroll', handleScroll, true));\n });\n\n // Calculate dropdown position\n const dropdownPosition = createMemo(() => {\n // Track isOpen to recalculate when dropdown opens\n if (!isOpen() || !containerRef) {\n return {};\n }\n\n const rect = containerRef.getBoundingClientRect();\n const spaceBelow = window.innerHeight - rect.bottom;\n const spaceAbove = rect.top;\n const dropdownHeight = 240; // max-h-60 = 15rem = 240px\n\n // Prefer below, flip to above if not enough space\n const showAbove = spaceBelow < dropdownHeight && spaceAbove > spaceBelow;\n\n return {\n left: `${rect.left}px`,\n width: `${rect.width}px`,\n ...(showAbove\n ? { bottom: `${window.innerHeight - rect.top + 4}px` }\n : { top: `${rect.bottom + 4}px` }),\n };\n });\n\n const sizeClasses = () => INPUT_SIZE_CLASSES[size()];\n const itemSizeClasses = () => DROPDOWN_ITEM_SIZE_CLASSES[size()];\n\n return (\n <div class={`w-full ${props.class ?? ''}`} ref={containerRef}>\n <Show when={props.label}>\n <label\n for={props.id}\n class=\"block text-sm font-medium text-surface-700 dark:text-surface-300 mb-1.5\"\n >\n {props.label}\n </label>\n </Show>\n\n <div class=\"relative\">\n <input\n ref={setInputRef}\n type=\"text\"\n id={props.id}\n name={props.name}\n class={`w-full glass-input text-surface-900 dark:text-surface-100 focus:outline-none disabled:opacity-50 disabled:cursor-not-allowed ${hasValue() && !props.disabled ? 'pr-16' : 'pr-10'} ${sizeClasses()} ${props.error ? 'border-red-500 dark:border-red-400' : ''}`}\n placeholder={props.placeholder}\n value={inputValue()}\n disabled={props.disabled}\n autocomplete=\"off\"\n role=\"combobox\"\n aria-expanded={isOpen()}\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n onInput={(e) => handleInputChange(e.currentTarget.value)}\n onFocus={handleInputFocus}\n onBlur={handleInputBlur}\n onKeyDown={handleKeyDown}\n onClick={() => !isOpen() && handleOpen()}\n />\n\n {/* Right side indicators */}\n <div class=\"absolute inset-y-0 right-0 flex items-center gap-1 pr-2\">\n <Show when={props.loading}>\n <div class=\"pointer-events-none\">\n <Spinner size=\"sm\" />\n </div>\n </Show>\n\n <Show when={!props.loading && hasValue() && !props.disabled}>\n <button\n type=\"button\"\n class=\"p-1 rounded-full text-surface-400 hover:text-surface-600 dark:hover:text-surface-300 hover:bg-surface-200/50 dark:hover:bg-surface-700/50 transition-colors\"\n onClick={handleClear}\n tabIndex={-1}\n aria-label=\"Clear selection\"\n >\n <CloseIcon class=\"w-4 h-4\" />\n </button>\n </Show>\n\n <Show when={!props.loading}>\n <button\n type=\"button\"\n class=\"p-1 text-surface-400 cursor-pointer disabled:cursor-not-allowed\"\n onClick={handleToggle}\n disabled={props.disabled}\n tabIndex={-1}\n aria-label={isOpen() ? 'Close dropdown' : 'Open dropdown'}\n >\n <ChevronDownIcon\n class={`transition-transform duration-150 ${isOpen() ? 'rotate-180' : ''}`}\n />\n </button>\n </Show>\n </div>\n </div>\n\n <Show when={props.error}>\n <p class=\"mt-1.5 text-sm text-red-500 dark:text-red-400\">\n {props.error}\n </p>\n </Show>\n\n {/* Dropdown */}\n <Show when={isOpen()}>\n <PortalWithDarkMode>\n <div\n ref={dropdownRef}\n class=\"fixed z-50 glass-card rounded-xl shadow-lg overflow-hidden animate-in fade-in zoom-in-95 duration-150\"\n style={dropdownPosition()}\n role=\"listbox\"\n >\n <div class=\"max-h-60 overflow-y-auto scrollbar-thin py-1\">\n <Show\n when={filteredOptions().length > 0}\n fallback={\n <div\n class={`text-surface-500 dark:text-surface-400 text-center ${itemSizeClasses()}`}\n >\n {emptyText()}\n </div>\n }\n >\n <For each={filteredOptions()}>\n {(option) => {\n const isFocused = () => {\n const focusableIdx = focusableOptions().indexOf(option);\n return focusableIdx === focusedIndex();\n };\n const isSelected = () => option.value === props.value;\n\n return (\n <button\n type=\"button\"\n data-option\n class={`w-full text-left transition-colors ${itemSizeClasses()}\n ${\n option.disabled\n ? 'text-surface-400 dark:text-surface-600 cursor-not-allowed'\n : 'text-surface-700 dark:text-surface-200 cursor-pointer'\n }\n ${isFocused() ? 'bg-black/5 dark:bg-white/5' : ''}\n ${isSelected() ? 'bg-primary-50 dark:bg-primary-900/20 text-primary-700 dark:text-primary-300' : ''}\n ${!option.disabled && !isFocused() && !isSelected() ? 'hover:bg-black/5 dark:hover:bg-white/5' : ''}\n `}\n onClick={() => handleSelect(option)}\n onMouseEnter={() => {\n if (!option.disabled) {\n const focusableIdx =\n focusableOptions().indexOf(option);\n setFocusedIndex(focusableIdx);\n }\n }}\n disabled={option.disabled}\n role=\"option\"\n aria-selected={isSelected()}\n tabIndex={-1}\n >\n <HighlightedText\n text={option.label}\n highlight={inputValue()}\n />\n </button>\n );\n }}\n </For>\n </Show>\n </div>\n </div>\n </PortalWithDarkMode>\n </Show>\n </div>\n );\n};\n"],"names":["defaultFilterFn","option","inputValue","label","toLowerCase","includes","HighlightedText","props","parts","createMemo","highlight","trim","text","match","lowerText","lowerHighlight","result","lastIndex","index","indexOf","push","slice","length","_el$","_tmpl$","_$insert","_$createComponent","For","each","children","part","Show","when","fallback","_el$3","_el$2","_tmpl$2","Autocomplete","isOpen","setIsOpen","createSignal","setInputValue","focusedIndex","setFocusedIndex","internalInputRef","containerRef","dropdownRef","justSelected","setInputRef","el","ref","size","emptyText","filterFn","createEffect","selectedOption","options","find","opt","value","allowCustomValue","filteredOptions","input","filter","focusableOptions","disabled","on","firstFocusable","idx","item","querySelectorAll","scrollIntoView","block","handleOpen","handleToggle","handleClose","focus","handleSelect","onChange","handleClear","e","stopPropagation","onInputChange","hasValue","handleInputChange","handleInputFocus","handleInputBlur","relatedTarget","contains","setTimeout","matchingOption","handleKeyDown","len","open","key","preventDefault","prev","Math","min","max","selected","useClickOutside","refs","onClickOutside","enabled","handleScroll","target","window","addEventListener","onCleanup","removeEventListener","dropdownPosition","rect","getBoundingClientRect","spaceBelow","innerHeight","bottom","spaceAbove","top","showAbove","left","width","sizeClasses","INPUT_SIZE_CLASSES","itemSizeClasses","DROPDOWN_ITEM_SIZE_CLASSES","_el$4","_tmpl$9","_el$6","firstChild","_el$7","_el$8","nextSibling","_ref$","_$use","_el$5","_tmpl$3","_$effect","_$setAttribute","id","$$click","$$keydown","$$input","currentTarget","loading","_el$9","_tmpl$4","Spinner","_$memo","_el$0","_tmpl$5","CloseIcon","_el$1","_tmpl$6","ChevronDownIcon","_p$","_v$","_v$2","t","undefined","error","_el$10","_tmpl$7","PortalWithDarkMode","_el$11","_tmpl$8","_el$12","_ref$2","_el$13","_tmpl$0","_$className","isFocused","isSelected","_el$14","_tmpl$1","focusableIdx","_v$0","_v$1","_v$10","a","_$p","_$style","_v$3","class","_v$4","_v$5","name","_v$6","_v$7","placeholder","_v$8","_v$9","o","i","n","s","_$delegateEvents"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Autocomplete.js","sources":["../../../src/components/Autocomplete/Autocomplete.tsx"],"sourcesContent":["import {\n type Component,\n For,\n Show,\n createEffect,\n createMemo,\n createSignal,\n on,\n onCleanup,\n} from 'solid-js';\nimport {\n DROPDOWN_ITEM_SIZE_CLASSES,\n INPUT_SIZE_CLASSES,\n} from '../../constants';\nimport { useClickOutside } from '../../hooks';\nimport { Spinner } from '../Spinner';\nimport { ChevronDownIcon, CloseIcon, PortalWithDarkMode } from '../shared';\nimport type { AutocompleteOption, AutocompleteProps } from './types';\n\n/**\n * Default filter function - case-insensitive substring match\n */\nconst defaultFilterFn = (\n option: AutocompleteOption,\n inputValue: string,\n): boolean => {\n return option.label.toLowerCase().includes(inputValue.toLowerCase());\n};\n\n/**\n * Highlight matching text in a string\n */\nconst HighlightedText: Component<{ text: string; highlight: string }> = (\n props,\n) => {\n const parts = createMemo(() => {\n if (!props.highlight.trim()) {\n return [{ text: props.text, match: false }];\n }\n\n const lowerText = props.text.toLowerCase();\n const lowerHighlight = props.highlight.toLowerCase();\n const result: { text: string; match: boolean }[] = [];\n let lastIndex = 0;\n\n let index = lowerText.indexOf(lowerHighlight, lastIndex);\n while (index !== -1) {\n if (index > lastIndex) {\n result.push({ text: props.text.slice(lastIndex, index), match: false });\n }\n result.push({\n text: props.text.slice(index, index + props.highlight.length),\n match: true,\n });\n lastIndex = index + props.highlight.length;\n index = lowerText.indexOf(lowerHighlight, lastIndex);\n }\n\n if (lastIndex < props.text.length) {\n result.push({ text: props.text.slice(lastIndex), match: false });\n }\n\n return result.length > 0 ? result : [{ text: props.text, match: false }];\n });\n\n return (\n <span>\n <For each={parts()}>\n {(part) => (\n <Show when={part.match} fallback={<span>{part.text}</span>}>\n <mark class=\"bg-primary-200 dark:bg-primary-700/50 text-inherit rounded-sm px-0.5\">\n {part.text}\n </mark>\n </Show>\n )}\n </For>\n </span>\n );\n};\n\n/**\n * A glassmorphic Autocomplete/Combobox component with dropdown suggestions.\n *\n * @example\n * ```tsx\n * const [value, setValue] = createSignal('');\n *\n * <Autocomplete\n * options={[\n * { value: 'apple', label: 'Apple' },\n * { value: 'banana', label: 'Banana' },\n * { value: 'cherry', label: 'Cherry' },\n * ]}\n * value={value()}\n * onChange={setValue}\n * placeholder=\"Select a fruit...\"\n * />\n * ```\n */\nexport const Autocomplete: Component<AutocompleteProps> = (props) => {\n const [isOpen, setIsOpen] = createSignal(false);\n const [inputValue, setInputValue] = createSignal('');\n const [focusedIndex, setFocusedIndex] = createSignal(-1);\n\n let internalInputRef: HTMLInputElement | undefined;\n let containerRef: HTMLDivElement | undefined;\n let dropdownRef: HTMLDivElement | undefined;\n let justSelected = false;\n\n // Combine internal ref with user-provided ref\n const setInputRef = (el: HTMLInputElement) => {\n internalInputRef = el;\n if (typeof props.ref === 'function') {\n props.ref(el);\n } else if (props.ref !== undefined) {\n // For direct assignment refs, we can't set them directly\n // but SolidJS handles this case automatically\n }\n };\n\n const size = () => props.size ?? 'md';\n const emptyText = () => props.emptyText ?? 'No options found';\n const filterFn = () => props.filterFn ?? defaultFilterFn;\n\n // Sync input value with selected value\n createEffect(() => {\n const selectedOption = props.options.find(\n (opt) => opt.value === props.value,\n );\n if (selectedOption) {\n setInputValue(selectedOption.label);\n } else if (props.allowCustomValue) {\n setInputValue(props.value);\n } else {\n setInputValue('');\n }\n });\n\n // Filtered options based on input\n const filteredOptions = createMemo(() => {\n const input = inputValue().trim();\n if (!input) {\n return props.options;\n }\n return props.options.filter((opt) => filterFn()(opt, input));\n });\n\n // Focusable options (non-disabled)\n const focusableOptions = createMemo(() => {\n return filteredOptions().filter((opt) => !opt.disabled);\n });\n\n // Reset focused index when options change (keep first item highlighted)\n createEffect(\n on(\n () => filteredOptions(),\n () => {\n if (isOpen()) {\n const firstFocusable = focusableOptions().length > 0 ? 0 : -1;\n setFocusedIndex(firstFocusable);\n }\n },\n ),\n );\n\n // Scroll focused item into view\n createEffect(() => {\n const idx = focusedIndex();\n if (idx >= 0 && dropdownRef) {\n const items = dropdownRef.querySelectorAll('[data-option]');\n const item = items[idx];\n if (item) {\n item.scrollIntoView({ block: 'nearest' });\n }\n }\n });\n\n const handleOpen = () => {\n if (props.disabled) {\n return;\n }\n setIsOpen(true);\n // Pre-select first focusable option\n const firstFocusable = focusableOptions().length > 0 ? 0 : -1;\n setFocusedIndex(firstFocusable);\n };\n\n const handleToggle = () => {\n if (props.disabled) {\n return;\n }\n if (isOpen()) {\n handleClose();\n } else {\n handleOpen();\n internalInputRef?.focus();\n }\n };\n\n const handleClose = () => {\n setIsOpen(false);\n setFocusedIndex(-1);\n };\n\n const handleSelect = (option: AutocompleteOption) => {\n if (option.disabled) {\n return;\n }\n setInputValue(option.label);\n props.onChange(option.value);\n handleClose();\n justSelected = true;\n internalInputRef?.focus();\n };\n\n const handleClear = (e: MouseEvent) => {\n e.stopPropagation();\n setInputValue('');\n props.onChange('');\n props.onInputChange?.('');\n internalInputRef?.focus();\n };\n\n const hasValue = () => !!props.value;\n\n const handleInputChange = (value: string) => {\n setInputValue(value);\n props.onInputChange?.(value);\n if (!isOpen()) {\n handleOpen();\n }\n };\n\n const handleInputFocus = () => {\n if (justSelected) {\n justSelected = false;\n return;\n }\n handleOpen();\n };\n\n const handleInputBlur = (e: FocusEvent) => {\n // Delay close to allow click on option to register\n const relatedTarget = e.relatedTarget as Node | null;\n if (dropdownRef?.contains(relatedTarget)) {\n return;\n }\n\n // On blur, validate the input\n setTimeout(() => {\n if (!isOpen()) {\n return;\n }\n\n const matchingOption = props.options.find(\n (opt) => opt.label.toLowerCase() === inputValue().toLowerCase(),\n );\n\n if (matchingOption) {\n props.onChange(matchingOption.value);\n setInputValue(matchingOption.label);\n } else if (props.allowCustomValue) {\n props.onChange(inputValue());\n } else {\n // Reset to current value\n const selectedOption = props.options.find(\n (opt) => opt.value === props.value,\n );\n setInputValue(selectedOption?.label ?? '');\n }\n\n handleClose();\n }, 150);\n };\n\n const handleKeyDown = (e: KeyboardEvent) => {\n const options = focusableOptions();\n const len = options.length;\n const open = isOpen();\n const idx = focusedIndex();\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n if (!open) {\n handleOpen();\n } else if (len > 0) {\n setFocusedIndex((prev) => Math.min(prev + 1, len - 1));\n }\n break;\n\n case 'ArrowUp':\n e.preventDefault();\n if (open && len > 0) {\n setFocusedIndex((prev) => Math.max(prev - 1, 0));\n }\n break;\n\n case 'Enter':\n e.preventDefault();\n if (open && idx >= 0 && idx < len) {\n handleSelect(options[idx]);\n } else if (props.allowCustomValue && inputValue().trim()) {\n props.onChange(inputValue());\n handleClose();\n }\n break;\n\n case 'Escape':\n if (open) {\n e.preventDefault();\n handleClose();\n const selected = props.options.find(\n (opt) => opt.value === props.value,\n );\n setInputValue(\n selected?.label ?? (props.allowCustomValue ? props.value : ''),\n );\n }\n break;\n\n case 'Tab':\n if (open) {\n handleClose();\n }\n break;\n\n case 'Home':\n if (open && len > 0) {\n e.preventDefault();\n setFocusedIndex(0);\n }\n break;\n\n case 'End':\n if (open && len > 0) {\n e.preventDefault();\n setFocusedIndex(len - 1);\n }\n break;\n }\n };\n\n // Click outside to close\n useClickOutside({\n refs: () => [containerRef, dropdownRef],\n onClickOutside: handleClose,\n enabled: isOpen,\n });\n\n // Close on scroll (any scrollable container, but not internal scroll)\n createEffect(() => {\n if (!isOpen()) {\n return;\n }\n\n const handleScroll = (e: Event) => {\n // Ignore scroll events from inside the dropdown\n if (dropdownRef?.contains(e.target as Node)) {\n return;\n }\n handleClose();\n };\n\n // Use capture to catch scroll events on any scrollable ancestor\n window.addEventListener('scroll', handleScroll, true);\n onCleanup(() => window.removeEventListener('scroll', handleScroll, true));\n });\n\n // Calculate dropdown position\n const dropdownPosition = createMemo(() => {\n // Track isOpen to recalculate when dropdown opens\n if (!isOpen() || !containerRef) {\n return {};\n }\n\n const rect = containerRef.getBoundingClientRect();\n const spaceBelow = window.innerHeight - rect.bottom;\n const spaceAbove = rect.top;\n const dropdownHeight = 240; // max-h-60 = 15rem = 240px\n\n // Prefer below, flip to above if not enough space\n const showAbove = spaceBelow < dropdownHeight && spaceAbove > spaceBelow;\n\n return {\n left: `${rect.left}px`,\n width: `${rect.width}px`,\n ...(showAbove\n ? { bottom: `${window.innerHeight - rect.top + 4}px` }\n : { top: `${rect.bottom + 4}px` }),\n };\n });\n\n const sizeClasses = () => INPUT_SIZE_CLASSES[size()];\n const itemSizeClasses = () => DROPDOWN_ITEM_SIZE_CLASSES[size()];\n\n return (\n <div class={`w-full ${props.class ?? ''}`} ref={containerRef}>\n <Show when={props.label}>\n <label\n for={props.id}\n class=\"block text-sm font-medium text-surface-700 dark:text-surface-300 mb-1.5\"\n >\n {props.label}\n </label>\n </Show>\n\n <div class=\"relative\">\n <input\n ref={setInputRef}\n type=\"text\"\n id={props.id}\n name={props.name}\n class={`w-full glass-input text-surface-900 dark:text-surface-100 focus:outline-none disabled:opacity-50 disabled:cursor-not-allowed ${hasValue() && !props.disabled ? 'pr-16' : 'pr-10'} ${sizeClasses()} ${props.error ? 'border-error-500 dark:border-error-400' : ''}`}\n placeholder={props.placeholder}\n value={inputValue()}\n disabled={props.disabled}\n autocomplete=\"off\"\n role=\"combobox\"\n aria-expanded={isOpen()}\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n onInput={(e) => handleInputChange(e.currentTarget.value)}\n onFocus={handleInputFocus}\n onBlur={handleInputBlur}\n onKeyDown={handleKeyDown}\n onClick={() => !isOpen() && handleOpen()}\n />\n\n {/* Right side indicators */}\n <div class=\"absolute inset-y-0 right-0 flex items-center gap-1 pr-2\">\n <Show when={props.loading}>\n <div class=\"pointer-events-none\">\n <Spinner size=\"sm\" />\n </div>\n </Show>\n\n <Show when={!props.loading && hasValue() && !props.disabled}>\n <button\n type=\"button\"\n class=\"p-1 rounded-full text-surface-400 hover:text-surface-600 dark:hover:text-surface-300 hover:bg-surface-200/50 dark:hover:bg-surface-700/50 transition-colors\"\n onClick={handleClear}\n tabIndex={-1}\n aria-label=\"Clear selection\"\n >\n <CloseIcon class=\"w-4 h-4\" />\n </button>\n </Show>\n\n <Show when={!props.loading}>\n <button\n type=\"button\"\n class=\"p-1 text-surface-400 cursor-pointer disabled:cursor-not-allowed\"\n onClick={handleToggle}\n disabled={props.disabled}\n tabIndex={-1}\n aria-label={isOpen() ? 'Close dropdown' : 'Open dropdown'}\n >\n <ChevronDownIcon\n class={`transition-transform duration-150 ${isOpen() ? 'rotate-180' : ''}`}\n />\n </button>\n </Show>\n </div>\n </div>\n\n <Show when={props.error}>\n <p class=\"mt-1.5 text-sm text-error-500 dark:text-error-400\">\n {props.error}\n </p>\n </Show>\n\n {/* Dropdown */}\n <Show when={isOpen()}>\n <PortalWithDarkMode>\n <div\n ref={dropdownRef}\n class=\"fixed z-50 glass-card rounded-xl shadow-lg overflow-hidden animate-in fade-in zoom-in-95 duration-150\"\n style={dropdownPosition()}\n role=\"listbox\"\n >\n <div class=\"max-h-60 overflow-y-auto scrollbar-thin py-1\">\n <Show\n when={filteredOptions().length > 0}\n fallback={\n <div\n class={`text-surface-500 dark:text-surface-400 text-center ${itemSizeClasses()}`}\n >\n {emptyText()}\n </div>\n }\n >\n <For each={filteredOptions()}>\n {(option) => {\n const isFocused = () => {\n const focusableIdx = focusableOptions().indexOf(option);\n return focusableIdx === focusedIndex();\n };\n const isSelected = () => option.value === props.value;\n\n return (\n <button\n type=\"button\"\n data-option\n class={`w-full text-left transition-colors ${itemSizeClasses()}\n ${\n option.disabled\n ? 'text-surface-400 dark:text-surface-600 cursor-not-allowed'\n : 'text-surface-700 dark:text-surface-200 cursor-pointer'\n }\n ${isFocused() ? 'bg-black/5 dark:bg-white/5' : ''}\n ${isSelected() ? 'bg-primary-50 dark:bg-primary-900/20 text-primary-700 dark:text-primary-300' : ''}\n ${!option.disabled && !isFocused() && !isSelected() ? 'hover:bg-black/5 dark:hover:bg-white/5' : ''}\n `}\n onClick={() => handleSelect(option)}\n onMouseEnter={() => {\n if (!option.disabled) {\n const focusableIdx =\n focusableOptions().indexOf(option);\n setFocusedIndex(focusableIdx);\n }\n }}\n disabled={option.disabled}\n role=\"option\"\n aria-selected={isSelected()}\n tabIndex={-1}\n >\n <HighlightedText\n text={option.label}\n highlight={inputValue()}\n />\n </button>\n );\n }}\n </For>\n </Show>\n </div>\n </div>\n </PortalWithDarkMode>\n </Show>\n </div>\n );\n};\n"],"names":["defaultFilterFn","option","inputValue","label","toLowerCase","includes","HighlightedText","props","parts","createMemo","highlight","trim","text","match","lowerText","lowerHighlight","result","lastIndex","index","indexOf","push","slice","length","_el$","_tmpl$","_$insert","_$createComponent","For","each","children","part","Show","when","fallback","_el$3","_el$2","_tmpl$2","Autocomplete","isOpen","setIsOpen","createSignal","setInputValue","focusedIndex","setFocusedIndex","internalInputRef","containerRef","dropdownRef","justSelected","setInputRef","el","ref","size","emptyText","filterFn","createEffect","selectedOption","options","find","opt","value","allowCustomValue","filteredOptions","input","filter","focusableOptions","disabled","on","firstFocusable","idx","item","querySelectorAll","scrollIntoView","block","handleOpen","handleToggle","handleClose","focus","handleSelect","onChange","handleClear","e","stopPropagation","onInputChange","hasValue","handleInputChange","handleInputFocus","handleInputBlur","relatedTarget","contains","setTimeout","matchingOption","handleKeyDown","len","open","key","preventDefault","prev","Math","min","max","selected","useClickOutside","refs","onClickOutside","enabled","handleScroll","target","window","addEventListener","onCleanup","removeEventListener","dropdownPosition","rect","getBoundingClientRect","spaceBelow","innerHeight","bottom","spaceAbove","top","showAbove","left","width","sizeClasses","INPUT_SIZE_CLASSES","itemSizeClasses","DROPDOWN_ITEM_SIZE_CLASSES","_el$4","_tmpl$9","_el$6","firstChild","_el$7","_el$8","nextSibling","_ref$","_$use","_el$5","_tmpl$3","_$effect","_$setAttribute","id","$$click","$$keydown","$$input","currentTarget","loading","_el$9","_tmpl$4","Spinner","_$memo","_el$0","_tmpl$5","CloseIcon","_el$1","_tmpl$6","ChevronDownIcon","_p$","_v$","_v$2","t","undefined","error","_el$10","_tmpl$7","PortalWithDarkMode","_el$11","_tmpl$8","_el$12","_ref$2","_el$13","_tmpl$0","_$className","isFocused","isSelected","_el$14","_tmpl$1","focusableIdx","_v$0","_v$1","_v$10","a","_$p","_$style","_v$3","class","_v$4","_v$5","name","_v$6","_v$7","placeholder","_v$8","_v$9","o","i","n","s","_$delegateEvents"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../src/components/Chat/Chat.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAI1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,IAAI,EAAE,SAAS,CAAC,SAAS,
|
|
1
|
+
{"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../src/components/Chat/Chat.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAI1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,IAAI,EAAE,SAAS,CAAC,SAAS,CAmCrC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Chat.js","sources":["../../../src/components/Chat/Chat.tsx"],"sourcesContent":["import type { Component } from 'solid-js';\nimport { Show } from 'solid-js';\nimport { ChatInput } from './ChatInput';\nimport { ChatMessageList } from './ChatMessageList';\nimport type { ChatProps } from './types';\n\n/**\n * A complete chat interface with message list and input.\n *\n * @example\n * ```tsx\n * const [messages, setMessages] = createSignal<ChatMessage[]>([]);\n * const [isStreaming, setIsStreaming] = createSignal(false);\n *\n * const handleSend = (content: string) => {\n * // Add user message\n * setMessages(prev => [...prev, {\n * id: crypto.randomUUID(),\n * role: 'user',\n * content,\n * timestamp: new Date(),\n * status: 'complete'\n * }]);\n * // Start streaming response...\n * setIsStreaming(true);\n * };\n *\n * <Chat\n * messages={messages()}\n * onSendMessage={handleSend}\n * isStreaming={isStreaming()}\n * showTypingIndicator\n * userName=\"You\"\n * assistantName=\"Claude\"\n * />\n * ```\n */\nexport const Chat: Component<ChatProps> = (props) => {\n return (\n <div\n class={`flex flex-col h-full bg-white/30 dark:bg-surface-900/30 backdrop-blur-sm rounded-2xl overflow-hidden ${props.class ?? ''}`}\n >\n {/* Optional header */}\n <Show when={props.header}>\n <div class=\"border-b border-surface-200 dark:border-surface-700\">\n {props.header}\n </div>\n </Show>\n\n {/* Message list */}\n <ChatMessageList\n messages={props.messages}\n userName={props.userName}\n userAvatarUrl={props.userAvatarUrl}\n assistantName={props.assistantName}\n assistantAvatarUrl={props.assistantAvatarUrl}\n showTypingIndicator={props.showTypingIndicator}\n isStreaming={props.isStreaming}\n emptyState={props.emptyState}\n />\n\n {/* Input area */}\n <ChatInput\n onSendMessage={props.onSendMessage}\n onCancelStream={props.onCancelStream}\n isStreaming={props.isStreaming}\n disabled={props.disabled}\n placeholder={props.placeholder}\n />\n </div>\n );\n};\n"],"names":["Chat","props","_el$","_tmpl$2","_$insert","_$createComponent","Show","when","header","children","_el$2","_tmpl$","ChatMessageList","messages","userName","userAvatarUrl","assistantName","assistantAvatarUrl","showTypingIndicator","isStreaming","emptyState","ChatInput","onSendMessage","onCancelStream","disabled","placeholder","_$effect","_$className","class"],"mappings":";;;;;AAqCO,MAAMA,IAA8BC,CAAAA,OACzC,MAAA;AAAA,MAAAC,IAAAC,EAAAA;AAAAC,SAAAA,EAAAF,GAAAG,EAKKC,GAAI;AAAA,IAAA,IAACC,OAAI;AAAA,aAAEN,EAAMO;AAAAA,IAAM;AAAA,IAAA,IAAAC,WAAA;AAAA,UAAAC,IAAAC,EAAAA;AAAAP,aAAAA,EAAAM,GAAA,MAEnBT,EAAMO,MAAM,GAAAE;AAAAA,IAAA;AAAA,EAAA,CAAA,GAAA,IAAA,GAAAN,EAAAF,GAAAG,EAKhBO,GAAe;AAAA,IAAA,IACdC,WAAQ;AAAA,aAAEZ,EAAMY;AAAAA,IAAQ;AAAA,IAAA,IACxBC,WAAQ;AAAA,aAAEb,EAAMa;AAAAA,IAAQ;AAAA,IAAA,IACxBC,gBAAa;AAAA,aAAEd,EAAMc;AAAAA,IAAa;AAAA,IAAA,IAClCC,gBAAa;AAAA,aAAEf,EAAMe;AAAAA,IAAa;AAAA,IAAA,IAClCC,qBAAkB;AAAA,aAAEhB,EAAMgB;AAAAA,IAAkB;AAAA,IAAA,IAC5CC,sBAAmB;AAAA,aAAEjB,EAAMiB;AAAAA,IAAmB;AAAA,IAAA,IAC9CC,cAAW;AAAA,aAAElB,EAAMkB;AAAAA,IAAW;AAAA,IAAA,IAC9BC,aAAU;AAAA,aAAEnB,EAAMmB;AAAAA,IAAU;AAAA,EAAA,CAAA,GAAA,IAAA,
|
|
1
|
+
{"version":3,"file":"Chat.js","sources":["../../../src/components/Chat/Chat.tsx"],"sourcesContent":["import type { Component } from 'solid-js';\nimport { Show } from 'solid-js';\nimport { ChatInput } from './ChatInput';\nimport { ChatMessageList } from './ChatMessageList';\nimport type { ChatProps } from './types';\n\n/**\n * A complete chat interface with message list and input.\n *\n * @example\n * ```tsx\n * const [messages, setMessages] = createSignal<ChatMessage[]>([]);\n * const [isStreaming, setIsStreaming] = createSignal(false);\n *\n * const handleSend = (content: string) => {\n * // Add user message\n * setMessages(prev => [...prev, {\n * id: crypto.randomUUID(),\n * role: 'user',\n * content,\n * timestamp: new Date(),\n * status: 'complete'\n * }]);\n * // Start streaming response...\n * setIsStreaming(true);\n * };\n *\n * <Chat\n * messages={messages()}\n * onSendMessage={handleSend}\n * isStreaming={isStreaming()}\n * showTypingIndicator\n * userName=\"You\"\n * assistantName=\"Claude\"\n * />\n * ```\n */\nexport const Chat: Component<ChatProps> = (props) => {\n return (\n <div\n class={`flex flex-col h-full bg-white/30 dark:bg-surface-900/30 backdrop-blur-sm rounded-2xl overflow-hidden ${props.class ?? ''}`}\n >\n {/* Optional header */}\n <Show when={props.header}>\n <div class=\"border-b border-surface-200 dark:border-surface-700\">\n {props.header}\n </div>\n </Show>\n\n {/* Message list */}\n <ChatMessageList\n messages={props.messages}\n userName={props.userName}\n userAvatarUrl={props.userAvatarUrl}\n assistantName={props.assistantName}\n assistantAvatarUrl={props.assistantAvatarUrl}\n showTypingIndicator={props.showTypingIndicator}\n isStreaming={props.isStreaming}\n emptyState={props.emptyState}\n codeBlockActions={props.codeBlockActions}\n />\n\n {/* Input area */}\n <ChatInput\n onSendMessage={props.onSendMessage}\n onCancelStream={props.onCancelStream}\n isStreaming={props.isStreaming}\n disabled={props.disabled}\n placeholder={props.placeholder}\n />\n </div>\n );\n};\n"],"names":["Chat","props","_el$","_tmpl$2","_$insert","_$createComponent","Show","when","header","children","_el$2","_tmpl$","ChatMessageList","messages","userName","userAvatarUrl","assistantName","assistantAvatarUrl","showTypingIndicator","isStreaming","emptyState","codeBlockActions","ChatInput","onSendMessage","onCancelStream","disabled","placeholder","_$effect","_$className","class"],"mappings":";;;;;AAqCO,MAAMA,IAA8BC,CAAAA,OACzC,MAAA;AAAA,MAAAC,IAAAC,EAAAA;AAAAC,SAAAA,EAAAF,GAAAG,EAKKC,GAAI;AAAA,IAAA,IAACC,OAAI;AAAA,aAAEN,EAAMO;AAAAA,IAAM;AAAA,IAAA,IAAAC,WAAA;AAAA,UAAAC,IAAAC,EAAAA;AAAAP,aAAAA,EAAAM,GAAA,MAEnBT,EAAMO,MAAM,GAAAE;AAAAA,IAAA;AAAA,EAAA,CAAA,GAAA,IAAA,GAAAN,EAAAF,GAAAG,EAKhBO,GAAe;AAAA,IAAA,IACdC,WAAQ;AAAA,aAAEZ,EAAMY;AAAAA,IAAQ;AAAA,IAAA,IACxBC,WAAQ;AAAA,aAAEb,EAAMa;AAAAA,IAAQ;AAAA,IAAA,IACxBC,gBAAa;AAAA,aAAEd,EAAMc;AAAAA,IAAa;AAAA,IAAA,IAClCC,gBAAa;AAAA,aAAEf,EAAMe;AAAAA,IAAa;AAAA,IAAA,IAClCC,qBAAkB;AAAA,aAAEhB,EAAMgB;AAAAA,IAAkB;AAAA,IAAA,IAC5CC,sBAAmB;AAAA,aAAEjB,EAAMiB;AAAAA,IAAmB;AAAA,IAAA,IAC9CC,cAAW;AAAA,aAAElB,EAAMkB;AAAAA,IAAW;AAAA,IAAA,IAC9BC,aAAU;AAAA,aAAEnB,EAAMmB;AAAAA,IAAU;AAAA,IAAA,IAC5BC,mBAAgB;AAAA,aAAEpB,EAAMoB;AAAAA,IAAgB;AAAA,EAAA,CAAA,GAAA,IAAA,GAAAjB,EAAAF,GAAAG,EAIzCiB,GAAS;AAAA,IAAA,IACRC,gBAAa;AAAA,aAAEtB,EAAMsB;AAAAA,IAAa;AAAA,IAAA,IAClCC,iBAAc;AAAA,aAAEvB,EAAMuB;AAAAA,IAAc;AAAA,IAAA,IACpCL,cAAW;AAAA,aAAElB,EAAMkB;AAAAA,IAAW;AAAA,IAAA,IAC9BM,WAAQ;AAAA,aAAExB,EAAMwB;AAAAA,IAAQ;AAAA,IAAA,IACxBC,cAAW;AAAA,aAAEzB,EAAMyB;AAAAA,IAAW;AAAA,EAAA,CAAA,GAAA,IAAA,GAAAC,EAAA,MAAAC,EAAA1B,GA5BzB,wGAAwGD,EAAM4B,SAAS,EAAE,EAAE,CAAA,GAAA3B;AAAA,GAAA;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatInput.d.ts","sourceRoot":"","sources":["../../../src/components/Chat/ChatInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAG1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C;;GAEG;AACH,eAAO,MAAM,SAAS,EAAE,SAAS,CAAC,cAAc,
|
|
1
|
+
{"version":3,"file":"ChatInput.d.ts","sourceRoot":"","sources":["../../../src/components/Chat/ChatInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAG1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C;;GAEG;AACH,eAAO,MAAM,SAAS,EAAE,SAAS,CAAC,cAAc,CA6G/C,CAAC"}
|
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
import { template as u, insert as c, createComponent as d, effect as
|
|
2
|
-
import { createSignal as _, createEffect as
|
|
1
|
+
import { template as u, insert as c, createComponent as d, effect as o, setAttribute as $, use as k, delegateEvents as C } from "solid-js/web";
|
|
2
|
+
import { createSignal as _, createEffect as H, onMount as D, Show as E } from "solid-js";
|
|
3
3
|
import { StopIcon as I, SendIcon as j } from "./icons.js";
|
|
4
|
-
var z = /* @__PURE__ */ u('<button type=button class="shrink-0 w-
|
|
5
|
-
const V = (
|
|
6
|
-
const [i,
|
|
7
|
-
let
|
|
8
|
-
const
|
|
9
|
-
if (
|
|
10
|
-
|
|
11
|
-
const e =
|
|
12
|
-
|
|
4
|
+
var z = /* @__PURE__ */ u('<button type=button class="shrink-0 w-[42px] h-[42px] flex items-center justify-center rounded-xl bg-error-500 text-white hover:bg-error-600 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"aria-label="Stop generation">'), M = /* @__PURE__ */ u('<div class="flex items-end gap-2 p-4 border-t border-surface-200 dark:border-surface-700 bg-white/50 dark:bg-surface-900/50 backdrop-blur-sm"><div class=flex-1><textarea rows=1 class="flex w-full glass-input text-surface-800 dark:text-surface-200 resize-none overflow-hidden focus:outline-none disabled:opacity-50 disabled:cursor-not-allowed py-2.5 px-4 min-h-[42px]">'), K = /* @__PURE__ */ u('<button type=button class="shrink-0 w-[42px] h-[42px] flex items-center justify-center rounded-xl bg-accent-500 text-white hover:bg-accent-600 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-accent-500 transition-colors"aria-label="Send message">');
|
|
5
|
+
const V = (n) => {
|
|
6
|
+
const [i, f] = _("");
|
|
7
|
+
let a;
|
|
8
|
+
const p = () => n.placeholder ?? "Type a message...", s = () => n.disabled ?? !1, h = () => i().trim().length > 0 && !s() && !n.isStreaming, g = () => {
|
|
9
|
+
if (a) {
|
|
10
|
+
a.style.height = "auto";
|
|
11
|
+
const e = a.scrollHeight, l = 150, r = Math.min(e, l);
|
|
12
|
+
a.style.height = `${r}px`, a.style.overflowY = e > l ? "auto" : "hidden";
|
|
13
13
|
}
|
|
14
14
|
};
|
|
15
|
-
|
|
16
|
-
i(),
|
|
17
|
-
}),
|
|
18
|
-
|
|
15
|
+
H(() => {
|
|
16
|
+
i(), g();
|
|
17
|
+
}), D(() => {
|
|
18
|
+
g();
|
|
19
19
|
});
|
|
20
|
-
const
|
|
20
|
+
const b = () => {
|
|
21
21
|
const e = i().trim();
|
|
22
|
-
e && !
|
|
22
|
+
e && !s() && !n.isStreaming && (n.onSendMessage(e), f(""), a && (a.style.height = "auto"));
|
|
23
23
|
}, m = () => {
|
|
24
|
-
|
|
25
|
-
}, $ = (e) => {
|
|
26
|
-
e.key === "Enter" && !e.shiftKey ? (e.preventDefault(), f() && g()) : e.key === "Escape" && a.isStreaming && (e.preventDefault(), m());
|
|
24
|
+
n.onCancelStream && n.onCancelStream();
|
|
27
25
|
}, w = (e) => {
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
e.key === "Enter" && !e.shiftKey ? (e.preventDefault(), h() && b()) : e.key === "Escape" && n.isStreaming && (e.preventDefault(), m());
|
|
27
|
+
}, S = (e) => {
|
|
28
|
+
const l = e.target;
|
|
29
|
+
f(l.value);
|
|
30
30
|
};
|
|
31
31
|
return (() => {
|
|
32
|
-
var e = M(),
|
|
33
|
-
|
|
34
|
-
var v =
|
|
35
|
-
return typeof v == "function" ?
|
|
32
|
+
var e = M(), l = e.firstChild, r = l.firstChild;
|
|
33
|
+
r.$$keydown = w, r.$$input = S;
|
|
34
|
+
var v = a;
|
|
35
|
+
return typeof v == "function" ? k(v, r) : a = r, c(e, d(E, {
|
|
36
36
|
get when() {
|
|
37
|
-
return
|
|
37
|
+
return n.isStreaming;
|
|
38
38
|
},
|
|
39
39
|
get fallback() {
|
|
40
40
|
return (() => {
|
|
41
41
|
var t = K();
|
|
42
|
-
return t.$$click =
|
|
42
|
+
return t.$$click = b, c(t, d(j, {
|
|
43
43
|
size: 18
|
|
44
|
-
})),
|
|
44
|
+
})), o(() => t.disabled = !h()), t;
|
|
45
45
|
})();
|
|
46
46
|
},
|
|
47
47
|
get children() {
|
|
48
48
|
var t = z();
|
|
49
49
|
return t.$$click = m, c(t, d(I, {
|
|
50
50
|
size: 18
|
|
51
|
-
})),
|
|
51
|
+
})), o(() => t.disabled = !n.onCancelStream), t;
|
|
52
52
|
}
|
|
53
|
-
}), null),
|
|
54
|
-
var
|
|
55
|
-
return
|
|
53
|
+
}), null), o((t) => {
|
|
54
|
+
var x = p(), y = s();
|
|
55
|
+
return x !== t.e && $(r, "placeholder", t.e = x), y !== t.t && (r.disabled = t.t = y), t;
|
|
56
56
|
}, {
|
|
57
57
|
e: void 0,
|
|
58
58
|
t: void 0
|
|
59
|
-
}),
|
|
59
|
+
}), o(() => r.value = i()), e;
|
|
60
60
|
})();
|
|
61
61
|
};
|
|
62
62
|
C(["input", "keydown", "click"]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatInput.js","sources":["../../../src/components/Chat/ChatInput.tsx"],"sourcesContent":["import type { Component } from 'solid-js';\nimport { Show, createEffect, createSignal, onMount } from 'solid-js';\nimport { SendIcon, StopIcon } from './icons';\nimport type { ChatInputProps } from './types';\n\n/**\n * Chat input with textarea and send/stop button\n */\nexport const ChatInput: Component<ChatInputProps> = (props) => {\n const [value, setValue] = createSignal('');\n let textareaRef: HTMLTextAreaElement | undefined;\n\n const placeholder = () => props.placeholder ?? 'Type a message...';\n const isDisabled = () => props.disabled ?? false;\n const canSend = () => value().trim().length > 0 && !isDisabled();\n\n // Auto-resize textarea based on content\n const adjustHeight = () => {\n if (textareaRef) {\n textareaRef.style.height = 'auto';\n const scrollHeight = textareaRef.scrollHeight;\n // Max height of ~6 lines\n const maxHeight = 150;\n
|
|
1
|
+
{"version":3,"file":"ChatInput.js","sources":["../../../src/components/Chat/ChatInput.tsx"],"sourcesContent":["import type { Component } from 'solid-js';\nimport { Show, createEffect, createSignal, onMount } from 'solid-js';\nimport { SendIcon, StopIcon } from './icons';\nimport type { ChatInputProps } from './types';\n\n/**\n * Chat input with textarea and send/stop button\n */\nexport const ChatInput: Component<ChatInputProps> = (props) => {\n const [value, setValue] = createSignal('');\n let textareaRef: HTMLTextAreaElement | undefined;\n\n const placeholder = () => props.placeholder ?? 'Type a message...';\n const isDisabled = () => props.disabled ?? false;\n const canSend = () => value().trim().length > 0 && !isDisabled() && !props.isStreaming;\n\n // Auto-resize textarea based on content\n const adjustHeight = () => {\n if (textareaRef) {\n textareaRef.style.height = 'auto';\n const scrollHeight = textareaRef.scrollHeight;\n // Max height of ~6 lines\n const maxHeight = 150;\n const newHeight = Math.min(scrollHeight, maxHeight);\n textareaRef.style.height = `${newHeight}px`;\n textareaRef.style.overflowY = scrollHeight > maxHeight ? 'auto' : 'hidden';\n }\n };\n\n createEffect(() => {\n // Trigger resize when value changes\n value();\n adjustHeight();\n });\n\n onMount(() => {\n adjustHeight();\n });\n\n const handleSend = () => {\n const content = value().trim();\n if (content && !isDisabled() && !props.isStreaming) {\n props.onSendMessage(content);\n setValue('');\n // Reset textarea height\n if (textareaRef) {\n textareaRef.style.height = 'auto';\n }\n }\n };\n\n const handleCancel = () => {\n if (props.onCancelStream) {\n props.onCancelStream();\n }\n };\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n if (canSend()) {\n handleSend();\n }\n } else if (e.key === 'Escape' && props.isStreaming) {\n e.preventDefault();\n handleCancel();\n }\n };\n\n const handleInput = (e: Event) => {\n const target = e.target as HTMLTextAreaElement;\n setValue(target.value);\n };\n\n return (\n <div class=\"flex items-end gap-2 p-4 border-t border-surface-200 dark:border-surface-700 bg-white/50 dark:bg-surface-900/50 backdrop-blur-sm\">\n {/* Textarea */}\n <div class=\"flex-1\">\n <textarea\n ref={textareaRef}\n value={value()}\n onInput={handleInput}\n onKeyDown={handleKeyDown}\n placeholder={placeholder()}\n disabled={isDisabled()}\n rows={1}\n class=\"flex w-full glass-input text-surface-800 dark:text-surface-200 resize-none overflow-hidden focus:outline-none disabled:opacity-50 disabled:cursor-not-allowed py-2.5 px-4 min-h-[42px]\"\n />\n </div>\n\n {/* Send/Stop button */}\n <Show\n when={props.isStreaming}\n fallback={\n <button\n type=\"button\"\n onClick={handleSend}\n disabled={!canSend()}\n class=\"shrink-0 w-[42px] h-[42px] flex items-center justify-center rounded-xl bg-accent-500 text-white hover:bg-accent-600 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-accent-500 transition-colors\"\n aria-label=\"Send message\"\n >\n <SendIcon size={18} />\n </button>\n }\n >\n <button\n type=\"button\"\n onClick={handleCancel}\n disabled={!props.onCancelStream}\n class=\"shrink-0 w-[42px] h-[42px] flex items-center justify-center rounded-xl bg-error-500 text-white hover:bg-error-600 disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n aria-label=\"Stop generation\"\n >\n <StopIcon size={18} />\n </button>\n </Show>\n </div>\n );\n};\n"],"names":["ChatInput","props","value","setValue","createSignal","textareaRef","placeholder","isDisabled","disabled","canSend","trim","length","isStreaming","adjustHeight","style","height","scrollHeight","maxHeight","newHeight","Math","min","overflowY","createEffect","onMount","handleSend","content","onSendMessage","handleCancel","onCancelStream","handleKeyDown","e","key","shiftKey","preventDefault","handleInput","target","_el$","_tmpl$2","_el$2","firstChild","_el$3","$$keydown","$$input","_ref$","_$use","_$insert","_$createComponent","Show","when","fallback","_el$5","_tmpl$3","$$click","SendIcon","size","_$effect","children","_el$4","_tmpl$","StopIcon","_p$","_v$","_v$2","_$setAttribute","t","undefined","_$delegateEvents"],"mappings":";;;;AAQO,MAAMA,IAAwCC,CAAAA,MAAU;AAC7D,QAAM,CAACC,GAAOC,CAAQ,IAAIC,EAAa,EAAE;AACzC,MAAIC;AAEJ,QAAMC,IAAcA,MAAML,EAAMK,eAAe,qBACzCC,IAAaA,MAAMN,EAAMO,YAAY,IACrCC,IAAUA,MAAMP,EAAAA,EAAQQ,KAAAA,EAAOC,SAAS,KAAK,CAACJ,OAAgB,CAACN,EAAMW,aAGrEC,IAAeA,MAAM;AACzB,QAAIR,GAAa;AACfA,MAAAA,EAAYS,MAAMC,SAAS;AAC3B,YAAMC,IAAeX,EAAYW,cAE3BC,IAAY,KACZC,IAAYC,KAAKC,IAAIJ,GAAcC,CAAS;AAClDZ,MAAAA,EAAYS,MAAMC,SAAS,GAAGG,CAAS,MACvCb,EAAYS,MAAMO,YAAYL,IAAeC,IAAY,SAAS;AAAA,IACpE;AAAA,EACF;AAEAK,EAAAA,EAAa,MAAM;AAEjBpB,IAAAA,EAAAA,GACAW,EAAAA;AAAAA,EACF,CAAC,GAEDU,EAAQ,MAAM;AACZV,IAAAA,EAAAA;AAAAA,EACF,CAAC;AAED,QAAMW,IAAaA,MAAM;AACvB,UAAMC,IAAUvB,EAAAA,EAAQQ,KAAAA;AACxB,IAAIe,KAAW,CAAClB,EAAAA,KAAgB,CAACN,EAAMW,gBACrCX,EAAMyB,cAAcD,CAAO,GAC3BtB,EAAS,EAAE,GAEPE,MACFA,EAAYS,MAAMC,SAAS;AAAA,EAGjC,GAEMY,IAAeA,MAAM;AACzB,IAAI1B,EAAM2B,kBACR3B,EAAM2B,eAAAA;AAAAA,EAEV,GAEMC,IAAgBA,CAACC,MAAqB;AAC1C,IAAIA,EAAEC,QAAQ,WAAW,CAACD,EAAEE,YAC1BF,EAAEG,eAAAA,GACExB,OACFe,EAAAA,KAEOM,EAAEC,QAAQ,YAAY9B,EAAMW,gBACrCkB,EAAEG,eAAAA,GACFN,EAAAA;AAAAA,EAEJ,GAEMO,IAAcA,CAACJ,MAAa;AAChC,UAAMK,IAASL,EAAEK;AACjBhC,IAAAA,EAASgC,EAAOjC,KAAK;AAAA,EACvB;AAEA,UAAA,MAAA;AAAA,QAAAkC,IAAAC,EAAAA,GAAAC,IAAAF,EAAAG,YAAAC,IAAAF,EAAAC;AAAAC,IAAAA,EAAAC,YAQmBZ,GAAaW,EAAAE,UADfR;AAAW,QAAAS,IAFftC;AAAW,kBAAAsC,KAAA,aAAAC,EAAAD,GAAAH,CAAA,IAAXnC,IAAWmC,GAAAK,EAAAT,GAAAU,EAYnBC,GAAI;AAAA,MAAA,IACHC,OAAI;AAAA,eAAE/C,EAAMW;AAAAA,MAAW;AAAA,MAAA,IACvBqC,WAAQ;AAAA,gBAAA,MAAA;AAAA,cAAAC,IAAAC,EAAAA;AAAAD,iBAAAA,EAAAE,UAGK5B,GAAUqB,EAAAK,GAAAJ,EAKlBO,GAAQ;AAAA,YAACC,MAAM;AAAA,UAAA,CAAE,CAAA,GAAAC,EAAA,MAAAL,EAAA1C,WAJR,CAACC,GAAS,GAAAyC;AAAAA,QAAA,GAAA;AAAA,MAAA;AAAA,MAAA,IAAAM,WAAA;AAAA,YAAAC,IAAAC,EAAAA;AAAAD,eAAAA,EAAAL,UAUbzB,GAAYkB,EAAAY,GAAAX,EAKpBa,GAAQ;AAAA,UAACL,MAAM;AAAA,QAAA,CAAE,CAAA,GAAAC,EAAA,MAAAE,EAAAjD,WAJR,CAACP,EAAM2B,cAAc,GAAA6B;AAAAA,MAAA;AAAA,IAAA,CAAA,GAAA,IAAA,GAAAF,EAAAK,CAAAA,MAAA;AAAA,UAAAC,IAzBlBvD,KAAawD,IAChBvD,EAAAA;AAAYsD,aAAAA,MAAAD,EAAA9B,KAAAiC,EAAAvB,GAAA,eAAAoB,EAAA9B,IAAA+B,CAAA,GAAAC,MAAAF,EAAAI,MAAAxB,EAAAhC,WAAAoD,EAAAI,IAAAF,IAAAF;AAAAA,IAAA,GAAA;AAAA,MAAA9B,GAAAmC;AAAAA,MAAAD,GAAAC;AAAAA,IAAAA,CAAA,GAAAV,QAAAf,EAAAtC,QAJfA,EAAAA,CAAO,GAAAkC;AAAAA,EAAA,GAAA;AAqCxB;AAAE8B,EAAA,CAAA,SAAA,WAAA,OAAA,CAAA;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatMessage.d.ts","sourceRoot":"","sources":["../../../src/components/Chat/ChatMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"ChatMessage.d.ts","sourceRoot":"","sources":["../../../src/components/Chat/ChatMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAM1C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,SAAS,CAAC,gBAAgB,CAwHnD,CAAC"}
|