@fluid-app/portal-sdk 0.1.78 → 0.1.80

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 (97) hide show
  1. package/dist/{AppDownloadScreen-C_NGlFZa.mjs → AppDownloadScreen-B0BNM-6c.mjs} +2 -2
  2. package/dist/{AppDownloadScreen-C_NGlFZa.mjs.map → AppDownloadScreen-B0BNM-6c.mjs.map} +1 -1
  3. package/dist/{AppDownloadScreen-BlfMkfi_.cjs → AppDownloadScreen-CgfEU2wC.cjs} +5 -5
  4. package/dist/{AppDownloadScreen-Cw1sGNNg.cjs → AppDownloadScreen-DRwTJHQ8.cjs} +2 -2
  5. package/dist/{AppDownloadScreen-Cw1sGNNg.cjs.map → AppDownloadScreen-DRwTJHQ8.cjs.map} +1 -1
  6. package/dist/{CalendarWidget-Bj0prW4s.cjs → CalendarWidget-BG5_GulK.cjs} +3 -3
  7. package/dist/CalendarWidget-BG5_GulK.cjs.map +1 -0
  8. package/dist/{CalendarWidget-DDFVe7-h.mjs → CalendarWidget-BHSLd43x.mjs} +3 -3
  9. package/dist/CalendarWidget-BHSLd43x.mjs.map +1 -0
  10. package/dist/{ContactsScreen-D4Cj5AKH.mjs → ContactsScreen-BeN-m9ht.mjs} +2 -2
  11. package/dist/{ContactsScreen-D4Cj5AKH.mjs.map → ContactsScreen-BeN-m9ht.mjs.map} +1 -1
  12. package/dist/{ContactsScreen-CwBXsCW8.cjs → ContactsScreen-DY-cfJc-.cjs} +2 -2
  13. package/dist/{ContactsScreen-CwBXsCW8.cjs.map → ContactsScreen-DY-cfJc-.cjs.map} +1 -1
  14. package/dist/{ContactsScreen-C6T8Vfz4.cjs → ContactsScreen-Dt74iM-l.cjs} +5 -5
  15. package/dist/{FluidProvider-CidgidrK.cjs → FluidProvider-B7whI5Fk.cjs} +7 -7
  16. package/dist/{FluidProvider-CidgidrK.cjs.map → FluidProvider-B7whI5Fk.cjs.map} +1 -1
  17. package/dist/{FluidProvider-6ARIhCTq.mjs → FluidProvider-C4OAgBdt.mjs} +7 -7
  18. package/dist/{FluidProvider-6ARIhCTq.mjs.map → FluidProvider-C4OAgBdt.mjs.map} +1 -1
  19. package/dist/{ListWidget-CunZTx5S.cjs → ListWidget-BKdwD5kR.cjs} +1 -1
  20. package/dist/{ListWidget-g2qBtmNZ.cjs → ListWidget-Ch386fkp.cjs} +7 -7
  21. package/dist/ListWidget-Ch386fkp.cjs.map +1 -0
  22. package/dist/{ListWidget-xPZwneuu.mjs → ListWidget-DhRPDaP7.mjs} +7 -7
  23. package/dist/ListWidget-DhRPDaP7.mjs.map +1 -0
  24. package/dist/{MessagingScreen-Dkm1cqJ8.mjs → MessagingScreen-BgDTY3Ej.mjs} +3 -3
  25. package/dist/{MessagingScreen-Dkm1cqJ8.mjs.map → MessagingScreen-BgDTY3Ej.mjs.map} +1 -1
  26. package/dist/{MessagingScreen-BshcZj2z.cjs → MessagingScreen-CUbqMqWe.cjs} +3 -3
  27. package/dist/{MessagingScreen-BshcZj2z.cjs.map → MessagingScreen-CUbqMqWe.cjs.map} +1 -1
  28. package/dist/{MessagingScreen-DevHJI6g.mjs → MessagingScreen-UiC3gK4x.mjs} +5 -5
  29. package/dist/{MessagingScreen-BA8ujs72.cjs → MessagingScreen-rTJ0M2md.cjs} +5 -5
  30. package/dist/{MySiteScreen-O7m3F8bT.mjs → MySiteScreen-CGXVSu2s.mjs} +2 -2
  31. package/dist/{MySiteScreen-O7m3F8bT.mjs.map → MySiteScreen-CGXVSu2s.mjs.map} +1 -1
  32. package/dist/{MySiteScreen-i8J8Ttzz.cjs → MySiteScreen-I6ebtBnN.cjs} +5 -5
  33. package/dist/{MySiteScreen-BTGBB4-v.cjs → MySiteScreen-jAT4_j14.cjs} +2 -2
  34. package/dist/{MySiteScreen-BTGBB4-v.cjs.map → MySiteScreen-jAT4_j14.cjs.map} +1 -1
  35. package/dist/{MySiteWidget-DI9-dyjX.mjs → MySiteWidget-DLBW4V7P.mjs} +25 -4
  36. package/dist/MySiteWidget-DLBW4V7P.mjs.map +1 -0
  37. package/dist/{MySiteWidget-BfBdrYgj.cjs → MySiteWidget-DUS5TAjk.cjs} +25 -4
  38. package/dist/MySiteWidget-DUS5TAjk.cjs.map +1 -0
  39. package/dist/{OrdersScreen-CWIKWDTW.cjs → OrdersScreen-B5ANhAJJ.cjs} +5 -5
  40. package/dist/{OrdersScreen-BF86JWxG.cjs → OrdersScreen-D2wDUClf.cjs} +3 -3
  41. package/dist/{OrdersScreen-BF86JWxG.cjs.map → OrdersScreen-D2wDUClf.cjs.map} +1 -1
  42. package/dist/{OrdersScreen-DoXE66il.mjs → OrdersScreen-gYB5v9-2.mjs} +3 -3
  43. package/dist/{OrdersScreen-DoXE66il.mjs.map → OrdersScreen-gYB5v9-2.mjs.map} +1 -1
  44. package/dist/{ProductsScreen-Bef0sSgj.mjs → ProductsScreen-D0-AZMm-.mjs} +5 -5
  45. package/dist/{ProductsScreen-868va-qn.cjs → ProductsScreen-DerVrACc.cjs} +5 -5
  46. package/dist/{ProductsScreen-CFKSDJJ0.mjs → ProductsScreen-yuVjp5Ia.mjs} +3 -3
  47. package/dist/{ProductsScreen-CFKSDJJ0.mjs.map → ProductsScreen-yuVjp5Ia.mjs.map} +1 -1
  48. package/dist/{ProductsScreen-D4dDVYFJ.cjs → ProductsScreen-zPoSxUNt.cjs} +3 -3
  49. package/dist/{ProductsScreen-D4dDVYFJ.cjs.map → ProductsScreen-zPoSxUNt.cjs.map} +1 -1
  50. package/dist/{ProfileScreen-BsUzZmHF.mjs → ProfileScreen-B6YgnBLf.mjs} +3 -3
  51. package/dist/{ProfileScreen-BsUzZmHF.mjs.map → ProfileScreen-B6YgnBLf.mjs.map} +1 -1
  52. package/dist/{ProfileScreen-B_I_A77d.cjs → ProfileScreen-BUtP6J5R.cjs} +3 -3
  53. package/dist/{ProfileScreen-B_I_A77d.cjs.map → ProfileScreen-BUtP6J5R.cjs.map} +1 -1
  54. package/dist/{ProfileScreen-C168MNNR.cjs → ProfileScreen-H6Bf48IB.cjs} +5 -5
  55. package/dist/{ShareablesScreen-2N0DWP77.mjs → ShareablesScreen-D-1sBYBA.mjs} +5 -5
  56. package/dist/{ShareablesScreen-D9uPu6DJ.cjs → ShareablesScreen-DQJX1_hv.cjs} +3 -3
  57. package/dist/{ShareablesScreen-D9uPu6DJ.cjs.map → ShareablesScreen-DQJX1_hv.cjs.map} +1 -1
  58. package/dist/{ShareablesScreen-2EJChSOH.mjs → ShareablesScreen-_W9PMbTW.mjs} +3 -3
  59. package/dist/{ShareablesScreen-2EJChSOH.mjs.map → ShareablesScreen-_W9PMbTW.mjs.map} +1 -1
  60. package/dist/{ShareablesScreen-BgUQxGzL.cjs → ShareablesScreen-vgMekz5j.cjs} +5 -5
  61. package/dist/{ShopScreen-CTp2FaRe.cjs → ShopScreen-D7c5SS1G.cjs} +5 -5
  62. package/dist/{ShopScreen-BaqN34iX.mjs → ShopScreen-DRYCLI2E.mjs} +4 -4
  63. package/dist/{ShopScreen-BaqN34iX.mjs.map → ShopScreen-DRYCLI2E.mjs.map} +1 -1
  64. package/dist/{ShopScreen-DhbYFraU.cjs → ShopScreen-DRgM8del.cjs} +4 -4
  65. package/dist/{ShopScreen-DhbYFraU.cjs.map → ShopScreen-DRgM8del.cjs.map} +1 -1
  66. package/dist/{SubscriptionsScreen-fliVeZk_.mjs → SubscriptionsScreen-B3c1ueS_.mjs} +3 -3
  67. package/dist/{SubscriptionsScreen-fliVeZk_.mjs.map → SubscriptionsScreen-B3c1ueS_.mjs.map} +1 -1
  68. package/dist/{SubscriptionsScreen-CwDH0DNT.cjs → SubscriptionsScreen-CUE6aS8F.cjs} +3 -3
  69. package/dist/{SubscriptionsScreen-CwDH0DNT.cjs.map → SubscriptionsScreen-CUE6aS8F.cjs.map} +1 -1
  70. package/dist/{SubscriptionsScreen-nkxjIDie.cjs → SubscriptionsScreen-CwBXa8Ft.cjs} +5 -5
  71. package/dist/index.cjs +37 -37
  72. package/dist/index.d.cts.map +1 -1
  73. package/dist/index.d.mts.map +1 -1
  74. package/dist/index.mjs +37 -37
  75. package/dist/{use-account-clients-CDAazmHw.mjs → use-account-clients-Bqwc4jT0.mjs} +2 -2
  76. package/dist/{use-account-clients-CDAazmHw.mjs.map → use-account-clients-Bqwc4jT0.mjs.map} +1 -1
  77. package/dist/{use-account-clients-CgP9ZZbx.cjs → use-account-clients-N3gfibU3.cjs} +2 -2
  78. package/dist/{use-account-clients-CgP9ZZbx.cjs.map → use-account-clients-N3gfibU3.cjs.map} +1 -1
  79. package/dist/{use-current-user-CudhrJtA.mjs → use-current-user-BUXtOeFz.mjs} +3 -3
  80. package/dist/{use-current-user-CudhrJtA.mjs.map → use-current-user-BUXtOeFz.mjs.map} +1 -1
  81. package/dist/{use-current-user-C3xp6f2-.cjs → use-current-user-C2A379kM.cjs} +3 -3
  82. package/dist/{use-current-user-C3xp6f2-.cjs.map → use-current-user-C2A379kM.cjs.map} +1 -1
  83. package/dist/{use-customer-account-72qR-BtL.cjs → use-customer-account-DJxnOr1n.cjs} +3 -3
  84. package/dist/{use-customer-account-72qR-BtL.cjs.map → use-customer-account-DJxnOr1n.cjs.map} +1 -1
  85. package/dist/{use-customer-account-Dfyhs3LY.mjs → use-customer-account-DVQzpWxo.mjs} +3 -3
  86. package/dist/{use-customer-account-Dfyhs3LY.mjs.map → use-customer-account-DVQzpWxo.mjs.map} +1 -1
  87. package/dist/{use-fluid-api-C53ZoBpG.mjs → use-fluid-api-BwYwsyDl.mjs} +2 -2
  88. package/dist/{use-fluid-api-C53ZoBpG.mjs.map → use-fluid-api-BwYwsyDl.mjs.map} +1 -1
  89. package/dist/{use-fluid-api-Cc0xHt74.cjs → use-fluid-api-C3T17MND.cjs} +2 -2
  90. package/dist/{use-fluid-api-Cc0xHt74.cjs.map → use-fluid-api-C3T17MND.cjs.map} +1 -1
  91. package/package.json +14 -14
  92. package/dist/CalendarWidget-Bj0prW4s.cjs.map +0 -1
  93. package/dist/CalendarWidget-DDFVe7-h.mjs.map +0 -1
  94. package/dist/ListWidget-g2qBtmNZ.cjs.map +0 -1
  95. package/dist/ListWidget-xPZwneuu.mjs.map +0 -1
  96. package/dist/MySiteWidget-BfBdrYgj.cjs.map +0 -1
  97. package/dist/MySiteWidget-DI9-dyjX.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"use-current-user-CudhrJtA.mjs","names":[],"sources":["../src/hooks/query-keys.ts","../src/hooks/use-current-user.ts"],"sourcesContent":["/**\n * Company-scoped query key factory for TanStack Query.\n *\n * All portal SDK query keys are prefixed with [\"company\", companyId, ...]\n * so that switching companies naturally invalidates the entire cache scope.\n *\n * The exported `*_QUERY_KEY` constants (e.g. PROFILE_QUERY_KEY) remain as\n * backwards-compatible base keys. The runtime keys used by hooks include the\n * company prefix via {@link createCompanyQueryKey}.\n */\n\nimport { useCallback, useRef } from \"react\";\nimport { useFluidAuthContext } from \"../providers/FluidAuthProvider\";\n\n/**\n * Create a company-scoped query key by prepending [\"company\", companyId].\n *\n * @param companyId - The company ID from the JWT payload\n * @param baseKey - The base query key segments (e.g. [\"fluid\", \"profile\"])\n * @returns A tuple like [\"company\", 42, \"fluid\", \"profile\"]\n *\n * @example\n * ```ts\n * const key = createCompanyQueryKey(42, \"fluid\", \"profile\");\n * // => [\"company\", 42, \"fluid\", \"profile\"]\n * ```\n */\nexport function createCompanyQueryKey(\n companyId: number,\n ...baseKey: readonly string[]\n): readonly [\"company\", number, ...string[]] {\n return [\"company\", companyId, ...baseKey] as const;\n}\n\n/**\n * Hook that returns a `scopeKey` function bound to the current company ID\n * from the auth context. If the user is not authenticated or has no\n * company_id, the base key is returned unscoped (graceful degradation).\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { scopeKey } = useCompanyScopedQueryKey();\n * const queryKey = scopeKey(PROFILE_QUERY_KEY);\n * // => [\"company\", 42, \"fluid\", \"profile\"] (when authenticated)\n * // => [\"fluid\", \"profile\"] (fallback)\n * }\n * ```\n */\nexport function useCompanyScopedQueryKey(): {\n readonly companyId: number | undefined;\n readonly scopeKey: <T extends readonly string[]>(\n baseKey: T,\n ) => readonly (string | number)[];\n} {\n const auth = useFluidAuthContext();\n const companyId = auth.user?.company_id;\n\n // Warn (once per component instance) when an authenticated user has no\n // company_id. This is a security-relevant condition: unscoped keys allow\n // cross-company cache collisions. The warning fires in all environments\n // so that it's visible in production logs if a misconfigured JWT is issued.\n const hasWarnedRef = useRef(false);\n if (auth.isAuthenticated && companyId == null && !hasWarnedRef.current) {\n hasWarnedRef.current = true;\n console.warn(\n \"[portal-sdk] Authenticated user has no company_id in JWT. \" +\n \"Query keys will fall back to unscoped keys, which may cause \" +\n \"cross-company cache collisions. Ensure the JWT includes company_id.\",\n );\n }\n\n const scopeKey = useCallback(\n <T extends readonly string[]>(baseKey: T): readonly (string | number)[] => {\n if (companyId != null) {\n return createCompanyQueryKey(companyId, ...baseKey);\n }\n return baseKey;\n },\n [companyId],\n );\n\n return { companyId, scopeKey } as const;\n}\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useFluidApi } from \"./use-fluid-api\";\nimport { useCompanyScopedQueryKey } from \"./query-keys\";\nimport type { UserMe } from \"../types/rep\";\n\n/**\n * Base query key for current user data.\n * Kept for backwards compatibility — the runtime key used by the hook\n * includes a company prefix via {@link useCompanyScopedQueryKey}.\n */\nexport const CURRENT_USER_QUERY_KEY = [\"fluid\", \"currentUser\"] as const;\n\n/**\n * Hook to fetch the currently authenticated user's full profile.\n * Returns company, country, and other fields from GET /api/me.\n *\n * @example\n * ```tsx\n * function ShopPage() {\n * const { data: user, isLoading } = useCurrentUser();\n * const subdomain = user?.company?.subdomain;\n * const countryIso = user?.country?.iso ?? \"US\";\n * // ...\n * }\n * ```\n */\nexport function useCurrentUser(): UseQueryResult<UserMe> {\n const api = useFluidApi();\n const { scopeKey } = useCompanyScopedQueryKey();\n\n return useQuery({\n queryKey: scopeKey(CURRENT_USER_QUERY_KEY),\n queryFn: () => api.users.me(),\n staleTime: 5 * 60 * 1000,\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,sBACd,WACA,GAAG,SACwC;AAC3C,QAAO;EAAC;EAAW;EAAW,GAAG;EAAQ;;;;;;;;;;;;;;;;;AAkB3C,SAAgB,2BAKd;CACA,MAAM,OAAO,qBAAqB;CAClC,MAAM,YAAY,KAAK,MAAM;CAM7B,MAAM,eAAe,OAAO,MAAM;AAClC,KAAI,KAAK,mBAAmB,aAAa,QAAQ,CAAC,aAAa,SAAS;AACtE,eAAa,UAAU;AACvB,UAAQ,KACN,4LAGD;;AAaH,QAAO;EAAE;EAAW,UAVH,aACe,YAA6C;AACzE,OAAI,aAAa,KACf,QAAO,sBAAsB,WAAW,GAAG,QAAQ;AAErD,UAAO;KAET,CAAC,UAAU,CACZ;EAE6B;;;;;;;;;ACxEhC,MAAa,yBAAyB,CAAC,SAAS,cAAc;;;;;;;;;;;;;;;AAgB9D,SAAgB,iBAAyC;CACvD,MAAM,MAAM,aAAa;CACzB,MAAM,EAAE,aAAa,0BAA0B;AAE/C,QAAO,SAAS;EACd,UAAU,SAAS,uBAAuB;EAC1C,eAAe,IAAI,MAAM,IAAI;EAC7B,WAAW,MAAS;EACrB,CAAC"}
