@fluid-app/portal-sdk 0.1.364 → 0.1.366
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/{AddressAutocompleteInput-cy8R9p6W.mjs → AddressAutocompleteInput-9gpjXB6B.mjs} +2 -2
- package/dist/{AddressAutocompleteInput-cy8R9p6W.mjs.map → AddressAutocompleteInput-9gpjXB6B.mjs.map} +1 -1
- package/dist/{AddressAutocompleteInput-BW0MZsjD.cjs → AddressAutocompleteInput-CFe3IfOj.cjs} +2 -2
- package/dist/{AddressAutocompleteInput-BW0MZsjD.cjs.map → AddressAutocompleteInput-CFe3IfOj.cjs.map} +1 -1
- package/dist/{EmbedWidget-BMy0C8ik.cjs → EmbedWidget-CiqR6HSo.cjs} +36 -6
- package/dist/EmbedWidget-CiqR6HSo.cjs.map +1 -0
- package/dist/{EmbedWidget-V-pGzMRC.mjs → EmbedWidget-ZPG0lFgF.mjs} +36 -6
- package/dist/EmbedWidget-ZPG0lFgF.mjs.map +1 -0
- package/dist/{FluidProvider-JmlsI08v.cjs → FluidProvider-2gVDT1i4.cjs} +11 -11
- package/dist/{FluidProvider-JmlsI08v.cjs.map → FluidProvider-2gVDT1i4.cjs.map} +1 -1
- package/dist/{FluidProvider-Cwnzfzi6.mjs → FluidProvider-2rT0X7u1.mjs} +11 -11
- package/dist/{FluidProvider-Cwnzfzi6.mjs.map → FluidProvider-2rT0X7u1.mjs.map} +1 -1
- package/dist/{ImageWidget-B6DESmDt.mjs → ImageWidget-B2FEHT-v.mjs} +2 -3
- package/dist/ImageWidget-B2FEHT-v.mjs.map +1 -0
- package/dist/{ImageWidget-Cz1W-CaS.cjs → ImageWidget-r9sPbyeC.cjs} +2 -3
- package/dist/ImageWidget-r9sPbyeC.cjs.map +1 -0
- package/dist/{ListWidget-CRsc53kj.mjs → ListWidget-C1_Fd58S.mjs} +5 -4
- package/dist/ListWidget-C1_Fd58S.mjs.map +1 -0
- package/dist/{ListWidget-IxrLNslF.cjs → ListWidget-D_C0p7HR.cjs} +5 -4
- package/dist/ListWidget-D_C0p7HR.cjs.map +1 -0
- package/dist/{ListWidget-BOH7TJJj.cjs → ListWidget-hz_xueC7.cjs} +1 -1
- package/dist/{MessagingScreen-BPJLhWGi.mjs → MessagingScreen-BR5ISUoK.mjs} +8 -7
- package/dist/{MessagingScreen-CgIlbc7d.cjs → MessagingScreen-FObvFAzr.cjs} +7 -7
- package/dist/{MessagingScreen-BJr7zF2A.mjs → MessagingScreen-UptArERP.mjs} +2 -2
- package/dist/{MessagingScreen-BJr7zF2A.mjs.map → MessagingScreen-UptArERP.mjs.map} +1 -1
- package/dist/{MessagingScreen-DVDFx_8s.cjs → MessagingScreen-ycXsOE9D.cjs} +2 -2
- package/dist/{MessagingScreen-DVDFx_8s.cjs.map → MessagingScreen-ycXsOE9D.cjs.map} +1 -1
- package/dist/{NestedWidget-BPTo7RQZ.mjs → NestedWidget-9eJaAdz9.mjs} +3 -3
- package/dist/{NestedWidget-BPTo7RQZ.mjs.map → NestedWidget-9eJaAdz9.mjs.map} +1 -1
- package/dist/{NestedWidget-Bg6vB_A6.cjs → NestedWidget-COMzekmy.cjs} +3 -3
- package/dist/{NestedWidget-Bg6vB_A6.cjs.map → NestedWidget-COMzekmy.cjs.map} +1 -1
- package/dist/{NestedWidget-Bep9VZwW.cjs → NestedWidget-DzBrds9R.cjs} +1 -1
- package/dist/{OrdersScreen-BvI394f1.cjs → OrdersScreen-B0Sg_NO1.cjs} +7 -7
- package/dist/{OrdersScreen-Ch9ia2Ga.mjs → OrdersScreen-BOFYWEZS.mjs} +2 -2
- package/dist/{OrdersScreen-Ch9ia2Ga.mjs.map → OrdersScreen-BOFYWEZS.mjs.map} +1 -1
- package/dist/{OrdersScreen-BC95_oBa.cjs → OrdersScreen-C__4uFwk.cjs} +2 -2
- package/dist/{OrdersScreen-BC95_oBa.cjs.map → OrdersScreen-C__4uFwk.cjs.map} +1 -1
- package/dist/{OrdersScreen-ClfjwlXi.mjs → OrdersScreen-Dm6J3112.mjs} +9 -7
- package/dist/{ProfileScreen-Bzfqc83K.cjs → ProfileScreen-5OPs7V99.cjs} +3 -3
- package/dist/{ProfileScreen-Bzfqc83K.cjs.map → ProfileScreen-5OPs7V99.cjs.map} +1 -1
- package/dist/{ProfileScreen-G3djGmU2.cjs → ProfileScreen-B7t-OVVJ.cjs} +8 -8
- package/dist/{ProfileScreen-DpUI78i1.mjs → ProfileScreen-COmd8OlO.mjs} +9 -8
- package/dist/{ProfileScreen-CEylhJU6.mjs → ProfileScreen-DUUPJzb4.mjs} +3 -3
- package/dist/{ProfileScreen-CEylhJU6.mjs.map → ProfileScreen-DUUPJzb4.mjs.map} +1 -1
- package/dist/{ShareablesScreen-CaVbAkb1.mjs → ShareablesScreen-BUg9Xl7e.mjs} +2 -0
- package/dist/{ShopScreen-CtglELsz.mjs → ShopScreen-BhrrBjS4.mjs} +8 -12
- package/dist/ShopScreen-BhrrBjS4.mjs.map +1 -0
- package/dist/{ShopScreen-g_umkXKo.cjs → ShopScreen-BqlB_GOB.cjs} +7 -7
- package/dist/{ShopScreen-B1HjIt1A.mjs → ShopScreen-CCYT4-tU.mjs} +9 -7
- package/dist/{ShopScreen-CPeoDfhv.cjs → ShopScreen-Dyl1Ne8n.cjs} +8 -12
- package/dist/ShopScreen-Dyl1Ne8n.cjs.map +1 -0
- package/dist/{SubscriptionsScreen-mAXtV4Oy.cjs → SubscriptionsScreen-05KrYqLb.cjs} +3 -3
- package/dist/{SubscriptionsScreen-mAXtV4Oy.cjs.map → SubscriptionsScreen-05KrYqLb.cjs.map} +1 -1
- package/dist/{SubscriptionsScreen-C6iOeMz4.mjs → SubscriptionsScreen-Dlw3cT_9.mjs} +10 -8
- package/dist/{SubscriptionsScreen-BQZQNzIu.cjs → SubscriptionsScreen-Dpg4UCwZ.cjs} +8 -8
- package/dist/{SubscriptionsScreen-DyZAbOFn.mjs → SubscriptionsScreen-jEcWsorf.mjs} +3 -3
- package/dist/{SubscriptionsScreen-DyZAbOFn.mjs.map → SubscriptionsScreen-jEcWsorf.mjs.map} +1 -1
- package/dist/{VideoWidget-DEG652tg.mjs → VideoWidget-CCTaBwub.mjs} +3 -3
- package/dist/{VideoWidget-DEG652tg.mjs.map → VideoWidget-CCTaBwub.mjs.map} +1 -1
- package/dist/{VideoWidget-CTByie5N.cjs → VideoWidget-rnVfjbuI.cjs} +3 -3
- package/dist/{VideoWidget-CTByie5N.cjs.map → VideoWidget-rnVfjbuI.cjs.map} +1 -1
- package/dist/index.cjs +22 -22
- package/dist/index.d.cts +9 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +9 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +24 -24
- package/dist/registries-BWdQbKof.cjs.map +1 -1
- package/dist/registries-DT36l-bR.mjs.map +1 -1
- package/package.json +17 -17
- package/dist/EmbedWidget-BMy0C8ik.cjs.map +0 -1
- package/dist/EmbedWidget-V-pGzMRC.mjs.map +0 -1
- package/dist/ImageWidget-B6DESmDt.mjs.map +0 -1
- package/dist/ImageWidget-Cz1W-CaS.cjs.map +0 -1
- package/dist/ListWidget-CRsc53kj.mjs.map +0 -1
- package/dist/ListWidget-IxrLNslF.cjs.map +0 -1
- package/dist/ShopScreen-CPeoDfhv.cjs.map +0 -1
- package/dist/ShopScreen-CtglELsz.mjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"EmbedWidget-V-pGzMRC.mjs","names":[],"sources":["../../widgets/src/contexts/RepUserContext.tsx","../../widgets/src/widgets/EmbedWidget.tsx"],"sourcesContent":["import React, {\n createContext,\n useContext,\n useMemo,\n type ReactNode,\n} from \"react\";\n\nexport interface RepUser {\n name: string | null;\n email: string | null;\n imageUrl: string | null;\n publicId?: string;\n}\n\nconst RepUserContext = createContext<RepUser | null>(null);\n\nexport interface RepUserProviderProps {\n user: RepUser;\n children: ReactNode;\n}\n\nexport function RepUserProvider({\n user,\n children,\n}: RepUserProviderProps): React.JSX.Element {\n const value = useMemo(() => user, [user]);\n return (\n <RepUserContext.Provider value={value}>{children}</RepUserContext.Provider>\n );\n}\n\nexport function useRepUser(): RepUser | null {\n return useContext(RepUserContext);\n}\n","import {\n Bell,\n BookmarkIcon,\n BookOpen,\n Calendar,\n ExternalLink,\n Gift,\n Globe,\n GraduationCap,\n Heart,\n Maximize2,\n RotateCw,\n ShoppingBag,\n Sparkles,\n Star,\n Trophy,\n User,\n Video,\n X,\n Zap,\n type LucideIcon,\n} from \"lucide-react\";\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ComponentProps,\n type RefObject,\n} from \"react\";\nimport type React from \"react\";\nimport { createPortal } from \"react-dom\";\nimport {\n getBorderRadiusField,\n getHeightField,\n type WidgetPropertySchema,\n} from \"@fluid-app/portal-core/registries\";\nimport type {\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n ShareableItem,\n} from \"@fluid-app/portal-core/types\";\nimport {\n getBorderWidthField,\n getBorderColorField,\n getColorField,\n borderWidthClasses,\n borderColorClasses,\n} from \"../core/fields\";\nimport { useRepUser } from \"../contexts/RepUserContext\";\n\ntype EmbedWidgetMessage = {\n type: \"OPEN_FULL_SCREEN_WEBVIEW\";\n url: string;\n};\n\ntype DisplayMode = \"inline\" | \"cover\";\n\ntype EmbedUrlState = {\n normalizedUrl: string;\n isValidUrl: boolean;\n iframeSrc: string;\n};\n\nfunction isValidHttpUrl(urlString: string): boolean {\n try {\n const parsed = new URL(urlString);\n return parsed.protocol === \"https:\" || parsed.protocol === \"http:\";\n } catch {\n return false;\n }\n}\n\nfunction useEmbedUrl(url: string, publicId: string | undefined): EmbedUrlState {\n return useMemo(() => {\n const normalizedUrl =\n url && (url.startsWith(\"http://\") || url.startsWith(\"https://\"))\n ? url\n : url\n ? `https://${url}`\n : \"\";\n\n let isValidUrl = false;\n if (normalizedUrl) {\n try {\n const parsed = new URL(normalizedUrl);\n isValidUrl =\n (parsed.protocol === \"http:\" || parsed.protocol === \"https:\") &&\n (parsed.hostname.includes(\".\") || parsed.hostname === \"localhost\");\n } catch {\n // invalid URL\n }\n }\n\n if (!isValidUrl || !publicId) {\n return { normalizedUrl, isValidUrl, iframeSrc: normalizedUrl };\n }\n\n const urlObj = new URL(normalizedUrl);\n urlObj.searchParams.set(\"public_id\", publicId);\n return { normalizedUrl, isValidUrl, iframeSrc: urlObj.toString() };\n }, [url, publicId]);\n}\n\ntype UseEmbedPostMessageBridgeProps = {\n iframeRef: RefObject<HTMLIFrameElement | null>;\n normalizedUrl: string;\n isValidUrl: boolean;\n editMode: boolean;\n};\n\nfunction useEmbedPostMessageBridge({\n iframeRef,\n normalizedUrl,\n isValidUrl,\n editMode,\n}: UseEmbedPostMessageBridgeProps): void {\n useEffect(() => {\n if (!isValidUrl || editMode) return;\n\n const expectedOrigin = new URL(normalizedUrl).origin;\n\n function handleMessage(event: MessageEvent) {\n if (event.origin !== expectedOrigin) return;\n if (event.source !== iframeRef.current?.contentWindow) return;\n\n let data: unknown;\n if (typeof event.data === \"string\") {\n try {\n data = JSON.parse(event.data);\n } catch {\n return;\n }\n } else {\n data = event.data;\n }\n\n if (\n typeof data === \"object\" &&\n data !== null &&\n \"type\" in data &&\n (data as EmbedWidgetMessage).type === \"OPEN_FULL_SCREEN_WEBVIEW\"\n ) {\n const messageUrl = (data as EmbedWidgetMessage).url;\n if (messageUrl && isValidHttpUrl(messageUrl)) {\n window.open(messageUrl, \"_blank\", \"noopener,noreferrer\");\n }\n }\n }\n\n window.addEventListener(\"message\", handleMessage);\n return () => window.removeEventListener(\"message\", handleMessage);\n }, [iframeRef, normalizedUrl, isValidUrl, editMode]);\n}\n\nfunction useModalBodyScrollLock(isOpen: boolean): void {\n useEffect(() => {\n if (!isOpen) return;\n const previousOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = previousOverflow;\n };\n }, [isOpen]);\n}\n\nfunction useModalEscapeClose(isOpen: boolean, onClose: () => void): void {\n useEffect(() => {\n if (!isOpen) return;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") onClose();\n };\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [isOpen, onClose]);\n}\n\nfunction useDialogFocusRestore(dialogRef: RefObject<HTMLElement | null>): void {\n useEffect(() => {\n const previouslyFocused =\n document.activeElement instanceof HTMLElement\n ? document.activeElement\n : null;\n dialogRef.current?.focus();\n return () => {\n previouslyFocused?.focus();\n };\n }, [dialogRef]);\n}\n\n// ---------- header icon registry ----------\n\nconst HEADER_ICON_MAP: Record<string, LucideIcon> = {\n GraduationCap,\n Video,\n BookOpen,\n Globe,\n User,\n Star,\n Heart,\n Trophy,\n Sparkles,\n Zap,\n Gift,\n ShoppingBag,\n Bell,\n Calendar,\n Bookmark: BookmarkIcon,\n};\n\nconst HEADER_ICON_OPTIONS: Array<{ label: string; value: string }> = [\n { label: \"Graduation Cap\", value: \"GraduationCap\" },\n { label: \"Video\", value: \"Video\" },\n { label: \"Book\", value: \"BookOpen\" },\n { label: \"Globe\", value: \"Globe\" },\n { label: \"User\", value: \"User\" },\n { label: \"Star\", value: \"Star\" },\n { label: \"Heart\", value: \"Heart\" },\n { label: \"Trophy\", value: \"Trophy\" },\n { label: \"Sparkles\", value: \"Sparkles\" },\n { label: \"Zap / Lightning\", value: \"Zap\" },\n { label: \"Gift\", value: \"Gift\" },\n { label: \"Shopping Bag\", value: \"ShoppingBag\" },\n { label: \"Bell\", value: \"Bell\" },\n { label: \"Calendar\", value: \"Calendar\" },\n { label: \"Bookmark\", value: \"Bookmark\" },\n];\n\nconst getHeaderIcon = (name: string | undefined): LucideIcon => {\n if (!name) return GraduationCap;\n return HEADER_ICON_MAP[name] ?? GraduationCap;\n};\n\ntype EmbedWidgetProps = ComponentProps<\"div\"> & {\n url?: string;\n title?: string;\n height?: string;\n fullScreen?: boolean;\n allowFullscreen?: boolean;\n loading?: \"eager\" | \"lazy\";\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n editMode?: boolean;\n isSelected?: boolean;\n\n // Cover-mode additions (all optional — inline mode ignores these)\n displayMode?: DisplayMode;\n coverResource?: ShareableItem;\n coverUseCustomUrl?: boolean;\n coverImageUrl?: string;\n coverTitle?: string;\n coverMeta?: string;\n coverShowHeader?: boolean;\n coverHeaderIcon?: string;\n coverHeaderIconColor?: ColorOptions;\n coverHeight?: string;\n};\n\nexport function EmbedWidget({\n url = \"\",\n title = \"Embedded Content\",\n height = \"400px\",\n fullScreen = false,\n allowFullscreen = true,\n loading = \"lazy\",\n borderRadius = \"md\",\n borderWidth = \"none\",\n borderColor = \"muted\",\n editMode = false,\n isSelected = false,\n\n displayMode = \"inline\",\n coverResource,\n coverUseCustomUrl = false,\n coverImageUrl = \"\",\n coverTitle = \"\",\n coverMeta = \"\",\n coverShowHeader = true,\n coverHeaderIcon = \"GraduationCap\",\n coverHeaderIconColor = \"primary\",\n coverHeight = \"320px\",\n\n className,\n ...props\n}: EmbedWidgetProps): React.JSX.Element {\n const isFullScreen = fullScreen;\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const repUser = useRepUser();\n const publicId = repUser?.publicId;\n\n const [modalOpen, setModalOpen] = useState(false);\n const [coverReloadKey, setCoverReloadKey] = useState(0);\n const [iframeReloadKey, setIframeReloadKey] = useState(0);\n\n const closeModal = useCallback(() => setModalOpen(false), []);\n\n const { normalizedUrl, isValidUrl, iframeSrc } = useEmbedUrl(url, publicId);\n useEmbedPostMessageBridge({\n iframeRef,\n normalizedUrl,\n isValidUrl,\n editMode,\n });\n useModalBodyScrollLock(modalOpen);\n useModalEscapeClose(modalOpen, closeModal);\n\n // ----- Empty/invalid URL states -----\n\n if (!url || !isValidUrl) {\n return (\n <div\n className={`flex items-center justify-center rounded-${borderRadius} border-border bg-muted text-muted-foreground border-2 border-dashed ${className ?? \"\"}`}\n {...props}\n style={\n isFullScreen\n ? {\n height:\n \"var(--portal-fullscreen-embed-height, calc(100dvh - 4rem))\",\n }\n : { height: displayMode === \"cover\" ? coverHeight : height }\n }\n >\n <div className=\"flex flex-col items-center gap-2 p-6 text-center\">\n <Globe className=\"size-12 opacity-50\" />\n <p className=\"text-sm font-medium\">\n Enter a URL to embed external content\n </p>\n <p className=\"text-xs opacity-75\">\n Configure the URL in the properties panel\n </p>\n </div>\n </div>\n );\n }\n\n // ----- Cover mode -----\n\n if (displayMode === \"cover\") {\n const resolvedCoverImage = coverUseCustomUrl\n ? coverImageUrl\n : coverResource?.imageUrl || coverResource?.image_url || coverImageUrl;\n\n const effectiveTitle = coverTitle || title;\n const HeaderIcon = getHeaderIcon(coverHeaderIcon);\n\n const handleOpenModal = () => {\n if (editMode) return;\n setModalOpen(true);\n };\n\n const handleReload = () => {\n if (editMode) return;\n setCoverReloadKey((key) => key + 1);\n };\n\n const handleOpenNewTab = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (editMode) return;\n window.open(iframeSrc, \"_blank\", \"noopener,noreferrer\");\n };\n\n return (\n <>\n <div\n className={`relative w-full overflow-hidden rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} bg-background ${className ?? \"\"}`}\n style={{\n boxShadow:\n \"0 1px 2px color-mix(in oklch, var(--color-foreground) 5%, transparent), 0 12px 32px -16px color-mix(in oklch, var(--color-foreground) 10%, transparent)\",\n }}\n {...props}\n >\n {/* Inset hairline ring */}\n <div\n aria-hidden=\"true\"\n className={`pointer-events-none absolute inset-0 z-[1] rounded-${borderRadius}`}\n style={{\n boxShadow:\n \"inset 0 0 0 1px color-mix(in oklch, var(--color-foreground) 8%, transparent)\",\n }}\n />\n {coverShowHeader && (\n <div className=\"relative z-[2] flex items-center gap-3 px-5 py-3\">\n <span\n aria-hidden=\"true\"\n className={`text-${coverHeaderIconColor}-foreground flex size-7 shrink-0 items-center justify-center rounded-${borderRadius}`}\n style={{\n background: `linear-gradient(135deg, color-mix(in oklch, var(--color-${coverHeaderIconColor}) 75%, white 25%) 0%, var(--color-${coverHeaderIconColor}) 100%)`,\n boxShadow: `\n inset 0 1px 0 rgba(255,255,255,0.25),\n inset 0 -1px 0 rgba(0,0,0,0.08),\n 0 1px 2px color-mix(in oklch, var(--color-${coverHeaderIconColor}) 25%, transparent)\n `,\n }}\n >\n <HeaderIcon className=\"size-3.5\" strokeWidth={2.25} />\n </span>\n\n <div className=\"min-w-0 flex-1\">\n {effectiveTitle && (\n <h3 className=\"text-foreground truncate text-[15px] leading-tight font-semibold tracking-tight\">\n {effectiveTitle}\n </h3>\n )}\n {coverMeta && (\n <p className=\"text-foreground/40 mt-0.5 truncate text-[11px] font-medium tracking-[0.08em] uppercase\">\n {coverMeta}\n </p>\n )}\n </div>\n\n <div className=\"bg-foreground/5 flex shrink-0 items-center rounded-lg p-0.5\">\n <HeaderIconButton\n Icon={RotateCw}\n label=\"Reload\"\n onClick={(e) => {\n e.stopPropagation();\n handleReload();\n }}\n />\n <HeaderIconButton\n Icon={Maximize2}\n label=\"Open\"\n onClick={(e) => {\n e.stopPropagation();\n handleOpenModal();\n }}\n />\n <HeaderIconButton\n Icon={ExternalLink}\n label=\"Open in new tab\"\n onClick={handleOpenNewTab}\n />\n </div>\n </div>\n )}\n\n <button\n type=\"button\"\n onClick={handleOpenModal}\n disabled={editMode}\n className={`relative block w-full overflow-hidden ${editMode ? \"cursor-default\" : \"cursor-pointer\"}`}\n style={{ height: coverHeight }}\n aria-label={`Open ${effectiveTitle || title}`}\n >\n {resolvedCoverImage ? (\n <img\n key={`cover-${coverReloadKey}`}\n src={resolvedCoverImage}\n alt={effectiveTitle || title}\n className=\"h-full w-full object-cover\"\n />\n ) : (\n <div className=\"bg-muted flex h-full w-full items-center justify-center\">\n <Globe className=\"text-muted-foreground/40 size-16\" />\n </div>\n )}\n </button>\n {editMode && !isSelected && <div className=\"absolute inset-0 z-10\" />}\n </div>\n\n {modalOpen && (\n <EmbedModal\n key={`modal-${iframeReloadKey}`}\n src={iframeSrc}\n title={effectiveTitle || title}\n allowFullscreen={allowFullscreen}\n iframeRef={iframeRef}\n onClose={closeModal}\n onReload={() => setIframeReloadKey((key) => key + 1)}\n />\n )}\n </>\n );\n }\n\n // ----- Inline mode (original behavior) -----\n\n return (\n <div\n className={`relative w-full rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} ${className ?? \"\"}`}\n {...props}\n style={\n isFullScreen\n ? {\n height:\n \"var(--portal-fullscreen-embed-height, calc(100dvh - 4rem))\",\n }\n : undefined\n }\n >\n <iframe\n ref={iframeRef}\n src={iframeSrc}\n title={title}\n width=\"100%\"\n style={isFullScreen ? { height: \"100%\" } : { height }}\n loading={loading}\n allowFullScreen={allowFullscreen}\n className={`rounded-${borderRadius} border-border border`}\n sandbox=\"allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox\"\n />\n {editMode && !isSelected && <div className=\"absolute inset-0 z-10\" />}\n </div>\n );\n}\n\n// ----- Header icon button -----\n\ntype HeaderIconButtonProps = {\n Icon: LucideIcon;\n label: string;\n onClick: (e: React.MouseEvent) => void;\n};\n\nfunction HeaderIconButton({\n Icon,\n label,\n onClick,\n}: HeaderIconButtonProps): React.JSX.Element {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label={label}\n className=\"text-foreground/45 hover:text-foreground hover:bg-background flex size-7 items-center justify-center rounded-md transition-colors\"\n >\n <Icon className=\"size-3.5\" strokeWidth={2.25} />\n </button>\n );\n}\n\n// ----- Modal -----\n\ntype EmbedModalProps = {\n src: string;\n title: string;\n allowFullscreen: boolean;\n iframeRef: RefObject<HTMLIFrameElement | null>;\n onClose: () => void;\n onReload: () => void;\n};\n\nfunction EmbedModal({\n src,\n title,\n allowFullscreen,\n iframeRef,\n onClose,\n onReload,\n}: EmbedModalProps): React.JSX.Element {\n const dialogRef = useRef<HTMLDivElement>(null);\n\n useDialogFocusRestore(dialogRef);\n\n // Portal to document.body so the fixed-position dialog isn't clipped by\n // a transformed widget container on the live canvas (CSS transforms make\n // descendants the containing block for `position: fixed`).\n return createPortal(\n <div\n ref={dialogRef}\n tabIndex={-1}\n className=\"fixed inset-0 z-[100] flex items-center justify-center p-4 focus:outline-none sm:p-8\"\n style={{\n background: \"color-mix(in oklch, var(--color-foreground) 80%, black)\",\n }}\n onClick={onClose}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n >\n <div\n className=\"bg-background relative flex h-full max-h-[95vh] w-full max-w-[1400px] flex-col overflow-hidden rounded-2xl shadow-2xl\"\n onClick={(e) => e.stopPropagation()}\n >\n <div\n className=\"flex items-center justify-between gap-4 px-5 py-3\"\n style={{\n borderBottom:\n \"1px solid color-mix(in oklch, var(--color-foreground) 8%, transparent)\",\n }}\n >\n <h3 className=\"text-foreground truncate text-sm font-semibold tracking-tight\">\n {title}\n </h3>\n <div className=\"flex shrink-0 items-center gap-1\">\n <HeaderIconButton\n Icon={RotateCw}\n label=\"Reload\"\n onClick={(e) => {\n e.stopPropagation();\n onReload();\n }}\n />\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close\"\n className=\"text-foreground/60 hover:text-foreground hover:bg-foreground/5 flex size-9 shrink-0 items-center justify-center rounded-full transition-colors\"\n >\n <X className=\"size-5\" />\n </button>\n </div>\n </div>\n <iframe\n ref={iframeRef}\n src={src}\n title={title}\n className=\"flex-1 border-0\"\n allowFullScreen={allowFullscreen}\n sandbox=\"allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox\"\n />\n </div>\n </div>,\n document.body,\n );\n}\n\n// ----- Schema -----\n\nexport const embedWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"EmbedWidget\",\n displayName: \"Embed\",\n fields: [\n // Content\n {\n key: \"url\",\n label: \"URL\",\n type: \"text\",\n description: \"The URL of the external site to embed\",\n placeholder: \"https://example.com\",\n defaultValue: \"\",\n group: \"Content\",\n },\n {\n key: \"title\",\n label: \"Screen Reader Label\",\n type: \"text\",\n description:\n \"Describes the embed for screen readers and assistive tech. Not visible on the page.\",\n defaultValue: \"Embedded Content\",\n group: \"Content\",\n },\n\n // Display Mode\n {\n key: \"displayMode\",\n label: \"Display Mode\",\n type: \"buttonGroup\",\n description:\n \"Inline: iframe renders directly. Cover: shows a card that opens the embed in a full-screen modal.\",\n defaultValue: \"inline\",\n options: [\n { label: \"Inline\", value: \"inline\" },\n { label: \"Cover + Modal\", value: \"cover\" },\n ],\n group: \"Display Mode\",\n },\n\n // Cover fields — all gated behind displayMode=cover\n {\n key: \"coverResource\",\n label: \"Cover Image\",\n type: \"resource\",\n description: \"Select the image shown before the embed opens\",\n allowedTypes: [\"Medium\"],\n group: \"Cover\",\n requiresKeyValue: { key: \"displayMode\", value: \"cover\" },\n },\n {\n key: \"coverUseCustomUrl\",\n label: \"Use Custom URL\",\n type: \"boolean\",\n description: \"Enter a custom image URL instead of selecting media\",\n defaultValue: false,\n group: \"Cover\",\n requiresKeyValue: { key: \"displayMode\", value: \"cover\" },\n },\n {\n key: \"coverImageUrl\",\n label: \"Cover Image URL\",\n type: \"text\",\n description: \"Direct URL to the cover image\",\n placeholder: \"https://example.com/cover.jpg\",\n defaultValue: \"\",\n group: \"Cover\",\n requiresKeyValue: [\n { key: \"displayMode\", value: \"cover\" },\n { key: \"coverUseCustomUrl\", value: true },\n ],\n },\n getHeightField({\n key: \"coverHeight\",\n label: \"Cover Height\",\n description: \"Height of the cover image area\",\n defaultValue: \"320px\",\n group: \"Cover\",\n requiresKeyValue: { key: \"displayMode\", value: \"cover\" },\n }),\n\n // Cover header (optional)\n {\n key: \"coverShowHeader\",\n label: \"Show Card Header\",\n type: \"boolean\",\n description: \"Show the header with icon, title, and action buttons\",\n defaultValue: true,\n group: \"Cover Header\",\n requiresKeyValue: { key: \"displayMode\", value: \"cover\" },\n },\n {\n key: \"coverHeaderIcon\",\n label: \"Header Icon\",\n type: \"select\",\n description: \"Icon displayed in the colored badge on the left\",\n options: HEADER_ICON_OPTIONS,\n defaultValue: \"GraduationCap\",\n group: \"Cover Header\",\n requiresKeyValue: [\n { key: \"displayMode\", value: \"cover\" },\n { key: \"coverShowHeader\", value: true },\n ],\n },\n getColorField({\n key: \"coverHeaderIconColor\",\n label: \"Icon Badge Color\",\n description: \"Background color of the icon badge\",\n defaultValue: \"primary\",\n group: \"Cover Header\",\n requiresKeyValue: [\n { key: \"displayMode\", value: \"cover\" },\n { key: \"coverShowHeader\", value: true },\n ],\n }),\n {\n key: \"coverTitle\",\n label: \"Header Title\",\n type: \"text\",\n description:\n \"Title shown in the card header and modal (falls back to the widget Title if empty). Available even when the card header is hidden so the modal still has a meaningful title.\",\n defaultValue: \"\",\n group: \"Cover Header\",\n requiresKeyValue: { key: \"displayMode\", value: \"cover\" },\n },\n {\n key: \"coverMeta\",\n label: \"Meta Text\",\n type: \"text\",\n description:\n \"Small uppercase meta line below the title (e.g. 'APR 16 · COACHING THE HOSTESS')\",\n defaultValue: \"\",\n group: \"Cover Header\",\n requiresKeyValue: [\n { key: \"displayMode\", value: \"cover\" },\n { key: \"coverShowHeader\", value: true },\n ],\n },\n\n // Design\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the embed container\",\n defaultValue: \"md\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the widget\",\n defaultValue: \"none\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the widget\",\n defaultValue: \"muted\",\n group: \"Design\",\n }),\n {\n key: \"fullScreen\",\n label: \"Full Screen\",\n type: \"boolean\",\n description:\n \"Inline mode: fill the available space instead of a fixed height\",\n defaultValue: false,\n group: \"Design\",\n requiresKeyValue: { key: \"displayMode\", value: \"inline\" },\n },\n getHeightField({\n key: \"height\",\n label: \"Height\",\n description: \"Height of the inline embed iframe\",\n defaultValue: \"400px\",\n group: \"Design\",\n requiresKeyValue: [\n { key: \"displayMode\", value: \"inline\" },\n { key: \"fullScreen\", value: false },\n ],\n }),\n\n // Settings\n {\n key: \"allowFullscreen\",\n label: \"Allow Fullscreen\",\n type: \"boolean\",\n description: \"Allow the embedded content to use fullscreen mode\",\n defaultValue: true,\n group: \"Settings\",\n },\n {\n key: \"loading\",\n label: \"Loading\",\n type: \"select\",\n description: \"When to load the embedded content (inline mode only)\",\n options: [\n { label: \"Lazy (on scroll)\", value: \"lazy\" },\n { label: \"Eager (immediately)\", value: \"eager\" },\n ],\n defaultValue: \"lazy\",\n group: \"Settings\",\n requiresKeyValue: { key: \"displayMode\", value: \"inline\" },\n },\n ],\n};\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ImageWidget-B6DESmDt.mjs","names":[],"sources":["../../widgets/src/widgets/ImageWidget.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport type React from \"react\";\nimport {\n getBorderRadiusField,\n getHeightField,\n type WidgetPropertySchema,\n} from \"@fluid-app/portal-core/registries\";\nimport type {\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n ShareableItem,\n} from \"@fluid-app/portal-core/types\";\nimport {\n getBorderWidthField,\n getBorderColorField,\n borderWidthClasses,\n borderColorClasses,\n} from \"../core/fields\";\nimport { MediaRenderer } from \"../components/MediaRenderer\";\n\ntype ImageWidgetProps = ComponentProps<\"div\"> & {\n src?: string;\n alt?: string;\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n verticalSizing?: \"auto\" | \"fixed\";\n fixedHeight?: string;\n displayFit?: \"cover\" | \"contain\";\n focusPoint?: string;\n linkUrl?: string;\n resource?: ShareableItem;\n useCustomUrl?: boolean;\n editMode?: boolean;\n};\n\nexport function ImageWidget({\n src = \"\",\n alt = \"\",\n borderRadius = \"md\",\n borderWidth = \"none\",\n borderColor = \"muted\",\n verticalSizing = \"auto\",\n fixedHeight = \"200px\",\n displayFit = \"cover\",\n focusPoint,\n linkUrl,\n resource,\n useCustomUrl,\n editMode = false,\n}: ImageWidgetProps): React.JSX.Element {\n const effectiveSrc = useCustomUrl ? src : (resource?.imageUrl ?? src);\n const effectiveAlt = resource?.title ?? alt;\n\n const isFixed = verticalSizing === \"fixed\";\n\n const content = (\n <div\n className={`w-full rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} overflow-hidden`}\n style={isFixed ? { height: fixedHeight } : undefined}\n >\n <MediaRenderer\n mediaType=\"image\"\n src={effectiveSrc}\n alt={effectiveAlt}\n objectFit={isFixed ? displayFit : \"contain\"}\n focusPoint={isFixed ? focusPoint : undefined}\n />\n </div>\n );\n\n if (linkUrl && !editMode) {\n return (\n <a href={linkUrl} target=\"_blank\" rel=\"noopener noreferrer\">\n {content}\n </a>\n );\n }\n\n return content;\n}\n\nexport const imageWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"ImageWidget\",\n displayName: \"Image\",\n fields: [\n // Content\n {\n key: \"resource\",\n label: \"Select Image\",\n type: \"resource\",\n description: \"Browse and select an image\",\n allowedTypes: [\"Medium\"],\n group: \"Content\",\n },\n {\n key: \"useCustomUrl\",\n label: \"Use Custom URL\",\n type: \"boolean\",\n description: \"Enter a custom image URL instead of selecting media\",\n defaultValue: false,\n group: \"Content\",\n },\n {\n key: \"src\",\n label: \"Image URL\",\n type: \"text\",\n description: \"The source URL of the image\",\n defaultValue:\n \"https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800&auto=format&fit=crop\",\n group: \"Content\",\n requiresKeyToBeTrue: \"useCustomUrl\",\n },\n {\n key: \"alt\",\n label: \"Alt Text\",\n type: \"text\",\n description: \"Alternative text for the image (for accessibility)\",\n defaultValue: \"Placeholder image\",\n group: \"Content\",\n },\n\n // Design\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the container\",\n defaultValue: \"md\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the widget\",\n defaultValue: \"none\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the widget\",\n defaultValue: \"muted\",\n group: \"Design\",\n }),\n {\n key: \"verticalSizing\",\n label: \"Vertical Sizing\",\n type: \"buttonGroup\",\n description: \"How the image height is determined\",\n options: [\n { label: \"Auto\", value: \"auto\" },\n { label: \"Fixed\", value: \"fixed\" },\n ],\n defaultValue: \"auto\",\n group: \"Design\",\n },\n getHeightField({\n key: \"fixedHeight\",\n label: \"Height\",\n description: \"Fixed height of the image container\",\n defaultValue: \"200px\",\n group: \"Design\",\n requiresKeyValue: { key: \"verticalSizing\", value: \"fixed\" },\n }),\n {\n key: \"displayFit\",\n label: \"Display Fit\",\n type: \"buttonGroup\",\n description: \"How the image fills its container\",\n options: [\n { label: \"Cover\", value: \"cover\" },\n { label: \"Contain\", value: \"contain\" },\n ],\n defaultValue: \"cover\",\n group: \"Design\",\n requiresKeyValue: { key: \"verticalSizing\", value: \"fixed\" },\n },\n {\n key: \"focusPoint\",\n label: \"Focus Point\",\n type: \"contentPosition\",\n description: \"The focal point of the image within its container\",\n defaultValue: \"center\",\n group: \"Design\",\n requiresKeyValue: { key: \"verticalSizing\", value: \"fixed\" },\n },\n\n // Link\n {\n key: \"linkUrl\",\n label: \"Link URL\",\n type: \"text\",\n description: \"Optional URL to wrap the image in a link\",\n defaultValue: \"\",\n group: \"Link\",\n },\n ],\n};\n"],"mappings":";;;;;;;;;AAqCA,SAAgB,YAAY,EAC1B,MAAM,IACN,MAAM,IACN,eAAe,MACf,cAAc,QACd,cAAc,SACd,iBAAiB,QACjB,cAAc,SACd,aAAa,SACb,YACA,SACA,UACA,cACA,WAAW,SAC2B;CACtC,MAAM,eAAe,eAAe,MAAO,UAAU,YAAY;CACjE,MAAM,eAAe,UAAU,SAAS;CAExC,MAAM,UAAU,mBAAmB;CAEnC,MAAM,UACJ,oBAAC,OAAD;EACE,WAAW,kBAAkB,aAAa,GAAG,mBAAmB,aAAa,GAAG,gBAAgB,SAAS,mBAAmB,eAAe,GAAG;EAC9I,OAAO,UAAU,EAAE,QAAQ,aAAa,GAAG,KAAA;YAE3C,oBAAC,eAAD;GACE,WAAU;GACV,KAAK;GACL,KAAK;GACL,WAAW,UAAU,aAAa;GAClC,YAAY,UAAU,aAAa,KAAA;GACnC,CAAA;EACE,CAAA;AAGR,KAAI,WAAW,CAAC,SACd,QACE,oBAAC,KAAD;EAAG,MAAM;EAAS,QAAO;EAAS,KAAI;YACnC;EACC,CAAA;AAIR,QAAO;;AAGT,MAAa,4BAAkD;CAC7D,YAAY;CACZ,aAAa;CACb,QAAQ;EAEN;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc,CAAC,SAAS;GACxB,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cACE;GACF,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,OAAO;GACR;EAGD,qBAAqB;GACnB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,OAAO;GACR,CAAC;EACF,oBAAoB;GAClB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,OAAO;GACR,CAAC;EACF,oBAAoB;GAClB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,SAAS,CACP;IAAE,OAAO;IAAQ,OAAO;IAAQ,EAChC;IAAE,OAAO;IAAS,OAAO;IAAS,CACnC;GACD,cAAc;GACd,OAAO;GACR;EACD,eAAe;GACb,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,OAAO;GACP,kBAAkB;IAAE,KAAK;IAAkB,OAAO;IAAS;GAC5D,CAAC;EACF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,SAAS,CACP;IAAE,OAAO;IAAS,OAAO;IAAS,EAClC;IAAE,OAAO;IAAW,OAAO;IAAW,CACvC;GACD,cAAc;GACd,OAAO;GACP,kBAAkB;IAAE,KAAK;IAAkB,OAAO;IAAS;GAC5D;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,OAAO;GACP,kBAAkB;IAAE,KAAK;IAAkB,OAAO;IAAS;GAC5D;EAGD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,OAAO;GACR;EACF;CACF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ImageWidget-Cz1W-CaS.cjs","names":["borderWidthClasses","borderColorClasses","MediaRenderer","getBorderRadiusField","getBorderWidthField","getBorderColorField","getHeightField"],"sources":["../../widgets/src/widgets/ImageWidget.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport type React from \"react\";\nimport {\n getBorderRadiusField,\n getHeightField,\n type WidgetPropertySchema,\n} from \"@fluid-app/portal-core/registries\";\nimport type {\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n ShareableItem,\n} from \"@fluid-app/portal-core/types\";\nimport {\n getBorderWidthField,\n getBorderColorField,\n borderWidthClasses,\n borderColorClasses,\n} from \"../core/fields\";\nimport { MediaRenderer } from \"../components/MediaRenderer\";\n\ntype ImageWidgetProps = ComponentProps<\"div\"> & {\n src?: string;\n alt?: string;\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n verticalSizing?: \"auto\" | \"fixed\";\n fixedHeight?: string;\n displayFit?: \"cover\" | \"contain\";\n focusPoint?: string;\n linkUrl?: string;\n resource?: ShareableItem;\n useCustomUrl?: boolean;\n editMode?: boolean;\n};\n\nexport function ImageWidget({\n src = \"\",\n alt = \"\",\n borderRadius = \"md\",\n borderWidth = \"none\",\n borderColor = \"muted\",\n verticalSizing = \"auto\",\n fixedHeight = \"200px\",\n displayFit = \"cover\",\n focusPoint,\n linkUrl,\n resource,\n useCustomUrl,\n editMode = false,\n}: ImageWidgetProps): React.JSX.Element {\n const effectiveSrc = useCustomUrl ? src : (resource?.imageUrl ?? src);\n const effectiveAlt = resource?.title ?? alt;\n\n const isFixed = verticalSizing === \"fixed\";\n\n const content = (\n <div\n className={`w-full rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} overflow-hidden`}\n style={isFixed ? { height: fixedHeight } : undefined}\n >\n <MediaRenderer\n mediaType=\"image\"\n src={effectiveSrc}\n alt={effectiveAlt}\n objectFit={isFixed ? displayFit : \"contain\"}\n focusPoint={isFixed ? focusPoint : undefined}\n />\n </div>\n );\n\n if (linkUrl && !editMode) {\n return (\n <a href={linkUrl} target=\"_blank\" rel=\"noopener noreferrer\">\n {content}\n </a>\n );\n }\n\n return content;\n}\n\nexport const imageWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"ImageWidget\",\n displayName: \"Image\",\n fields: [\n // Content\n {\n key: \"resource\",\n label: \"Select Image\",\n type: \"resource\",\n description: \"Browse and select an image\",\n allowedTypes: [\"Medium\"],\n group: \"Content\",\n },\n {\n key: \"useCustomUrl\",\n label: \"Use Custom URL\",\n type: \"boolean\",\n description: \"Enter a custom image URL instead of selecting media\",\n defaultValue: false,\n group: \"Content\",\n },\n {\n key: \"src\",\n label: \"Image URL\",\n type: \"text\",\n description: \"The source URL of the image\",\n defaultValue:\n \"https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800&auto=format&fit=crop\",\n group: \"Content\",\n requiresKeyToBeTrue: \"useCustomUrl\",\n },\n {\n key: \"alt\",\n label: \"Alt Text\",\n type: \"text\",\n description: \"Alternative text for the image (for accessibility)\",\n defaultValue: \"Placeholder image\",\n group: \"Content\",\n },\n\n // Design\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the container\",\n defaultValue: \"md\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the widget\",\n defaultValue: \"none\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the widget\",\n defaultValue: \"muted\",\n group: \"Design\",\n }),\n {\n key: \"verticalSizing\",\n label: \"Vertical Sizing\",\n type: \"buttonGroup\",\n description: \"How the image height is determined\",\n options: [\n { label: \"Auto\", value: \"auto\" },\n { label: \"Fixed\", value: \"fixed\" },\n ],\n defaultValue: \"auto\",\n group: \"Design\",\n },\n getHeightField({\n key: \"fixedHeight\",\n label: \"Height\",\n description: \"Fixed height of the image container\",\n defaultValue: \"200px\",\n group: \"Design\",\n requiresKeyValue: { key: \"verticalSizing\", value: \"fixed\" },\n }),\n {\n key: \"displayFit\",\n label: \"Display Fit\",\n type: \"buttonGroup\",\n description: \"How the image fills its container\",\n options: [\n { label: \"Cover\", value: \"cover\" },\n { label: \"Contain\", value: \"contain\" },\n ],\n defaultValue: \"cover\",\n group: \"Design\",\n requiresKeyValue: { key: \"verticalSizing\", value: \"fixed\" },\n },\n {\n key: \"focusPoint\",\n label: \"Focus Point\",\n type: \"contentPosition\",\n description: \"The focal point of the image within its container\",\n defaultValue: \"center\",\n group: \"Design\",\n requiresKeyValue: { key: \"verticalSizing\", value: \"fixed\" },\n },\n\n // Link\n {\n key: \"linkUrl\",\n label: \"Link URL\",\n type: \"text\",\n description: \"Optional URL to wrap the image in a link\",\n defaultValue: \"\",\n group: \"Link\",\n },\n ],\n};\n"],"mappings":";;;;;;;;;AAqCA,SAAgB,YAAY,EAC1B,MAAM,IACN,MAAM,IACN,eAAe,MACf,cAAc,QACd,cAAc,SACd,iBAAiB,QACjB,cAAc,SACd,aAAa,SACb,YACA,SACA,UACA,cACA,WAAW,SAC2B;CACtC,MAAM,eAAe,eAAe,MAAO,UAAU,YAAY;CACjE,MAAM,eAAe,UAAU,SAAS;CAExC,MAAM,UAAU,mBAAmB;CAEnC,MAAM,UACJ,iBAAA,GAAA,kBAAA,KAAC,OAAD;EACE,WAAW,kBAAkB,aAAa,GAAGA,mBAAAA,mBAAmB,aAAa,GAAG,gBAAgB,SAASC,mBAAAA,mBAAmB,eAAe,GAAG;EAC9I,OAAO,UAAU,EAAE,QAAQ,aAAa,GAAG,KAAA;YAE3C,iBAAA,GAAA,kBAAA,KAACC,sBAAAA,eAAD;GACE,WAAU;GACV,KAAK;GACL,KAAK;GACL,WAAW,UAAU,aAAa;GAClC,YAAY,UAAU,aAAa,KAAA;GACnC,CAAA;EACE,CAAA;AAGR,KAAI,WAAW,CAAC,SACd,QACE,iBAAA,GAAA,kBAAA,KAAC,KAAD;EAAG,MAAM;EAAS,QAAO;EAAS,KAAI;YACnC;EACC,CAAA;AAIR,QAAO;;AAGT,MAAa,4BAAkD;CAC7D,YAAY;CACZ,aAAa;CACb,QAAQ;EAEN;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc,CAAC,SAAS;GACxB,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cACE;GACF,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,OAAO;GACR;EAGDC,mBAAAA,qBAAqB;GACnB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,OAAO;GACR,CAAC;EACFC,mBAAAA,oBAAoB;GAClB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,OAAO;GACR,CAAC;EACFC,mBAAAA,oBAAoB;GAClB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,SAAS,CACP;IAAE,OAAO;IAAQ,OAAO;IAAQ,EAChC;IAAE,OAAO;IAAS,OAAO;IAAS,CACnC;GACD,cAAc;GACd,OAAO;GACR;EACDC,mBAAAA,eAAe;GACb,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,OAAO;GACP,kBAAkB;IAAE,KAAK;IAAkB,OAAO;IAAS;GAC5D,CAAC;EACF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,SAAS,CACP;IAAE,OAAO;IAAS,OAAO;IAAS,EAClC;IAAE,OAAO;IAAW,OAAO;IAAW,CACvC;GACD,cAAc;GACd,OAAO;GACP,kBAAkB;IAAE,KAAK;IAAkB,OAAO;IAAS;GAC5D;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,OAAO;GACP,kBAAkB;IAAE,KAAK;IAAkB,OAAO;IAAS;GAC5D;EAGD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,OAAO;GACR;EACF;CACF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ListWidget-CRsc53kj.mjs","names":["DOMPurify","getImageUrl"],"sources":["../../widgets/src/widgets/list-widget/helpers.ts","../../widgets/src/widgets/list-widget/FeaturedSection.tsx","../../widgets/src/widgets/list-widget/ListItemCard.tsx","../../widgets/src/widgets/list-widget/UnorderedList.tsx","../../widgets/src/widgets/list-widget/OrderedList.tsx","../../widgets/src/widgets/ListWidget.tsx"],"sourcesContent":["import type { BorderRadiusOptions } from \"@fluid-app/portal-core/types\";\n\n/**\n * Maps the schema's BorderRadiusOptions to a Tailwind `rounded-*` class.\n * `\"full\"` is converted to `rounded-2xl` because the list item cards and\n * featured section read better as large-radius rectangles than as\n * pill-shaped containers.\n */\nexport const cardRadiusClass = (radius: BorderRadiusOptions): string =>\n radius === \"full\" ? \"rounded-2xl\" : `rounded-${radius}`;\n","import type React from \"react\";\nimport type {\n BorderRadiusOptions,\n FontSizeOptions,\n ColorOptions,\n} from \"@fluid-app/portal-core/types\";\nimport { MediaRenderer } from \"../../components/MediaRenderer\";\nimport { cardRadiusClass } from \"./helpers\";\n\ninterface FeaturedSectionProps {\n borderRadius: BorderRadiusOptions;\n titleSize: FontSizeOptions;\n featuredTitle?: string | undefined;\n featuredSubtitle?: string | undefined;\n featuredButtonText?: string | undefined;\n featuredButtonUrl?: string | undefined;\n featuredSubtitleColor: ColorOptions;\n featuredSubtitleSize: FontSizeOptions;\n asset: { url: string; isVideo: boolean };\n}\n\nexport function FeaturedSection({\n borderRadius,\n titleSize,\n featuredTitle,\n featuredSubtitle,\n featuredButtonText,\n featuredButtonUrl,\n featuredSubtitleColor,\n featuredSubtitleSize,\n asset,\n}: FeaturedSectionProps): React.JSX.Element {\n return (\n <div\n className={`group relative h-full min-h-[320px] w-full overflow-hidden ${cardRadiusClass(borderRadius)}`}\n >\n <div className=\"absolute inset-0 h-full w-full\">\n <MediaRenderer\n src={asset.url}\n mediaType={asset.isVideo ? \"video\" : \"image\"}\n alt={featuredTitle || \"Featured\"}\n objectFit=\"cover\"\n autoplay={asset.isVideo}\n loop={asset.isVideo}\n muted={asset.isVideo}\n controls={false}\n />\n </div>\n\n <div\n className=\"pointer-events-none absolute inset-0\"\n style={{\n background:\n \"linear-gradient(180deg, rgba(0,0,0,0) 45%, rgba(0,0,0,0.55) 100%)\",\n }}\n />\n\n <div className=\"absolute inset-0 flex flex-col items-start justify-end p-10\">\n {featuredTitle && (\n <h3\n className={`font-header mb-3 font-medium tracking-tight text-white text-${titleSize === \"md\" ? \"base\" : titleSize}`}\n >\n {featuredTitle}\n </h3>\n )}\n {featuredSubtitle && (\n <p\n className={`mb-6 max-w-md text-${featuredSubtitleColor}/80 text-${featuredSubtitleSize === \"md\" ? \"base\" : featuredSubtitleSize} leading-relaxed`}\n >\n {featuredSubtitle}\n </p>\n )}\n {featuredButtonText && (\n <a\n href={featuredButtonUrl || \"#\"}\n className={`text-foreground inline-flex items-center gap-2 bg-white px-6 py-3 text-sm font-medium tracking-tight transition-opacity hover:opacity-90 ${cardRadiusClass(borderRadius)}`}\n >\n {featuredButtonText}\n <span\n aria-hidden=\"true\"\n className=\"transition-transform group-hover:translate-x-0.5\"\n >\n →\n </span>\n </a>\n )}\n </div>\n </div>\n );\n}\n","import type React from \"react\";\nimport DOMPurify from \"dompurify\";\nimport type {\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\n\ntype ListItem = {\n id: string;\n image?: string;\n imageUrl?: string;\n videoUrl?: string;\n title?: string;\n description?: string;\n price?: string;\n display_price?: string;\n originalPrice?: string;\n discount?: string;\n qv?: string;\n cv?: string;\n [key: string]: unknown;\n};\n\nfunction getStringValue(value: unknown): string {\n if (!value) return \"\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\") return String(value);\n if (typeof value === \"object\" && value !== null) {\n if (\"body\" in value) {\n const body = (value as { body: unknown }).body;\n if (typeof body === \"string\") return body;\n }\n if (\"text\" in value) {\n const text = (value as { text: unknown }).text;\n if (typeof text === \"string\") return text;\n }\n if (\"value\" in value) {\n const val = (value as { value: unknown }).value;\n if (typeof val === \"string\") return val;\n if (typeof val === \"number\") return String(val);\n }\n }\n return \"\";\n}\n\nfunction stripParentheticalText(text: string): string {\n return text.replace(/\\s*\\([^)]*\\)/g, \"\").trim();\n}\n\nfunction formatPrice(value: unknown): string {\n const str = getStringValue(value);\n if (!str) return \"\";\n return stripParentheticalText(str);\n}\n\nexport interface ListItemCardContentProps {\n item: ListItem;\n padding: PaddingOptions;\n itemTitleColor: ColorOptions;\n itemTitleSize: FontSizeOptions;\n descriptionColor: ColorOptions;\n descriptionSize: FontSizeOptions;\n priceColor: ColorOptions;\n priceSize: FontSizeOptions;\n originalPriceColor: ColorOptions;\n metaTextColor: ColorOptions;\n metaTextSize: FontSizeOptions;\n showMetaText: boolean;\n}\n\nexport function ListItemCardContent({\n item,\n padding,\n itemTitleColor,\n itemTitleSize,\n descriptionColor,\n descriptionSize,\n priceColor,\n priceSize,\n originalPriceColor,\n metaTextColor,\n metaTextSize,\n showMetaText,\n}: ListItemCardContentProps): React.JSX.Element {\n const hasPrice = Boolean(item.display_price || item.price);\n const hasOriginal = Boolean(item.originalPrice);\n\n return (\n <div className={`flex flex-1 flex-col p-${padding}`}>\n {item.title && (\n <h3\n className={`text-${itemTitleColor} text-${itemTitleSize === \"md\" ? \"base\" : itemTitleSize} font-header mb-1.5 leading-snug font-medium tracking-tight`}\n >\n {getStringValue(item.title)}\n </h3>\n )}\n {item.description && (\n <div\n className={`text-${descriptionColor}/60 text-${descriptionSize === \"md\" ? \"base\" : descriptionSize} mb-3 line-clamp-2 overflow-hidden leading-relaxed`}\n dangerouslySetInnerHTML={{\n __html: DOMPurify.sanitize(item.description ?? \"\", {\n ALLOWED_TAGS: [\n \"br\",\n \"strong\",\n \"em\",\n \"b\",\n \"i\",\n \"ul\",\n \"ol\",\n \"li\",\n \"p\",\n ],\n ALLOWED_ATTR: [],\n }),\n }}\n />\n )}\n {(hasPrice || hasOriginal) && (\n <div className=\"mt-auto flex items-baseline gap-2\">\n {hasPrice && (\n <span\n className={`text-${priceColor} text-${priceSize === \"md\" ? \"base\" : priceSize} font-semibold tracking-tight tabular-nums`}\n >\n {formatPrice(item.display_price || item.price)}\n </span>\n )}\n {hasOriginal && (\n <span\n className={`text-${originalPriceColor}/50 text-${descriptionSize === \"md\" ? \"base\" : descriptionSize} tabular-nums line-through`}\n >\n {formatPrice(item.originalPrice)}\n </span>\n )}\n </div>\n )}\n {showMetaText && (item.qv || item.cv) && (\n <div\n className={`mt-2 flex gap-4 text-${metaTextColor}/70 text-${metaTextSize === \"md\" ? \"base\" : metaTextSize} font-medium tracking-wide uppercase`}\n >\n {item.qv && (\n <span>\n <span className=\"opacity-50\">QV</span>{\" \"}\n <span className=\"tabular-nums\">{getStringValue(item.qv)}</span>\n </span>\n )}\n {item.cv && (\n <span>\n <span className=\"opacity-50\">CV</span>{\" \"}\n <span className=\"tabular-nums\">{getStringValue(item.cv)}</span>\n </span>\n )}\n </div>\n )}\n </div>\n );\n}\n\nexport function DiscountBadge({\n discount,\n}: {\n discount: string;\n}): React.JSX.Element {\n return (\n <div className=\"bg-background text-foreground absolute top-3 left-3 z-10 rounded-full px-2.5 py-1 text-[10px] font-semibold tracking-[0.08em] uppercase\">\n {getStringValue(discount)}\n </div>\n );\n}\n\nexport { getStringValue };\nexport type { ListItem };\n","import type React from \"react\";\nimport type {\n ColorOptions,\n FontSizeOptions,\n BorderRadiusOptions,\n PaddingOptions,\n GapOptions,\n} from \"@fluid-app/portal-core/types\";\nimport { gapValues } from \"../../core/fields\";\nimport { useWidgetInteraction } from \"../../contexts/WidgetInteractionContext\";\nimport {\n ListItemCardContent,\n DiscountBadge,\n type ListItem,\n} from \"./ListItemCard\";\nimport { cardRadiusClass } from \"./helpers\";\n\ntype ImageAspectRatio = \"square\" | \"landscape\" | \"portrait\";\n\nconst getImageUrl = (item: ListItem): string | undefined => {\n return item.imageUrl || item.image;\n};\n\nconst getAspectRatioClass = (ratio: ImageAspectRatio): string => {\n const ratios = {\n square: \"aspect-square\",\n landscape: \"aspect-video\",\n portrait: \"aspect-[3/4]\",\n };\n return ratios[ratio];\n};\n\nconst getResponsiveGridClass = (columns: number): string => {\n const responsiveClasses: Record<number, string> = {\n 1: \"grid-cols-2 @lg:grid-cols-1\",\n 2: \"grid-cols-2 @lg:grid-cols-2\",\n 3: \"grid-cols-2 @lg:grid-cols-3\",\n 4: \"grid-cols-2 @lg:grid-cols-4\",\n 5: \"grid-cols-2 @lg:grid-cols-5\",\n 6: \"grid-cols-2 @lg:grid-cols-6\",\n };\n return responsiveClasses[columns] || \"grid-cols-2 @lg:grid-cols-3\";\n};\n\nexport interface UnorderedListProps {\n items: ListItem[];\n columns: number;\n gap: GapOptions;\n borderRadius: BorderRadiusOptions;\n imageAspectRatio: ImageAspectRatio;\n showBadge: boolean;\n padding: PaddingOptions;\n itemTitleColor: ColorOptions;\n itemTitleSize: FontSizeOptions;\n descriptionColor: ColorOptions;\n descriptionSize: FontSizeOptions;\n priceColor: ColorOptions;\n priceSize: FontSizeOptions;\n originalPriceColor: ColorOptions;\n metaTextColor: ColorOptions;\n metaTextSize: FontSizeOptions;\n showMetaText: boolean;\n}\n\nexport function UnorderedList({\n items,\n columns,\n gap,\n borderRadius,\n imageAspectRatio,\n showBadge,\n padding,\n itemTitleColor,\n itemTitleSize,\n descriptionColor,\n descriptionSize,\n priceColor,\n priceSize,\n originalPriceColor,\n metaTextColor,\n metaTextSize,\n showMetaText,\n}: UnorderedListProps): React.JSX.Element {\n const gridClass = getResponsiveGridClass(columns);\n const { onItemClick } = useWidgetInteraction();\n\n return (\n <div className={`grid ${gridClass} gap-${gapValues[gap]}`}>\n {items.map((item) => {\n const imageUrl = getImageUrl(item);\n const aspectRatioClass = getAspectRatioClass(imageAspectRatio);\n\n return (\n <div\n key={item.id}\n className={`group relative flex flex-col ${onItemClick ? \"cursor-pointer\" : \"\"}`}\n {...(onItemClick\n ? {\n role: \"button\",\n tabIndex: 0,\n onClick: () => onItemClick(item),\n onKeyDown: (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onItemClick(item);\n }\n },\n }\n : {})}\n >\n {imageUrl && (\n <div\n className={`relative w-full ${aspectRatioClass} bg-muted/30 overflow-hidden ${cardRadiusClass(borderRadius)}`}\n >\n {showBadge && item.discount && (\n <DiscountBadge discount={item.discount} />\n )}\n <img\n src={imageUrl}\n alt={item.title || \"Product\"}\n className=\"h-full w-full object-cover transition-opacity duration-300 group-hover:opacity-90\"\n />\n </div>\n )}\n <div className=\"mt-4\">\n <ListItemCardContent\n item={item}\n padding={padding}\n itemTitleColor={itemTitleColor}\n itemTitleSize={itemTitleSize}\n descriptionColor={descriptionColor}\n descriptionSize={descriptionSize}\n priceColor={priceColor}\n priceSize={priceSize}\n originalPriceColor={originalPriceColor}\n metaTextColor={metaTextColor}\n metaTextSize={metaTextSize}\n showMetaText={showMetaText}\n />\n </div>\n </div>\n );\n })}\n </div>\n );\n}\n","import { useRef } from \"react\";\nimport type React from \"react\";\nimport type { RefObject } from \"react\";\nimport type {\n ColorOptions,\n FontSizeOptions,\n BorderRadiusOptions,\n PaddingOptions,\n GapOptions,\n} from \"@fluid-app/portal-core/types\";\nimport { gapValues } from \"../../core/fields\";\nimport { useWidgetInteraction } from \"../../contexts/WidgetInteractionContext\";\nimport {\n ListItemCardContent,\n DiscountBadge,\n getStringValue,\n type ListItem,\n} from \"./ListItemCard\";\nimport { cardRadiusClass } from \"./helpers\";\n\ntype ImageAspectRatio = \"square\" | \"landscape\" | \"portrait\";\ntype ScrollAxis = \"horizontal\" | \"vertical\";\n\nconst getImageUrl = (item: ListItem): string | undefined => {\n return item.imageUrl || item.image;\n};\n\nexport interface OrderedListProps {\n items: ListItem[];\n scrollAxis: ScrollAxis;\n gap: GapOptions;\n borderRadius: BorderRadiusOptions;\n imageAspectRatio: ImageAspectRatio;\n showBadge: boolean;\n padding: PaddingOptions;\n itemTitleColor: ColorOptions;\n itemTitleSize: FontSizeOptions;\n descriptionColor: ColorOptions;\n descriptionSize: FontSizeOptions;\n priceColor: ColorOptions;\n priceSize: FontSizeOptions;\n originalPriceColor: ColorOptions;\n metaTextColor: ColorOptions;\n metaTextSize: FontSizeOptions;\n numberColor: ColorOptions;\n numberSize: FontSizeOptions;\n showMetaText: boolean;\n /** Optional ref from the parent to control horizontal scroll externally */\n scrollContainerRef?: RefObject<HTMLDivElement | null> | undefined;\n}\n\nconst formatRank = (n: number): string => (n < 10 ? `0${n}` : String(n));\n\nexport function OrderedList({\n items,\n scrollAxis,\n gap,\n borderRadius,\n // imageAspectRatio is intentionally not consumed — ordered layouts use a\n // fixed aspect ratio per axis (3:4 poster horizontal, 16x16 thumb vertical)\n // by design. The schema gates this field to unordered lists.\n imageAspectRatio: _imageAspectRatio,\n showBadge,\n padding,\n itemTitleColor,\n itemTitleSize,\n descriptionColor,\n descriptionSize,\n priceColor,\n priceSize,\n originalPriceColor,\n metaTextColor,\n metaTextSize,\n numberColor,\n numberSize,\n showMetaText,\n scrollContainerRef: externalScrollRef,\n}: OrderedListProps): React.JSX.Element | null {\n const internalScrollRef = useRef<HTMLDivElement>(null);\n const scrollContainerRef = externalScrollRef ?? internalScrollRef;\n\n const { onItemClick } = useWidgetInteraction();\n\n const interactionProps = (item: ListItem) =>\n onItemClick\n ? ({\n role: \"button\" as const,\n tabIndex: 0,\n onClick: () => onItemClick(item),\n onKeyDown: (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onItemClick(item);\n }\n },\n } as const)\n : {};\n\n const contentProps = {\n padding,\n itemTitleColor,\n itemTitleSize,\n descriptionColor,\n descriptionSize,\n priceColor,\n priceSize,\n originalPriceColor,\n metaTextColor,\n metaTextSize,\n showMetaText,\n };\n\n if (scrollAxis === \"horizontal\") {\n return (\n <div className=\"relative\">\n <div\n ref={scrollContainerRef}\n className={`flex gap-${gapValues[gap]} scrollbar-hide overflow-x-auto overflow-y-hidden scroll-smooth`}\n >\n {items.map((item, index) => {\n const imageUrl = getImageUrl(item);\n const rank = index + 1;\n\n return (\n <div\n key={item.id}\n className={`group relative flex flex-shrink-0 flex-col ${onItemClick ? \"cursor-pointer\" : \"\"}`}\n {...interactionProps(item)}\n >\n <div className=\"flex items-end\">\n <span className=\"sr-only\">Rank {rank}: </span>\n <span\n className={`text-${numberColor} pointer-events-none flex-shrink-0 font-black italic tabular-nums select-none`}\n style={{\n fontSize: \"11rem\",\n lineHeight: \"0.82\",\n letterSpacing: \"-0.06em\",\n }}\n aria-hidden=\"true\"\n >\n {rank}\n </span>\n {imageUrl && (\n <div\n className={`relative aspect-[3/4] w-[200px] flex-shrink-0 ${cardRadiusClass(borderRadius)} bg-muted/30 overflow-hidden`}\n >\n {showBadge && item.discount && (\n <DiscountBadge discount={item.discount} />\n )}\n <img\n src={imageUrl}\n alt={item.title || \"Product\"}\n className=\"h-full w-full object-cover\"\n />\n </div>\n )}\n </div>\n <div className=\"mt-5 ml-auto w-[200px]\">\n <ListItemCardContent item={item} {...contentProps} />\n </div>\n </div>\n );\n })}\n </div>\n </div>\n );\n }\n\n if (scrollAxis === \"vertical\") {\n return (\n <div className={`flex flex-col gap-${gapValues[gap]}`}>\n {items.map((item, index) => {\n const imageUrl = getImageUrl(item);\n const rank = index + 1;\n const isLast = index === items.length - 1;\n\n return (\n <div\n key={item.id}\n className={`group relative flex items-center gap-${gapValues[gap]} py-6 ${!isLast ? \"border-b\" : \"\"} ${onItemClick ? \"cursor-pointer\" : \"\"}`}\n style={\n !isLast\n ? {\n borderColor:\n \"color-mix(in oklch, var(--color-foreground) 8%, transparent)\",\n }\n : undefined\n }\n {...interactionProps(item)}\n >\n <span className=\"sr-only\">Rank {rank}: </span>\n <span\n className={`text-${numberColor} font-header w-14 flex-shrink-0 text-${numberSize === \"md\" ? \"base\" : numberSize} leading-none font-light tracking-tight italic`}\n aria-hidden=\"true\"\n >\n {formatRank(rank)}\n </span>\n {imageUrl && (\n <div\n className={`relative h-16 w-16 flex-shrink-0 overflow-hidden ${cardRadiusClass(borderRadius)} bg-muted/30`}\n >\n <img\n src={imageUrl}\n alt={item.title || \"Product\"}\n className=\"h-full w-full object-cover\"\n />\n </div>\n )}\n <div className=\"min-w-0 flex-1\">\n <ListItemCardContent item={item} {...contentProps} />\n </div>\n {showBadge && item.discount && (\n <span className=\"text-muted ml-2 flex-shrink-0 text-[10px] font-semibold tracking-[0.08em] uppercase\">\n {getStringValue(item.discount)}\n </span>\n )}\n </div>\n );\n })}\n </div>\n );\n }\n\n return null;\n}\n","import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type ComponentProps,\n} from \"react\";\nimport type React from \"react\";\nimport { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport type {\n BorderWidthOptions,\n ColorOptions,\n FontSizeOptions,\n BorderRadiusOptions,\n PaddingOptions,\n GapOptions,\n BackgroundValue,\n} from \"@fluid-app/portal-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getBorderWidthField,\n getBorderColorField,\n borderWidthClasses,\n borderColorClasses,\n getColorField,\n getFontSizeField,\n getPaddingField,\n getGapField,\n} from \"../core/fields\";\nimport { FeaturedSection } from \"./list-widget/FeaturedSection\";\nimport { UnorderedList } from \"./list-widget/UnorderedList\";\nimport { OrderedList } from \"./list-widget/OrderedList\";\n\nconst DEFAULT_ITEMS: ListItem[] = [];\n\ntype ListItem = {\n id: string;\n image?: string;\n imageUrl?: string;\n videoUrl?: string;\n title?: string;\n description?: string;\n price?: string;\n originalPrice?: string;\n discount?: string;\n qv?: string;\n cv?: string;\n [key: string]: unknown;\n};\n\ntype ImageAspectRatio = \"square\" | \"landscape\" | \"portrait\";\ntype ListType = \"ordered\" | \"unordered\";\ntype ScrollAxis = \"horizontal\" | \"vertical\";\n\ntype ListWidgetProps = ComponentProps<\"div\"> & {\n // List configuration\n listType?: ListType;\n scrollAxis?: ScrollAxis;\n titleEnabled?: boolean;\n title?: string;\n items?: ListItem[];\n\n // Text styling\n titleColor?: ColorOptions;\n titleSize?: FontSizeOptions;\n itemTitleColor?: ColorOptions;\n itemTitleSize?: FontSizeOptions;\n descriptionColor?: ColorOptions;\n descriptionSize?: FontSizeOptions;\n priceColor?: ColorOptions;\n priceSize?: FontSizeOptions;\n originalPriceColor?: ColorOptions;\n metaTextColor?: ColorOptions;\n metaTextSize?: FontSizeOptions;\n\n // Ordered list styling\n numberColor?: ColorOptions;\n numberSize?: FontSizeOptions;\n\n // Layout\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n padding?: PaddingOptions;\n gap?: GapOptions;\n columns?: number;\n imageAspectRatio?: ImageAspectRatio;\n background?: BackgroundValue;\n\n // Behavior\n showBadge?: boolean;\n showMetaText?: boolean;\n maxItems?: number;\n\n // Featured section\n showFeaturedSection?: boolean;\n featuredAsset?: string | { [key: string]: unknown };\n featuredTitle?: string;\n featuredSubtitle?: string;\n featuredButtonText?: string;\n featuredButtonUrl?: string;\n featuredSubtitleColor?: ColorOptions;\n featuredSubtitleSize?: FontSizeOptions;\n};\n\nfunction getFeaturedAssetUrl(\n value: string | { [key: string]: unknown } | undefined,\n): { url: string; isVideo: boolean } | undefined {\n if (!value) return undefined;\n\n // Handle string URLs\n if (typeof value === \"string\") {\n const isVideo = /\\.(mp4|webm|ogg|mov)$/i.test(value);\n return { url: value, isVideo };\n }\n\n // Handle ShareableItem objects\n if (typeof value === \"object\") {\n // Check for video URL first\n const videoUrl =\n (value.videoUrl as string) ||\n (value.video_url as string) ||\n (value.url as string);\n if (videoUrl && /\\.(mp4|webm|ogg|mov)$/i.test(videoUrl)) {\n return { url: videoUrl, isVideo: true };\n }\n\n // Fall back to image URL\n const imageUrl =\n (value.imageUrl as string) ||\n (value.image_url as string) ||\n (value.url as string);\n if (imageUrl) {\n return { url: imageUrl, isVideo: false };\n }\n }\n\n return undefined;\n}\n\nexport function ListWidget({\n listType = \"unordered\",\n scrollAxis = \"horizontal\",\n titleEnabled = true,\n title,\n items = DEFAULT_ITEMS,\n titleColor = \"foreground\",\n titleSize = \"lg\",\n itemTitleColor = \"foreground\",\n itemTitleSize = \"sm\",\n descriptionColor = \"foreground\",\n descriptionSize = \"sm\",\n priceColor = \"foreground\",\n priceSize = \"md\",\n originalPriceColor = \"muted\",\n metaTextColor = \"muted\",\n metaTextSize = \"xs\",\n numberColor = \"primary\",\n numberSize = \"2xl\",\n borderRadius = \"md\",\n borderWidth = \"none\",\n borderColor = \"muted\",\n padding = 4,\n gap = \"md\",\n columns = 3,\n imageAspectRatio = \"square\",\n background = { type: \"solid\", color: \"background\" },\n showBadge = true,\n showMetaText = true,\n maxItems = 12,\n showFeaturedSection = false,\n featuredAsset,\n featuredTitle,\n featuredSubtitle,\n featuredButtonText,\n featuredButtonUrl,\n featuredSubtitleColor = \"background\",\n featuredSubtitleSize = \"md\",\n className,\n ...props\n}: ListWidgetProps): React.JSX.Element {\n const displayItems = maxItems ? items.slice(0, maxItems) : items;\n const hasItems = displayItems.length > 0;\n\n const itemStyleProps = {\n padding,\n itemTitleColor,\n itemTitleSize,\n descriptionColor,\n descriptionSize,\n priceColor,\n priceSize,\n originalPriceColor,\n metaTextColor,\n metaTextSize,\n showMetaText,\n showBadge,\n borderRadius,\n imageAspectRatio,\n gap,\n };\n\n const hasFeaturedAsset = getFeaturedAssetUrl(featuredAsset);\n const shouldShowFeaturedSection = showFeaturedSection && hasFeaturedAsset;\n\n // Background styling\n const backgroundColor = background.color || \"background\";\n const backgroundImage =\n (background.resource?.image_url || background.resource?.imageUrl) &&\n background.type === \"image\"\n ? `url(${background.resource.image_url || background.resource.imageUrl})`\n : \"none\";\n\n const isOrderedHorizontal =\n listType === \"ordered\" && scrollAxis === \"horizontal\";\n const showScrollArrows =\n isOrderedHorizontal && hasItems && displayItems.length > 1;\n\n const { scrollContainerRef, canScrollPrev, canScrollNext, scrollByAmount } =\n useHorizontalScrollState({\n enabled: showScrollArrows,\n contentLength: displayItems.length,\n });\n\n const hasTitle = titleEnabled && title;\n const showTitleRow = hasTitle || showScrollArrows;\n\n return (\n <div\n className={`@container bg-${backgroundColor} p-${padding} rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n {showTitleRow && (\n <div className=\"mb-8 flex items-center justify-between gap-4\">\n {hasTitle ? (\n <h2\n className={`text-${titleColor} text-${titleSize === \"md\" ? \"base\" : titleSize} font-header leading-tight font-medium tracking-tight`}\n >\n {title}\n </h2>\n ) : (\n <span />\n )}\n {showScrollArrows && (\n <div className=\"flex shrink-0 items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => scrollByAmount(\"prev\")}\n disabled={!canScrollPrev}\n aria-label=\"Previous items\"\n className={`text-${numberColor} flex size-9 items-center justify-center rounded-full transition-opacity hover:opacity-60 disabled:cursor-not-allowed disabled:opacity-20`}\n style={{\n boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${numberColor}) 25%, transparent)`,\n }}\n >\n <ChevronLeft aria-hidden=\"true\" className=\"size-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => scrollByAmount(\"next\")}\n disabled={!canScrollNext}\n aria-label=\"Next items\"\n className={`text-${numberColor} flex size-9 items-center justify-center rounded-full transition-opacity hover:opacity-60 disabled:cursor-not-allowed disabled:opacity-20`}\n style={{\n boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${numberColor}) 25%, transparent)`,\n }}\n >\n <ChevronRight aria-hidden=\"true\" className=\"size-4\" />\n </button>\n </div>\n )}\n </div>\n )}\n {!hasItems ? (\n <div className=\"flex items-center justify-center py-20 text-center\">\n <p className=\"text-muted/70 text-sm tracking-tight\">\n No items to display\n </p>\n </div>\n ) : shouldShowFeaturedSection ? (\n <div className=\"flex flex-col gap-4 @lg:flex-row @lg:gap-6\">\n <div className=\"w-full @lg:w-[45%]\">\n <FeaturedSection\n borderRadius={borderRadius}\n titleSize={titleSize}\n featuredTitle={featuredTitle}\n featuredSubtitle={featuredSubtitle}\n featuredButtonText={featuredButtonText}\n featuredButtonUrl={featuredButtonUrl}\n featuredSubtitleColor={featuredSubtitleColor}\n featuredSubtitleSize={featuredSubtitleSize}\n asset={hasFeaturedAsset!}\n />\n </div>\n <div className=\"w-full @lg:w-[55%]\">\n {listType === \"unordered\" ? (\n <UnorderedList\n items={displayItems}\n columns={columns}\n {...itemStyleProps}\n />\n ) : (\n <OrderedList\n items={displayItems}\n scrollAxis={scrollAxis}\n numberColor={numberColor}\n numberSize={numberSize}\n scrollContainerRef={\n isOrderedHorizontal ? scrollContainerRef : undefined\n }\n {...itemStyleProps}\n />\n )}\n </div>\n </div>\n ) : listType === \"unordered\" ? (\n <UnorderedList\n items={displayItems}\n columns={columns}\n {...itemStyleProps}\n />\n ) : (\n <OrderedList\n items={displayItems}\n scrollAxis={scrollAxis}\n numberColor={numberColor}\n numberSize={numberSize}\n scrollContainerRef={\n isOrderedHorizontal ? scrollContainerRef : undefined\n }\n {...itemStyleProps}\n />\n )}\n </div>\n );\n}\n\n// ----- Hooks -----\n\nconst SCROLL_BUTTON_AMOUNT = 300;\nconst SCROLL_EDGE_TOLERANCE = 4;\nconst useIsomorphicLayoutEffect =\n typeof window !== \"undefined\" ? useLayoutEffect : useEffect;\n\ntype HorizontalScrollState = {\n scrollContainerRef: React.RefObject<HTMLDivElement | null>;\n canScrollPrev: boolean;\n canScrollNext: boolean;\n scrollByAmount: (direction: \"prev\" | \"next\") => void;\n};\n\n// Tracks horizontal scroll position of an external container so the parent\n// can drive prev/next arrow disabled states from a single source of truth.\n// Both edges initialize to `false` and are populated by the post-mount\n// measurement, avoiding a brief enabled-then-disabled flicker when content\n// fits entirely within the viewport.\nfunction useHorizontalScrollState({\n enabled,\n contentLength,\n}: {\n enabled: boolean;\n contentLength: number;\n}): HorizontalScrollState {\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n const [canScrollPrev, setCanScrollPrev] = useState(false);\n const [canScrollNext, setCanScrollNext] = useState(false);\n\n const resetScrollState = useCallback(() => {\n setCanScrollPrev(false);\n setCanScrollNext(false);\n }, []);\n\n const updateScrollState = useCallback(() => {\n const el = scrollContainerRef.current;\n if (!enabled || !el) {\n resetScrollState();\n return;\n }\n setCanScrollPrev(el.scrollLeft > SCROLL_EDGE_TOLERANCE);\n setCanScrollNext(\n el.scrollLeft + el.clientWidth < el.scrollWidth - SCROLL_EDGE_TOLERANCE,\n );\n }, [enabled, resetScrollState]);\n\n // Fires synchronously before paint so the arrows reflect post-layout\n // geometry without a flicker. `updateScrollState` is memoized on\n // `enabled`, so this only fires on mount and when toggling enablement —\n // not on every render.\n useIsomorphicLayoutEffect(() => {\n updateScrollState();\n }, [updateScrollState]);\n\n useEffect(() => {\n if (!enabled) {\n resetScrollState();\n return undefined;\n }\n\n const el = scrollContainerRef.current;\n if (!el) {\n resetScrollState();\n return undefined;\n }\n\n updateScrollState();\n el.addEventListener(\"scroll\", updateScrollState, { passive: true });\n const resize =\n typeof ResizeObserver !== \"undefined\"\n ? new ResizeObserver(updateScrollState)\n : undefined;\n resize?.observe(el);\n\n return () => {\n el.removeEventListener(\"scroll\", updateScrollState);\n resize?.disconnect();\n };\n }, [enabled, resetScrollState, updateScrollState, contentLength]);\n\n const scrollByAmount = useCallback((direction: \"prev\" | \"next\") => {\n const el = scrollContainerRef.current;\n if (!el) return;\n const computedGap = parseFloat(getComputedStyle(el).gap) || 0;\n const amount = SCROLL_BUTTON_AMOUNT + computedGap;\n el.scrollTo({\n left: el.scrollLeft + (direction === \"next\" ? amount : -amount),\n behavior: \"smooth\",\n });\n }, []);\n\n return { scrollContainerRef, canScrollPrev, canScrollNext, scrollByAmount };\n}\n\nexport const listWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"ListWidget\",\n displayName: \"List\",\n tabsConfig: [\n { id: \"styling\", label: \"Styling\" },\n { id: \"data\", label: \"Data\" },\n ],\n dataSourceTargetProps: [\"items\"],\n fields: [\n // Styling tab - Title group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed above the list\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"title\",\n label: \"Title\",\n type: \"text\",\n description: \"Header text for the list\",\n defaultValue: \"List\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n key: \"titleSize\",\n label: \"Title Font Size\",\n description: \"Size of the list title\",\n defaultValue: \"xl\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the list title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n\n // Styling tab - Design group\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding inside the container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Rounded corners for the container and images\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the widget\",\n defaultValue: \"none\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the widget\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getGapField({\n key: \"gap\",\n label: \"Gap\",\n description: \"Spacing between items\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n type: \"background\",\n defaultValue: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background color or image for the widget\",\n tab: \"styling\",\n group: \"Design\",\n },\n\n // Styling tab - List Configuration group\n {\n key: \"listType\",\n label: \"List Type\",\n type: \"select\",\n description: \"Type of list layout\",\n defaultValue: \"unordered\",\n options: [\n { label: \"Unordered (Grid)\", value: \"unordered\" },\n { label: \"Ordered (Numbered)\", value: \"ordered\" },\n ],\n tab: \"styling\",\n group: \"List Configuration\",\n },\n {\n key: \"maxItems\",\n label: \"Max Items\",\n type: \"number\",\n description: \"Maximum number of items to display\",\n min: 1,\n max: 100,\n step: 1,\n defaultValue: 12,\n tab: \"styling\",\n group: \"List Configuration\",\n },\n {\n key: \"imageAspectRatio\",\n label: \"Image Aspect Ratio\",\n type: \"buttonGroup\",\n description:\n \"Aspect ratio for item images (unordered list — ordered layouts use a fixed ratio per axis)\",\n defaultValue: \"square\",\n options: [\n { label: \"Square\", value: \"square\" },\n { label: \"Landscape\", value: \"landscape\" },\n { label: \"Portrait\", value: \"portrait\" },\n ],\n tab: \"styling\",\n group: \"List Configuration\",\n requiresKeyValue: { key: \"listType\", value: \"unordered\" },\n },\n {\n key: \"showBadge\",\n label: \"Show Discount Badge\",\n type: \"boolean\",\n description: \"Display discount badge on images\",\n defaultValue: true,\n tab: \"styling\",\n group: \"List Configuration\",\n },\n {\n key: \"showMetaText\",\n label: \"Show QV/CV Text\",\n type: \"boolean\",\n description: \"Display QV and CV values\",\n defaultValue: true,\n tab: \"styling\",\n group: \"List Configuration\",\n },\n\n // Styling tab - Unordered List Configuration\n {\n key: \"columns\",\n label: \"Grid Columns\",\n type: \"number\",\n description: \"Number of columns in the grid (unordered list only)\",\n min: 1,\n max: 6,\n step: 1,\n defaultValue: 3,\n tab: \"styling\",\n group: \"Unordered List Configuration\",\n requiresKeyValue: { key: \"listType\", value: \"unordered\" },\n },\n\n // Styling tab - Ordered List Configuration\n {\n key: \"scrollAxis\",\n label: \"Scroll Direction\",\n type: \"select\",\n description: \"Direction for ordered list scrolling\",\n defaultValue: \"horizontal\",\n options: [\n { label: \"Horizontal\", value: \"horizontal\" },\n { label: \"Vertical\", value: \"vertical\" },\n ],\n tab: \"styling\",\n group: \"Ordered List Configuration\",\n requiresKeyValue: { key: \"listType\", value: \"ordered\" },\n },\n getColorField({\n key: \"numberColor\",\n label: \"Number Color\",\n description: \"Color for ordered list numbers\",\n defaultValue: \"primary\",\n tab: \"styling\",\n group: \"Ordered List Configuration\",\n requiresKeyValue: { key: \"listType\", value: \"ordered\" },\n }),\n getFontSizeField({\n key: \"numberSize\",\n label: \"Number Font Size\",\n description:\n \"Size of ordered list numbers (vertical scroll only — horizontal uses a fixed editorial size)\",\n defaultValue: \"2xl\",\n tab: \"styling\",\n group: \"Ordered List Configuration\",\n requiresKeyValue: [\n { key: \"listType\", value: \"ordered\" },\n { key: \"scrollAxis\", value: \"vertical\" },\n ],\n }),\n\n // Styling tab - Item Styling group\n getColorField({\n key: \"itemTitleColor\",\n label: \"Item Title Color\",\n description: \"Color for item titles\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n getFontSizeField({\n key: \"itemTitleSize\",\n label: \"Item Title Font Size\",\n description: \"Size of item titles\",\n defaultValue: \"sm\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n {\n key: \"separator2\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Item Styling\",\n },\n getColorField({\n key: \"descriptionColor\",\n label: \"Description Color\",\n description: \"Color for descriptions\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n getFontSizeField({\n key: \"descriptionSize\",\n label: \"Description Font Size\",\n description: \"Size of descriptions\",\n defaultValue: \"sm\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n {\n key: \"separator3\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Item Styling\",\n },\n getColorField({\n key: \"priceColor\",\n label: \"Price Color\",\n description: \"Color for prices\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n getFontSizeField({\n key: \"priceSize\",\n label: \"Price Font Size\",\n description: \"Size of prices\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n getColorField({\n key: \"originalPriceColor\",\n label: \"Original Price Color\",\n description: \"Color for crossed-out original prices\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n {\n key: \"separator4\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Item Styling\",\n },\n getColorField({\n key: \"metaTextColor\",\n label: \"Meta Text Color\",\n description: \"Color for QV/CV text\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n getFontSizeField({\n key: \"metaTextSize\",\n label: \"Meta Text Font Size\",\n description: \"Size of QV/CV text\",\n defaultValue: \"xs\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n\n // Styling tab - Featured Section group\n {\n key: \"showFeaturedSection\",\n label: \"Show Featured Section\",\n type: \"boolean\",\n description: \"Display a featured content section\",\n defaultValue: false,\n tab: \"styling\",\n group: \"Featured Section\",\n },\n {\n key: \"featuredAsset\",\n label: \"Featured Asset\",\n type: \"resource\",\n description:\n \"Select a single image or video resource for the featured section\",\n tab: \"styling\",\n group: \"Featured Section\",\n allowedTypes: [\"Medium\"],\n requiresKeyToBeTrue: \"showFeaturedSection\",\n },\n {\n key: \"featuredTitle\",\n label: \"Featured Title\",\n type: \"text\",\n description: \"Title for featured section\",\n tab: \"styling\",\n group: \"Featured Section\",\n requiresKeyToBeTrue: \"showFeaturedSection\",\n },\n {\n key: \"featuredSubtitle\",\n label: \"Featured Subtitle\",\n type: \"text\",\n description: \"Subtitle for featured section\",\n tab: \"styling\",\n group: \"Featured Section\",\n requiresKeyToBeTrue: \"showFeaturedSection\",\n },\n {\n key: \"featuredButtonText\",\n label: \"Featured Button Text\",\n type: \"text\",\n description: \"Text for featured section button\",\n tab: \"styling\",\n group: \"Featured Section\",\n requiresKeyToBeTrue: \"showFeaturedSection\",\n },\n {\n key: \"featuredButtonUrl\",\n label: \"Featured Button URL\",\n type: \"text\",\n description: \"URL for featured section button\",\n tab: \"styling\",\n group: \"Featured Section\",\n requiresKeyToBeTrue: \"showFeaturedSection\",\n },\n getColorField({\n key: \"featuredSubtitleColor\",\n label: \"Featured Subtitle Color\",\n description: \"Color for featured subtitle\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Featured Section\",\n requiresKeyToBeTrue: \"showFeaturedSection\",\n }),\n getFontSizeField({\n key: \"featuredSubtitleSize\",\n label: \"Featured Subtitle Font Size\",\n description: \"Size of featured subtitle\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Featured Section\",\n requiresKeyToBeTrue: \"showFeaturedSection\",\n }),\n\n // Data tab - Data Configuration\n {\n key: \"dataSource\",\n label: \"Data Source\",\n type: \"dataSource\",\n description: \"\",\n tab: \"data\",\n group: \"Data Configuration\",\n },\n ],\n itemConfigSchema: {\n description: \"Configure settings for this list item\",\n fields: [\n {\n key: \"title\",\n label: \"Custom Title\",\n type: \"text\",\n description: \"Override the item's title\",\n },\n {\n key: \"description\",\n label: \"Custom Description\",\n type: \"textarea\",\n description: \"Override the item's description\",\n rows: 3,\n },\n {\n key: \"price\",\n label: \"Price\",\n type: \"text\",\n description: \"Current price\",\n },\n {\n key: \"originalPrice\",\n label: \"Original Price\",\n type: \"text\",\n description: \"Original price (will be crossed out)\",\n },\n {\n key: \"discount\",\n label: \"Discount Badge\",\n type: \"text\",\n description: \"Discount text (e.g., '40% Off')\",\n },\n {\n key: \"qv\",\n label: \"QV Value\",\n type: \"text\",\n description: \"Qualifying Volume value\",\n },\n {\n key: \"cv\",\n label: \"CV Value\",\n type: \"text\",\n description: \"Commission Volume value\",\n },\n {\n key: \"image\",\n label: \"Image URL\",\n type: \"text\",\n description: \"Custom image URL for this item\",\n },\n ],\n },\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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F,iBAAiB;GACf,KAAK;GACL,OAAO;GACP,aACE;GACF,cAAc;GACd,KAAK;GACL,OAAO;GACP,kBAAkB,CAChB;IAAE,KAAK;IAAY,OAAO;IAAW,EACrC;IAAE,KAAK;IAAc,OAAO;IAAY,CACzC;GACF,CAAC;EAGF,cAAc;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,iBAAiB;GACf,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,MAAM;GACN,OAAO;GACP,KAAK;GACL,OAAO;GACR;EACD,cAAc;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,iBAAiB;GACf,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,MAAM;GACN,OAAO;GACP,KAAK;GACL,OAAO;GACR;EACD,cAAc;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,iBAAiB;GACf,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,cAAc;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,MAAM;GACN,OAAO;GACP,KAAK;GACL,OAAO;GACR;EACD,cAAc;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,iBAAiB;GACf,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EAGF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aACE;GACF,KAAK;GACL,OAAO;GACP,cAAc,CAAC,SAAS;GACxB,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD,cAAc;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;EACF,iBAAiB;GACf,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;EAGF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACR;EACF;CACD,kBAAkB;EAChB,aAAa;EACb,QAAQ;GACN;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACb,MAAM;IACP;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACF;EACF;CACF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ListWidget-IxrLNslF.cjs","names":["MediaRenderer","DOMPurify","getImageUrl","useWidgetInteraction","gapValues","useWidgetInteraction","gapValues","borderWidthClasses","borderColorClasses","ChevronLeft","ChevronRight","useLayoutEffect","useEffect","getFontSizeField","getColorField","getPaddingField","getBorderRadiusField","getBorderWidthField","getBorderColorField","getGapField"],"sources":["../../widgets/src/widgets/list-widget/helpers.ts","../../widgets/src/widgets/list-widget/FeaturedSection.tsx","../../widgets/src/widgets/list-widget/ListItemCard.tsx","../../widgets/src/widgets/list-widget/UnorderedList.tsx","../../widgets/src/widgets/list-widget/OrderedList.tsx","../../widgets/src/widgets/ListWidget.tsx"],"sourcesContent":["import type { BorderRadiusOptions } from \"@fluid-app/portal-core/types\";\n\n/**\n * Maps the schema's BorderRadiusOptions to a Tailwind `rounded-*` class.\n * `\"full\"` is converted to `rounded-2xl` because the list item cards and\n * featured section read better as large-radius rectangles than as\n * pill-shaped containers.\n */\nexport const cardRadiusClass = (radius: BorderRadiusOptions): string =>\n radius === \"full\" ? \"rounded-2xl\" : `rounded-${radius}`;\n","import type React from \"react\";\nimport type {\n BorderRadiusOptions,\n FontSizeOptions,\n ColorOptions,\n} from \"@fluid-app/portal-core/types\";\nimport { MediaRenderer } from \"../../components/MediaRenderer\";\nimport { cardRadiusClass } from \"./helpers\";\n\ninterface FeaturedSectionProps {\n borderRadius: BorderRadiusOptions;\n titleSize: FontSizeOptions;\n featuredTitle?: string | undefined;\n featuredSubtitle?: string | undefined;\n featuredButtonText?: string | undefined;\n featuredButtonUrl?: string | undefined;\n featuredSubtitleColor: ColorOptions;\n featuredSubtitleSize: FontSizeOptions;\n asset: { url: string; isVideo: boolean };\n}\n\nexport function FeaturedSection({\n borderRadius,\n titleSize,\n featuredTitle,\n featuredSubtitle,\n featuredButtonText,\n featuredButtonUrl,\n featuredSubtitleColor,\n featuredSubtitleSize,\n asset,\n}: FeaturedSectionProps): React.JSX.Element {\n return (\n <div\n className={`group relative h-full min-h-[320px] w-full overflow-hidden ${cardRadiusClass(borderRadius)}`}\n >\n <div className=\"absolute inset-0 h-full w-full\">\n <MediaRenderer\n src={asset.url}\n mediaType={asset.isVideo ? \"video\" : \"image\"}\n alt={featuredTitle || \"Featured\"}\n objectFit=\"cover\"\n autoplay={asset.isVideo}\n loop={asset.isVideo}\n muted={asset.isVideo}\n controls={false}\n />\n </div>\n\n <div\n className=\"pointer-events-none absolute inset-0\"\n style={{\n background:\n \"linear-gradient(180deg, rgba(0,0,0,0) 45%, rgba(0,0,0,0.55) 100%)\",\n }}\n />\n\n <div className=\"absolute inset-0 flex flex-col items-start justify-end p-10\">\n {featuredTitle && (\n <h3\n className={`font-header mb-3 font-medium tracking-tight text-white text-${titleSize === \"md\" ? \"base\" : titleSize}`}\n >\n {featuredTitle}\n </h3>\n )}\n {featuredSubtitle && (\n <p\n className={`mb-6 max-w-md text-${featuredSubtitleColor}/80 text-${featuredSubtitleSize === \"md\" ? \"base\" : featuredSubtitleSize} leading-relaxed`}\n >\n {featuredSubtitle}\n </p>\n )}\n {featuredButtonText && (\n <a\n href={featuredButtonUrl || \"#\"}\n className={`text-foreground inline-flex items-center gap-2 bg-white px-6 py-3 text-sm font-medium tracking-tight transition-opacity hover:opacity-90 ${cardRadiusClass(borderRadius)}`}\n >\n {featuredButtonText}\n <span\n aria-hidden=\"true\"\n className=\"transition-transform group-hover:translate-x-0.5\"\n >\n →\n </span>\n </a>\n )}\n </div>\n </div>\n );\n}\n","import type React from \"react\";\nimport DOMPurify from \"dompurify\";\nimport type {\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\n\ntype ListItem = {\n id: string;\n image?: string;\n imageUrl?: string;\n videoUrl?: string;\n title?: string;\n description?: string;\n price?: string;\n display_price?: string;\n originalPrice?: string;\n discount?: string;\n qv?: string;\n cv?: string;\n [key: string]: unknown;\n};\n\nfunction getStringValue(value: unknown): string {\n if (!value) return \"\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\") return String(value);\n if (typeof value === \"object\" && value !== null) {\n if (\"body\" in value) {\n const body = (value as { body: unknown }).body;\n if (typeof body === \"string\") return body;\n }\n if (\"text\" in value) {\n const text = (value as { text: unknown }).text;\n if (typeof text === \"string\") return text;\n }\n if (\"value\" in value) {\n const val = (value as { value: unknown }).value;\n if (typeof val === \"string\") return val;\n if (typeof val === \"number\") return String(val);\n }\n }\n return \"\";\n}\n\nfunction stripParentheticalText(text: string): string {\n return text.replace(/\\s*\\([^)]*\\)/g, \"\").trim();\n}\n\nfunction formatPrice(value: unknown): string {\n const str = getStringValue(value);\n if (!str) return \"\";\n return stripParentheticalText(str);\n}\n\nexport interface ListItemCardContentProps {\n item: ListItem;\n padding: PaddingOptions;\n itemTitleColor: ColorOptions;\n itemTitleSize: FontSizeOptions;\n descriptionColor: ColorOptions;\n descriptionSize: FontSizeOptions;\n priceColor: ColorOptions;\n priceSize: FontSizeOptions;\n originalPriceColor: ColorOptions;\n metaTextColor: ColorOptions;\n metaTextSize: FontSizeOptions;\n showMetaText: boolean;\n}\n\nexport function ListItemCardContent({\n item,\n padding,\n itemTitleColor,\n itemTitleSize,\n descriptionColor,\n descriptionSize,\n priceColor,\n priceSize,\n originalPriceColor,\n metaTextColor,\n metaTextSize,\n showMetaText,\n}: ListItemCardContentProps): React.JSX.Element {\n const hasPrice = Boolean(item.display_price || item.price);\n const hasOriginal = Boolean(item.originalPrice);\n\n return (\n <div className={`flex flex-1 flex-col p-${padding}`}>\n {item.title && (\n <h3\n className={`text-${itemTitleColor} text-${itemTitleSize === \"md\" ? \"base\" : itemTitleSize} font-header mb-1.5 leading-snug font-medium tracking-tight`}\n >\n {getStringValue(item.title)}\n </h3>\n )}\n {item.description && (\n <div\n className={`text-${descriptionColor}/60 text-${descriptionSize === \"md\" ? \"base\" : descriptionSize} mb-3 line-clamp-2 overflow-hidden leading-relaxed`}\n dangerouslySetInnerHTML={{\n __html: DOMPurify.sanitize(item.description ?? \"\", {\n ALLOWED_TAGS: [\n \"br\",\n \"strong\",\n \"em\",\n \"b\",\n \"i\",\n \"ul\",\n \"ol\",\n \"li\",\n \"p\",\n ],\n ALLOWED_ATTR: [],\n }),\n }}\n />\n )}\n {(hasPrice || hasOriginal) && (\n <div className=\"mt-auto flex items-baseline gap-2\">\n {hasPrice && (\n <span\n className={`text-${priceColor} text-${priceSize === \"md\" ? \"base\" : priceSize} font-semibold tracking-tight tabular-nums`}\n >\n {formatPrice(item.display_price || item.price)}\n </span>\n )}\n {hasOriginal && (\n <span\n className={`text-${originalPriceColor}/50 text-${descriptionSize === \"md\" ? \"base\" : descriptionSize} tabular-nums line-through`}\n >\n {formatPrice(item.originalPrice)}\n </span>\n )}\n </div>\n )}\n {showMetaText && (item.qv || item.cv) && (\n <div\n className={`mt-2 flex gap-4 text-${metaTextColor}/70 text-${metaTextSize === \"md\" ? \"base\" : metaTextSize} font-medium tracking-wide uppercase`}\n >\n {item.qv && (\n <span>\n <span className=\"opacity-50\">QV</span>{\" \"}\n <span className=\"tabular-nums\">{getStringValue(item.qv)}</span>\n </span>\n )}\n {item.cv && (\n <span>\n <span className=\"opacity-50\">CV</span>{\" \"}\n <span className=\"tabular-nums\">{getStringValue(item.cv)}</span>\n </span>\n )}\n </div>\n )}\n </div>\n );\n}\n\nexport function DiscountBadge({\n discount,\n}: {\n discount: string;\n}): React.JSX.Element {\n return (\n <div className=\"bg-background text-foreground absolute top-3 left-3 z-10 rounded-full px-2.5 py-1 text-[10px] font-semibold tracking-[0.08em] uppercase\">\n {getStringValue(discount)}\n </div>\n );\n}\n\nexport { getStringValue };\nexport type { ListItem };\n","import type React from \"react\";\nimport type {\n ColorOptions,\n FontSizeOptions,\n BorderRadiusOptions,\n PaddingOptions,\n GapOptions,\n} from \"@fluid-app/portal-core/types\";\nimport { gapValues } from \"../../core/fields\";\nimport { useWidgetInteraction } from \"../../contexts/WidgetInteractionContext\";\nimport {\n ListItemCardContent,\n DiscountBadge,\n type ListItem,\n} from \"./ListItemCard\";\nimport { cardRadiusClass } from \"./helpers\";\n\ntype ImageAspectRatio = \"square\" | \"landscape\" | \"portrait\";\n\nconst getImageUrl = (item: ListItem): string | undefined => {\n return item.imageUrl || item.image;\n};\n\nconst getAspectRatioClass = (ratio: ImageAspectRatio): string => {\n const ratios = {\n square: \"aspect-square\",\n landscape: \"aspect-video\",\n portrait: \"aspect-[3/4]\",\n };\n return ratios[ratio];\n};\n\nconst getResponsiveGridClass = (columns: number): string => {\n const responsiveClasses: Record<number, string> = {\n 1: \"grid-cols-2 @lg:grid-cols-1\",\n 2: \"grid-cols-2 @lg:grid-cols-2\",\n 3: \"grid-cols-2 @lg:grid-cols-3\",\n 4: \"grid-cols-2 @lg:grid-cols-4\",\n 5: \"grid-cols-2 @lg:grid-cols-5\",\n 6: \"grid-cols-2 @lg:grid-cols-6\",\n };\n return responsiveClasses[columns] || \"grid-cols-2 @lg:grid-cols-3\";\n};\n\nexport interface UnorderedListProps {\n items: ListItem[];\n columns: number;\n gap: GapOptions;\n borderRadius: BorderRadiusOptions;\n imageAspectRatio: ImageAspectRatio;\n showBadge: boolean;\n padding: PaddingOptions;\n itemTitleColor: ColorOptions;\n itemTitleSize: FontSizeOptions;\n descriptionColor: ColorOptions;\n descriptionSize: FontSizeOptions;\n priceColor: ColorOptions;\n priceSize: FontSizeOptions;\n originalPriceColor: ColorOptions;\n metaTextColor: ColorOptions;\n metaTextSize: FontSizeOptions;\n showMetaText: boolean;\n}\n\nexport function UnorderedList({\n items,\n columns,\n gap,\n borderRadius,\n imageAspectRatio,\n showBadge,\n padding,\n itemTitleColor,\n itemTitleSize,\n descriptionColor,\n descriptionSize,\n priceColor,\n priceSize,\n originalPriceColor,\n metaTextColor,\n metaTextSize,\n showMetaText,\n}: UnorderedListProps): React.JSX.Element {\n const gridClass = getResponsiveGridClass(columns);\n const { onItemClick } = useWidgetInteraction();\n\n return (\n <div className={`grid ${gridClass} gap-${gapValues[gap]}`}>\n {items.map((item) => {\n const imageUrl = getImageUrl(item);\n const aspectRatioClass = getAspectRatioClass(imageAspectRatio);\n\n return (\n <div\n key={item.id}\n className={`group relative flex flex-col ${onItemClick ? \"cursor-pointer\" : \"\"}`}\n {...(onItemClick\n ? {\n role: \"button\",\n tabIndex: 0,\n onClick: () => onItemClick(item),\n onKeyDown: (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onItemClick(item);\n }\n },\n }\n : {})}\n >\n {imageUrl && (\n <div\n className={`relative w-full ${aspectRatioClass} bg-muted/30 overflow-hidden ${cardRadiusClass(borderRadius)}`}\n >\n {showBadge && item.discount && (\n <DiscountBadge discount={item.discount} />\n )}\n <img\n src={imageUrl}\n alt={item.title || \"Product\"}\n className=\"h-full w-full object-cover transition-opacity duration-300 group-hover:opacity-90\"\n />\n </div>\n )}\n <div className=\"mt-4\">\n <ListItemCardContent\n item={item}\n padding={padding}\n itemTitleColor={itemTitleColor}\n itemTitleSize={itemTitleSize}\n descriptionColor={descriptionColor}\n descriptionSize={descriptionSize}\n priceColor={priceColor}\n priceSize={priceSize}\n originalPriceColor={originalPriceColor}\n metaTextColor={metaTextColor}\n metaTextSize={metaTextSize}\n showMetaText={showMetaText}\n />\n </div>\n </div>\n );\n })}\n </div>\n );\n}\n","import { useRef } from \"react\";\nimport type React from \"react\";\nimport type { RefObject } from \"react\";\nimport type {\n ColorOptions,\n FontSizeOptions,\n BorderRadiusOptions,\n PaddingOptions,\n GapOptions,\n} from \"@fluid-app/portal-core/types\";\nimport { gapValues } from \"../../core/fields\";\nimport { useWidgetInteraction } from \"../../contexts/WidgetInteractionContext\";\nimport {\n ListItemCardContent,\n DiscountBadge,\n getStringValue,\n type ListItem,\n} from \"./ListItemCard\";\nimport { cardRadiusClass } from \"./helpers\";\n\ntype ImageAspectRatio = \"square\" | \"landscape\" | \"portrait\";\ntype ScrollAxis = \"horizontal\" | \"vertical\";\n\nconst getImageUrl = (item: ListItem): string | undefined => {\n return item.imageUrl || item.image;\n};\n\nexport interface OrderedListProps {\n items: ListItem[];\n scrollAxis: ScrollAxis;\n gap: GapOptions;\n borderRadius: BorderRadiusOptions;\n imageAspectRatio: ImageAspectRatio;\n showBadge: boolean;\n padding: PaddingOptions;\n itemTitleColor: ColorOptions;\n itemTitleSize: FontSizeOptions;\n descriptionColor: ColorOptions;\n descriptionSize: FontSizeOptions;\n priceColor: ColorOptions;\n priceSize: FontSizeOptions;\n originalPriceColor: ColorOptions;\n metaTextColor: ColorOptions;\n metaTextSize: FontSizeOptions;\n numberColor: ColorOptions;\n numberSize: FontSizeOptions;\n showMetaText: boolean;\n /** Optional ref from the parent to control horizontal scroll externally */\n scrollContainerRef?: RefObject<HTMLDivElement | null> | undefined;\n}\n\nconst formatRank = (n: number): string => (n < 10 ? `0${n}` : String(n));\n\nexport function OrderedList({\n items,\n scrollAxis,\n gap,\n borderRadius,\n // imageAspectRatio is intentionally not consumed — ordered layouts use a\n // fixed aspect ratio per axis (3:4 poster horizontal, 16x16 thumb vertical)\n // by design. The schema gates this field to unordered lists.\n imageAspectRatio: _imageAspectRatio,\n showBadge,\n padding,\n itemTitleColor,\n itemTitleSize,\n descriptionColor,\n descriptionSize,\n priceColor,\n priceSize,\n originalPriceColor,\n metaTextColor,\n metaTextSize,\n numberColor,\n numberSize,\n showMetaText,\n scrollContainerRef: externalScrollRef,\n}: OrderedListProps): React.JSX.Element | null {\n const internalScrollRef = useRef<HTMLDivElement>(null);\n const scrollContainerRef = externalScrollRef ?? internalScrollRef;\n\n const { onItemClick } = useWidgetInteraction();\n\n const interactionProps = (item: ListItem) =>\n onItemClick\n ? ({\n role: \"button\" as const,\n tabIndex: 0,\n onClick: () => onItemClick(item),\n onKeyDown: (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onItemClick(item);\n }\n },\n } as const)\n : {};\n\n const contentProps = {\n padding,\n itemTitleColor,\n itemTitleSize,\n descriptionColor,\n descriptionSize,\n priceColor,\n priceSize,\n originalPriceColor,\n metaTextColor,\n metaTextSize,\n showMetaText,\n };\n\n if (scrollAxis === \"horizontal\") {\n return (\n <div className=\"relative\">\n <div\n ref={scrollContainerRef}\n className={`flex gap-${gapValues[gap]} scrollbar-hide overflow-x-auto overflow-y-hidden scroll-smooth`}\n >\n {items.map((item, index) => {\n const imageUrl = getImageUrl(item);\n const rank = index + 1;\n\n return (\n <div\n key={item.id}\n className={`group relative flex flex-shrink-0 flex-col ${onItemClick ? \"cursor-pointer\" : \"\"}`}\n {...interactionProps(item)}\n >\n <div className=\"flex items-end\">\n <span className=\"sr-only\">Rank {rank}: </span>\n <span\n className={`text-${numberColor} pointer-events-none flex-shrink-0 font-black italic tabular-nums select-none`}\n style={{\n fontSize: \"11rem\",\n lineHeight: \"0.82\",\n letterSpacing: \"-0.06em\",\n }}\n aria-hidden=\"true\"\n >\n {rank}\n </span>\n {imageUrl && (\n <div\n className={`relative aspect-[3/4] w-[200px] flex-shrink-0 ${cardRadiusClass(borderRadius)} bg-muted/30 overflow-hidden`}\n >\n {showBadge && item.discount && (\n <DiscountBadge discount={item.discount} />\n )}\n <img\n src={imageUrl}\n alt={item.title || \"Product\"}\n className=\"h-full w-full object-cover\"\n />\n </div>\n )}\n </div>\n <div className=\"mt-5 ml-auto w-[200px]\">\n <ListItemCardContent item={item} {...contentProps} />\n </div>\n </div>\n );\n })}\n </div>\n </div>\n );\n }\n\n if (scrollAxis === \"vertical\") {\n return (\n <div className={`flex flex-col gap-${gapValues[gap]}`}>\n {items.map((item, index) => {\n const imageUrl = getImageUrl(item);\n const rank = index + 1;\n const isLast = index === items.length - 1;\n\n return (\n <div\n key={item.id}\n className={`group relative flex items-center gap-${gapValues[gap]} py-6 ${!isLast ? \"border-b\" : \"\"} ${onItemClick ? \"cursor-pointer\" : \"\"}`}\n style={\n !isLast\n ? {\n borderColor:\n \"color-mix(in oklch, var(--color-foreground) 8%, transparent)\",\n }\n : undefined\n }\n {...interactionProps(item)}\n >\n <span className=\"sr-only\">Rank {rank}: </span>\n <span\n className={`text-${numberColor} font-header w-14 flex-shrink-0 text-${numberSize === \"md\" ? \"base\" : numberSize} leading-none font-light tracking-tight italic`}\n aria-hidden=\"true\"\n >\n {formatRank(rank)}\n </span>\n {imageUrl && (\n <div\n className={`relative h-16 w-16 flex-shrink-0 overflow-hidden ${cardRadiusClass(borderRadius)} bg-muted/30`}\n >\n <img\n src={imageUrl}\n alt={item.title || \"Product\"}\n className=\"h-full w-full object-cover\"\n />\n </div>\n )}\n <div className=\"min-w-0 flex-1\">\n <ListItemCardContent item={item} {...contentProps} />\n </div>\n {showBadge && item.discount && (\n <span className=\"text-muted ml-2 flex-shrink-0 text-[10px] font-semibold tracking-[0.08em] uppercase\">\n {getStringValue(item.discount)}\n </span>\n )}\n </div>\n );\n })}\n </div>\n );\n }\n\n return null;\n}\n","import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type ComponentProps,\n} from \"react\";\nimport type React from \"react\";\nimport { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport type {\n BorderWidthOptions,\n ColorOptions,\n FontSizeOptions,\n BorderRadiusOptions,\n PaddingOptions,\n GapOptions,\n BackgroundValue,\n} from \"@fluid-app/portal-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getBorderWidthField,\n getBorderColorField,\n borderWidthClasses,\n borderColorClasses,\n getColorField,\n getFontSizeField,\n getPaddingField,\n getGapField,\n} from \"../core/fields\";\nimport { FeaturedSection } from \"./list-widget/FeaturedSection\";\nimport { UnorderedList } from \"./list-widget/UnorderedList\";\nimport { OrderedList } from \"./list-widget/OrderedList\";\n\nconst DEFAULT_ITEMS: ListItem[] = [];\n\ntype ListItem = {\n id: string;\n image?: string;\n imageUrl?: string;\n videoUrl?: string;\n title?: string;\n description?: string;\n price?: string;\n originalPrice?: string;\n discount?: string;\n qv?: string;\n cv?: string;\n [key: string]: unknown;\n};\n\ntype ImageAspectRatio = \"square\" | \"landscape\" | \"portrait\";\ntype ListType = \"ordered\" | \"unordered\";\ntype ScrollAxis = \"horizontal\" | \"vertical\";\n\ntype ListWidgetProps = ComponentProps<\"div\"> & {\n // List configuration\n listType?: ListType;\n scrollAxis?: ScrollAxis;\n titleEnabled?: boolean;\n title?: string;\n items?: ListItem[];\n\n // Text styling\n titleColor?: ColorOptions;\n titleSize?: FontSizeOptions;\n itemTitleColor?: ColorOptions;\n itemTitleSize?: FontSizeOptions;\n descriptionColor?: ColorOptions;\n descriptionSize?: FontSizeOptions;\n priceColor?: ColorOptions;\n priceSize?: FontSizeOptions;\n originalPriceColor?: ColorOptions;\n metaTextColor?: ColorOptions;\n metaTextSize?: FontSizeOptions;\n\n // Ordered list styling\n numberColor?: ColorOptions;\n numberSize?: FontSizeOptions;\n\n // Layout\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n padding?: PaddingOptions;\n gap?: GapOptions;\n columns?: number;\n imageAspectRatio?: ImageAspectRatio;\n background?: BackgroundValue;\n\n // Behavior\n showBadge?: boolean;\n showMetaText?: boolean;\n maxItems?: number;\n\n // Featured section\n showFeaturedSection?: boolean;\n featuredAsset?: string | { [key: string]: unknown };\n featuredTitle?: string;\n featuredSubtitle?: string;\n featuredButtonText?: string;\n featuredButtonUrl?: string;\n featuredSubtitleColor?: ColorOptions;\n featuredSubtitleSize?: FontSizeOptions;\n};\n\nfunction getFeaturedAssetUrl(\n value: string | { [key: string]: unknown } | undefined,\n): { url: string; isVideo: boolean } | undefined {\n if (!value) return undefined;\n\n // Handle string URLs\n if (typeof value === \"string\") {\n const isVideo = /\\.(mp4|webm|ogg|mov)$/i.test(value);\n return { url: value, isVideo };\n }\n\n // Handle ShareableItem objects\n if (typeof value === \"object\") {\n // Check for video URL first\n const videoUrl =\n (value.videoUrl as string) ||\n (value.video_url as string) ||\n (value.url as string);\n if (videoUrl && /\\.(mp4|webm|ogg|mov)$/i.test(videoUrl)) {\n return { url: videoUrl, isVideo: true };\n }\n\n // Fall back to image URL\n const imageUrl =\n (value.imageUrl as string) ||\n (value.image_url as string) ||\n (value.url as string);\n if (imageUrl) {\n return { url: imageUrl, isVideo: false };\n }\n }\n\n return undefined;\n}\n\nexport function ListWidget({\n listType = \"unordered\",\n scrollAxis = \"horizontal\",\n titleEnabled = true,\n title,\n items = DEFAULT_ITEMS,\n titleColor = \"foreground\",\n titleSize = \"lg\",\n itemTitleColor = \"foreground\",\n itemTitleSize = \"sm\",\n descriptionColor = \"foreground\",\n descriptionSize = \"sm\",\n priceColor = \"foreground\",\n priceSize = \"md\",\n originalPriceColor = \"muted\",\n metaTextColor = \"muted\",\n metaTextSize = \"xs\",\n numberColor = \"primary\",\n numberSize = \"2xl\",\n borderRadius = \"md\",\n borderWidth = \"none\",\n borderColor = \"muted\",\n padding = 4,\n gap = \"md\",\n columns = 3,\n imageAspectRatio = \"square\",\n background = { type: \"solid\", color: \"background\" },\n showBadge = true,\n showMetaText = true,\n maxItems = 12,\n showFeaturedSection = false,\n featuredAsset,\n featuredTitle,\n featuredSubtitle,\n featuredButtonText,\n featuredButtonUrl,\n featuredSubtitleColor = \"background\",\n featuredSubtitleSize = \"md\",\n className,\n ...props\n}: ListWidgetProps): React.JSX.Element {\n const displayItems = maxItems ? items.slice(0, maxItems) : items;\n const hasItems = displayItems.length > 0;\n\n const itemStyleProps = {\n padding,\n itemTitleColor,\n itemTitleSize,\n descriptionColor,\n descriptionSize,\n priceColor,\n priceSize,\n originalPriceColor,\n metaTextColor,\n metaTextSize,\n showMetaText,\n showBadge,\n borderRadius,\n imageAspectRatio,\n gap,\n };\n\n const hasFeaturedAsset = getFeaturedAssetUrl(featuredAsset);\n const shouldShowFeaturedSection = showFeaturedSection && hasFeaturedAsset;\n\n // Background styling\n const backgroundColor = background.color || \"background\";\n const backgroundImage =\n (background.resource?.image_url || background.resource?.imageUrl) &&\n background.type === \"image\"\n ? `url(${background.resource.image_url || background.resource.imageUrl})`\n : \"none\";\n\n const isOrderedHorizontal =\n listType === \"ordered\" && scrollAxis === \"horizontal\";\n const showScrollArrows =\n isOrderedHorizontal && hasItems && displayItems.length > 1;\n\n const { scrollContainerRef, canScrollPrev, canScrollNext, scrollByAmount } =\n useHorizontalScrollState({\n enabled: showScrollArrows,\n contentLength: displayItems.length,\n });\n\n const hasTitle = titleEnabled && title;\n const showTitleRow = hasTitle || showScrollArrows;\n\n return (\n <div\n className={`@container bg-${backgroundColor} p-${padding} rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n {showTitleRow && (\n <div className=\"mb-8 flex items-center justify-between gap-4\">\n {hasTitle ? (\n <h2\n className={`text-${titleColor} text-${titleSize === \"md\" ? \"base\" : titleSize} font-header leading-tight font-medium tracking-tight`}\n >\n {title}\n </h2>\n ) : (\n <span />\n )}\n {showScrollArrows && (\n <div className=\"flex shrink-0 items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => scrollByAmount(\"prev\")}\n disabled={!canScrollPrev}\n aria-label=\"Previous items\"\n className={`text-${numberColor} flex size-9 items-center justify-center rounded-full transition-opacity hover:opacity-60 disabled:cursor-not-allowed disabled:opacity-20`}\n style={{\n boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${numberColor}) 25%, transparent)`,\n }}\n >\n <ChevronLeft aria-hidden=\"true\" className=\"size-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => scrollByAmount(\"next\")}\n disabled={!canScrollNext}\n aria-label=\"Next items\"\n className={`text-${numberColor} flex size-9 items-center justify-center rounded-full transition-opacity hover:opacity-60 disabled:cursor-not-allowed disabled:opacity-20`}\n style={{\n boxShadow: `inset 0 0 0 1px color-mix(in oklch, var(--color-${numberColor}) 25%, transparent)`,\n }}\n >\n <ChevronRight aria-hidden=\"true\" className=\"size-4\" />\n </button>\n </div>\n )}\n </div>\n )}\n {!hasItems ? (\n <div className=\"flex items-center justify-center py-20 text-center\">\n <p className=\"text-muted/70 text-sm tracking-tight\">\n No items to display\n </p>\n </div>\n ) : shouldShowFeaturedSection ? (\n <div className=\"flex flex-col gap-4 @lg:flex-row @lg:gap-6\">\n <div className=\"w-full @lg:w-[45%]\">\n <FeaturedSection\n borderRadius={borderRadius}\n titleSize={titleSize}\n featuredTitle={featuredTitle}\n featuredSubtitle={featuredSubtitle}\n featuredButtonText={featuredButtonText}\n featuredButtonUrl={featuredButtonUrl}\n featuredSubtitleColor={featuredSubtitleColor}\n featuredSubtitleSize={featuredSubtitleSize}\n asset={hasFeaturedAsset!}\n />\n </div>\n <div className=\"w-full @lg:w-[55%]\">\n {listType === \"unordered\" ? (\n <UnorderedList\n items={displayItems}\n columns={columns}\n {...itemStyleProps}\n />\n ) : (\n <OrderedList\n items={displayItems}\n scrollAxis={scrollAxis}\n numberColor={numberColor}\n numberSize={numberSize}\n scrollContainerRef={\n isOrderedHorizontal ? scrollContainerRef : undefined\n }\n {...itemStyleProps}\n />\n )}\n </div>\n </div>\n ) : listType === \"unordered\" ? (\n <UnorderedList\n items={displayItems}\n columns={columns}\n {...itemStyleProps}\n />\n ) : (\n <OrderedList\n items={displayItems}\n scrollAxis={scrollAxis}\n numberColor={numberColor}\n numberSize={numberSize}\n scrollContainerRef={\n isOrderedHorizontal ? scrollContainerRef : undefined\n }\n {...itemStyleProps}\n />\n )}\n </div>\n );\n}\n\n// ----- Hooks -----\n\nconst SCROLL_BUTTON_AMOUNT = 300;\nconst SCROLL_EDGE_TOLERANCE = 4;\nconst useIsomorphicLayoutEffect =\n typeof window !== \"undefined\" ? useLayoutEffect : useEffect;\n\ntype HorizontalScrollState = {\n scrollContainerRef: React.RefObject<HTMLDivElement | null>;\n canScrollPrev: boolean;\n canScrollNext: boolean;\n scrollByAmount: (direction: \"prev\" | \"next\") => void;\n};\n\n// Tracks horizontal scroll position of an external container so the parent\n// can drive prev/next arrow disabled states from a single source of truth.\n// Both edges initialize to `false` and are populated by the post-mount\n// measurement, avoiding a brief enabled-then-disabled flicker when content\n// fits entirely within the viewport.\nfunction useHorizontalScrollState({\n enabled,\n contentLength,\n}: {\n enabled: boolean;\n contentLength: number;\n}): HorizontalScrollState {\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n const [canScrollPrev, setCanScrollPrev] = useState(false);\n const [canScrollNext, setCanScrollNext] = useState(false);\n\n const resetScrollState = useCallback(() => {\n setCanScrollPrev(false);\n setCanScrollNext(false);\n }, []);\n\n const updateScrollState = useCallback(() => {\n const el = scrollContainerRef.current;\n if (!enabled || !el) {\n resetScrollState();\n return;\n }\n setCanScrollPrev(el.scrollLeft > SCROLL_EDGE_TOLERANCE);\n setCanScrollNext(\n el.scrollLeft + el.clientWidth < el.scrollWidth - SCROLL_EDGE_TOLERANCE,\n );\n }, [enabled, resetScrollState]);\n\n // Fires synchronously before paint so the arrows reflect post-layout\n // geometry without a flicker. `updateScrollState` is memoized on\n // `enabled`, so this only fires on mount and when toggling enablement —\n // not on every render.\n useIsomorphicLayoutEffect(() => {\n updateScrollState();\n }, [updateScrollState]);\n\n useEffect(() => {\n if (!enabled) {\n resetScrollState();\n return undefined;\n }\n\n const el = scrollContainerRef.current;\n if (!el) {\n resetScrollState();\n return undefined;\n }\n\n updateScrollState();\n el.addEventListener(\"scroll\", updateScrollState, { passive: true });\n const resize =\n typeof ResizeObserver !== \"undefined\"\n ? new ResizeObserver(updateScrollState)\n : undefined;\n resize?.observe(el);\n\n return () => {\n el.removeEventListener(\"scroll\", updateScrollState);\n resize?.disconnect();\n };\n }, [enabled, resetScrollState, updateScrollState, contentLength]);\n\n const scrollByAmount = useCallback((direction: \"prev\" | \"next\") => {\n const el = scrollContainerRef.current;\n if (!el) return;\n const computedGap = parseFloat(getComputedStyle(el).gap) || 0;\n const amount = SCROLL_BUTTON_AMOUNT + computedGap;\n el.scrollTo({\n left: el.scrollLeft + (direction === \"next\" ? amount : -amount),\n behavior: \"smooth\",\n });\n }, []);\n\n return { scrollContainerRef, canScrollPrev, canScrollNext, scrollByAmount };\n}\n\nexport const listWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"ListWidget\",\n displayName: \"List\",\n tabsConfig: [\n { id: \"styling\", label: \"Styling\" },\n { id: \"data\", label: \"Data\" },\n ],\n dataSourceTargetProps: [\"items\"],\n fields: [\n // Styling tab - Title group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed above the list\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"title\",\n label: \"Title\",\n type: \"text\",\n description: \"Header text for the list\",\n defaultValue: \"List\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n key: \"titleSize\",\n label: \"Title Font Size\",\n description: \"Size of the list title\",\n defaultValue: \"xl\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the list title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n\n // Styling tab - Design group\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding inside the container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Rounded corners for the container and images\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the widget\",\n defaultValue: \"none\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the widget\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getGapField({\n key: \"gap\",\n label: \"Gap\",\n description: \"Spacing between items\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n type: \"background\",\n defaultValue: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background color or image for the widget\",\n tab: \"styling\",\n group: \"Design\",\n },\n\n // Styling tab - List Configuration group\n {\n key: \"listType\",\n label: \"List Type\",\n type: \"select\",\n description: \"Type of list layout\",\n defaultValue: \"unordered\",\n options: [\n { label: \"Unordered (Grid)\", value: \"unordered\" },\n { label: \"Ordered (Numbered)\", value: \"ordered\" },\n ],\n tab: \"styling\",\n group: \"List Configuration\",\n },\n {\n key: \"maxItems\",\n label: \"Max Items\",\n type: \"number\",\n description: \"Maximum number of items to display\",\n min: 1,\n max: 100,\n step: 1,\n defaultValue: 12,\n tab: \"styling\",\n group: \"List Configuration\",\n },\n {\n key: \"imageAspectRatio\",\n label: \"Image Aspect Ratio\",\n type: \"buttonGroup\",\n description:\n \"Aspect ratio for item images (unordered list — ordered layouts use a fixed ratio per axis)\",\n defaultValue: \"square\",\n options: [\n { label: \"Square\", value: \"square\" },\n { label: \"Landscape\", value: \"landscape\" },\n { label: \"Portrait\", value: \"portrait\" },\n ],\n tab: \"styling\",\n group: \"List Configuration\",\n requiresKeyValue: { key: \"listType\", value: \"unordered\" },\n },\n {\n key: \"showBadge\",\n label: \"Show Discount Badge\",\n type: \"boolean\",\n description: \"Display discount badge on images\",\n defaultValue: true,\n tab: \"styling\",\n group: \"List Configuration\",\n },\n {\n key: \"showMetaText\",\n label: \"Show QV/CV Text\",\n type: \"boolean\",\n description: \"Display QV and CV values\",\n defaultValue: true,\n tab: \"styling\",\n group: \"List Configuration\",\n },\n\n // Styling tab - Unordered List Configuration\n {\n key: \"columns\",\n label: \"Grid Columns\",\n type: \"number\",\n description: \"Number of columns in the grid (unordered list only)\",\n min: 1,\n max: 6,\n step: 1,\n defaultValue: 3,\n tab: \"styling\",\n group: \"Unordered List Configuration\",\n requiresKeyValue: { key: \"listType\", value: \"unordered\" },\n },\n\n // Styling tab - Ordered List Configuration\n {\n key: \"scrollAxis\",\n label: \"Scroll Direction\",\n type: \"select\",\n description: \"Direction for ordered list scrolling\",\n defaultValue: \"horizontal\",\n options: [\n { label: \"Horizontal\", value: \"horizontal\" },\n { label: \"Vertical\", value: \"vertical\" },\n ],\n tab: \"styling\",\n group: \"Ordered List Configuration\",\n requiresKeyValue: { key: \"listType\", value: \"ordered\" },\n },\n getColorField({\n key: \"numberColor\",\n label: \"Number Color\",\n description: \"Color for ordered list numbers\",\n defaultValue: \"primary\",\n tab: \"styling\",\n group: \"Ordered List Configuration\",\n requiresKeyValue: { key: \"listType\", value: \"ordered\" },\n }),\n getFontSizeField({\n key: \"numberSize\",\n label: \"Number Font Size\",\n description:\n \"Size of ordered list numbers (vertical scroll only — horizontal uses a fixed editorial size)\",\n defaultValue: \"2xl\",\n tab: \"styling\",\n group: \"Ordered List Configuration\",\n requiresKeyValue: [\n { key: \"listType\", value: \"ordered\" },\n { key: \"scrollAxis\", value: \"vertical\" },\n ],\n }),\n\n // Styling tab - Item Styling group\n getColorField({\n key: \"itemTitleColor\",\n label: \"Item Title Color\",\n description: \"Color for item titles\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n getFontSizeField({\n key: \"itemTitleSize\",\n label: \"Item Title Font Size\",\n description: \"Size of item titles\",\n defaultValue: \"sm\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n {\n key: \"separator2\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Item Styling\",\n },\n getColorField({\n key: \"descriptionColor\",\n label: \"Description Color\",\n description: \"Color for descriptions\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n getFontSizeField({\n key: \"descriptionSize\",\n label: \"Description Font Size\",\n description: \"Size of descriptions\",\n defaultValue: \"sm\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n {\n key: \"separator3\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Item Styling\",\n },\n getColorField({\n key: \"priceColor\",\n label: \"Price Color\",\n description: \"Color for prices\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n getFontSizeField({\n key: \"priceSize\",\n label: \"Price Font Size\",\n description: \"Size of prices\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n getColorField({\n key: \"originalPriceColor\",\n label: \"Original Price Color\",\n description: \"Color for crossed-out original prices\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n {\n key: \"separator4\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Item Styling\",\n },\n getColorField({\n key: \"metaTextColor\",\n label: \"Meta Text Color\",\n description: \"Color for QV/CV text\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n getFontSizeField({\n key: \"metaTextSize\",\n label: \"Meta Text Font Size\",\n description: \"Size of QV/CV text\",\n defaultValue: \"xs\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n\n // Styling tab - Featured Section group\n {\n key: \"showFeaturedSection\",\n label: \"Show Featured Section\",\n type: \"boolean\",\n description: \"Display a featured content section\",\n defaultValue: false,\n tab: \"styling\",\n group: \"Featured Section\",\n },\n {\n key: \"featuredAsset\",\n label: \"Featured Asset\",\n type: \"resource\",\n description:\n \"Select a single image or video resource for the featured section\",\n tab: \"styling\",\n group: \"Featured Section\",\n allowedTypes: [\"Medium\"],\n requiresKeyToBeTrue: \"showFeaturedSection\",\n },\n {\n key: \"featuredTitle\",\n label: \"Featured Title\",\n type: \"text\",\n description: \"Title for featured section\",\n tab: \"styling\",\n group: \"Featured Section\",\n requiresKeyToBeTrue: \"showFeaturedSection\",\n },\n {\n key: \"featuredSubtitle\",\n label: \"Featured Subtitle\",\n type: \"text\",\n description: \"Subtitle for featured section\",\n tab: \"styling\",\n group: \"Featured Section\",\n requiresKeyToBeTrue: \"showFeaturedSection\",\n },\n {\n key: \"featuredButtonText\",\n label: \"Featured Button Text\",\n type: \"text\",\n description: \"Text for featured section button\",\n tab: \"styling\",\n group: \"Featured Section\",\n requiresKeyToBeTrue: \"showFeaturedSection\",\n },\n {\n key: \"featuredButtonUrl\",\n label: \"Featured Button URL\",\n type: \"text\",\n description: \"URL for featured section button\",\n tab: \"styling\",\n group: \"Featured Section\",\n requiresKeyToBeTrue: \"showFeaturedSection\",\n },\n getColorField({\n key: \"featuredSubtitleColor\",\n label: \"Featured Subtitle Color\",\n description: \"Color for featured subtitle\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Featured Section\",\n requiresKeyToBeTrue: \"showFeaturedSection\",\n }),\n getFontSizeField({\n key: \"featuredSubtitleSize\",\n label: \"Featured Subtitle Font Size\",\n description: \"Size of featured subtitle\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Featured Section\",\n requiresKeyToBeTrue: \"showFeaturedSection\",\n }),\n\n // Data tab - Data Configuration\n {\n key: \"dataSource\",\n label: \"Data Source\",\n type: \"dataSource\",\n description: \"\",\n tab: \"data\",\n group: \"Data Configuration\",\n },\n ],\n itemConfigSchema: {\n description: \"Configure settings for this list item\",\n fields: [\n {\n key: \"title\",\n label: \"Custom Title\",\n type: \"text\",\n description: \"Override the item's title\",\n },\n {\n key: \"description\",\n label: \"Custom Description\",\n type: \"textarea\",\n description: \"Override the item's description\",\n rows: 3,\n },\n {\n key: \"price\",\n label: \"Price\",\n type: \"text\",\n description: \"Current price\",\n },\n {\n key: \"originalPrice\",\n label: \"Original Price\",\n type: \"text\",\n description: \"Original price (will be crossed out)\",\n },\n {\n key: \"discount\",\n label: \"Discount Badge\",\n type: \"text\",\n description: \"Discount text (e.g., '40% Off')\",\n },\n {\n key: \"qv\",\n label: \"QV Value\",\n type: \"text\",\n description: \"Qualifying Volume value\",\n },\n {\n key: \"cv\",\n label: \"CV Value\",\n type: \"text\",\n description: \"Commission Volume value\",\n },\n {\n key: \"image\",\n label: \"Image URL\",\n type: \"text\",\n description: \"Custom image URL for this item\",\n },\n ],\n },\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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ACR,CAAC;EACFD,mBAAAA,iBAAiB;GACf,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EAGF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aACE;GACF,KAAK;GACL,OAAO;GACP,cAAc,CAAC,SAAS;GACxB,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACDC,mBAAAA,cAAc;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;EACFD,mBAAAA,iBAAiB;GACf,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;EAGF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACR;EACF;CACD,kBAAkB;EAChB,aAAa;EACb,QAAQ;GACN;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACb,MAAM;IACP;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACF;EACF;CACF"}
|