@mordn/chat-widget 0.6.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +140 -56
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +140 -56
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -720,6 +720,7 @@ function useInputPlugins({ textareaRef, value, setValue, plugins }) {
|
|
|
720
720
|
const [loading, setLoading] = useState2(false);
|
|
721
721
|
const debounceRef = useRef2(null);
|
|
722
722
|
const requestIdRef = useRef2(0);
|
|
723
|
+
const sessionValidatedRef = useRef2(false);
|
|
723
724
|
const pluginsByTrigger = useMemo2(() => {
|
|
724
725
|
const map = /* @__PURE__ */ new Map();
|
|
725
726
|
for (const p of plugins ?? []) {
|
|
@@ -736,9 +737,14 @@ function useInputPlugins({ textareaRef, value, setValue, plugins }) {
|
|
|
736
737
|
return value.slice(active.triggerIndex + 1, cursor);
|
|
737
738
|
}, [active, value, textareaRef]);
|
|
738
739
|
useEffect2(() => {
|
|
739
|
-
if (!active)
|
|
740
|
-
|
|
741
|
-
|
|
740
|
+
if (!active) {
|
|
741
|
+
sessionValidatedRef.current = false;
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
if (value[active.triggerIndex] === active.plugin.trigger) {
|
|
745
|
+
sessionValidatedRef.current = true;
|
|
746
|
+
}
|
|
747
|
+
if (!sessionValidatedRef.current) return;
|
|
742
748
|
if (value[active.triggerIndex] !== active.plugin.trigger) {
|
|
743
749
|
setActive(null);
|
|
744
750
|
return;
|
|
@@ -746,7 +752,7 @@ function useInputPlugins({ textareaRef, value, setValue, plugins }) {
|
|
|
746
752
|
if (/\s/.test(query)) {
|
|
747
753
|
setActive(null);
|
|
748
754
|
}
|
|
749
|
-
}, [active, value, query
|
|
755
|
+
}, [active, value, query]);
|
|
750
756
|
useEffect2(() => {
|
|
751
757
|
if (!active) {
|
|
752
758
|
setItems([]);
|
|
@@ -754,13 +760,20 @@ function useInputPlugins({ textareaRef, value, setValue, plugins }) {
|
|
|
754
760
|
return;
|
|
755
761
|
}
|
|
756
762
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
757
|
-
setLoading(true);
|
|
758
763
|
const reqId = ++requestIdRef.current;
|
|
764
|
+
const result = active.plugin.fetch(query);
|
|
765
|
+
if (Array.isArray(result)) {
|
|
766
|
+
setItems(result);
|
|
767
|
+
setHighlight(0);
|
|
768
|
+
setLoading(false);
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
setLoading(true);
|
|
759
772
|
debounceRef.current = setTimeout(async () => {
|
|
760
773
|
try {
|
|
761
|
-
const
|
|
774
|
+
const items2 = await result;
|
|
762
775
|
if (reqId !== requestIdRef.current) return;
|
|
763
|
-
setItems(
|
|
776
|
+
setItems(items2);
|
|
764
777
|
setHighlight(0);
|
|
765
778
|
} catch (err) {
|
|
766
779
|
console.error("[input-plugin] fetch failed:", err);
|
|
@@ -841,14 +854,8 @@ function useInputPlugins({ textareaRef, value, setValue, plugins }) {
|
|
|
841
854
|
},
|
|
842
855
|
[active, items, highlight, selectItem, close, pluginsByTrigger, value]
|
|
843
856
|
);
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
if (value[active.triggerIndex] !== active.plugin.trigger) {
|
|
847
|
-
close();
|
|
848
|
-
}
|
|
849
|
-
}, [value, active, close]);
|
|
850
|
-
const popover = active && (loading || items.length > 0 || active.plugin.emptyText) ? /* @__PURE__ */ jsx10(
|
|
851
|
-
PluginPopover,
|
|
857
|
+
const panel = active ? /* @__PURE__ */ jsx10(
|
|
858
|
+
PluginPanel,
|
|
852
859
|
{
|
|
853
860
|
plugin: active.plugin,
|
|
854
861
|
items,
|
|
@@ -858,43 +865,122 @@ function useInputPlugins({ textareaRef, value, setValue, plugins }) {
|
|
|
858
865
|
onSelect: selectItem
|
|
859
866
|
}
|
|
860
867
|
) : null;
|
|
861
|
-
return { onKeyDown,
|
|
868
|
+
return { onKeyDown, panel, isOpen: !!active };
|
|
862
869
|
}
|
|
863
|
-
function
|
|
870
|
+
function PluginPanel({ plugin, items, loading, highlight, onHover, onSelect }) {
|
|
871
|
+
const viewportRef = useRef2(null);
|
|
872
|
+
const itemRefs = useRef2([]);
|
|
873
|
+
useEffect2(() => {
|
|
874
|
+
const btn = itemRefs.current[highlight];
|
|
875
|
+
const viewport = viewportRef.current;
|
|
876
|
+
if (!btn || !viewport) return;
|
|
877
|
+
const btnRect = btn.getBoundingClientRect();
|
|
878
|
+
const viewRect = viewport.getBoundingClientRect();
|
|
879
|
+
if (btnRect.top < viewRect.top) {
|
|
880
|
+
viewport.scrollTop -= viewRect.top - btnRect.top;
|
|
881
|
+
} else if (btnRect.bottom > viewRect.bottom) {
|
|
882
|
+
viewport.scrollTop += btnRect.bottom - viewRect.bottom;
|
|
883
|
+
}
|
|
884
|
+
}, [highlight]);
|
|
864
885
|
return /* @__PURE__ */ jsxs6(
|
|
865
886
|
"div",
|
|
866
887
|
{
|
|
867
888
|
role: "listbox",
|
|
868
|
-
className:
|
|
869
|
-
"absolute bottom-full left-0 right-0 mb-2 z-30",
|
|
870
|
-
"rounded-md border border-border bg-popover text-popover-foreground shadow-md",
|
|
871
|
-
"max-h-64 overflow-y-auto"
|
|
872
|
-
),
|
|
889
|
+
className: "rounded-t-xl bg-[hsl(var(--chat-background))] overflow-hidden mx-auto",
|
|
873
890
|
onMouseDown: (e) => e.preventDefault(),
|
|
891
|
+
style: {
|
|
892
|
+
width: "96%",
|
|
893
|
+
borderTop: "1px solid var(--chat-divider)",
|
|
894
|
+
borderLeft: "1px solid var(--chat-divider)",
|
|
895
|
+
borderRight: "1px solid var(--chat-divider)",
|
|
896
|
+
// Pull down 1px so our bottom edge overlaps the form's top
|
|
897
|
+
// border, removing the visible seam between the two surfaces.
|
|
898
|
+
marginBottom: -1
|
|
899
|
+
},
|
|
874
900
|
children: [
|
|
875
|
-
plugin.heading && /* @__PURE__ */ jsx10(
|
|
876
|
-
|
|
877
|
-
!loading && items.length === 0 && /* @__PURE__ */ jsx10("div", { className: "px-3 py-2 text-xs text-muted-foreground", children: plugin.emptyText ?? "No results" }),
|
|
878
|
-
items.map((item, idx) => /* @__PURE__ */ jsxs6(
|
|
879
|
-
"button",
|
|
901
|
+
plugin.heading && /* @__PURE__ */ jsx10(
|
|
902
|
+
"div",
|
|
880
903
|
{
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
|
|
904
|
+
className: "px-3 py-1.5 text-[11px] font-semibold uppercase tracking-wide",
|
|
905
|
+
style: {
|
|
906
|
+
color: "hsl(var(--chat-text)/0.5)",
|
|
907
|
+
borderBottom: "1px solid var(--chat-divider)"
|
|
908
|
+
},
|
|
909
|
+
children: plugin.heading
|
|
910
|
+
}
|
|
911
|
+
),
|
|
912
|
+
loading && items.length === 0 && /* @__PURE__ */ jsx10(
|
|
913
|
+
"div",
|
|
914
|
+
{
|
|
915
|
+
className: "px-3 py-2 text-[13px]",
|
|
916
|
+
style: { color: "hsl(var(--chat-text)/0.5)" },
|
|
917
|
+
children: "Loading\u2026"
|
|
918
|
+
}
|
|
919
|
+
),
|
|
920
|
+
!loading && items.length === 0 && /* @__PURE__ */ jsx10(
|
|
921
|
+
"div",
|
|
922
|
+
{
|
|
923
|
+
className: "px-3 py-2 text-[13px]",
|
|
924
|
+
style: { color: "hsl(var(--chat-text)/0.5)" },
|
|
925
|
+
children: plugin.emptyText ?? "No results"
|
|
926
|
+
}
|
|
927
|
+
),
|
|
928
|
+
items.length > 0 && /* @__PURE__ */ jsx10(
|
|
929
|
+
"div",
|
|
930
|
+
{
|
|
931
|
+
ref: viewportRef,
|
|
932
|
+
className: "max-h-[200px] overflow-y-auto",
|
|
933
|
+
children: /* @__PURE__ */ jsx10("div", { className: "py-1", children: items.map((item, idx) => /* @__PURE__ */ jsxs6("div", { children: [
|
|
934
|
+
/* @__PURE__ */ jsxs6(
|
|
935
|
+
"button",
|
|
936
|
+
{
|
|
937
|
+
ref: (el) => {
|
|
938
|
+
itemRefs.current[idx] = el;
|
|
939
|
+
},
|
|
940
|
+
type: "button",
|
|
941
|
+
role: "option",
|
|
942
|
+
"aria-selected": idx === highlight,
|
|
943
|
+
onMouseEnter: () => onHover(idx),
|
|
944
|
+
onClick: () => onSelect(item),
|
|
945
|
+
className: cn(
|
|
946
|
+
"w-full text-left px-3 py-2",
|
|
947
|
+
"flex items-center justify-between gap-3",
|
|
948
|
+
"transition-colors duration-150 ease-out",
|
|
949
|
+
"cursor-pointer"
|
|
950
|
+
),
|
|
951
|
+
style: {
|
|
952
|
+
backgroundColor: idx === highlight ? "hsl(var(--chat-text)/0.06)" : "transparent"
|
|
953
|
+
},
|
|
954
|
+
children: [
|
|
955
|
+
/* @__PURE__ */ jsx10(
|
|
956
|
+
"span",
|
|
957
|
+
{
|
|
958
|
+
className: "text-[13px] truncate",
|
|
959
|
+
style: { color: "hsl(var(--chat-text)/0.85)" },
|
|
960
|
+
children: item.label
|
|
961
|
+
}
|
|
962
|
+
),
|
|
963
|
+
item.sublabel && /* @__PURE__ */ jsx10(
|
|
964
|
+
"span",
|
|
965
|
+
{
|
|
966
|
+
className: "text-[11px] flex-shrink-0",
|
|
967
|
+
style: { color: "hsl(var(--chat-text)/0.4)" },
|
|
968
|
+
children: item.sublabel
|
|
969
|
+
}
|
|
970
|
+
)
|
|
971
|
+
]
|
|
972
|
+
}
|
|
973
|
+
),
|
|
974
|
+
idx < items.length - 1 && /* @__PURE__ */ jsx10(
|
|
975
|
+
"div",
|
|
976
|
+
{
|
|
977
|
+
className: "h-px mx-3",
|
|
978
|
+
style: { backgroundColor: "var(--chat-divider)" }
|
|
979
|
+
}
|
|
980
|
+
)
|
|
981
|
+
] }, item.id)) })
|
|
982
|
+
}
|
|
983
|
+
)
|
|
898
984
|
]
|
|
899
985
|
}
|
|
900
986
|
);
|
|
@@ -2352,21 +2438,19 @@ function ChatInterface({ id, initialMessages, config, onClose, headerActions } =
|
|
|
2352
2438
|
}
|
|
2353
2439
|
}
|
|
2354
2440
|
),
|
|
2441
|
+
inputPlugins.panel,
|
|
2355
2442
|
/* @__PURE__ */ jsxs13(PromptInput, { onSubmit: handleSubmit, globalDrop: true, multiple: true, accept: "image/*", children: [
|
|
2356
2443
|
/* @__PURE__ */ jsxs13(PromptInputBody, { children: [
|
|
2357
2444
|
/* @__PURE__ */ jsx21(PromptInputAttachments, { children: (attachment) => /* @__PURE__ */ jsx21(PromptInputAttachment, { data: attachment }) }),
|
|
2358
|
-
/* @__PURE__ */
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
),
|
|
2368
|
-
inputPlugins.popover
|
|
2369
|
-
] })
|
|
2445
|
+
/* @__PURE__ */ jsx21(
|
|
2446
|
+
PromptInputTextarea,
|
|
2447
|
+
{
|
|
2448
|
+
ref: inputRef,
|
|
2449
|
+
onChange: (e) => setInput(e.target.value),
|
|
2450
|
+
onKeyDown: inputPlugins.onKeyDown,
|
|
2451
|
+
value: input
|
|
2452
|
+
}
|
|
2453
|
+
)
|
|
2370
2454
|
] }),
|
|
2371
2455
|
/* @__PURE__ */ jsxs13(PromptInputToolbar, { children: [
|
|
2372
2456
|
/* @__PURE__ */ jsx21(PromptInputTools, { children: config?.features?.fileUpload === true && /* @__PURE__ */ jsx21(AttachButton, {}) }),
|