1
+ {"version":3,"file":"use-current-user-BUXtOeFz.mjs","names":[],"sources":["../src/hooks/query-keys.ts","../src/hooks/use-current-user.ts"],"sourcesContent":["/**\n * Company-scoped query key factory for TanStack Query.\n *\n * All portal SDK query keys are prefixed with [\"company\", companyId, ...]\n * so that switching companies naturally invalidates the entire cache scope.\n *\n * The exported `*_QUERY_KEY` constants (e.g. PROFILE_QUERY_KEY) remain as\n * backwards-compatible base keys. The runtime keys used by hooks include the\n * company prefix via {@link createCompanyQueryKey}.\n */\n\nimport { useCallback, useRef } from \"react\";\nimport { useFluidAuthContext } from \"../providers/FluidAuthProvider\";\n\n/**\n * Create a company-scoped query key by prepending [\"company\", companyId].\n *\n * @param companyId - The company ID from the JWT payload\n * @param baseKey - The base query key segments (e.g. [\"fluid\", \"profile\"])\n * @returns A tuple like [\"company\", 42, \"fluid\", \"profile\"]\n *\n * @example\n * ```ts\n * const key = createCompanyQueryKey(42, \"fluid\", \"profile\");\n * // => [\"company\", 42, \"fluid\", \"profile\"]\n * ```\n */\nexport function createCompanyQueryKey(\n companyId: number,\n ...baseKey: readonly string[]\n): readonly [\"company\", number, ...string[]] {\n return [\"company\", companyId, ...baseKey] as const;\n}\n\n/**\n * Hook that returns a `scopeKey` function bound to the current company ID\n * from the auth context. If the user is not authenticated or has no\n * company_id, the base key is returned unscoped (graceful degradation).\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { scopeKey } = useCompanyScopedQueryKey();\n * const queryKey = scopeKey(PROFILE_QUERY_KEY);\n * // => [\"company\", 42, \"fluid\", \"profile\"] (when authenticated)\n * // => [\"fluid\", \"profile\"] (fallback)\n * }\n * ```\n */\nexport function useCompanyScopedQueryKey(): {\n readonly companyId: number | undefined;\n readonly scopeKey: <T extends readonly string[]>(\n baseKey: T,\n ) => readonly (string | number)[];\n} {\n const auth = useFluidAuthContext();\n const companyId = auth.user?.company_id;\n\n // Warn (once per component instance) when an authenticated user has no\n // company_id. This is a security-relevant condition: unscoped keys allow\n // cross-company cache collisions. The warning fires in all environments\n // so that it's visible in production logs if a misconfigured JWT is issued.\n const hasWarnedRef = useRef(false);\n if (auth.isAuthenticated && companyId == null && !hasWarnedRef.current) {\n hasWarnedRef.current = true;\n console.warn(\n \"[portal-sdk] Authenticated user has no company_id in JWT. \" +\n \"Query keys will fall back to unscoped keys, which may cause \" +\n \"cross-company cache collisions. Ensure the JWT includes company_id.\",\n );\n }\n\n const scopeKey = useCallback(\n <T extends readonly string[]>(baseKey: T): readonly (string | number)[] => {\n if (companyId != null) {\n return createCompanyQueryKey(companyId, ...baseKey);\n }\n return baseKey;\n },\n [companyId],\n );\n\n return { companyId, scopeKey } as const;\n}\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useFluidApi } from \"./use-fluid-api\";\nimport { useCompanyScopedQueryKey } from \"./query-keys\";\nimport type { UserMe } from \"../types/rep\";\n\n/**\n * Base query key for current user data.\n * Kept for backwards compatibility — the runtime key used by the hook\n * includes a company prefix via {@link useCompanyScopedQueryKey}.\n */\nexport const CURRENT_USER_QUERY_KEY = [\"fluid\", \"currentUser\"] as const;\n\n/**\n * Hook to fetch the currently authenticated user's full profile.\n * Returns company, country, and other fields from GET /api/me.\n *\n * @example\n * ```tsx\n * function ShopPage() {\n * const { data: user, isLoading } = useCurrentUser();\n * const subdomain = user?.company?.subdomain;\n * const countryIso = user?.country?.iso ?? \"US\";\n * // ...\n * }\n * ```\n */\nexport function useCurrentUser(): UseQueryResult<UserMe> {\n const api = useFluidApi();\n const { scopeKey } = useCompanyScopedQueryKey();\n\n return useQuery({\n queryKey: scopeKey(CURRENT_USER_QUERY_KEY),\n queryFn: () => api.users.me(),\n staleTime: 5 * 60 * 1000,\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,sBACd,WACA,GAAG,SACwC;AAC3C,QAAO;EAAC;EAAW;EAAW,GAAG;EAAQ;;;;;;;;;;;;;;;;;AAkB3C,SAAgB,2BAKd;CACA,MAAM,OAAO,qBAAqB;CAClC,MAAM,YAAY,KAAK,MAAM;CAM7B,MAAM,eAAe,OAAO,MAAM;AAClC,KAAI,KAAK,mBAAmB,aAAa,QAAQ,CAAC,aAAa,SAAS;AACtE,eAAa,UAAU;AACvB,UAAQ,KACN,4LAGD;;AAaH,QAAO;EAAE;EAAW,UAVH,aACe,YAA6C;AACzE,OAAI,aAAa,KACf,QAAO,sBAAsB,WAAW,GAAG,QAAQ;AAErD,UAAO;KAET,CAAC,UAAU,CACZ;EAE6B;;;;;;;;;ACxEhC,MAAa,yBAAyB,CAAC,SAAS,cAAc;;;;;;;;;;;;;;;AAgB9D,SAAgB,iBAAyC;CACvD,MAAM,MAAM,aAAa;CACzB,MAAM,EAAE,aAAa,0BAA0B;AAE/C,QAAO,SAAS;EACd,UAAU,SAAS,uBAAuB;EAC1C,eAAe,IAAI,MAAM,IAAI;EAC7B,WAAW,MAAS;EACrB,CAAC"}
@@ -1,6 +1,6 @@
1
1
  require("./chunk-9hOWP6kD.cjs");
2
- const require_FluidProvider = require("./FluidProvider-CidgidrK.cjs");
3
- const require_use_fluid_api = require("./use-fluid-api-Cc0xHt74.cjs");
2
+ const require_FluidProvider = require("./FluidProvider-B7whI5Fk.cjs");
3
+ const require_use_fluid_api = require("./use-fluid-api-C3T17MND.cjs");
4
4
  let react = require("react");
5
5
  let _tanstack_react_query = require("@tanstack/react-query");
6
6
  //#region src/hooks/query-keys.ts
@@ -122,4 +122,4 @@ Object.defineProperty(exports, "useCurrentUser", {
122
122
  }
123
123
  });
124
124
 
