@fluid-app/portal-sdk 0.1.238 → 0.1.240

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 (129) hide show
  1. package/dist/{CalendarWidget-BaGML5Xh.mjs → CalendarWidget-C03VcDLQ.mjs} +2 -2
  2. package/dist/{CalendarWidget-BaGML5Xh.mjs.map → CalendarWidget-C03VcDLQ.mjs.map} +1 -1
  3. package/dist/{CalendarWidget-oGK122s9.cjs → CalendarWidget-C4Dv_TUk.cjs} +2 -2
  4. package/dist/{CalendarWidget-oGK122s9.cjs.map → CalendarWidget-C4Dv_TUk.cjs.map} +1 -1
  5. package/dist/{CardWidget-CqYjGkq-.mjs → CardWidget-2wcjCf2M.mjs} +2 -2
  6. package/dist/{CardWidget-CqYjGkq-.mjs.map → CardWidget-2wcjCf2M.mjs.map} +1 -1
  7. package/dist/{CardWidget-DjhK0yr-.cjs → CardWidget-BQl-8Xrt.cjs} +3 -3
  8. package/dist/{CardWidget-CSLSlKM6.cjs → CardWidget-D-KEikO_.cjs} +2 -2
  9. package/dist/{CardWidget-CSLSlKM6.cjs.map → CardWidget-D-KEikO_.cjs.map} +1 -1
  10. package/dist/{CarouselWidget-CdQhlRrW.mjs → CarouselWidget-Cn5P4FVN.mjs} +93 -84
  11. package/dist/CarouselWidget-Cn5P4FVN.mjs.map +1 -0
  12. package/dist/{CarouselWidget-DlxYQB5j.cjs → CarouselWidget-Cu1b3ERq.cjs} +93 -84
  13. package/dist/CarouselWidget-Cu1b3ERq.cjs.map +1 -0
  14. package/dist/{CatchUpWidget-BQjtjcGR.mjs → CatchUpWidget-B9CI7lq0.mjs} +2 -2
  15. package/dist/{CatchUpWidget-BQjtjcGR.mjs.map → CatchUpWidget-B9CI7lq0.mjs.map} +1 -1
  16. package/dist/{CatchUpWidget-B1Muaurg.cjs → CatchUpWidget-BzgybvuC.cjs} +2 -2
  17. package/dist/{CatchUpWidget-B1Muaurg.cjs.map → CatchUpWidget-BzgybvuC.cjs.map} +1 -1
  18. package/dist/ContainerWidget-CDbB8c0E.cjs +8 -0
  19. package/dist/{ContainerWidget-DYThUtiZ.mjs → ContainerWidget-DNenbORS.mjs} +2 -2
  20. package/dist/{ContainerWidget-DYThUtiZ.mjs.map → ContainerWidget-DNenbORS.mjs.map} +1 -1
  21. package/dist/{ContainerWidget-Cjwrq2MS.cjs → ContainerWidget-DbAhQKbY.cjs} +2 -2
  22. package/dist/{ContainerWidget-Cjwrq2MS.cjs.map → ContainerWidget-DbAhQKbY.cjs.map} +1 -1
  23. package/dist/{FluidProvider-B3DjYoUW.mjs → FluidProvider-BbXSELEP.mjs} +67 -84
  24. package/dist/FluidProvider-BbXSELEP.mjs.map +1 -0
  25. package/dist/{FluidProvider-DcpUKHrn.cjs → FluidProvider-DRXysbXj.cjs} +67 -84
  26. package/dist/FluidProvider-DRXysbXj.cjs.map +1 -0
  27. package/dist/{ImageWidget-xcE0sFf-.cjs → ImageWidget-CbQVxMe3.cjs} +2 -2
  28. package/dist/{ImageWidget-xcE0sFf-.cjs.map → ImageWidget-CbQVxMe3.cjs.map} +1 -1
  29. package/dist/{ImageWidget-CFTpbu8X.mjs → ImageWidget-vNWT_O1E.mjs} +2 -2
  30. package/dist/{ImageWidget-CFTpbu8X.mjs.map → ImageWidget-vNWT_O1E.mjs.map} +1 -1
  31. package/dist/{LayoutWidget-CK-SvFQL.cjs → LayoutWidget-Bt2I2XMy.cjs} +2 -2
  32. package/dist/{LayoutWidget-CK-SvFQL.cjs.map → LayoutWidget-Bt2I2XMy.cjs.map} +1 -1
  33. package/dist/{LayoutWidget-DuueFNAS.cjs → LayoutWidget-DKqZgCMu.cjs} +3 -3
  34. package/dist/{LayoutWidget-Cx5ZyXSU.mjs → LayoutWidget-UI5fbsx4.mjs} +2 -2
  35. package/dist/{LayoutWidget-Cx5ZyXSU.mjs.map → LayoutWidget-UI5fbsx4.mjs.map} +1 -1
  36. package/dist/{LinkWidget-B14FTQP7.cjs → LinkWidget-BoR7nVbH.cjs} +2 -2
  37. package/dist/{LinkWidget-B14FTQP7.cjs.map → LinkWidget-BoR7nVbH.cjs.map} +1 -1
  38. package/dist/{LinkWidget-CQHmKO-O.mjs → LinkWidget-CO-Cxf7Z.mjs} +2 -2
  39. package/dist/{LinkWidget-CQHmKO-O.mjs.map → LinkWidget-CO-Cxf7Z.mjs.map} +1 -1
  40. package/dist/{LinkWidget-CPmE8gpd.cjs → LinkWidget-M9YzMJT8.cjs} +2 -2
  41. package/dist/{ListWidget-YvCp7XDq.cjs → ListWidget-CuSjvwEw.cjs} +3 -3
  42. package/dist/{ListWidget-wBDnXWxa.cjs → ListWidget-CzljZ1LA.cjs} +3 -3
  43. package/dist/{ListWidget-wBDnXWxa.cjs.map → ListWidget-CzljZ1LA.cjs.map} +1 -1
  44. package/dist/{ListWidget-BnyD2Hpc.mjs → ListWidget-f88QhcGI.mjs} +3 -3
  45. package/dist/{ListWidget-BnyD2Hpc.mjs.map → ListWidget-f88QhcGI.mjs.map} +1 -1
  46. package/dist/{MediaRenderer-CfgWd0cC.cjs → MediaRenderer-CvN8Ku0i.cjs} +4 -4
  47. package/dist/MediaRenderer-CvN8Ku0i.cjs.map +1 -0
  48. package/dist/{MediaRenderer-CqUpv3St.mjs → MediaRenderer-DMdb_5xw.mjs} +4 -4
  49. package/dist/MediaRenderer-DMdb_5xw.mjs.map +1 -0
  50. package/dist/{MessagingScreen-CPBUg-32.cjs → MessagingScreen-DZvq5j13.cjs} +22 -22
  51. package/dist/{MessagingScreen-BBqwXPZB.mjs → MessagingScreen-DlRwCPg8.mjs} +2 -2
  52. package/dist/{MessagingScreen-BBqwXPZB.mjs.map → MessagingScreen-DlRwCPg8.mjs.map} +1 -1
  53. package/dist/{MessagingScreen-BzWV22JZ.cjs → MessagingScreen-_-sdlwh0.cjs} +2 -2
  54. package/dist/{MessagingScreen-BzWV22JZ.cjs.map → MessagingScreen-_-sdlwh0.cjs.map} +1 -1
  55. package/dist/{MySiteWidget-COj7yYQF.mjs → MySiteWidget-CQNASVaF.mjs} +2 -2
  56. package/dist/{MySiteWidget-COj7yYQF.mjs.map → MySiteWidget-CQNASVaF.mjs.map} +1 -1
  57. package/dist/{MySiteWidget-DRH4q_YV.cjs → MySiteWidget-CYiH2lmX.cjs} +2 -2
  58. package/dist/{MySiteWidget-DRH4q_YV.cjs.map → MySiteWidget-CYiH2lmX.cjs.map} +1 -1
  59. package/dist/{NestedWidget-C_2XwnW0.cjs → NestedWidget-CEoAO2sp.cjs} +3 -3
  60. package/dist/{NestedWidget-C_2XwnW0.cjs.map → NestedWidget-CEoAO2sp.cjs.map} +1 -1
  61. package/dist/{NestedWidget-CXIvsJdD.cjs → NestedWidget-CMCZjV6t.cjs} +3 -3
  62. package/dist/{NestedWidget-WJoWOFda.mjs → NestedWidget-RuyrOrFn.mjs} +3 -3
  63. package/dist/{NestedWidget-WJoWOFda.mjs.map → NestedWidget-RuyrOrFn.mjs.map} +1 -1
  64. package/dist/{PointsWidget-CLUWrFjZ.cjs → PointsWidget-C5cXxKlM.cjs} +2 -2
  65. package/dist/{PointsWidget-CLUWrFjZ.cjs.map → PointsWidget-C5cXxKlM.cjs.map} +1 -1
  66. package/dist/{PointsWidget-DoUljaNY.mjs → PointsWidget-icodgubL.mjs} +2 -2
  67. package/dist/{PointsWidget-DoUljaNY.mjs.map → PointsWidget-icodgubL.mjs.map} +1 -1
  68. package/dist/{ProfileScreen-CwQr_Km7.mjs → ProfileScreen-91WrZUpz.mjs} +2 -2
  69. package/dist/{ProfileScreen-CwQr_Km7.mjs.map → ProfileScreen-91WrZUpz.mjs.map} +1 -1
  70. package/dist/{ProfileScreen-MCfnv8eT.cjs → ProfileScreen-BalGphXn.cjs} +22 -22
  71. package/dist/{ProfileScreen-C0nmvuW1.cjs → ProfileScreen-SWcwqDK4.cjs} +2 -2
  72. package/dist/{ProfileScreen-C0nmvuW1.cjs.map → ProfileScreen-SWcwqDK4.cjs.map} +1 -1
  73. package/dist/{RecentActivityWidget-zQxtUECm.mjs → RecentActivityWidget-D1AlZgfV.mjs} +2 -2
  74. package/dist/{RecentActivityWidget-zQxtUECm.mjs.map → RecentActivityWidget-D1AlZgfV.mjs.map} +1 -1
  75. package/dist/{RecentActivityWidget-C6RwlUUw.cjs → RecentActivityWidget-DNyhUZNs.cjs} +2 -2
  76. package/dist/{RecentActivityWidget-C6RwlUUw.cjs.map → RecentActivityWidget-DNyhUZNs.cjs.map} +1 -1
  77. package/dist/{ScreenRenderer-Bk23YOtN.mjs → ScreenRenderer-Cl2aAJ7D.mjs} +2 -2
  78. package/dist/{ScreenRenderer-Bk23YOtN.mjs.map → ScreenRenderer-Cl2aAJ7D.mjs.map} +1 -1
  79. package/dist/{ScreenRenderer-aYfgv6mR.cjs → ScreenRenderer-xH01YkEQ.cjs} +2 -2
  80. package/dist/{ScreenRenderer-aYfgv6mR.cjs.map → ScreenRenderer-xH01YkEQ.cjs.map} +1 -1
  81. package/dist/{ShopScreen-CiGozvW4.cjs → ShopScreen-B6Bo1VOu.cjs} +6 -2
  82. package/dist/ShopScreen-B6Bo1VOu.cjs.map +1 -0
  83. package/dist/{ShopScreen-Brw7gNMu.cjs → ShopScreen-Ce29yINo.cjs} +22 -22
  84. package/dist/{ShopScreen-D39WpS6j.mjs → ShopScreen-DbMmVqSK.mjs} +6 -2
  85. package/dist/ShopScreen-DbMmVqSK.mjs.map +1 -0
  86. package/dist/{TableWidget-D4jQN-to.cjs → TableWidget-BIn1oRiJ.cjs} +4 -4
  87. package/dist/TableWidget-BIn1oRiJ.cjs.map +1 -0
  88. package/dist/{TableWidget-DWAYgQcl.cjs → TableWidget-C--8TSX7.cjs} +3 -3
  89. package/dist/{TableWidget-B0CRdzNf.mjs → TableWidget-dfUvhH0S.mjs} +4 -4
  90. package/dist/TableWidget-dfUvhH0S.mjs.map +1 -0
  91. package/dist/{ToDoWidget-VSaNmtWH.mjs → ToDoWidget-BciI_D70.mjs} +2 -2
  92. package/dist/{ToDoWidget-VSaNmtWH.mjs.map → ToDoWidget-BciI_D70.mjs.map} +1 -1
  93. package/dist/{ToDoWidget-BbeXt99H.cjs → ToDoWidget-OxT9z59F.cjs} +2 -2
  94. package/dist/{ToDoWidget-BbeXt99H.cjs.map → ToDoWidget-OxT9z59F.cjs.map} +1 -1
  95. package/dist/{ToDoWidget-YHmoDbVU.cjs → ToDoWidget-mSGQgnu3.cjs} +2 -2
  96. package/dist/{VideoWidget-Bc6ZAAaA.cjs → VideoWidget-CDcV0J5W.cjs} +2 -2
  97. package/dist/{VideoWidget-Bc6ZAAaA.cjs.map → VideoWidget-CDcV0J5W.cjs.map} +1 -1
  98. package/dist/{VideoWidget-DcWm239R.mjs → VideoWidget-Dj9wue7j.mjs} +2 -2
  99. package/dist/{VideoWidget-DcWm239R.mjs.map → VideoWidget-Dj9wue7j.mjs.map} +1 -1
  100. package/dist/WidgetInteractionContext-B1mELhQ_.mjs +28 -0
  101. package/dist/{WidgetInteractionContext-D0TJv70C.mjs.map → WidgetInteractionContext-B1mELhQ_.mjs.map} +1 -1
  102. package/dist/WidgetInteractionContext-DvPmzGqB.cjs +41 -0
  103. package/dist/{WidgetInteractionContext-Bs3LkFFH.cjs.map → WidgetInteractionContext-DvPmzGqB.cjs.map} +1 -1
  104. package/dist/index.cjs +81 -52
  105. package/dist/index.cjs.map +1 -1
  106. package/dist/index.d.cts.map +1 -1
  107. package/dist/index.d.mts.map +1 -1
  108. package/dist/index.mjs +81 -52
  109. package/dist/index.mjs.map +1 -1
  110. package/dist/{registry-context-BDH0vNHR.mjs → registry-context-CTHUCfEc.mjs} +17 -24
  111. package/dist/registry-context-CTHUCfEc.mjs.map +1 -0
  112. package/dist/{registry-context-C7-RLxVt.cjs → registry-context-CcZYS15Q.cjs} +17 -24
  113. package/dist/registry-context-CcZYS15Q.cjs.map +1 -0
  114. package/package.json +17 -17
  115. package/dist/CarouselWidget-CdQhlRrW.mjs.map +0 -1
  116. package/dist/CarouselWidget-DlxYQB5j.cjs.map +0 -1
  117. package/dist/ContainerWidget-NFBqSeRV.cjs +0 -8
  118. package/dist/FluidProvider-B3DjYoUW.mjs.map +0 -1
  119. package/dist/FluidProvider-DcpUKHrn.cjs.map +0 -1
  120. package/dist/MediaRenderer-CfgWd0cC.cjs.map +0 -1
  121. package/dist/MediaRenderer-CqUpv3St.mjs.map +0 -1
  122. package/dist/ShopScreen-CiGozvW4.cjs.map +0 -1
  123. package/dist/ShopScreen-D39WpS6j.mjs.map +0 -1
  124. package/dist/TableWidget-B0CRdzNf.mjs.map +0 -1
  125. package/dist/TableWidget-D4jQN-to.cjs.map +0 -1
  126. package/dist/WidgetInteractionContext-Bs3LkFFH.cjs +0 -18
  127. package/dist/WidgetInteractionContext-D0TJv70C.mjs +0 -11
  128. package/dist/registry-context-BDH0vNHR.mjs.map +0 -1
  129. package/dist/registry-context-C7-RLxVt.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ScreenRenderer-aYfgv6mR.cjs","names":["useDataSourceRegistryConfig"],"sources":["../../core/src/data-source-api-context.ts","../../widgets/src/contexts/RegistryContext.tsx","../../widgets/src/contexts/ScreenRendererContext.tsx","../../core/src/types/widget-schema.ts","../../core/src/data-sources/presets.ts","../../react/src/data-sources/use-widget-data.ts","../../react/src/data-sources/ErrorState.tsx","../../react/src/data-sources/DataAwareWidget.tsx","../../widgets/src/core/ScreenRenderer.tsx"],"sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { DataSourceApi } from \"./data-source-api\";\n\nconst DataSourceApiContext = createContext<DataSourceApi | null>(null);\n\nexport const DataSourceApiProvider = DataSourceApiContext.Provider;\n\n/**\n * Access the DataSourceApi adapter.\n * Throws if no DataSourceApiProvider ancestor exists.\n */\nexport function useDataSourceApi(): DataSourceApi {\n const api = useContext(DataSourceApiContext);\n if (!api) {\n throw new Error(\n \"useDataSourceApi must be used within a DataSourceApiProvider\",\n );\n }\n return api;\n}\n\n/**\n * Access the DataSourceApi adapter without throwing.\n * Returns null when no DataSourceApiProvider ancestor exists.\n * Use in isolated rendering contexts (Storybook, unit tests) where the\n * full provider stack may not be wired.\n */\nexport function useDataSourceApiOptional(): DataSourceApi | null {\n return useContext(DataSourceApiContext);\n}\n","import React, {\n createContext,\n useContext,\n type ComponentType,\n type ReactNode,\n} from \"react\";\nimport type { WidgetSchema } from \"@fluid-app/portal-core/types\";\n\n/**\n * Base props interface for widget components.\n * All widgets receive at least these props from the ScreenRenderer.\n */\nexport interface WidgetBaseProps {\n readonly widget: WidgetSchema;\n readonly path?: readonly number[];\n}\n\n/**\n * Generic widget component type.\n * Widgets receive WidgetBaseProps and may have additional props.\n */\nexport type WidgetComponent<P extends WidgetBaseProps = WidgetBaseProps> =\n ComponentType<P>;\n\n/**\n * Registry mapping widget type names to their components.\n * The keys are widget type strings (e.g., \"TextWidget\", \"ButtonWidget\").\n * Using WidgetComponent for the value type provides better type safety than `any`.\n */\nexport type WidgetRegistry = Readonly<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Widget props vary by type\n Record<string, WidgetComponent<any>>\n>;\n\n/**\n * Context for providing the widget registry to all components in the tree.\n * This eliminates prop drilling and makes the registry accessible anywhere.\n *\n * Default to undefined - registry must be provided by a RegistryProvider.\n */\nexport const RegistryContext: React.Context<WidgetRegistry | undefined> =\n createContext<WidgetRegistry | undefined>(undefined);\n\nexport interface RegistryProviderProps {\n registry?: WidgetRegistry;\n children: ReactNode;\n}\n\n/**\n * Provider component that makes the widget registry available to all descendants.\n * A registry must be provided either via props or by nesting within another RegistryProvider.\n */\nexport function RegistryProvider({\n registry,\n children,\n}: RegistryProviderProps): React.JSX.Element {\n // If no registry provided, inherit from parent provider\n const parentRegistry = useContext(RegistryContext);\n const contextValue = registry ?? parentRegistry;\n\n if (!contextValue) {\n throw new Error(\n \"RegistryProvider requires a registry prop or must be nested within another RegistryProvider.\",\n );\n }\n\n return (\n <RegistryContext.Provider value={contextValue}>\n {children}\n </RegistryContext.Provider>\n );\n}\n\n/**\n * Hook to access the widget registry from anywhere in the component tree.\n * Must be used within a RegistryProvider that has a registry prop.\n */\nexport function useRegistry(): WidgetRegistry {\n const registry = useContext(RegistryContext);\n\n if (!registry) {\n throw new Error(\n \"useRegistry must be used within a RegistryProvider with a registry prop.\",\n );\n }\n\n return registry;\n}\n","import React, { createContext, useContext, type ComponentType } from \"react\";\nimport type { WidgetSchema } from \"@fluid-app/portal-core/types\";\nimport type { WidgetRegistry } from \"./RegistryContext\";\n\n/**\n * Props that any ScreenRenderer must accept.\n * This is the minimal interface used by container widgets (e.g. LayoutWidget)\n * to render their children.\n */\nexport interface ScreenRendererComponentProps {\n screen: WidgetSchema[];\n registry?: WidgetRegistry;\n className?: string;\n}\n\n/**\n * Context for providing an alternative ScreenRenderer component.\n *\n * This allows packages like portal-builder to inject their own ScreenRenderer\n * (with edit mode, drag-and-drop, etc.) so that container widgets in portal-widgets\n * use the richer renderer instead of the basic view-only one.\n *\n * Default is undefined — container widgets fall back to the local ScreenRenderer import.\n */\nexport const ScreenRendererContext: React.Context<\n ComponentType<ScreenRendererComponentProps> | undefined\n> = createContext<ComponentType<ScreenRendererComponentProps> | undefined>(\n undefined,\n);\n\n/**\n * Hook to get the ScreenRenderer component from context.\n * Returns undefined if no override has been provided.\n */\nexport function useScreenRenderer():\n | ComponentType<ScreenRendererComponentProps>\n | undefined {\n return useContext(ScreenRendererContext);\n}\n","import type { DataSourceConfig } from \"../data-sources/types\";\n\n/**\n * Generic component type — avoids React dependency in core.\n * Accepts both function components and class component constructors.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyComponent = ((props: any) => any) | (new (props: any) => any);\n\n/**\n * Widget type names as a const object.\n * This serves as the single source of truth for widget discriminants.\n * Use `as const` for literal type inference (safety-as-const-deep-readonly rule).\n */\nexport const WIDGET_TYPE_NAMES = {\n Alert: \"AlertWidget\",\n BulletList: \"BulletListWidget\",\n Calendar: \"CalendarWidget\",\n Card: \"CardWidget\",\n Carousel: \"CarouselWidget\",\n CatchUp: \"CatchUpWidget\",\n Chart: \"ChartWidget\",\n Container: \"ContainerWidget\",\n Embed: \"EmbedWidget\",\n Image: \"ImageWidget\",\n Layout: \"LayoutWidget\",\n Link: \"LinkWidget\",\n List: \"ListWidget\",\n MySite: \"MySiteWidget\",\n Nested: \"NestedWidget\",\n Points: \"PointsWidget\",\n QuickLinks: \"QuickLinksWidget\",\n QuickShare: \"QuickShareWidget\",\n RecentActivity: \"RecentActivityWidget\",\n Separator: \"SeparatorWidget\",\n Spacer: \"SpacerWidget\",\n Table: \"TableWidget\",\n Text: \"TextWidget\",\n ToDo: \"ToDoWidget\",\n Video: \"VideoWidget\",\n} as const;\n\n/**\n * Union of all known widget type names.\n * Derived from WIDGET_TYPE_NAMES to avoid duplication (deriving-typeof-for-object-keys rule).\n */\nexport type WidgetTypeName =\n (typeof WIDGET_TYPE_NAMES)[keyof typeof WIDGET_TYPE_NAMES];\n\n/**\n * Legacy alias for backwards compatibility.\n * Prefer using WidgetTypeName for new code when you need the union type.\n */\nexport type WidgetType = string;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type WidgetRegistry = Record<WidgetType, AnyComponent>;\n\n/**\n * Base widget schema with loose typing for runtime data.\n * Use TypedWidgetSchema<T> when you have a known registry for better type safety.\n */\nexport type WidgetSchema = {\n readonly type: WidgetType;\n readonly props: Readonly<Record<string, unknown>>;\n readonly id?: string; // Optional unique identifier for drag-and-drop\n /** Optional data source configuration for data-bound widgets */\n readonly dataSource?: DataSourceConfig | undefined;\n /** Column index for masonry layouts (0-indexed) */\n readonly columnIndex?: number;\n};\n\n/**\n * Type-safe widget schema based on registry.\n * Uses discriminated unions - the `type` field serves as discriminant.\n * When narrowed (e.g., `if (widget.type === \"AlertWidget\")`),\n * TypeScript automatically knows the correct props type.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type TypedWidgetSchema<T extends Record<string, AnyComponent>> = {\n [K in keyof T]: {\n readonly type: K;\n readonly props: Readonly<\n T[K] extends (props: infer P) => any\n ? P\n : T[K] extends new (props: infer P) => any\n ? P\n : never\n >;\n readonly id?: string;\n readonly dataSource?: DataSourceConfig | undefined;\n /** Column index for masonry layouts (0-indexed) */\n readonly columnIndex?: number;\n };\n}[keyof T];\n\n/**\n * Widget path in the tree - array of indices.\n * Readonly tuple to prevent accidental mutation.\n */\nexport type WidgetPath = readonly number[];\n\n// ============================================================================\n// Type Guards and Assertion Functions\n// ============================================================================\n\n/**\n * Type predicate to check if a string is a known widget type name.\n * Use for runtime validation of widget types.\n *\n * @example\n * if (isWidgetTypeName(widget.type)) {\n * // TypeScript knows widget.type is WidgetTypeName\n * }\n */\nexport function isWidgetTypeName(type: string): type is WidgetTypeName {\n // Type assertion required in type guard: Object.values() returns string[], but we\n // need to check against WidgetTypeName values. The assertion is safe because we're\n // checking membership, and the return type predicate ensures correct narrowing.\n return Object.values(WIDGET_TYPE_NAMES).includes(type as WidgetTypeName);\n}\n\n/**\n * Type predicate to check if a widget has a specific type.\n * Enables type-safe widget narrowing without `as` assertions.\n *\n * @example\n * if (isWidgetType(widget, \"LayoutWidget\")) {\n * // TypeScript knows widget.type === \"LayoutWidget\"\n * // and widget.props is LayoutWidget props\n * }\n */\nexport function isWidgetType<T extends WidgetTypeName>(\n widget: WidgetSchema | null | undefined,\n typeName: T,\n): widget is WidgetSchema & { readonly type: T } {\n return widget != null && widget.type === typeName;\n}\n\n/**\n * Helper for exhaustive switch statements on widget types.\n * Use in the default case to ensure all widget types are handled.\n *\n * @example\n * switch (widget.type) {\n * case \"AlertWidget\": return handleAlert();\n * case \"TextWidget\": return handleText();\n * // ... all other widget types\n * default: return assertNever(widget.type, \"widget type\");\n * }\n */\nexport function assertNever(value: never, context?: string): never {\n const message = context\n ? `Unexpected ${context}: ${String(value)}`\n : `Unexpected value: ${String(value)}`;\n throw new Error(message);\n}\n\n/**\n * Assertion function that throws if value is undefined.\n * Narrows the type to exclude undefined.\n *\n * @example\n * const widget = screen[0];\n * assertDefined(widget, \"widget at index 0\");\n * // TypeScript knows widget is defined here\n */\nexport function assertDefined<T>(\n value: T | undefined | null,\n name?: string,\n): asserts value is T {\n if (value == null) {\n throw new Error(name ? `${name} is required` : \"Value is required\");\n }\n}\n","/**\n * Data Source Presets Registry\n *\n * Configurable presets that allow users to select options via sub-menus\n * and fine-tune parameters in a detail panel.\n */\n\nimport type {\n SelectFieldSchema,\n NumberFieldSchema,\n} from \"../registries/property-schema-types\";\nimport type { DataSource } from \"./types\";\n\n/** Widget types that can use data sources */\nexport type DataSourceCompatibleWidget =\n | \"CarouselWidget\"\n | \"ChartWidget\"\n | \"EmbedWidget\"\n | \"ImageWidget\"\n | \"ListWidget\"\n | \"NestedWidget\"\n | \"TableWidget\"\n | \"VideoWidget\";\n\n/** Field types supported in preset config panels */\nexport type PresetConfigField = SelectFieldSchema<string> | NumberFieldSchema;\n\n/** A preset data source configuration */\nexport interface DataSourcePreset {\n /** Unique identifier for the preset */\n id: string;\n /** Human-readable name for display */\n name: string;\n /** Description of what data this endpoint provides */\n description: string;\n /** The API endpoint path (can include {variable} placeholders) */\n endpoint: string;\n /** Transformer name to apply to the data */\n transform?: string;\n /** Optional path to extract data from response (e.g., \"data.items\") */\n resultPath?: string;\n /** Which widgets this preset is compatible with */\n compatibleWidgets: DataSourceCompatibleWidget[];\n /** Optional select field shown as a sub-menu. The field's key becomes a variable in the endpoint URL. */\n menuField?: SelectFieldSchema<string>;\n /** Optional config fields rendered in the detail panel below the popover. Each field's key becomes a variable. */\n configFields?: PresetConfigField[];\n}\n\n/**\n * Pre-configured data source presets\n */\nexport const DATA_SOURCE_PRESETS: DataSourcePreset[] = [\n {\n id: \"rep-most-shared\",\n name: \"Most Shared Visits\",\n description: \"Content with the most share-link click-throughs\",\n endpoint:\n \"/v2025-06/reps/{rep_id}/most_shared?shareable_type={shareable_type}&limit={limit}&period={period}&language_iso={language_iso}\",\n resultPath: \"resources\",\n compatibleWidgets: [\n \"CarouselWidget\",\n \"ListWidget\",\n \"NestedWidget\",\n \"TableWidget\",\n ],\n menuField: {\n key: \"shareable_type\",\n label: \"Content Type\",\n type: \"select\",\n options: [\n { label: \"Products\", value: \"products\" },\n { label: \"Media\", value: \"media\" },\n { label: \"Pages\", value: \"pages\" },\n { label: \"Libraries\", value: \"libraries\" },\n { label: \"Enrollment Packs\", value: \"enrollment_packs\" },\n ],\n defaultValue: \"products\",\n },\n configFields: [\n {\n key: \"limit\",\n label: \"Limit\",\n type: \"number\",\n defaultValue: 10,\n min: 1,\n max: 20,\n description: \"Maximum number of items to show\",\n },\n {\n key: \"period\",\n label: \"Time Range\",\n type: \"select\",\n options: [\n { label: \"7 days\", value: \"7d\" },\n { label: \"30 days\", value: \"30d\" },\n { label: \"90 days\", value: \"90d\" },\n { label: \"1 year\", value: \"1y\" },\n { label: \"All time\", value: \"all\" },\n ],\n defaultValue: \"all\",\n },\n ],\n },\n {\n id: \"rep-most-viewed\",\n name: \"Most Viewed\",\n description: \"Most viewed content\",\n endpoint:\n \"/v2025-06/reps/{rep_id}/most_viewed?shareable_type={shareable_type}&limit={limit}&period={period}&language_iso={language_iso}\",\n resultPath: \"resources\",\n compatibleWidgets: [\n \"CarouselWidget\",\n \"ListWidget\",\n \"NestedWidget\",\n \"TableWidget\",\n ],\n menuField: {\n key: \"shareable_type\",\n label: \"Content Type\",\n type: \"select\",\n options: [\n { label: \"Products\", value: \"products\" },\n { label: \"Media\", value: \"media\" },\n { label: \"Pages\", value: \"pages\" },\n { label: \"Libraries\", value: \"libraries\" },\n { label: \"Enrollment Packs\", value: \"enrollment_packs\" },\n ],\n defaultValue: \"products\",\n },\n configFields: [\n {\n key: \"limit\",\n label: \"Limit\",\n type: \"number\",\n defaultValue: 10,\n min: 1,\n max: 20,\n description: \"Maximum number of items to show\",\n },\n {\n key: \"period\",\n label: \"Time Range\",\n type: \"select\",\n options: [\n { label: \"7 days\", value: \"7d\" },\n { label: \"30 days\", value: \"30d\" },\n { label: \"90 days\", value: \"90d\" },\n { label: \"1 year\", value: \"1y\" },\n { label: \"All time\", value: \"all\" },\n ],\n defaultValue: \"all\",\n },\n ],\n },\n {\n id: \"customer-orders\",\n name: \"Orders\",\n description: \"Customer order history\",\n endpoint:\n \"/v202506/orders?customer_id={customer_id}&page[limit]={limit}&status={status}\",\n resultPath: \"orders\",\n transform: \"toOrderTableProps\",\n compatibleWidgets: [\"TableWidget\"],\n configFields: [\n {\n key: \"limit\",\n label: \"Limit\",\n type: \"number\",\n defaultValue: 10,\n min: 1,\n max: 50,\n description: \"Maximum number of orders to show\",\n },\n {\n key: \"status\",\n label: \"Status\",\n type: \"select\",\n options: [\n { label: \"All\", value: \"all\" },\n { label: \"Paid\", value: \"paid\" },\n { label: \"Unpaid\", value: \"unpaid\" },\n { label: \"Refunded\", value: \"refunded\" },\n ],\n defaultValue: \"all\",\n },\n ],\n },\n {\n id: \"customer-subscriptions\",\n name: \"Subscriptions\",\n description: \"Customer subscriptions\",\n // Subscriptions endpoint is unversioned (legacy API), orders uses v202506\n endpoint:\n \"/subscriptions?customer_id={customer_id}&per_page={limit}&status={status}\",\n resultPath: \"subscriptions\",\n transform: \"toSubscriptionTableProps\",\n compatibleWidgets: [\"TableWidget\"],\n configFields: [\n {\n key: \"limit\",\n label: \"Limit\",\n type: \"number\",\n defaultValue: 10,\n min: 1,\n max: 50,\n description: \"Maximum number of subscriptions to show\",\n },\n {\n key: \"status\",\n label: \"Status\",\n type: \"select\",\n options: [\n { label: \"All\", value: \"all\" },\n { label: \"Active\", value: \"active\" },\n { label: \"Paused\", value: \"paused\" },\n { label: \"Cancelled\", value: \"cancelled\" },\n ],\n defaultValue: \"all\",\n },\n ],\n },\n];\n\n/** Lookup map for O(1) preset resolution */\nconst PRESET_MAP = new Map<string, DataSourcePreset>(\n DATA_SOURCE_PRESETS.map((p) => [p.id, p]),\n);\n\n/**\n * Resolves a preset by ID, returning the current preset definition.\n * Returns undefined if the preset ID is not recognized.\n */\nexport function resolvePreset(presetId: string): DataSourcePreset | undefined {\n return PRESET_MAP.get(presetId);\n}\n\n/**\n * If the source is an API source with a presetId, returns a copy with\n * endpoint, resultPath, and transform resolved from the current preset.\n * Falls back to stored values if the preset is unknown.\n * Non-API sources are returned as-is.\n */\nexport function resolveSource<T extends DataSource>(source: T): T {\n if (source.type !== \"api\" || !source.presetId) return source;\n\n const preset = resolvePreset(source.presetId);\n if (!preset) {\n console.warn(\n `[DataSource] Unknown preset \"${source.presetId}\", falling back to stored values`,\n );\n return source;\n }\n\n return {\n ...source,\n endpoint: preset.endpoint,\n resultPath: preset.resultPath,\n transform: preset.transform ?? source.transform,\n } as T;\n}\n","import { useQueries } from \"@tanstack/react-query\";\nimport { useCallback, useMemo, useRef } from \"react\";\nimport type { WidgetSchema } from \"@fluid-app/portal-core/types\";\nimport type {\n DataSourceRegistry,\n WidgetDataResult,\n DataSourceContext,\n DataSource,\n} from \"@fluid-app/portal-core/data-sources/types\";\nimport { resolveSource } from \"@fluid-app/portal-core/data-sources/presets\";\nimport { useDataSourceApiOptional } from \"@fluid-app/portal-core/data-source-api-context\";\nimport { useDataSourceRegistryConfig } from \"./registry-context\";\n\ninterface UseWidgetDataOptions {\n /** Override the default registry from context */\n registry?: DataSourceRegistry | undefined;\n /** Base URL for API calls (e.g., \"https://api.fluid.app/api\") */\n baseUrl?: string | undefined;\n}\n\n/**\n * Generates a cache key for the raw data fetch (endpoint/items identity only).\n * Transforms and targetProps are NOT included — they are applied per-widget\n * after reading from the shared cache.\n */\nfunction getSourceKey(source: DataSource): string {\n if (source.type === \"api\") {\n const varsKey = source.variables\n ? `:${JSON.stringify(source.variables)}`\n : \"\";\n // Use presetId as identity when available — keeps cache key stable across preset endpoint changes\n const identity = source.presetId ?? source.endpoint;\n return `${identity}${varsKey}`;\n }\n if (source.type === \"custom\") {\n const itemKeys =\n source.selectedItems?.map((item) => {\n return `${item.shareableType}:${item.id}`;\n }) ?? [];\n return `custom:${itemKeys.join(\",\")}`;\n }\n if (source.type === \"static\") {\n return `static:${source.staticType}:${source.selectedId}`;\n }\n return \"unknown\";\n}\n\n/**\n * Resolves cached raw data into widget props by applying each widget's own\n * transforms and targetProps mapping.\n */\nfunction resolvePropsFromQueries<T>(\n queryResults: ReadonlyArray<{\n data?: unknown;\n isLoading: boolean;\n error: Error | null;\n }>,\n sources: DataSource[],\n registry: DataSourceRegistry,\n errorConfig?: { fallback?: unknown },\n): T | undefined {\n if (sources.length === 0) return undefined;\n if (queryResults.some((q) => q.isLoading && !q.data)) return undefined;\n\n const failedQuery = queryResults.find((q) => q.error);\n const hasError = !!failedQuery?.error;\n\n if (hasError && errorConfig?.fallback) {\n return errorConfig.fallback as T;\n }\n\n if (hasError) {\n return undefined;\n }\n\n const resolvedProps: Record<string, unknown> = {};\n\n for (let i = 0; i < queryResults.length; i++) {\n const query = queryResults[i];\n const source = sources[i];\n if (!query?.data || !source) continue;\n\n // Sentry fix: FLUID-ADMIN-1DH — source or targetProps can be undefined from malformed widget config\n if (!source.targetProps) continue;\n\n // Apply this widget's transform to the cached raw data\n let result: unknown = query.data;\n if (source.transform) {\n const transformer = registry.transformers[source.transform];\n if (transformer) {\n result = transformer(result, source);\n } else {\n console.warn(`Transform \"${source.transform}\" not found in registry`);\n }\n }\n\n // Map to this widget's targetProps\n if (\n result !== null &&\n typeof result === \"object\" &&\n !Array.isArray(result) &&\n source.targetProps.length > 1\n ) {\n const resultObj = result as Record<string, unknown>;\n for (const prop of source.targetProps) {\n if (prop in resultObj) {\n resolvedProps[prop] = resultObj[prop];\n }\n }\n } else {\n for (const prop of source.targetProps) {\n resolvedProps[prop] = result;\n }\n }\n }\n\n return resolvedProps as T;\n}\n\n/**\n * Hook that fetches and resolves data sources for a widget using React Query.\n *\n * Raw API data is cached and shared across widgets with the same data source.\n * Transforms and targetProps mapping are applied per-widget after cache reads,\n * so multiple widgets can share one fetch but resolve data independently.\n */\nexport function useWidgetData<T = Record<string, unknown>>(\n widget: WidgetSchema,\n options?: UseWidgetDataOptions,\n): WidgetDataResult<T> {\n const config = useDataSourceRegistryConfig();\n const registry = options?.registry ?? config.registry;\n const baseUrl = options?.baseUrl ?? config.baseUrl;\n const getApiHeaders = config.getApiHeaders;\n const variables = config.variables;\n // useDataSourceApiOptional returns null outside a DataSourceApiProvider.\n // This allows widgets with zero data sources to render in isolation\n // (Storybook, unit tests). Fetchers that require api will throw at call\n // time if it's missing — not at render time for every widget.\n const api = useDataSourceApiOptional() ?? undefined;\n\n // Resolve preset-backed sources to their current endpoint/resultPath/transform\n const sources = useMemo(\n () => (widget.dataSource?.sources ?? []).map(resolveSource),\n [widget.dataSource?.sources],\n );\n const errorConfig = widget.dataSource?.error;\n const widgetId = widget.id ?? \"unknown\";\n const widgetType = widget.type;\n\n const queryResultsRef = useRef<Array<{ refetch: () => void }>>([]);\n\n // Cache only raw fetched data — no transforms or source objects stored\n const results = useQueries({\n queries: sources.map((source: DataSource) => ({\n queryKey: [\n \"portal-widget-data\",\n getSourceKey(source),\n baseUrl,\n variables,\n ] as const,\n queryFn: async ({\n signal,\n }: {\n signal: AbortSignal;\n }): Promise<unknown> => {\n const context: DataSourceContext = {\n widgetId,\n widgetType,\n signal,\n baseUrl,\n getApiHeaders,\n variables,\n api,\n };\n\n const fetcher = registry.fetchers[source.type];\n if (!fetcher) {\n throw new Error(\n `No fetcher registered for source type: ${source.type}`,\n );\n }\n\n return fetcher(source, context);\n },\n enabled: sources.length > 0,\n retry: errorConfig?.retryCount ?? 0,\n retryDelay: errorConfig?.retryDelay ?? 1000,\n refetchInterval: source.refreshInterval || false,\n })),\n });\n\n // Update ref for refetch callback\n queryResultsRef.current = results;\n\n // Aggregate loading state\n const isLoading = results.some((q) => q.isLoading);\n\n // Get first error from any failed query\n const failedQuery = results.find((q) => q.error);\n const error =\n failedQuery?.error instanceof Error\n ? failedQuery.error\n : failedQuery?.error\n ? new Error(String(failedQuery.error))\n : null;\n\n // Stable fingerprint that changes only when query data or loading states change\n const queryFingerprint = results\n .map((r) => `${r.dataUpdatedAt}:${r.isLoading}`)\n .join(\",\");\n\n // Resolve data: apply per-widget transforms and map to targetProps\n const resultsRef = useRef(results);\n resultsRef.current = results;\n\n const data = useMemo(() => {\n const querySnapshots = resultsRef.current.map((q) => ({\n data: q.data,\n isLoading: q.isLoading,\n error: q.error instanceof Error ? q.error : null,\n }));\n return resolvePropsFromQueries<T>(\n querySnapshots,\n sources,\n registry,\n errorConfig,\n );\n }, [queryFingerprint, sources, registry, errorConfig]);\n\n // Stable refetch callback using ref\n const refetch = useCallback(() => {\n queryResultsRef.current.forEach((q) => q.refetch());\n }, []);\n\n return {\n data,\n isLoading,\n error,\n refetch,\n };\n}\n","import type React from \"react\";\n\nexport function ErrorState(): React.JSX.Element {\n return (\n <div className=\"flex min-h-[120px] flex-col items-center justify-center p-6 text-center\">\n <p className=\"text-lg font-semibold\">Something Went Wrong</p>\n <p className=\"text-muted-foreground text-sm\">\n Please contact a company admin for help\n </p>\n </div>\n );\n}\n","import type React from \"react\";\nimport { memo, useMemo, type ComponentType, type ReactNode } from \"react\";\nimport type { WidgetSchema } from \"@fluid-app/portal-core/types\";\nimport { useWidgetData } from \"./use-widget-data\";\nimport { ErrorState } from \"./ErrorState\";\n\nexport interface DataAwareWidgetProps {\n widget: WidgetSchema;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Component: ComponentType<any>;\n /** Additional props to pass through (e.g., edit mode callbacks) */\n additionalProps?: Record<string, unknown>;\n /** Custom loading component */\n loadingComponent?: ReactNode;\n /** Custom error component */\n errorComponent?: (error: Error) => ReactNode;\n /** Base URL for API calls (e.g., \"https://api.fluid.app/api\") */\n baseUrl?: string | undefined;\n}\n\n// Empty object constant to avoid creating new references\nconst EMPTY_OBJECT: Record<string, unknown> = {};\n\n/**\n * Wrapper component that resolves data sources before rendering the widget.\n * Merges resolved data with static props.\n */\nfunction DataAwareWidgetImpl({\n widget,\n Component,\n additionalProps,\n loadingComponent,\n errorComponent,\n baseUrl,\n}: DataAwareWidgetProps): React.JSX.Element | null {\n // Use stable empty object if no additionalProps provided\n const stableAdditionalProps = additionalProps ?? EMPTY_OBJECT;\n const { data, isLoading, error } = useWidgetData(widget, { baseUrl });\n\n // Merge static props with resolved data\n // Data takes precedence (allows overriding defaults)\n // Memoized to prevent unnecessary child re-renders\n // Note: Must be called before any early returns to satisfy Rules of Hooks\n const mergedProps = useMemo(\n () => ({\n ...widget.props,\n ...data,\n ...stableAdditionalProps,\n }),\n [widget.props, data, stableAdditionalProps],\n );\n\n // Show loading state\n if (isLoading && widget.dataSource?.loading?.showSkeleton !== false) {\n if (loadingComponent) {\n return <>{loadingComponent}</>;\n }\n // Default skeleton - can be customized\n return (\n <div\n className=\"bg-muted animate-pulse rounded-md\"\n style={{ minHeight: 100 }}\n >\n <span className=\"sr-only\">Loading...</span>\n </div>\n );\n }\n\n // Show error state (if no fallback was applied)\n if (error && !data) {\n if (errorComponent) {\n return <>{errorComponent(error)}</>;\n }\n // Default error display\n return <ErrorState />;\n }\n\n return <Component {...mergedProps} />;\n}\n\n/**\n * Memoized wrapper component that resolves data sources before rendering the widget.\n * Prevents re-renders when parent re-renders but props haven't changed.\n */\nexport const DataAwareWidget: React.NamedExoticComponent<DataAwareWidgetProps> =\n memo(DataAwareWidgetImpl);\n","import type { ComponentType } from \"react\";\nimport { useCallback } from \"react\";\nimport type React from \"react\";\nimport type {\n WidgetSchema,\n TypedWidgetSchema,\n WidgetPath,\n} from \"@fluid-app/portal-core/types\";\nimport { WIDGET_TYPE_NAMES } from \"@fluid-app/portal-core/types\";\nimport { DataAwareWidget } from \"@fluid-app/portal-react/data-sources/DataAwareWidget\";\nimport { RegistryProvider, useRegistry } from \"../contexts/RegistryContext\";\n\nexport interface ScreenRendererProps<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n T extends Record<string, ComponentType<any>>,\n> {\n /** Array of widget schemas to render */\n screen: TypedWidgetSchema<T>[] | WidgetSchema[];\n /** Widget registry mapping type names to components */\n registry?: T;\n /** Container widgets (like LayoutWidget) receive these additional props */\n containerWidgetTypes?: string[];\n /** Additional CSS classes for the wrapper div */\n className?: string;\n}\n\ninterface ScreenRendererContentProps {\n screen: WidgetSchema[];\n containerWidgetTypes: string[];\n className?: string | undefined;\n}\n\n/**\n * Internal component that uses the registry from context.\n * This allows us to avoid prop drilling the registry.\n */\nfunction ScreenRendererContent({\n screen,\n containerWidgetTypes,\n className,\n}: ScreenRendererContentProps) {\n const registry = useRegistry();\n\n // Check if a widget type is a container\n const isContainerWidget = useCallback(\n (widgetType: string) => containerWidgetTypes.includes(widgetType),\n [containerWidgetTypes],\n );\n\n // Render widgets recursively with path tracking\n const renderWidget = useCallback(\n (widget: WidgetSchema, index: number, currentPath: WidgetPath) => {\n const Component = registry[widget.type];\n if (!Component) {\n console.warn(\n `Widget type \"${String(widget.type)}\" not found in registry`,\n );\n return null;\n }\n\n const widgetPath = [...currentPath, index];\n\n // Build additional props for container widgets\n const additionalProps = isContainerWidget(widget.type)\n ? {\n widgetId: widget.id,\n widgetPath,\n }\n : {};\n\n const props = {\n ...widget.props,\n ...additionalProps,\n };\n\n // Wrap data-bound widgets with DataAwareWidget to resolve data sources\n if (widget.dataSource) {\n return (\n <div\n key={widget.id || index}\n className=\"h-full w-full overflow-x-hidden\"\n >\n <DataAwareWidget widget={widget} Component={Component} />\n </div>\n );\n }\n\n return (\n <div\n key={widget.id || index}\n className=\"h-full w-full overflow-x-hidden\"\n >\n <Component {...props} />\n </div>\n );\n },\n [registry, isContainerWidget],\n );\n\n return (\n <div className={className || \"h-full w-full\"}>\n {screen?.map((item, index) => {\n // Skip null items (empty grid cells)\n if (!item) return null;\n return renderWidget(item, index, []);\n })}\n </div>\n );\n}\n\n/**\n * ScreenRenderer - View-only component for rendering widget screens.\n *\n * This is a simplified version designed for the SDK that only handles\n * rendering widgets without edit mode or drag-and-drop functionality.\n *\n * Features:\n * - Static rendering of widgets\n * - Registry context: No prop drilling for widget registry\n * - Container widget support with path tracking\n *\n * Usage:\n * ```tsx\n * import { ScreenRenderer } from '@fluid-app/portal-widgets/core';\n * import { WIDGET_REGISTRY } from '@fluid-app/portal-widgets/widgets';\n *\n * <ScreenRenderer\n * screen={widgets}\n * registry={WIDGET_REGISTRY}\n * />\n * ```\n */\nexport function ScreenRenderer<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n T extends Record<string, ComponentType<any>>,\n>(props: ScreenRendererProps<T>): React.JSX.Element {\n const {\n screen,\n registry,\n containerWidgetTypes = [\n WIDGET_TYPE_NAMES.Layout,\n WIDGET_TYPE_NAMES.Container,\n ],\n className,\n } = props;\n\n // Conditionally pass registry prop to satisfy exactOptionalPropertyTypes\n // When registry is undefined, we omit it entirely and let RegistryProvider inherit from parent\n const registryProviderProps = registry !== undefined ? { registry } : {};\n\n return (\n <RegistryProvider {...registryProviderProps}>\n {/* Type assertion required: TypedWidgetSchema<T>[] is a subtype of WidgetSchema[]\n when T's components accept props compatible with WidgetSchema props.\n This enables type-safe widget rendering with custom registries while allowing\n the internal renderer to work with the base WidgetSchema type. */}\n <ScreenRendererContent\n screen={screen as WidgetSchema[]}\n containerWidgetTypes={containerWidgetTypes}\n className={className}\n />\n </RegistryProvider>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ScreenRenderer-xH01YkEQ.cjs","names":["useDataSourceRegistryConfig"],"sources":["../../core/src/data-source-api-context.ts","../../widgets/src/contexts/RegistryContext.tsx","../../widgets/src/contexts/ScreenRendererContext.tsx","../../core/src/types/widget-schema.ts","../../core/src/data-sources/presets.ts","../../react/src/data-sources/use-widget-data.ts","../../react/src/data-sources/ErrorState.tsx","../../react/src/data-sources/DataAwareWidget.tsx","../../widgets/src/core/ScreenRenderer.tsx"],"sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { DataSourceApi } from \"./data-source-api\";\n\nconst DataSourceApiContext = createContext<DataSourceApi | null>(null);\n\nexport const DataSourceApiProvider = DataSourceApiContext.Provider;\n\n/**\n * Access the DataSourceApi adapter.\n * Throws if no DataSourceApiProvider ancestor exists.\n */\nexport function useDataSourceApi(): DataSourceApi {\n const api = useContext(DataSourceApiContext);\n if (!api) {\n throw new Error(\n \"useDataSourceApi must be used within a DataSourceApiProvider\",\n );\n }\n return api;\n}\n\n/**\n * Access the DataSourceApi adapter without throwing.\n * Returns null when no DataSourceApiProvider ancestor exists.\n * Use in isolated rendering contexts (Storybook, unit tests) where the\n * full provider stack may not be wired.\n */\nexport function useDataSourceApiOptional(): DataSourceApi | null {\n return useContext(DataSourceApiContext);\n}\n","import React, {\n createContext,\n useContext,\n type ComponentType,\n type ReactNode,\n} from \"react\";\nimport type { WidgetSchema } from \"@fluid-app/portal-core/types\";\n\n/**\n * Base props interface for widget components.\n * All widgets receive at least these props from the ScreenRenderer.\n */\nexport interface WidgetBaseProps {\n readonly widget: WidgetSchema;\n readonly path?: readonly number[];\n}\n\n/**\n * Generic widget component type.\n * Widgets receive WidgetBaseProps and may have additional props.\n */\nexport type WidgetComponent<P extends WidgetBaseProps = WidgetBaseProps> =\n ComponentType<P>;\n\n/**\n * Registry mapping widget type names to their components.\n * The keys are widget type strings (e.g., \"TextWidget\", \"ButtonWidget\").\n * Using WidgetComponent for the value type provides better type safety than `any`.\n */\nexport type WidgetRegistry = Readonly<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Widget props vary by type\n Record<string, WidgetComponent<any>>\n>;\n\n/**\n * Context for providing the widget registry to all components in the tree.\n * This eliminates prop drilling and makes the registry accessible anywhere.\n *\n * Default to undefined - registry must be provided by a RegistryProvider.\n */\nexport const RegistryContext: React.Context<WidgetRegistry | undefined> =\n createContext<WidgetRegistry | undefined>(undefined);\n\nexport interface RegistryProviderProps {\n registry?: WidgetRegistry;\n children: ReactNode;\n}\n\n/**\n * Provider component that makes the widget registry available to all descendants.\n * A registry must be provided either via props or by nesting within another RegistryProvider.\n */\nexport function RegistryProvider({\n registry,\n children,\n}: RegistryProviderProps): React.JSX.Element {\n // If no registry provided, inherit from parent provider\n const parentRegistry = useContext(RegistryContext);\n const contextValue = registry ?? parentRegistry;\n\n if (!contextValue) {\n throw new Error(\n \"RegistryProvider requires a registry prop or must be nested within another RegistryProvider.\",\n );\n }\n\n return (\n <RegistryContext.Provider value={contextValue}>\n {children}\n </RegistryContext.Provider>\n );\n}\n\n/**\n * Hook to access the widget registry from anywhere in the component tree.\n * Must be used within a RegistryProvider that has a registry prop.\n */\nexport function useRegistry(): WidgetRegistry {\n const registry = useContext(RegistryContext);\n\n if (!registry) {\n throw new Error(\n \"useRegistry must be used within a RegistryProvider with a registry prop.\",\n );\n }\n\n return registry;\n}\n","import React, { createContext, useContext, type ComponentType } from \"react\";\nimport type { WidgetSchema } from \"@fluid-app/portal-core/types\";\nimport type { WidgetRegistry } from \"./RegistryContext\";\n\n/**\n * Props that any ScreenRenderer must accept.\n * This is the minimal interface used by container widgets (e.g. LayoutWidget)\n * to render their children.\n */\nexport interface ScreenRendererComponentProps {\n screen: WidgetSchema[];\n registry?: WidgetRegistry;\n className?: string;\n}\n\n/**\n * Context for providing an alternative ScreenRenderer component.\n *\n * This allows packages like portal-builder to inject their own ScreenRenderer\n * (with edit mode, drag-and-drop, etc.) so that container widgets in portal-widgets\n * use the richer renderer instead of the basic view-only one.\n *\n * Default is undefined — container widgets fall back to the local ScreenRenderer import.\n */\nexport const ScreenRendererContext: React.Context<\n ComponentType<ScreenRendererComponentProps> | undefined\n> = createContext<ComponentType<ScreenRendererComponentProps> | undefined>(\n undefined,\n);\n\n/**\n * Hook to get the ScreenRenderer component from context.\n * Returns undefined if no override has been provided.\n */\nexport function useScreenRenderer():\n | ComponentType<ScreenRendererComponentProps>\n | undefined {\n return useContext(ScreenRendererContext);\n}\n","import type { DataSourceConfig } from \"../data-sources/types\";\n\n/**\n * Generic component type — avoids React dependency in core.\n * Accepts both function components and class component constructors.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyComponent = ((props: any) => any) | (new (props: any) => any);\n\n/**\n * Widget type names as a const object.\n * This serves as the single source of truth for widget discriminants.\n * Use `as const` for literal type inference (safety-as-const-deep-readonly rule).\n */\nexport const WIDGET_TYPE_NAMES = {\n Alert: \"AlertWidget\",\n BulletList: \"BulletListWidget\",\n Calendar: \"CalendarWidget\",\n Card: \"CardWidget\",\n Carousel: \"CarouselWidget\",\n CatchUp: \"CatchUpWidget\",\n Chart: \"ChartWidget\",\n Container: \"ContainerWidget\",\n Embed: \"EmbedWidget\",\n Image: \"ImageWidget\",\n Layout: \"LayoutWidget\",\n Link: \"LinkWidget\",\n List: \"ListWidget\",\n MySite: \"MySiteWidget\",\n Nested: \"NestedWidget\",\n Points: \"PointsWidget\",\n QuickLinks: \"QuickLinksWidget\",\n QuickShare: \"QuickShareWidget\",\n RecentActivity: \"RecentActivityWidget\",\n Separator: \"SeparatorWidget\",\n Spacer: \"SpacerWidget\",\n Table: \"TableWidget\",\n Text: \"TextWidget\",\n ToDo: \"ToDoWidget\",\n Video: \"VideoWidget\",\n} as const;\n\n/**\n * Union of all known widget type names.\n * Derived from WIDGET_TYPE_NAMES to avoid duplication (deriving-typeof-for-object-keys rule).\n */\nexport type WidgetTypeName =\n (typeof WIDGET_TYPE_NAMES)[keyof typeof WIDGET_TYPE_NAMES];\n\n/**\n * Legacy alias for backwards compatibility.\n * Prefer using WidgetTypeName for new code when you need the union type.\n */\nexport type WidgetType = string;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type WidgetRegistry = Record<WidgetType, AnyComponent>;\n\n/**\n * Base widget schema with loose typing for runtime data.\n * Use TypedWidgetSchema<T> when you have a known registry for better type safety.\n */\nexport type WidgetSchema = {\n readonly type: WidgetType;\n readonly props: Readonly<Record<string, unknown>>;\n readonly id?: string; // Optional unique identifier for drag-and-drop\n /** Optional data source configuration for data-bound widgets */\n readonly dataSource?: DataSourceConfig | undefined;\n /** Column index for masonry layouts (0-indexed) */\n readonly columnIndex?: number;\n};\n\n/**\n * Type-safe widget schema based on registry.\n * Uses discriminated unions - the `type` field serves as discriminant.\n * When narrowed (e.g., `if (widget.type === \"AlertWidget\")`),\n * TypeScript automatically knows the correct props type.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type TypedWidgetSchema<T extends Record<string, AnyComponent>> = {\n [K in keyof T]: {\n readonly type: K;\n readonly props: Readonly<\n T[K] extends (props: infer P) => any\n ? P\n : T[K] extends new (props: infer P) => any\n ? P\n : never\n >;\n readonly id?: string;\n readonly dataSource?: DataSourceConfig | undefined;\n /** Column index for masonry layouts (0-indexed) */\n readonly columnIndex?: number;\n };\n}[keyof T];\n\n/**\n * Widget path in the tree - array of indices.\n * Readonly tuple to prevent accidental mutation.\n */\nexport type WidgetPath = readonly number[];\n\n// ============================================================================\n// Type Guards and Assertion Functions\n// ============================================================================\n\n/**\n * Type predicate to check if a string is a known widget type name.\n * Use for runtime validation of widget types.\n *\n * @example\n * if (isWidgetTypeName(widget.type)) {\n * // TypeScript knows widget.type is WidgetTypeName\n * }\n */\nexport function isWidgetTypeName(type: string): type is WidgetTypeName {\n // Type assertion required in type guard: Object.values() returns string[], but we\n // need to check against WidgetTypeName values. The assertion is safe because we're\n // checking membership, and the return type predicate ensures correct narrowing.\n return Object.values(WIDGET_TYPE_NAMES).includes(type as WidgetTypeName);\n}\n\n/**\n * Type predicate to check if a widget has a specific type.\n * Enables type-safe widget narrowing without `as` assertions.\n *\n * @example\n * if (isWidgetType(widget, \"LayoutWidget\")) {\n * // TypeScript knows widget.type === \"LayoutWidget\"\n * // and widget.props is LayoutWidget props\n * }\n */\nexport function isWidgetType<T extends WidgetTypeName>(\n widget: WidgetSchema | null | undefined,\n typeName: T,\n): widget is WidgetSchema & { readonly type: T } {\n return widget != null && widget.type === typeName;\n}\n\n/**\n * Helper for exhaustive switch statements on widget types.\n * Use in the default case to ensure all widget types are handled.\n *\n * @example\n * switch (widget.type) {\n * case \"AlertWidget\": return handleAlert();\n * case \"TextWidget\": return handleText();\n * // ... all other widget types\n * default: return assertNever(widget.type, \"widget type\");\n * }\n */\nexport function assertNever(value: never, context?: string): never {\n const message = context\n ? `Unexpected ${context}: ${String(value)}`\n : `Unexpected value: ${String(value)}`;\n throw new Error(message);\n}\n\n/**\n * Assertion function that throws if value is undefined.\n * Narrows the type to exclude undefined.\n *\n * @example\n * const widget = screen[0];\n * assertDefined(widget, \"widget at index 0\");\n * // TypeScript knows widget is defined here\n */\nexport function assertDefined<T>(\n value: T | undefined | null,\n name?: string,\n): asserts value is T {\n if (value == null) {\n throw new Error(name ? `${name} is required` : \"Value is required\");\n }\n}\n","/**\n * Data Source Presets Registry\n *\n * Configurable presets that allow users to select options via sub-menus\n * and fine-tune parameters in a detail panel.\n */\n\nimport type {\n SelectFieldSchema,\n NumberFieldSchema,\n} from \"../registries/property-schema-types\";\nimport type { DataSource } from \"./types\";\n\n/** Widget types that can use data sources */\nexport type DataSourceCompatibleWidget =\n | \"CarouselWidget\"\n | \"ChartWidget\"\n | \"EmbedWidget\"\n | \"ImageWidget\"\n | \"ListWidget\"\n | \"NestedWidget\"\n | \"TableWidget\"\n | \"VideoWidget\";\n\n/** Field types supported in preset config panels */\nexport type PresetConfigField = SelectFieldSchema<string> | NumberFieldSchema;\n\n/** A preset data source configuration */\nexport interface DataSourcePreset {\n /** Unique identifier for the preset */\n id: string;\n /** Human-readable name for display */\n name: string;\n /** Description of what data this endpoint provides */\n description: string;\n /** The API endpoint path (can include {variable} placeholders) */\n endpoint: string;\n /** Transformer name to apply to the data */\n transform?: string;\n /** Optional path to extract data from response (e.g., \"data.items\") */\n resultPath?: string;\n /** Which widgets this preset is compatible with */\n compatibleWidgets: DataSourceCompatibleWidget[];\n /** Optional select field shown as a sub-menu. The field's key becomes a variable in the endpoint URL. */\n menuField?: SelectFieldSchema<string>;\n /** Optional config fields rendered in the detail panel below the popover. Each field's key becomes a variable. */\n configFields?: PresetConfigField[];\n}\n\n/**\n * Pre-configured data source presets\n */\nexport const DATA_SOURCE_PRESETS: DataSourcePreset[] = [\n {\n id: \"rep-most-shared\",\n name: \"Most Shared Visits\",\n description: \"Content with the most share-link click-throughs\",\n endpoint:\n \"/v2025-06/reps/{rep_id}/most_shared?shareable_type={shareable_type}&limit={limit}&period={period}&language_iso={language_iso}\",\n resultPath: \"resources\",\n compatibleWidgets: [\n \"CarouselWidget\",\n \"ListWidget\",\n \"NestedWidget\",\n \"TableWidget\",\n ],\n menuField: {\n key: \"shareable_type\",\n label: \"Content Type\",\n type: \"select\",\n options: [\n { label: \"Products\", value: \"products\" },\n { label: \"Media\", value: \"media\" },\n { label: \"Pages\", value: \"pages\" },\n { label: \"Libraries\", value: \"libraries\" },\n { label: \"Enrollment Packs\", value: \"enrollment_packs\" },\n ],\n defaultValue: \"products\",\n },\n configFields: [\n {\n key: \"limit\",\n label: \"Limit\",\n type: \"number\",\n defaultValue: 10,\n min: 1,\n max: 20,\n description: \"Maximum number of items to show\",\n },\n {\n key: \"period\",\n label: \"Time Range\",\n type: \"select\",\n options: [\n { label: \"7 days\", value: \"7d\" },\n { label: \"30 days\", value: \"30d\" },\n { label: \"90 days\", value: \"90d\" },\n { label: \"1 year\", value: \"1y\" },\n { label: \"All time\", value: \"all\" },\n ],\n defaultValue: \"all\",\n },\n ],\n },\n {\n id: \"rep-most-viewed\",\n name: \"Most Viewed\",\n description: \"Most viewed content\",\n endpoint:\n \"/v2025-06/reps/{rep_id}/most_viewed?shareable_type={shareable_type}&limit={limit}&period={period}&language_iso={language_iso}\",\n resultPath: \"resources\",\n compatibleWidgets: [\n \"CarouselWidget\",\n \"ListWidget\",\n \"NestedWidget\",\n \"TableWidget\",\n ],\n menuField: {\n key: \"shareable_type\",\n label: \"Content Type\",\n type: \"select\",\n options: [\n { label: \"Products\", value: \"products\" },\n { label: \"Media\", value: \"media\" },\n { label: \"Pages\", value: \"pages\" },\n { label: \"Libraries\", value: \"libraries\" },\n { label: \"Enrollment Packs\", value: \"enrollment_packs\" },\n ],\n defaultValue: \"products\",\n },\n configFields: [\n {\n key: \"limit\",\n label: \"Limit\",\n type: \"number\",\n defaultValue: 10,\n min: 1,\n max: 20,\n description: \"Maximum number of items to show\",\n },\n {\n key: \"period\",\n label: \"Time Range\",\n type: \"select\",\n options: [\n { label: \"7 days\", value: \"7d\" },\n { label: \"30 days\", value: \"30d\" },\n { label: \"90 days\", value: \"90d\" },\n { label: \"1 year\", value: \"1y\" },\n { label: \"All time\", value: \"all\" },\n ],\n defaultValue: \"all\",\n },\n ],\n },\n {\n id: \"customer-orders\",\n name: \"Orders\",\n description: \"Customer order history\",\n endpoint:\n \"/v202506/orders?customer_id={customer_id}&page[limit]={limit}&status={status}\",\n resultPath: \"orders\",\n transform: \"toOrderTableProps\",\n compatibleWidgets: [\"TableWidget\"],\n configFields: [\n {\n key: \"limit\",\n label: \"Limit\",\n type: \"number\",\n defaultValue: 10,\n min: 1,\n max: 50,\n description: \"Maximum number of orders to show\",\n },\n {\n key: \"status\",\n label: \"Status\",\n type: \"select\",\n options: [\n { label: \"All\", value: \"all\" },\n { label: \"Paid\", value: \"paid\" },\n { label: \"Unpaid\", value: \"unpaid\" },\n { label: \"Refunded\", value: \"refunded\" },\n ],\n defaultValue: \"all\",\n },\n ],\n },\n {\n id: \"customer-subscriptions\",\n name: \"Subscriptions\",\n description: \"Customer subscriptions\",\n // Subscriptions endpoint is unversioned (legacy API), orders uses v202506\n endpoint:\n \"/subscriptions?customer_id={customer_id}&per_page={limit}&status={status}\",\n resultPath: \"subscriptions\",\n transform: \"toSubscriptionTableProps\",\n compatibleWidgets: [\"TableWidget\"],\n configFields: [\n {\n key: \"limit\",\n label: \"Limit\",\n type: \"number\",\n defaultValue: 10,\n min: 1,\n max: 50,\n description: \"Maximum number of subscriptions to show\",\n },\n {\n key: \"status\",\n label: \"Status\",\n type: \"select\",\n options: [\n { label: \"All\", value: \"all\" },\n { label: \"Active\", value: \"active\" },\n { label: \"Paused\", value: \"paused\" },\n { label: \"Cancelled\", value: \"cancelled\" },\n ],\n defaultValue: \"all\",\n },\n ],\n },\n];\n\n/** Lookup map for O(1) preset resolution */\nconst PRESET_MAP = new Map<string, DataSourcePreset>(\n DATA_SOURCE_PRESETS.map((p) => [p.id, p]),\n);\n\n/**\n * Resolves a preset by ID, returning the current preset definition.\n * Returns undefined if the preset ID is not recognized.\n */\nexport function resolvePreset(presetId: string): DataSourcePreset | undefined {\n return PRESET_MAP.get(presetId);\n}\n\n/**\n * If the source is an API source with a presetId, returns a copy with\n * endpoint, resultPath, and transform resolved from the current preset.\n * Falls back to stored values if the preset is unknown.\n * Non-API sources are returned as-is.\n */\nexport function resolveSource<T extends DataSource>(source: T): T {\n if (source.type !== \"api\" || !source.presetId) return source;\n\n const preset = resolvePreset(source.presetId);\n if (!preset) {\n console.warn(\n `[DataSource] Unknown preset \"${source.presetId}\", falling back to stored values`,\n );\n return source;\n }\n\n return {\n ...source,\n endpoint: preset.endpoint,\n resultPath: preset.resultPath,\n transform: preset.transform ?? source.transform,\n } as T;\n}\n","import { useQueries } from \"@tanstack/react-query\";\nimport { useCallback, useMemo, useRef } from \"react\";\nimport type { WidgetSchema } from \"@fluid-app/portal-core/types\";\nimport type {\n DataSourceRegistry,\n WidgetDataResult,\n DataSourceContext,\n DataSource,\n} from \"@fluid-app/portal-core/data-sources/types\";\nimport { resolveSource } from \"@fluid-app/portal-core/data-sources/presets\";\nimport { useDataSourceApiOptional } from \"@fluid-app/portal-core/data-source-api-context\";\nimport { useDataSourceRegistryConfig } from \"./registry-context\";\n\ninterface UseWidgetDataOptions {\n /** Override the default registry from context */\n registry?: DataSourceRegistry | undefined;\n /** Base URL for API calls (e.g., \"https://api.fluid.app/api\") */\n baseUrl?: string | undefined;\n}\n\n/**\n * Generates a cache key for the raw data fetch (endpoint/items identity only).\n * Transforms and targetProps are NOT included — they are applied per-widget\n * after reading from the shared cache.\n */\nfunction getSourceKey(source: DataSource): string {\n if (source.type === \"api\") {\n const varsKey = source.variables\n ? `:${JSON.stringify(source.variables)}`\n : \"\";\n // Use presetId as identity when available — keeps cache key stable across preset endpoint changes\n const identity = source.presetId ?? source.endpoint;\n return `${identity}${varsKey}`;\n }\n if (source.type === \"custom\") {\n const itemKeys =\n source.selectedItems?.map((item) => {\n return `${item.shareableType}:${item.id}`;\n }) ?? [];\n return `custom:${itemKeys.join(\",\")}`;\n }\n if (source.type === \"static\") {\n return `static:${source.staticType}:${source.selectedId}`;\n }\n return \"unknown\";\n}\n\n/**\n * Resolves cached raw data into widget props by applying each widget's own\n * transforms and targetProps mapping.\n */\nfunction resolvePropsFromQueries<T>(\n queryResults: ReadonlyArray<{\n data?: unknown;\n isLoading: boolean;\n error: Error | null;\n }>,\n sources: DataSource[],\n registry: DataSourceRegistry,\n errorConfig?: { fallback?: unknown },\n): T | undefined {\n if (sources.length === 0) return undefined;\n if (queryResults.some((q) => q.isLoading && !q.data)) return undefined;\n\n const failedQuery = queryResults.find((q) => q.error);\n const hasError = !!failedQuery?.error;\n\n if (hasError && errorConfig?.fallback) {\n return errorConfig.fallback as T;\n }\n\n if (hasError) {\n return undefined;\n }\n\n const resolvedProps: Record<string, unknown> = {};\n\n for (let i = 0; i < queryResults.length; i++) {\n const query = queryResults[i];\n const source = sources[i];\n if (!query?.data || !source) continue;\n\n // Sentry fix: FLUID-ADMIN-1DH — source or targetProps can be undefined from malformed widget config\n if (!source.targetProps) continue;\n\n // Apply this widget's transform to the cached raw data\n let result: unknown = query.data;\n if (source.transform) {\n const transformer = registry.transformers[source.transform];\n if (transformer) {\n result = transformer(result, source);\n } else {\n console.warn(`Transform \"${source.transform}\" not found in registry`);\n }\n }\n\n // Map to this widget's targetProps\n if (\n result !== null &&\n typeof result === \"object\" &&\n !Array.isArray(result) &&\n source.targetProps.length > 1\n ) {\n const resultObj = result as Record<string, unknown>;\n for (const prop of source.targetProps) {\n if (prop in resultObj) {\n resolvedProps[prop] = resultObj[prop];\n }\n }\n } else {\n for (const prop of source.targetProps) {\n resolvedProps[prop] = result;\n }\n }\n }\n\n return resolvedProps as T;\n}\n\n/**\n * Hook that fetches and resolves data sources for a widget using React Query.\n *\n * Raw API data is cached and shared across widgets with the same data source.\n * Transforms and targetProps mapping are applied per-widget after cache reads,\n * so multiple widgets can share one fetch but resolve data independently.\n */\nexport function useWidgetData<T = Record<string, unknown>>(\n widget: WidgetSchema,\n options?: UseWidgetDataOptions,\n): WidgetDataResult<T> {\n const config = useDataSourceRegistryConfig();\n const registry = options?.registry ?? config.registry;\n const baseUrl = options?.baseUrl ?? config.baseUrl;\n const getApiHeaders = config.getApiHeaders;\n const variables = config.variables;\n // useDataSourceApiOptional returns null outside a DataSourceApiProvider.\n // This allows widgets with zero data sources to render in isolation\n // (Storybook, unit tests). Fetchers that require api will throw at call\n // time if it's missing — not at render time for every widget.\n const api = useDataSourceApiOptional() ?? undefined;\n\n // Resolve preset-backed sources to their current endpoint/resultPath/transform\n const sources = useMemo(\n () => (widget.dataSource?.sources ?? []).map(resolveSource),\n [widget.dataSource?.sources],\n );\n const errorConfig = widget.dataSource?.error;\n const widgetId = widget.id ?? \"unknown\";\n const widgetType = widget.type;\n\n const queryResultsRef = useRef<Array<{ refetch: () => void }>>([]);\n\n // Cache only raw fetched data — no transforms or source objects stored\n const results = useQueries({\n queries: sources.map((source: DataSource) => ({\n queryKey: [\n \"portal-widget-data\",\n getSourceKey(source),\n baseUrl,\n variables,\n ] as const,\n queryFn: async ({\n signal,\n }: {\n signal: AbortSignal;\n }): Promise<unknown> => {\n const context: DataSourceContext = {\n widgetId,\n widgetType,\n signal,\n baseUrl,\n getApiHeaders,\n variables,\n api,\n };\n\n const fetcher = registry.fetchers[source.type];\n if (!fetcher) {\n throw new Error(\n `No fetcher registered for source type: ${source.type}`,\n );\n }\n\n return fetcher(source, context);\n },\n enabled: sources.length > 0,\n retry: errorConfig?.retryCount ?? 0,\n retryDelay: errorConfig?.retryDelay ?? 1000,\n refetchInterval: source.refreshInterval || false,\n })),\n });\n\n // Update ref for refetch callback\n queryResultsRef.current = results;\n\n // Aggregate loading state\n const isLoading = results.some((q) => q.isLoading);\n\n // Get first error from any failed query\n const failedQuery = results.find((q) => q.error);\n const error =\n failedQuery?.error instanceof Error\n ? failedQuery.error\n : failedQuery?.error\n ? new Error(String(failedQuery.error))\n : null;\n\n // Stable fingerprint that changes only when query data or loading states change\n const queryFingerprint = results\n .map((r) => `${r.dataUpdatedAt}:${r.isLoading}`)\n .join(\",\");\n\n // Resolve data: apply per-widget transforms and map to targetProps\n const resultsRef = useRef(results);\n resultsRef.current = results;\n\n const data = useMemo(() => {\n const querySnapshots = resultsRef.current.map((q) => ({\n data: q.data,\n isLoading: q.isLoading,\n error: q.error instanceof Error ? q.error : null,\n }));\n return resolvePropsFromQueries<T>(\n querySnapshots,\n sources,\n registry,\n errorConfig,\n );\n }, [queryFingerprint, sources, registry, errorConfig]);\n\n // Stable refetch callback using ref\n const refetch = useCallback(() => {\n queryResultsRef.current.forEach((q) => q.refetch());\n }, []);\n\n return {\n data,\n isLoading,\n error,\n refetch,\n };\n}\n","import type React from \"react\";\n\nexport function ErrorState(): React.JSX.Element {\n return (\n <div className=\"flex min-h-[120px] flex-col items-center justify-center p-6 text-center\">\n <p className=\"text-lg font-semibold\">Something Went Wrong</p>\n <p className=\"text-muted-foreground text-sm\">\n Please contact a company admin for help\n </p>\n </div>\n );\n}\n","import type React from \"react\";\nimport { memo, useMemo, type ComponentType, type ReactNode } from \"react\";\nimport type { WidgetSchema } from \"@fluid-app/portal-core/types\";\nimport { useWidgetData } from \"./use-widget-data\";\nimport { ErrorState } from \"./ErrorState\";\n\nexport interface DataAwareWidgetProps {\n widget: WidgetSchema;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Component: ComponentType<any>;\n /** Additional props to pass through (e.g., edit mode callbacks) */\n additionalProps?: Record<string, unknown>;\n /** Custom loading component */\n loadingComponent?: ReactNode;\n /** Custom error component */\n errorComponent?: (error: Error) => ReactNode;\n /** Base URL for API calls (e.g., \"https://api.fluid.app/api\") */\n baseUrl?: string | undefined;\n}\n\n// Empty object constant to avoid creating new references\nconst EMPTY_OBJECT: Record<string, unknown> = {};\n\n/**\n * Wrapper component that resolves data sources before rendering the widget.\n * Merges resolved data with static props.\n */\nfunction DataAwareWidgetImpl({\n widget,\n Component,\n additionalProps,\n loadingComponent,\n errorComponent,\n baseUrl,\n}: DataAwareWidgetProps): React.JSX.Element | null {\n // Use stable empty object if no additionalProps provided\n const stableAdditionalProps = additionalProps ?? EMPTY_OBJECT;\n const { data, isLoading, error } = useWidgetData(widget, { baseUrl });\n\n // Merge static props with resolved data\n // Data takes precedence (allows overriding defaults)\n // Memoized to prevent unnecessary child re-renders\n // Note: Must be called before any early returns to satisfy Rules of Hooks\n const mergedProps = useMemo(\n () => ({\n ...widget.props,\n ...data,\n ...stableAdditionalProps,\n }),\n [widget.props, data, stableAdditionalProps],\n );\n\n // Show loading state\n if (isLoading && widget.dataSource?.loading?.showSkeleton !== false) {\n if (loadingComponent) {\n return <>{loadingComponent}</>;\n }\n // Default skeleton - can be customized\n return (\n <div\n className=\"bg-muted animate-pulse rounded-md\"\n style={{ minHeight: 100 }}\n >\n <span className=\"sr-only\">Loading...</span>\n </div>\n );\n }\n\n // Show error state (if no fallback was applied)\n if (error && !data) {\n if (errorComponent) {\n return <>{errorComponent(error)}</>;\n }\n // Default error display\n return <ErrorState />;\n }\n\n return <Component {...mergedProps} />;\n}\n\n/**\n * Memoized wrapper component that resolves data sources before rendering the widget.\n * Prevents re-renders when parent re-renders but props haven't changed.\n */\nexport const DataAwareWidget: React.NamedExoticComponent<DataAwareWidgetProps> =\n memo(DataAwareWidgetImpl);\n","import type { ComponentType } from \"react\";\nimport { useCallback } from \"react\";\nimport type React from \"react\";\nimport type {\n WidgetSchema,\n TypedWidgetSchema,\n WidgetPath,\n} from \"@fluid-app/portal-core/types\";\nimport { WIDGET_TYPE_NAMES } from \"@fluid-app/portal-core/types\";\nimport { DataAwareWidget } from \"@fluid-app/portal-react/data-sources/DataAwareWidget\";\nimport { RegistryProvider, useRegistry } from \"../contexts/RegistryContext\";\n\nexport interface ScreenRendererProps<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n T extends Record<string, ComponentType<any>>,\n> {\n /** Array of widget schemas to render */\n screen: TypedWidgetSchema<T>[] | WidgetSchema[];\n /** Widget registry mapping type names to components */\n registry?: T;\n /** Container widgets (like LayoutWidget) receive these additional props */\n containerWidgetTypes?: string[];\n /** Additional CSS classes for the wrapper div */\n className?: string;\n}\n\ninterface ScreenRendererContentProps {\n screen: WidgetSchema[];\n containerWidgetTypes: string[];\n className?: string | undefined;\n}\n\n/**\n * Internal component that uses the registry from context.\n * This allows us to avoid prop drilling the registry.\n */\nfunction ScreenRendererContent({\n screen,\n containerWidgetTypes,\n className,\n}: ScreenRendererContentProps) {\n const registry = useRegistry();\n\n // Check if a widget type is a container\n const isContainerWidget = useCallback(\n (widgetType: string) => containerWidgetTypes.includes(widgetType),\n [containerWidgetTypes],\n );\n\n // Render widgets recursively with path tracking\n const renderWidget = useCallback(\n (widget: WidgetSchema, index: number, currentPath: WidgetPath) => {\n const Component = registry[widget.type];\n if (!Component) {\n console.warn(\n `Widget type \"${String(widget.type)}\" not found in registry`,\n );\n return null;\n }\n\n const widgetPath = [...currentPath, index];\n\n // Build additional props for container widgets\n const additionalProps = isContainerWidget(widget.type)\n ? {\n widgetId: widget.id,\n widgetPath,\n }\n : {};\n\n const props = {\n ...widget.props,\n ...additionalProps,\n };\n\n // Wrap data-bound widgets with DataAwareWidget to resolve data sources\n if (widget.dataSource) {\n return (\n <div\n key={widget.id || index}\n className=\"h-full w-full overflow-x-hidden\"\n >\n <DataAwareWidget widget={widget} Component={Component} />\n </div>\n );\n }\n\n return (\n <div\n key={widget.id || index}\n className=\"h-full w-full overflow-x-hidden\"\n >\n <Component {...props} />\n </div>\n );\n },\n [registry, isContainerWidget],\n );\n\n return (\n <div className={className || \"h-full w-full\"}>\n {screen?.map((item, index) => {\n // Skip null items (empty grid cells)\n if (!item) return null;\n return renderWidget(item, index, []);\n })}\n </div>\n );\n}\n\n/**\n * ScreenRenderer - View-only component for rendering widget screens.\n *\n * This is a simplified version designed for the SDK that only handles\n * rendering widgets without edit mode or drag-and-drop functionality.\n *\n * Features:\n * - Static rendering of widgets\n * - Registry context: No prop drilling for widget registry\n * - Container widget support with path tracking\n *\n * Usage:\n * ```tsx\n * import { ScreenRenderer } from '@fluid-app/portal-widgets/core';\n * import { WIDGET_REGISTRY } from '@fluid-app/portal-widgets/widgets';\n *\n * <ScreenRenderer\n * screen={widgets}\n * registry={WIDGET_REGISTRY}\n * />\n * ```\n */\nexport function ScreenRenderer<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n T extends Record<string, ComponentType<any>>,\n>(props: ScreenRendererProps<T>): React.JSX.Element {\n const {\n screen,\n registry,\n containerWidgetTypes = [\n WIDGET_TYPE_NAMES.Layout,\n WIDGET_TYPE_NAMES.Container,\n ],\n className,\n } = props;\n\n // Conditionally pass registry prop to satisfy exactOptionalPropertyTypes\n // When registry is undefined, we omit it entirely and let RegistryProvider inherit from parent\n const registryProviderProps = registry !== undefined ? { registry } : {};\n\n return (\n <RegistryProvider {...registryProviderProps}>\n {/* Type assertion required: TypedWidgetSchema<T>[] is a subtype of WidgetSchema[]\n when T's components accept props compatible with WidgetSchema props.\n This enables type-safe widget rendering with custom registries while allowing\n the internal renderer to work with the base WidgetSchema type. */}\n <ScreenRendererContent\n screen={screen as WidgetSchema[]}\n containerWidgetTypes={containerWidgetTypes}\n className={className}\n />\n </RegistryProvider>\n );\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-9hOWP6kD.cjs");
