@yushaw/sanqian-chat 0.2.32 → 0.2.33

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.
@@ -7900,6 +7900,7 @@ var ChatInput = (0, import_react23.memo)(
7900
7900
  const textareaRef = (0, import_react23.useRef)(null);
7901
7901
  const submitInFlightRef = (0, import_react23.useRef)(false);
7902
7902
  const inputRevisionRef = (0, import_react23.useRef)(0);
7903
+ const buttonActionRef = (0, import_react23.useRef)(null);
7903
7904
  const canSend = (text.trim().length > 0 || allowEmptySubmit) && !disabled && !isLoading;
7904
7905
  const showStopButton = isStreaming && !!onStop;
7905
7906
  const showSpinner = isLoading && !showStopButton;
@@ -7948,6 +7949,28 @@ var ChatInput = (0, import_react23.memo)(
7948
7949
  },
7949
7950
  [text, canSend, onSend]
7950
7951
  );
7952
+ const handleActionPointerDown = (0, import_react23.useCallback)(
7953
+ (_e) => {
7954
+ buttonActionRef.current = showStopButton ? "stop" : "send";
7955
+ },
7956
+ [showStopButton]
7957
+ );
7958
+ const clearButtonAction = (0, import_react23.useCallback)(() => {
7959
+ buttonActionRef.current = null;
7960
+ }, []);
7961
+ const handleActionClick = (0, import_react23.useCallback)(
7962
+ (e) => {
7963
+ const action = buttonActionRef.current ?? (showStopButton ? "stop" : "send");
7964
+ buttonActionRef.current = null;
7965
+ if (action === "stop") {
7966
+ e.preventDefault();
7967
+ onStop?.();
7968
+ return;
7969
+ }
7970
+ void handleSubmit(e);
7971
+ },
7972
+ [showStopButton, onStop, handleSubmit]
7973
+ );
7951
7974
  const handleKeyDown = (0, import_react23.useCallback)(
7952
7975
  (e) => {
7953
7976
  if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
@@ -8006,8 +8029,11 @@ var ChatInput = (0, import_react23.memo)(
8006
8029
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
8007
8030
  "button",
8008
8031
  {
8009
- type: showStopButton ? "button" : "submit",
8010
- onClick: showStopButton ? onStop : void 0,
8032
+ type: "button",
8033
+ onPointerDown: handleActionPointerDown,
8034
+ onPointerCancel: clearButtonAction,
8035
+ onBlur: clearButtonAction,
8036
+ onClick: handleActionClick,
8011
8037
  disabled: !showStopButton && !canSend,
8012
8038
  className: "chat-input-send-btn",
8013
8039
  "aria-label": showStopButton ? stopLabel : sendLabel,
@@ -8238,7 +8264,6 @@ var HitlCard = (0, import_react24.memo)(function HitlCard2({
8238
8264
  borderColor: "rgba(220, 38, 38, 0.45)",
8239
8265
  boxShadow: "0 0 0 2px rgba(220, 38, 38, 0.11)"
8240
8266
  } : void 0;
8241
- const requiredHintStyle = isDarkMode ? { color: "rgba(252, 165, 165, 0.92)" } : { color: "rgba(185, 28, 28, 0.84)" };
8242
8267
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
8243
8268
  "div",
8244
8269
  {
@@ -8287,74 +8312,46 @@ var HitlCard = (0, import_react24.memo)(function HitlCard2({
8287
8312
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("code", { className: "text-[10px]", children: JSON.stringify(interrupt.args, null, 0) })
8288
8313
  ] })
8289
8314
  ] }),
8290
- isUserInput && interrupt.options && interrupt.options.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "space-y-1.5", children: [
8291
- interrupt.options.map((option, index) => {
8292
- const isSelected = selectedIndices.includes(index);
8293
- const optionStyle = isSelected ? isDarkMode ? { borderColor: "rgba(96, 165, 250, 0.75)", background: "rgba(59, 130, 246, 0.24)" } : { borderColor: "rgba(37, 99, 235, 0.36)", background: "rgba(239, 246, 255, 0.98)" } : isDarkMode ? { borderColor: "rgba(113, 113, 122, 0.6)", background: "rgba(9, 9, 11, 0.84)" } : { borderColor: "rgba(113, 113, 122, 0.34)", background: "rgba(250, 250, 250, 0.96)" };
8294
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
8295
- "label",
8296
- {
8297
- className: `flex cursor-pointer items-center gap-2 rounded p-2 transition-colors ${isSelected ? isDarkMode ? "border-blue-500/50 bg-blue-500/20" : "border-blue-200 bg-blue-50" : `${inputBg} border-transparent hover:border-zinc-300`} border`,
8298
- style: optionStyle,
8299
- children: [
8300
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
8301
- "input",
8302
- {
8303
- type: interrupt.multi_select ? "checkbox" : "radio",
8304
- name: "hitl-options",
8305
- checked: isSelected,
8306
- onChange: () => handleOptionToggle(index),
8307
- style: optionControlStyle
8308
- }
8309
- ),
8310
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `text-sm ${textPrimary} break-words ${isSelected ? "font-semibold" : "font-medium"}`, children: option })
8311
- ]
8312
- },
8313
- index
8314
- );
8315
- }),
8316
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "min-h-[18px]", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
8317
- "div",
8315
+ isUserInput && interrupt.options && interrupt.options.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "space-y-1.5", children: interrupt.options.map((option, index) => {
8316
+ const isSelected = selectedIndices.includes(index);
8317
+ const optionStyle = isSelected ? isDarkMode ? { borderColor: "rgba(96, 165, 250, 0.75)", background: "rgba(59, 130, 246, 0.24)" } : { borderColor: "rgba(37, 99, 235, 0.36)", background: "rgba(239, 246, 255, 0.98)" } : isDarkMode ? { borderColor: "rgba(113, 113, 122, 0.6)", background: "rgba(9, 9, 11, 0.84)" } : { borderColor: "rgba(113, 113, 122, 0.34)", background: "rgba(250, 250, 250, 0.96)" };
8318
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
8319
+ "label",
8318
8320
  {
8319
- className: `flex items-center gap-1 text-xs transition-all duration-150 ${showRequiredError ? "translate-y-0 opacity-100" : "-translate-y-1 opacity-0"}`,
8320
- style: requiredHintStyle,
8321
- "aria-live": "polite",
8321
+ className: `flex cursor-pointer items-center gap-2 rounded p-2 transition-colors ${isSelected ? isDarkMode ? "border-blue-500/50 bg-blue-500/20" : "border-blue-200 bg-blue-50" : `${inputBg} border-transparent hover:border-zinc-300`} border`,
8322
+ style: optionStyle,
8322
8323
  children: [
8323
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "inline-block h-1.5 w-1.5 rounded-full bg-current opacity-75" }),
8324
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: t.requiredField })
8325
- ]
8326
- }
8327
- ) })
8328
- ] }),
8329
- isUserInput && (!interrupt.options || interrupt.options.length === 0) && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
8330
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
8331
- "input",
8332
- {
8333
- ref: inputRef,
8334
- type: "text",
8335
- value: answer,
8336
- onChange: (e) => handleAnswerChange(e.target.value),
8337
- onKeyDown: handleKeyDown,
8338
- onCompositionStart: () => setIsComposing(true),
8339
- onCompositionEnd: () => setIsComposing(false),
8340
- placeholder: interrupt.default ? `${t.defaultPrefix}: ${interrupt.default}` : t.enterResponse,
8341
- className: `w-full rounded-lg border px-3 py-2 text-sm ${inputBorder} ${inputBg} ${textPrimary} placeholder:${textSecondary} ${showRequiredError ? "focus:border-red-400 focus:ring-red-400/25" : "focus:border-blue-500 focus:ring-blue-500/40"} focus:outline-none focus:ring-2`,
8342
- style: inputValidationStyle
8343
- }
8344
- ),
8345
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "mt-1 min-h-[18px]", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
8346
- "div",
8347
- {
8348
- className: `flex items-center gap-1 text-xs transition-all duration-150 ${showRequiredError ? "translate-y-0 opacity-100" : "-translate-y-1 opacity-0"}`,
8349
- style: requiredHintStyle,
8350
- "aria-live": "polite",
8351
- children: [
8352
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "inline-block h-1.5 w-1.5 rounded-full bg-current opacity-75" }),
8353
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: t.requiredField })
8324
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
8325
+ "input",
8326
+ {
8327
+ type: interrupt.multi_select ? "checkbox" : "radio",
8328
+ name: "hitl-options",
8329
+ checked: isSelected,
8330
+ onChange: () => handleOptionToggle(index),
8331
+ style: optionControlStyle
8332
+ }
8333
+ ),
8334
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `text-sm ${textPrimary} break-words ${isSelected ? "font-semibold" : "font-medium"}`, children: option })
8354
8335
  ]
