react-optimistic-chat 2.0.0 → 2.2.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 CHANGED
@@ -61,7 +61,7 @@ module.exports = __toCommonJS(index_exports);
61
61
 
62
62
  // src/components/indicators/LoadingSpinner.tsx
63
63
  var import_jsx_runtime = require("react/jsx-runtime");
64
- function LoadingSpinner({ size }) {
64
+ function LoadingSpinner({ size = "md" }) {
65
65
  const sizeMap = {
66
66
  xs: 24,
67
67
  sm: 32,
@@ -146,12 +146,12 @@ function ChatMessage({
146
146
  loadingRenderer
147
147
  }) {
148
148
  const isAI = role === "AI";
149
- const justify = position === "auto" ? isAI ? "justify-start" : "justify-end" : position === "left" ? "justify-start" : "justify-end";
149
+ const justify = position === "auto" ? isAI ? "left" : "right" : position;
150
150
  const defaultAIIcon = /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
151
151
  "svg",
152
152
  {
153
153
  xmlns: "http://www.w3.org/2000/svg",
154
- className: `${aiIconColor}`,
154
+ className: aiIconColor,
155
155
  width: "24",
156
156
  height: "24",
157
157
  viewBox: "0 0 24 24",
@@ -170,30 +170,41 @@ function ChatMessage({
170
170
  ]
171
171
  }
172
172
  );
173
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `flex mb-4 items-start ${justify} ${wrapperClassName}`, children: [
174
- isAI && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
175
- "div",
176
- {
177
- className: `
178
- mr-2 bg-gray-100 rounded-full p-2 border-2 border-black
173
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
174
+ "div",
175
+ {
176
+ className: `
177
+ roc-chat-message
178
+ roc-chat-message--${justify}
179
+ ${wrapperClassName}
180
+ `,
181
+ children: [
182
+ isAI && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
183
+ "div",
184
+ {
185
+ className: `
186
+ roc-chat-message__icon
179
187
  ${aiIconWrapperClassName}
180
188
  `,
181
- children: icon || defaultAIIcon
182
- }
183
- ),
184
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
185
- "div",
186
- {
187
- className: `
188
- py-3 px-3 max-h-96 overflow-y-auto w-fit max-w-[calc(100%-3rem)]
189
- whitespace-pre-wrap break-words text-sm
190
- ${isAI ? `bg-gray-100 border-gray-200 rounded-b-xl rounded-t-xl ${aiBubbleClassName}` : `bg-white border border-gray-200 rounded-b-xl rounded-tl-xl ${userBubbleClassName}`}
189
+ children: icon || defaultAIIcon
190
+ }
191
+ ),
192
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
193
+ "div",
194
+ {
195
+ className: `
196
+ roc-chat-message__bubble
197
+ ${isAI ? "roc-chat-message__bubble--ai" : "roc-chat-message__bubble--user"}
198
+ ${isAI ? aiBubbleClassName : userBubbleClassName}
191
199
  ${bubbleClassName}
192
200
  `,
193
- children: isLoading ? loadingRenderer != null ? loadingRenderer : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LoadingSpinner, { size: "xs" }) : content
194
- }
195
- )
196
- ] }, id);
201
+ children: isLoading ? loadingRenderer != null ? loadingRenderer : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LoadingSpinner, { size: "xs" }) : content
202
+ }
203
+ )
204
+ ]
205
+ },
206
+ id
207
+ );
197
208
  }
198
209
 
199
210
  // src/components/ChatList.tsx
