@streamoid/chat-components 0.2.11 → 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 +82 -38
  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);
@@ -844,7 +847,7 @@ function DynamicForm(props) {
844
847
  variant: "destructive",
845
848
  size: "sm",
846
849
  onClick: () => handleApproval(field.id, false),
847
- 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",
848
851
  disabled: isLoading,
849
852
  children: [
850
853
  /* @__PURE__ */ jsx10(AlertCircle, { className: "w-3 h-3 mr-1.5" }),
@@ -879,42 +882,83 @@ function DynamicForm(props) {
879
882
  const feedbackPlaceholder = field.feedback_placeholder ?? "Describe what needs to be modified.";
880
883
  const approveLabel = field.approve_label ?? "Approve";
881
884
  const rejectLabel = field.reject_label ?? "Needs Modification";
885
+ const carouselIdx = carouselIndices[field.id] ?? 0;
886
+ const hasMultipleMedia = mediaUrls.length > 1;
882
887
  return /* @__PURE__ */ jsxs2("div", { className: "space-y-3", children: [
883
- mediaUrls.length > 0 && /* @__PURE__ */ jsx10("div", { className: "grid gap-2 sm:grid-cols-2", children: mediaUrls.map((url, idx) => {
884
- const mediaType = field.media_type && field.media_type !== "mixed" ? field.media_type : inferMediaTypeFromUrl(url);
885
- return /* @__PURE__ */ jsx10(
886
- "div",
887
- {
888
- className: "rounded-md border border-border overflow-hidden bg-muted/20",
889
- children: /* @__PURE__ */ jsx10(
890
- "button",
891
- {
892
- type: "button",
893
- onClick: () => setMediaPreview({ url, type: mediaType }),
894
- className: "w-full text-left cursor-zoom-in",
895
- title: "Click to view full media",
896
- children: mediaType === "video" ? /* @__PURE__ */ jsx10(
897
- "video",
898
- {
899
- src: url,
900
- controls: true,
901
- className: "w-full h-44 object-contain bg-black"
902
- }
903
- ) : /* @__PURE__ */ jsx10(
904
- "img",
905
- {
906
- src: url,
907
- alt: `Generated media ${idx + 1}`,
908
- className: "w-full h-44 object-contain bg-black",
909
- loading: "lazy"
910
- }
911
- )
912
- }
913
- )
914
- },
915
- `${field.id}-${idx}`
916
- );
917
- }) }),
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
+ ] }),
918
962
  /* @__PURE__ */ jsxs2("div", { className: "space-y-1", children: [
919
963
  /* @__PURE__ */ jsx10(Label2, { className: "text-xs font-medium", children: feedbackLabel }),
920
964
  /* @__PURE__ */ jsx10(
@@ -940,7 +984,7 @@ function DynamicForm(props) {
940
984
  variant: "destructive",
941
985
  size: "sm",
942
986
  onClick: () => handleMediaApprovalDecision(field, "needs_modification"),
943
- 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",
944
988
  disabled: isLoading,
945
989
  children: [
946
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.11",
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",