125
- //# sourceMappingURL=use-current-user-C3xp6f2-.cjs.map
125
+ //# sourceMappingURL=use-current-user-C2A379kM.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-current-user-C3xp6f2-.cjs","names":["useFluidAuthContext","useFluidApi"],"sources":["../src/hooks/query-keys.ts","../src/hooks/use-current-user.ts"],"sourcesContent":["/**\n * Company-scoped query key factory for TanStack Query.\n *\n * All portal SDK query keys are prefixed with [\"company\", companyId, ...]\n * so that switching companies naturally invalidates the entire cache scope.\n *\n * The exported `*_QUERY_KEY` constants (e.g. PROFILE_QUERY_KEY) remain as\n * backwards-compatible base keys. The runtime keys used by hooks include the\n * company prefix via {@link createCompanyQueryKey}.\n */\n\nimport { useCallback, useRef } from \"react\";\nimport { useFluidAuthContext } from \"../providers/FluidAuthProvider\";\n\n/**\n * Create a company-scoped query key by prepending [\"company\", companyId].\n *\n * @param companyId - The company ID from the JWT payload\n * @param baseKey - The base query key segments (e.g. [\"fluid\", \"profile\"])\n * @returns A tuple like [\"company\", 42, \"fluid\", \"profile\"]\n *\n * @example\n * ```ts\n * const key = createCompanyQueryKey(42, \"fluid\", \"profile\");\n * // => [\"company\", 42, \"fluid\", \"profile\"]\n * ```\n */\nexport function createCompanyQueryKey(\n companyId: number,\n ...baseKey: readonly string[]\n): readonly [\"company\", number, ...string[]] {\n return [\"company\", companyId, ...baseKey] as const;\n}\n\n/**\n * Hook that returns a `scopeKey` function bound to the current company ID\n * from the auth context. If the user is not authenticated or has no\n * company_id, the base key is returned unscoped (graceful degradation).\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { scopeKey } = useCompanyScopedQueryKey();\n * const queryKey = scopeKey(PROFILE_QUERY_KEY);\n * // => [\"company\", 42, \"fluid\", \"profile\"] (when authenticated)\n * // => [\"fluid\", \"profile\"] (fallback)\n * }\n * ```\n */\nexport function useCompanyScopedQueryKey(): {\n readonly companyId: number | undefined;\n readonly scopeKey: <T extends readonly string[]>(\n baseKey: T,\n ) => readonly (string | number)[];\n} {\n const auth = useFluidAuthContext();\n const companyId = auth.user?.company_id;\n\n // Warn (once per component instance) when an authenticated user has no\n // company_id. This is a security-relevant condition: unscoped keys allow\n // cross-company cache collisions. The warning fires in all environments\n // so that it's visible in production logs if a misconfigured JWT is issued.\n const hasWarnedRef = useRef(false);\n if (auth.isAuthenticated && companyId == null && !hasWarnedRef.current) {\n hasWarnedRef.current = true;\n console.warn(\n \"[portal-sdk] Authenticated user has no company_id in JWT. \" +\n \"Query keys will fall back to unscoped keys, which may cause \" +\n \"cross-company cache collisions. Ensure the JWT includes company_id.\",\n );\n }\n\n const scopeKey = useCallback(\n <T extends readonly string[]>(baseKey: T): readonly (string | number)[] => {\n if (companyId != null) {\n return createCompanyQueryKey(companyId, ...baseKey);\n }\n return baseKey;\n },\n [companyId],\n );\n\n return { companyId, scopeKey } as const;\n}\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useFluidApi } from \"./use-fluid-api\";\nimport { useCompanyScopedQueryKey } from \"./query-keys\";\nimport type { UserMe } from \"../types/rep\";\n\n/**\n * Base query key for current user data.\n * Kept for backwards compatibility — the runtime key used by the hook\n * includes a company prefix via {@link useCompanyScopedQueryKey}.\n */\nexport const CURRENT_USER_QUERY_KEY = [\"fluid\", \"currentUser\"] as const;\n\n/**\n * Hook to fetch the currently authenticated user's full profile.\n * Returns company, country, and other fields from GET /api/me.\n *\n * @example\n * ```tsx\n * function ShopPage() {\n * const { data: user, isLoading } = useCurrentUser();\n * const subdomain = user?.company?.subdomain;\n * const countryIso = user?.country?.iso ?? \"US\";\n * // ...\n * }\n * ```\n */\nexport function useCurrentUser(): UseQueryResult<UserMe> {\n const api = useFluidApi();\n const { scopeKey } = useCompanyScopedQueryKey();\n\n return useQuery({\n queryKey: scopeKey(CURRENT_USER_QUERY_KEY),\n queryFn: () => api.users.me(),\n staleTime: 5 * 60 * 1000,\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,sBACd,WACA,GAAG,SACwC;AAC3C,QAAO;EAAC;EAAW;EAAW,GAAG;EAAQ;;;;;;;;;;;;;;;;;AAkB3C,SAAgB,2BAKd;CACA,MAAM,OAAOA,sBAAAA,qBAAqB;CAClC,MAAM,YAAY,KAAK,MAAM;CAM7B,MAAM,gBAAA,GAAA,MAAA,QAAsB,MAAM;AAClC,KAAI,KAAK,mBAAmB,aAAa,QAAQ,CAAC,aAAa,SAAS;AACtE,eAAa,UAAU;AACvB,UAAQ,KACN,4LAGD;;AAaH,QAAO;EAAE;EAAW,WAAA,GAAA,MAAA,cATY,YAA6C;AACzE,OAAI,aAAa,KACf,QAAO,sBAAsB,WAAW,GAAG,QAAQ;AAErD,UAAO;KAET,CAAC,UAAU,CACZ;EAE6B;;;;;;;;;ACxEhC,MAAa,yBAAyB,CAAC,SAAS,cAAc;;;;;;;;;;;;;;;AAgB9D,SAAgB,iBAAyC;CACvD,MAAM,MAAMC,sBAAAA,aAAa;CACzB,MAAM,EAAE,aAAa,0BAA0B;AAE/C,SAAA,GAAA,sBAAA,UAAgB;EACd,UAAU,SAAS,uBAAuB;EAC1C,eAAe,IAAI,MAAM,IAAI;EAC7B,WAAW,MAAS;EACrB,CAAC"}
1
+ {"version":3,"file":"use-current-user-C2A379kM.cjs","names":["useFluidAuthContext","useFluidApi"],"sources":["../src/hooks/query-keys.ts","../src/hooks/use-current-user.ts"],"sourcesContent":["/**\n * Company-scoped query key factory for TanStack Query.\n *\n * All portal SDK query keys are prefixed with [\"company\", companyId, ...]\n * so that switching companies naturally invalidates the entire cache scope.\n *\n * The exported `*_QUERY_KEY` constants (e.g. PROFILE_QUERY_KEY) remain as\n * backwards-compatible base keys. The runtime keys used by hooks include the\n * company prefix via {@link createCompanyQueryKey}.\n */\n\nimport { useCallback, useRef } from \"react\";\nimport { useFluidAuthContext } from \"../providers/FluidAuthProvider\";\n\n/**\n * Create a company-scoped query key by prepending [\"company\", companyId].\n *\n * @param companyId - The company ID from the JWT payload\n * @param baseKey - The base query key segments (e.g. [\"fluid\", \"profile\"])\n * @returns A tuple like [\"company\", 42, \"fluid\", \"profile\"]\n *\n * @example\n * ```ts\n * const key = createCompanyQueryKey(42, \"fluid\", \"profile\");\n * // => [\"company\", 42, \"fluid\", \"profile\"]\n * ```\n */\nexport function createCompanyQueryKey(\n companyId: number,\n ...baseKey: readonly string[]\n): readonly [\"company\", number, ...string[]] {\n return [\"company\", companyId, ...baseKey] as const;\n}\n\n/**\n * Hook that returns a `scopeKey` function bound to the current company ID\n * from the auth context. If the user is not authenticated or has no\n * company_id, the base key is returned unscoped (graceful degradation).\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { scopeKey } = useCompanyScopedQueryKey();\n * const queryKey = scopeKey(PROFILE_QUERY_KEY);\n * // => [\"company\", 42, \"fluid\", \"profile\"] (when authenticated)\n * // => [\"fluid\", \"profile\"] (fallback)\n * }\n * ```\n */\nexport function useCompanyScopedQueryKey(): {\n readonly companyId: number | undefined;\n readonly scopeKey: <T extends readonly string[]>(\n baseKey: T,\n ) => readonly (string | number)[];\n} {\n const auth = useFluidAuthContext();\n const companyId = auth.user?.company_id;\n\n // Warn (once per component instance) when an authenticated user has no\n // company_id. This is a security-relevant condition: unscoped keys allow\n // cross-company cache collisions. The warning fires in all environments\n // so that it's visible in production logs if a misconfigured JWT is issued.\n const hasWarnedRef = useRef(false);\n if (auth.isAuthenticated && companyId == null && !hasWarnedRef.current) {\n hasWarnedRef.current = true;\n console.warn(\n \"[portal-sdk] Authenticated user has no company_id in JWT. \" +\n \"Query keys will fall back to unscoped keys, which may cause \" +\n \"cross-company cache collisions. Ensure the JWT includes company_id.\",\n );\n }\n\n const scopeKey = useCallback(\n <T extends readonly string[]>(baseKey: T): readonly (string | number)[] => {\n if (companyId != null) {\n return createCompanyQueryKey(companyId, ...baseKey);\n }\n return baseKey;\n },\n [companyId],\n );\n\n return { companyId, scopeKey } as const;\n}\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useFluidApi } from \"./use-fluid-api\";\nimport { useCompanyScopedQueryKey } from \"./query-keys\";\nimport type { UserMe } from \"../types/rep\";\n\n/**\n * Base query key for current user data.\n * Kept for backwards compatibility — the runtime key used by the hook\n * includes a company prefix via {@link useCompanyScopedQueryKey}.\n */\nexport const CURRENT_USER_QUERY_KEY = [\"fluid\", \"currentUser\"] as const;\n\n/**\n * Hook to fetch the currently authenticated user's full profile.\n * Returns company, country, and other fields from GET /api/me.\n *\n * @example\n * ```tsx\n * function ShopPage() {\n * const { data: user, isLoading } = useCurrentUser();\n * const subdomain = user?.company?.subdomain;\n * const countryIso = user?.country?.iso ?? \"US\";\n * // ...\n * }\n * ```\n */\nexport function useCurrentUser(): UseQueryResult<UserMe> {\n const api = useFluidApi();\n const { scopeKey } = useCompanyScopedQueryKey();\n\n return useQuery({\n queryKey: scopeKey(CURRENT_USER_QUERY_KEY),\n queryFn: () => api.users.me(),\n staleTime: 5 * 60 * 1000,\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,sBACd,WACA,GAAG,SACwC;AAC3C,QAAO;EAAC;EAAW;EAAW,GAAG;EAAQ;;;;;;;;;;;;;;;;;AAkB3C,SAAgB,2BAKd;CACA,MAAM,OAAOA,sBAAAA,qBAAqB;CAClC,MAAM,YAAY,KAAK,MAAM;CAM7B,MAAM,gBAAA,GAAA,MAAA,QAAsB,MAAM;AAClC,KAAI,KAAK,mBAAmB,aAAa,QAAQ,CAAC,aAAa,SAAS;AACtE,eAAa,UAAU;AACvB,UAAQ,KACN,4LAGD;;AAaH,QAAO;EAAE;EAAW,WAAA,GAAA,MAAA,cATY,YAA6C;AACzE,OAAI,aAAa,KACf,QAAO,sBAAsB,WAAW,GAAG,QAAQ;AAErD,UAAO;KAET,CAAC,UAAU,CACZ;EAE6B;;;;;;;;;ACxEhC,MAAa,yBAAyB,CAAC,SAAS,cAAc;;;;;;;;;;;;;;;AAgB9D,SAAgB,iBAAyC;CACvD,MAAM,MAAMC,sBAAAA,aAAa;CACzB,MAAM,EAAE,aAAa,0BAA0B;AAE/C,SAAA,GAAA,sBAAA,UAAgB;EACd,UAAU,SAAS,uBAAuB;EAC1C,eAAe,IAAI,MAAM,IAAI;EAC7B,WAAW,MAAS;EACrB,CAAC"}
@@ -1,6 +1,6 @@
1
1
  require("./chunk-9hOWP6kD.cjs");
2
- const require_FluidProvider = require("./FluidProvider-CidgidrK.cjs");
3
- const require_use_account_clients = require("./use-account-clients-CgP9ZZbx.cjs");
2
+ const require_FluidProvider = require("./FluidProvider-B7whI5Fk.cjs");
3
+ const require_use_account_clients = require("./use-account-clients-N3gfibU3.cjs");
4
4
  let _tanstack_react_query = require("@tanstack/react-query");
5
5
  //#region src/account/use-customer-account.ts
6
6
  function useCustomerAccount({ enabled = true } = {}) {
@@ -26,4 +26,4 @@ Object.defineProperty(exports, "useCustomerAccount", {
26
26
  }
27
27
  });
28
28
 
29
- //# sourceMappingURL=use-customer-account-72qR-BtL.cjs.map
29
+ //# sourceMappingURL=use-customer-account-DJxnOr1n.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-customer-account-72qR-BtL.cjs","names":["useFluidAuth","useFluidPayClient"],"sources":["../src/account/use-customer-account.ts"],"sourcesContent":["import { useQuery } from \"@tanstack/react-query\";\nimport { customersApi } from \"@fluid-app/fluid-pay-api-client\";\nimport { useFluidAuth } from \"../hooks/use-fluid-auth\";\nimport { useFluidPayClient } from \"./use-account-clients\";\n\nexport function useCustomerAccount({\n enabled = true,\n}: { enabled?: boolean } = {}) {\n const { token, user } = useFluidAuth();\n const fluidPayClient = useFluidPayClient();\n const jwt = token ?? \"\";\n\n const query = useQuery({\n queryKey: [\"fluidPayAccount\", user?.id],\n queryFn: () => customersApi.fetchCustomerAccount(fluidPayClient, jwt),\n enabled: !!jwt && enabled,\n });\n\n return {\n customerId: query.data?.customer?.id,\n isLoadingCustomer: query.isLoading,\n isCustomerError: query.isError,\n };\n}\n"],"mappings":";;;;;AAKA,SAAgB,mBAAmB,EACjC,UAAU,SACe,EAAE,EAAE;CAC7B,MAAM,EAAE,OAAO,SAASA,4BAAAA,cAAc;CACtC,MAAM,iBAAiBC,4BAAAA,mBAAmB;CAC1C,MAAM,MAAM,SAAS;CAErB,MAAM,SAAA,GAAA,sBAAA,UAAiB;EACrB,UAAU,CAAC,mBAAmB,MAAM,GAAG;EACvC,eAAA,sBAAA,qBAAiD,gBAAgB,IAAI;EACrE,SAAS,CAAC,CAAC,OAAO;EACnB,CAAC;AAEF,QAAO;EACL,YAAY,MAAM,MAAM,UAAU;EAClC,mBAAmB,MAAM;EACzB,iBAAiB,MAAM;EACxB"}
1
+ {"version":3,"file":"use-customer-account-DJxnOr1n.cjs","names":["useFluidAuth","useFluidPayClient"],"sources":["../src/account/use-customer-account.ts"],"sourcesContent":["import { useQuery } from \"@tanstack/react-query\";\nimport { customersApi } from \"@fluid-app/fluid-pay-api-client\";\nimport { useFluidAuth } from \"../hooks/use-fluid-auth\";\nimport { useFluidPayClient } from \"./use-account-clients\";\n\nexport function useCustomerAccount({\n enabled = true,\n}: { enabled?: boolean } = {}) {\n const { token, user } = useFluidAuth();\n const fluidPayClient = useFluidPayClient();\n const jwt = token ?? \"\";\n\n const query = useQuery({\n queryKey: [\"fluidPayAccount\", user?.id],\n queryFn: () => customersApi.fetchCustomerAccount(fluidPayClient, jwt),\n enabled: !!jwt && enabled,\n });\n\n return {\n customerId: query.data?.customer?.id,\n isLoadingCustomer: query.isLoading,\n isCustomerError: query.isError,\n };\n}\n"],"mappings":";;;;;AAKA,SAAgB,mBAAmB,EACjC,UAAU,SACe,EAAE,EAAE;CAC7B,MAAM,EAAE,OAAO,SAASA,4BAAAA,cAAc;CACtC,MAAM,iBAAiBC,4BAAAA,mBAAmB;CAC1C,MAAM,MAAM,SAAS;CAErB,MAAM,SAAA,GAAA,sBAAA,UAAiB;EACrB,UAAU,CAAC,mBAAmB,MAAM,GAAG;EACvC,eAAA,sBAAA,qBAAiD,gBAAgB,IAAI;EACrE,SAAS,CAAC,CAAC,OAAO;EACnB,CAAC;AAEF,QAAO;EACL,YAAY,MAAM,MAAM,UAAU;EAClC,mBAAmB,MAAM;EACzB,iBAAiB,MAAM;EACxB"}
@@ -1,5 +1,5 @@
1
- import { _t as fetchCustomerAccount } from "./FluidProvider-6ARIhCTq.mjs";
2
- import { n as useFluidPayClient, o as useFluidAuth } from "./use-account-clients-CDAazmHw.mjs";
1
+ import { _t as fetchCustomerAccount } from "./FluidProvider-C4OAgBdt.mjs";
2
+ import { n as useFluidPayClient, o as useFluidAuth } from "./use-account-clients-Bqwc4jT0.mjs";
3
3
  import { useQuery } from "@tanstack/react-query";
4
4
  //#region src/account/use-customer-account.ts
5
5
  function useCustomerAccount({ enabled = true } = {}) {
@@ -20,4 +20,4 @@ function useCustomerAccount({ enabled = true } = {}) {
20
20
  //#endregion
21
21
  export { useCustomerAccount as t };
22
22
 
23
- //# sourceMappingURL=use-customer-account-Dfyhs3LY.mjs.map
23
+ //# sourceMappingURL=use-customer-account-DVQzpWxo.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-customer-account-Dfyhs3LY.mjs","names":["customersApi.fetchCustomerAccount"],"sources":["../src/account/use-customer-account.ts"],"sourcesContent":["import { useQuery } from \"@tanstack/react-query\";\nimport { customersApi } from \"@fluid-app/fluid-pay-api-client\";\nimport { useFluidAuth } from \"../hooks/use-fluid-auth\";\nimport { useFluidPayClient } from \"./use-account-clients\";\n\nexport function useCustomerAccount({\n enabled = true,\n}: { enabled?: boolean } = {}) {\n const { token, user } = useFluidAuth();\n const fluidPayClient = useFluidPayClient();\n const jwt = token ?? \"\";\n\n const query = useQuery({\n queryKey: [\"fluidPayAccount\", user?.id],\n queryFn: () => customersApi.fetchCustomerAccount(fluidPayClient, jwt),\n enabled: !!jwt && enabled,\n });\n\n return {\n customerId: query.data?.customer?.id,\n isLoadingCustomer: query.isLoading,\n isCustomerError: query.isError,\n };\n}\n"],"mappings":";;;;AAKA,SAAgB,mBAAmB,EACjC,UAAU,SACe,EAAE,EAAE;CAC7B,MAAM,EAAE,OAAO,SAAS,cAAc;CACtC,MAAM,iBAAiB,mBAAmB;CAC1C,MAAM,MAAM,SAAS;CAErB,MAAM,QAAQ,SAAS;EACrB,UAAU,CAAC,mBAAmB,MAAM,GAAG;EACvC,eAAeA,qBAAkC,gBAAgB,IAAI;EACrE,SAAS,CAAC,CAAC,OAAO;EACnB,CAAC;AAEF,QAAO;EACL,YAAY,MAAM,MAAM,UAAU;EAClC,mBAAmB,MAAM;EACzB,iBAAiB,MAAM;EACxB"}
1
+ {"version":3,"file":"use-customer-account-DVQzpWxo.mjs","names":["customersApi.fetchCustomerAccount"],"sources":["../src/account/use-customer-account.ts"],"sourcesContent":["import { useQuery } from \"@tanstack/react-query\";\nimport { customersApi } from \"@fluid-app/fluid-pay-api-client\";\nimport { useFluidAuth } from \"../hooks/use-fluid-auth\";\nimport { useFluidPayClient } from \"./use-account-clients\";\n\nexport function useCustomerAccount({\n enabled = true,\n}: { enabled?: boolean } = {}) {\n const { token, user } = useFluidAuth();\n const fluidPayClient = useFluidPayClient();\n const jwt = token ?? \"\";\n\n const query = useQuery({\n queryKey: [\"fluidPayAccount\", user?.id],\n queryFn: () => customersApi.fetchCustomerAccount(fluidPayClient, jwt),\n enabled: !!jwt && enabled,\n });\n\n return {\n customerId: query.data?.customer?.id,\n isLoadingCustomer: query.isLoading,\n isCustomerError: query.isError,\n };\n}\n"],"mappings":";;;;AAKA,SAAgB,mBAAmB,EACjC,UAAU,SACe,EAAE,EAAE;CAC7B,MAAM,EAAE,OAAO,SAAS,cAAc;CACtC,MAAM,iBAAiB,mBAAmB;CAC1C,MAAM,MAAM,SAAS;CAErB,MAAM,QAAQ,SAAS;EACrB,UAAU,CAAC,mBAAmB,MAAM,GAAG;EACvC,eAAeA,qBAAkC,gBAAgB,IAAI;EACrE,SAAS,CAAC,CAAC,OAAO;EACnB,CAAC;AAEF,QAAO;EACL,YAAY,MAAM,MAAM,UAAU;EAClC,mBAAmB,MAAM;EACzB,iBAAiB,MAAM;EACxB"}
@@ -1,4 +1,4 @@
1
- import { n as useFluidContext } from "./FluidProvider-6ARIhCTq.mjs";
1
+ import { n as useFluidContext } from "./FluidProvider-C4OAgBdt.mjs";
2
2
  //#region src/hooks/use-fluid-api.ts
3
3
  /**
4
4
  * Hook to access the Fluid API client
@@ -24,4 +24,4 @@ function useFluidApi() {
24
24
  //#endregion
25
25
  export { useFluidApi as t };
26
26
 
27
- //# sourceMappingURL=use-fluid-api-C53ZoBpG.mjs.map
27
+ //# sourceMappingURL=use-fluid-api-BwYwsyDl.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-fluid-api-C53ZoBpG.mjs","names":[],"sources":["../src/hooks/use-fluid-api.ts"],"sourcesContent":["import { useFluidContext } from \"../providers/FluidProvider\";\nimport type { FluidClient } from \"../client/fluid-client\";\n\n/**\n * Hook to access the Fluid API client\n *\n * @example\n * ```tsx\n * function ProductList() {\n * const api = useFluidApi();\n *\n * const { data: products } = useQuery({\n * queryKey: [\"products\"],\n * queryFn: () => api.products.list(),\n * });\n *\n * return <ul>{products?.map(p => <li key={p.id}>{p.name}</li>)}</ul>;\n * }\n * ```\n */\nexport function useFluidApi(): FluidClient {\n const { client } = useFluidContext();\n return client;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,cAA2B;CACzC,MAAM,EAAE,WAAW,iBAAiB;AACpC,QAAO"}
1
+ {"version":3,"file":"use-fluid-api-BwYwsyDl.mjs","names":[],"sources":["../src/hooks/use-fluid-api.ts"],"sourcesContent":["import { useFluidContext } from \"../providers/FluidProvider\";\nimport type { FluidClient } from \"../client/fluid-client\";\n\n/**\n * Hook to access the Fluid API client\n *\n * @example\n * ```tsx\n * function ProductList() {\n * const api = useFluidApi();\n *\n * const { data: products } = useQuery({\n * queryKey: [\"products\"],\n * queryFn: () => api.products.list(),\n * });\n *\n * return <ul>{products?.map(p => <li key={p.id}>{p.name}</li>)}</ul>;\n * }\n * ```\n */\nexport function useFluidApi(): FluidClient {\n const { client } = useFluidContext();\n return client;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,cAA2B;CACzC,MAAM,EAAE,WAAW,iBAAiB;AACpC,QAAO"}
@@ -1,4 +1,4 @@
1
- const require_FluidProvider = require("./FluidProvider-CidgidrK.cjs");
1
+ const require_FluidProvider = require("./FluidProvider-B7whI5Fk.cjs");
2
2
  //#region src/hooks/use-fluid-api.ts
3
3
  /**
4
4
  * Hook to access the Fluid API client
@@ -29,4 +29,4 @@ Object.defineProperty(exports, "useFluidApi", {
29
29
  }
30
30
  });
31
31
 
32
- //# sourceMappingURL=use-fluid-api-Cc0xHt74.cjs.map
32
+ //# sourceMappingURL=use-fluid-api-C3T17MND.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-fluid-api-Cc0xHt74.cjs","names":["useFluidContext"],"sources":["../src/hooks/use-fluid-api.ts"],"sourcesContent":["import { useFluidContext } from \"../providers/FluidProvider\";\nimport type { FluidClient } from \"../client/fluid-client\";\n\n/**\n * Hook to access the Fluid API client\n *\n * @example\n * ```tsx\n * function ProductList() {\n * const api = useFluidApi();\n *\n * const { data: products } = useQuery({\n * queryKey: [\"products\"],\n * queryFn: () => api.products.list(),\n * });\n *\n * return <ul>{products?.map(p => <li key={p.id}>{p.name}</li>)}</ul>;\n * }\n * ```\n */\nexport function useFluidApi(): FluidClient {\n const { client } = useFluidContext();\n return client;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,cAA2B;CACzC,MAAM,EAAE,WAAWA,sBAAAA,iBAAiB;AACpC,QAAO"}
1
+ {"version":3,"file":"use-fluid-api-C3T17MND.cjs","names":["useFluidContext"],"sources":["../src/hooks/use-fluid-api.ts"],"sourcesContent":["import { useFluidContext } from \"../providers/FluidProvider\";\nimport type { FluidClient } from \"../client/fluid-client\";\n\n/**\n * Hook to access the Fluid API client\n *\n * @example\n * ```tsx\n * function ProductList() {\n * const api = useFluidApi();\n *\n * const { data: products } = useQuery({\n * queryKey: [\"products\"],\n * queryFn: () => api.products.list(),\n * });\n *\n * return <ul>{products?.map(p => <li key={p.id}>{p.name}</li>)}</ul>;\n * }\n * ```\n */\nexport function useFluidApi(): FluidClient {\n const { client } = useFluidContext();\n return client;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,cAA2B;CACzC,MAAM,EAAE,WAAWA,sBAAAA,iBAAiB;AACpC,QAAO"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluid-app/portal-sdk",
3
- "version": "0.1.78",
3
+ "version": "0.1.80",
4
4
  "description": "SDK for building custom Fluid portals",
5
5
  "files": [
6
6
  "dist",
@@ -69,39 +69,39 @@
69
69
  "@fluid-app/auth": "0.1.0",
70
70
  "@fluid-app/company-switcher-core": "0.1.0",
71
71
  "@fluid-app/cart-ui": "0.1.12",
72
+ "@fluid-app/contacts-ui": "0.1.0",
72
73
  "@fluid-app/company-switcher-ui": "0.1.0",
73
74
  "@fluid-app/file-picker-api-client": "0.1.0",
74
- "@fluid-app/contacts-ui": "0.1.0",
75
75
  "@fluid-app/fluid-pay-api-client": "0.1.0",
76
76
  "@fluid-app/messaging-api-client": "0.1.0",
77
- "@fluid-app/messaging-core": "0.1.0",
78
77
  "@fluid-app/fluidos-api-client": "0.1.0",
79
- "@fluid-app/messaging-ui": "0.1.0",
78
+ "@fluid-app/messaging-core": "0.1.0",
80
79
  "@fluid-app/mysite-ui": "0.1.0",
81
- "@fluid-app/orders-api-client": "0.1.0",
80
+ "@fluid-app/messaging-ui": "0.1.0",
82
81
  "@fluid-app/orders-core": "0.1.0",
83
82
  "@fluid-app/orders-ui": "0.1.0",
83
+ "@fluid-app/orders-api-client": "0.1.0",
84
84
  "@fluid-app/portal-app-download-ui": "0.1.0",
85
- "@fluid-app/portal-core": "0.1.23",
86
85
  "@fluid-app/permissions": "0.1.0",
87
- "@fluid-app/portal-pro-upgrade-ui": "0.1.0",
88
86
  "@fluid-app/portal-preview": "0.1.0",
87
+ "@fluid-app/portal-core": "0.1.23",
88
+ "@fluid-app/portal-pro-upgrade-ui": "0.1.0",
89
89
  "@fluid-app/portal-react": "0.1.0",
90
90
  "@fluid-app/portal-widgets": "0.1.22",
91
- "@fluid-app/products-core": "0.1.0",
91
+ "@fluid-app/products-api-client": "0.1.0",
92
92
  "@fluid-app/profile-ui": "0.1.0",
93
+ "@fluid-app/products-core": "0.1.0",
94
+ "@fluid-app/profile-core": "0.1.0",
93
95
  "@fluid-app/shareables-api-client": "0.1.0",
94
- "@fluid-app/shareables-core": "0.1.0",
95
96
  "@fluid-app/shareables-ui": "0.1.0",
96
97
  "@fluid-app/query-persister": "0.1.0",
97
- "@fluid-app/profile-core": "0.1.0",
98
- "@fluid-app/products-api-client": "0.1.0",
99
- "@fluid-app/subscriptions-core": "0.1.0",
100
98
  "@fluid-app/shop-ui": "0.1.0",
99
+ "@fluid-app/shareables-core": "0.1.0",
100
+ "@fluid-app/subscriptions-api-client": "0.1.0",
101
+ "@fluid-app/subscriptions-core": "0.1.0",
101
102
  "@fluid-app/subscriptions-ui": "0.1.0",
102
- "@fluid-app/ui-primitives": "0.1.13",
103
103
  "@fluid-app/typescript-config": "0.0.0",
104
- "@fluid-app/subscriptions-api-client": "0.1.0",
104
+ "@fluid-app/ui-primitives": "0.1.13",
105
105
  "@fluid-app/user-contacts-api-client": "0.1.0",
106
106
  "@fluid-app/user-notes-api-client": "0.1.0",
107
107
  "@fluid-app/user-tasks-api-client": "0.1.0"
@@ -1 +0,0 @@
1
- {"version":3,"file":"CalendarWidget-Bj0prW4s.cjs","names":["useDataSourceConfig","useWidgetPreviewContext","borderWidthClasses","borderColorClasses","ErrorState","ChevronLeft","ChevronRight","ChevronsDown","ChevronsUp","getFontSizeField","getColorField","getPaddingField","getBorderRadiusField","getBorderWidthField","getBorderColorField"],"sources":["../../widgets/src/hooks/use-calendar-events.preview.ts","../../widgets/src/hooks/use-calendar-events.ts","../../widgets/src/widgets/CalendarWidget.tsx"],"sourcesContent":["import type { CalendarEvent } from \"./use-calendar-events.types\";\n\nconst today = new Date();\nconst inTwoDays = new Date(today);\ninTwoDays.setDate(inTwoDays.getDate() + 2);\n\nfunction toISO(date: Date, hours: number, minutes = 0): string {\n const d = new Date(date);\n d.setHours(hours, minutes, 0, 0);\n return d.toISOString();\n}\n\nfunction toDateString(date: Date): string {\n return date.toISOString().split(\"T\")[0]!;\n}\n\nexport const PREVIEW_DATA: CalendarEvent[] = [\n {\n id: 1,\n title: \"Team Strategy Call\",\n start: toISO(today, 9, 0),\n end: toISO(today, 10, 0),\n status: \"active\",\n color: \"#4f46e5\",\n },\n {\n id: 2,\n title: \"Product Launch Webinar\",\n start: toISO(today, 14, 0),\n end: toISO(today, 15, 30),\n status: \"active\",\n color: \"#0891b2\",\n venue: \"Zoom\",\n },\n {\n id: 3,\n title: \"Annual Leadership Summit\",\n start: `${toDateString(inTwoDays)}T00:00:00.000Z`,\n end: `${toDateString(inTwoDays)}T23:59:59.000Z`,\n status: \"active\",\n color: \"#059669\",\n isAllDay: true,\n venue: \"Convention Center\",\n },\n];\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useDataSourceConfig } from \"@fluid-app/portal-react/data-sources/context\";\nimport { useWidgetPreviewContext } from \"@fluid-app/portal-react/data-sources/preview-context\";\nimport { PREVIEW_DATA } from \"./use-calendar-events.preview\";\n\nimport type { CalendarEvent } from \"./use-calendar-events.types\";\n\nexport type { CalendarEvent } from \"./use-calendar-events.types\";\n\nexport function useCalendarEvents(): UseQueryResult<CalendarEvent[], Error> {\n const { baseUrl, getApiHeaders } = useDataSourceConfig();\n const { isPreview } = useWidgetPreviewContext();\n\n return useQuery({\n queryKey: [\n \"portal-widget-use\",\n \"calendar-events\",\n isPreview ? \"preview\" : baseUrl,\n ] as const,\n queryFn: async ({ signal }): Promise<CalendarEvent[]> => {\n const url = baseUrl\n ? `${baseUrl}/events.json?event_timeline=upcoming`\n : \"/events.json?event_timeline=upcoming\";\n const response = await fetch(url, {\n headers: {\n \"content-type\": \"application/json\",\n ...getApiHeaders?.(),\n },\n signal,\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch calendar events: ${response.status}`);\n }\n\n return response.json();\n },\n enabled: !isPreview,\n ...(isPreview && { placeholderData: PREVIEW_DATA }),\n });\n}\n","import { useState, useMemo, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getBorderWidthField,\n getBorderColorField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n borderWidthClasses,\n borderColorClasses,\n} from \"../core/fields\";\nimport {\n useCalendarEvents,\n type CalendarEvent,\n} from \"../hooks/use-calendar-events\";\nimport { ErrorState } from \"../components/error-state\";\nimport {\n ChevronLeft,\n ChevronRight,\n ChevronsDown,\n ChevronsUp,\n} from \"lucide-react\";\n\n// Utility to get days in a month\nconst getDaysInMonth = (year: number, month: number) => {\n return new Date(year, month + 1, 0).getDate();\n};\n\n// Utility to get the first day of month (0 = Sunday, 1 = Monday, etc.)\nconst getFirstDayOfMonth = (year: number, month: number) => {\n return new Date(year, month, 1).getDay();\n};\n\n// Generate calendar grid for a month\nconst generateMonthGrid = (year: number, month: number) => {\n const daysInMonth = getDaysInMonth(year, month);\n const firstDay = getFirstDayOfMonth(year, month);\n const today = new Date();\n\n const days: Array<{\n date: Date | null;\n isToday: boolean;\n isCurrentMonth: boolean;\n }> = [];\n\n // Add empty slots for days before the 1st\n for (let i = 0; i < firstDay; i++) {\n days.push({ date: null, isToday: false, isCurrentMonth: false });\n }\n\n // Add days of the month\n for (let day = 1; day <= daysInMonth; day++) {\n const date = new Date(year, month, day);\n const isToday =\n date.getDate() === today.getDate() &&\n date.getMonth() === today.getMonth() &&\n date.getFullYear() === today.getFullYear();\n days.push({ date, isToday, isCurrentMonth: true });\n }\n\n return days;\n};\n\n// Generate week grid for current week\nconst generateWeekGrid = () => {\n const today = new Date();\n const currentDay = today.getDay();\n const days: Array<{\n date: Date;\n isToday: boolean;\n }> = [];\n\n for (let i = 0; i < 7; i++) {\n const date = new Date(today);\n date.setDate(today.getDate() - currentDay + i);\n days.push({\n date,\n isToday: date.toDateString() === today.toDateString(),\n });\n }\n\n return days;\n};\n\n// Get events for a specific date\nconst getEventsForDate = (date: Date, events: CalendarEvent[]) => {\n const dayStart = new Date(date);\n dayStart.setHours(0, 0, 0, 0);\n const dayEnd = new Date(date);\n dayEnd.setHours(23, 59, 59, 999);\n\n return events.filter((event) => {\n const eventStart = new Date(event.start);\n const eventEnd = new Date(event.end);\n return eventStart <= dayEnd && eventEnd >= dayStart;\n });\n};\n\n// Check if a date has events\nconst hasEventsOnDate = (date: Date | null, events: CalendarEvent[]) => {\n if (!date) return false;\n return getEventsForDate(date, events).length > 0;\n};\n\n// Event item component\nconst EventItem = ({\n title,\n start,\n end,\n color,\n isAllDay,\n accentColor,\n}: CalendarEvent & { accentColor?: string }) => {\n const startTime = new Date(start).toLocaleTimeString(\"en-US\", {\n hour: \"numeric\",\n minute: \"2-digit\",\n });\n const endTime = new Date(end).toLocaleTimeString(\"en-US\", {\n hour: \"numeric\",\n minute: \"2-digit\",\n });\n\n return (\n <div className=\"flex gap-x-2\">\n <div\n className=\"w-0.5 shrink-0 rounded-full\"\n style={{ backgroundColor: color || accentColor }}\n />\n <div className=\"min-w-0 flex-1\">\n <div className=\"truncate text-sm font-medium\">{title}</div>\n <div className=\"text-xs opacity-60\">\n {isAllDay ? \"All day\" : `${startTime} - ${endTime}`}\n </div>\n </div>\n </div>\n );\n};\n\nconst dayNames = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"];\n\ntype DayButtonProps = {\n date: Date;\n isToday: boolean;\n isSelected: boolean;\n hasEvents: boolean;\n accentColor: string;\n onClick: () => void;\n extraClassName?: string;\n};\n\nfunction DayButton({\n date,\n isToday,\n isSelected,\n hasEvents,\n accentColor,\n onClick,\n extraClassName = \"\",\n}: DayButtonProps) {\n return (\n <button\n onClick={onClick}\n className={`relative flex aspect-square items-center justify-center rounded-full text-sm transition-colors ${\n isSelected\n ? `bg-${accentColor} text-${accentColor}-foreground`\n : isToday\n ? `bg-${accentColor}/30 text-${accentColor}-foreground hover:bg-${accentColor}/50`\n : `hover:bg-${accentColor}/50 hover:text-${accentColor}-foreground`\n } ${extraClassName}`}\n >\n {date.getDate()}\n {hasEvents && (\n <div\n className={`absolute bottom-1 h-1 w-1 rounded-full bg-${accentColor}`}\n />\n )}\n </button>\n );\n}\n\ntype CalendarWidgetProps = ComponentProps<\"div\"> & {\n // Title\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n // Styling\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n};\n\nexport function CalendarWidget({\n // Title defaults\n titleEnabled = true,\n titleText = \"Calendar\",\n titleFontSize = \"xl\",\n titleColor = \"foreground\",\n\n // Styling defaults\n background = {\n type: \"solid\",\n color: \"background\",\n },\n textColor = \"foreground\",\n accentColor = \"primary\",\n padding = 4,\n borderRadius = \"md\",\n borderWidth = \"none\",\n borderColor = \"muted\",\n\n className,\n ...props\n}: CalendarWidgetProps): React.JSX.Element {\n const backgroundColor = background.color || \"background\";\n const backgroundImage =\n (background.resource?.image_url || background.resource?.imageUrl) &&\n background.type === \"image\"\n ? `url(${background.resource.image_url || background.resource.imageUrl})`\n : \"none\";\n const today = new Date();\n const [currentMonth, setCurrentMonth] = useState(today.getMonth());\n const [currentYear, setCurrentYear] = useState(today.getFullYear());\n const [isCollapsed, setIsCollapsed] = useState(false);\n const [selectedDate, setSelectedDate] = useState<Date | null>(today);\n\n const { data: events = [], isLoading, isError } = useCalendarEvents();\n\n // Generate calendar grids\n const monthGrid = useMemo(\n () => generateMonthGrid(currentYear, currentMonth),\n [currentYear, currentMonth],\n );\n const weekGrid = useMemo(() => generateWeekGrid(), []);\n\n // Get events for selected date\n const selectedDateEvents = useMemo(() => {\n if (!selectedDate) return [];\n return getEventsForDate(selectedDate, events);\n }, [selectedDate, events]);\n\n // Navigation handlers\n const goToPrevMonth = () => {\n if (currentMonth === 0) {\n setCurrentMonth(11);\n setCurrentYear(currentYear - 1);\n } else {\n setCurrentMonth(currentMonth - 1);\n }\n };\n\n const goToNextMonth = () => {\n if (currentMonth === 11) {\n setCurrentMonth(0);\n setCurrentYear(currentYear + 1);\n } else {\n setCurrentMonth(currentMonth + 1);\n }\n };\n\n const monthYearLabel = new Date(currentYear, currentMonth).toLocaleString(\n \"en-US\",\n {\n month: \"long\",\n year: \"numeric\",\n },\n );\n\n return (\n <div\n className={`@container overflow-hidden rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} bg-${backgroundColor} text-${textColor} ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n {/* Title */}\n {titleEnabled && titleText && (\n <div className={`p-${padding} pb-0`}>\n <h2\n className={`text-${titleFontSize} font-header font-bold text-${titleColor}`}\n >\n {titleText}\n </h2>\n </div>\n )}\n\n {/* Loading state */}\n {isLoading ? (\n <div\n className={`flex min-h-[300px] items-center justify-center p-${padding}`}\n >\n <div className=\"h-8 w-8 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n </div>\n ) : isError ? (\n /* Error state */\n <ErrorState />\n ) : (\n <div className={`p-${padding}`}>\n {/* Desktop: Side by side layout */}\n <div className=\"@md:flex @md:gap-6\">\n {/* Calendar Section */}\n <div className=\"@md:flex-none\">\n {/* Month/Year Header with Navigation */}\n <div className=\"mb-4 flex items-center justify-between\">\n <button\n onClick={goToPrevMonth}\n className=\"hover:bg-foreground/10 rounded-full p-1\"\n aria-label=\"Previous month\"\n >\n <ChevronLeft className=\"size-4\" />\n </button>\n\n <span className=\"text-base font-semibold\">\n {monthYearLabel}\n </span>\n\n <button\n onClick={goToNextMonth}\n className=\"hover:bg-foreground/10 rounded-full p-1\"\n aria-label=\"Next month\"\n >\n <ChevronRight className=\"size-4\" />\n </button>\n </div>\n\n {/* Day Headers */}\n <div className=\"mb-2 grid grid-cols-7 gap-1 text-center\">\n {dayNames.map((day, idx) => (\n <div\n key={idx}\n className=\"text-xs font-medium uppercase opacity-60\"\n >\n {day}\n </div>\n ))}\n </div>\n\n {/* Calendar Grid - Week view on mobile when collapsed */}\n {isCollapsed && (\n <div className=\"grid grid-cols-7 gap-1 @md:hidden\">\n {weekGrid.map(({ date, isToday }, idx) => (\n <DayButton\n key={idx}\n date={date}\n isToday={isToday}\n isSelected={\n selectedDate?.toDateString() === date.toDateString()\n }\n hasEvents={hasEventsOnDate(date, events)}\n accentColor={accentColor}\n onClick={() => setSelectedDate(date)}\n />\n ))}\n </div>\n )}\n\n {/* Month view (always on desktop, when not collapsed on mobile) */}\n <div\n className={`grid grid-cols-7 gap-1 ${isCollapsed ? \"hidden @md:grid\" : \"grid\"}`}\n >\n {monthGrid.map((day, idx) => {\n if (!day.date) {\n return <div key={idx} className=\"aspect-square\" />;\n }\n\n return (\n <DayButton\n key={idx}\n date={day.date}\n isToday={day.isToday}\n isSelected={\n selectedDate?.toDateString() === day.date.toDateString()\n }\n hasEvents={hasEventsOnDate(day.date, events)}\n accentColor={accentColor}\n onClick={() => setSelectedDate(day.date)}\n extraClassName=\"p-2 @md:m-3\"\n />\n );\n })}\n </div>\n\n {/* Mobile collapse toggle */}\n <button\n onClick={() => setIsCollapsed(!isCollapsed)}\n className={`ml-2 flex w-full items-center justify-center gap-3 rounded-full p-1 text-${textColor}/50 @md:hidden`}\n aria-label={\n isCollapsed ? \"Expand calendar\" : \"Collapse calendar\"\n }\n >\n <div className={`h-1 w-1/2 bg-${textColor}/50`} />\n {isCollapsed ? (\n <ChevronsDown className=\"size-4\" />\n ) : (\n <ChevronsUp className=\"size-4\" />\n )}\n <div className={`h-1 w-1/2 bg-${textColor}/50`} />\n </button>\n </div>\n\n {/* Events Panel */}\n <div className=\"border-muted mt-4 pt-4 @md:mt-0 @md:w-56 @md:border-l @md:pt-0 @md:pl-6\">\n <div className=\"mb-2 text-sm font-medium opacity-60\">\n {selectedDate\n ? selectedDate.toLocaleDateString(\"en-US\", {\n weekday: \"long\",\n month: \"short\",\n day: \"numeric\",\n })\n : \"Select a date\"}\n </div>\n\n {selectedDateEvents.length > 0 ? (\n <div className=\"flex flex-col gap-3\">\n {selectedDateEvents.map((event, idx) => (\n <EventItem\n key={`${event.id}-${idx}`}\n {...event}\n accentColor={`var(--${accentColor})`}\n />\n ))}\n </div>\n ) : (\n <div className=\"text-sm opacity-50\">No events</div>\n )}\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const calendarWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"CalendarWidget\",\n displayName: \"Calendar Widget\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [\n // Styling Tab - Title Group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed above the calendar\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Title text displayed above the calendar\",\n defaultValue: \"Calendar\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n key: \"titleFontSize\",\n label: \"Title Font Size\",\n description: \"Font size for the widget title\",\n defaultValue: \"xl\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n\n // Styling Tab - Design Group\n {\n type: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background for the calendar container\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for calendar content\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"accentColor\",\n label: \"Accent Color\",\n description: \"Color used for today highlight and event indicators\",\n defaultValue: \"primary\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the calendar container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the calendar container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the widget\",\n defaultValue: \"none\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the widget\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"CalendarWidget-DDFVe7-h.mjs","names":[],"sources":["../../widgets/src/hooks/use-calendar-events.preview.ts","../../widgets/src/hooks/use-calendar-events.ts","../../widgets/src/widgets/CalendarWidget.tsx"],"sourcesContent":["import type { CalendarEvent } from \"./use-calendar-events.types\";\n\nconst today = new Date();\nconst inTwoDays = new Date(today);\ninTwoDays.setDate(inTwoDays.getDate() + 2);\n\nfunction toISO(date: Date, hours: number, minutes = 0): string {\n const d = new Date(date);\n d.setHours(hours, minutes, 0, 0);\n return d.toISOString();\n}\n\nfunction toDateString(date: Date): string {\n return date.toISOString().split(\"T\")[0]!;\n}\n\nexport const PREVIEW_DATA: CalendarEvent[] = [\n {\n id: 1,\n title: \"Team Strategy Call\",\n start: toISO(today, 9, 0),\n end: toISO(today, 10, 0),\n status: \"active\",\n color: \"#4f46e5\",\n },\n {\n id: 2,\n title: \"Product Launch Webinar\",\n start: toISO(today, 14, 0),\n end: toISO(today, 15, 30),\n status: \"active\",\n color: \"#0891b2\",\n venue: \"Zoom\",\n },\n {\n id: 3,\n title: \"Annual Leadership Summit\",\n start: `${toDateString(inTwoDays)}T00:00:00.000Z`,\n end: `${toDateString(inTwoDays)}T23:59:59.000Z`,\n status: \"active\",\n color: \"#059669\",\n isAllDay: true,\n venue: \"Convention Center\",\n },\n];\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useDataSourceConfig } from \"@fluid-app/portal-react/data-sources/context\";\nimport { useWidgetPreviewContext } from \"@fluid-app/portal-react/data-sources/preview-context\";\nimport { PREVIEW_DATA } from \"./use-calendar-events.preview\";\n\nimport type { CalendarEvent } from \"./use-calendar-events.types\";\n\nexport type { CalendarEvent } from \"./use-calendar-events.types\";\n\nexport function useCalendarEvents(): UseQueryResult<CalendarEvent[], Error> {\n const { baseUrl, getApiHeaders } = useDataSourceConfig();\n const { isPreview } = useWidgetPreviewContext();\n\n return useQuery({\n queryKey: [\n \"portal-widget-use\",\n \"calendar-events\",\n isPreview ? \"preview\" : baseUrl,\n ] as const,\n queryFn: async ({ signal }): Promise<CalendarEvent[]> => {\n const url = baseUrl\n ? `${baseUrl}/events.json?event_timeline=upcoming`\n : \"/events.json?event_timeline=upcoming\";\n const response = await fetch(url, {\n headers: {\n \"content-type\": \"application/json\",\n ...getApiHeaders?.(),\n },\n signal,\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch calendar events: ${response.status}`);\n }\n\n return response.json();\n },\n enabled: !isPreview,\n ...(isPreview && { placeholderData: PREVIEW_DATA }),\n });\n}\n","import { useState, useMemo, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getBorderWidthField,\n getBorderColorField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n borderWidthClasses,\n borderColorClasses,\n} from \"../core/fields\";\nimport {\n useCalendarEvents,\n type CalendarEvent,\n} from \"../hooks/use-calendar-events\";\nimport { ErrorState } from \"../components/error-state\";\nimport {\n ChevronLeft,\n ChevronRight,\n ChevronsDown,\n ChevronsUp,\n} from \"lucide-react\";\n\n// Utility to get days in a month\nconst getDaysInMonth = (year: number, month: number) => {\n return new Date(year, month + 1, 0).getDate();\n};\n\n// Utility to get the first day of month (0 = Sunday, 1 = Monday, etc.)\nconst getFirstDayOfMonth = (year: number, month: number) => {\n return new Date(year, month, 1).getDay();\n};\n\n// Generate calendar grid for a month\nconst generateMonthGrid = (year: number, month: number) => {\n const daysInMonth = getDaysInMonth(year, month);\n const firstDay = getFirstDayOfMonth(year, month);\n const today = new Date();\n\n const days: Array<{\n date: Date | null;\n isToday: boolean;\n isCurrentMonth: boolean;\n }> = [];\n\n // Add empty slots for days before the 1st\n for (let i = 0; i < firstDay; i++) {\n days.push({ date: null, isToday: false, isCurrentMonth: false });\n }\n\n // Add days of the month\n for (let day = 1; day <= daysInMonth; day++) {\n const date = new Date(year, month, day);\n const isToday =\n date.getDate() === today.getDate() &&\n date.getMonth() === today.getMonth() &&\n date.getFullYear() === today.getFullYear();\n days.push({ date, isToday, isCurrentMonth: true });\n }\n\n return days;\n};\n\n// Generate week grid for current week\nconst generateWeekGrid = () => {\n const today = new Date();\n const currentDay = today.getDay();\n const days: Array<{\n date: Date;\n isToday: boolean;\n }> = [];\n\n for (let i = 0; i < 7; i++) {\n const date = new Date(today);\n date.setDate(today.getDate() - currentDay + i);\n days.push({\n date,\n isToday: date.toDateString() === today.toDateString(),\n });\n }\n\n return days;\n};\n\n// Get events for a specific date\nconst getEventsForDate = (date: Date, events: CalendarEvent[]) => {\n const dayStart = new Date(date);\n dayStart.setHours(0, 0, 0, 0);\n const dayEnd = new Date(date);\n dayEnd.setHours(23, 59, 59, 999);\n\n return events.filter((event) => {\n const eventStart = new Date(event.start);\n const eventEnd = new Date(event.end);\n return eventStart <= dayEnd && eventEnd >= dayStart;\n });\n};\n\n// Check if a date has events\nconst hasEventsOnDate = (date: Date | null, events: CalendarEvent[]) => {\n if (!date) return false;\n return getEventsForDate(date, events).length > 0;\n};\n\n// Event item component\nconst EventItem = ({\n title,\n start,\n end,\n color,\n isAllDay,\n accentColor,\n}: CalendarEvent & { accentColor?: string }) => {\n const startTime = new Date(start).toLocaleTimeString(\"en-US\", {\n hour: \"numeric\",\n minute: \"2-digit\",\n });\n const endTime = new Date(end).toLocaleTimeString(\"en-US\", {\n hour: \"numeric\",\n minute: \"2-digit\",\n });\n\n return (\n <div className=\"flex gap-x-2\">\n <div\n className=\"w-0.5 shrink-0 rounded-full\"\n style={{ backgroundColor: color || accentColor }}\n />\n <div className=\"min-w-0 flex-1\">\n <div className=\"truncate text-sm font-medium\">{title}</div>\n <div className=\"text-xs opacity-60\">\n {isAllDay ? \"All day\" : `${startTime} - ${endTime}`}\n </div>\n </div>\n </div>\n );\n};\n\nconst dayNames = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"];\n\ntype DayButtonProps = {\n date: Date;\n isToday: boolean;\n isSelected: boolean;\n hasEvents: boolean;\n accentColor: string;\n onClick: () => void;\n extraClassName?: string;\n};\n\nfunction DayButton({\n date,\n isToday,\n isSelected,\n hasEvents,\n accentColor,\n onClick,\n extraClassName = \"\",\n}: DayButtonProps) {\n return (\n <button\n onClick={onClick}\n className={`relative flex aspect-square items-center justify-center rounded-full text-sm transition-colors ${\n isSelected\n ? `bg-${accentColor} text-${accentColor}-foreground`\n : isToday\n ? `bg-${accentColor}/30 text-${accentColor}-foreground hover:bg-${accentColor}/50`\n : `hover:bg-${accentColor}/50 hover:text-${accentColor}-foreground`\n } ${extraClassName}`}\n >\n {date.getDate()}\n {hasEvents && (\n <div\n className={`absolute bottom-1 h-1 w-1 rounded-full bg-${accentColor}`}\n />\n )}\n </button>\n );\n}\n\ntype CalendarWidgetProps = ComponentProps<\"div\"> & {\n // Title\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n // Styling\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n};\n\nexport function CalendarWidget({\n // Title defaults\n titleEnabled = true,\n titleText = \"Calendar\",\n titleFontSize = \"xl\",\n titleColor = \"foreground\",\n\n // Styling defaults\n background = {\n type: \"solid\",\n color: \"background\",\n },\n textColor = \"foreground\",\n accentColor = \"primary\",\n padding = 4,\n borderRadius = \"md\",\n borderWidth = \"none\",\n borderColor = \"muted\",\n\n className,\n ...props\n}: CalendarWidgetProps): React.JSX.Element {\n const backgroundColor = background.color || \"background\";\n const backgroundImage =\n (background.resource?.image_url || background.resource?.imageUrl) &&\n background.type === \"image\"\n ? `url(${background.resource.image_url || background.resource.imageUrl})`\n : \"none\";\n const today = new Date();\n const [currentMonth, setCurrentMonth] = useState(today.getMonth());\n const [currentYear, setCurrentYear] = useState(today.getFullYear());\n const [isCollapsed, setIsCollapsed] = useState(false);\n const [selectedDate, setSelectedDate] = useState<Date | null>(today);\n\n const { data: events = [], isLoading, isError } = useCalendarEvents();\n\n // Generate calendar grids\n const monthGrid = useMemo(\n () => generateMonthGrid(currentYear, currentMonth),\n [currentYear, currentMonth],\n );\n const weekGrid = useMemo(() => generateWeekGrid(), []);\n\n // Get events for selected date\n const selectedDateEvents = useMemo(() => {\n if (!selectedDate) return [];\n return getEventsForDate(selectedDate, events);\n }, [selectedDate, events]);\n\n // Navigation handlers\n const goToPrevMonth = () => {\n if (currentMonth === 0) {\n setCurrentMonth(11);\n setCurrentYear(currentYear - 1);\n } else {\n setCurrentMonth(currentMonth - 1);\n }\n };\n\n const goToNextMonth = () => {\n if (currentMonth === 11) {\n setCurrentMonth(0);\n setCurrentYear(currentYear + 1);\n } else {\n setCurrentMonth(currentMonth + 1);\n }\n };\n\n const monthYearLabel = new Date(currentYear, currentMonth).toLocaleString(\n \"en-US\",\n {\n month: \"long\",\n year: \"numeric\",\n },\n );\n\n return (\n <div\n className={`@container overflow-hidden rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} bg-${backgroundColor} text-${textColor} ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n {/* Title */}\n {titleEnabled && titleText && (\n <div className={`p-${padding} pb-0`}>\n <h2\n className={`text-${titleFontSize} font-header font-bold text-${titleColor}`}\n >\n {titleText}\n </h2>\n </div>\n )}\n\n {/* Loading state */}\n {isLoading ? (\n <div\n className={`flex min-h-[300px] items-center justify-center p-${padding}`}\n >\n <div className=\"h-8 w-8 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n </div>\n ) : isError ? (\n /* Error state */\n <ErrorState />\n ) : (\n <div className={`p-${padding}`}>\n {/* Desktop: Side by side layout */}\n <div className=\"@md:flex @md:gap-6\">\n {/* Calendar Section */}\n <div className=\"@md:flex-none\">\n {/* Month/Year Header with Navigation */}\n <div className=\"mb-4 flex items-center justify-between\">\n <button\n onClick={goToPrevMonth}\n className=\"hover:bg-foreground/10 rounded-full p-1\"\n aria-label=\"Previous month\"\n >\n <ChevronLeft className=\"size-4\" />\n </button>\n\n <span className=\"text-base font-semibold\">\n {monthYearLabel}\n </span>\n\n <button\n onClick={goToNextMonth}\n className=\"hover:bg-foreground/10 rounded-full p-1\"\n aria-label=\"Next month\"\n >\n <ChevronRight className=\"size-4\" />\n </button>\n </div>\n\n {/* Day Headers */}\n <div className=\"mb-2 grid grid-cols-7 gap-1 text-center\">\n {dayNames.map((day, idx) => (\n <div\n key={idx}\n className=\"text-xs font-medium uppercase opacity-60\"\n >\n {day}\n </div>\n ))}\n </div>\n\n {/* Calendar Grid - Week view on mobile when collapsed */}\n {isCollapsed && (\n <div className=\"grid grid-cols-7 gap-1 @md:hidden\">\n {weekGrid.map(({ date, isToday }, idx) => (\n <DayButton\n key={idx}\n date={date}\n isToday={isToday}\n isSelected={\n selectedDate?.toDateString() === date.toDateString()\n }\n hasEvents={hasEventsOnDate(date, events)}\n accentColor={accentColor}\n onClick={() => setSelectedDate(date)}\n />\n ))}\n </div>\n )}\n\n {/* Month view (always on desktop, when not collapsed on mobile) */}\n <div\n className={`grid grid-cols-7 gap-1 ${isCollapsed ? \"hidden @md:grid\" : \"grid\"}`}\n >\n {monthGrid.map((day, idx) => {\n if (!day.date) {\n return <div key={idx} className=\"aspect-square\" />;\n }\n\n return (\n <DayButton\n key={idx}\n date={day.date}\n isToday={day.isToday}\n isSelected={\n selectedDate?.toDateString() === day.date.toDateString()\n }\n hasEvents={hasEventsOnDate(day.date, events)}\n accentColor={accentColor}\n onClick={() => setSelectedDate(day.date)}\n extraClassName=\"p-2 @md:m-3\"\n />\n );\n })}\n </div>\n\n {/* Mobile collapse toggle */}\n <button\n onClick={() => setIsCollapsed(!isCollapsed)}\n className={`ml-2 flex w-full items-center justify-center gap-3 rounded-full p-1 text-${textColor}/50 @md:hidden`}\n aria-label={\n isCollapsed ? \"Expand calendar\" : \"Collapse calendar\"\n }\n >\n <div className={`h-1 w-1/2 bg-${textColor}/50`} />\n {isCollapsed ? (\n <ChevronsDown className=\"size-4\" />\n ) : (\n <ChevronsUp className=\"size-4\" />\n )}\n <div className={`h-1 w-1/2 bg-${textColor}/50`} />\n </button>\n </div>\n\n {/* Events Panel */}\n <div className=\"border-muted mt-4 pt-4 @md:mt-0 @md:w-56 @md:border-l @md:pt-0 @md:pl-6\">\n <div className=\"mb-2 text-sm font-medium opacity-60\">\n {selectedDate\n ? selectedDate.toLocaleDateString(\"en-US\", {\n weekday: \"long\",\n month: \"short\",\n day: \"numeric\",\n })\n : \"Select a date\"}\n </div>\n\n {selectedDateEvents.length > 0 ? (\n <div className=\"flex flex-col gap-3\">\n {selectedDateEvents.map((event, idx) => (\n <EventItem\n key={`${event.id}-${idx}`}\n {...event}\n accentColor={`var(--${accentColor})`}\n />\n ))}\n </div>\n ) : (\n <div className=\"text-sm opacity-50\">No events</div>\n )}\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const calendarWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"CalendarWidget\",\n displayName: \"Calendar Widget\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [\n // Styling Tab - Title Group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed above the calendar\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Title text displayed above the calendar\",\n defaultValue: \"Calendar\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n key: \"titleFontSize\",\n label: \"Title Font Size\",\n description: \"Font size for the widget title\",\n defaultValue: \"xl\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n\n // Styling Tab - Design Group\n {\n type: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background for the calendar container\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for calendar content\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"accentColor\",\n label: \"Accent Color\",\n description: \"Color used for today highlight and event indicators\",\n defaultValue: \"primary\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the calendar container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the calendar container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the widget\",\n defaultValue: \"none\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the widget\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"ListWidget-g2qBtmNZ.cjs","names":["MediaRenderer","DOMPurify","getImageUrl","getAspectRatioClass","useWidgetInteraction","gapValues","useWidgetInteraction","gapValues","ScrollArrows","borderWidthClasses","borderColorClasses","getFontSizeField","getColorField","getPaddingField","getBorderRadiusField","getBorderWidthField","getBorderColorField","getGapField"],"sources":["../../widgets/src/widgets/list-widget/FeaturedSection.tsx","../../widgets/src/widgets/list-widget/ListItemCard.tsx","../../widgets/src/widgets/list-widget/UnorderedList.tsx","../../widgets/src/widgets/list-widget/OrderedList.tsx","../../widgets/src/widgets/ListWidget.tsx"],"sourcesContent":["import type React from \"react\";\nimport type {\n BorderRadiusOptions,\n FontSizeOptions,\n ColorOptions,\n} from \"@fluid-app/portal-core/types\";\nimport { MediaRenderer } from \"../../components/MediaRenderer\";\n\ninterface FeaturedSectionProps {\n borderRadius: BorderRadiusOptions;\n titleSize: FontSizeOptions;\n featuredTitle?: string | undefined;\n featuredSubtitle?: string | undefined;\n featuredButtonText?: string | undefined;\n featuredButtonUrl?: string | undefined;\n featuredSubtitleColor: ColorOptions;\n featuredSubtitleSize: FontSizeOptions;\n asset: { url: string; isVideo: boolean };\n}\n\nexport function FeaturedSection({\n borderRadius,\n titleSize,\n featuredTitle,\n featuredSubtitle,\n featuredButtonText,\n featuredButtonUrl,\n featuredSubtitleColor,\n featuredSubtitleSize,\n asset,\n}: FeaturedSectionProps): React.JSX.Element {\n return (\n <div\n className={`relative h-full min-h-[300px] w-full overflow-hidden rounded-${borderRadius}`}\n >\n <div className=\"absolute inset-0 h-full w-full\">\n <MediaRenderer\n src={asset.url}\n mediaType={asset.isVideo ? \"video\" : \"image\"}\n alt={featuredTitle || \"Featured\"}\n objectFit=\"cover\"\n autoplay={asset.isVideo}\n loop={asset.isVideo}\n muted={asset.isVideo}\n controls={false}\n />\n </div>\n\n <div className=\"absolute inset-0 bg-black/40\" />\n\n <div className=\"absolute inset-0 flex flex-col items-start justify-end p-8\">\n {featuredTitle && (\n <h3\n className={`font-header mb-2 font-bold text-white text-${titleSize === \"md\" ? \"base\" : titleSize}`}\n >\n {featuredTitle}\n </h3>\n )}\n {featuredSubtitle && (\n <p\n className={`mb-4 text-${featuredSubtitleColor} text-${featuredSubtitleSize === \"md\" ? \"base\" : featuredSubtitleSize}`}\n >\n {featuredSubtitle}\n </p>\n )}\n {featuredButtonText && (\n <a\n href={featuredButtonUrl || \"#\"}\n className={`text-foreground bg-white px-6 py-2 font-medium transition-opacity hover:opacity-90 rounded-${borderRadius}`}\n >\n {featuredButtonText}\n </a>\n )}\n </div>\n </div>\n );\n}\n","import type React from \"react\";\nimport DOMPurify from \"dompurify\";\nimport type {\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\n\ntype ListItem = {\n id: string;\n image?: string;\n imageUrl?: string;\n videoUrl?: string;\n title?: string;\n description?: string;\n price?: string;\n display_price?: string;\n originalPrice?: string;\n discount?: string;\n qv?: string;\n cv?: string;\n [key: string]: unknown;\n};\n\nfunction getStringValue(value: unknown): string {\n if (!value) return \"\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\") return String(value);\n if (typeof value === \"object\" && value !== null) {\n if (\"body\" in value) {\n const body = (value as { body: unknown }).body;\n if (typeof body === \"string\") return body;\n }\n if (\"text\" in value) {\n const text = (value as { text: unknown }).text;\n if (typeof text === \"string\") return text;\n }\n if (\"value\" in value) {\n const val = (value as { value: unknown }).value;\n if (typeof val === \"string\") return val;\n if (typeof val === \"number\") return String(val);\n }\n }\n return \"\";\n}\n\n/**\n * Strips parenthetical text like \"(USD)\" from price strings.\n * Matches the shop page's stripParentheticalText pattern.\n */\nfunction stripParentheticalText(text: string): string {\n return text.replace(/\\s*\\([^)]*\\)/g, \"\").trim();\n}\n\n/**\n * Formats a price for display. Follows the shop page pattern:\n * prices arrive pre-formatted from the API via display_price\n * (e.g. \"$19.99\", \"€15.00 (EUR)\") so we just extract the string\n * and strip parenthetical suffixes.\n */\nfunction formatPrice(value: unknown): string {\n const str = getStringValue(value);\n if (!str) return \"\";\n return stripParentheticalText(str);\n}\n\nexport interface ListItemCardContentProps {\n item: ListItem;\n padding: PaddingOptions;\n itemTitleColor: ColorOptions;\n itemTitleSize: FontSizeOptions;\n descriptionColor: ColorOptions;\n descriptionSize: FontSizeOptions;\n priceColor: ColorOptions;\n priceSize: FontSizeOptions;\n originalPriceColor: ColorOptions;\n metaTextColor: ColorOptions;\n metaTextSize: FontSizeOptions;\n showMetaText: boolean;\n}\n\nexport function ListItemCardContent({\n item,\n padding,\n itemTitleColor,\n itemTitleSize,\n descriptionColor,\n descriptionSize,\n priceColor,\n priceSize,\n originalPriceColor,\n metaTextColor,\n metaTextSize,\n showMetaText,\n}: ListItemCardContentProps): React.JSX.Element {\n return (\n <div className={`p-${padding}`}>\n {item.title && (\n <h3\n className={`text-${itemTitleColor} text-${itemTitleSize === \"md\" ? \"base\" : itemTitleSize} font-header mb-1 font-semibold`}\n >\n {getStringValue(item.title)}\n </h3>\n )}\n {item.description && (\n <div\n className={`text-${descriptionColor} text-${descriptionSize === \"md\" ? \"base\" : descriptionSize} mb-2 line-clamp-2 overflow-hidden`}\n dangerouslySetInnerHTML={{\n __html: DOMPurify.sanitize(item.description ?? \"\", {\n ALLOWED_TAGS: [\n \"br\",\n \"strong\",\n \"em\",\n \"b\",\n \"i\",\n \"ul\",\n \"ol\",\n \"li\",\n \"p\",\n ],\n ALLOWED_ATTR: [],\n }),\n }}\n />\n )}\n <div className=\"flex items-center gap-2\">\n {(item.display_price || item.price) && (\n <span\n className={`text-${priceColor} text-${priceSize === \"md\" ? \"base\" : priceSize} font-bold`}\n >\n {formatPrice(item.display_price || item.price)}\n </span>\n )}\n {item.originalPrice && (\n <span\n className={`text-${originalPriceColor} text-${descriptionSize === \"md\" ? \"base\" : descriptionSize} line-through`}\n >\n {formatPrice(item.originalPrice)}\n </span>\n )}\n </div>\n {showMetaText && (item.qv || item.cv) && (\n <div\n className={`mt-2 flex gap-3 text-${metaTextColor} text-${metaTextSize === \"md\" ? \"base\" : metaTextSize}`}\n >\n {item.qv && <span>QV: {getStringValue(item.qv)}</span>}\n {item.cv && <span>CV: {getStringValue(item.cv)}</span>}\n </div>\n )}\n </div>\n );\n}\n\nexport function DiscountBadge({\n discount,\n}: {\n discount: string;\n}): React.JSX.Element {\n return (\n <div className=\"bg-destructive text-destructive-foreground absolute top-2 right-2 z-10 rounded-md px-2 py-1 text-xs font-bold\">\n {getStringValue(discount)}\n </div>\n );\n}\n\nexport { getStringValue };\nexport type { ListItem };\n","import type React from \"react\";\nimport type {\n ColorOptions,\n FontSizeOptions,\n BorderRadiusOptions,\n PaddingOptions,\n GapOptions,\n} from \"@fluid-app/portal-core/types\";\nimport { gapValues } from \"../../core/fields\";\nimport { useWidgetInteraction } from \"../../contexts/WidgetInteractionContext\";\nimport {\n ListItemCardContent,\n DiscountBadge,\n type ListItem,\n} from \"./ListItemCard\";\n\ntype ImageAspectRatio = \"square\" | \"landscape\" | \"portrait\";\n\nconst getImageUrl = (item: ListItem): string | undefined => {\n return item.imageUrl || item.image;\n};\n\nconst getAspectRatioClass = (ratio: ImageAspectRatio): string => {\n const ratios = {\n square: \"aspect-square\",\n landscape: \"aspect-video\",\n portrait: \"aspect-[3/4]\",\n };\n return ratios[ratio];\n};\n\nconst getResponsiveGridClass = (columns: number): string => {\n const responsiveClasses: Record<number, string> = {\n 1: \"grid-cols-2 @lg:grid-cols-1\",\n 2: \"grid-cols-2 @lg:grid-cols-2\",\n 3: \"grid-cols-2 @lg:grid-cols-3\",\n 4: \"grid-cols-2 @lg:grid-cols-4\",\n 5: \"grid-cols-2 @lg:grid-cols-5\",\n 6: \"grid-cols-2 @lg:grid-cols-6\",\n };\n return responsiveClasses[columns] || \"grid-cols-2 @lg:grid-cols-3\";\n};\n\nexport interface UnorderedListProps {\n items: ListItem[];\n columns: number;\n gap: GapOptions;\n borderRadius: BorderRadiusOptions;\n imageAspectRatio: ImageAspectRatio;\n showBadge: boolean;\n padding: PaddingOptions;\n itemTitleColor: ColorOptions;\n itemTitleSize: FontSizeOptions;\n descriptionColor: ColorOptions;\n descriptionSize: FontSizeOptions;\n priceColor: ColorOptions;\n priceSize: FontSizeOptions;\n originalPriceColor: ColorOptions;\n metaTextColor: ColorOptions;\n metaTextSize: FontSizeOptions;\n showMetaText: boolean;\n}\n\nexport function UnorderedList({\n items,\n columns,\n gap,\n borderRadius,\n imageAspectRatio,\n showBadge,\n padding,\n itemTitleColor,\n itemTitleSize,\n descriptionColor,\n descriptionSize,\n priceColor,\n priceSize,\n originalPriceColor,\n metaTextColor,\n metaTextSize,\n showMetaText,\n}: UnorderedListProps): React.JSX.Element {\n const gridClass = getResponsiveGridClass(columns);\n const { onItemClick } = useWidgetInteraction();\n\n return (\n <div className={`grid ${gridClass} gap-${gapValues[gap]}`}>\n {items.map((item) => {\n const imageUrl = getImageUrl(item);\n const aspectRatioClass = getAspectRatioClass(imageAspectRatio);\n\n return (\n <div\n key={item.id}\n className={`relative rounded-${borderRadius} bg-background overflow-hidden shadow-sm transition-shadow hover:shadow-md ${onItemClick ? \"cursor-pointer\" : \"\"}`}\n {...(onItemClick\n ? {\n role: \"button\",\n tabIndex: 0,\n onClick: () => onItemClick(item),\n onKeyDown: (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onItemClick(item);\n }\n },\n }\n : {})}\n >\n {showBadge && item.discount && (\n <DiscountBadge discount={item.discount} />\n )}\n {imageUrl && (\n <div className={`w-full ${aspectRatioClass} overflow-hidden`}>\n <img\n src={imageUrl}\n alt={item.title || \"Product\"}\n className=\"h-full w-full object-cover\"\n />\n </div>\n )}\n <ListItemCardContent\n item={item}\n padding={padding}\n itemTitleColor={itemTitleColor}\n itemTitleSize={itemTitleSize}\n descriptionColor={descriptionColor}\n descriptionSize={descriptionSize}\n priceColor={priceColor}\n priceSize={priceSize}\n originalPriceColor={originalPriceColor}\n metaTextColor={metaTextColor}\n metaTextSize={metaTextSize}\n showMetaText={showMetaText}\n />\n </div>\n );\n })}\n </div>\n );\n}\n","import { useRef } from \"react\";\nimport type React from \"react\";\nimport type {\n ColorOptions,\n FontSizeOptions,\n BorderRadiusOptions,\n PaddingOptions,\n GapOptions,\n} from \"@fluid-app/portal-core/types\";\nimport { gapValues } from \"../../core/fields\";\nimport { useWidgetInteraction } from \"../../contexts/WidgetInteractionContext\";\nimport { ScrollArrows } from \"../../ui/scroll-arrows\";\nimport {\n ListItemCardContent,\n DiscountBadge,\n getStringValue,\n type ListItem,\n} from \"./ListItemCard\";\n\ntype ImageAspectRatio = \"square\" | \"landscape\" | \"portrait\";\ntype ScrollAxis = \"horizontal\" | \"vertical\";\n\nconst SCROLL_ITEM_WIDTH = 300;\n\nconst getImageUrl = (item: ListItem): string | undefined => {\n return item.imageUrl || item.image;\n};\n\nconst getAspectRatioClass = (ratio: ImageAspectRatio): string => {\n const ratios = {\n square: \"aspect-square\",\n landscape: \"aspect-video\",\n portrait: \"aspect-[3/4]\",\n };\n return ratios[ratio];\n};\n\nexport interface OrderedListProps {\n items: ListItem[];\n scrollAxis: ScrollAxis;\n gap: GapOptions;\n borderRadius: BorderRadiusOptions;\n imageAspectRatio: ImageAspectRatio;\n showBadge: boolean;\n padding: PaddingOptions;\n itemTitleColor: ColorOptions;\n itemTitleSize: FontSizeOptions;\n descriptionColor: ColorOptions;\n descriptionSize: FontSizeOptions;\n priceColor: ColorOptions;\n priceSize: FontSizeOptions;\n originalPriceColor: ColorOptions;\n metaTextColor: ColorOptions;\n metaTextSize: FontSizeOptions;\n numberColor: ColorOptions;\n numberSize: FontSizeOptions;\n showMetaText: boolean;\n}\n\nconst largeNumberSizes: Record<FontSizeOptions, string> = {\n xs: \"8rem\",\n sm: \"10rem\",\n md: \"12rem\",\n lg: \"14rem\",\n xl: \"16rem\",\n \"2xl\": \"20rem\",\n};\n\nexport function OrderedList({\n items,\n scrollAxis,\n gap,\n borderRadius,\n imageAspectRatio,\n showBadge,\n padding,\n itemTitleColor,\n itemTitleSize,\n descriptionColor,\n descriptionSize,\n priceColor,\n priceSize,\n originalPriceColor,\n metaTextColor,\n metaTextSize,\n numberColor,\n numberSize,\n showMetaText,\n}: OrderedListProps): React.JSX.Element | null {\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n\n const scrollByAmount = (direction: \"prev\" | \"next\") => {\n const container = scrollContainerRef.current;\n if (!container) return;\n\n const computedGap = parseFloat(getComputedStyle(container).gap) || 0;\n const scrollAmount = SCROLL_ITEM_WIDTH + computedGap;\n\n container.scrollTo({\n left:\n container.scrollLeft +\n (direction === \"next\" ? scrollAmount : -scrollAmount),\n behavior: \"smooth\",\n });\n };\n\n const { onItemClick } = useWidgetInteraction();\n\n const interactionProps = (item: ListItem) =>\n onItemClick\n ? ({\n role: \"button\" as const,\n tabIndex: 0,\n onClick: () => onItemClick(item),\n onKeyDown: (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onItemClick(item);\n }\n },\n } as const)\n : {};\n\n const contentProps = {\n padding,\n itemTitleColor,\n itemTitleSize,\n descriptionColor,\n descriptionSize,\n priceColor,\n priceSize,\n originalPriceColor,\n metaTextColor,\n metaTextSize,\n showMetaText,\n };\n\n if (scrollAxis === \"horizontal\") {\n return (\n <div className=\"relative\">\n <div\n ref={scrollContainerRef}\n className={`flex gap-${gapValues[gap]} scrollbar-hide overflow-x-auto overflow-y-hidden scroll-smooth`}\n >\n {items.map((item, index) => {\n const imageUrl = getImageUrl(item);\n const aspectRatioClass = getAspectRatioClass(imageAspectRatio);\n\n return (\n <div\n key={item.id}\n className={`relative w-[300px] flex-shrink-0 ${onItemClick ? \"cursor-pointer\" : \"\"}`}\n {...interactionProps(item)}\n >\n <div\n className={`absolute top-0 left-0 text-${numberColor} z-0 leading-none font-bold opacity-20`}\n style={{ fontSize: largeNumberSizes[numberSize] }}\n >\n {index + 1}\n </div>\n\n <div\n className={`relative z-10 ml-20 rounded-${borderRadius} bg-background overflow-hidden shadow-sm transition-shadow hover:shadow-md`}\n >\n {showBadge && item.discount && (\n <DiscountBadge discount={item.discount} />\n )}\n {imageUrl && (\n <div\n className={`w-full ${aspectRatioClass} overflow-hidden`}\n >\n <img\n src={imageUrl}\n alt={item.title || \"Product\"}\n className=\"h-full w-full object-cover\"\n />\n </div>\n )}\n <ListItemCardContent item={item} {...contentProps} />\n </div>\n </div>\n );\n })}\n </div>\n\n <div className=\"absolute inset-x-0 top-1/2 z-20 flex w-full -translate-y-1/2 items-center justify-between px-8\">\n <ScrollArrows\n onPrevious={() => scrollByAmount(\"prev\")}\n onNext={() => scrollByAmount(\"next\")}\n />\n </div>\n </div>\n );\n }\n\n if (scrollAxis === \"vertical\") {\n return (\n <div className={`flex flex-col gap-${gapValues[gap]}`}>\n {items.map((item, index) => {\n const imageUrl = getImageUrl(item);\n\n return (\n <div\n key={item.id}\n className={`relative flex gap-${gapValues[gap]} rounded-${borderRadius} bg-background overflow-hidden shadow-sm transition-shadow hover:shadow-md ${`p-${padding}`} ${onItemClick ? \"cursor-pointer\" : \"\"}`}\n {...interactionProps(item)}\n >\n <div\n className={`flex-shrink-0 text-${numberColor} text-${numberSize === \"md\" ? \"base\" : numberSize} flex w-16 items-center justify-center font-bold`}\n >\n {index + 1}\n </div>\n {imageUrl && (\n <div className=\"h-24 w-24 flex-shrink-0 overflow-hidden rounded-md\">\n <img\n src={imageUrl}\n alt={item.title || \"Product\"}\n className=\"h-full w-full object-cover\"\n />\n </div>\n )}\n <div className=\"flex-1\">\n <ListItemCardContent item={item} {...contentProps} />\n </div>\n {showBadge && item.discount && (\n <div className=\"bg-destructive text-destructive-foreground absolute top-2 right-2 rounded-md px-2 py-1 text-xs font-bold\">\n {getStringValue(item.discount)}\n </div>\n )}\n </div>\n );\n })}\n </div>\n );\n }\n\n return null;\n}\n","import type { ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BorderWidthOptions,\n ColorOptions,\n FontSizeOptions,\n BorderRadiusOptions,\n PaddingOptions,\n GapOptions,\n BackgroundValue,\n} from \"@fluid-app/portal-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getBorderWidthField,\n getBorderColorField,\n borderWidthClasses,\n borderColorClasses,\n getColorField,\n getFontSizeField,\n getPaddingField,\n getGapField,\n} from \"../core/fields\";\nimport { FeaturedSection } from \"./list-widget/FeaturedSection\";\nimport { UnorderedList } from \"./list-widget/UnorderedList\";\nimport { OrderedList } from \"./list-widget/OrderedList\";\n\nconst DEFAULT_ITEMS: ListItem[] = [];\n\ntype ListItem = {\n id: string;\n image?: string;\n imageUrl?: string;\n videoUrl?: string;\n title?: string;\n description?: string;\n price?: string;\n originalPrice?: string;\n discount?: string;\n qv?: string;\n cv?: string;\n [key: string]: unknown;\n};\n\ntype ImageAspectRatio = \"square\" | \"landscape\" | \"portrait\";\ntype ListType = \"ordered\" | \"unordered\";\ntype ScrollAxis = \"horizontal\" | \"vertical\";\n\ntype ListWidgetProps = ComponentProps<\"div\"> & {\n // List configuration\n listType?: ListType;\n scrollAxis?: ScrollAxis;\n titleEnabled?: boolean;\n title?: string;\n items?: ListItem[];\n\n // Text styling\n titleColor?: ColorOptions;\n titleSize?: FontSizeOptions;\n itemTitleColor?: ColorOptions;\n itemTitleSize?: FontSizeOptions;\n descriptionColor?: ColorOptions;\n descriptionSize?: FontSizeOptions;\n priceColor?: ColorOptions;\n priceSize?: FontSizeOptions;\n originalPriceColor?: ColorOptions;\n metaTextColor?: ColorOptions;\n metaTextSize?: FontSizeOptions;\n\n // Ordered list styling\n numberColor?: ColorOptions;\n numberSize?: FontSizeOptions;\n\n // Layout\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n padding?: PaddingOptions;\n gap?: GapOptions;\n columns?: number;\n imageAspectRatio?: ImageAspectRatio;\n background?: BackgroundValue;\n\n // Behavior\n showBadge?: boolean;\n showMetaText?: boolean;\n maxItems?: number;\n\n // Featured section\n showFeaturedSection?: boolean;\n featuredAsset?: string | { [key: string]: unknown };\n featuredTitle?: string;\n featuredSubtitle?: string;\n featuredButtonText?: string;\n featuredButtonUrl?: string;\n featuredSubtitleColor?: ColorOptions;\n featuredSubtitleSize?: FontSizeOptions;\n};\n\nfunction getFeaturedAssetUrl(\n value: string | { [key: string]: unknown } | undefined,\n): { url: string; isVideo: boolean } | undefined {\n if (!value) return undefined;\n\n // Handle string URLs\n if (typeof value === \"string\") {\n const isVideo = /\\.(mp4|webm|ogg|mov)$/i.test(value);\n return { url: value, isVideo };\n }\n\n // Handle ShareableItem objects\n if (typeof value === \"object\") {\n // Check for video URL first\n const videoUrl =\n (value.videoUrl as string) ||\n (value.video_url as string) ||\n (value.url as string);\n if (videoUrl && /\\.(mp4|webm|ogg|mov)$/i.test(videoUrl)) {\n return { url: videoUrl, isVideo: true };\n }\n\n // Fall back to image URL\n const imageUrl =\n (value.imageUrl as string) ||\n (value.image_url as string) ||\n (value.url as string);\n if (imageUrl) {\n return { url: imageUrl, isVideo: false };\n }\n }\n\n return undefined;\n}\n\nexport function ListWidget({\n listType = \"unordered\",\n scrollAxis = \"horizontal\",\n titleEnabled = true,\n title,\n items = DEFAULT_ITEMS,\n titleColor = \"foreground\",\n titleSize = \"lg\",\n itemTitleColor = \"foreground\",\n itemTitleSize = \"sm\",\n descriptionColor = \"foreground\",\n descriptionSize = \"sm\",\n priceColor = \"foreground\",\n priceSize = \"md\",\n originalPriceColor = \"muted\",\n metaTextColor = \"muted\",\n metaTextSize = \"xs\",\n numberColor = \"primary\",\n numberSize = \"2xl\",\n borderRadius = \"md\",\n borderWidth = \"none\",\n borderColor = \"muted\",\n padding = 4,\n gap = \"md\",\n columns = 3,\n imageAspectRatio = \"square\",\n background = { type: \"solid\", color: \"background\" },\n showBadge = true,\n showMetaText = true,\n maxItems = 12,\n showFeaturedSection = false,\n featuredAsset,\n featuredTitle,\n featuredSubtitle,\n featuredButtonText,\n featuredButtonUrl,\n featuredSubtitleColor = \"background\",\n featuredSubtitleSize = \"md\",\n className,\n ...props\n}: ListWidgetProps): React.JSX.Element {\n const displayItems = maxItems ? items.slice(0, maxItems) : items;\n const hasItems = displayItems.length > 0;\n\n const itemStyleProps = {\n padding,\n itemTitleColor,\n itemTitleSize,\n descriptionColor,\n descriptionSize,\n priceColor,\n priceSize,\n originalPriceColor,\n metaTextColor,\n metaTextSize,\n showMetaText,\n showBadge,\n borderRadius,\n imageAspectRatio,\n gap,\n };\n\n const hasFeaturedAsset = getFeaturedAssetUrl(featuredAsset);\n const shouldShowFeaturedSection = showFeaturedSection && hasFeaturedAsset;\n\n // Background styling\n const backgroundColor = background.color || \"background\";\n const backgroundImage =\n (background.resource?.image_url || background.resource?.imageUrl) &&\n background.type === \"image\"\n ? `url(${background.resource.image_url || background.resource.imageUrl})`\n : \"none\";\n\n return (\n <div\n className={`@container bg-${backgroundColor} rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n {titleEnabled && title && (\n <h2\n className={`text-${titleColor} text-${titleSize === \"md\" ? \"base\" : titleSize} font-header mb-6 font-bold`}\n >\n {title}\n </h2>\n )}\n {!hasItems ? (\n <div className=\"border-border bg-muted flex items-center justify-center rounded-md border-2 border-dashed py-12 text-center\">\n <p className=\"text-muted\">No items to display</p>\n </div>\n ) : shouldShowFeaturedSection ? (\n <div className=\"flex flex-col gap-4 @lg:flex-row @lg:gap-6\">\n <div className=\"w-full @lg:w-[45%]\">\n <FeaturedSection\n borderRadius={borderRadius}\n titleSize={titleSize}\n featuredTitle={featuredTitle}\n featuredSubtitle={featuredSubtitle}\n featuredButtonText={featuredButtonText}\n featuredButtonUrl={featuredButtonUrl}\n featuredSubtitleColor={featuredSubtitleColor}\n featuredSubtitleSize={featuredSubtitleSize}\n asset={hasFeaturedAsset!}\n />\n </div>\n <div className=\"w-full @lg:w-[55%]\">\n {listType === \"unordered\" ? (\n <UnorderedList\n items={displayItems}\n columns={columns}\n {...itemStyleProps}\n />\n ) : (\n <OrderedList\n items={displayItems}\n scrollAxis={scrollAxis}\n numberColor={numberColor}\n numberSize={numberSize}\n {...itemStyleProps}\n />\n )}\n </div>\n </div>\n ) : listType === \"unordered\" ? (\n <UnorderedList\n items={displayItems}\n columns={columns}\n {...itemStyleProps}\n />\n ) : (\n <OrderedList\n items={displayItems}\n scrollAxis={scrollAxis}\n numberColor={numberColor}\n numberSize={numberSize}\n {...itemStyleProps}\n />\n )}\n </div>\n );\n}\n\nexport const listWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"ListWidget\",\n displayName: \"List\",\n tabsConfig: [\n { id: \"styling\", label: \"Styling\" },\n { id: \"data\", label: \"Data\" },\n ],\n dataSourceTargetProps: [\"items\"],\n fields: [\n // Styling tab - Title group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed above the list\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"title\",\n label: \"Title\",\n type: \"text\",\n description: \"Header text for the list\",\n defaultValue: \"List\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n key: \"titleSize\",\n label: \"Title Font Size\",\n description: \"Size of the list title\",\n defaultValue: \"xl\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the list title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n\n // Styling tab - Design group\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding inside the container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Rounded corners for the container and images\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the widget\",\n defaultValue: \"none\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the widget\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getGapField({\n key: \"gap\",\n label: \"Gap\",\n description: \"Spacing between items\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n type: \"background\",\n defaultValue: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background color or image for the widget\",\n tab: \"styling\",\n group: \"Design\",\n },\n\n // Styling tab - List Configuration group\n {\n key: \"listType\",\n label: \"List Type\",\n type: \"select\",\n description: \"Type of list layout\",\n defaultValue: \"unordered\",\n options: [\n { label: \"Unordered (Grid)\", value: \"unordered\" },\n { label: \"Ordered (Numbered)\", value: \"ordered\" },\n ],\n tab: \"styling\",\n group: \"List Configuration\",\n },\n {\n key: \"maxItems\",\n label: \"Max Items\",\n type: \"number\",\n description: \"Maximum number of items to display\",\n min: 1,\n max: 100,\n step: 1,\n defaultValue: 12,\n tab: \"styling\",\n group: \"List Configuration\",\n },\n {\n key: \"imageAspectRatio\",\n label: \"Image Aspect Ratio\",\n type: \"buttonGroup\",\n description: \"Aspect ratio for item images\",\n defaultValue: \"square\",\n options: [\n { label: \"Square\", value: \"square\" },\n { label: \"Landscape\", value: \"landscape\" },\n { label: \"Portrait\", value: \"portrait\" },\n ],\n tab: \"styling\",\n group: \"List Configuration\",\n },\n {\n key: \"showBadge\",\n label: \"Show Discount Badge\",\n type: \"boolean\",\n description: \"Display discount badge on images\",\n defaultValue: true,\n tab: \"styling\",\n group: \"List Configuration\",\n },\n {\n key: \"showMetaText\",\n label: \"Show QV/CV Text\",\n type: \"boolean\",\n description: \"Display QV and CV values\",\n defaultValue: true,\n tab: \"styling\",\n group: \"List Configuration\",\n },\n\n // Styling tab - Unordered List Configuration\n {\n key: \"columns\",\n label: \"Grid Columns\",\n type: \"number\",\n description: \"Number of columns in the grid (unordered list only)\",\n min: 1,\n max: 6,\n step: 1,\n defaultValue: 3,\n tab: \"styling\",\n group: \"Unordered List Configuration\",\n requiresKeyValue: { key: \"listType\", value: \"unordered\" },\n },\n\n // Styling tab - Ordered List Configuration\n {\n key: \"scrollAxis\",\n label: \"Scroll Direction\",\n type: \"select\",\n description: \"Direction for ordered list scrolling\",\n defaultValue: \"horizontal\",\n options: [\n { label: \"Horizontal\", value: \"horizontal\" },\n { label: \"Vertical\", value: \"vertical\" },\n ],\n tab: \"styling\",\n group: \"Ordered List Configuration\",\n requiresKeyValue: { key: \"listType\", value: \"ordered\" },\n },\n getColorField({\n key: \"numberColor\",\n label: \"Number Color\",\n description: \"Color for ordered list numbers\",\n defaultValue: \"primary\",\n tab: \"styling\",\n group: \"Ordered List Configuration\",\n requiresKeyValue: { key: \"listType\", value: \"ordered\" },\n }),\n getFontSizeField({\n key: \"numberSize\",\n label: \"Number Font Size\",\n description: \"Size of ordered list numbers\",\n defaultValue: \"2xl\",\n tab: \"styling\",\n group: \"Ordered List Configuration\",\n requiresKeyValue: { key: \"listType\", value: \"ordered\" },\n }),\n\n // Styling tab - Item Styling group\n getColorField({\n key: \"itemTitleColor\",\n label: \"Item Title Color\",\n description: \"Color for item titles\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n getFontSizeField({\n key: \"itemTitleSize\",\n label: \"Item Title Font Size\",\n description: \"Size of item titles\",\n defaultValue: \"sm\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n {\n key: \"separator2\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Item Styling\",\n },\n getColorField({\n key: \"descriptionColor\",\n label: \"Description Color\",\n description: \"Color for descriptions\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n getFontSizeField({\n key: \"descriptionSize\",\n label: \"Description Font Size\",\n description: \"Size of descriptions\",\n defaultValue: \"sm\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n {\n key: \"separator3\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Item Styling\",\n },\n getColorField({\n key: \"priceColor\",\n label: \"Price Color\",\n description: \"Color for prices\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n getFontSizeField({\n key: \"priceSize\",\n label: \"Price Font Size\",\n description: \"Size of prices\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n getColorField({\n key: \"originalPriceColor\",\n label: \"Original Price Color\",\n description: \"Color for crossed-out original prices\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n {\n key: \"separator4\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Item Styling\",\n },\n getColorField({\n key: \"metaTextColor\",\n label: \"Meta Text Color\",\n description: \"Color for QV/CV text\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n getFontSizeField({\n key: \"metaTextSize\",\n label: \"Meta Text Font Size\",\n description: \"Size of QV/CV text\",\n defaultValue: \"xs\",\n tab: \"styling\",\n group: \"Item Styling\",\n }),\n\n // Styling tab - Featured Section group\n {\n key: \"showFeaturedSection\",\n label: \"Show Featured Section\",\n type: \"boolean\",\n description: \"Display a featured content section\",\n defaultValue: false,\n tab: \"styling\",\n group: \"Featured Section\",\n },\n {\n key: \"featuredAsset\",\n label: \"Featured Asset\",\n type: \"resource\",\n description:\n \"Select a single image or video resource for the featured section\",\n tab: \"styling\",\n group: \"Featured Section\",\n allowedTypes: [\"Medium\"],\n requiresKeyToBeTrue: \"showFeaturedSection\",\n },\n {\n key: \"featuredTitle\",\n label: \"Featured Title\",\n type: \"text\",\n description: \"Title for featured section\",\n tab: \"styling\",\n group: \"Featured Section\",\n requiresKeyToBeTrue: \"showFeaturedSection\",\n },\n {\n key: \"featuredSubtitle\",\n label: \"Featured Subtitle\",\n type: \"text\",\n description: \"Subtitle for featured section\",\n tab: \"styling\",\n group: \"Featured Section\",\n requiresKeyToBeTrue: \"showFeaturedSection\",\n },\n {\n key: \"featuredButtonText\",\n label: \"Featured Button Text\",\n type: \"text\",\n description: \"Text for featured section button\",\n tab: \"styling\",\n group: \"Featured Section\",\n requiresKeyToBeTrue: \"showFeaturedSection\",\n },\n {\n key: \"featuredButtonUrl\",\n label: \"Featured Button URL\",\n type: \"text\",\n description: \"URL for featured section button\",\n tab: \"styling\",\n group: \"Featured Section\",\n requiresKeyToBeTrue: \"showFeaturedSection\",\n },\n getColorField({\n key: \"featuredSubtitleColor\",\n label: \"Featured Subtitle Color\",\n description: \"Color for featured subtitle\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Featured Section\",\n requiresKeyToBeTrue: \"showFeaturedSection\",\n }),\n getFontSizeField({\n key: \"featuredSubtitleSize\",\n label: \"Featured Subtitle Font Size\",\n description: \"Size of featured subtitle\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Featured Section\",\n requiresKeyToBeTrue: \"showFeaturedSection\",\n }),\n\n // Data tab - Data Configuration\n {\n key: \"dataSource\",\n label: \"Data Source\",\n type: \"dataSource\",\n description: \"\",\n tab: \"data\",\n group: \"Data Configuration\",\n },\n ],\n itemConfigSchema: {\n description: \"Configure settings for this list item\",\n fields: [\n {\n key: \"title\",\n label: \"Custom Title\",\n type: \"text\",\n description: \"Override the item's title\",\n },\n {\n key: \"description\",\n label: \"Custom Description\",\n type: \"textarea\",\n description: \"Override the item's description\",\n rows: 3,\n },\n {\n key: \"price\",\n label: \"Price\",\n type: \"text\",\n description: \"Current price\",\n },\n {\n key: \"originalPrice\",\n label: \"Original Price\",\n type: \"text\",\n description: \"Original price (will be crossed out)\",\n },\n {\n key: \"discount\",\n label: \"Discount Badge\",\n type: \"text\",\n description: \"Discount text (e.g., '40% Off')\",\n },\n {\n key: \"qv\",\n label: \"QV Value\",\n type: \"text\",\n description: \"Qualifying Volume value\",\n },\n {\n key: \"cv\",\n label: \"CV Value\",\n type: \"text\",\n description: \"Commission Volume value\",\n },\n {\n key: \"image\",\n label: \"Image URL\",\n type: \"text\",\n description: \"Custom image URL for this item\",\n },\n ],\n },\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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aACE;GACF,KAAK;GACL,OAAO;GACP,cAAc,CAAC,SAAS;GACxB,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACDC,mBAAAA,cAAc;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;EACFD,mBAAAA,iBAAiB;GACf,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;EAGF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACR;EACF;CACD,kBAAkB;EAChB,aAAa;EACb,QAAQ;GACN;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACb,MAAM;IACP;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACF;EACF;CACF"}