2
- const require_FluidProvider = require("./FluidProvider-DcpUKHrn.cjs");
2
+ const require_FluidProvider = require("./FluidProvider-DRXysbXj.cjs");
3
3
  const require_src = require("./src-uhf6Szlw.cjs");
4
4
  const require_ScreenHeaderContext = require("./ScreenHeaderContext-oIu5Bvhs.cjs");
5
5
  const require_use_store = require("./use-store-D2S1FywW.cjs");
@@ -355,11 +355,13 @@ function PurchaseOptions({ showBuyOnce, showSubscribe, isSubscribe, onSubscribeC
355
355
  onValueChange: (value) => onSubscribeChange(value === "subscribe"),
356
356
  className: "gap-0 space-y-0",
357
357
  children: [showSubscribe && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
358
+ onClick: () => onSubscribeChange(true),
358
359
  className: `cursor-pointer rounded-t-lg p-4 text-left transition-all duration-200 ${showBuyOnce ? "border border-b-0" : "rounded-b-lg"} ${userSelectedSubscribe ? "bg-muted" : "bg-background"}`,
359
360
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
360
361
  className: "flex items-start space-x-3",
361
362
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.RadioGroupItem, {
362
363
  value: "subscribe",
364
+ onClick: (e) => e.stopPropagation(),
363
365
  className: `flex items-center justify-center [&_svg]:h-1.5 [&_svg]:w-1.5 [&_svg]:fill-white ${isSubscribe ? "border-contrast bg-contrast text-foreground" : "border-border bg-background text-muted-foreground"}`
364
366
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
365
367
  className: "flex-1",
@@ -388,11 +390,13 @@ function PurchaseOptions({ showBuyOnce, showSubscribe, isSubscribe, onSubscribeC
388
390
  })]
389
391
  })
390
392
  }), showBuyOnce && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
