@streamoid/chat-components 0.2.10 → 0.2.12

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.
Files changed (2) hide show
  1. package/dist/index.js +83 -63
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -401,7 +401,9 @@ import {
401
401
  X,
402
402
  Plus,
403
403
  Pencil,
404
- Trash2
404
+ Trash2,
405
+ ChevronLeft,
406
+ ChevronRight
405
407
  } from "lucide-react";
406
408
  import { Fragment, jsx as jsx10, jsxs as jsxs2 } from "react/jsx-runtime";
407
409
  function DynamicForm(props) {
@@ -495,6 +497,7 @@ function DynamicForm(props) {
495
497
  const [newTodoInputs, setNewTodoInputs] = useState({});
496
498
  const [fileUploadState, setFileUploadState] = useState({});
497
499
  const [mediaPreview, setMediaPreview] = useState(null);
500
+ const [carouselIndices, setCarouselIndices] = useState({});
498
501
  const scrollRef = useRef(null);
499
502
  const [canScrollUp, setCanScrollUp] = useState(false);
500
503
  const [canScrollDown, setCanScrollDown] = useState(false);
@@ -722,31 +725,7 @@ function DynamicForm(props) {
722
725
  form_title: title,
723
726
  values
724
727
  };
725
- const valueSummaryParts = [];
726
- for (const [fieldId, val] of Object.entries(values)) {
727
- const field = fields.find((f) => f.id === fieldId);
728
- const fieldLabel = field?.label || fieldId;
729
- let displayVal;
730
- if (field?.type === "media_approval" && val && typeof val === "object") {
731
- const mediaVal = val;
732
- const decisionText = mediaVal.decision ?? "pending";
733
- const feedbackText = mediaVal.feedback?.trim() || "none";
734
- const mediaCount = Array.isArray(mediaVal.media_urls) ? mediaVal.media_urls.length : 0;
735
- displayVal = `decision=${decisionText}, feedback=${feedbackText}, media_count=${mediaCount}`;
736
- } else if (field?.options && typeof val === "string") {
737
- const opt = field.options.find((o) => o.id === val);
738
- displayVal = opt?.label || val;
739
- } else if (field?.options && Array.isArray(val)) {
740
- displayVal = val.map((v) => field.options.find((o) => o.id === v)?.label || v).join(", ");
741
- } else {
742
- displayVal = String(val ?? "");
743
- }
744
- valueSummaryParts.push(`${fieldLabel}: ${displayVal}`);
745
- }
746
- const valueSummary = valueSummaryParts.length > 0 ? `
747
- Submitted values:
748
- ${valueSummaryParts.join("\n")}` : "";
749
- const messageText = `User clicked "${userAction}" on form "${title}"${valueSummary}`;
728
+ const messageText = `User clicked "${userAction}" on form "${title}"`;
750
729
  try {
751
730
  await onSubmit(resumePayload, messageText);
752
731
  setSubmittedData({ user_action: userAction, values });
@@ -868,7 +847,7 @@ ${valueSummaryParts.join("\n")}` : "";
868
847
  variant: "destructive",
869
848
  size: "sm",
870
849
  onClick: () => handleApproval(field.id, false),
871
- className: "bg-destructive/10 text-destructive hover:bg-destructive/20 border-transparent shadow-none h-8 text-xs",
850
+ className: "bg-destructive/10 text-destructive hover:bg-destructive/20 dark:bg-red-500/15 dark:text-red-400 dark:hover:bg-red-500/25 border-transparent shadow-none h-8 text-xs",
872
851
  disabled: isLoading,
873
852
  children: [
874
853
  /* @__PURE__ */ jsx10(AlertCircle, { className: "w-3 h-3 mr-1.5" }),
@@ -903,42 +882,83 @@ ${valueSummaryParts.join("\n")}` : "";
903
882
  const feedbackPlaceholder = field.feedback_placeholder ?? "Describe what needs to be modified.";
904
883
  const approveLabel = field.approve_label ?? "Approve";
905
884
  const rejectLabel = field.reject_label ?? "Needs Modification";
885
+ const carouselIdx = carouselIndices[field.id] ?? 0;
886
+ const hasMultipleMedia = mediaUrls.length > 1;
906
887
  return /* @__PURE__ */ jsxs2("div", { className: "space-y-3", children: [
907
- mediaUrls.length > 0 && /* @__PURE__ */ jsx10("div", { className: "grid gap-2 sm:grid-cols-2", children: mediaUrls.map((url, idx) => {
908
- const mediaType = field.media_type && field.media_type !== "mixed" ? field.media_type : inferMediaTypeFromUrl(url);
909
- return /* @__PURE__ */ jsx10(
910
- "div",
911
- {
912
- className: "rounded-md border border-border overflow-hidden bg-muted/20",
913
- children: /* @__PURE__ */ jsx10(
914
- "button",
915
- {
916
- type: "button",
917
- onClick: () => setMediaPreview({ url, type: mediaType }),
918
- className: "w-full text-left cursor-zoom-in",
919
- title: "Click to view full media",
920
- children: mediaType === "video" ? /* @__PURE__ */ jsx10(
921
- "video",
922
- {
923
- src: url,
924
- controls: true,
925
- className: "w-full h-44 object-contain bg-black"
926
- }
927
- ) : /* @__PURE__ */ jsx10(
928
- "img",
929
- {
930
- src: url,
931
- alt: `Generated media ${idx + 1}`,
932
- className: "w-full h-44 object-contain bg-black",
933
- loading: "lazy"
934
- }
935
- )
936
- }
937
- )
938
- },
939
- `${field.id}-${idx}`
940
- );
941
- }) }),
888
+ mediaUrls.length > 0 && /* @__PURE__ */ jsxs2("div", { className: "relative rounded-md border border-border overflow-hidden bg-muted/20", children: [
889
+ (() => {
890
+ const url = mediaUrls[carouselIdx] ?? mediaUrls[0];
891
+ const mediaType = field.media_type && field.media_type !== "mixed" ? field.media_type : inferMediaTypeFromUrl(url);
892
+ return /* @__PURE__ */ jsx10(
893
+ "button",
894
+ {
895
+ type: "button",
896
+ onClick: () => setMediaPreview({ url, type: mediaType }),
897
+ className: "w-full text-left cursor-zoom-in",
898
+ title: "Click to view full media",
899
+ children: mediaType === "video" ? /* @__PURE__ */ jsx10(
900
+ "video",
901
+ {
902
+ src: url,
903
+ controls: true,
904
+ className: "w-full h-52 object-contain bg-black"
905
+ }
906
+ ) : /* @__PURE__ */ jsx10(
907
+ "img",
908
+ {
909
+ src: url,
910
+ alt: `Generated media ${carouselIdx + 1}`,
911
+ className: "w-full h-52 object-contain bg-black",
912
+ loading: "lazy"
913
+ }
914
+ )
915
+ }
916
+ );
917
+ })(),
918
+ hasMultipleMedia && /* @__PURE__ */ jsxs2(Fragment, { children: [
919
+ /* @__PURE__ */ jsx10(
920
+ "button",
921
+ {
922
+ type: "button",
923
+ onClick: () => setCarouselIndices((prev) => ({
924
+ ...prev,
925
+ [field.id]: (carouselIdx - 1 + mediaUrls.length) % mediaUrls.length
926
+ })),
927
+ className: "absolute left-1.5 top-1/2 -translate-y-1/2 w-7 h-7 rounded-full bg-black/50 hover:bg-black/70 text-white flex items-center justify-center transition-colors backdrop-blur-sm",
928
+ title: "Previous",
929
+ children: /* @__PURE__ */ jsx10(ChevronLeft, { className: "w-4 h-4" })
930
+ }
931
+ ),
932
+ /* @__PURE__ */ jsx10(
933
+ "button",
934
+ {
935
+ type: "button",
936
+ onClick: () => setCarouselIndices((prev) => ({
937
+ ...prev,
938
+ [field.id]: (carouselIdx + 1) % mediaUrls.length
939
+ })),
940
+ className: "absolute right-1.5 top-1/2 -translate-y-1/2 w-7 h-7 rounded-full bg-black/50 hover:bg-black/70 text-white flex items-center justify-center transition-colors backdrop-blur-sm",
941
+ title: "Next",
942
+ children: /* @__PURE__ */ jsx10(ChevronRight, { className: "w-4 h-4" })
943
+ }
944
+ ),
945
+ /* @__PURE__ */ jsx10("div", { className: "absolute bottom-2 left-1/2 -translate-x-1/2 flex items-center gap-1.5 px-2 py-1 rounded-full bg-black/50 backdrop-blur-sm", children: mediaUrls.map((_, idx) => /* @__PURE__ */ jsx10(
946
+ "button",
947
+ {
948
+ type: "button",
949
+ onClick: () => setCarouselIndices((prev) => ({ ...prev, [field.id]: idx })),
950
+ className: `w-1.5 h-1.5 rounded-full transition-all ${idx === carouselIdx ? "bg-white w-3" : "bg-white/50 hover:bg-white/75"}`,
951
+ title: `Go to media ${idx + 1}`
952
+ },
953
+ idx
954
+ )) }),
955
+ /* @__PURE__ */ jsxs2("div", { className: "absolute top-2 right-2 px-2 py-0.5 rounded-full bg-black/50 backdrop-blur-sm text-white text-[10px] font-medium", children: [
956
+ carouselIdx + 1,
957
+ " / ",
958
+ mediaUrls.length
959
+ ] })
960
+ ] })
961
+ ] }),
942
962
  /* @__PURE__ */ jsxs2("div", { className: "space-y-1", children: [
943
963
  /* @__PURE__ */ jsx10(Label2, { className: "text-xs font-medium", children: feedbackLabel }),
944
964
  /* @__PURE__ */ jsx10(
@@ -964,7 +984,7 @@ ${valueSummaryParts.join("\n")}` : "";
964
984
  variant: "destructive",
965
985
  size: "sm",
966
986
  onClick: () => handleMediaApprovalDecision(field, "needs_modification"),
967
- className: "bg-destructive/10 text-destructive hover:bg-destructive/20 border-transparent shadow-none h-8 text-xs",
987
+ className: "bg-destructive/10 text-destructive hover:bg-destructive/20 dark:bg-red-500/15 dark:text-red-400 dark:hover:bg-red-500/25 border-transparent shadow-none h-8 text-xs",
968
988
  disabled: isLoading,
969
989
  children: [
970
990
  /* @__PURE__ */ jsx10(AlertCircle, { className: "w-3 h-3 mr-1.5" }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamoid/chat-components",
3
- "version": "0.2.10",
3
+ "version": "0.2.12",
4
4
  "description": "Shared chat UI components for the Streamoid chat host — DynamicForm and other cross-service components",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",