@@ -207,7 +218,7 @@ function ChatList({
207
218
  loadingRenderer
208
219
  }) {
209
220
  const mappedMessages = messageMapper ? messages.map((msg) => __spreadValues(__spreadValues({}, msg), messageMapper(msg))) : messages;
210
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: `flex flex-col ${className}`, children: mappedMessages.map((msg) => {
221
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: `roc-chat-list ${className != null ? className : ""}`, children: mappedMessages.map((msg) => {
211
222
  if (messageRenderer) {
212
223
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react2.default.Fragment, { children: messageRenderer(msg) }, msg.id);
213
224
  }
@@ -385,134 +396,95 @@ function ChatInput({
385
396
  return null;
386
397
  };
387
398
  const activeLayer = getActivityLayer();
388
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
389
- "div",
390
- {
391
- className: `
392
- flex border border-gray-300 p-2 rounded-3xl
393
- ${className}
394
- `,
395
- children: [
396
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
397
- "textarea",
398
- {
399
- ref: textareaRef,
400
- value: text,
401
- onChange: handleChange,
402
- placeholder,
403
- rows: 1,
404
- onKeyDown: handleKeyDown,
405
- className: `
406
- w-full px-3 py-2
407
- resize-none border-none
408
- text-sm focus:outline-none
409
- overflow-hidden chatinput-scroll
410
- ${inputClassName}
411
- `
412
- }
413
- ),
414
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
415
- "button",
416
- {
417
- type: "button",
418
- disabled: isSending,
419
- onClick: activeLayer === "mic" || activeLayer === "recording" ? handleRecord : handleSend,
420
- className: "relative w-10 h-10 ml-2 mt-auto flex-shrink-0",
421
- children: [
422
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
423
- "div",
424
- {
425
- className: `
426
- absolute inset-0 flex items-center justify-center rounded-3xl
427
- transition-opacity duration-150
428
- ${activeLayer === "mic" ? "opacity-100" : "opacity-0"}
429
- bg-gray-100 text-gray-700
430
- ${(micButton == null ? void 0 : micButton.className) || ""}
431
- `,
432
- children: (micButton == null ? void 0 : micButton.icon) || /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { width: "24", height: "24", stroke: "currentColor", fill: "none", strokeWidth: "2", children: [
433
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 19v3" }),
434
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
435
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { x: "9", y: "2", width: "6", height: "13", rx: "3" })
436
- ] })
437
- }
438
- ),
439
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
440
- "div",
441
- {
442
- className: `
443
- absolute inset-0 flex items-center justify-center rounded-3xl
444
- transition-opacity duration-150
445
- ${activeLayer === "recording" ? "opacity-100" : "opacity-0"}
446
- bg-red-600 text-white
447
- ${(recordingButton == null ? void 0 : recordingButton.className) || ""}
448
- `,
449
- children: (recordingButton == null ? void 0 : recordingButton.icon) || /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { width: "24", height: "24", stroke: "currentColor", fill: "none", strokeWidth: "2", children: [
450
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 19v3" }),
451
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
452
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { x: "9", y: "2", width: "6", height: "13", rx: "3" })
453
- ] })
454
- }
455
- ),
456
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
457
- "div",
399
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `roc-chat-input ${className}`, children: [
400
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
401
+ "textarea",
402
+ {
403
+ ref: textareaRef,
404
+ value: text,
405
+ onChange: handleChange,
406
+ placeholder,
407
+ rows: 1,
408
+ onKeyDown: handleKeyDown,
409
+ className: `roc-chat-input__textarea ${inputClassName}`
410
+ }
411
+ ),
412
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
413
+ "button",
414
+ {
415
+ type: "button",
416
+ disabled: isSending,
417
+ onClick: activeLayer === "mic" || activeLayer === "recording" ? handleRecord : handleSend,
418
+ className: "roc-chat-input__button",
419
+ children: [
420
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
421
+ "div",
422
+ {
423
+ className: `roc-chat-input__layer roc-chat-input__layer--mic ${activeLayer === "mic" ? "is-active" : ""} ${(micButton == null ? void 0 : micButton.className) || ""}`,
424
+ children: (micButton == null ? void 0 : micButton.icon) || /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { width: "24", height: "24", stroke: "currentColor", fill: "none", strokeWidth: "2", children: [
425
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 19v3" }),
426
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
427
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { x: "9", y: "2", width: "6", height: "13", rx: "3" })
428
+ ] })
429
+ }
430
+ ),
431
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
432
+ "div",
433
+ {
434
+ className: `roc-chat-input__layer roc-chat-input__layer--recording ${activeLayer === "recording" ? "is-active" : ""} ${(recordingButton == null ? void 0 : recordingButton.className) || ""}`,
435
+ children: (recordingButton == null ? void 0 : recordingButton.icon) || /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { width: "24", height: "24", stroke: "currentColor", fill: "none", strokeWidth: "2", children: [
436
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 19v3" }),
437
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
438
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { x: "9", y: "2", width: "6", height: "13", rx: "3" })
439
+ ] })
440
+ }
441
+ ),
442
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
443
+ "div",
444
+ {
445
+ className: `roc-chat-input__layer roc-chat-input__layer--send ${activeLayer === "send" ? "is-active" : ""} ${(sendButton == null ? void 0 : sendButton.className) || ""}`,
446
+ children: (sendButton == null ? void 0 : sendButton.icon) || /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
447
+ "svg",
458
448
  {
459
- className: `
460
- absolute inset-0 flex items-center justify-center rounded-3xl
461
- transition-opacity duration-150
462
- ${activeLayer === "send" ? "opacity-100" : "opacity-0"}
463
- bg-black text-white
464
- ${(sendButton == null ? void 0 : sendButton.className) || ""}
465
- `,
466
- children: (sendButton == null ? void 0 : sendButton.icon) || /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
467
- "svg",
468
- {
469
- width: "20",
470
- height: "20",
471
- viewBox: "0 0 22 24",
472
- fill: "none",
473
- stroke: "currentColor",
474
- "stroke-width": "2",
475
- children: [
476
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M3.714 3.048a.498.498 0 0 0-.683.627l2.843 7.627a2 2 0 0 1 0 1.396l-2.842 7.627a.498.498 0 0 0 .682.627l18-8.5a.5.5 0 0 0 0-.904z" }),
477
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M6 12h16" })
478
- ]
479
- }
480
- )
449
+ width: "20",
450
+ height: "20",
451
+ viewBox: "0 0 22 24",
452
+ fill: "none",
453
+ stroke: "currentColor",
454
+ "stroke-width": "2",
455
+ children: [
456
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M3.714 3.048a.498.498 0 0 0-.683.627l2.843 7.627a2 2 0 0 1 0 1.396l-2.842 7.627a.498.498 0 0 0 .682.627l18-8.5a.5.5 0 0 0 0-.904z" }),
457
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M6 12h16" })
458
+ ]
481
459
  }
