@fluid-app/portal-widgets 0.1.17

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 (145) hide show
  1. package/dist/AlertWidget-AS_8Jjbd.cjs +39 -0
  2. package/dist/AlertWidget-AS_8Jjbd.cjs.map +1 -0
  3. package/dist/AlertWidget-Dy6pBmXm.mjs +22 -0
  4. package/dist/AlertWidget-Dy6pBmXm.mjs.map +1 -0
  5. package/dist/CalendarWidget-DAHnT9Wn.mjs +424 -0
  6. package/dist/CalendarWidget-DAHnT9Wn.mjs.map +1 -0
  7. package/dist/CalendarWidget-DW7q6Q7_.cjs +441 -0
  8. package/dist/CalendarWidget-DW7q6Q7_.cjs.map +1 -0
  9. package/dist/CarouselWidget-BJvLjY7H.mjs +436 -0
  10. package/dist/CarouselWidget-BJvLjY7H.mjs.map +1 -0
  11. package/dist/CarouselWidget-Bdn0LVXT.cjs +453 -0
  12. package/dist/CarouselWidget-Bdn0LVXT.cjs.map +1 -0
  13. package/dist/CatchUpWidget-CZMptzf8.cjs +264 -0
  14. package/dist/CatchUpWidget-CZMptzf8.cjs.map +1 -0
  15. package/dist/CatchUpWidget-vEP5scfy.mjs +247 -0
  16. package/dist/CatchUpWidget-vEP5scfy.mjs.map +1 -0
  17. package/dist/ChartWidget-B3GcdLqH.mjs +415 -0
  18. package/dist/ChartWidget-B3GcdLqH.mjs.map +1 -0
  19. package/dist/ChartWidget-DQB7K6S0.cjs +432 -0
  20. package/dist/ChartWidget-DQB7K6S0.cjs.map +1 -0
  21. package/dist/ContainerWidget-B-4hcPKJ.mjs +44 -0
  22. package/dist/ContainerWidget-B-4hcPKJ.mjs.map +1 -0
  23. package/dist/ContainerWidget-CHa4gVvV.cjs +2 -0
  24. package/dist/ContainerWidget-rGsakG66.cjs +51 -0
  25. package/dist/ContainerWidget-rGsakG66.cjs.map +1 -0
  26. package/dist/EmbedWidget-ChLVA_9a.mjs +156 -0
  27. package/dist/EmbedWidget-ChLVA_9a.mjs.map +1 -0
  28. package/dist/EmbedWidget-mv5ce32s.cjs +173 -0
  29. package/dist/EmbedWidget-mv5ce32s.cjs.map +1 -0
  30. package/dist/ImageWidget-DFt4mJJx.cjs +167 -0
  31. package/dist/ImageWidget-DFt4mJJx.cjs.map +1 -0
  32. package/dist/ImageWidget-DMubcgat.mjs +150 -0
  33. package/dist/ImageWidget-DMubcgat.mjs.map +1 -0
  34. package/dist/LayoutWidget-BEi0yFpz.mjs +107 -0
  35. package/dist/LayoutWidget-BEi0yFpz.mjs.map +1 -0
  36. package/dist/LayoutWidget-C4-ka0Ge.cjs +114 -0
  37. package/dist/LayoutWidget-C4-ka0Ge.cjs.map +1 -0
  38. package/dist/LayoutWidget-D4haEqTQ.cjs +2 -0
  39. package/dist/ListWidget-C-jcsCb4.mjs +901 -0
  40. package/dist/ListWidget-C-jcsCb4.mjs.map +1 -0
  41. package/dist/ListWidget-RHQ2fQXa.cjs +919 -0
  42. package/dist/ListWidget-RHQ2fQXa.cjs.map +1 -0
  43. package/dist/MediaRenderer-CcJvyOJ1.cjs +181 -0
  44. package/dist/MediaRenderer-CcJvyOJ1.cjs.map +1 -0
  45. package/dist/MediaRenderer-Uq90PZcY.mjs +163 -0
  46. package/dist/MediaRenderer-Uq90PZcY.mjs.map +1 -0
  47. package/dist/MySiteWidget-A_cYFgxJ.cjs +279 -0
  48. package/dist/MySiteWidget-A_cYFgxJ.cjs.map +1 -0
  49. package/dist/MySiteWidget-DariqlfU.mjs +262 -0
  50. package/dist/MySiteWidget-DariqlfU.mjs.map +1 -0
  51. package/dist/NestedWidget-CNkwGwhM.mjs +330 -0
  52. package/dist/NestedWidget-CNkwGwhM.mjs.map +1 -0
  53. package/dist/NestedWidget-ofk9O-t1.cjs +346 -0
  54. package/dist/NestedWidget-ofk9O-t1.cjs.map +1 -0
  55. package/dist/QuickShareWidget-DWvgEy74.cjs +262 -0
  56. package/dist/QuickShareWidget-DWvgEy74.cjs.map +1 -0
  57. package/dist/QuickShareWidget-DXq5lcDn.mjs +245 -0
  58. package/dist/QuickShareWidget-DXq5lcDn.mjs.map +1 -0
  59. package/dist/RecentActivityWidget-BvncOdax.mjs +391 -0
  60. package/dist/RecentActivityWidget-BvncOdax.mjs.map +1 -0
  61. package/dist/RecentActivityWidget-wODng8dt.cjs +408 -0
  62. package/dist/RecentActivityWidget-wODng8dt.cjs.map +1 -0
  63. package/dist/RegistryContext-CscXrsRa.mjs +36 -0
  64. package/dist/RegistryContext-CscXrsRa.mjs.map +1 -0
  65. package/dist/RegistryContext-xjea4xVV.cjs +55 -0
  66. package/dist/RegistryContext-xjea4xVV.cjs.map +1 -0
  67. package/dist/ScreenRenderer-D52h5VQr.mjs +76 -0
  68. package/dist/ScreenRenderer-D52h5VQr.mjs.map +1 -0
  69. package/dist/ScreenRenderer-DZAxcg7x.cjs +82 -0
  70. package/dist/ScreenRenderer-DZAxcg7x.cjs.map +1 -0
  71. package/dist/ScreenRendererContext-CK1IsFTn.cjs +36 -0
  72. package/dist/ScreenRendererContext-CK1IsFTn.cjs.map +1 -0
  73. package/dist/ScreenRendererContext-DKcdcmiT.mjs +23 -0
  74. package/dist/ScreenRendererContext-DKcdcmiT.mjs.map +1 -0
  75. package/dist/SpacerWidget-Bgz6701y.cjs +60 -0
  76. package/dist/SpacerWidget-Bgz6701y.cjs.map +1 -0
  77. package/dist/SpacerWidget-DHGoW6eu.mjs +43 -0
  78. package/dist/SpacerWidget-DHGoW6eu.mjs.map +1 -0
  79. package/dist/TableWidget--yLJTqoW.mjs +438 -0
  80. package/dist/TableWidget--yLJTqoW.mjs.map +1 -0
  81. package/dist/TableWidget-TfQfFHft.cjs +455 -0
  82. package/dist/TableWidget-TfQfFHft.cjs.map +1 -0
  83. package/dist/TextWidget-CL2H3vei.mjs +129 -0
  84. package/dist/TextWidget-CL2H3vei.mjs.map +1 -0
  85. package/dist/TextWidget-D6Ug_2Z1.cjs +146 -0
  86. package/dist/TextWidget-D6Ug_2Z1.cjs.map +1 -0
  87. package/dist/ToDoWidget-D8YIsl7y.mjs +274 -0
  88. package/dist/ToDoWidget-D8YIsl7y.mjs.map +1 -0
  89. package/dist/ToDoWidget-Dvs0GDkx.cjs +291 -0
  90. package/dist/ToDoWidget-Dvs0GDkx.cjs.map +1 -0
  91. package/dist/VideoWidget-D6C_jHOF.mjs +192 -0
  92. package/dist/VideoWidget-D6C_jHOF.mjs.map +1 -0
  93. package/dist/VideoWidget-SODAPZO4.cjs +209 -0
  94. package/dist/VideoWidget-SODAPZO4.cjs.map +1 -0
  95. package/dist/chunk-CZWwpsFl.cjs +43 -0
  96. package/dist/components/index.cjs +14 -0
  97. package/dist/components/index.cjs.map +1 -0
  98. package/dist/components/index.d.cts +11 -0
  99. package/dist/components/index.d.cts.map +1 -0
  100. package/dist/components/index.d.mts +11 -0
  101. package/dist/components/index.d.mts.map +1 -0
  102. package/dist/components/index.mjs +11 -0
  103. package/dist/components/index.mjs.map +1 -0
  104. package/dist/contexts/index.cjs +8 -0
  105. package/dist/contexts/index.d.cts +77 -0
  106. package/dist/contexts/index.d.cts.map +1 -0
  107. package/dist/contexts/index.d.mts +77 -0
  108. package/dist/contexts/index.d.mts.map +1 -0
  109. package/dist/contexts/index.mjs +3 -0
  110. package/dist/core/index.cjs +51 -0
  111. package/dist/core/index.d.cts +77 -0
  112. package/dist/core/index.d.cts.map +1 -0
  113. package/dist/core/index.d.mts +77 -0
  114. package/dist/core/index.d.mts.map +1 -0
  115. package/dist/core/index.mjs +4 -0
  116. package/dist/error-state-DErSxZwH.mjs +18 -0
  117. package/dist/error-state-DErSxZwH.mjs.map +1 -0
  118. package/dist/error-state-DSzVUtEl.cjs +24 -0
  119. package/dist/error-state-DSzVUtEl.cjs.map +1 -0
  120. package/dist/fields-4FC6JUNH.d.mts +2 -0
  121. package/dist/fields-DjLFJmz6.d.cts +2 -0
  122. package/dist/fields-wPOk-SmZ.mjs +2 -0
  123. package/dist/rolldown-runtime-wcPFST8Q.mjs +13 -0
  124. package/dist/scroll-arrows-BZIlsE_x.cjs +35 -0
  125. package/dist/scroll-arrows-BZIlsE_x.cjs.map +1 -0
  126. package/dist/scroll-arrows-BevCYRNT.mjs +29 -0
  127. package/dist/scroll-arrows-BevCYRNT.mjs.map +1 -0
  128. package/dist/ui/index.cjs +101 -0
  129. package/dist/ui/index.d.cts +15 -0
  130. package/dist/ui/index.d.cts.map +1 -0
  131. package/dist/ui/index.d.mts +15 -0
  132. package/dist/ui/index.d.mts.map +1 -0
  133. package/dist/ui/index.mjs +3 -0
  134. package/dist/widgets/index.cjs +92 -0
  135. package/dist/widgets/index.cjs.map +1 -0
  136. package/dist/widgets/index.d.cts +689 -0
  137. package/dist/widgets/index.d.cts.map +1 -0
  138. package/dist/widgets/index.d.mts +689 -0
  139. package/dist/widgets/index.d.mts.map +1 -0
  140. package/dist/widgets/index.mjs +46 -0
  141. package/dist/widgets/index.mjs.map +1 -0
  142. package/package.json +104 -0
  143. package/src/styles/globals.css +23 -0
  144. package/src/styles/index.ts +1 -0
  145. package/tailwind.config.ts +61 -0