393
+ onClick: () => onSubscribeChange(false),
391
394
  className: `cursor-pointer rounded-b-lg border p-4 text-left transition-all duration-200 ${showSubscribe ? "border-t-0" : "rounded-t-lg"} ${!userSelectedSubscribe ? "bg-muted" : "bg-background"}`,
392
395
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
393
396
  className: "flex items-center space-x-3",
394
397
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.RadioGroupItem, {
395
398
  value: "once",
399
+ onClick: (e) => e.stopPropagation(),
396
400
  className: `flex items-center justify-center [&_svg]:h-1.5 [&_svg]:w-1.5 [&_svg]:fill-white ${!isSubscribe ? "border-contrast bg-contrast text-foreground" : "border-border bg-background text-muted-foreground"}`
397
401
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
398
402
  className: "text-foreground mb-1 text-sm leading-tight font-medium",
@@ -1149,4 +1153,4 @@ Object.defineProperty(exports, "shopScreenPropertySchema", {
1149
1153
  }
1150
1154
  });
1151
1155
 
1152
- //# sourceMappingURL=ShopScreen-CiGozvW4.cjs.map
1156
+ //# sourceMappingURL=ShopScreen-B6Bo1VOu.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ShopScreen-B6Bo1VOu.cjs","names":["defaultRenderImage","getProductImageUrl","determineProductPrice","CirclePlay","Card","ChevronLeft","ChevronRight","Button","RadioGroup","RadioGroupItem","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","Skeleton","usePortalProductCatalog","SearchSort","DropdownMenu","DropdownMenuTrigger","Button","ArrowUpDown","DropdownMenuContent","DropdownMenuLabel","DropdownMenuSeparator","DropdownMenuRadioGroup","DropdownMenuRadioItem","usePortalProductDetail","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","ShoppingCart","React","Button","ShoppingCart","useFluidContext","useStore","useAppNavigation","Breadcrumb","BreadcrumbList","BreadcrumbItem","BreadcrumbLink","BreadcrumbPage","PortalProductsApiProvider","usePortalProductDetail","BreadcrumbSeparator"],"sources":["../../../shop/ui/src/utils/media-helpers.ts","../../../shop/ui/src/components/product-card.tsx","../../../shop/ui/src/components/image-gallery.tsx","../../../shop/ui/src/components/quantity-selector.tsx","../../../shop/ui/src/components/purchase-options.tsx","../../../shop/ui/src/components/shop-app.tsx","../../../cart/ui/src/components/cart-script.tsx","../../../cart/ui/src/components/cart-widget.tsx","../../../cart/ui/src/components/cart-button.tsx","../../../cart/ui/src/components/shop-container.tsx","../src/screens/ShopScreen.tsx"],"sourcesContent":["const VIDEO_EXTENSIONS = [\n \".mp4\",\n \".webm\",\n \".mov\",\n \".avi\",\n \".m4v\",\n \".mkv\",\n \".ogv\",\n \".ogg\",\n \".wmv\",\n \".flv\",\n \".3gp\",\n];\n\nconst IMAGE_EXTENSIONS = [\n \".jpg\",\n \".jpeg\",\n \".png\",\n \".gif\",\n \".webp\",\n \".svg\",\n \".bmp\",\n \".ico\",\n \".tiff\",\n \".tif\",\n];\n\nexport function isVideoUrl(url: string | undefined | null): boolean {\n if (!url) return false;\n const lowerUrl = url.toLowerCase();\n return VIDEO_EXTENSIONS.some((ext) => lowerUrl.includes(ext));\n}\n\nexport function isImageUrl(url: string | undefined | null): boolean {\n if (!url) return false;\n const lowerUrl = url.toLowerCase();\n return IMAGE_EXTENSIONS.some((ext) => lowerUrl.includes(ext));\n}\n\nexport function getMediaTypeFromUrl(\n url: string | undefined | null,\n): \"video\" | \"image\" | \"unknown\" {\n if (isVideoUrl(url)) return \"video\";\n if (isImageUrl(url)) return \"image\";\n return \"unknown\";\n}\n\nexport function getVideoThumbnailUrl(videoUrl: string): string {\n if (videoUrl.includes(\"ik.imagekit.io\")) {\n return `${videoUrl}/ik-thumbnail.jpg`;\n }\n return videoUrl;\n}\n\nexport function ensureImageIsFeatured<\n T extends { image_url: string; position?: number },\n>(items: T[]): T[] {\n if (items.length === 0) return items;\n\n const firstItem = items[0];\n if (!firstItem || !isVideoUrl(firstItem.image_url)) {\n return items;\n }\n\n const firstImageIndex = items.findIndex(\n (item) => !isVideoUrl(item.image_url),\n );\n\n if (firstImageIndex === -1) {\n return items;\n }\n\n const reordered = [...items];\n const [imageToMove] = reordered.splice(firstImageIndex, 1);\n if (imageToMove) {\n reordered.unshift(imageToMove);\n }\n\n return reordered;\n}\n","import type React from \"react\";\nimport { useState, type ReactNode } from \"react\";\nimport type { products, portalProducts } from \"@fluid-app/products-core\";\nimport {\n determineProductPrice,\n getProductImageUrl,\n} from \"@fluid-app/products-core\";\nimport { Card } from \"@fluid-app/ui-primitives\";\nimport { CirclePlay } from \"lucide-react\";\nimport { getVideoThumbnailUrl, isVideoUrl } from \"../utils/media-helpers\";\n\ntype LegacyProduct = (products.Product | products.ShopProduct) & {\n kind?: string;\n video_url?: string;\n};\n\nexport interface RenderImageProps {\n src: string;\n alt: string;\n fill?: boolean;\n className?: string;\n onError?: (e: React.SyntheticEvent<HTMLImageElement>) => void;\n unoptimized?: boolean;\n}\n\ntype TaggedPortalProduct = portalProducts.Product & {\n readonly __portalProduct: true;\n};\n\nexport type ProductCardProduct = LegacyProduct | TaggedPortalProduct;\n\ninterface ProductCardProps {\n product: ProductCardProduct;\n countryIso?: string;\n companyLogoUrl?: string | null;\n showShareModal?: boolean;\n setShareModalOpen?: (open: boolean) => void;\n setSelectedProduct?: (product: LegacyProduct) => void;\n renderLink?: (props: { href: string; children: ReactNode }) => ReactNode;\n renderImage?: (props: RenderImageProps) => ReactNode;\n onClick?: () => void;\n}\n\nexport function tagPortalProduct(\n product: portalProducts.Product,\n): TaggedPortalProduct {\n return { ...product, __portalProduct: true as const };\n}\n\nfunction isPortalProduct(\n product: ProductCardProduct,\n): product is TaggedPortalProduct {\n return \"__portalProduct\" in product && product.__portalProduct === true;\n}\n\nfunction getPortalProductCoverImage(\n product: portalProducts.Product,\n): string | null {\n if (product.images && product.images.length > 0) {\n return product.images[0]?.url ?? null;\n }\n return null;\n}\n\nfunction defaultRenderImage({\n src,\n alt,\n fill,\n className,\n onError,\n}: RenderImageProps): ReactNode {\n return (\n <img\n src={src}\n alt={alt}\n className={`${fill ? \"absolute inset-0 h-full w-full\" : \"\"} ${className ?? \"\"}`}\n onError={onError}\n />\n );\n}\n\nfunction formatPortalPrice(\n price: string | undefined,\n currency: string | undefined,\n): string | null {\n if (!price) return null;\n const numericPrice = Number(price);\n if (Number.isNaN(numericPrice)) return `${currency ?? \"\"}${price}`;\n try {\n return new Intl.NumberFormat(undefined, {\n style: \"currency\",\n currency: currency || \"USD\",\n }).format(numericPrice);\n } catch {\n return `$${price}`;\n }\n}\n\nfunction ProductCardContent({\n product,\n countryIso,\n companyLogoUrl,\n renderImage = defaultRenderImage,\n}: {\n product: ProductCardProduct;\n countryIso?: string;\n companyLogoUrl?: string | null;\n renderImage?: (props: RenderImageProps) => ReactNode;\n}) {\n const [isHovered, setIsHovered] = useState(false);\n\n const isPortal = isPortalProduct(product);\n const coverImage = isPortal\n ? getPortalProductCoverImage(product)\n : getProductImageUrl(product as Parameters<typeof getProductImageUrl>[0]);\n const isVideo = isVideoUrl(coverImage);\n const productName = isPortal\n ? product.name || \"No title available\"\n : (product as LegacyProduct).title || \"No title available\";\n\n let repPrice: string | null | undefined = null;\n let price: string | null | undefined = null;\n if (isPortal) {\n // wholesale_price is non-null for reps, null for customers\n if (product.wholesale_price) {\n repPrice = formatPortalPrice(product.wholesale_price, product.currency);\n // Show retail as strikethrough if different from wholesale\n const retailFormatted = formatPortalPrice(\n product.price,\n product.currency,\n );\n if (retailFormatted !== repPrice) {\n price = retailFormatted;\n }\n } else {\n repPrice = formatPortalPrice(product.price, product.currency);\n }\n } else if (countryIso) {\n const prices = determineProductPrice(product, countryIso);\n repPrice = prices.repPrice;\n price = prices.price;\n }\n\n return (\n <>\n {/* Image/Video container */}\n <div\n className=\"bg-muted relative aspect-square overflow-hidden\"\n onMouseEnter={() => isVideo && setIsHovered(true)}\n onMouseLeave={() => isVideo && setIsHovered(false)}\n >\n {isVideo && isHovered ? (\n <video\n src={coverImage || \"\"}\n className=\"absolute inset-0 h-full w-full object-cover\"\n autoPlay\n muted\n loop\n playsInline\n />\n ) : (\n renderImage({\n src:\n isVideo && coverImage\n ? getVideoThumbnailUrl(coverImage)\n : coverImage ||\n \"https://assets.fluid.app/fluid-admin/images/we-commerce/we-commerce.png\",\n alt: productName,\n fill: true,\n className:\n \"object-cover transition-transform group-hover:scale-105\",\n onError: (e) => {\n e.currentTarget.src =\n companyLogoUrl ||\n \"https://assets.fluid.app/fluid-admin/images/we-commerce/we-commerce.png\";\n },\n unoptimized: true,\n })\n )}\n\n {/* Video play indicator */}\n {isVideo && !isHovered && (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <div className=\"flex h-16 w-16 items-center justify-center rounded-full bg-black/50 backdrop-blur-sm\">\n <CirclePlay className=\"h-12 w-12 text-white\" />\n </div>\n </div>\n )}\n </div>\n\n {/* Product info */}\n <div className=\"px-3 pt-2 pb-4\">\n <h3 className=\"text-foreground line-clamp-1 text-sm font-bold\">\n {productName}\n </h3>\n\n <div className=\"flex items-center gap-2\">\n {repPrice && (\n <span className=\"text-foreground text-sm font-bold\">\n {repPrice}\n </span>\n )}\n {price && (\n <span className=\"text-muted-foreground text-sm line-through\">\n {price}\n </span>\n )}\n </div>\n\n {!isPortal && countryIso && (\n <div className=\"text-muted-foreground text-sm\">\n CV{\" \"}\n {getVariantCountryValue(\n getSelectedVariant(product as LegacyProduct),\n countryIso,\n \"cv\",\n ) || \"-\"}{\" \"}\n | QV{\" \"}\n {getVariantCountryValue(\n getSelectedVariant(product as LegacyProduct),\n countryIso,\n \"qv\",\n ) || \"-\"}\n </div>\n )}\n </div>\n </>\n );\n}\n\nfunction getSelectedVariant(\n product: LegacyProduct,\n): products.Variant | products.ShopVariant | null {\n if (!product.variants || product.variants.length === 0) return null;\n\n const masterVariant = product.variants.find(\n (v: products.Variant | products.ShopVariant) => {\n return \"is_master\" in v && v.is_master;\n },\n );\n if (masterVariant) return masterVariant;\n\n return product.variants[0] || null;\n}\n\nfunction getVariantCountryValue(\n variant: products.Variant | products.ShopVariant | null,\n countryIso: string,\n field: \"cv\" | \"qv\",\n): number | null {\n if (!variant || !variant.variant_countries) return null;\n\n if (\n typeof variant.variant_countries === \"object\" &&\n !Array.isArray(variant.variant_countries)\n ) {\n const countryData = variant.variant_countries[countryIso] as\n | products.VariantCountry\n | undefined;\n return countryData?.[field] ?? null;\n }\n\n if (Array.isArray(variant.variant_countries)) {\n const countryData = variant.variant_countries.find(\n (vc: products.ShopVariantCountry) => vc.country_iso === countryIso,\n );\n return countryData?.[field] ?? null;\n }\n\n return null;\n}\n\nexport default function ProductCard({\n product,\n countryIso,\n companyLogoUrl,\n showShareModal = false,\n setShareModalOpen,\n setSelectedProduct,\n renderLink,\n renderImage,\n onClick,\n}: ProductCardProps): React.JSX.Element {\n const cardContent = (\n <ProductCardContent\n product={product}\n countryIso={countryIso}\n companyLogoUrl={companyLogoUrl}\n renderImage={renderImage}\n />\n );\n\n const cardClassName = \"overflow-hidden border-0 shadow-none pt-0 gap-0\";\n\n if (showShareModal && !isPortalProduct(product)) {\n const handleShareClick = () => {\n if (setSelectedProduct && setShareModalOpen) {\n setSelectedProduct(product);\n setShareModalOpen(true);\n }\n };\n return (\n <Card className={cardClassName}>\n <button\n onClick={handleShareClick}\n className=\"group block w-full cursor-pointer text-left\"\n >\n {cardContent}\n </button>\n </Card>\n );\n }\n\n if (onClick) {\n return (\n <Card className={cardClassName}>\n <button\n onClick={onClick}\n className=\"group block w-full cursor-pointer text-left\"\n >\n {cardContent}\n </button>\n </Card>\n );\n }\n\n const href = `/portal/shop/${product.id}`;\n\n if (renderLink) {\n return (\n <Card className={cardClassName}>\n {renderLink({ href, children: cardContent })}\n </Card>\n );\n }\n\n return (\n <Card className={cardClassName}>\n <a href={href} className=\"group block cursor-pointer\">\n {cardContent}\n </a>\n </Card>\n );\n}\n","import type React from \"react\";\nimport { type ReactNode, useEffect, useMemo, useState } from \"react\";\nimport { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { isVideoUrl } from \"../utils/media-helpers\";\nimport type { RenderImageProps } from \"./product-card\";\n\ninterface ImageGalleryProps {\n images: Array<{\n id: number;\n image_url: string;\n image_path: string | null;\n position: number;\n }>;\n fallbackImageUrl: string;\n productTitle: string;\n renderImage?: (props: RenderImageProps) => ReactNode;\n}\n\nfunction defaultRenderImage({\n src,\n alt,\n fill,\n className,\n onError,\n}: RenderImageProps): ReactNode {\n return (\n <img\n src={src}\n alt={alt}\n className={`${fill ? \"absolute inset-0 h-full w-full\" : \"\"} ${className ?? \"\"}`}\n onError={onError}\n />\n );\n}\n\nexport default function ImageGallery({\n images,\n fallbackImageUrl,\n productTitle,\n renderImage = defaultRenderImage,\n}: ImageGalleryProps): React.JSX.Element {\n const [currentImageIndex, setCurrentImageIndex] = useState(0);\n\n const hasMultipleImages = images && images.length > 0;\n const displayImages = useMemo(\n () =>\n hasMultipleImages\n ? [...images].sort((a, b) => a.position - b.position)\n : [{ id: 0, image_url: fallbackImageUrl, position: 0 }],\n [images, hasMultipleImages, fallbackImageUrl],\n );\n\n // Reset to first image when the images array changes (e.g. variant switch)\n useEffect(() => {\n setCurrentImageIndex(0);\n }, [displayImages]);\n\n const nextImage = () => {\n if (displayImages.length > 1) {\n setCurrentImageIndex((prev) => (prev + 1) % displayImages.length);\n }\n };\n\n const prevImage = () => {\n if (displayImages.length > 1) {\n setCurrentImageIndex(\n (prev) => (prev - 1 + displayImages.length) % displayImages.length,\n );\n }\n };\n\n return (\n <div className=\"space-y-4\">\n {/* Main Image */}\n <div className=\"group relative aspect-square overflow-hidden rounded-sm bg-gray-100\">\n {isVideoUrl(displayImages[currentImageIndex]?.image_url) ? (\n <video\n key={displayImages[currentImageIndex]?.id}\n src={displayImages[currentImageIndex]?.image_url}\n className=\"absolute inset-0 h-full w-full object-cover\"\n controls\n loop\n playsInline\n />\n ) : (\n renderImage({\n src:\n displayImages[currentImageIndex]?.image_url || fallbackImageUrl,\n alt: productTitle,\n fill: true,\n className: \"object-cover\",\n onError: (e) => {\n e.currentTarget.src =\n \"https://assets.fluid.app/fluid-admin/images/we-commerce/we-commerce.png\";\n },\n unoptimized: true,\n })\n )}\n\n {/* Navigation arrows */}\n {displayImages.length > 1 && (\n <>\n <button\n type=\"button\"\n aria-label=\"Previous image\"\n className=\"absolute top-1/2 left-3 z-10 flex h-8 w-8 -translate-y-1/2 cursor-pointer items-center justify-center rounded-full bg-white/40 shadow-sm transition-colors group-hover:bg-white/80 hover:bg-white\"\n onClick={prevImage}\n >\n <ChevronLeft className=\"h-5 w-5 text-black/40 transition-colors group-hover:text-black\" />\n </button>\n <button\n type=\"button\"\n aria-label=\"Next image\"\n className=\"absolute top-1/2 right-3 z-10 flex h-8 w-8 -translate-y-1/2 cursor-pointer items-center justify-center rounded-full bg-white/40 shadow-sm transition-colors group-hover:bg-white/80 hover:bg-white\"\n onClick={nextImage}\n >\n <ChevronRight className=\"h-5 w-5 text-black/40 transition-colors group-hover:text-black\" />\n </button>\n </>\n )}\n\n {/* Page Indicators - Bottom Center */}\n {displayImages.length > 1 && (\n <div className=\"absolute bottom-3 left-1/2 flex -translate-x-1/2 gap-3\">\n {displayImages.map((_, index) => (\n <button\n type=\"button\"\n key={index}\n className={`h-1.5 w-6 cursor-pointer rounded-lg transition-colors ${\n index === currentImageIndex\n ? \"bg-gray-800\"\n : \"bg-gray-400 hover:bg-gray-600\"\n }`}\n aria-label={`Go to image ${index + 1}`}\n onClick={() => setCurrentImageIndex(index)}\n />\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n","import type React from \"react\";\nimport { Button } from \"@fluid-app/ui-primitives\";\n\ninterface QuantitySelectorProps {\n quantity: number;\n setQuantity: (quantity: number) => void;\n}\n\nexport default function QuantitySelector({\n quantity,\n setQuantity,\n}: QuantitySelectorProps): React.JSX.Element {\n return (\n <div className=\"flex items-center gap-3\">\n <div className=\"flex items-center rounded-lg\">\n <Button\n variant=\"default\"\n onClick={() => setQuantity(Math.max(1, quantity - 1))}\n className=\"border-0 px-3 py-2 shadow-none\"\n >\n −\n </Button>\n <span className=\"text-foreground min-w-8 px-4 py-2 text-center text-sm font-medium\">\n {quantity}\n </span>\n <Button\n variant=\"default\"\n onClick={() => setQuantity(quantity + 1)}\n className=\"border-0 px-3 py-2 shadow-none\"\n >\n +\n </Button>\n </div>\n </div>\n );\n}\n","import type React from \"react\";\nimport { useMemo } from \"react\";\nimport type { products } from \"@fluid-app/products-core\";\nimport {\n RadioGroup,\n RadioGroupItem,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@fluid-app/ui-primitives\";\n\ninterface PurchaseOptionsProps {\n showBuyOnce: boolean;\n showSubscribe: boolean;\n isSubscribe: boolean;\n onSubscribeChange: (subscribe: boolean) => void;\n product_subscription_plans: products.ProductSubscriptionPlan[];\n selectedSubscriptionPlan?: products.ProductSubscriptionPlan;\n onSubscriptionPlanChange?: (plan: products.ProductSubscriptionPlan) => void;\n userSelectedSubscribe: boolean;\n wholesalePrice?: number;\n wholesaleSubscriptionPrice?: number;\n}\n\nexport default function PurchaseOptions({\n showBuyOnce,\n showSubscribe,\n isSubscribe,\n onSubscribeChange,\n product_subscription_plans,\n selectedSubscriptionPlan,\n onSubscriptionPlanChange,\n userSelectedSubscribe,\n wholesalePrice,\n wholesaleSubscriptionPrice,\n}: PurchaseOptionsProps): React.JSX.Element | null {\n // Find default subscription plan or use first one\n const defaultSubscriptionPlan = useMemo(() => {\n if (!product_subscription_plans?.length) return null;\n return (\n product_subscription_plans.find((plan) => plan.default) ||\n product_subscription_plans[0]\n );\n }, [product_subscription_plans]);\n\n // Use selected plan or default to the default/first plan\n const currentSubscriptionPlan =\n selectedSubscriptionPlan || defaultSubscriptionPlan;\n\n // Calculate savings percentage from wholesale prices\n const savingsText = useMemo(() => {\n if (\n wholesalePrice === undefined ||\n wholesaleSubscriptionPrice === undefined ||\n wholesalePrice <= 0\n ) {\n return null;\n }\n\n const savings = wholesalePrice - wholesaleSubscriptionPrice;\n if (savings <= 0) return null;\n\n const savingsPercentage = Math.round((savings / wholesalePrice) * 100);\n if (savingsPercentage <= 0) return null;\n\n return `Save ${savingsPercentage}%`;\n }, [wholesalePrice, wholesaleSubscriptionPrice]);\n\n // Format subscription plan display name\n const formatSubscriptionPlan = (plan: products.ProductSubscriptionPlan) => {\n const interval = plan.subscription_plan.billing_interval;\n const unit = plan.subscription_plan.billing_interval_unit;\n return `${interval} ${unit} (${plan.subscription_plan.name})`;\n };\n\n // Prepare subscription plan options for Select component\n const subscriptionPlanOptions = useMemo(() => {\n if (!product_subscription_plans?.length) return [];\n\n return product_subscription_plans.map((plan) => ({\n value: plan.subscription_plan.id.toString(),\n label: formatSubscriptionPlan(plan),\n }));\n }, [product_subscription_plans]);\n\n // Don't render if only buy once is shown and subscribe is false\n if (showBuyOnce && !showSubscribe) {\n return null;\n }\n const handleSubscriptionPlanChange = (planId: string) => {\n const selectedPlan = product_subscription_plans?.find(\n (plan) => plan.subscription_plan.id.toString() === planId,\n );\n if (selectedPlan && onSubscriptionPlanChange) {\n onSubscriptionPlanChange(selectedPlan);\n }\n };\n\n const purchaseType = isSubscribe ? \"subscribe\" : \"once\";\n\n return (\n <div className=\"mb-3 flex flex-col\">\n <RadioGroup\n value={purchaseType}\n onValueChange={(value) => onSubscribeChange(value === \"subscribe\")}\n className=\"gap-0 space-y-0\"\n >\n {showSubscribe && (\n <div\n onClick={() => onSubscribeChange(true)}\n className={`cursor-pointer rounded-t-lg p-4 text-left transition-all duration-200 ${showBuyOnce ? \"border border-b-0\" : \"rounded-b-lg\"} ${userSelectedSubscribe ? \"bg-muted\" : \"bg-background\"}`}\n >\n <div className=\"flex items-start space-x-3\">\n <RadioGroupItem\n value=\"subscribe\"\n onClick={(e) => e.stopPropagation()}\n className={`flex items-center justify-center [&_svg]:h-1.5 [&_svg]:w-1.5 [&_svg]:fill-white ${\n isSubscribe\n ? \"border-contrast bg-contrast text-foreground\"\n : \"border-border bg-background text-muted-foreground\"\n }`}\n />\n <div className=\"flex-1\">\n <div className=\"text-foreground mb-1 text-sm leading-tight font-medium\">\n Subscribe{savingsText ? ` & ${savingsText}` : \"\"}\n </div>\n\n {/* Subscription Plan Dropdown*/}\n {product_subscription_plans?.length > 0 && (\n <div\n className=\"bg-muted mt-3 rounded-lg p-2\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"text-foreground mb-1 text-xs font-medium\">\n Delivery Frequency:\n </div>\n <Select\n value={\n currentSubscriptionPlan?.subscription_plan.id.toString() ||\n \"\"\n }\n onValueChange={handleSubscriptionPlanChange}\n disabled={product_subscription_plans?.length === 1}\n >\n <SelectTrigger className=\"bg-background text-foreground! w-full text-xs\">\n <SelectValue placeholder=\"Select delivery schedule\" />\n </SelectTrigger>\n <SelectContent>\n {subscriptionPlanOptions.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n )}\n </div>\n </div>\n </div>\n )}\n {showBuyOnce && (\n <div\n onClick={() => onSubscribeChange(false)}\n className={`cursor-pointer rounded-b-lg border p-4 text-left transition-all duration-200 ${showSubscribe ? \"border-t-0\" : \"rounded-t-lg\"} ${!userSelectedSubscribe ? \"bg-muted\" : \"bg-background\"}`}\n >\n <div className=\"flex items-center space-x-3\">\n <RadioGroupItem\n value=\"once\"\n onClick={(e) => e.stopPropagation()}\n className={`flex items-center justify-center [&_svg]:h-1.5 [&_svg]:w-1.5 [&_svg]:fill-white ${\n !isSubscribe\n ? \"border-contrast bg-contrast text-foreground\"\n : \"border-border bg-background text-muted-foreground\"\n }`}\n />\n <div className=\"text-foreground mb-1 text-sm leading-tight font-medium\">\n One-Time Purchase\n </div>\n </div>\n </div>\n )}\n </RadioGroup>\n </div>\n );\n}\n","import type React from \"react\";\nimport {\n useState,\n useMemo,\n useEffect,\n useRef,\n useCallback,\n type ReactNode,\n} from \"react\";\nimport {\n usePortalProductCatalog,\n usePortalProductDetail,\n type PortalProductPageParam,\n type portalProducts,\n type products,\n} from \"@fluid-app/products-core\";\nimport { useInfiniteQuery } from \"@tanstack/react-query\";\nimport {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuLabel,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Skeleton,\n} from \"@fluid-app/ui-primitives\";\nimport { SearchSort } from \"@fluid-app/ui-components/components/SearchSort\";\nimport { ArrowUpDown, ShoppingCart } from \"lucide-react\";\nimport ProductCard, {\n tagPortalProduct,\n type RenderImageProps,\n} from \"./product-card\";\nimport ImageGallery from \"./image-gallery\";\nimport QuantitySelector from \"./quantity-selector\";\nimport PurchaseOptions from \"./purchase-options\";\n\ninterface ShopAppProps {\n companyLogoUrl?: string | null;\n renderImage?: (props: RenderImageProps) => ReactNode;\n /** When provided, controls which product detail to show (URL-driven routing) */\n productId?: string | null;\n /** Called when a product is selected from the listing */\n onSelectProduct?: (productId: string) => void;\n /** Called when user navigates back from product detail */\n onBack?: () => void;\n /** Optional cart button to render in the header area */\n cartButton?: ReactNode;\n}\n\nconst PAGE_SIZE = 25;\n\nfunction sanitizeHtml(html: string): string {\n const doc = new DOMParser().parseFromString(html, \"text/html\");\n for (const el of doc.querySelectorAll(\n \"script, iframe, object, embed, form, base, meta, link, style\",\n )) {\n el.remove();\n }\n for (const el of doc.querySelectorAll(\"*\")) {\n for (const attr of [...el.attributes]) {\n if (\n attr.name.toLowerCase().startsWith(\"on\") ||\n attr.value.toLowerCase().trim().startsWith(\"javascript:\")\n ) {\n el.removeAttribute(attr.name);\n }\n }\n }\n return doc.body.innerHTML;\n}\n\nconst SORT_OPTIONS = [\n { id: \"title_asc\", label: \"Title (A-Z)\" },\n { id: \"title_desc\", label: \"Title (Z-A)\" },\n { id: \"price_asc\", label: \"Price (Low to High)\" },\n { id: \"price_desc\", label: \"Price (High to Low)\" },\n { id: \"created_at_desc\", label: \"Recently Updated\" },\n { id: \"created_at_asc\", label: \"Oldest Updated\" },\n];\n\nconst GRID_CLASS =\n \"grid grid-cols-1 gap-8 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-4\";\n\nfunction SkeletonGrid({ count = 8 }: { count?: number }) {\n return (\n <div className={GRID_CLASS}>\n {Array.from({ length: count }, (_, i) => (\n <div key={i} className=\"space-y-2\">\n <Skeleton className=\"aspect-square w-full rounded-lg\" />\n <Skeleton className=\"h-4 w-3/4\" />\n <Skeleton className=\"h-4 w-1/2\" />\n <Skeleton className=\"h-3 w-1/3\" />\n </div>\n ))}\n </div>\n );\n}\n\nfunction ProductListing({\n companyLogoUrl,\n renderImage,\n onSelectProduct,\n cartButton,\n}: {\n companyLogoUrl?: string | null;\n renderImage?: (props: RenderImageProps) => ReactNode;\n onSelectProduct: (productId: string) => void;\n cartButton?: ReactNode;\n}) {\n const observerTarget = useRef<HTMLDivElement>(null);\n\n const catalog = usePortalProductCatalog({ perPage: PAGE_SIZE });\n\n const {\n data,\n isLoading,\n isFetchingNextPage,\n hasNextPage,\n fetchNextPage,\n error,\n isFetched,\n } = useInfiniteQuery({\n queryKey: catalog.queryKey,\n queryFn: ({ pageParam }) => catalog.fetchProducts(pageParam),\n getNextPageParam: catalog.getNextPageParam,\n initialPageParam: undefined as PortalProductPageParam,\n });\n\n const handleIntersect = useCallback(\n (entries: IntersectionObserverEntry[]) => {\n if (entries[0]?.isIntersecting && hasNextPage && !isFetchingNextPage) {\n fetchNextPage();\n }\n },\n [hasNextPage, isFetchingNextPage, fetchNextPage],\n );\n\n useEffect(() => {\n const target = observerTarget.current;\n if (!target) return;\n\n const observer = new IntersectionObserver(handleIntersect, {\n threshold: 0.1,\n rootMargin: \"200px\",\n });\n observer.observe(target);\n return () => observer.disconnect();\n }, [handleIntersect]);\n\n const allProducts = data?.pages.flatMap((page) => page.products) ?? [];\n\n return (\n <div>\n <div className=\"mx-auto px-2 md:px-10\">\n {/* Search + Sort */}\n <div className=\"flex items-center justify-end gap-2 py-4\">\n <div className=\"w-full max-w-sm\">\n <SearchSort\n searchValue={catalog.searchTerm}\n onSearchChange={catalog.setSearchTerm}\n placeholder=\"Search products...\"\n />\n </div>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"outline\"\n size=\"icon\"\n className=\"h-9 w-9 shrink-0\"\n >\n <ArrowUpDown className=\"h-3 w-3\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-60\">\n <DropdownMenuLabel>Sort By</DropdownMenuLabel>\n <DropdownMenuSeparator />\n <DropdownMenuRadioGroup\n value={catalog.currentSort}\n onValueChange={catalog.setCurrentSort}\n >\n {SORT_OPTIONS.map((opt) => (\n <DropdownMenuRadioItem key={opt.id} value={opt.id}>\n {opt.label}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n {cartButton && (\n <div className=\"flex shrink-0 items-center gap-3\">{cartButton}</div>\n )}\n </div>\n </div>\n\n {/* Product Grid */}\n <div className=\"mx-auto space-y-8 px-2 md:px-10 md:py-8\">\n {isLoading ? (\n <SkeletonGrid />\n ) : error ? (\n <p className=\"mx-auto my-6 rounded-lg bg-red-100 px-3 py-2 text-red-500\">\n Error: {error.message}\n </p>\n ) : isFetched && allProducts.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-8 text-center\">\n <p className=\"text-muted-foreground text-sm\">\n {catalog.searchTerm\n ? `No products match \"${catalog.searchTerm}\". Try a different search term.`\n : \"There are no products available at the moment.\"}\n </p>\n </div>\n ) : (\n <>\n <div className={GRID_CLASS}>\n {allProducts.map((product) => (\n <ProductCard\n key={product.id}\n product={tagPortalProduct(product)}\n companyLogoUrl={companyLogoUrl}\n renderImage={renderImage}\n onClick={() => onSelectProduct(String(product.id))}\n />\n ))}\n </div>\n <div ref={observerTarget} />\n {isFetchingNextPage && <SkeletonGrid count={4} />}\n </>\n )}\n </div>\n </div>\n );\n}\n\ninterface OptionGroup {\n optionId: number;\n name: string;\n values: { id: number; name: string }[];\n}\n\n/**\n * Build the variant options map by grouping option_values across non-master variants.\n * Groups by option_id, collecting unique value entries.\n */\nfunction buildOptionGroups(variants: portalProducts.Variant[]): OptionGroup[] {\n const groupMap = new Map<\n number,\n { name: string; values: Map<number, string> }\n >();\n\n for (const variant of variants) {\n if (variant.is_master) continue;\n for (const ov of variant.option_values ?? []) {\n if (ov.option_id == null || ov.id == null) continue;\n if (!groupMap.has(ov.option_id)) {\n groupMap.set(ov.option_id, {\n name: ov.option_name ?? `Option ${ov.option_id}`,\n values: new Map(),\n });\n }\n groupMap.get(ov.option_id)!.values.set(ov.id, ov.name ?? String(ov.id));\n }\n }\n\n return [...groupMap.entries()].map(([optionId, group]) => ({\n optionId,\n name: group.name,\n values: [...group.values.entries()].map(([id, name]) => ({ id, name })),\n }));\n}\n\n/**\n * Find the variant matching a set of selected option value IDs.\n * selections is a map of optionId → selected value id.\n */\nfunction findVariantBySelections(\n variants: portalProducts.Variant[],\n selections: Record<number, number>,\n): portalProducts.Variant | undefined {\n const entries = Object.entries(selections).map(\n ([k, v]) => [Number(k), v] as const,\n );\n if (entries.length === 0) return undefined;\n return variants.find(\n (v) =>\n !v.is_master &&\n entries.every(([optionId, valueId]) =>\n v.option_values?.some(\n (ov) => ov.option_id === optionId && ov.id === valueId,\n ),\n ),\n );\n}\n\n/**\n * Map BFF flat subscription plans to the legacy ProductSubscriptionPlan shape\n * expected by the PurchaseOptions component.\n */\nfunction mapToLegacySubscriptionPlans(\n plans: portalProducts.SubscriptionPlan[],\n): products.ProductSubscriptionPlan[] {\n return plans.map((plan, idx) => ({\n id: plan.id,\n default: idx === 0,\n products_count: null,\n subscribers_count: null,\n active: true,\n subscription_plan: {\n id: plan.id ?? 0,\n name: plan.name ?? \"\",\n billing_interval: plan.billing_interval ?? 1,\n billing_interval_unit: plan.billing_interval_unit ?? \"month\",\n billing_frequency_in_words:\n plan.billing_frequency ??\n `${plan.billing_interval} ${plan.billing_interval_unit}`,\n active: true,\n price_adjustment_amount: null,\n price_adjustment_type: null,\n },\n }));\n}\n\nfunction formatPrice(price: string | undefined, currency: string | undefined) {\n if (!price) return null;\n const numericPrice = Number(price);\n if (Number.isNaN(numericPrice)) return `${currency ?? \"\"}${price}`;\n try {\n return new Intl.NumberFormat(undefined, {\n style: \"currency\",\n currency: currency || \"USD\",\n }).format(numericPrice);\n } catch {\n return `$${price}`;\n }\n}\n\nfunction ProductDetail({\n productId,\n renderImage,\n}: {\n productId: string;\n renderImage?: (props: RenderImageProps) => ReactNode;\n}) {\n const [quantity, setQuantity] = useState(1);\n // selections: optionId → selected value id\n const [selections, setSelections] = useState<Record<number, number>>({});\n const [userSelectedSubscribe, setUserSelectedSubscribe] = useState(false);\n const [selectedSubscriptionPlan, setSelectedSubscriptionPlan] = useState<\n products.ProductSubscriptionPlan | undefined\n >(undefined);\n\n const { product, isLoading, error, images } = usePortalProductDetail({\n productId,\n });\n\n const variants = useMemo(() => product?.variants ?? [], [product?.variants]);\n const subscriptionPlans = useMemo(\n () => product?.subscription_plans ?? [],\n [product?.subscription_plans],\n );\n\n // Default to the master variant, or the first available variant\n const masterVariant = useMemo(\n () => variants.find((v) => v.is_master) ?? variants[0],\n [variants],\n );\n\n // Build option groups from non-master variants\n const optionGroups = useMemo(() => buildOptionGroups(variants), [variants]);\n\n // Initialise selections from the first non-master variant (or master fallback)\n useEffect(() => {\n if (optionGroups.length === 0) return;\n const firstNonMaster = variants.find((v) => !v.is_master);\n const source = firstNonMaster ?? masterVariant;\n if (!source?.option_values?.length) return;\n const defaults: Record<number, number> = {};\n for (const ov of source.option_values) {\n if (ov.option_id != null && ov.id != null) {\n defaults[ov.option_id] = ov.id;\n }\n }\n setSelections(defaults);\n }, [optionGroups, variants, masterVariant]);\n\n // Resolve the currently selected variant\n const selectedVariant = useMemo(() => {\n if (optionGroups.length === 0) return masterVariant;\n return findVariantBySelections(variants, selections) ?? masterVariant;\n }, [variants, optionGroups, selections, masterVariant]);\n\n // Map BFF subscription plans → legacy ProductSubscriptionPlan shape for PurchaseOptions\n const legacySubscriptionPlans = useMemo(\n () => mapToLegacySubscriptionPlans(subscriptionPlans),\n [subscriptionPlans],\n );\n\n // Derive subscription state from variant\n const isSubscribe =\n selectedVariant?.subscription_only === true || userSelectedSubscribe;\n const showSubscribe = legacySubscriptionPlans.length > 0;\n const showBuyOnce = selectedVariant?.subscription_only !== true;\n\n // Auto-select subscribe when variant is subscription-only\n useEffect(() => {\n if (\n selectedVariant?.subscription_only &&\n legacySubscriptionPlans.length > 0\n ) {\n setUserSelectedSubscribe(true);\n }\n }, [selectedVariant, legacySubscriptionPlans]);\n\n // Prefer variant-specific images when available, fall back to product-level images\n const galleryImages = useMemo(() => {\n const variantImages = selectedVariant?.images;\n if (variantImages && variantImages.length > 0) {\n return variantImages.map((img, idx) => ({\n id: idx,\n image_url: img.url ?? \"\",\n image_path: null as string | null,\n position: idx,\n }));\n }\n return images.map((img, idx) => ({\n id: img.id ?? idx,\n image_url: img.url,\n image_path: null as string | null,\n position: idx,\n }));\n }, [selectedVariant?.images, images]);\n\n const coverImage = galleryImages[0]?.image_url ?? null;\n\n // Pricing: use selected variant's subscription_pricing for wholesale comparison\n const selectedPricing = selectedVariant?.subscription_pricing?.find(\n (sp) =>\n sp.plan_id ===\n (selectedSubscriptionPlan?.subscription_plan.id ??\n legacySubscriptionPlans[0]?.subscription_plan.id),\n );\n const wholesalePrice = selectedVariant?.wholesale_price\n ? Number(selectedVariant.wholesale_price)\n : undefined;\n const wholesaleSubscriptionPrice = selectedPricing?.wholesale_price\n ? Number(selectedPricing.wholesale_price)\n : undefined;\n\n // Display prices\n // price = retail price, wholesale_price = rep/logged-in price\n // subscription_pricing.wholesale_price = subscription wholesale price\n const currency = selectedVariant?.currency ?? product?.currency;\n const displayPrice = formatPrice(\n selectedVariant?.price ?? product?.price,\n currency,\n );\n const displayWholesalePrice = formatPrice(\n selectedVariant?.wholesale_price ??\n selectedVariant?.price ??\n product?.price,\n currency,\n );\n const displayWholesaleSubscriptionPrice = formatPrice(\n selectedPricing?.wholesale_price ??\n selectedPricing?.price ??\n selectedVariant?.wholesale_price ??\n undefined,\n currency,\n );\n\n // Resolve subscription plan ID for the cart SDK\n const resolvedPlanId =\n selectedSubscriptionPlan?.subscription_plan.id ??\n legacySubscriptionPlans.find((p) => p.default)?.subscription_plan.id ??\n legacySubscriptionPlans[0]?.subscription_plan.id;\n\n // Cart data attributes — SDK expects variant ID, not product ID\n const cartVariantId = String(selectedVariant?.id ?? product?.id ?? \"\");\n\n if (isLoading) {\n return (\n <div className=\"mx-auto max-w-7xl py-8 pr-4 pl-0 md:pr-6 lg:pr-8 lg:pl-0\">\n <div className=\"grid grid-cols-1 gap-5 lg:grid-cols-2\">\n <Skeleton className=\"aspect-square w-full rounded-lg\" />\n <div className=\"space-y-4 pl-2 lg:pl-20\">\n <Skeleton className=\"h-8 w-3/4\" />\n <Skeleton className=\"h-5 w-1/4\" />\n <Skeleton className=\"h-20 w-full\" />\n <Skeleton className=\"h-10 w-1/2\" />\n <Skeleton className=\"h-10 w-full\" />\n </div>\n </div>\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <div className=\"text-center\">\n <h3 className=\"text-foreground mb-2 text-lg font-medium\">\n Unable to load product\n </h3>\n <p className=\"text-muted-foreground\">\n Something went wrong. Please try again later.\n </p>\n </div>\n </div>\n );\n }\n\n if (!product) {\n return (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <div className=\"text-center\">\n <h3 className=\"text-foreground mb-2 text-lg font-medium\">\n Product not found\n </h3>\n <p className=\"text-muted-foreground\">\n The product you&apos;re looking for doesn&apos;t exist.\n </p>\n </div>\n </div>\n );\n }\n\n const title = product.name || \"Product\";\n const isBundle = product.bundle === true;\n const bundleUrl =\n isBundle && product.canonical_url ? product.canonical_url : null;\n\n return (\n <div className=\"pb-5 md:pl-8\">\n <div className=\"mx-auto max-w-7xl px-4 py-8 md:pr-6 md:pl-0 lg:pr-8 lg:pl-0\">\n <div className=\"grid grid-cols-1 gap-5 lg:grid-cols-2\">\n {/* Image Gallery */}\n <ImageGallery\n images={galleryImages}\n fallbackImageUrl={\n coverImage ??\n \"https://assets.fluid.app/fluid-admin/images/we-commerce/we-commerce.png\"\n }\n productTitle={title}\n renderImage={renderImage}\n />\n\n {/* Product Info */}\n <div className=\"max-w-lg pl-2 lg:pl-20\">\n <h1 className=\"text-foreground text-3xl font-bold\">{title}</h1>\n\n {/* Price — matches admin exactly */}\n {!isBundle && (\n <div className=\"mb-2 flex items-center gap-2\">\n <span className=\"text-foreground text-sm\">\n {isSubscribe\n ? displayWholesaleSubscriptionPrice\n : displayWholesalePrice}\n </span>\n {((isSubscribe &&\n displayWholesaleSubscriptionPrice !==\n displayWholesalePrice) ||\n (!isSubscribe && displayWholesalePrice !== displayPrice)) && (\n <span className=\"text-muted-foreground text-sm line-through\">\n {isSubscribe ? displayWholesalePrice : displayPrice}\n </span>\n )}\n </div>\n )}\n\n {/* Product Description */}\n <div className=\"pt-2\">\n <h3 className=\"text-foreground mb-1 text-sm font-medium\">\n Product Description\n </h3>\n <div\n className=\"text-foreground mb-3 text-[12px]\"\n dangerouslySetInnerHTML={{\n __html: sanitizeHtml(product.description ?? \"\"),\n }}\n />\n </div>\n\n {isBundle ? (\n <div className=\"pt-4\">\n <Button\n variant=\"default\"\n className=\"w-full gap-2 py-2 text-base font-medium\"\n disabled={!bundleUrl}\n onClick={() => {\n if (bundleUrl)\n window.open(bundleUrl, \"_blank\", \"noopener,noreferrer\");\n }}\n >\n Purchase Bundle\n </Button>\n {!bundleUrl && (\n <p className=\"text-muted-foreground mt-2 text-center text-xs\">\n Bundle configuration is unavailable. Please contact support.\n </p>\n )}\n </div>\n ) : (\n <>\n {/* Purchase Options — matches admin PurchaseOptions component */}\n <PurchaseOptions\n showBuyOnce={showBuyOnce}\n showSubscribe={showSubscribe}\n isSubscribe={isSubscribe}\n userSelectedSubscribe={userSelectedSubscribe}\n onSubscribeChange={setUserSelectedSubscribe}\n wholesalePrice={wholesalePrice}\n wholesaleSubscriptionPrice={wholesaleSubscriptionPrice}\n product_subscription_plans={legacySubscriptionPlans}\n selectedSubscriptionPlan={selectedSubscriptionPlan}\n onSubscriptionPlanChange={setSelectedSubscriptionPlan}\n />\n\n {/* Variant Options — matches admin layout */}\n {optionGroups.length > 0 && (\n <div className=\"mb-4 pt-4\">\n {optionGroups.map((group) => (\n <div\n key={group.optionId}\n className=\"mb-3 flex items-center\"\n >\n <h3 className=\"text-md text-foreground w-24 font-bold\">\n {group.name.charAt(0).toUpperCase() +\n group.name.slice(1)}\n </h3>\n <Select\n value={String(selections[group.optionId] ?? \"\")}\n onValueChange={(value) =>\n setSelections((prev) => ({\n ...prev,\n [group.optionId]: Number(value),\n }))\n }\n >\n <SelectTrigger className=\"w-48 max-w-full\">\n <SelectValue placeholder={`Select ${group.name}`} />\n </SelectTrigger>\n <SelectContent position=\"popper\" className=\"max-h-60\">\n {group.values.map((v) => (\n <SelectItem key={v.id} value={String(v.id)}>\n {v.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n ))}\n </div>\n )}\n\n {/* Unavailable product message */}\n {selectedVariant?.subscription_only &&\n !selectedVariant?.allow_subscription && (\n <div className=\"text-muted-foreground text-sm\">\n This product is unavailable for purchase.\n </div>\n )}\n\n {/* Quantity and Add to Cart — matches admin */}\n <div className=\"mt-4 mb-3\" />\n <div className=\"flex items-center gap-3 pb-3\">\n <QuantitySelector\n quantity={quantity}\n setQuantity={setQuantity}\n />\n\n <Button\n variant=\"default\"\n className=\"flex-1 gap-2 py-2 text-base font-medium\"\n disabled={\n selectedVariant?.subscription_only === true &&\n !selectedVariant?.allow_subscription\n }\n data-fluid-add-to-cart={cartVariantId}\n data-fluid-quantity={quantity}\n data-fluid-subscribe={isSubscribe}\n data-fluid-subscription-plan-id={\n isSubscribe ? String(resolvedPlanId ?? \"\") : \"\"\n }\n data-fluid-open-cart-after-add=\"false\"\n >\n <ShoppingCart className=\"h-4 w-4\" />\n {isSubscribe ? \"Subscribe\" : \"Add to Cart\"}\n </Button>\n </div>\n </>\n )}\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nexport default function ShopApp({\n companyLogoUrl,\n renderImage,\n productId: controlledProductId,\n onSelectProduct: onSelectProductProp,\n onBack: _onBack,\n cartButton,\n}: ShopAppProps): React.JSX.Element {\n // Internal state used only when navigation is not controlled externally\n const [internalProductId, setInternalProductId] = useState<string | null>(\n null,\n );\n\n const isControlled = controlledProductId !== undefined;\n const activeProductId = isControlled\n ? controlledProductId\n : internalProductId;\n\n const handleSelectProduct = onSelectProductProp ?? setInternalProductId;\n\n if (activeProductId) {\n return (\n <ProductDetail productId={activeProductId} renderImage={renderImage} />\n );\n }\n\n return (\n <ProductListing\n companyLogoUrl={companyLogoUrl}\n renderImage={renderImage}\n onSelectProduct={handleSelectProduct}\n cartButton={cartButton}\n />\n );\n}\n","import { useEffect, useRef } from \"react\";\n\ninterface CartScriptProps {\n subdomain: string;\n authJwt?: string;\n /** Enable BFF mode — uses portal session cookies instead of JWT for cart auth. */\n bffMode?: boolean;\n /** Override the SDK script URL (e.g. \"http://localhost:4444/index.js\" for local dev). */\n scriptSrc?: string;\n /** Override the API base URL the SDK uses (e.g. \"http://localhost:3000\" for local dev). */\n apiBaseUrl?: string;\n /** Enable SDK debug logging. */\n debug?: boolean;\n}\n\nconst SCRIPT_ID = \"fluid-cdn-script\";\nconst LEAD_CAPTURE_ID = \"fluid-lead-capture-suppress\";\nconst DEFAULT_SCRIPT_SRC =\n \"https://assets.fluid.app/scripts/fluid-sdk/latest/web-widgets/index.js\";\n\nexport default function CartScript({\n subdomain,\n authJwt,\n bffMode,\n scriptSrc,\n apiBaseUrl,\n debug,\n}: CartScriptProps): React.ReactNode {\n // Use a ref so the script is injected once with the initial values.\n // ES modules are cached by URL — re-inserting the same script won't\n // re-execute it, so changing props after the first load has no effect.\n const authJwtRef = useRef(authJwt);\n authJwtRef.current = authJwt;\n\n useEffect(() => {\n if (!subdomain) return;\n\n // Don't add a duplicate script\n if (document.getElementById(SCRIPT_ID)) return;\n\n const script = document.createElement(\"script\");\n script.id = SCRIPT_ID;\n script.src = scriptSrc ?? DEFAULT_SCRIPT_SRC;\n script.type = \"module\";\n script.crossOrigin = \"anonymous\";\n script.dataset.fluidShop = subdomain;\n if (bffMode) {\n script.dataset.bffMode = \"true\";\n } else if (authJwtRef.current) {\n script.dataset.authJwt = authJwtRef.current;\n }\n if (apiBaseUrl) {\n script.dataset.fluidApiBaseUrl = apiBaseUrl;\n }\n if (debug) {\n script.dataset.debug = \"true\";\n }\n document.head.appendChild(script);\n\n // Suppress the SDK's auto-injected lead capture widget.\n // The SDK skips injection when it finds an existing element with hide-widget.\n const leadCapture = document.createElement(\"fluid-lead-capture-widget\");\n leadCapture.id = LEAD_CAPTURE_ID;\n leadCapture.setAttribute(\"hide-widget\", \"true\");\n document.body.appendChild(leadCapture);\n\n return () => {\n const existing = document.getElementById(SCRIPT_ID);\n if (existing) existing.remove();\n const existingLeadCapture = document.getElementById(LEAD_CAPTURE_ID);\n if (existingLeadCapture) existingLeadCapture.remove();\n };\n }, [subdomain, bffMode, scriptSrc, apiBaseUrl, debug]);\n\n return null;\n}\n","import React, { useEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\ninterface CartWidgetProps {\n theme?: Record<string, string>;\n}\n\nexport default function CartWidget({\n theme,\n}: CartWidgetProps): React.ReactNode {\n const [mounted, setMounted] = useState(false);\n const widgetRef = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n if (!mounted) return;\n const el = widgetRef.current;\n if (!el) return;\n if (theme) {\n el.setAttribute(\"theme\", JSON.stringify(theme));\n } else {\n el.removeAttribute(\"theme\");\n }\n }, [theme, mounted]);\n\n const widget = React.createElement(\"fluid-cart-widget\", {\n ref: (el: HTMLElement | null) => {\n widgetRef.current = el;\n },\n \"data-fluid-widget\": \"true\",\n \"hide-widget\": \"true\",\n \"is-primary\": \"true\",\n });\n\n // Portal to document.body so the cart drawer escapes any\n // overflow-hidden / isolation stacking contexts in the layout.\n if (mounted) {\n return createPortal(widget, document.body);\n }\n\n return null;\n}\n","\"use client\";\n\nimport { Button } from \"@fluid-app/ui-primitives\";\nimport { ShoppingCart } from \"lucide-react\";\nimport React, { useEffect, useCallback, useState } from \"react\";\n\ndeclare global {\n interface Window {\n FluidCommerceSDK?: {\n getCheckoutUrl: () => string;\n setOnCheckout: (callback: () => void) => void;\n };\n FairShareSDK?: {\n getCartItemCount: () => number;\n isBffMode: () => boolean;\n updateLocaleSettings: (options: {\n language?: string;\n country?: string;\n }) => Promise<void>;\n };\n fluidCart?: {\n open: () => void;\n };\n }\n}\n\ninterface CartButtonProps {\n onCheckout?: (checkoutUrl: string) => void;\n}\n\nconst MAX_SDK_POLL_ATTEMPTS = 50; // 5 seconds at 100ms intervals\n\nexport function CartButton({ onCheckout }: CartButtonProps): React.ReactNode {\n const [initialCount, setInitialCount] = useState(0);\n\n const navigateToCheckout = useCallback(() => {\n if (!window.FluidCommerceSDK) {\n console.error(\"FluidCommerceSDK not available\");\n return;\n }\n\n try {\n const checkoutUrl = window.FluidCommerceSDK.getCheckoutUrl();\n if (!checkoutUrl) {\n console.error(\"No checkout URL available\");\n return;\n }\n onCheckout?.(checkoutUrl);\n } catch (error) {\n console.error(\"Error getting checkout URL:\", error);\n }\n }, [onCheckout]);\n\n useEffect(() => {\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n let attempts = 0;\n let cancelled = false;\n\n const setupSDK = () => {\n if (cancelled) return;\n if (window.FluidCommerceSDK) {\n if (onCheckout) {\n window.FluidCommerceSDK.setOnCheckout(navigateToCheckout);\n }\n const count = window.FairShareSDK?.getCartItemCount?.();\n if (count != null) {\n setInitialCount(count);\n }\n } else if (attempts < MAX_SDK_POLL_ATTEMPTS) {\n attempts++;\n timeoutId = setTimeout(setupSDK, 100);\n }\n };\n\n setupSDK();\n return () => {\n cancelled = true;\n if (timeoutId) clearTimeout(timeoutId);\n };\n }, [navigateToCheckout, onCheckout]);\n\n return (\n <Button\n className=\"bg-primary text-primary-foreground hover:bg-primary/70 relative flex items-center gap-4 rounded-sm px-4 py-1.5\"\n onClick={() => {\n window.fluidCart?.open();\n }}\n >\n <div className=\"relative\">\n <ShoppingCart className=\"size-5\" />\n <span\n id=\"fluid-cart-count\"\n className=\"bg-primary-foreground text-primary absolute -top-1 -right-2 flex h-4 w-4 items-center justify-center rounded-full text-[8px] font-bold\"\n >\n {initialCount}\n </span>\n </div>\n <span>Cart</span>\n </Button>\n );\n}\n","import React, { useEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\ninterface ShopContainerProps {\n children: React.ReactNode;\n className?: string;\n cartScript?: React.ReactNode;\n cartWidget?: React.ReactNode;\n}\n\nexport default function ShopContainer({\n children,\n className = \"\",\n cartScript,\n cartWidget,\n}: ShopContainerProps): React.ReactNode {\n const containerRef = useRef<HTMLDivElement>(null);\n const [portalContainer, setPortalContainer] = useState<HTMLDivElement | null>(\n null,\n );\n\n useEffect(() => {\n const currentContainer = containerRef.current;\n if (!currentContainer) return;\n\n const reactContentWrapper = document.createElement(\"div\");\n reactContentWrapper.id = \"react-content-wrapper\";\n reactContentWrapper.style.cssText = `\n position: relative;\n `;\n reactContentWrapper.className = \"min-h-full\";\n\n currentContainer.appendChild(reactContentWrapper);\n\n setPortalContainer(reactContentWrapper);\n\n return () => {\n if (currentContainer && reactContentWrapper) {\n try {\n currentContainer.removeChild(reactContentWrapper);\n } catch (e) {\n console.warn(\"Failed to cleanup isolated container:\", e);\n }\n }\n setPortalContainer(null);\n };\n }, []);\n\n return (\n <>\n <div\n ref={containerRef}\n className={`isolated-shop-wrapper ${className} h-full`}\n >\n {portalContainer &&\n createPortal(\n <>\n {cartScript}\n {cartWidget}\n {children}\n </>,\n portalContainer,\n )}\n </div>\n </>\n );\n}\n","import { type ComponentProps, useEffect, useMemo } from \"react\";\nimport ShopApp from \"@fluid-app/shop-ui/components/shop-app\";\nimport {\n CartButton,\n CartScript,\n CartWidget,\n ShopContainer,\n} from \"@fluid-app/cart-ui\";\nimport {\n Breadcrumb,\n BreadcrumbList,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@fluid-app/ui-primitives\";\nimport {\n useScreenHeaderBreadcrumbs,\n useScreenHeaderActions,\n} from \"@fluid-app/portal-react/shell/ScreenHeaderContext\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n PaddingOptions,\n} from \"../types\";\nimport type { WidgetPropertySchema } from \"../registries/property-schema-types\";\nimport { useFluidContext } from \"../providers/FluidProvider\";\nimport { useAppNavigation } from \"../shell/AppNavigationContext\";\nimport { useStore } from \"../hooks/use-store\";\nimport { PortalProductsApiProvider } from \"../products/PortalProductsApiProvider\";\nimport { usePortalProductDetail } from \"@fluid-app/products-core\";\n\ntype ShopScreenProps = ComponentProps<\"div\"> & {\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n};\n\nexport function ShopScreen({\n /* eslint-disable @typescript-eslint/no-unused-vars -- destructured to exclude from divProps spread */\n background,\n textColor,\n accentColor,\n padding,\n borderRadius,\n /* eslint-enable @typescript-eslint/no-unused-vars */\n ...divProps\n}: ShopScreenProps): React.JSX.Element {\n const { config } = useFluidContext();\n const { data: store } = useStore();\n const { currentSlug, navigate } = useAppNavigation();\n const countryCode = config.countryIso ?? \"US\";\n const subdomain = store?.subdomain;\n\n // Parse product ID from slug: \"shop/{productId}\"\n const parts = currentSlug.split(\"/\");\n const productId = parts[1] ?? null;\n\n const headerBreadcrumbs = useMemo(\n () => (\n <Breadcrumb>\n <BreadcrumbList className=\"text-lg\">\n <BreadcrumbItem>\n {productId ? (\n <BreadcrumbLink\n onClick={() => navigate(\"shop\")}\n className=\"cursor-pointer font-semibold\"\n >\n Shop\n </BreadcrumbLink>\n ) : (\n <BreadcrumbPage className=\"font-semibold\">Shop</BreadcrumbPage>\n )}\n </BreadcrumbItem>\n </BreadcrumbList>\n </Breadcrumb>\n ),\n [productId, navigate],\n );\n useScreenHeaderBreadcrumbs(headerBreadcrumbs);\n\n const headerActions = useMemo(\n () => (\n <div className=\"flex items-center gap-4\">\n <CartButton />\n </div>\n ),\n [],\n );\n useScreenHeaderActions(headerActions);\n\n // Sync country to FairShare SDK so the cart uses the correct country.\n // The SDK loads asynchronously via a script tag and also initializes its\n // session asynchronously after the object appears on window. Poll until\n // updateLocaleSettings resolves successfully (Sentry fix: FLUID-ADMIN-1FD —\n // SDK object present does not mean session is ready).\n useEffect(() => {\n if (!countryCode) return;\n type FairShareWindow = {\n FairShareSDK?: {\n updateLocaleSettings: (opts: { country: string }) => Promise<void>;\n };\n };\n const sdk = () => (window as FairShareWindow).FairShareSDK;\n let done = false;\n\n let inFlight = false;\n const tryUpdate = async () => {\n const fairShareSdk = sdk();\n if (done || inFlight || !fairShareSdk) return;\n inFlight = true;\n try {\n await fairShareSdk.updateLocaleSettings({ country: countryCode });\n done = true;\n clearInterval(id);\n } catch {\n // Session not yet initialized — keep polling until it is\n } finally {\n inFlight = false;\n }\n };\n\n let attempts = 0;\n const id = setInterval(() => {\n if (attempts >= 50) {\n console.warn(\n \"[FairShare] updateLocaleSettings: gave up after 50 attempts — session never became ready\",\n { country: countryCode },\n );\n clearInterval(id);\n return;\n }\n attempts++;\n void tryUpdate();\n }, 100);\n\n return () => {\n done = true;\n clearInterval(id);\n };\n }, [countryCode]);\n\n // TODO(portal-theme): Cart widget theming requires AppShell to expose\n // resolvedTheme via context. Currently it's local state in AppShell.\n\n return (\n <div {...divProps} className={divProps.className ?? \"\"}>\n <ShopContainer\n cartScript={\n subdomain ? (\n <CartScript\n subdomain={subdomain}\n bffMode\n scriptSrc={\n import.meta.env.DEV\n ? String(\n import.meta.env.VITE_FAIRSHARE_SDK_URL ||\n \"http://localhost:4444/index.js\",\n )\n : undefined\n }\n apiBaseUrl={\n import.meta.env.DEV\n ? String(\n import.meta.env.VITE_FAIRSHARE_API_BASE_URL ||\n \"http://api.fluid.localhost:3000\",\n )\n : undefined\n }\n debug={import.meta.env.DEV}\n />\n ) : null\n }\n cartWidget={<CartWidget />}\n >\n <PortalProductsApiProvider>\n {productId && <ProductBreadcrumb productId={productId} />}\n <ShopApp\n companyLogoUrl={store?.logo_url ?? undefined}\n productId={productId}\n onSelectProduct={(id) => navigate(`shop/${id}`)}\n onBack={() => navigate(\"shop\")}\n />\n </PortalProductsApiProvider>\n </ShopContainer>\n </div>\n );\n}\n\nexport const shopScreenPropertySchema: WidgetPropertySchema = {\n widgetType: \"ShopScreen\",\n displayName: \"Shop Screen\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [],\n} as const satisfies WidgetPropertySchema;\n\n/**\n * Renders inside PortalProductsCoreProvider to set breadcrumbs with the\n * product name: \"Shop > {product name}\". Overrides the parent's \"Shop\"\n * breadcrumb once product data loads.\n */\nfunction ProductBreadcrumb({ productId }: { productId: string }) {\n const { navigate } = useAppNavigation();\n const { product } = usePortalProductDetail({ productId });\n const productName = product?.name ?? \"Product\";\n\n const breadcrumb = useMemo(\n () => (\n <Breadcrumb>\n <BreadcrumbList className=\"text-lg\">\n <BreadcrumbItem>\n <BreadcrumbLink\n onClick={() => navigate(\"shop\")}\n className=\"cursor-pointer font-semibold\"\n >\n Shop\n </BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbPage className=\"font-semibold\">\n {productName}\n </BreadcrumbPage>\n </BreadcrumbItem>\n </BreadcrumbList>\n </Breadcrumb>\n ),\n [productName, navigate],\n );\n useScreenHeaderBreadcrumbs(breadcrumb);\n\n return null;\n}\n"],"mappings":"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"}
@@ -1,49 +1,49 @@
1
1
  require("./chunk-9hOWP6kD.cjs");
