@fluid-app/portal-widgets 0.1.18 → 0.1.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/ListWidget-C0RDtImi.cjs +2 -0
  2. package/dist/{ListWidget-RHQ2fQXa.cjs → ListWidget-DPVLRWoB.cjs} +37 -49
  3. package/dist/ListWidget-DPVLRWoB.cjs.map +1 -0
  4. package/dist/{ListWidget-C-jcsCb4.mjs → ListWidget-DdvuIQXy.mjs} +37 -39
  5. package/dist/ListWidget-DdvuIQXy.mjs.map +1 -0
  6. package/dist/{MySiteWidget-A_cYFgxJ.cjs → MySiteWidget-1xqN0Bcg.cjs} +1 -1
  7. package/dist/{MySiteWidget-A_cYFgxJ.cjs.map → MySiteWidget-1xqN0Bcg.cjs.map} +1 -1
  8. package/dist/{MySiteWidget-DariqlfU.mjs → MySiteWidget-CX_jY14-.mjs} +1 -1
  9. package/dist/{MySiteWidget-DariqlfU.mjs.map → MySiteWidget-CX_jY14-.mjs.map} +1 -1
  10. package/dist/NestedWidget-DjZYPLc7.cjs +2 -0
  11. package/dist/{NestedWidget-BaRb7Z5r.mjs → NestedWidget-DoevHJKG.mjs} +27 -3
  12. package/dist/NestedWidget-DoevHJKG.mjs.map +1 -0
  13. package/dist/{NestedWidget-Dbo3dXEi.cjs → NestedWidget-DszMmpt7.cjs} +28 -14
  14. package/dist/NestedWidget-DszMmpt7.cjs.map +1 -0
  15. package/dist/{QuickShareWidget-DXq5lcDn.mjs → QuickShareWidget-CdvP1eRx.mjs} +1 -1
  16. package/dist/{QuickShareWidget-DXq5lcDn.mjs.map → QuickShareWidget-CdvP1eRx.mjs.map} +1 -1
  17. package/dist/{QuickShareWidget-DWvgEy74.cjs → QuickShareWidget-Dg2OcMYg.cjs} +1 -1
  18. package/dist/{QuickShareWidget-DWvgEy74.cjs.map → QuickShareWidget-Dg2OcMYg.cjs.map} +1 -1
  19. package/dist/{RecentActivityWidget-BvncOdax.mjs → RecentActivityWidget-Cj-vLOGu.mjs} +1 -1
  20. package/dist/{RecentActivityWidget-BvncOdax.mjs.map → RecentActivityWidget-Cj-vLOGu.mjs.map} +1 -1
  21. package/dist/{RecentActivityWidget-wODng8dt.cjs → RecentActivityWidget-RGChzfaD.cjs} +1 -1
  22. package/dist/{RecentActivityWidget-wODng8dt.cjs.map → RecentActivityWidget-RGChzfaD.cjs.map} +1 -1
  23. package/dist/{SpacerWidget-BFboILmz.cjs → SpacerWidget-BdVf_Yqm.cjs} +1 -1
  24. package/dist/{SpacerWidget-BFboILmz.cjs.map → SpacerWidget-BdVf_Yqm.cjs.map} +1 -1
  25. package/dist/{SpacerWidget-Cc0IuKda.mjs → SpacerWidget-DxR5K3hp.mjs} +1 -1
  26. package/dist/{SpacerWidget-Cc0IuKda.mjs.map → SpacerWidget-DxR5K3hp.mjs.map} +1 -1
  27. package/dist/{TableWidget-TfQfFHft.cjs → TableWidget-BQNVZUkg.cjs} +32 -23
  28. package/dist/TableWidget-BQNVZUkg.cjs.map +1 -0
  29. package/dist/TableWidget-amUotAZN.cjs +2 -0
  30. package/dist/{TableWidget--yLJTqoW.mjs → TableWidget-bpvdvJHI.mjs} +31 -12
  31. package/dist/TableWidget-bpvdvJHI.mjs.map +1 -0
  32. package/dist/{ToDoWidget-D8YIsl7y.mjs → ToDoWidget-4EZIWq_Z.mjs} +1 -1
  33. package/dist/{ToDoWidget-D8YIsl7y.mjs.map → ToDoWidget-4EZIWq_Z.mjs.map} +1 -1
  34. package/dist/{ToDoWidget-Dvs0GDkx.cjs → ToDoWidget-D5BFKUrZ.cjs} +1 -1
  35. package/dist/{ToDoWidget-Dvs0GDkx.cjs.map → ToDoWidget-D5BFKUrZ.cjs.map} +1 -1
  36. package/dist/{VideoWidget-D_1kluGw.mjs → VideoWidget-CYSOjVec.mjs} +1 -1
  37. package/dist/{VideoWidget-D_1kluGw.mjs.map → VideoWidget-CYSOjVec.mjs.map} +1 -1
  38. package/dist/{VideoWidget-D3Fw1jZE.cjs → VideoWidget-CqRHfFnI.cjs} +1 -1
  39. package/dist/{VideoWidget-D3Fw1jZE.cjs.map → VideoWidget-CqRHfFnI.cjs.map} +1 -1
  40. package/dist/WidgetInteractionContext-DjlpWpTR.cjs +31 -0
  41. package/dist/WidgetInteractionContext-DjlpWpTR.cjs.map +1 -0
  42. package/dist/WidgetInteractionContext-awLrJeAK.mjs +18 -0
  43. package/dist/WidgetInteractionContext-awLrJeAK.mjs.map +1 -0
  44. package/dist/contexts/index.cjs +3 -0
  45. package/dist/contexts/index.d.cts +19 -1
  46. package/dist/contexts/index.d.cts.map +1 -1
  47. package/dist/contexts/index.d.mts +19 -1
  48. package/dist/contexts/index.d.mts.map +1 -1
  49. package/dist/contexts/index.mjs +2 -1
  50. package/dist/core/index.d.mts +1 -1
  51. package/dist/widgets/index.cjs +18 -18
  52. package/dist/widgets/index.cjs.map +1 -1
  53. package/dist/widgets/index.d.cts +1 -2
  54. package/dist/widgets/index.d.cts.map +1 -1
  55. package/dist/widgets/index.d.mts +2 -3
  56. package/dist/widgets/index.d.mts.map +1 -1
  57. package/dist/widgets/index.mjs +18 -18
  58. package/package.json +3 -3
  59. package/dist/ListWidget-C-jcsCb4.mjs.map +0 -1
  60. package/dist/ListWidget-RHQ2fQXa.cjs.map +0 -1
  61. package/dist/NestedWidget-BaRb7Z5r.mjs.map +0 -1
  62. package/dist/NestedWidget-Dbo3dXEi.cjs.map +0 -1
  63. package/dist/TableWidget--yLJTqoW.mjs.map +0 -1
  64. package/dist/TableWidget-TfQfFHft.cjs.map +0 -1
  65. /package/dist/{fields-4FC6JUNH.d.mts → fields-BGGlw1MW.d.mts} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"file":"ListWidget-C-jcsCb4.mjs","names":["getImageUrl","getAspectRatioClass"],"sources":["../src/widgets/list-widget/FeaturedSection.tsx","../src/widgets/list-widget/ListItemCard.tsx","../src/widgets/list-widget/UnorderedList.tsx","../src/widgets/list-widget/OrderedList.tsx","../src/widgets/ListWidget.tsx"],"sourcesContent":["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\";\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={`relative h-full min-h-[300px] w-full overflow-hidden rounded-${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 className=\"absolute inset-0 bg-black/40\" />\n\n <div className=\"absolute inset-0 flex flex-col items-start justify-end p-8\">\n {featuredTitle && (\n <h3\n className={`mb-2 font-bold text-white text-${titleSize === \"md\" ? \"base\" : titleSize}`}\n >\n {featuredTitle}\n </h3>\n )}\n {featuredSubtitle && (\n <p\n className={`mb-4 text-${featuredSubtitleColor} text-${featuredSubtitleSize === \"md\" ? \"base\" : featuredSubtitleSize}`}\n >\n {featuredSubtitle}\n </p>\n )}\n {featuredButtonText && (\n <a\n href={featuredButtonUrl || \"#\"}\n className={`text-foreground bg-white px-6 py-2 font-medium transition-opacity hover:opacity-90 rounded-${borderRadius}`}\n >\n {featuredButtonText}\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};\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\n/**\n * Strips parenthetical text like \"(USD)\" from price strings.\n * Matches the shop page's stripParentheticalText pattern.\n */\nfunction stripParentheticalText(text: string): string {\n return text.replace(/\\s*\\([^)]*\\)/g, \"\").trim();\n}\n\n/**\n * Formats a price for display. Follows the shop page pattern:\n * prices arrive pre-formatted from the API via display_price\n * (e.g. \"$19.99\", \"€15.00 (EUR)\") so we just extract the string\n * and strip parenthetical suffixes.\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 return (\n <div className={`p-${padding}`}>\n {item.title && (\n <h3\n className={`text-${itemTitleColor} text-${itemTitleSize === \"md\" ? \"base\" : itemTitleSize} mb-1 font-semibold`}\n >\n {getStringValue(item.title)}\n </h3>\n )}\n {item.description && (\n <div\n className={`text-${descriptionColor} text-${descriptionSize === \"md\" ? \"base\" : descriptionSize} mb-2 line-clamp-2 overflow-hidden`}\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 <div className=\"flex items-center gap-2\">\n {(item.display_price || item.price) && (\n <span\n className={`text-${priceColor} text-${priceSize === \"md\" ? \"base\" : priceSize} font-bold`}\n >\n {formatPrice(item.display_price || item.price)}\n </span>\n )}\n {item.originalPrice && (\n <span\n className={`text-${originalPriceColor} text-${descriptionSize === \"md\" ? \"base\" : descriptionSize} line-through`}\n >\n {formatPrice(item.originalPrice)}\n </span>\n )}\n </div>\n {showMetaText && (item.qv || item.cv) && (\n <div\n className={`mt-2 flex gap-3 text-${metaTextColor} text-${metaTextSize === \"md\" ? \"base\" : metaTextSize}`}\n >\n {item.qv && <span>QV: {getStringValue(item.qv)}</span>}\n {item.cv && <span>CV: {getStringValue(item.cv)}</span>}\n </div>\n )}\n </div>\n );\n}\n\nexport interface BadgeAndFavoriteProps {\n showBadge: boolean;\n showFavorite: boolean;\n discount?: string;\n favoritePosition?: \"default\" | \"inline\";\n}\n\nexport function DiscountBadge({\n discount,\n}: {\n discount: string;\n}): React.JSX.Element {\n return (\n <div className=\"bg-destructive text-destructive-foreground absolute top-2 right-2 z-10 rounded-md px-2 py-1 text-xs font-bold\">\n {getStringValue(discount)}\n </div>\n );\n}\n\nexport function FavoriteButton({\n className,\n}: {\n className?: string;\n}): React.JSX.Element {\n return (\n <button\n className={\n className ||\n \"bg-background/80 hover:bg-background absolute top-2 left-2 z-10 rounded-full p-2 backdrop-blur-sm transition-colors\"\n }\n >\n <svg\n className=\"text-muted-foreground h-5 w-5\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z\"\n />\n </svg>\n </button>\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 {\n ListItemCardContent,\n DiscountBadge,\n FavoriteButton,\n type ListItem,\n} from \"./ListItemCard\";\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 showFavorite: 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 showFavorite,\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\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={`relative rounded-${borderRadius} bg-background overflow-hidden shadow-sm transition-shadow hover:shadow-md`}\n >\n {showBadge && item.discount && (\n <DiscountBadge discount={item.discount} />\n )}\n {showFavorite && <FavoriteButton />}\n {imageUrl && (\n <div className={`w-full ${aspectRatioClass} overflow-hidden`}>\n <img\n src={imageUrl}\n alt={item.title || \"Product\"}\n className=\"h-full w-full object-cover\"\n />\n </div>\n )}\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 );\n })}\n </div>\n );\n}\n","import { useRef } from \"react\";\nimport 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 { ScrollArrows } from \"../../ui/scroll-arrows\";\nimport {\n ListItemCardContent,\n DiscountBadge,\n FavoriteButton,\n getStringValue,\n type ListItem,\n} from \"./ListItemCard\";\n\ntype ImageAspectRatio = \"square\" | \"landscape\" | \"portrait\";\ntype ScrollAxis = \"horizontal\" | \"vertical\";\n\nconst SCROLL_ITEM_WIDTH = 300;\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\nexport interface OrderedListProps {\n items: ListItem[];\n scrollAxis: ScrollAxis;\n gap: GapOptions;\n borderRadius: BorderRadiusOptions;\n imageAspectRatio: ImageAspectRatio;\n showBadge: boolean;\n showFavorite: 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}\n\nconst largeNumberSizes: Record<FontSizeOptions, string> = {\n xs: \"8rem\",\n sm: \"10rem\",\n md: \"12rem\",\n lg: \"14rem\",\n xl: \"16rem\",\n \"2xl\": \"20rem\",\n};\n\nexport function OrderedList({\n items,\n scrollAxis,\n gap,\n borderRadius,\n imageAspectRatio,\n showBadge,\n showFavorite,\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}: OrderedListProps): React.JSX.Element | null {\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n\n const scrollByAmount = (direction: \"prev\" | \"next\") => {\n const container = scrollContainerRef.current;\n if (!container) return;\n\n const computedGap = parseFloat(getComputedStyle(container).gap) || 0;\n const scrollAmount = SCROLL_ITEM_WIDTH + computedGap;\n\n container.scrollTo({\n left:\n container.scrollLeft +\n (direction === \"next\" ? scrollAmount : -scrollAmount),\n behavior: \"smooth\",\n });\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 aspectRatioClass = getAspectRatioClass(imageAspectRatio);\n\n return (\n <div key={item.id} className=\"relative w-[300px] flex-shrink-0\">\n <div\n className={`absolute top-0 left-0 text-${numberColor} z-0 leading-none font-bold opacity-20`}\n style={{ fontSize: largeNumberSizes[numberSize] }}\n >\n {index + 1}\n </div>\n\n <div\n className={`relative z-10 ml-20 rounded-${borderRadius} bg-background overflow-hidden shadow-sm transition-shadow hover:shadow-md`}\n >\n {showBadge && item.discount && (\n <DiscountBadge discount={item.discount} />\n )}\n {showFavorite && <FavoriteButton />}\n {imageUrl && (\n <div\n className={`w-full ${aspectRatioClass} overflow-hidden`}\n >\n <img\n src={imageUrl}\n alt={item.title || \"Product\"}\n className=\"h-full w-full object-cover\"\n />\n </div>\n )}\n <ListItemCardContent item={item} {...contentProps} />\n </div>\n </div>\n );\n })}\n </div>\n\n <div className=\"absolute inset-x-0 top-1/2 z-20 flex w-full -translate-y-1/2 items-center justify-between px-8\">\n <ScrollArrows\n onPrevious={() => scrollByAmount(\"prev\")}\n onNext={() => scrollByAmount(\"next\")}\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\n return (\n <div\n key={item.id}\n className={`relative flex gap-${gapValues[gap]} rounded-${borderRadius} bg-background overflow-hidden shadow-sm transition-shadow hover:shadow-md ${`p-${padding}`}`}\n >\n <div\n className={`flex-shrink-0 text-${numberColor} text-${numberSize === \"md\" ? \"base\" : numberSize} flex w-16 items-center justify-center font-bold`}\n >\n {index + 1}\n </div>\n {imageUrl && (\n <div className=\"h-24 w-24 flex-shrink-0 overflow-hidden rounded-md\">\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=\"flex-1\">\n <ListItemCardContent item={item} {...contentProps} />\n </div>\n {showBadge && item.discount && (\n <div className=\"bg-destructive text-destructive-foreground absolute top-2 right-2 rounded-md px-2 py-1 text-xs font-bold\">\n {getStringValue(item.discount)}\n </div>\n )}\n {showFavorite && (\n <FavoriteButton className=\"bg-background/80 hover:bg-background absolute top-2 right-12 rounded-full p-2 backdrop-blur-sm transition-colors\" />\n )}\n </div>\n );\n })}\n </div>\n );\n }\n\n return null;\n}\n","import type { ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\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 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};\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 padding?: PaddingOptions;\n gap?: GapOptions;\n columns?: number;\n imageAspectRatio?: ImageAspectRatio;\n background?: BackgroundValue;\n\n // Behavior\n showBadge?: boolean;\n showFavorite?: 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 padding = 4,\n gap = \"md\",\n columns = 3,\n imageAspectRatio = \"square\",\n background = { type: \"solid\", color: \"background\" },\n showBadge = true,\n showFavorite = 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 showFavorite,\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 return (\n <div\n className={`@container bg-${backgroundColor} ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n {titleEnabled && title && (\n <h2\n className={`text-${titleColor} text-${titleSize === \"md\" ? \"base\" : titleSize} mb-6 font-bold`}\n >\n {title}\n </h2>\n )}\n {!hasItems ? (\n <div className=\"border-border bg-muted flex items-center justify-center rounded-md border-2 border-dashed py-12 text-center\">\n <p className=\"text-muted\">No items to display</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 {...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 {...itemStyleProps}\n />\n )}\n </div>\n );\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 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: \"Aspect ratio for item images\",\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 },\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: \"showFavorite\",\n label: \"Show Favorite Icon\",\n type: \"boolean\",\n description: \"Display favorite/heart icon 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: \"Size of ordered list numbers\",\n defaultValue: \"2xl\",\n tab: \"styling\",\n group: \"Ordered List Configuration\",\n requiresKeyValue: { key: \"listType\", value: \"ordered\" },\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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AAiB;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-RHQ2fQXa.cjs","names":["MediaRenderer","DOMPurify","getImageUrl","getAspectRatioClass","gapValues","gapValues","ScrollArrows"],"sources":["../src/widgets/list-widget/FeaturedSection.tsx","../src/widgets/list-widget/ListItemCard.tsx","../src/widgets/list-widget/UnorderedList.tsx","../src/widgets/list-widget/OrderedList.tsx","../src/widgets/ListWidget.tsx"],"sourcesContent":["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\";\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={`relative h-full min-h-[300px] w-full overflow-hidden rounded-${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 className=\"absolute inset-0 bg-black/40\" />\n\n <div className=\"absolute inset-0 flex flex-col items-start justify-end p-8\">\n {featuredTitle && (\n <h3\n className={`mb-2 font-bold text-white text-${titleSize === \"md\" ? \"base\" : titleSize}`}\n >\n {featuredTitle}\n </h3>\n )}\n {featuredSubtitle && (\n <p\n className={`mb-4 text-${featuredSubtitleColor} text-${featuredSubtitleSize === \"md\" ? \"base\" : featuredSubtitleSize}`}\n >\n {featuredSubtitle}\n </p>\n )}\n {featuredButtonText && (\n <a\n href={featuredButtonUrl || \"#\"}\n className={`text-foreground bg-white px-6 py-2 font-medium transition-opacity hover:opacity-90 rounded-${borderRadius}`}\n >\n {featuredButtonText}\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};\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\n/**\n * Strips parenthetical text like \"(USD)\" from price strings.\n * Matches the shop page's stripParentheticalText pattern.\n */\nfunction stripParentheticalText(text: string): string {\n return text.replace(/\\s*\\([^)]*\\)/g, \"\").trim();\n}\n\n/**\n * Formats a price for display. Follows the shop page pattern:\n * prices arrive pre-formatted from the API via display_price\n * (e.g. \"$19.99\", \"€15.00 (EUR)\") so we just extract the string\n * and strip parenthetical suffixes.\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 return (\n <div className={`p-${padding}`}>\n {item.title && (\n <h3\n className={`text-${itemTitleColor} text-${itemTitleSize === \"md\" ? \"base\" : itemTitleSize} mb-1 font-semibold`}\n >\n {getStringValue(item.title)}\n </h3>\n )}\n {item.description && (\n <div\n className={`text-${descriptionColor} text-${descriptionSize === \"md\" ? \"base\" : descriptionSize} mb-2 line-clamp-2 overflow-hidden`}\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 <div className=\"flex items-center gap-2\">\n {(item.display_price || item.price) && (\n <span\n className={`text-${priceColor} text-${priceSize === \"md\" ? \"base\" : priceSize} font-bold`}\n >\n {formatPrice(item.display_price || item.price)}\n </span>\n )}\n {item.originalPrice && (\n <span\n className={`text-${originalPriceColor} text-${descriptionSize === \"md\" ? \"base\" : descriptionSize} line-through`}\n >\n {formatPrice(item.originalPrice)}\n </span>\n )}\n </div>\n {showMetaText && (item.qv || item.cv) && (\n <div\n className={`mt-2 flex gap-3 text-${metaTextColor} text-${metaTextSize === \"md\" ? \"base\" : metaTextSize}`}\n >\n {item.qv && <span>QV: {getStringValue(item.qv)}</span>}\n {item.cv && <span>CV: {getStringValue(item.cv)}</span>}\n </div>\n )}\n </div>\n );\n}\n\nexport interface BadgeAndFavoriteProps {\n showBadge: boolean;\n showFavorite: boolean;\n discount?: string;\n favoritePosition?: \"default\" | \"inline\";\n}\n\nexport function DiscountBadge({\n discount,\n}: {\n discount: string;\n}): React.JSX.Element {\n return (\n <div className=\"bg-destructive text-destructive-foreground absolute top-2 right-2 z-10 rounded-md px-2 py-1 text-xs font-bold\">\n {getStringValue(discount)}\n </div>\n );\n}\n\nexport function FavoriteButton({\n className,\n}: {\n className?: string;\n}): React.JSX.Element {\n return (\n <button\n className={\n className ||\n \"bg-background/80 hover:bg-background absolute top-2 left-2 z-10 rounded-full p-2 backdrop-blur-sm transition-colors\"\n }\n >\n <svg\n className=\"text-muted-foreground h-5 w-5\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z\"\n />\n </svg>\n </button>\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 {\n ListItemCardContent,\n DiscountBadge,\n FavoriteButton,\n type ListItem,\n} from \"./ListItemCard\";\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 showFavorite: 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 showFavorite,\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\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={`relative rounded-${borderRadius} bg-background overflow-hidden shadow-sm transition-shadow hover:shadow-md`}\n >\n {showBadge && item.discount && (\n <DiscountBadge discount={item.discount} />\n )}\n {showFavorite && <FavoriteButton />}\n {imageUrl && (\n <div className={`w-full ${aspectRatioClass} overflow-hidden`}>\n <img\n src={imageUrl}\n alt={item.title || \"Product\"}\n className=\"h-full w-full object-cover\"\n />\n </div>\n )}\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 );\n })}\n </div>\n );\n}\n","import { useRef } from \"react\";\nimport 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 { ScrollArrows } from \"../../ui/scroll-arrows\";\nimport {\n ListItemCardContent,\n DiscountBadge,\n FavoriteButton,\n getStringValue,\n type ListItem,\n} from \"./ListItemCard\";\n\ntype ImageAspectRatio = \"square\" | \"landscape\" | \"portrait\";\ntype ScrollAxis = \"horizontal\" | \"vertical\";\n\nconst SCROLL_ITEM_WIDTH = 300;\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\nexport interface OrderedListProps {\n items: ListItem[];\n scrollAxis: ScrollAxis;\n gap: GapOptions;\n borderRadius: BorderRadiusOptions;\n imageAspectRatio: ImageAspectRatio;\n showBadge: boolean;\n showFavorite: 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}\n\nconst largeNumberSizes: Record<FontSizeOptions, string> = {\n xs: \"8rem\",\n sm: \"10rem\",\n md: \"12rem\",\n lg: \"14rem\",\n xl: \"16rem\",\n \"2xl\": \"20rem\",\n};\n\nexport function OrderedList({\n items,\n scrollAxis,\n gap,\n borderRadius,\n imageAspectRatio,\n showBadge,\n showFavorite,\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}: OrderedListProps): React.JSX.Element | null {\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n\n const scrollByAmount = (direction: \"prev\" | \"next\") => {\n const container = scrollContainerRef.current;\n if (!container) return;\n\n const computedGap = parseFloat(getComputedStyle(container).gap) || 0;\n const scrollAmount = SCROLL_ITEM_WIDTH + computedGap;\n\n container.scrollTo({\n left:\n container.scrollLeft +\n (direction === \"next\" ? scrollAmount : -scrollAmount),\n behavior: \"smooth\",\n });\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 aspectRatioClass = getAspectRatioClass(imageAspectRatio);\n\n return (\n <div key={item.id} className=\"relative w-[300px] flex-shrink-0\">\n <div\n className={`absolute top-0 left-0 text-${numberColor} z-0 leading-none font-bold opacity-20`}\n style={{ fontSize: largeNumberSizes[numberSize] }}\n >\n {index + 1}\n </div>\n\n <div\n className={`relative z-10 ml-20 rounded-${borderRadius} bg-background overflow-hidden shadow-sm transition-shadow hover:shadow-md`}\n >\n {showBadge && item.discount && (\n <DiscountBadge discount={item.discount} />\n )}\n {showFavorite && <FavoriteButton />}\n {imageUrl && (\n <div\n className={`w-full ${aspectRatioClass} overflow-hidden`}\n >\n <img\n src={imageUrl}\n alt={item.title || \"Product\"}\n className=\"h-full w-full object-cover\"\n />\n </div>\n )}\n <ListItemCardContent item={item} {...contentProps} />\n </div>\n </div>\n );\n })}\n </div>\n\n <div className=\"absolute inset-x-0 top-1/2 z-20 flex w-full -translate-y-1/2 items-center justify-between px-8\">\n <ScrollArrows\n onPrevious={() => scrollByAmount(\"prev\")}\n onNext={() => scrollByAmount(\"next\")}\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\n return (\n <div\n key={item.id}\n className={`relative flex gap-${gapValues[gap]} rounded-${borderRadius} bg-background overflow-hidden shadow-sm transition-shadow hover:shadow-md ${`p-${padding}`}`}\n >\n <div\n className={`flex-shrink-0 text-${numberColor} text-${numberSize === \"md\" ? \"base\" : numberSize} flex w-16 items-center justify-center font-bold`}\n >\n {index + 1}\n </div>\n {imageUrl && (\n <div className=\"h-24 w-24 flex-shrink-0 overflow-hidden rounded-md\">\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=\"flex-1\">\n <ListItemCardContent item={item} {...contentProps} />\n </div>\n {showBadge && item.discount && (\n <div className=\"bg-destructive text-destructive-foreground absolute top-2 right-2 rounded-md px-2 py-1 text-xs font-bold\">\n {getStringValue(item.discount)}\n </div>\n )}\n {showFavorite && (\n <FavoriteButton className=\"bg-background/80 hover:bg-background absolute top-2 right-12 rounded-full p-2 backdrop-blur-sm transition-colors\" />\n )}\n </div>\n );\n })}\n </div>\n );\n }\n\n return null;\n}\n","import type { ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\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 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};\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 padding?: PaddingOptions;\n gap?: GapOptions;\n columns?: number;\n imageAspectRatio?: ImageAspectRatio;\n background?: BackgroundValue;\n\n // Behavior\n showBadge?: boolean;\n showFavorite?: 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 padding = 4,\n gap = \"md\",\n columns = 3,\n imageAspectRatio = \"square\",\n background = { type: \"solid\", color: \"background\" },\n showBadge = true,\n showFavorite = 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 showFavorite,\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 return (\n <div\n className={`@container bg-${backgroundColor} ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n {titleEnabled && title && (\n <h2\n className={`text-${titleColor} text-${titleSize === \"md\" ? \"base\" : titleSize} mb-6 font-bold`}\n >\n {title}\n </h2>\n )}\n {!hasItems ? (\n <div className=\"border-border bg-muted flex items-center justify-center rounded-md border-2 border-dashed py-12 text-center\">\n <p className=\"text-muted\">No items to display</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 {...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 {...itemStyleProps}\n />\n )}\n </div>\n );\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 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: \"Aspect ratio for item images\",\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 },\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: \"showFavorite\",\n label: \"Show Favorite Icon\",\n type: \"boolean\",\n description: \"Display favorite/heart icon 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: \"Size of ordered list numbers\",\n defaultValue: \"2xl\",\n tab: \"styling\",\n group: \"Ordered List Configuration\",\n requiresKeyValue: { key: \"listType\", value: \"ordered\" },\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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CR,CAAC;0DACe;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;uDACa;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;0DACe;GACf,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;uDACY;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;uDACa;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;0DACe;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;uDACa;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;0DACe;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":"NestedWidget-BaRb7Z5r.mjs","names":["getBorderRadiusField"],"sources":["../src/widgets/NestedWidget.tsx"],"sourcesContent":["import { useRef, useState, useEffect, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport {\n MediaRenderer,\n getMediaPropsFromShareable,\n} from \"../components/MediaRenderer\";\nimport type {\n BorderRadiusOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n AlignOptions,\n GapOptions,\n BackgroundValue,\n} from \"@fluid-app/portal-core/types\";\nimport {\n getHeightField,\n type WidgetPropertySchema,\n} from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getColorField,\n getFontSizeField,\n getGapField,\n getPaddingField,\n gapValues,\n} from \"../core/fields\";\nimport { ScrollArrows } from \"../ui/scroll-arrows\";\nimport { type ShareableItem } from \"@fluid-app/portal-core/types\";\n\nconst DEFAULT_SHAREABLES: ShareableItem[] = [];\n\ntype NestedWidgetProps = ComponentProps<\"div\"> & {\n // Content\n resource?: ShareableItem;\n titleEnabled?: boolean;\n titleText?: string;\n shareables?: ShareableItem[];\n\n // Layout\n gap?: GapOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n primaryMediaHeight?: string;\n\n // Title styling\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n titleAlignment?: AlignOptions;\n\n // Nested media styling\n nestedTextColor?: ColorOptions;\n background?: BackgroundValue;\n\n // Overlay\n overlayEnabled?: boolean;\n overlayType?: \"solid\" | \"gradient\";\n overlayIntensity?: number;\n};\n\nexport function NestedWidget({\n resource,\n titleEnabled = true,\n titleText = \"Featured Collection\",\n shareables = DEFAULT_SHAREABLES,\n gap = \"md\",\n padding = 4,\n borderRadius = \"md\",\n primaryMediaHeight = \"400px\",\n titleFontSize = \"xl\",\n titleColor = \"background\",\n titleAlignment = { horizontal: \"left\", vertical: \"bottom\" },\n nestedTextColor = \"foreground\",\n background = {\n type: \"solid\",\n color: \"background\",\n },\n overlayEnabled = true,\n overlayType = \"gradient\",\n overlayIntensity = 50,\n className,\n ...props\n}: NestedWidgetProps): React.JSX.Element {\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n const primaryMediaRef = useRef<HTMLDivElement>(null);\n const [primaryMediaWidthPx, setPrimaryMediaWidthPx] = useState(400);\n\n useEffect(() => {\n const el = primaryMediaRef.current;\n if (!el) return;\n const observer = new ResizeObserver(([entry]) => {\n if (entry) setPrimaryMediaWidthPx(entry.contentRect.width);\n });\n observer.observe(el);\n return () => observer.disconnect();\n }, []);\n\n const scrollByAmount = (direction: \"prev\" | \"next\") => {\n const container = scrollContainerRef.current;\n if (!container) return;\n\n const computedGap = parseFloat(getComputedStyle(container).gap) || 0;\n const itemWidth = primaryMediaWidthPx * 0.75;\n const scrollAmount = itemWidth + computedGap;\n\n container.scrollTo({\n left:\n container.scrollLeft +\n (direction === \"next\" ? scrollAmount : -scrollAmount),\n behavior: \"smooth\",\n });\n };\n\n const hasNestedMedia = shareables.length > 0;\n\n const titleAlignmentClasses = {\n left: \"text-left\",\n center: \"text-center\",\n right: \"text-right\",\n };\n\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 return (\n <div\n className={`@container flex w-full p-${padding} rounded-${borderRadius} bg-${backgroundColor} ${className}`}\n {...props}\n style={{\n maxHeight: primaryMediaHeight,\n backgroundImage: backgroundImage,\n }}\n >\n {/* Primary Media Container - Full width on mobile, fixed on desktop */}\n <div\n ref={primaryMediaRef}\n className={`overflow-hidden @md:flex-none rounded-${borderRadius}`}\n style={{\n width: primaryMediaHeight,\n }}\n >\n {/* Primary Media */}\n <div className=\"relative h-full w-full\">\n <MediaRenderer\n {...(resource ? getMediaPropsFromShareable(resource) : {})}\n />\n\n {/* Overlay */}\n {overlayEnabled && (\n <div\n className={`pointer-events-none absolute inset-0 z-10 ${\n overlayType === \"gradient\"\n ? \"bg-gradient-to-t from-black to-transparent\"\n : \"bg-black\"\n }`}\n style={{\n opacity:\n (Number(String(overlayIntensity).replace(\"%\", \"\")) || 50) /\n 100,\n }}\n />\n )}\n\n {/* Title and Mobile Nested Media */}\n {((titleEnabled && titleText) || hasNestedMedia) && (\n <div\n className={`absolute z-20 w-full ${titleAlignmentClasses[titleAlignment?.horizontal ?? \"left\"]} p-${padding} ${\n titleAlignment.vertical === \"top\"\n ? `top-0 pt-${padding}`\n : titleAlignment.vertical === \"center\"\n ? \"top-1/2 -translate-y-1/2\"\n : `bottom-0 pb-${padding}`\n }`}\n >\n {titleEnabled && titleText && (\n <h2\n className={`leading-tight font-bold text-${titleColor} text-${titleFontSize === \"md\" ? \"base\" : titleFontSize}`}\n >\n {titleText}\n </h2>\n )}\n\n {/* Mobile: Products overlay inside primary media */}\n {hasNestedMedia && (\n <div className={`pt-${padding} @md:hidden`}>\n <div\n className={`flex overflow-x-auto gap-${gapValues[gap]} bg-transparent`}\n >\n {shareables.map((shareable) => (\n <div\n key={shareable.id}\n className=\"flex shrink-0 flex-col items-center\"\n >\n <div\n className={`aspect-3/4 h-40 overflow-hidden rounded-${borderRadius}`}\n >\n <MediaRenderer\n {...getMediaPropsFromShareable(shareable)}\n />\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n\n {/* Desktop: Products Container - Single row beside primary media */}\n {hasNestedMedia && (\n <div\n className={`relative hidden min-w-0 self-stretch @md:flex @md:flex-1 px-${padding}`}\n >\n <div\n ref={scrollContainerRef}\n className={`flex h-full flex-row overflow-x-auto gap-${gapValues[gap]}`}\n style={{ scrollSnapType: \"x mandatory\" }}\n >\n {shareables.map((shareable) => (\n <div\n key={shareable.id}\n className=\"flex flex-col gap-1\"\n style={{\n width: `${primaryMediaWidthPx * 0.75}px`,\n scrollSnapAlign: \"start\",\n }}\n >\n <div\n className={`aspect-3/4 h-full rounded-${borderRadius} overflow-hidden`}\n >\n <MediaRenderer {...getMediaPropsFromShareable(shareable)} />\n </div>\n <span className={`flex-none text-sm text-${nestedTextColor}`}>\n <p className=\"truncate\">{shareable.title || \"\"}</p>\n <p className=\"truncate\">\n {((shareable.display_price as string) ?? shareable.price) ||\n \"\"}\n </p>\n </span>\n </div>\n ))}\n </div>\n\n {/* Navigation arrows */}\n <div\n className={`absolute inset-x-0 top-1/2 flex w-full -translate-y-1/2 items-center justify-between px-8`}\n >\n <ScrollArrows\n onPrevious={() => scrollByAmount(\"prev\")}\n onNext={() => scrollByAmount(\"next\")}\n />\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const nestedWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"NestedWidget\",\n displayName: \"Nested Widget\",\n tabsConfig: [\n { id: \"styling\", label: \"Styling\" },\n { id: \"data\", label: \"Data\" },\n ],\n dataSourceTargetProps: [\"shareables\"],\n fields: [\n // Content tab - Resource group\n {\n key: \"resource\",\n label: \"Primary Media\",\n type: \"resource\",\n description: \"Select the primary media displayed in the large panel\",\n allowedTypes: [\"Medium\"],\n tab: \"styling\",\n group: \"Content\",\n },\n // Content tab - Title group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed over the primary media\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Main title displayed over the primary media\",\n defaultValue: \"Featured Collection\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n label: \"Title Font Size\",\n defaultValue: \"xl\",\n key: \"titleFontSize\",\n description: \"Font size for the widget title\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n defaultValue: \"background\",\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n // Styling tab - Design group\n getHeightField({\n key: \"primaryMediaHeight\",\n label: \"Primary Media Height\",\n description: \"Height of the primary media container\",\n defaultValue: \"400px\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"titleAlignment\",\n label: \"Content Alignment\",\n type: \"alignment\",\n description: \"Alignment of the content inside the primary media\",\n defaultValue: { horizontal: \"left\", vertical: \"bottom\" },\n options: {\n horizontalEnabled: true,\n verticalEnabled: true,\n },\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"separator2\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n defaultValue: 4,\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding used throughout the widget\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n defaultValue: \"md\",\n label: \"Border Radius\",\n key: \"borderRadius\",\n description: \"Rounded corners for the widget\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"overlayEnabled\",\n label: \"Enable Overlay\",\n type: \"boolean\",\n description:\n \"Add a dark overlay to the primary media for better text readability\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"overlayType\",\n label: \"Overlay Type\",\n type: \"buttonGroup\",\n description: \"Type of overlay effect\",\n defaultValue: \"gradient\",\n options: [\n { label: \"Solid\", value: \"solid\" },\n { label: \"Gradient\", value: \"gradient\" },\n ],\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"overlayEnabled\",\n },\n {\n key: \"overlayIntensity\",\n label: \"Overlay Intensity\",\n type: \"slider\",\n description: \"Opacity of the overlay (0-100)\",\n min: 0,\n max: 100,\n step: 5,\n defaultValue: 50,\n unit: \"%\",\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"overlayEnabled\",\n },\n // Styling tab - Nested Media Styling group\n getGapField({\n label: \"Gap\",\n defaultValue: \"md\",\n key: \"gap\",\n description: \"Gap between nested media items\",\n tab: \"styling\",\n group: \"Nested Design\",\n }),\n getColorField({\n defaultValue: \"foreground\",\n key: \"nestedTextColor\",\n label: \"Nested Text Color\",\n description: \"Color for nested media labels\",\n tab: \"styling\",\n group: \"Nested Design\",\n }),\n {\n type: \"background\",\n defaultValue: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background color for nested media container\",\n tab: \"styling\",\n group: \"Nested Design\",\n },\n // Data tab\n {\n key: \"dataSource\",\n label: \"Data Source\",\n type: \"dataSource\",\n description: \"Configure dynamic data fetching from an API\",\n tab: \"data\",\n group: \"Data Configuration\",\n },\n ],\n // Per-item configuration schema for custom data sources\n itemConfigSchema: {\n description: \"Configure settings for this item\",\n fields: [\n {\n key: \"title\",\n label: \"Custom Title\",\n type: \"text\",\n description: \"Override the item's title for this widget\",\n },\n ],\n },\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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d,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EACFA,uBAAqB;GACnB,cAAc;GACd,OAAO;GACP,KAAK;GACL,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aACE;GACF,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,SAAS,CACP;IAAE,OAAO;IAAS,OAAO;IAAS,EAClC;IAAE,OAAO;IAAY,OAAO;IAAY,CACzC;GACD,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,KAAK;GACL,MAAM;GACN,cAAc;GACd,MAAM;GACN,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EAED,YAAY;GACV,OAAO;GACP,cAAc;GACd,KAAK;GACL,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EACF,cAAc;GACZ,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,MAAM;GACN,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR;EAED;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACR;EACF;CAED,kBAAkB;EAChB,aAAa;EACb,QAAQ,CACN;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACd,CACF;EACF;CACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"NestedWidget-Dbo3dXEi.cjs","names":["MediaRenderer","getMediaPropsFromShareable","gapValues","ScrollArrows"],"sources":["../src/widgets/NestedWidget.tsx"],"sourcesContent":["import { useRef, useState, useEffect, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport {\n MediaRenderer,\n getMediaPropsFromShareable,\n} from \"../components/MediaRenderer\";\nimport type {\n BorderRadiusOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n AlignOptions,\n GapOptions,\n BackgroundValue,\n} from \"@fluid-app/portal-core/types\";\nimport {\n getHeightField,\n type WidgetPropertySchema,\n} from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getColorField,\n getFontSizeField,\n getGapField,\n getPaddingField,\n gapValues,\n} from \"../core/fields\";\nimport { ScrollArrows } from \"../ui/scroll-arrows\";\nimport { type ShareableItem } from \"@fluid-app/portal-core/types\";\n\nconst DEFAULT_SHAREABLES: ShareableItem[] = [];\n\ntype NestedWidgetProps = ComponentProps<\"div\"> & {\n // Content\n resource?: ShareableItem;\n titleEnabled?: boolean;\n titleText?: string;\n shareables?: ShareableItem[];\n\n // Layout\n gap?: GapOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n primaryMediaHeight?: string;\n\n // Title styling\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n titleAlignment?: AlignOptions;\n\n // Nested media styling\n nestedTextColor?: ColorOptions;\n background?: BackgroundValue;\n\n // Overlay\n overlayEnabled?: boolean;\n overlayType?: \"solid\" | \"gradient\";\n overlayIntensity?: number;\n};\n\nexport function NestedWidget({\n resource,\n titleEnabled = true,\n titleText = \"Featured Collection\",\n shareables = DEFAULT_SHAREABLES,\n gap = \"md\",\n padding = 4,\n borderRadius = \"md\",\n primaryMediaHeight = \"400px\",\n titleFontSize = \"xl\",\n titleColor = \"background\",\n titleAlignment = { horizontal: \"left\", vertical: \"bottom\" },\n nestedTextColor = \"foreground\",\n background = {\n type: \"solid\",\n color: \"background\",\n },\n overlayEnabled = true,\n overlayType = \"gradient\",\n overlayIntensity = 50,\n className,\n ...props\n}: NestedWidgetProps): React.JSX.Element {\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n const primaryMediaRef = useRef<HTMLDivElement>(null);\n const [primaryMediaWidthPx, setPrimaryMediaWidthPx] = useState(400);\n\n useEffect(() => {\n const el = primaryMediaRef.current;\n if (!el) return;\n const observer = new ResizeObserver(([entry]) => {\n if (entry) setPrimaryMediaWidthPx(entry.contentRect.width);\n });\n observer.observe(el);\n return () => observer.disconnect();\n }, []);\n\n const scrollByAmount = (direction: \"prev\" | \"next\") => {\n const container = scrollContainerRef.current;\n if (!container) return;\n\n const computedGap = parseFloat(getComputedStyle(container).gap) || 0;\n const itemWidth = primaryMediaWidthPx * 0.75;\n const scrollAmount = itemWidth + computedGap;\n\n container.scrollTo({\n left:\n container.scrollLeft +\n (direction === \"next\" ? scrollAmount : -scrollAmount),\n behavior: \"smooth\",\n });\n };\n\n const hasNestedMedia = shareables.length > 0;\n\n const titleAlignmentClasses = {\n left: \"text-left\",\n center: \"text-center\",\n right: \"text-right\",\n };\n\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 return (\n <div\n className={`@container flex w-full p-${padding} rounded-${borderRadius} bg-${backgroundColor} ${className}`}\n {...props}\n style={{\n maxHeight: primaryMediaHeight,\n backgroundImage: backgroundImage,\n }}\n >\n {/* Primary Media Container - Full width on mobile, fixed on desktop */}\n <div\n ref={primaryMediaRef}\n className={`overflow-hidden @md:flex-none rounded-${borderRadius}`}\n style={{\n width: primaryMediaHeight,\n }}\n >\n {/* Primary Media */}\n <div className=\"relative h-full w-full\">\n <MediaRenderer\n {...(resource ? getMediaPropsFromShareable(resource) : {})}\n />\n\n {/* Overlay */}\n {overlayEnabled && (\n <div\n className={`pointer-events-none absolute inset-0 z-10 ${\n overlayType === \"gradient\"\n ? \"bg-gradient-to-t from-black to-transparent\"\n : \"bg-black\"\n }`}\n style={{\n opacity:\n (Number(String(overlayIntensity).replace(\"%\", \"\")) || 50) /\n 100,\n }}\n />\n )}\n\n {/* Title and Mobile Nested Media */}\n {((titleEnabled && titleText) || hasNestedMedia) && (\n <div\n className={`absolute z-20 w-full ${titleAlignmentClasses[titleAlignment?.horizontal ?? \"left\"]} p-${padding} ${\n titleAlignment.vertical === \"top\"\n ? `top-0 pt-${padding}`\n : titleAlignment.vertical === \"center\"\n ? \"top-1/2 -translate-y-1/2\"\n : `bottom-0 pb-${padding}`\n }`}\n >\n {titleEnabled && titleText && (\n <h2\n className={`leading-tight font-bold text-${titleColor} text-${titleFontSize === \"md\" ? \"base\" : titleFontSize}`}\n >\n {titleText}\n </h2>\n )}\n\n {/* Mobile: Products overlay inside primary media */}\n {hasNestedMedia && (\n <div className={`pt-${padding} @md:hidden`}>\n <div\n className={`flex overflow-x-auto gap-${gapValues[gap]} bg-transparent`}\n >\n {shareables.map((shareable) => (\n <div\n key={shareable.id}\n className=\"flex shrink-0 flex-col items-center\"\n >\n <div\n className={`aspect-3/4 h-40 overflow-hidden rounded-${borderRadius}`}\n >\n <MediaRenderer\n {...getMediaPropsFromShareable(shareable)}\n />\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n\n {/* Desktop: Products Container - Single row beside primary media */}\n {hasNestedMedia && (\n <div\n className={`relative hidden min-w-0 self-stretch @md:flex @md:flex-1 px-${padding}`}\n >\n <div\n ref={scrollContainerRef}\n className={`flex h-full flex-row overflow-x-auto gap-${gapValues[gap]}`}\n style={{ scrollSnapType: \"x mandatory\" }}\n >\n {shareables.map((shareable) => (\n <div\n key={shareable.id}\n className=\"flex flex-col gap-1\"\n style={{\n width: `${primaryMediaWidthPx * 0.75}px`,\n scrollSnapAlign: \"start\",\n }}\n >\n <div\n className={`aspect-3/4 h-full rounded-${borderRadius} overflow-hidden`}\n >\n <MediaRenderer {...getMediaPropsFromShareable(shareable)} />\n </div>\n <span className={`flex-none text-sm text-${nestedTextColor}`}>\n <p className=\"truncate\">{shareable.title || \"\"}</p>\n <p className=\"truncate\">\n {((shareable.display_price as string) ?? shareable.price) ||\n \"\"}\n </p>\n </span>\n </div>\n ))}\n </div>\n\n {/* Navigation arrows */}\n <div\n className={`absolute inset-x-0 top-1/2 flex w-full -translate-y-1/2 items-center justify-between px-8`}\n >\n <ScrollArrows\n onPrevious={() => scrollByAmount(\"prev\")}\n onNext={() => scrollByAmount(\"next\")}\n />\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const nestedWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"NestedWidget\",\n displayName: \"Nested Widget\",\n tabsConfig: [\n { id: \"styling\", label: \"Styling\" },\n { id: \"data\", label: \"Data\" },\n ],\n dataSourceTargetProps: [\"shareables\"],\n fields: [\n // Content tab - Resource group\n {\n key: \"resource\",\n label: \"Primary Media\",\n type: \"resource\",\n description: \"Select the primary media displayed in the large panel\",\n allowedTypes: [\"Medium\"],\n tab: \"styling\",\n group: \"Content\",\n },\n // Content tab - Title group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed over the primary media\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Main title displayed over the primary media\",\n defaultValue: \"Featured Collection\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n label: \"Title Font Size\",\n defaultValue: \"xl\",\n key: \"titleFontSize\",\n description: \"Font size for the widget title\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n defaultValue: \"background\",\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n // Styling tab - Design group\n getHeightField({\n key: \"primaryMediaHeight\",\n label: \"Primary Media Height\",\n description: \"Height of the primary media container\",\n defaultValue: \"400px\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"titleAlignment\",\n label: \"Content Alignment\",\n type: \"alignment\",\n description: \"Alignment of the content inside the primary media\",\n defaultValue: { horizontal: \"left\", vertical: \"bottom\" },\n options: {\n horizontalEnabled: true,\n verticalEnabled: true,\n },\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"separator2\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n defaultValue: 4,\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding used throughout the widget\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n defaultValue: \"md\",\n label: \"Border Radius\",\n key: \"borderRadius\",\n description: \"Rounded corners for the widget\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"overlayEnabled\",\n label: \"Enable Overlay\",\n type: \"boolean\",\n description:\n \"Add a dark overlay to the primary media for better text readability\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"overlayType\",\n label: \"Overlay Type\",\n type: \"buttonGroup\",\n description: \"Type of overlay effect\",\n defaultValue: \"gradient\",\n options: [\n { label: \"Solid\", value: \"solid\" },\n { label: \"Gradient\", value: \"gradient\" },\n ],\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"overlayEnabled\",\n },\n {\n key: \"overlayIntensity\",\n label: \"Overlay Intensity\",\n type: \"slider\",\n description: \"Opacity of the overlay (0-100)\",\n min: 0,\n max: 100,\n step: 5,\n defaultValue: 50,\n unit: \"%\",\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"overlayEnabled\",\n },\n // Styling tab - Nested Media Styling group\n getGapField({\n label: \"Gap\",\n defaultValue: \"md\",\n key: \"gap\",\n description: \"Gap between nested media items\",\n tab: \"styling\",\n group: \"Nested Design\",\n }),\n getColorField({\n defaultValue: \"foreground\",\n key: \"nestedTextColor\",\n label: \"Nested Text Color\",\n description: \"Color for nested media labels\",\n tab: \"styling\",\n group: \"Nested Design\",\n }),\n {\n type: \"background\",\n defaultValue: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background color for nested media container\",\n tab: \"styling\",\n group: \"Nested Design\",\n },\n // Data tab\n {\n key: \"dataSource\",\n label: \"Data Source\",\n type: \"dataSource\",\n description: \"Configure dynamic data fetching from an API\",\n tab: \"data\",\n group: \"Data Configuration\",\n },\n ],\n // Per-item configuration schema for custom data sources\n itemConfigSchema: {\n description: \"Configure settings for this item\",\n fields: [\n {\n key: \"title\",\n label: \"Custom Title\",\n type: \"text\",\n description: \"Override the item's title for this widget\",\n },\n ],\n },\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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Y;GACZ,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;wDAEa;GACb,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;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;IAAE,YAAY;IAAQ,UAAU;IAAU;GACxD,SAAS;IACP,mBAAmB;IACnB,iBAAiB;IAClB;GACD,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,MAAM;GACN,OAAO;GACP,KAAK;GACL,OAAO;GACR;yDACe;GACd,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;8DACmB;GACnB,cAAc;GACd,OAAO;GACP,KAAK;GACL,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aACE;GACF,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,SAAS,CACP;IAAE,OAAO;IAAS,OAAO;IAAS,EAClC;IAAE,OAAO;IAAY,OAAO;IAAY,CACzC;GACD,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,KAAK;GACL,MAAM;GACN,cAAc;GACd,MAAM;GACN,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;qDAEW;GACV,OAAO;GACP,cAAc;GACd,KAAK;GACL,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;uDACY;GACZ,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,MAAM;GACN,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR;EAED;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACR;EACF;CAED,kBAAkB;EAChB,aAAa;EACb,QAAQ,CACN;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACd,CACF;EACF;CACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"TableWidget--yLJTqoW.mjs","names":[],"sources":["../src/widgets/TableWidget.tsx"],"sourcesContent":["import { useState, useMemo, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n} from \"../core/fields\";\nimport { Input } from \"@fluid-app/ui-primitives\";\nimport {\n MediaRenderer,\n getMediaPropsFromShareable,\n} from \"../components/MediaRenderer\";\nimport { type ShareableItem } from \"@fluid-app/portal-core/types\";\n\n// Column definition for the table\ntype ColumnDef = {\n key: string;\n label: string;\n sortable: boolean;\n render?: (value: unknown, item: ShareableItem) => React.ReactNode;\n};\n\nconst DEFAULT_DATA: ShareableItem[] = [];\n\n// ---------------------------------------------------------------------------\n// Column cell renderers\n// ---------------------------------------------------------------------------\n\nfunction ImageCellRenderer(_value: unknown, item: ShareableItem) {\n return (\n <div className=\"h-10 w-10 rounded object-cover\">\n <MediaRenderer {...getMediaPropsFromShareable(item)} />\n </div>\n );\n}\n\nfunction PriceCellRenderer(_value: unknown, item: ShareableItem) {\n return ((item.display_price as string) ?? item.price) || \"-\";\n}\n\nfunction StatusCellRenderer(value: unknown) {\n const status = String(value || \"unknown\").toLowerCase();\n const statusStyles: Record<string, string> = {\n active: \"bg-primary text-primary-foreground\",\n inactive: \"bg-secondary text-secondary-foreground\",\n unknown: \"bg-muted text-muted-foreground\",\n };\n return (\n <span\n className={`inline-flex rounded-full px-2 py-1 text-xs font-medium ${statusStyles[status] || \"bg-muted text-foreground\"}`}\n >\n {String(value || \"Unknown\")}\n </span>\n );\n}\n\n// Default columns for product data\nconst defaultColumns: ColumnDef[] = [\n {\n key: \"imageUrl\",\n label: \"Image\",\n sortable: false,\n render: ImageCellRenderer,\n },\n {\n key: \"title\",\n label: \"Title\",\n sortable: true,\n },\n {\n key: \"price\",\n label: \"Price\",\n sortable: true,\n render: PriceCellRenderer,\n },\n {\n key: \"status\",\n label: \"Status\",\n sortable: true,\n render: StatusCellRenderer,\n },\n];\n\ntype TableWidgetProps = ComponentProps<\"div\"> & {\n // Title\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n // Styling\n background?: BackgroundValue;\n alternatingColorEnabled?: boolean;\n textColor?: ColorOptions;\n headerBackgroundColor?: ColorOptions;\n headerTextColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n\n // Data\n data?: ShareableItem[];\n\n // Features\n filterEnabled?: boolean;\n sortingEnabled?: boolean;\n paginationEnabled?: boolean;\n maxRowsPerPage?: number;\n};\n\nexport function TableWidget({\n // Title defaults\n titleEnabled = true,\n titleText = \"Products\",\n titleFontSize = \"xl\",\n titleColor = \"foreground\",\n\n // Styling defaults\n background = {\n type: \"solid\",\n color: \"background\",\n },\n alternatingColorEnabled = true,\n textColor = \"foreground\",\n headerBackgroundColor = \"muted\",\n headerTextColor = \"foreground\",\n padding = 4,\n borderRadius = \"md\",\n\n // Data\n data = DEFAULT_DATA,\n\n // Feature defaults\n filterEnabled = true,\n sortingEnabled = true,\n paginationEnabled = true,\n maxRowsPerPage = 5,\n\n className,\n ...props\n}: TableWidgetProps): React.JSX.Element {\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 const pageSize = maxRowsPerPage;\n\n // State for filtering, sorting, and pagination\n const [globalFilter, setGlobalFilter] = useState(\"\");\n const [sortConfig, setSortConfig] = useState<{\n key: string;\n direction: \"asc\" | \"desc\";\n } | null>(null);\n const [currentPage, setCurrentPage] = useState(1);\n\n const columns = defaultColumns;\n\n // Filter data\n const filteredData = useMemo(() => {\n let result = [...data];\n\n if (globalFilter) {\n const lowerFilter = globalFilter.toLowerCase();\n result = result.filter((item) =>\n columns.some((col) => {\n const value = item[col.key];\n return String(value ?? \"\")\n .toLowerCase()\n .includes(lowerFilter);\n }),\n );\n }\n\n return result;\n }, [data, globalFilter, columns]);\n\n // Sort data\n const sortedData = useMemo(() => {\n if (!sortConfig) return filteredData;\n\n return [...filteredData].sort((a, b) => {\n const aValue = a[sortConfig.key];\n const bValue = b[sortConfig.key];\n\n // Handle null/undefined\n if (aValue == null && bValue == null) return 0;\n if (aValue == null) return sortConfig.direction === \"asc\" ? 1 : -1;\n if (bValue == null) return sortConfig.direction === \"asc\" ? -1 : 1;\n\n // Compare values\n let comparison = 0;\n if (typeof aValue === \"number\" && typeof bValue === \"number\") {\n comparison = aValue - bValue;\n } else {\n comparison = String(aValue).localeCompare(String(bValue));\n }\n\n return sortConfig.direction === \"asc\" ? comparison : -comparison;\n });\n }, [filteredData, sortConfig]);\n\n // Paginate data\n const paginatedData = useMemo(() => {\n if (!paginationEnabled) return sortedData;\n\n const startIndex = (currentPage - 1) * pageSize;\n return sortedData.slice(startIndex, startIndex + pageSize);\n }, [sortedData, currentPage, pageSize, paginationEnabled]);\n\n const totalPages = Math.ceil(sortedData.length / pageSize);\n\n // Reset to page 1 when filters change\n const handleGlobalFilterChange = (value: string) => {\n setGlobalFilter(value);\n setCurrentPage(1);\n };\n\n // Handle sort\n const handleSort = (key: string) => {\n if (!sortingEnabled) return;\n\n setSortConfig((prev) => {\n if (prev?.key !== key) return { key, direction: \"asc\" };\n if (prev.direction === \"asc\") return { key, direction: \"desc\" };\n return null;\n });\n };\n\n // Get sort indicator\n const getSortIndicator = (key: string) => {\n if (sortConfig?.key !== key) return null;\n return sortConfig.direction === \"asc\" ? \" ↑\" : \" ↓\";\n };\n\n // Empty state\n if (data.length === 0) {\n return (\n <div\n className={`@container rounded-${borderRadius} bg-${backgroundColor} p-${padding} ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n <div className=\"text-muted-foreground flex min-h-[200px] flex-col items-center justify-center gap-2\">\n <div className=\"text-4xl\">📋</div>\n <p className=\"text-sm\">No data available</p>\n <p className=\"text-muted-foreground/70 text-xs\">\n Connect a data source to display table data\n </p>\n </div>\n </div>\n );\n }\n\n return (\n <div\n className={`@container overflow-hidden ${paginationEnabled ? \"\" : \"overflow-y-auto\"} rounded-${borderRadius} text-${textColor} ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n <div\n className={`flex items-center justify-between p-${padding} bg-${backgroundColor}`}\n >\n {/* Title */}\n {titleEnabled && titleText && (\n <h2\n className={`text-${titleFontSize === \"md\" ? \"base\" : titleFontSize} font-bold text-${titleColor}`}\n >\n {titleText}\n </h2>\n )}\n\n {/* Global Search */}\n {filterEnabled && (\n <Input\n type=\"text\"\n placeholder=\"Search all columns...\"\n value={globalFilter}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n handleGlobalFilterChange(e.target.value)\n }\n className={`w-full rounded-md border border-${headerBackgroundColor}-600 bg-${headerBackgroundColor}-400 ring-offset-muted px-3 py-2 text-sm placeholder:text-${headerTextColor}-900 focus-visible:ring-primary focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none md:w-64`}\n />\n )}\n </div>\n\n {/* Table */}\n <div className=\"overflow-x-auto\">\n <table className=\"w-full border-collapse\">\n <thead>\n <tr\n className={`bg-${headerBackgroundColor}-400 border-${headerBackgroundColor}-600 border-y`}\n >\n {columns.map((col) => (\n <th\n key={col.key}\n className={`px-4 py-3 text-left text-sm font-semibold text-${headerTextColor} ${col.sortable && sortingEnabled ? \"cursor-pointer select-none hover:opacity-80\" : \"\"}`}\n {...(col.sortable && sortingEnabled\n ? {\n role: \"button\" as const,\n tabIndex: 0,\n onClick: () => handleSort(col.key),\n onKeyDown: (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleSort(col.key);\n }\n },\n }\n : {})}\n >\n <div className=\"flex flex-col gap-1\">\n <span>\n {col.label}\n {col.sortable &&\n sortingEnabled &&\n getSortIndicator(col.key)}\n </span>\n </div>\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {paginatedData.map((item, index) => (\n <tr\n key={item.id ?? index}\n className={`h-17 border-b border-${backgroundColor}-600 last:border-none bg-${backgroundColor} ${alternatingColorEnabled ? `even:bg-${backgroundColor}-400` : \"\"}`}\n >\n {columns.map((col) => (\n <td key={col.key} className=\"px-4 py-3 text-sm\">\n {col.render\n ? col.render(item[col.key], item)\n : String(item[col.key] ?? \"-\")}\n </td>\n ))}\n </tr>\n ))}\n {/* Empty rows to fill the last page for consistent pagination position */}\n {paginationEnabled &&\n paginatedData.length < pageSize &&\n paginatedData.length > 0 &&\n Array.from({ length: pageSize - paginatedData.length }).map(\n (_, index) => (\n <tr\n key={`empty-${index}`}\n className={`h-17 border-b border-${backgroundColor}-600 last:border-none bg-${backgroundColor} ${alternatingColorEnabled ? `even:bg-${backgroundColor}-400` : \"\"}`}\n >\n {columns.map((col) => (\n <td key={col.key} className=\"px-4 py-3 text-sm\">\n &nbsp;\n </td>\n ))}\n </tr>\n ),\n )}\n </tbody>\n </table>\n </div>\n\n {/* No results message */}\n {paginatedData.length === 0 && data.length > 0 && (\n <div className={`py-8 text-center bg-${backgroundColor}`}>\n <p className=\"text-sm\">No results found</p>\n <p className=\"text-xs\">Try adjusting your search</p>\n </div>\n )}\n\n {/* Pagination */}\n {paginationEnabled && totalPages > 1 && (\n <div\n className={`flex flex-col items-center justify-between gap-2 border-t border-${backgroundColor}-600 p-${padding} @md:flex-row bg-${backgroundColor}-400 text-${textColor}`}\n >\n <p className=\"text-sm\">\n Showing {(currentPage - 1) * pageSize + 1}-\n {Math.min(currentPage * pageSize, sortedData.length)} of{\" \"}\n {sortedData.length} results\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}\n disabled={currentPage === 1}\n className={`rounded-md border border-${headerBackgroundColor}-600 bg-${headerBackgroundColor} ring-offset-muted placeholder:text-muted-foreground focus-visible:ring-primary px-3 py-1 text-sm transition-opacity hover:opacity-80 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50`}\n >\n Previous\n </button>\n <span className=\"text-sm\">\n Page {currentPage} of {totalPages}\n </span>\n <button\n onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))}\n disabled={currentPage === totalPages}\n className={`rounded-md border border-${headerBackgroundColor}-600 bg-${headerBackgroundColor} ring-offset-muted placeholder:text-muted-foreground focus-visible:ring-primary px-3 py-1 text-sm transition-opacity hover:opacity-80 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50`}\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const tableWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"TableWidget\",\n displayName: \"Table Widget\",\n tabsConfig: [\n { id: \"styling\", label: \"Styling\" },\n { id: \"behavior\", label: \"Behavior\" },\n { id: \"data\", label: \"Data\" },\n ],\n dataSourceTargetProps: [\"data\"],\n fields: [\n // Content Tab - Title Group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed above the table\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Title text displayed above the table\",\n defaultValue: \"Products\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n label: \"Title Font Size\",\n defaultValue: \"xl\",\n key: \"titleFontSize\",\n description: \"Font size for the widget title\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n\n // Styling Tab - Design Group\n {\n type: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background for the table container\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"alternatingColorEnabled\",\n label: \"Enable Alternating Colors\",\n type: \"boolean\",\n description: \"Enable alternating colors for table rows\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n key: \"headerBackgroundColor\",\n label: \"Header Background\",\n description: \"Background color for the table header\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for table content\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"headerTextColor\",\n label: \"Header Text Color\",\n description: \"Text color for the table header\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the table container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the table container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n\n // Behavior Tab - Features Group\n {\n key: \"filterEnabled\",\n label: \"Enable Filters\",\n type: \"boolean\",\n description: \"Show global search and column filters\",\n defaultValue: true,\n tab: \"behavior\",\n group: \"Features\",\n },\n {\n key: \"sortingEnabled\",\n label: \"Enable Sorting\",\n type: \"boolean\",\n description: \"Allow sorting by clicking column headers\",\n defaultValue: true,\n tab: \"behavior\",\n group: \"Features\",\n },\n {\n key: \"paginationEnabled\",\n label: \"Enable Pagination\",\n type: \"boolean\",\n description: \"Split data into pages\",\n defaultValue: true,\n tab: \"behavior\",\n group: \"Features\",\n },\n {\n key: \"maxRowsPerPage\",\n label: \"Max Rows Per Page\",\n type: \"number\",\n description: \"Maximum number of rows to display per page\",\n min: 1,\n max: 50,\n step: 1,\n defaultValue: 5,\n tab: \"behavior\",\n group: \"Features\",\n requiresKeyToBeTrue: \"paginationEnabled\",\n },\n\n // Data Tab\n {\n key: \"dataSource\",\n label: \"Data Source\",\n type: \"dataSource\",\n description: \"Configure data source for the table\",\n tab: \"data\",\n group: \"Data Configuration\",\n },\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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F;GACE,KAAK;GACL,MAAM;GACN,OAAO;GACP,KAAK;GACL,OAAO;GACR;EACD,gBAAgB;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,qBAAqB;GACnB,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,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,KAAK;GACL,MAAM;GACN,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EAGD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACR;EACF;CACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"TableWidget-TfQfFHft.cjs","names":["MediaRenderer","getMediaPropsFromShareable","Input"],"sources":["../src/widgets/TableWidget.tsx"],"sourcesContent":["import { useState, useMemo, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n} from \"../core/fields\";\nimport { Input } from \"@fluid-app/ui-primitives\";\nimport {\n MediaRenderer,\n getMediaPropsFromShareable,\n} from \"../components/MediaRenderer\";\nimport { type ShareableItem } from \"@fluid-app/portal-core/types\";\n\n// Column definition for the table\ntype ColumnDef = {\n key: string;\n label: string;\n sortable: boolean;\n render?: (value: unknown, item: ShareableItem) => React.ReactNode;\n};\n\nconst DEFAULT_DATA: ShareableItem[] = [];\n\n// ---------------------------------------------------------------------------\n// Column cell renderers\n// ---------------------------------------------------------------------------\n\nfunction ImageCellRenderer(_value: unknown, item: ShareableItem) {\n return (\n <div className=\"h-10 w-10 rounded object-cover\">\n <MediaRenderer {...getMediaPropsFromShareable(item)} />\n </div>\n );\n}\n\nfunction PriceCellRenderer(_value: unknown, item: ShareableItem) {\n return ((item.display_price as string) ?? item.price) || \"-\";\n}\n\nfunction StatusCellRenderer(value: unknown) {\n const status = String(value || \"unknown\").toLowerCase();\n const statusStyles: Record<string, string> = {\n active: \"bg-primary text-primary-foreground\",\n inactive: \"bg-secondary text-secondary-foreground\",\n unknown: \"bg-muted text-muted-foreground\",\n };\n return (\n <span\n className={`inline-flex rounded-full px-2 py-1 text-xs font-medium ${statusStyles[status] || \"bg-muted text-foreground\"}`}\n >\n {String(value || \"Unknown\")}\n </span>\n );\n}\n\n// Default columns for product data\nconst defaultColumns: ColumnDef[] = [\n {\n key: \"imageUrl\",\n label: \"Image\",\n sortable: false,\n render: ImageCellRenderer,\n },\n {\n key: \"title\",\n label: \"Title\",\n sortable: true,\n },\n {\n key: \"price\",\n label: \"Price\",\n sortable: true,\n render: PriceCellRenderer,\n },\n {\n key: \"status\",\n label: \"Status\",\n sortable: true,\n render: StatusCellRenderer,\n },\n];\n\ntype TableWidgetProps = ComponentProps<\"div\"> & {\n // Title\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n // Styling\n background?: BackgroundValue;\n alternatingColorEnabled?: boolean;\n textColor?: ColorOptions;\n headerBackgroundColor?: ColorOptions;\n headerTextColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n\n // Data\n data?: ShareableItem[];\n\n // Features\n filterEnabled?: boolean;\n sortingEnabled?: boolean;\n paginationEnabled?: boolean;\n maxRowsPerPage?: number;\n};\n\nexport function TableWidget({\n // Title defaults\n titleEnabled = true,\n titleText = \"Products\",\n titleFontSize = \"xl\",\n titleColor = \"foreground\",\n\n // Styling defaults\n background = {\n type: \"solid\",\n color: \"background\",\n },\n alternatingColorEnabled = true,\n textColor = \"foreground\",\n headerBackgroundColor = \"muted\",\n headerTextColor = \"foreground\",\n padding = 4,\n borderRadius = \"md\",\n\n // Data\n data = DEFAULT_DATA,\n\n // Feature defaults\n filterEnabled = true,\n sortingEnabled = true,\n paginationEnabled = true,\n maxRowsPerPage = 5,\n\n className,\n ...props\n}: TableWidgetProps): React.JSX.Element {\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 const pageSize = maxRowsPerPage;\n\n // State for filtering, sorting, and pagination\n const [globalFilter, setGlobalFilter] = useState(\"\");\n const [sortConfig, setSortConfig] = useState<{\n key: string;\n direction: \"asc\" | \"desc\";\n } | null>(null);\n const [currentPage, setCurrentPage] = useState(1);\n\n const columns = defaultColumns;\n\n // Filter data\n const filteredData = useMemo(() => {\n let result = [...data];\n\n if (globalFilter) {\n const lowerFilter = globalFilter.toLowerCase();\n result = result.filter((item) =>\n columns.some((col) => {\n const value = item[col.key];\n return String(value ?? \"\")\n .toLowerCase()\n .includes(lowerFilter);\n }),\n );\n }\n\n return result;\n }, [data, globalFilter, columns]);\n\n // Sort data\n const sortedData = useMemo(() => {\n if (!sortConfig) return filteredData;\n\n return [...filteredData].sort((a, b) => {\n const aValue = a[sortConfig.key];\n const bValue = b[sortConfig.key];\n\n // Handle null/undefined\n if (aValue == null && bValue == null) return 0;\n if (aValue == null) return sortConfig.direction === \"asc\" ? 1 : -1;\n if (bValue == null) return sortConfig.direction === \"asc\" ? -1 : 1;\n\n // Compare values\n let comparison = 0;\n if (typeof aValue === \"number\" && typeof bValue === \"number\") {\n comparison = aValue - bValue;\n } else {\n comparison = String(aValue).localeCompare(String(bValue));\n }\n\n return sortConfig.direction === \"asc\" ? comparison : -comparison;\n });\n }, [filteredData, sortConfig]);\n\n // Paginate data\n const paginatedData = useMemo(() => {\n if (!paginationEnabled) return sortedData;\n\n const startIndex = (currentPage - 1) * pageSize;\n return sortedData.slice(startIndex, startIndex + pageSize);\n }, [sortedData, currentPage, pageSize, paginationEnabled]);\n\n const totalPages = Math.ceil(sortedData.length / pageSize);\n\n // Reset to page 1 when filters change\n const handleGlobalFilterChange = (value: string) => {\n setGlobalFilter(value);\n setCurrentPage(1);\n };\n\n // Handle sort\n const handleSort = (key: string) => {\n if (!sortingEnabled) return;\n\n setSortConfig((prev) => {\n if (prev?.key !== key) return { key, direction: \"asc\" };\n if (prev.direction === \"asc\") return { key, direction: \"desc\" };\n return null;\n });\n };\n\n // Get sort indicator\n const getSortIndicator = (key: string) => {\n if (sortConfig?.key !== key) return null;\n return sortConfig.direction === \"asc\" ? \" ↑\" : \" ↓\";\n };\n\n // Empty state\n if (data.length === 0) {\n return (\n <div\n className={`@container rounded-${borderRadius} bg-${backgroundColor} p-${padding} ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n <div className=\"text-muted-foreground flex min-h-[200px] flex-col items-center justify-center gap-2\">\n <div className=\"text-4xl\">📋</div>\n <p className=\"text-sm\">No data available</p>\n <p className=\"text-muted-foreground/70 text-xs\">\n Connect a data source to display table data\n </p>\n </div>\n </div>\n );\n }\n\n return (\n <div\n className={`@container overflow-hidden ${paginationEnabled ? \"\" : \"overflow-y-auto\"} rounded-${borderRadius} text-${textColor} ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n <div\n className={`flex items-center justify-between p-${padding} bg-${backgroundColor}`}\n >\n {/* Title */}\n {titleEnabled && titleText && (\n <h2\n className={`text-${titleFontSize === \"md\" ? \"base\" : titleFontSize} font-bold text-${titleColor}`}\n >\n {titleText}\n </h2>\n )}\n\n {/* Global Search */}\n {filterEnabled && (\n <Input\n type=\"text\"\n placeholder=\"Search all columns...\"\n value={globalFilter}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n handleGlobalFilterChange(e.target.value)\n }\n className={`w-full rounded-md border border-${headerBackgroundColor}-600 bg-${headerBackgroundColor}-400 ring-offset-muted px-3 py-2 text-sm placeholder:text-${headerTextColor}-900 focus-visible:ring-primary focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none md:w-64`}\n />\n )}\n </div>\n\n {/* Table */}\n <div className=\"overflow-x-auto\">\n <table className=\"w-full border-collapse\">\n <thead>\n <tr\n className={`bg-${headerBackgroundColor}-400 border-${headerBackgroundColor}-600 border-y`}\n >\n {columns.map((col) => (\n <th\n key={col.key}\n className={`px-4 py-3 text-left text-sm font-semibold text-${headerTextColor} ${col.sortable && sortingEnabled ? \"cursor-pointer select-none hover:opacity-80\" : \"\"}`}\n {...(col.sortable && sortingEnabled\n ? {\n role: \"button\" as const,\n tabIndex: 0,\n onClick: () => handleSort(col.key),\n onKeyDown: (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleSort(col.key);\n }\n },\n }\n : {})}\n >\n <div className=\"flex flex-col gap-1\">\n <span>\n {col.label}\n {col.sortable &&\n sortingEnabled &&\n getSortIndicator(col.key)}\n </span>\n </div>\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {paginatedData.map((item, index) => (\n <tr\n key={item.id ?? index}\n className={`h-17 border-b border-${backgroundColor}-600 last:border-none bg-${backgroundColor} ${alternatingColorEnabled ? `even:bg-${backgroundColor}-400` : \"\"}`}\n >\n {columns.map((col) => (\n <td key={col.key} className=\"px-4 py-3 text-sm\">\n {col.render\n ? col.render(item[col.key], item)\n : String(item[col.key] ?? \"-\")}\n </td>\n ))}\n </tr>\n ))}\n {/* Empty rows to fill the last page for consistent pagination position */}\n {paginationEnabled &&\n paginatedData.length < pageSize &&\n paginatedData.length > 0 &&\n Array.from({ length: pageSize - paginatedData.length }).map(\n (_, index) => (\n <tr\n key={`empty-${index}`}\n className={`h-17 border-b border-${backgroundColor}-600 last:border-none bg-${backgroundColor} ${alternatingColorEnabled ? `even:bg-${backgroundColor}-400` : \"\"}`}\n >\n {columns.map((col) => (\n <td key={col.key} className=\"px-4 py-3 text-sm\">\n &nbsp;\n </td>\n ))}\n </tr>\n ),\n )}\n </tbody>\n </table>\n </div>\n\n {/* No results message */}\n {paginatedData.length === 0 && data.length > 0 && (\n <div className={`py-8 text-center bg-${backgroundColor}`}>\n <p className=\"text-sm\">No results found</p>\n <p className=\"text-xs\">Try adjusting your search</p>\n </div>\n )}\n\n {/* Pagination */}\n {paginationEnabled && totalPages > 1 && (\n <div\n className={`flex flex-col items-center justify-between gap-2 border-t border-${backgroundColor}-600 p-${padding} @md:flex-row bg-${backgroundColor}-400 text-${textColor}`}\n >\n <p className=\"text-sm\">\n Showing {(currentPage - 1) * pageSize + 1}-\n {Math.min(currentPage * pageSize, sortedData.length)} of{\" \"}\n {sortedData.length} results\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}\n disabled={currentPage === 1}\n className={`rounded-md border border-${headerBackgroundColor}-600 bg-${headerBackgroundColor} ring-offset-muted placeholder:text-muted-foreground focus-visible:ring-primary px-3 py-1 text-sm transition-opacity hover:opacity-80 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50`}\n >\n Previous\n </button>\n <span className=\"text-sm\">\n Page {currentPage} of {totalPages}\n </span>\n <button\n onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))}\n disabled={currentPage === totalPages}\n className={`rounded-md border border-${headerBackgroundColor}-600 bg-${headerBackgroundColor} ring-offset-muted placeholder:text-muted-foreground focus-visible:ring-primary px-3 py-1 text-sm transition-opacity hover:opacity-80 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50`}\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const tableWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"TableWidget\",\n displayName: \"Table Widget\",\n tabsConfig: [\n { id: \"styling\", label: \"Styling\" },\n { id: \"behavior\", label: \"Behavior\" },\n { id: \"data\", label: \"Data\" },\n ],\n dataSourceTargetProps: [\"data\"],\n fields: [\n // Content Tab - Title Group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed above the table\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Title text displayed above the table\",\n defaultValue: \"Products\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n label: \"Title Font Size\",\n defaultValue: \"xl\",\n key: \"titleFontSize\",\n description: \"Font size for the widget title\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n\n // Styling Tab - Design Group\n {\n type: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background for the table container\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"alternatingColorEnabled\",\n label: \"Enable Alternating Colors\",\n type: \"boolean\",\n description: \"Enable alternating colors for table rows\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n key: \"headerBackgroundColor\",\n label: \"Header Background\",\n description: \"Background color for the table header\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for table content\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"headerTextColor\",\n label: \"Header Text Color\",\n description: \"Text color for the table header\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the table container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the table container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n\n // Behavior Tab - Features Group\n {\n key: \"filterEnabled\",\n label: \"Enable Filters\",\n type: \"boolean\",\n description: \"Show global search and column filters\",\n defaultValue: true,\n tab: \"behavior\",\n group: \"Features\",\n },\n {\n key: \"sortingEnabled\",\n label: \"Enable Sorting\",\n type: \"boolean\",\n description: \"Allow sorting by clicking column headers\",\n defaultValue: true,\n tab: \"behavior\",\n group: \"Features\",\n },\n {\n key: \"paginationEnabled\",\n label: \"Enable Pagination\",\n type: \"boolean\",\n description: \"Split data into pages\",\n defaultValue: true,\n tab: \"behavior\",\n group: \"Features\",\n },\n {\n key: \"maxRowsPerPage\",\n label: \"Max Rows Per Page\",\n type: \"number\",\n description: \"Maximum number of rows to display per page\",\n min: 1,\n max: 50,\n step: 1,\n defaultValue: 5,\n tab: \"behavior\",\n group: \"Features\",\n requiresKeyToBeTrue: \"paginationEnabled\",\n },\n\n // Data Tab\n {\n key: \"dataSource\",\n label: \"Data Source\",\n type: \"dataSource\",\n description: \"Configure data source for the table\",\n tab: \"data\",\n group: \"Data Configuration\",\n },\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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AAO;GACP,qBAAqB;GACtB;0DACgB;GACf,OAAO;GACP,cAAc;GACd,KAAK;GACL,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;uDACY;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;EAGF;GACE,MAAM;GACN,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;uDACa;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;uDACY;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;uDACY;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;yDACe;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;8DACmB;GACnB,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,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,KAAK;GACL,MAAM;GACN,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EAGD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACR;EACF;CACF"}