@@ -0,0 +1,408 @@
1
+ const require_chunk = require("./chunk-CZWwpsFl.cjs");
2
+ const require_error_state = require("./error-state-DSzVUtEl.cjs");
3
+ let react_jsx_runtime = require("react/jsx-runtime");
4
+ let react = require("react");
5
+ let _tanstack_react_query = require("@tanstack/react-query");
6
+ let _fluid_app_portal_core_data_sources_context = require("@fluid-app/portal-core/data-sources/context");
7
+ let _fluid_app_portal_core_data_sources_preview_context = require("@fluid-app/portal-core/data-sources/preview-context");
8
+ let _fortawesome_react_fontawesome = require("@fortawesome/react-fontawesome");
9
+ let _fortawesome_pro_regular_svg_icons = require("@fortawesome/pro-regular-svg-icons");
10
+ let _fluid_app_portal_core_registries = require("@fluid-app/portal-core/registries");
11
+ //#region src/hooks/use-activities.preview.ts
12
+ const now = /* @__PURE__ */ new Date();
13
+ function minutesAgo(minutes) {
14
+ return (/* @__PURE__ */ new Date(now.getTime() - minutes * 6e4)).toISOString();
15
+ }
16
+ const PREVIEW_DATA = [
17
+ {
18
+ id: 1,
19
+ userName: "Sarah Johnson",
20
+ avatarUrl: null,
21
+ activityType: "Order Placed",
22
+ targetName: "Wellness Starter Kit",
23
+ timestamp: minutesAgo(12),
24
+ slug: "order_placed"
25
+ },
26
+ {
27
+ id: 2,
28
+ userName: "Mike Chen",
29
+ avatarUrl: null,
30
+ activityType: "New Lead",
31
+ targetName: "Signed up from Instagram link",
32
+ timestamp: minutesAgo(45),
33
+ slug: "new_lead"
34
+ },
35
+ {
36
+ id: 3,
37
+ userName: "Visitor from Austin, TX",
38
+ avatarUrl: null,
39
+ activityType: "Page Views",
40
+ targetName: "Viewed product catalog (3 pages)",
41
+ timestamp: minutesAgo(90),
42
+ slug: "page_views"
43
+ },
44
+ {
45
+ id: 4,
46
+ userName: "Lisa Park",
47
+ avatarUrl: null,
48
+ activityType: "Video Complete",
49
+ targetName: "Watched: Getting Started Guide",
50
+ timestamp: minutesAgo(180),
51
+ slug: "video_complete"
52
+ }
53
+ ];
54
+ //#endregion
55
+ //#region src/hooks/use-activities.ts
56
+ function useActivities() {
57
+ const { baseUrl, getApiHeaders } = (0, _fluid_app_portal_core_data_sources_context.useDataSourceConfig)();
58
+ const { isPreview } = (0, _fluid_app_portal_core_data_sources_preview_context.useWidgetPreviewContext)();
59
+ return (0, _tanstack_react_query.useQuery)({
60
+ queryKey: [
61
+ "portal-widget-use",
62
+ "activities",
63
+ isPreview ? "preview" : baseUrl
64
+ ],
65
+ queryFn: async ({ signal }) => {
66
+ const url = baseUrl ? `${baseUrl}/v1.1/activities.json` : "/v1.1/activities.json";
67
+ const response = await fetch(url, {
68
+ headers: {
69
+ "content-type": "application/json",
70
+ ...getApiHeaders?.()
71
+ },
72
+ signal
73
+ });
74
+ if (!response.ok) throw new Error(`Failed to fetch activities: ${response.status}`);
75
+ return transformActivities(await response.json());
76
+ },
77
+ enabled: !isPreview,
78
+ ...isPreview && { placeholderData: PREVIEW_DATA }
79
+ });
80
+ }
81
+ function getUserName(contact, visitor) {
82
+ if (contact?.full_name) return contact.full_name;
83
+ if (contact?.first_name && contact?.last_name) return `${contact.first_name} ${contact.last_name}`;
84
+ if (visitor?.city && visitor?.state) return `Visitor from ${visitor.city}, ${visitor.state}`;
85
+ return "Unknown Visitor";
86
+ }
87
+ function transformActivities(rawData) {
88
+ const itemsObj = rawData[1];
89
+ if (!itemsObj?.items) return [];
90
+ return itemsObj.items.map((activity) => ({
91
+ id: activity.id,
92
+ userName: getUserName(activity.contact, activity.visitor),
93
+ avatarUrl: activity.contact?.avatar_url ?? null,
94
+ activityType: formatActivityType(activity.slug),
95
+ targetName: activity.description || activity.title,
96
+ timestamp: activity.created_at,
97
+ slug: activity.slug
98
+ })).sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
99
+ }
100
+ function formatActivityType(slug) {
101
+ return slug.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
102
+ }
103
+ //#endregion
104
+ //#region src/widgets/RecentActivityWidget.tsx
105
+ var RecentActivityWidget_exports = /* @__PURE__ */ require_chunk.__exportAll({
106
+ RecentActivityWidget: () => RecentActivityWidget,
107
+ recentActivityWidgetPropertySchema: () => recentActivityWidgetPropertySchema
108
+ });
109
+ const formatTimestamp = (timestamp) => {
110
+ return new Date(timestamp).toLocaleTimeString("en-US", {
111
+ hour: "numeric",
112
+ minute: "2-digit",
113
+ hour12: true
114
+ });
115
+ };
116
+ const formatDateHeader = (timestamp) => {
117
+ return new Date(timestamp).toLocaleDateString("en-US", {
118
+ month: "long",
119
+ day: "numeric"
120
+ });
121
+ };
122
+ const getDateKey = (timestamp) => {
123
+ return new Date(timestamp).toISOString().split("T")[0] ?? timestamp;
124
+ };
125
+ const groupActivitiesByDate = (activities) => {
126
+ const grouped = /* @__PURE__ */ new Map();
127
+ for (const activity of activities) {
128
+ const dateKey = getDateKey(activity.timestamp);
129
+ const existing = grouped.get(dateKey);
130
+ if (existing) existing.push(activity);
131
+ else grouped.set(dateKey, [activity]);
132
+ }
133
+ return grouped;
134
+ };
135
+ const ACTIVITY_ICON_MAP = {
136
+ order_placed: _fortawesome_pro_regular_svg_icons.faCartShopping,
137
+ abandoned_cart: _fortawesome_pro_regular_svg_icons.faCartShopping,
138
+ cart_items_added: _fortawesome_pro_regular_svg_icons.faCartShopping,
139
+ new_cart_items_added: _fortawesome_pro_regular_svg_icons.faCartShopping,
140
+ direct_message: _fortawesome_pro_regular_svg_icons.faComment,
141
+ comment_reply: _fortawesome_pro_regular_svg_icons.faComment,
142
+ message_received: _fortawesome_pro_regular_svg_icons.faComment,
143
+ message_sent: _fortawesome_pro_regular_svg_icons.faComment,
144
+ video: _fortawesome_pro_regular_svg_icons.faPlay,
145
+ video_complete: _fortawesome_pro_regular_svg_icons.faPlay,
146
+ video_contact: _fortawesome_pro_regular_svg_icons.faPlay,
147
+ video_complete_contact: _fortawesome_pro_regular_svg_icons.faPlay,
148
+ new_lead: _fortawesome_pro_regular_svg_icons.faUserPlus,
149
+ page_views_contact: _fortawesome_pro_regular_svg_icons.faUserPlus,
150
+ smart_link_clicked: _fortawesome_pro_regular_svg_icons.faUserPlus,
151
+ page_views: _fortawesome_pro_regular_svg_icons.faEye,
152
+ upcoming_event: _fortawesome_pro_regular_svg_icons.faCalendar,
153
+ review_left: _fortawesome_pro_regular_svg_icons.faStar,
154
+ tasks: _fortawesome_pro_regular_svg_icons.faSquareCheck,
155
+ announcements: _fortawesome_pro_regular_svg_icons.faBell,
156
+ fantasy_point: _fortawesome_pro_regular_svg_icons.faTrophy
157
+ };
158
+ const getActivityIcon = (slug) => ACTIVITY_ICON_MAP[slug] ?? _fortawesome_pro_regular_svg_icons.faUser;
159
+ function ActivityFeedItem({ activity, accentColor, textColor }) {
160
+ const icon = getActivityIcon(activity.slug);
161
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
162
+ className: "flex w-full items-start gap-1.5",
163
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
164
+ className: "shrink-0",
165
+ children: activity.avatarUrl ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
166
+ className: "relative size-8 overflow-hidden rounded-full",
167
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
168
+ src: activity.avatarUrl,
169
+ alt: activity.userName,
170
+ className: "size-full object-cover"
171
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "border-foreground/[0.08] absolute inset-0 rounded-full border" })]
172
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
173
+ className: `bg-muted flex size-8 items-center justify-center rounded-full`,
174
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_fortawesome_react_fontawesome.FontAwesomeIcon, {
175
+ icon,
176
+ className: `size-3.5 text-${textColor} opacity-60`
177
+ })
178
+ })
179
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
180
+ className: "min-w-0 flex-1",
181
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
182
+ className: "flex w-full items-center gap-1.5",
183
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
184
+ className: `flex-1 text-base font-semibold text-${textColor} truncate`,
185
+ children: activity.activityType
186
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
187
+ className: `text-xs text-${textColor} shrink-0 opacity-50`,
188
+ children: formatTimestamp(activity.timestamp)
189
+ })]
190
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
191
+ className: `text-sm text-${textColor} opacity-80`,
192
+ children: [
193
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
194
+ className: `font-medium text-${accentColor}`,
195
+ children: activity.userName
196
+ }),
197
+ " ",
198
+ activity.targetName
199
+ ]
200
+ })]
201
+ })]
202
+ });
203
+ }
204
+ function RecentActivityWidget({ titleEnabled = true, titleText = "Recent Activity", titleFontSize = "lg", titleColor = "foreground", background = {
205
+ type: "solid",
206
+ color: "background"
207
+ }, textColor = "foreground", accentColor = "primary", padding = 4, borderRadius = "md", maxItemsToShow = 5, className, ...props }) {
208
+ const backgroundColor = background.color || "background";
209
+ const backgroundImage = (background.resource?.image_url || background.resource?.imageUrl) && background.type === "image" ? `url(${background.resource.image_url || background.resource.imageUrl})` : "none";
210
+ const { data: activities = [], isLoading, isError } = useActivities();
211
+ const groupedActivities = (0, react.useMemo)(() => groupActivitiesByDate(activities), [activities]);
212
+ const totalCount = Math.min(activities.length, maxItemsToShow);
213
+ const activitiesToShow = (0, react.useMemo)(() => {
214
+ const result = [];
215
+ let count = 0;
216
+ for (const [dateKey, items] of groupedActivities) {
217
+ if (count >= maxItemsToShow) break;
218
+ const remainingSlots = maxItemsToShow - count;
219
+ const itemsToAdd = items.slice(0, remainingSlots);
220
+ if (itemsToAdd.length > 0) {
221
+ result.push({
222
+ date: formatDateHeader(items[0]?.timestamp ?? dateKey),
223
+ items: itemsToAdd
224
+ });
225
+ count += itemsToAdd.length;
226
+ }
227
+ }
228
+ return result;
229
+ }, [groupedActivities, maxItemsToShow]);
230
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
231
+ className: `@container overflow-hidden rounded-${borderRadius} bg-${backgroundColor} text-${textColor} border-muted border ${className}`,
232
+ style: { backgroundImage },
233
+ ...props,
234
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
235
+ className: `p-${padding} flex flex-col gap-2`,
236
+ children: [titleEnabled && titleText && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
237
+ className: "flex w-full items-start gap-2",
238
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
239
+ className: `flex-1 text-${titleFontSize} font-bold text-${titleColor}`,
240
+ children: titleText
241
+ }), !isLoading && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
242
+ className: `text-4xl font-bold text-${textColor} leading-none`,
243
+ children: totalCount.toString().padStart(2, "0")
244
+ })]
245
+ }), isLoading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
246
+ className: "flex min-h-[200px] items-center justify-center",
247
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "h-8 w-8 animate-spin rounded-full border-2 border-current border-t-transparent" })
248
+ }) : isError ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_error_state.ErrorState, {}) : activities.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
249
+ className: "flex min-h-[200px] flex-col items-center justify-center gap-2",
250
+ children: [
251
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_fortawesome_react_fontawesome.FontAwesomeIcon, {
252
+ icon: _fortawesome_pro_regular_svg_icons.faUser,
253
+ className: `size-12 text-${textColor} opacity-30`
254
+ }),
255
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
256
+ className: `text-base font-semibold text-${textColor} opacity-50`,
257
+ children: "No Activity To Report"
258
+ }),
259
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
260
+ className: `text-sm text-${textColor} opacity-40`,
261
+ children: "You'll Do Great!"
262
+ })
263
+ ]
264
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
265
+ className: "flex flex-col gap-4",
266
+ children: activitiesToShow.map((group, groupIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
267
+ className: "flex flex-col gap-4",
268
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
269
+ className: `text-base font-semibold text-${textColor}`,
270
+ children: group.date
271
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
272
+ className: "flex flex-col gap-4",
273
+ children: group.items.map((activity) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActivityFeedItem, {
274
+ activity,
275
+ accentColor,
276
+ textColor
277
+ }, activity.id))
278
+ })]
279
+ }, groupIndex))
280
+ })]
281
+ })
282
+ });
283
+ }
284
+ const recentActivityWidgetPropertySchema = {
285
+ widgetType: "RecentActivityWidget",
286
+ displayName: "Recent Activity Widget",
287
+ tabsConfig: [{
288
+ id: "styling",
289
+ label: "Styling"
290
+ }],
291
+ fields: [
292
+ {
293
+ key: "titleEnabled",
294
+ label: "Widget Title",
295
+ type: "boolean",
296
+ description: "Enable the title displayed above the activity feed",
297
+ defaultValue: true,
298
+ tab: "styling",
299
+ group: "Title"
300
+ },
301
+ {
302
+ key: "titleText",
303
+ label: "Title",
304
+ type: "text",
305
+ description: "Title text displayed above the activity feed",
306
+ defaultValue: "Recent Activity",
307
+ tab: "styling",
308
+ group: "Title",
309
+ requiresKeyToBeTrue: "titleEnabled"
310
+ },
311
+ (0, _fluid_app_portal_core_registries.getFontSizeField)({
312
+ key: "titleFontSize",
313
+ label: "Title Font Size",
314
+ description: "Font size for the widget title",
315
+ defaultValue: "xl",
316
+ tab: "styling",
317
+ group: "Title",
318
+ requiresKeyToBeTrue: "titleEnabled"
319
+ }),
320
+ (0, _fluid_app_portal_core_registries.getColorField)({
321
+ key: "titleColor",
322
+ label: "Title Color",
323
+ description: "Color for the widget title",
324
+ defaultValue: "foreground",
325
+ tab: "styling",
326
+ group: "Title",
327
+ requiresKeyToBeTrue: "titleEnabled"
328
+ }),
329
+ {
330
+ type: "background",
331
+ key: "background",
332
+ label: "Background",
333
+ description: "Background for the widget container",
334
+ defaultValue: "background",
335
+ tab: "styling",
336
+ group: "Design"
337
+ },
338
+ (0, _fluid_app_portal_core_registries.getColorField)({
339
+ key: "textColor",
340
+ label: "Text Color",
341
+ description: "Default text color for activity content",
342
+ defaultValue: "foreground",
343
+ tab: "styling",
344
+ group: "Design"
345
+ }),
346
+ (0, _fluid_app_portal_core_registries.getColorField)({
347
+ key: "accentColor",
348
+ label: "Accent Color",
349
+ description: "Color used for links and highlights",
350
+ defaultValue: "primary",
351
+ tab: "styling",
352
+ group: "Design"
353
+ }),
354
+ {
355
+ key: "separator",
356
+ type: "separator",
357
+ label: "Separator",
358
+ tab: "styling",
359
+ group: "Design"
360
+ },
361
+ (0, _fluid_app_portal_core_registries.getPaddingField)({
362
+ key: "padding",
363
+ label: "Padding",
364
+ description: "Padding around the widget container",
365
+ defaultValue: 4,
366
+ tab: "styling",
367
+ group: "Design"
368
+ }),
369
+ (0, _fluid_app_portal_core_registries.getBorderRadiusField)({
370
+ key: "borderRadius",
371
+ label: "Border Radius",
372
+ description: "Border radius for the widget container",
373
+ defaultValue: "md",
374
+ tab: "styling",
375
+ group: "Design"
376
+ }),
377
+ {
378
+ key: "maxItemsToShow",
379
+ label: "Max Items",
380
+ type: "number",
381
+ description: "Maximum number of activity items to display",
382
+ defaultValue: 5,
383
+ tab: "styling",
384
+ group: "Display"
385
+ }
386
+ ]
387
+ };
388
+ //#endregion
389
+ Object.defineProperty(exports, "RecentActivityWidget", {
390
+ enumerable: true,
391
+ get: function() {
392
+ return RecentActivityWidget;
393
+ }
394
+ });
395
+ Object.defineProperty(exports, "RecentActivityWidget_exports", {
396
+ enumerable: true,
397
+ get: function() {
398
+ return RecentActivityWidget_exports;
399
+ }
400
+ });
401
+ Object.defineProperty(exports, "recentActivityWidgetPropertySchema", {
402
+ enumerable: true,
403
+ get: function() {
404
+ return recentActivityWidgetPropertySchema;
405
+ }
406
+ });
407
+
408
+ //# sourceMappingURL=RecentActivityWidget-wODng8dt.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RecentActivityWidget-wODng8dt.cjs","names":["faCartShopping","faComment","faPlay","faUserPlus","faEye","faCalendar","faStar","faSquareCheck","faBell","faTrophy","faUser","FontAwesomeIcon","ErrorState"],"sources":["../src/hooks/use-activities.preview.ts","../src/hooks/use-activities.ts","../src/widgets/RecentActivityWidget.tsx"],"sourcesContent":["import type { Activity } from \"./use-activities.types\";\n\nconst now = new Date();\n\nfunction minutesAgo(minutes: number): string {\n return new Date(now.getTime() - minutes * 60_000).toISOString();\n}\n\nexport const PREVIEW_DATA: Activity[] = [\n {\n id: 1,\n userName: \"Sarah Johnson\",\n avatarUrl: null,\n activityType: \"Order Placed\",\n targetName: \"Wellness Starter Kit\",\n timestamp: minutesAgo(12),\n slug: \"order_placed\",\n },\n {\n id: 2,\n userName: \"Mike Chen\",\n avatarUrl: null,\n activityType: \"New Lead\",\n targetName: \"Signed up from Instagram link\",\n timestamp: minutesAgo(45),\n slug: \"new_lead\",\n },\n {\n id: 3,\n userName: \"Visitor from Austin, TX\",\n avatarUrl: null,\n activityType: \"Page Views\",\n targetName: \"Viewed product catalog (3 pages)\",\n timestamp: minutesAgo(90),\n slug: \"page_views\",\n },\n {\n id: 4,\n userName: \"Lisa Park\",\n avatarUrl: null,\n activityType: \"Video Complete\",\n targetName: \"Watched: Getting Started Guide\",\n timestamp: minutesAgo(180),\n slug: \"video_complete\",\n },\n];\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useDataSourceConfig } from \"@fluid-app/portal-core/data-sources/context\";\nimport { useWidgetPreviewContext } from \"@fluid-app/portal-core/data-sources/preview-context\";\nimport { PREVIEW_DATA } from \"./use-activities.preview\";\nimport type {\n Activity,\n ActivityContact,\n ActivityVisitor,\n ApiActivity,\n} from \"./use-activities.types\";\n\nexport type {\n ActivityContact,\n ActivityVisitor,\n ActivitySlug,\n ApiActivity,\n Activity,\n} from \"./use-activities.types\";\n\ntype PaginationInfo = {\n current: number;\n previous: number | null;\n next: number | null;\n per_page: number;\n pages: number;\n count: number;\n};\n\ntype ApiResponse = [{ pagination: PaginationInfo }, { items: ApiActivity[] }];\n\nexport function useActivities(): UseQueryResult<Activity[], Error> {\n const { baseUrl, getApiHeaders } = useDataSourceConfig();\n const { isPreview } = useWidgetPreviewContext();\n\n return useQuery({\n queryKey: [\n \"portal-widget-use\",\n \"activities\",\n isPreview ? \"preview\" : baseUrl,\n ] as const,\n queryFn: async ({ signal }): Promise<Activity[]> => {\n const url = baseUrl\n ? `${baseUrl}/v1.1/activities.json`\n : \"/v1.1/activities.json\";\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 activities: ${response.status}`);\n }\n\n const data: ApiResponse = await response.json();\n return transformActivities(data);\n },\n enabled: !isPreview,\n ...(isPreview && { placeholderData: PREVIEW_DATA }),\n });\n}\n\n// Transform and format helpers\nfunction getUserName(\n contact: ActivityContact | null,\n visitor: ActivityVisitor | null,\n): string {\n if (contact?.full_name) {\n return contact.full_name;\n }\n if (contact?.first_name && contact?.last_name) {\n return `${contact.first_name} ${contact.last_name}`;\n }\n if (visitor?.city && visitor?.state) {\n return `Visitor from ${visitor.city}, ${visitor.state}`;\n }\n return \"Unknown Visitor\";\n}\n\nfunction transformActivities(rawData: ApiResponse): Activity[] {\n const itemsObj = rawData[1];\n if (!itemsObj?.items) return [];\n\n return itemsObj.items\n .map((activity) => ({\n id: activity.id,\n userName: getUserName(activity.contact, activity.visitor),\n avatarUrl: activity.contact?.avatar_url ?? null,\n activityType: formatActivityType(activity.slug),\n targetName: activity.description || activity.title,\n timestamp: activity.created_at,\n slug: activity.slug,\n }))\n .sort(\n (a, b) =>\n new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime(),\n );\n}\n\nfunction formatActivityType(slug: string): string {\n return slug\n .split(\"_\")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \");\n}\n","import { useMemo, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n} from \"../core/fields\";\nimport {\n useActivities,\n type Activity,\n type ActivitySlug,\n} from \"../hooks/use-activities\";\nimport { ErrorState } from \"../components/error-state\";\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\nimport type { IconDefinition } from \"@fortawesome/fontawesome-svg-core\";\nimport {\n faBell,\n faCalendar,\n faSquareCheck,\n faEye,\n faComment,\n faPlay,\n faCartShopping,\n faStar,\n faTrophy,\n faUser,\n faUserPlus,\n} from \"@fortawesome/pro-regular-svg-icons\";\n\n// Format timestamp to time string\nconst formatTimestamp = (timestamp: string): string => {\n const date = new Date(timestamp);\n return date.toLocaleTimeString(\"en-US\", {\n hour: \"numeric\",\n minute: \"2-digit\",\n hour12: true,\n });\n};\n\n// Format date for grouping header\nconst formatDateHeader = (timestamp: string): string => {\n const date = new Date(timestamp);\n return date.toLocaleDateString(\"en-US\", {\n month: \"long\",\n day: \"numeric\",\n });\n};\n\n// Get date string for grouping (without time)\nconst getDateKey = (timestamp: string): string => {\n const date = new Date(timestamp);\n return date.toISOString().split(\"T\")[0] ?? timestamp;\n};\n\n// Group activities by date\nconst groupActivitiesByDate = (\n activities: Activity[],\n): Map<string, Activity[]> => {\n const grouped = new Map<string, Activity[]>();\n\n for (const activity of activities) {\n const dateKey = getDateKey(activity.timestamp);\n const existing = grouped.get(dateKey);\n if (existing) {\n existing.push(activity);\n } else {\n grouped.set(dateKey, [activity]);\n }\n }\n\n return grouped;\n};\n\n// Activity slug to icon mapping\nconst ACTIVITY_ICON_MAP: Record<ActivitySlug, IconDefinition> = {\n // Orders/Cart\n order_placed: faCartShopping,\n abandoned_cart: faCartShopping,\n cart_items_added: faCartShopping,\n new_cart_items_added: faCartShopping,\n // Messages\n direct_message: faComment,\n comment_reply: faComment,\n message_received: faComment,\n message_sent: faComment,\n // Video\n video: faPlay,\n video_complete: faPlay,\n video_contact: faPlay,\n video_complete_contact: faPlay,\n // Leads\n new_lead: faUserPlus,\n page_views_contact: faUserPlus,\n smart_link_clicked: faUserPlus,\n // Page Views\n page_views: faEye,\n // Events\n upcoming_event: faCalendar,\n // Reviews\n review_left: faStar,\n // Tasks\n tasks: faSquareCheck,\n // Announcements\n announcements: faBell,\n // Fantasy\n fantasy_point: faTrophy,\n};\n\nconst getActivityIcon = (slug: ActivitySlug) =>\n ACTIVITY_ICON_MAP[slug] ?? faUser;\n\n// Activity feed item component\ntype ActivityFeedItemProps = {\n activity: Activity;\n accentColor: ColorOptions;\n textColor: ColorOptions;\n};\n\nfunction ActivityFeedItem({\n activity,\n accentColor,\n textColor,\n}: ActivityFeedItemProps) {\n const icon = getActivityIcon(activity.slug);\n\n return (\n <div className=\"flex w-full items-start gap-1.5\">\n {/* Avatar */}\n <div className=\"shrink-0\">\n {activity.avatarUrl ? (\n <div className=\"relative size-8 overflow-hidden rounded-full\">\n <img\n src={activity.avatarUrl}\n alt={activity.userName}\n className=\"size-full object-cover\"\n />\n <div className=\"border-foreground/[0.08] absolute inset-0 rounded-full border\" />\n </div>\n ) : (\n <div\n className={`bg-muted flex size-8 items-center justify-center rounded-full`}\n >\n <FontAwesomeIcon\n icon={icon}\n className={`size-3.5 text-${textColor} opacity-60`}\n />\n </div>\n )}\n </div>\n\n {/* Content */}\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex w-full items-center gap-1.5\">\n <p\n className={`flex-1 text-base font-semibold text-${textColor} truncate`}\n >\n {activity.activityType}\n </p>\n <p className={`text-xs text-${textColor} shrink-0 opacity-50`}>\n {formatTimestamp(activity.timestamp)}\n </p>\n </div>\n <p className={`text-sm text-${textColor} opacity-80`}>\n <span className={`font-medium text-${accentColor}`}>\n {activity.userName}\n </span>{\" \"}\n {activity.targetName}\n </p>\n </div>\n </div>\n );\n}\n\ntype RecentActivityWidgetProps = 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\n // Activity settings\n maxItemsToShow?: number;\n};\n\nexport function RecentActivityWidget({\n // Title defaults\n titleEnabled = true,\n titleText = \"Recent Activity\",\n titleFontSize = \"lg\",\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\n // Activity defaults\n maxItemsToShow = 5,\n\n className,\n ...props\n}: RecentActivityWidgetProps): 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 { data: activities = [], isLoading, isError } = useActivities();\n\n const groupedActivities = useMemo(\n () => groupActivitiesByDate(activities),\n [activities],\n );\n\n const totalCount = Math.min(activities.length, maxItemsToShow);\n\n // Get activities to display (limited by maxItemsToShow)\n const activitiesToShow = useMemo(() => {\n const result: { date: string; items: Activity[] }[] = [];\n let count = 0;\n\n for (const [dateKey, items] of groupedActivities) {\n if (count >= maxItemsToShow) break;\n\n const remainingSlots = maxItemsToShow - count;\n const itemsToAdd = items.slice(0, remainingSlots);\n\n if (itemsToAdd.length > 0) {\n result.push({\n date: formatDateHeader(items[0]?.timestamp ?? dateKey),\n items: itemsToAdd,\n });\n count += itemsToAdd.length;\n }\n }\n\n return result;\n }, [groupedActivities, maxItemsToShow]);\n\n return (\n <div\n className={`@container overflow-hidden rounded-${borderRadius} bg-${backgroundColor} text-${textColor} border-muted border ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n <div className={`p-${padding} flex flex-col gap-2`}>\n {/* Header */}\n {titleEnabled && titleText && (\n <div className=\"flex w-full items-start gap-2\">\n <h2\n className={`flex-1 text-${titleFontSize} font-bold text-${titleColor}`}\n >\n {titleText}\n </h2>\n {!isLoading && (\n <span\n className={`text-4xl font-bold text-${textColor} leading-none`}\n >\n {totalCount.toString().padStart(2, \"0\")}\n </span>\n )}\n </div>\n )}\n\n {/* Loading state */}\n {isLoading ? (\n <div className=\"flex min-h-[200px] items-center justify-center\">\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 ) : activities.length === 0 ? (\n /* Empty state */\n <div className=\"flex min-h-[200px] flex-col items-center justify-center gap-2\">\n <FontAwesomeIcon\n icon={faUser}\n className={`size-12 text-${textColor} opacity-30`}\n />\n <p\n className={`text-base font-semibold text-${textColor} opacity-50`}\n >\n No Activity To Report\n </p>\n <p className={`text-sm text-${textColor} opacity-40`}>\n You&apos;ll Do Great!\n </p>\n </div>\n ) : (\n /* Activity list */\n <div className=\"flex flex-col gap-4\">\n {activitiesToShow.map((group, groupIndex) => (\n <div key={groupIndex} className=\"flex flex-col gap-4\">\n {/* Date header */}\n <p className={`text-base font-semibold text-${textColor}`}>\n {group.date}\n </p>\n\n {/* Activity items */}\n <div className=\"flex flex-col gap-4\">\n {group.items.map((activity) => (\n <ActivityFeedItem\n key={activity.id}\n activity={activity}\n accentColor={accentColor}\n textColor={textColor}\n />\n ))}\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n\nexport const recentActivityWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"RecentActivityWidget\",\n displayName: \"Recent Activity 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 activity feed\",\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 activity feed\",\n defaultValue: \"Recent Activity\",\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 widget 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 activity 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 links and highlights\",\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 widget 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 widget container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n\n // Styling Tab - Display Group\n {\n key: \"maxItemsToShow\",\n label: \"Max Items\",\n type: \"number\",\n description: \"Maximum number of activity items to display\",\n defaultValue: 5,\n tab: \"styling\",\n group: \"Display\",\n },\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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P,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;uDACY;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;EAGF;GACE,MAAM;GACN,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;uDACa;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;uDACY;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,MAAM;GACN,OAAO;GACP,KAAK;GACL,OAAO;GACR;yDACe;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;8DACmB;GACnB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EAGF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACF;CACF"}
@@ -0,0 +1,36 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext } from "react";
3
+ //#region src/contexts/RegistryContext.tsx
4
+ /**
5
+ * Context for providing the widget registry to all components in the tree.
6
+ * This eliminates prop drilling and makes the registry accessible anywhere.
7
+ *
8
+ * Default to undefined - registry must be provided by a RegistryProvider.
9
+ */
10
+ const RegistryContext = createContext(void 0);
11
+ /**
12
+ * Provider component that makes the widget registry available to all descendants.
13
+ * A registry must be provided either via props or by nesting within another RegistryProvider.
14
+ */
15
+ function RegistryProvider({ registry, children }) {
16
+ const parentRegistry = useContext(RegistryContext);
17
+ const contextValue = registry ?? parentRegistry;
18
+ if (!contextValue) throw new Error("RegistryProvider requires a registry prop or must be nested within another RegistryProvider.");
19
+ return /* @__PURE__ */ jsx(RegistryContext.Provider, {
20
+ value: contextValue,
21
+ children
22
+ });
23
+ }
24
+ /**
25
+ * Hook to access the widget registry from anywhere in the component tree.
26
+ * Must be used within a RegistryProvider that has a registry prop.
27
+ */
28
+ function useRegistry() {
29
+ const registry = useContext(RegistryContext);
30
+ if (!registry) throw new Error("useRegistry must be used within a RegistryProvider with a registry prop.");
31
+ return registry;
32
+ }
33
+ //#endregion
34
+ export { RegistryProvider as n, useRegistry as r, RegistryContext as t };
35
+
36
+ //# sourceMappingURL=RegistryContext-CscXrsRa.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RegistryContext-CscXrsRa.mjs","names":[],"sources":["../src/contexts/RegistryContext.tsx"],"sourcesContent":["import React, {\n createContext,\n useContext,\n type ComponentType,\n type ReactNode,\n} from \"react\";\nimport type { WidgetSchema } from \"@fluid-app/portal-core/types\";\n\n/**\n * Base props interface for widget components.\n * All widgets receive at least these props from the ScreenRenderer.\n */\nexport interface WidgetBaseProps {\n readonly widget: WidgetSchema;\n readonly path?: readonly number[];\n}\n\n/**\n * Generic widget component type.\n * Widgets receive WidgetBaseProps and may have additional props.\n */\nexport type WidgetComponent<P extends WidgetBaseProps = WidgetBaseProps> =\n ComponentType<P>;\n\n/**\n * Registry mapping widget type names to their components.\n * The keys are widget type strings (e.g., \"TextWidget\", \"ButtonWidget\").\n * Using WidgetComponent for the value type provides better type safety than `any`.\n */\nexport type WidgetRegistry = Readonly<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Widget props vary by type\n Record<string, WidgetComponent<any>>\n>;\n\n/**\n * Context for providing the widget registry to all components in the tree.\n * This eliminates prop drilling and makes the registry accessible anywhere.\n *\n * Default to undefined - registry must be provided by a RegistryProvider.\n */\nexport const RegistryContext: React.Context<WidgetRegistry | undefined> =\n createContext<WidgetRegistry | undefined>(undefined);\n\nexport interface RegistryProviderProps {\n registry?: WidgetRegistry;\n children: ReactNode;\n}\n\n/**\n * Provider component that makes the widget registry available to all descendants.\n * A registry must be provided either via props or by nesting within another RegistryProvider.\n */\nexport function RegistryProvider({\n registry,\n children,\n}: RegistryProviderProps): React.JSX.Element {\n // If no registry provided, inherit from parent provider\n const parentRegistry = useContext(RegistryContext);\n const contextValue = registry ?? parentRegistry;\n\n if (!contextValue) {\n throw new Error(\n \"RegistryProvider requires a registry prop or must be nested within another RegistryProvider.\",\n );\n }\n\n return (\n <RegistryContext.Provider value={contextValue}>\n {children}\n </RegistryContext.Provider>\n );\n}\n\n/**\n * Hook to access the widget registry from anywhere in the component tree.\n * Must be used within a RegistryProvider that has a registry prop.\n */\nexport function useRegistry(): WidgetRegistry {\n const registry = useContext(RegistryContext);\n\n if (!registry) {\n throw new Error(\n \"useRegistry must be used within a RegistryProvider with a registry prop.\",\n );\n }\n\n return registry;\n}\n"],"mappings":";;;;;;;;;AAwCA,MAAa,kBACX,cAA0C,KAAA,EAAU;;;;;AAWtD,SAAgB,iBAAiB,EAC/B,UACA,YAC2C;CAE3C,MAAM,iBAAiB,WAAW,gBAAgB;CAClD,MAAM,eAAe,YAAY;AAEjC,KAAI,CAAC,aACH,OAAM,IAAI,MACR,+FACD;AAGH,QACE,oBAAC,gBAAgB,UAAjB;EAA0B,OAAO;EAC9B;EACwB,CAAA;;;;;;AAQ/B,SAAgB,cAA8B;CAC5C,MAAM,WAAW,WAAW,gBAAgB;AAE5C,KAAI,CAAC,SACH,OAAM,IAAI,MACR,2EACD;AAGH,QAAO"}
@@ -0,0 +1,55 @@
1
+ const require_chunk = require("./chunk-CZWwpsFl.cjs");
2
+ let react_jsx_runtime = require("react/jsx-runtime");
3
+ let react = require("react");
4
+ react = require_chunk.__toESM(react);
5
+ //#region src/contexts/RegistryContext.tsx
6
+ /**
7
+ * Context for providing the widget registry to all components in the tree.
8
+ * This eliminates prop drilling and makes the registry accessible anywhere.
9
+ *
10
+ * Default to undefined - registry must be provided by a RegistryProvider.
11
+ */
12
+ const RegistryContext = (0, react.createContext)(void 0);
13
+ /**
14
+ * Provider component that makes the widget registry available to all descendants.
15
+ * A registry must be provided either via props or by nesting within another RegistryProvider.
16
+ */
17
+ function RegistryProvider({ registry, children }) {
18
+ const parentRegistry = (0, react.useContext)(RegistryContext);
19
+ const contextValue = registry ?? parentRegistry;
20
+ if (!contextValue) throw new Error("RegistryProvider requires a registry prop or must be nested within another RegistryProvider.");
21
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RegistryContext.Provider, {
22
+ value: contextValue,
23
+ children
24
+ });
25
+ }
26
+ /**
27
+ * Hook to access the widget registry from anywhere in the component tree.
28
+ * Must be used within a RegistryProvider that has a registry prop.
29
+ */
30
+ function useRegistry() {
31
+ const registry = (0, react.useContext)(RegistryContext);
32
+ if (!registry) throw new Error("useRegistry must be used within a RegistryProvider with a registry prop.");
33
+ return registry;
34
+ }
35
+ //#endregion
36
+ Object.defineProperty(exports, "RegistryContext", {
37
+ enumerable: true,
38
+ get: function() {
39
+ return RegistryContext;
40
+ }
41
+ });
42
+ Object.defineProperty(exports, "RegistryProvider", {
43
+ enumerable: true,
44
+ get: function() {
45
+ return RegistryProvider;
46
+ }
47
+ });
48
+ Object.defineProperty(exports, "useRegistry", {
49
+ enumerable: true,
50
+ get: function() {
51
+ return useRegistry;
52
+ }
53
+ });
54
+
55
+ //# sourceMappingURL=RegistryContext-xjea4xVV.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RegistryContext-xjea4xVV.cjs","names":[],"sources":["../src/contexts/RegistryContext.tsx"],"sourcesContent":["import React, {\n createContext,\n useContext,\n type ComponentType,\n type ReactNode,\n} from \"react\";\nimport type { WidgetSchema } from \"@fluid-app/portal-core/types\";\n\n/**\n * Base props interface for widget components.\n * All widgets receive at least these props from the ScreenRenderer.\n */\nexport interface WidgetBaseProps {\n readonly widget: WidgetSchema;\n readonly path?: readonly number[];\n}\n\n/**\n * Generic widget component type.\n * Widgets receive WidgetBaseProps and may have additional props.\n */\nexport type WidgetComponent<P extends WidgetBaseProps = WidgetBaseProps> =\n ComponentType<P>;\n\n/**\n * Registry mapping widget type names to their components.\n * The keys are widget type strings (e.g., \"TextWidget\", \"ButtonWidget\").\n * Using WidgetComponent for the value type provides better type safety than `any`.\n */\nexport type WidgetRegistry = Readonly<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Widget props vary by type\n Record<string, WidgetComponent<any>>\n>;\n\n/**\n * Context for providing the widget registry to all components in the tree.\n * This eliminates prop drilling and makes the registry accessible anywhere.\n *\n * Default to undefined - registry must be provided by a RegistryProvider.\n */\nexport const RegistryContext: React.Context<WidgetRegistry | undefined> =\n createContext<WidgetRegistry | undefined>(undefined);\n\nexport interface RegistryProviderProps {\n registry?: WidgetRegistry;\n children: ReactNode;\n}\n\n/**\n * Provider component that makes the widget registry available to all descendants.\n * A registry must be provided either via props or by nesting within another RegistryProvider.\n */\nexport function RegistryProvider({\n registry,\n children,\n}: RegistryProviderProps): React.JSX.Element {\n // If no registry provided, inherit from parent provider\n const parentRegistry = useContext(RegistryContext);\n const contextValue = registry ?? parentRegistry;\n\n if (!contextValue) {\n throw new Error(\n \"RegistryProvider requires a registry prop or must be nested within another RegistryProvider.\",\n );\n }\n\n return (\n <RegistryContext.Provider value={contextValue}>\n {children}\n </RegistryContext.Provider>\n );\n}\n\n/**\n * Hook to access the widget registry from anywhere in the component tree.\n * Must be used within a RegistryProvider that has a registry prop.\n */\nexport function useRegistry(): WidgetRegistry {\n const registry = useContext(RegistryContext);\n\n if (!registry) {\n throw new Error(\n \"useRegistry must be used within a RegistryProvider with a registry prop.\",\n );\n }\n\n return registry;\n}\n"],"mappings":";;;;;;;;;;;AAwCA,MAAa,mBAAA,GAAA,MAAA,eAC+B,KAAA,EAAU;;;;;AAWtD,SAAgB,iBAAiB,EAC/B,UACA,YAC2C;CAE3C,MAAM,kBAAA,GAAA,MAAA,YAA4B,gBAAgB;CAClD,MAAM,eAAe,YAAY;AAEjC,KAAI,CAAC,aACH,OAAM,IAAI,MACR,+FACD;AAGH,QACE,iBAAA,GAAA,kBAAA,KAAC,gBAAgB,UAAjB;EAA0B,OAAO;EAC9B;EACwB,CAAA;;;;;;AAQ/B,SAAgB,cAA8B;CAC5C,MAAM,YAAA,GAAA,MAAA,YAAsB,gBAAgB;AAE5C,KAAI,CAAC,SACH,OAAM,IAAI,MACR,2EACD;AAGH,QAAO"}
@@ -0,0 +1,76 @@
1
+ import { n as RegistryProvider, r as useRegistry } from "./RegistryContext-CscXrsRa.mjs";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { useCallback } from "react";
4
+ import { WIDGET_TYPE_NAMES } from "@fluid-app/portal-core/types";
5
+ //#region src/core/ScreenRenderer.tsx
6
+ /**
7
+ * Internal component that uses the registry from context.
8
+ * This allows us to avoid prop drilling the registry.
9
+ */
10
+ function ScreenRendererContent({ screen, containerWidgetTypes, className }) {
11
+ const registry = useRegistry();
12
+ const isContainerWidget = useCallback((widgetType) => containerWidgetTypes.includes(widgetType), [containerWidgetTypes]);
13
+ const renderWidget = useCallback((widget, index, currentPath) => {
14
+ const Component = registry[widget.type];
15
+ if (!Component) {
16
+ console.warn(`Widget type "${String(widget.type)}" not found in registry`);
17
+ return null;
18
+ }
19
+ const widgetPath = [...currentPath, index];
20
+ const additionalProps = isContainerWidget(widget.type) ? {
21
+ widgetId: widget.id,
22
+ widgetPath
23
+ } : {};
24
+ return /* @__PURE__ */ jsx("div", {
25
+ className: "h-full w-full overflow-x-hidden",
26
+ children: /* @__PURE__ */ jsx(Component, {
27
+ ...widget.props,
28
+ ...additionalProps
29
+ })
30
+ }, widget.id || index);
31
+ }, [registry, isContainerWidget]);
32
+ return /* @__PURE__ */ jsx("div", {
33
+ className: className || "h-full w-full",
34
+ children: screen?.map((item, index) => {
35
+ if (!item) return null;
36
+ return renderWidget(item, index, []);
37
+ })
38
+ });
39
+ }
40
+ /**
41
+ * ScreenRenderer - View-only component for rendering widget screens.
42
+ *
43
+ * This is a simplified version designed for the SDK that only handles
44
+ * rendering widgets without edit mode or drag-and-drop functionality.
45
+ *
46
+ * Features:
47
+ * - Static rendering of widgets
48
+ * - Registry context: No prop drilling for widget registry
49
+ * - Container widget support with path tracking
50
+ *
51
+ * Usage:
52
+ * ```tsx
53
+ * import { ScreenRenderer } from '@fluid-app/portal-widgets/core';
54
+ * import { WIDGET_REGISTRY } from '@fluid-app/portal-widgets/widgets';
55
+ *
56
+ * <ScreenRenderer
57
+ * screen={widgets}
58
+ * registry={WIDGET_REGISTRY}
59
+ * />
60
+ * ```
61
+ */
62
+ function ScreenRenderer(props) {
63
+ const { screen, registry, containerWidgetTypes = [WIDGET_TYPE_NAMES.Layout, WIDGET_TYPE_NAMES.Container], className } = props;
64
+ return /* @__PURE__ */ jsx(RegistryProvider, {
65
+ ...registry !== void 0 ? { registry } : {},
66
+ children: /* @__PURE__ */ jsx(ScreenRendererContent, {
67
+ screen,
68
+ containerWidgetTypes,
69
+ className
70
+ })
71
+ });
72
+ }
73
+ //#endregion
74
+ export { ScreenRenderer as t };
75
+
76
+ //# sourceMappingURL=ScreenRenderer-D52h5VQr.mjs.map