2
- require("./FluidProvider-DcpUKHrn.cjs");
3
- require("./ScreenRenderer-aYfgv6mR.cjs");
2
+ require("./FluidProvider-DRXysbXj.cjs");
3
+ require("./ScreenRenderer-xH01YkEQ.cjs");
4
4
  require("./account-api-context-DZP9IiGg.cjs");
5
5
  require("./store-api-context-D1gZn22Z.cjs");
6
6
  require("./pay-api-context-_o5ZEXYt.cjs");
7
7
  require("./mysite-api-context-Dz4lI5Xd.cjs");
8
8
  require("./countries-api-context-C0C0K9gJ.cjs");
9
9
  require("./src-DiFCBegK.cjs");
10
- require("./registry-context-C7-RLxVt.cjs");
11
- require("./WidgetInteractionContext-Bs3LkFFH.cjs");
10
+ require("./registry-context-CcZYS15Q.cjs");
11
+ require("./WidgetInteractionContext-DvPmzGqB.cjs");
12
12
  require("./EmbedWidget-Q45pAeCI.cjs");
13
13
  require("./error-state-BDhSltIa.cjs");
14
- require("./LayoutWidget-CK-SvFQL.cjs");
14
+ require("./LayoutWidget-Bt2I2XMy.cjs");
15
15
  require("./registries-DBb6VjAX.cjs");