8355
- }
8356
- ) })
8357
- ] }),
8336
+ },
8337
+ index
8338
+ );
8339
+ }) }),
8340
+ isUserInput && (!interrupt.options || interrupt.options.length === 0) && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
8341
+ "input",
8342
+ {
8343
+ ref: inputRef,
8344
+ type: "text",
8345
+ value: answer,
8346
+ onChange: (e) => handleAnswerChange(e.target.value),
8347
+ onKeyDown: handleKeyDown,
8348
+ onCompositionStart: () => setIsComposing(true),
8349
+ onCompositionEnd: () => setIsComposing(false),
8350
+ placeholder: interrupt.default ? `${t.defaultPrefix}: ${interrupt.default}` : t.enterResponse,
8351
+ className: `w-full rounded-lg border px-3 py-2 text-sm ${inputBorder} ${inputBg} ${textPrimary} placeholder:${textSecondary} ${showRequiredError ? "focus:border-red-400 focus:ring-red-400/25" : "focus:border-blue-500 focus:ring-blue-500/40"} focus:outline-none focus:ring-2`,
8352
+ style: inputValidationStyle
8353
+ }
8354
+ ) }),
8358
8355
  isApproval && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
8359
8356
  "label",
8360
8357
  {
@@ -7828,6 +7828,7 @@ var ChatInput = memo7(
7828
7828
  const textareaRef = useRef9(null);
7829
7829
  const submitInFlightRef = useRef9(false);
7830
7830
  const inputRevisionRef = useRef9(0);
7831
+ const buttonActionRef = useRef9(null);
7831
7832
  const canSend = (text.trim().length > 0 || allowEmptySubmit) && !disabled && !isLoading;
7832
7833
  const showStopButton = isStreaming && !!onStop;
7833
7834
  const showSpinner = isLoading && !showStopButton;
@@ -7876,6 +7877,28 @@ var ChatInput = memo7(
7876
7877
  },
7877
7878
  [text, canSend, onSend]
7878
7879
  );
7880
+ const handleActionPointerDown = useCallback14(
7881
+ (_e) => {
7882
+ buttonActionRef.current = showStopButton ? "stop" : "send";
7883
+ },
7884
+ [showStopButton]
7885
+ );
7886
+ const clearButtonAction = useCallback14(() => {
7887
+ buttonActionRef.current = null;
7888
+ }, []);
7889
+ const handleActionClick = useCallback14(
7890
+ (e) => {
7891
+ const action = buttonActionRef.current ?? (showStopButton ? "stop" : "send");
7892
+ buttonActionRef.current = null;
7893
+ if (action === "stop") {
7894
+ e.preventDefault();
7895
+ onStop?.();
7896
+ return;
7897
+ }
7898
+ void handleSubmit(e);
7899
+ },
7900
+ [showStopButton, onStop, handleSubmit]
7901
+ );
7879
7902
  const handleKeyDown = useCallback14(
7880
7903
  (e) => {
7881
7904
  if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
@@ -7934,8 +7957,11 @@ var ChatInput = memo7(
7934
7957
  /* @__PURE__ */ jsx11(
7935
7958
  "button",
7936
7959
  {
7937
- type: showStopButton ? "button" : "submit",
7938
- onClick: showStopButton ? onStop : void 0,
7960
+ type: "button",
7961
+ onPointerDown: handleActionPointerDown,
7962
+ onPointerCancel: clearButtonAction,
7963
+ onBlur: clearButtonAction,
7964
+ onClick: handleActionClick,
7939
7965
  disabled: !showStopButton && !canSend,
7940
7966
  className: "chat-input-send-btn",
7941
7967
  "aria-label": showStopButton ? stopLabel : sendLabel,
@@ -8166,7 +8192,6 @@ var HitlCard = memo8(function HitlCard2({
8166
8192
  borderColor: "rgba(220, 38, 38, 0.45)",
8167
8193
  boxShadow: "0 0 0 2px rgba(220, 38, 38, 0.11)"
8168
8194
  } : void 0;
8169
- const requiredHintStyle = isDarkMode ? { color: "rgba(252, 165, 165, 0.92)" } : { color: "rgba(185, 28, 28, 0.84)" };
8170
8195
  return /* @__PURE__ */ jsxs6(
8171
8196
  "div",
8172
8197
  {
@@ -8215,74 +8240,46 @@ var HitlCard = memo8(function HitlCard2({
8215
8240
  /* @__PURE__ */ jsx12("code", { className: "text-[10px]", children: JSON.stringify(interrupt.args, null, 0) })
8216
8241
  ] })
8217
8242
  ] }),
8218
- isUserInput && interrupt.options && interrupt.options.length > 0 && /* @__PURE__ */ jsxs6("div", { className: "space-y-1.5", children: [
8219
- interrupt.options.map((option, index) => {
8220
- const isSelected = selectedIndices.includes(index);
8221
- const optionStyle = isSelected ? isDarkMode ? { borderColor: "rgba(96, 165, 250, 0.75)", background: "rgba(59, 130, 246, 0.24)" } : { borderColor: "rgba(37, 99, 235, 0.36)", background: "rgba(239, 246, 255, 0.98)" } : isDarkMode ? { borderColor: "rgba(113, 113, 122, 0.6)", background: "rgba(9, 9, 11, 0.84)" } : { borderColor: "rgba(113, 113, 122, 0.34)", background: "rgba(250, 250, 250, 0.96)" };
8222
- return /* @__PURE__ */ jsxs6(
8223
- "label",
8224
- {
8225
- className: `flex cursor-pointer items-center gap-2 rounded p-2 transition-colors ${isSelected ? isDarkMode ? "border-blue-500/50 bg-blue-500/20" : "border-blue-200 bg-blue-50" : `${inputBg} border-transparent hover:border-zinc-300`} border`,
8226
- style: optionStyle,
8227
- children: [
8228
- /* @__PURE__ */ jsx12(
8229
- "input",
8230
- {
8231
- type: interrupt.multi_select ? "checkbox" : "radio",
8232
- name: "hitl-options",
8233
- checked: isSelected,
8234
- onChange: () => handleOptionToggle(index),
8235
- style: optionControlStyle
8236
- }
8237
- ),
8238
- /* @__PURE__ */ jsx12("span", { className: `text-sm ${textPrimary} break-words ${isSelected ? "font-semibold" : "font-medium"}`, children: option })
8239
- ]
8240
- },
8241
- index
8242
- );
8243
- }),
8244
- /* @__PURE__ */ jsx12("div", { className: "min-h-[18px]", children: /* @__PURE__ */ jsxs6(
8245
- "div",
8243
+ isUserInput && interrupt.options && interrupt.options.length > 0 && /* @__PURE__ */ jsx12("div", { className: "space-y-1.5", children: interrupt.options.map((option, index) => {
8244
+ const isSelected = selectedIndices.includes(index);
8245
+ const optionStyle = isSelected ? isDarkMode ? { borderColor: "rgba(96, 165, 250, 0.75)", background: "rgba(59, 130, 246, 0.24)" } : { borderColor: "rgba(37, 99, 235, 0.36)", background: "rgba(239, 246, 255, 0.98)" } : isDarkMode ? { borderColor: "rgba(113, 113, 122, 0.6)", background: "rgba(9, 9, 11, 0.84)" } : { borderColor: "rgba(113, 113, 122, 0.34)", background: "rgba(250, 250, 250, 0.96)" };
8246
+ return /* @__PURE__ */ jsxs6(
8247
+ "label",
8246
8248
  {
8247
- className: `flex items-center gap-1 text-xs transition-all duration-150 ${showRequiredError ? "translate-y-0 opacity-100" : "-translate-y-1 opacity-0"}`,
8248
- style: requiredHintStyle,
8249
- "aria-live": "polite",
8249
+ className: `flex cursor-pointer items-center gap-2 rounded p-2 transition-colors ${isSelected ? isDarkMode ? "border-blue-500/50 bg-blue-500/20" : "border-blue-200 bg-blue-50" : `${inputBg} border-transparent hover:border-zinc-300`} border`,
8250
+ style: optionStyle,
8250
8251
  children: [
8251
- /* @__PURE__ */ jsx12("span", { className: "inline-block h-1.5 w-1.5 rounded-full bg-current opacity-75" }),
8252
- /* @__PURE__ */ jsx12("span", { children: t.requiredField })
8253
- ]
8254
- }
8255
- ) })
8256
- ] }),
8257
- isUserInput && (!interrupt.options || interrupt.options.length === 0) && /* @__PURE__ */ jsxs6("div", { children: [
8258
- /* @__PURE__ */ jsx12(
8259
- "input",
8260
- {
8261
- ref: inputRef,
8262
- type: "text",
8263
- value: answer,
8264
- onChange: (e) => handleAnswerChange(e.target.value),
8265
- onKeyDown: handleKeyDown,
8266
- onCompositionStart: () => setIsComposing(true),
8267
- onCompositionEnd: () => setIsComposing(false),
8268
- placeholder: interrupt.default ? `${t.defaultPrefix}: ${interrupt.default}` : t.enterResponse,
8269
- className: `w-full rounded-lg border px-3 py-2 text-sm ${inputBorder} ${inputBg} ${textPrimary} placeholder:${textSecondary} ${showRequiredError ? "focus:border-red-400 focus:ring-red-400/25" : "focus:border-blue-500 focus:ring-blue-500/40"} focus:outline-none focus:ring-2`,
8270
- style: inputValidationStyle
8271
- }
8272
- ),
8273
- /* @__PURE__ */ jsx12("div", { className: "mt-1 min-h-[18px]", children: /* @__PURE__ */ jsxs6(
8274
- "div",
8275
- {
8276
- className: `flex items-center gap-1 text-xs transition-all duration-150 ${showRequiredError ? "translate-y-0 opacity-100" : "-translate-y-1 opacity-0"}`,
8277
- style: requiredHintStyle,
8278
- "aria-live": "polite",
8279
- children: [
8280
- /* @__PURE__ */ jsx12("span", { className: "inline-block h-1.5 w-1.5 rounded-full bg-current opacity-75" }),
8281
- /* @__PURE__ */ jsx12("span", { children: t.requiredField })
8252
+ /* @__PURE__ */ jsx12(
8253
+ "input",
8254
+ {
8255
+ type: interrupt.multi_select ? "checkbox" : "radio",
8256
+ name: "hitl-options",
8257
+ checked: isSelected,
8258
+ onChange: () => handleOptionToggle(index),
8259
+ style: optionControlStyle
8260
+ }
8261
+ ),
8262
+ /* @__PURE__ */ jsx12("span", { className: `text-sm ${textPrimary} break-words ${isSelected ? "font-semibold" : "font-medium"}`, children: option })
8282
8263
  ]
8283
- }
8284
- ) })
8285
- ] }),
8264
+ },
8265
+ index
8266
+ );
8267
+ }) }),
8268
+ isUserInput && (!interrupt.options || interrupt.options.length === 0) && /* @__PURE__ */ jsx12("div", { children: /* @__PURE__ */ jsx12(
8269
+ "input",
8270
+ {
8271
+ ref: inputRef,
8272
+ type: "text",
8273
+ value: answer,
8274
+ onChange: (e) => handleAnswerChange(e.target.value),
8275
+ onKeyDown: handleKeyDown,
8276
+ onCompositionStart: () => setIsComposing(true),
8277
+ onCompositionEnd: () => setIsComposing(false),
8278
+ placeholder: interrupt.default ? `${t.defaultPrefix}: ${interrupt.default}` : t.enterResponse,
8279
+ className: `w-full rounded-lg border px-3 py-2 text-sm ${inputBorder} ${inputBg} ${textPrimary} placeholder:${textSecondary} ${showRequiredError ? "focus:border-red-400 focus:ring-red-400/25" : "focus:border-blue-500 focus:ring-blue-500/40"} focus:outline-none focus:ring-2`,
8280
+ style: inputValidationStyle
8281
+ }
8282
+ ) }),
8286
8283
  isApproval && /* @__PURE__ */ jsxs6(
8287
8284
  "label",
8288
8285
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yushaw/sanqian-chat",
3
- "version": "0.2.32",
3
+ "version": "0.2.33",
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",