482
- ),
483
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
484
- "div",
460
+ )
461
+ }
462
+ ),
463
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
464
+ "div",
465
+ {
466
+ className: `roc-chat-input__layer roc-chat-input__layer--sending ${activeLayer === "sending" ? "is-active" : ""} ${(sendingButton == null ? void 0 : sendingButton.className) || ""}`,
467
+ children: (sendingButton == null ? void 0 : sendingButton.icon) || /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
468
+ "svg",
485
469
  {
486
- className: `
487
- absolute inset-0 flex items-center justify-center rounded-3xl
488
- transition-opacity duration-150
489
- ${activeLayer === "sending" ? "opacity-100" : "opacity-0"}
490
- bg-gray-400 text-white
491
- ${(sendingButton == null ? void 0 : sendingButton.className) || ""}
492
- `,
493
- children: (sendingButton == null ? void 0 : sendingButton.icon) || /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
494
- "svg",
495
- {
496
- width: "20",
497
- height: "20",
498
- viewBox: "0 0 22 24",
499
- fill: "none",
500
- stroke: "currentColor",
501
- "stroke-width": "2",
502
- children: [
503
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M3.714 3.048a.498.498 0 0 0-.683.627l2.843 7.627a2 2 0 0 1 0 1.396l-2.842 7.627a.498.498 0 0 0 .682.627l18-8.5a.5.5 0 0 0 0-.904z" }),
504
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M6 12h16" })
505
- ]
506
- }
507
- )
470
+ width: "20",
471
+ height: "20",
472
+ viewBox: "0 0 22 24",
473
+ fill: "none",
474
+ stroke: "currentColor",
475
+ "stroke-width": "2",
476
+ children: [
477
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M3.714 3.048a.498.498 0 0 0-.683.627l2.843 7.627a2 2 0 0 1 0 1.396l-2.842 7.627a.498.498 0 0 0 .682.627l18-8.5a.5.5 0 0 0 0-.904z" }),
478
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M6 12h16" })
479
+ ]
508
480
  }
509
481
  )
510
- ]
511
- }
512
- )
513
- ]
514
- }
515
- );
482
+ }
483
+ )
484
+ ]
485
+ }
486
+ )
487
+ ] });
516
488
  }