16
16
  require("./fields-COJ84ouS.cjs");
17
17
  require("./TextWidget-C7oY0X3r.cjs");
18
18
  require("./AlertWidget-BZ67Uqfh.cjs");
19
19
  require("./BulletListWidget-iGJI33Ed.cjs");
20
- require("./CalendarWidget-oGK122s9.cjs");
21
- require("./CardWidget-CSLSlKM6.cjs");
20
+ require("./CalendarWidget-C4Dv_TUk.cjs");
21
+ require("./CardWidget-D-KEikO_.cjs");
22
22
  require("./purify.es-CxBw_WJp.cjs");
23
- require("./MediaRenderer-CfgWd0cC.cjs");
24
- require("./CarouselWidget-DlxYQB5j.cjs");
25
- require("./CatchUpWidget-B1Muaurg.cjs");
23
+ require("./MediaRenderer-CvN8Ku0i.cjs");
24
+ require("./CarouselWidget-Cu1b3ERq.cjs");
25
+ require("./CatchUpWidget-BzgybvuC.cjs");
26
26
  require("./src-uhf6Szlw.cjs");
27
27
  require("./ChartWidget-CFB4Yg0k.cjs");
28
- require("./ContainerWidget-Cjwrq2MS.cjs");
29
- require("./ImageWidget-xcE0sFf-.cjs");
30
- require("./LinkWidget-B14FTQP7.cjs");
31
- require("./ListWidget-wBDnXWxa.cjs");
32
- require("./MySiteWidget-DRH4q_YV.cjs");
28
+ require("./ContainerWidget-DbAhQKbY.cjs");
29
+ require("./ImageWidget-CbQVxMe3.cjs");
30
+ require("./LinkWidget-BoR7nVbH.cjs");
31
+ require("./ListWidget-CzljZ1LA.cjs");
32
+ require("./MySiteWidget-CYiH2lmX.cjs");
33
33
  require("./scroll-arrows-DhwdUQBY.cjs");
