@yushaw/sanqian-chat 0.2.21 → 0.2.23

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.
@@ -7869,6 +7869,7 @@ var ChatInput = (0, import_react23.memo)(
7869
7869
  const [text, setText] = (0, import_react23.useState)("");
7870
7870
  const textareaRef = (0, import_react23.useRef)(null);
7871
7871
  const submitInFlightRef = (0, import_react23.useRef)(false);
7872
+ const inputRevisionRef = (0, import_react23.useRef)(0);
7872
7873
  const canSend = (text.trim().length > 0 || allowEmptySubmit) && !disabled && !isLoading;
7873
7874
  const showStopButton = isStreaming && !!onStop;
7874
7875
  const showSpinner = isLoading && !showStopButton;
@@ -7893,13 +7894,24 @@ var ChatInput = (0, import_react23.memo)(
7893
7894
  e?.preventDefault();
7894
7895
  if (!canSend) return;
7895
7896
  if (submitInFlightRef.current) return;
7897
+ const draft = text;
7898
+ const payload = draft.trim();
7899
+ const submitRevision = inputRevisionRef.current;
7896
7900
  submitInFlightRef.current = true;
7901
+ setText("");
7902
+ const restoreDraft = () => {
7903
+ setText((current) => {
7904
+ if (inputRevisionRef.current !== submitRevision) return current;
7905
+ return current.length === 0 ? draft : current;
7906
+ });
7907
+ };
7897
7908
  try {
7898
- const result = await onSend(text.trim());
7899
- if (result !== false) {
7900
- setText("");
7909
+ const result = await onSend(payload);
7910
+ if (result === false) {
7911
+ restoreDraft();
7901
7912
  }
7902
7913
  } catch {
7914
+ restoreDraft();
7903
7915
  } finally {
7904
7916
  submitInFlightRef.current = false;
7905
7917
  }
@@ -7945,7 +7957,10 @@ var ChatInput = (0, import_react23.memo)(
7945
7957
  {
7946
7958
  ref: textareaRef,
7947
7959
  value: text,
7948
- onChange: (e) => setText(e.target.value),
7960
+ onChange: (e) => {
7961
+ inputRevisionRef.current += 1;
7962
+ setText(e.target.value);
7963
+ },
7949
7964
  onKeyDown: handleKeyDown,
7950
7965
  placeholder,
7951
7966
  disabled,
@@ -10778,6 +10793,39 @@ var CompactChat = (0, import_react38.memo)(function CompactChat2({
10778
10793
  leftSlot: addResourceButtonSlot
10779
10794
  }
10780
10795
  );
10796
+ const hasContextTags = chat.sessionResources.length > 0 || resourcePicker.attachedResources.length > 0;
10797
+ const contextTagsOverlay = hasContextTags ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
10798
+ "div",
10799
+ {
10800
+ className: "pointer-events-none absolute left-0 right-0 z-10",
10801
+ style: { bottom: "calc(100% + 8px)" },
10802
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-col gap-1", children: [
10803
+ chat.sessionResources.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "pointer-events-auto", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
10804
+ AttachedResourceTags,
10805
+ {
10806
+ resources: chat.sessionResources.map((r) => ({
10807
+ providerId: r.appName,
10808
+ resourceId: r.fullId,
10809
+ title: r.title,
10810
+ summary: r.summary,
10811
+ icon: r.icon,
10812
+ type: r.type
10813
+ })),
10814
+ onRemove: (_, fullId) => chat.removeSessionResource(fullId),
10815
+ disabled: disableInput
10816
+ }
10817
+ ) }),
10818
+ resourcePicker.attachedResources.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "pointer-events-auto", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
10819
+ AttachedResourceTags,
10820
+ {
10821
+ resources: resourcePicker.attachedResources,
10822
+ onRemove: resourcePicker.detachResource,
10823
+ disabled: disableInput
10824
+ }
10825
+ ) })
10826
+ ] })
10827
+ }
10828
+ ) : null;
10781
10829
  if (shouldRenderInputExternally && portalContainerRef.current) {
10782
10830
  return (0, import_react_dom.createPortal)(inputElement, portalContainerRef.current);
10783
10831
  }
@@ -10837,32 +10885,10 @@ var CompactChat = (0, import_react38.memo)(function CompactChat2({
10837
10885
  }
10838
10886
  }
10839
10887
  ),
10840
- (chat.sessionResources.length > 0 || resourcePicker.attachedResources.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
10841
- chat.sessionResources.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
10842
- AttachedResourceTags,
10843
- {
10844
- resources: chat.sessionResources.map((r) => ({
10845
- providerId: r.appName,
10846
- resourceId: r.fullId,
10847
- title: r.title,
10848
- summary: r.summary,
10849
- icon: r.icon,
10850
- type: r.type
10851
- })),
10852
- onRemove: (_, fullId) => chat.removeSessionResource(fullId),
10853
- disabled: disableInput
10854
- }
10855
- ),
10856
- resourcePicker.attachedResources.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
10857
- AttachedResourceTags,
10858
- {
10859
- resources: resourcePicker.attachedResources,
10860
- onRemove: resourcePicker.detachResource,
10861
- disabled: disableInput
10862
- }
10863
- )
10864
- ] }),
10865
- inputElement
10888
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "relative", children: [
10889
+ contextTagsOverlay,
10890
+ inputElement
10891
+ ] })
10866
10892
  ] });
10867
10893
  })()
10868
10894
  ]