517
489
 
518
490
  // src/components/ChatContainer.tsx
@@ -575,67 +547,59 @@ function ChatContainer(props) {
575
547
  });
576
548
  await onSend(value);
577
549
  };
578
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
579
- "div",
580
- {
581
- className: `
582
- flex flex-col ${className || ""}
583
- `,
584
- children: [
585
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
586
- "div",
587
- {
588
- ref: scrollRef,
589
- className: `flex-1 overflow-y-auto chatContainer-scroll p-2`,
590
- children: [
591
- hasNextPage && isFetchingNextPage && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex justify-center py-2", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(LoadingSpinner, { size: "sm" }) }),
592
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
593
- ChatList,
594
- __spreadValues(__spreadValues(__spreadValues({
595
- messages: mappedMessages
596
- }, messageRenderer && { messageRenderer }), loadingRenderer && { loadingRenderer }), listClassName && { className: listClassName })
597
- )
598
- ]
599
- }
600
- ),
601
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex-shrink-0 relative", children: [
602
- !isAtBottom && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
603
- "button",
604
- {
605
- onClick: scrollToBottom,
606
- className: "\r\n absolute bottom-20 left-1/2 -translate-x-1/2\r\n w-10 h-10 rounded-full bg-white font-bold\r\n flex items-center justify-center\r\n border-gray-200 border-[1px]\r\n ",
607
- "aria-label": "scroll to bottom",
608
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
609
- "svg",
610
- {
611
- xmlns: "http://www.w3.org/2000/svg",
612
- width: "24",
613
- height: "24",
614
- viewBox: "0 0 24 24",
615
- fill: "none",
616
- stroke: "currentColor",
617
- strokeWidth: "2",
618
- strokeLinecap: "round",
619
- strokeLinejoin: "round",
620
- children: [
621
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M12 5v14" }),
622
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m19 12-7 7-7-7" })
623
- ]
624
- }
625
- )
626
- }
627
- ),
550
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `roc-chat-container ${className || ""}`, children: [
551
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
552
+ "div",
553
+ {
554
+ ref: scrollRef,
555
+ className: "roc-chat-container__list",
556
+ children: [
557
+ hasNextPage && isFetchingNextPage && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "roc-chat-container__loading", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(LoadingSpinner, { size: "sm" }) }),
628
558
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
629
- ChatInput,
559
+ ChatList,
630
560
  __spreadValues(__spreadValues(__spreadValues({
631
- onSend: handleSend,
632
- isSending
633
- }, disableVoice && { disableVoice }), placeholder && { placeholder }), inputClassName && { className: inputClassName })
561
+ messages: mappedMessages
562
+ }, messageRenderer && { messageRenderer }), loadingRenderer && { loadingRenderer }), listClassName && { className: listClassName })
634
563
  )
635
- ] })
636
- ]
637
- }
638
- ) });
564
+ ]
565
+ }
566
+ ),
567
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "roc-chat-container__input", children: [
568
+ !isAtBottom && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
569
+ "button",
570
+ {
571
+ className: "roc-chat-container__scroll-button",
572
+ onClick: scrollToBottom,
573
+ "aria-label": "scroll to bottom",
574
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
575
+ "svg",
576
+ {
577
+ xmlns: "http://www.w3.org/2000/svg",
578
+ width: "24",
579
+ height: "24",
580
+ viewBox: "0 0 24 24",
581
+ fill: "none",
582
+ stroke: "currentColor",
583
+ strokeWidth: "2",
584
+ strokeLinecap: "round",
585
+ strokeLinejoin: "round",
586
+ children: [
587
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M12 5v14" }),
588
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m19 12-7 7-7-7" })
589
+ ]
590
+ }
591
+ )
592
+ }
593
+ ),
594
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
595
+ ChatInput,
596
+ __spreadValues(__spreadValues(__spreadValues({
597
+ onSend: handleSend,
598
+ isSending
599
+ }, disableVoice && { disableVoice }), placeholder && { placeholder }), inputClassName && { className: inputClassName })
600
+ )
601
+ ] })
602
+ ] }) });
639
603
  }
640
604
 
641
605
  // src/hooks/useChat.ts