34
- require("./NestedWidget-C_2XwnW0.cjs");
35
- require("./PointsWidget-CLUWrFjZ.cjs");
34
+ require("./NestedWidget-CEoAO2sp.cjs");
35
+ require("./PointsWidget-C5cXxKlM.cjs");
36
36
  require("./QuickLinksWidget-DBH-HRvz.cjs");
37
37
  require("./QuickShareWidget-Btoe8CyN.cjs");
38
- require("./RecentActivityWidget-C6RwlUUw.cjs");
38
+ require("./RecentActivityWidget-DNyhUZNs.cjs");
39
39
  require("./SeparatorWidget-BCbzDxnz.cjs");
40
40
  require("./SpacerWidget-CI3to-88.cjs");
41
- require("./TableWidget-D4jQN-to.cjs");
42
- require("./ToDoWidget-BbeXt99H.cjs");
43
- require("./VideoWidget-Bc6ZAAaA.cjs");
41
+ require("./TableWidget-BIn1oRiJ.cjs");
42
+ require("./ToDoWidget-OxT9z59F.cjs");
43
+ require("./VideoWidget-CDcV0J5W.cjs");
44
44
  require("./ScreenHeaderContext-oIu5Bvhs.cjs");
45
45
  require("./SearchSort-CeJqRK2c.cjs");
46
46
  require("./PortalProductsApiProvider-DL8nl7To.cjs");
47
- const require_ShopScreen = require("./ShopScreen-CiGozvW4.cjs");
47
+ const require_ShopScreen = require("./ShopScreen-B6Bo1VOu.cjs");
48
48
  exports.ShopScreen = require_ShopScreen.ShopScreen;
49
49
  exports.shopScreenPropertySchema = require_ShopScreen.shopScreenPropertySchema;