@@ -7797,6 +7797,7 @@ var ChatInput = memo7(
7797
7797
  const [text, setText] = useState14("");
7798
7798
  const textareaRef = useRef9(null);
7799
7799
  const submitInFlightRef = useRef9(false);
7800
+ const inputRevisionRef = useRef9(0);
7800
7801
  const canSend = (text.trim().length > 0 || allowEmptySubmit) && !disabled && !isLoading;
7801
7802
  const showStopButton = isStreaming && !!onStop;
7802
7803
  const showSpinner = isLoading && !showStopButton;
@@ -7821,13 +7822,24 @@ var ChatInput = memo7(
7821
7822
  e?.preventDefault();
7822
7823
  if (!canSend) return;
7823
7824
  if (submitInFlightRef.current) return;
7825
+ const draft = text;
7826
+ const payload = draft.trim();
7827
+ const submitRevision = inputRevisionRef.current;
7824
7828
  submitInFlightRef.current = true;
7829
+ setText("");
7830
+ const restoreDraft = () => {
7831
+ setText((current) => {
7832
+ if (inputRevisionRef.current !== submitRevision) return current;
7833
+ return current.length === 0 ? draft : current;
7834
+ });
7835
+ };
7825
7836
  try {
7826
- const result = await onSend(text.trim());
7827
- if (result !== false) {
7828
- setText("");
7837
+ const result = await onSend(payload);
7838
+ if (result === false) {
7839
+ restoreDraft();
7829
7840
  }
7830
7841
  } catch {
7842
+ restoreDraft();
7831
7843
  } finally {
7832
7844
  submitInFlightRef.current = false;
7833
7845
  }
@@ -7873,7 +7885,10 @@ var ChatInput = memo7(
7873
7885
  {
7874
7886
  ref: textareaRef,
7875
7887
  value: text,
7876
- onChange: (e) => setText(e.target.value),
7888
+ onChange: (e) => {
7889
+ inputRevisionRef.current += 1;
7890
+ setText(e.target.value);
7891
+ },
7877
7892
  onKeyDown: handleKeyDown,
7878
7893
  placeholder,
7879
7894
  disabled,
@@ -10706,6 +10721,39 @@ var CompactChat = memo18(function CompactChat2({
10706
10721
  leftSlot: addResourceButtonSlot
10707
10722
  }
10708
10723
  );
10724
+ const hasContextTags = chat.sessionResources.length > 0 || resourcePicker.attachedResources.length > 0;
10725
+ const contextTagsOverlay = hasContextTags ? /* @__PURE__ */ jsx26(
10726
+ "div",
10727
+ {
10728
+ className: "pointer-events-none absolute left-0 right-0 z-10",
10729
+ style: { bottom: "calc(100% + 8px)" },
10730
+ children: /* @__PURE__ */ jsxs20("div", { className: "flex flex-col gap-1", children: [
10731
+ chat.sessionResources.length > 0 && /* @__PURE__ */ jsx26("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx26(
10732
+ AttachedResourceTags,
10733
+ {
10734
+ resources: chat.sessionResources.map((r) => ({
10735
+ providerId: r.appName,
10736
+ resourceId: r.fullId,
10737
+ title: r.title,
10738
+ summary: r.summary,
10739
+ icon: r.icon,
10740
+ type: r.type
10741
+ })),
10742
+ onRemove: (_, fullId) => chat.removeSessionResource(fullId),
10743
+ disabled: disableInput
10744
+ }
10745
+ ) }),
10746
+ resourcePicker.attachedResources.length > 0 && /* @__PURE__ */ jsx26("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx26(
10747
+ AttachedResourceTags,
10748
+ {
10749
+ resources: resourcePicker.attachedResources,
10750
+ onRemove: resourcePicker.detachResource,
10751
+ disabled: disableInput
10752
+ }
10753
+ ) })
10754
+ ] })
10755
+ }
10756
+ ) : null;
10709
10757
  if (shouldRenderInputExternally && portalContainerRef.current) {
10710
10758
  return createPortal(inputElement, portalContainerRef.current);
10711
10759
  }
@@ -10765,32 +10813,10 @@ var CompactChat = memo18(function CompactChat2({
10765
10813
  }
10766
10814
  }
10767
10815
  ),
10768
- (chat.sessionResources.length > 0 || resourcePicker.attachedResources.length > 0) && /* @__PURE__ */ jsxs20(Fragment6, { children: [
10769
- chat.sessionResources.length > 0 && /* @__PURE__ */ jsx26(
10770
- AttachedResourceTags,
10771
- {
10772
- resources: chat.sessionResources.map((r) => ({
10773
- providerId: r.appName,
10774
- resourceId: r.fullId,
10775
- title: r.title,
10776
- summary: r.summary,
10777
- icon: r.icon,
10778
- type: r.type
10779
- })),
10780
- onRemove: (_, fullId) => chat.removeSessionResource(fullId),
10781
- disabled: disableInput
10782
- }
10783
- ),
10784
- resourcePicker.attachedResources.length > 0 && /* @__PURE__ */ jsx26(
10785
- AttachedResourceTags,
10786
- {
10787
- resources: resourcePicker.attachedResources,
10788
- onRemove: resourcePicker.detachResource,
10789
- disabled: disableInput
10790
- }
10791
- )
10792
- ] }),
10793
- inputElement
10816
+ /* @__PURE__ */ jsxs20("div", { className: "relative", children: [
10817
+ contextTagsOverlay,
10818
+ inputElement
10819
+ ] })
10794
10820
  ] });
10795
10821
  })()
10796
10822
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yushaw/sanqian-chat",
3
- "version": "0.2.21",
3
+ "version": "0.2.23",
4
4
  "description": "Floating chat window SDK for Sanqian AI Assistant",
5
5
  "main": "./dist/main/index.js",
6
6
  "types": "./dist/main/index.d.ts",