@fluid-app/portal-widgets 0.1.18 → 0.1.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/ListWidget-C0RDtImi.cjs +2 -0
  2. package/dist/{ListWidget-RHQ2fQXa.cjs → ListWidget-DPVLRWoB.cjs} +37 -49
  3. package/dist/ListWidget-DPVLRWoB.cjs.map +1 -0
  4. package/dist/{ListWidget-C-jcsCb4.mjs → ListWidget-DdvuIQXy.mjs} +37 -39
  5. package/dist/ListWidget-DdvuIQXy.mjs.map +1 -0
  6. package/dist/{MySiteWidget-A_cYFgxJ.cjs → MySiteWidget-1xqN0Bcg.cjs} +1 -1
  7. package/dist/{MySiteWidget-A_cYFgxJ.cjs.map → MySiteWidget-1xqN0Bcg.cjs.map} +1 -1
  8. package/dist/{MySiteWidget-DariqlfU.mjs → MySiteWidget-CX_jY14-.mjs} +1 -1
  9. package/dist/{MySiteWidget-DariqlfU.mjs.map → MySiteWidget-CX_jY14-.mjs.map} +1 -1
  10. package/dist/NestedWidget-DjZYPLc7.cjs +2 -0
  11. package/dist/{NestedWidget-BaRb7Z5r.mjs → NestedWidget-DoevHJKG.mjs} +27 -3
  12. package/dist/NestedWidget-DoevHJKG.mjs.map +1 -0
  13. package/dist/{NestedWidget-Dbo3dXEi.cjs → NestedWidget-DszMmpt7.cjs} +28 -14
  14. package/dist/NestedWidget-DszMmpt7.cjs.map +1 -0
  15. package/dist/{QuickShareWidget-DXq5lcDn.mjs → QuickShareWidget-CdvP1eRx.mjs} +1 -1
  16. package/dist/{QuickShareWidget-DXq5lcDn.mjs.map → QuickShareWidget-CdvP1eRx.mjs.map} +1 -1
  17. package/dist/{QuickShareWidget-DWvgEy74.cjs → QuickShareWidget-Dg2OcMYg.cjs} +1 -1
  18. package/dist/{QuickShareWidget-DWvgEy74.cjs.map → QuickShareWidget-Dg2OcMYg.cjs.map} +1 -1
  19. package/dist/{RecentActivityWidget-BvncOdax.mjs → RecentActivityWidget-Cj-vLOGu.mjs} +1 -1
  20. package/dist/{RecentActivityWidget-BvncOdax.mjs.map → RecentActivityWidget-Cj-vLOGu.mjs.map} +1 -1
  21. package/dist/{RecentActivityWidget-wODng8dt.cjs → RecentActivityWidget-RGChzfaD.cjs} +1 -1
  22. package/dist/{RecentActivityWidget-wODng8dt.cjs.map → RecentActivityWidget-RGChzfaD.cjs.map} +1 -1
  23. package/dist/{SpacerWidget-BFboILmz.cjs → SpacerWidget-BdVf_Yqm.cjs} +1 -1
  24. package/dist/{SpacerWidget-BFboILmz.cjs.map → SpacerWidget-BdVf_Yqm.cjs.map} +1 -1
  25. package/dist/{SpacerWidget-Cc0IuKda.mjs → SpacerWidget-DxR5K3hp.mjs} +1 -1
  26. package/dist/{SpacerWidget-Cc0IuKda.mjs.map → SpacerWidget-DxR5K3hp.mjs.map} +1 -1
  27. package/dist/{TableWidget-TfQfFHft.cjs → TableWidget-BQNVZUkg.cjs} +32 -23
  28. package/dist/TableWidget-BQNVZUkg.cjs.map +1 -0
  29. package/dist/TableWidget-amUotAZN.cjs +2 -0
  30. package/dist/{TableWidget--yLJTqoW.mjs → TableWidget-bpvdvJHI.mjs} +31 -12
  31. package/dist/TableWidget-bpvdvJHI.mjs.map +1 -0
  32. package/dist/{ToDoWidget-D8YIsl7y.mjs → ToDoWidget-4EZIWq_Z.mjs} +1 -1
  33. package/dist/{ToDoWidget-D8YIsl7y.mjs.map → ToDoWidget-4EZIWq_Z.mjs.map} +1 -1
  34. package/dist/{ToDoWidget-Dvs0GDkx.cjs → ToDoWidget-D5BFKUrZ.cjs} +1 -1
  35. package/dist/{ToDoWidget-Dvs0GDkx.cjs.map → ToDoWidget-D5BFKUrZ.cjs.map} +1 -1
  36. package/dist/{VideoWidget-D_1kluGw.mjs → VideoWidget-CYSOjVec.mjs} +1 -1
  37. package/dist/{VideoWidget-D_1kluGw.mjs.map → VideoWidget-CYSOjVec.mjs.map} +1 -1
  38. package/dist/{VideoWidget-D3Fw1jZE.cjs → VideoWidget-CqRHfFnI.cjs} +1 -1
  39. package/dist/{VideoWidget-D3Fw1jZE.cjs.map → VideoWidget-CqRHfFnI.cjs.map} +1 -1
  40. package/dist/WidgetInteractionContext-DjlpWpTR.cjs +31 -0
  41. package/dist/WidgetInteractionContext-DjlpWpTR.cjs.map +1 -0
  42. package/dist/WidgetInteractionContext-awLrJeAK.mjs +18 -0
  43. package/dist/WidgetInteractionContext-awLrJeAK.mjs.map +1 -0
  44. package/dist/contexts/index.cjs +3 -0
  45. package/dist/contexts/index.d.cts +19 -1
  46. package/dist/contexts/index.d.cts.map +1 -1
  47. package/dist/contexts/index.d.mts +19 -1
  48. package/dist/contexts/index.d.mts.map +1 -1
  49. package/dist/contexts/index.mjs +2 -1
  50. package/dist/core/index.d.mts +1 -1
  51. package/dist/widgets/index.cjs +18 -18
  52. package/dist/widgets/index.cjs.map +1 -1
  53. package/dist/widgets/index.d.cts +1 -2
  54. package/dist/widgets/index.d.cts.map +1 -1
  55. package/dist/widgets/index.d.mts +2 -3
  56. package/dist/widgets/index.d.mts.map +1 -1
  57. package/dist/widgets/index.mjs +18 -18
  58. package/package.json +3 -3
  59. package/dist/ListWidget-C-jcsCb4.mjs.map +0 -1
  60. package/dist/ListWidget-RHQ2fQXa.cjs.map +0 -1
  61. package/dist/NestedWidget-BaRb7Z5r.mjs.map +0 -1
  62. package/dist/NestedWidget-Dbo3dXEi.cjs.map +0 -1
  63. package/dist/TableWidget--yLJTqoW.mjs.map +0 -1
  64. package/dist/TableWidget-TfQfFHft.cjs.map +0 -1
  65. /package/dist/{fields-4FC6JUNH.d.mts → fields-BGGlw1MW.d.mts} +0 -0
@@ -1,15 +1,12 @@
1
- const require_chunk = require("./chunk-CZWwpsFl.cjs");
1
+ require("./chunk-CZWwpsFl.cjs");
2
2
  const require_MediaRenderer = require("./MediaRenderer-CcJvyOJ1.cjs");
3
+ const require_WidgetInteractionContext = require("./WidgetInteractionContext-DjlpWpTR.cjs");
3
4
  let react_jsx_runtime = require("react/jsx-runtime");
4
5
  let react = require("react");
5
6
  let _fluid_app_ui_primitives = require("@fluid-app/ui-primitives");
6
7
  require("@fluid-app/portal-core/types");
7
8
  let _fluid_app_portal_core_registries = require("@fluid-app/portal-core/registries");
8
9
  //#region src/widgets/TableWidget.tsx
9
- var TableWidget_exports = /* @__PURE__ */ require_chunk.__exportAll({
10
- TableWidget: () => TableWidget,
11
- tableWidgetPropertySchema: () => tableWidgetPropertySchema
12
- });
13
10
  const DEFAULT_DATA = [];
14
11
  function ImageCellRenderer(_value, item) {
15
12
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -60,8 +57,15 @@ function TableWidget({ titleEnabled = true, titleText = "Products", titleFontSiz
60
57
  color: "background"
61
58
  }, alternatingColorEnabled = true, textColor = "foreground", headerBackgroundColor = "muted", headerTextColor = "foreground", padding = 4, borderRadius = "md", data = DEFAULT_DATA, filterEnabled = true, sortingEnabled = true, paginationEnabled = true, maxRowsPerPage = 5, className, ...props }) {
62
59
  const backgroundColor = background.color || "background";
63
- const backgroundImage = (background.resource?.image_url || background.resource?.imageUrl) && background.type === "image" ? `url(${background.resource.image_url || background.resource.imageUrl})` : "none";
60
+ const isImageBackground = background.type === "image";
61
+ const backgroundImage = (background.resource?.image_url || background.resource?.imageUrl) && isImageBackground ? `url(${background.resource.image_url || background.resource.imageUrl})` : "none";
64
62
  const pageSize = maxRowsPerPage;
63
+ const innerBg = isImageBackground ? "bg-transparent" : `bg-${backgroundColor}`;
64
+ const innerBgAlt = isImageBackground ? "bg-black/5" : `bg-${backgroundColor}-400`;
65
+ const innerBorder = isImageBackground ? "border-white/20" : `border-${backgroundColor}-600`;
66
+ const headerBg = isImageBackground ? "bg-black/10" : `bg-${headerBackgroundColor}-400`;
67
+ const headerBorder = isImageBackground ? "border-white/20" : `border-${headerBackgroundColor}-600`;
68
+ const paginationBg = isImageBackground ? "bg-black/10" : `bg-${backgroundColor}-400`;
65
69
  const [globalFilter, setGlobalFilter] = (0, react.useState)("");
66
70
  const [sortConfig, setSortConfig] = (0, react.useState)(null);
67
71
  const [currentPage, setCurrentPage] = (0, react.useState)(1);
@@ -128,8 +132,9 @@ function TableWidget({ titleEnabled = true, titleText = "Products", titleFontSiz
128
132
  if (sortConfig?.key !== key) return null;
129
133
  return sortConfig.direction === "asc" ? " ↑" : " ↓";
130
134
  };
135
+ const { onItemClick } = require_WidgetInteractionContext.useWidgetInteraction();
131
136
  if (data.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
132
- className: `@container rounded-${borderRadius} bg-${backgroundColor} p-${padding} ${className}`,
137
+ className: `@container rounded-${borderRadius} bg-${backgroundColor} bg-cover bg-center p-${padding} ${className}`,
133
138
  style: { backgroundImage },
134
139
  ...props,
135
140
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -151,21 +156,21 @@ function TableWidget({ titleEnabled = true, titleText = "Products", titleFontSiz
151
156
  })
152
157
  });
153
158
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
154
- className: `@container overflow-hidden ${paginationEnabled ? "" : "overflow-y-auto"} rounded-${borderRadius} text-${textColor} ${className}`,
159
+ className: `@container overflow-hidden ${paginationEnabled ? "" : "overflow-y-auto"} rounded-${borderRadius} bg-${backgroundColor} bg-cover bg-center text-${textColor} ${className}`,
155
160
  style: { backgroundImage },
156
161
  ...props,
157
162
  children: [
158
163
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
159
- className: `flex items-center justify-between p-${padding} bg-${backgroundColor}`,
164
+ className: `flex items-center justify-between p-${padding} ${innerBg} space-x-2`,
160
165
  children: [titleEnabled && titleText && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
161
- className: `text-${titleFontSize === "md" ? "base" : titleFontSize} font-bold text-${titleColor}`,
166
+ className: `text-${titleFontSize === "md" ? "base" : titleFontSize} font-bold text-${titleColor} min-w-0 truncate`,
162
167
  children: titleText
163
168
  }), filterEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_fluid_app_ui_primitives.Input, {
164
169
  type: "text",
165
170
  placeholder: "Search all columns...",
166
171
  value: globalFilter,
167
172
  onChange: (e) => handleGlobalFilterChange(e.target.value),
168
- className: `w-full rounded-md border border-${headerBackgroundColor}-600 bg-${headerBackgroundColor}-400 ring-offset-muted px-3 py-2 text-sm placeholder:text-${headerTextColor}-900 focus-visible:ring-primary focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none md:w-64`
173
+ className: `w-full rounded-md border ${headerBorder} ${headerBg} ring-offset-muted px-3 py-2 text-sm placeholder:text-${headerTextColor}-900 focus-visible:ring-primary focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none md:w-64`
169
174
  })]
170
175
  }),
171
176
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -173,7 +178,7 @@ function TableWidget({ titleEnabled = true, titleText = "Products", titleFontSiz
173
178
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("table", {
174
179
  className: "w-full border-collapse",
175
180
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tr", {
176
- className: `bg-${headerBackgroundColor}-400 border-${headerBackgroundColor}-600 border-y`,
181
+ className: `${headerBg} ${headerBorder} border-y`,
177
182
  children: columns.map((col) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
178
183
  className: `px-4 py-3 text-left text-sm font-semibold text-${headerTextColor} ${col.sortable && sortingEnabled ? "cursor-pointer select-none hover:opacity-80" : ""}`,
179
184
  ...col.sortable && sortingEnabled ? {
@@ -193,13 +198,23 @@ function TableWidget({ titleEnabled = true, titleText = "Products", titleFontSiz
193
198
  })
194
199
  }, col.key))
195
200
  }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tbody", { children: [paginatedData.map((item, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tr", {
196
- className: `h-17 border-b border-${backgroundColor}-600 last:border-none bg-${backgroundColor} ${alternatingColorEnabled ? `even:bg-${backgroundColor}-400` : ""}`,
201
+ className: `h-17 border-b ${innerBorder} last:border-none ${innerBg} ${alternatingColorEnabled ? `even:${innerBgAlt}` : ""} ${onItemClick ? "cursor-pointer hover:opacity-80" : ""}`,
202
+ ...onItemClick ? {
203
+ tabIndex: 0,
204
+ onClick: () => onItemClick(item),
205
+ onKeyDown: (e) => {
206
+ if (e.key === "Enter" || e.key === " ") {
207
+ e.preventDefault();
208
+ onItemClick(item);
209
+ }
210
+ }
211
+ } : {},
197
212
  children: columns.map((col) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
198
213
  className: "px-4 py-3 text-sm",
199
214
  children: col.render ? col.render(item[col.key], item) : String(item[col.key] ?? "-")
200
215
  }, col.key))
201
216
  }, item.id ?? index)), paginationEnabled && paginatedData.length < pageSize && paginatedData.length > 0 && Array.from({ length: pageSize - paginatedData.length }).map((_, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tr", {
202
- className: `h-17 border-b border-${backgroundColor}-600 last:border-none bg-${backgroundColor} ${alternatingColorEnabled ? `even:bg-${backgroundColor}-400` : ""}`,
217
+ className: `h-17 border-b ${innerBorder} last:border-none ${innerBg} ${alternatingColorEnabled ? `even:${innerBgAlt}` : ""}`,
203
218
  children: columns.map((col) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
204
219
  className: "px-4 py-3 text-sm",
205
220
  children: "\xA0"
@@ -208,7 +223,7 @@ function TableWidget({ titleEnabled = true, titleText = "Products", titleFontSiz
208
223
  })
209
224
  }),
210
225
  paginatedData.length === 0 && data.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
211
- className: `py-8 text-center bg-${backgroundColor}`,
226
+ className: `py-8 text-center ${innerBg}`,
212
227
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
213
228
  className: "text-sm",
214
229
  children: "No results found"
@@ -218,7 +233,7 @@ function TableWidget({ titleEnabled = true, titleText = "Products", titleFontSiz
218
233
  })]
219
234
  }),
220
235
  paginationEnabled && totalPages > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
221
- className: `flex flex-col items-center justify-between gap-2 border-t border-${backgroundColor}-600 p-${padding} @md:flex-row bg-${backgroundColor}-400 text-${textColor}`,
236
+ className: `flex flex-col items-center justify-between gap-2 border-t ${innerBorder} p-${padding} @md:flex-row ${paginationBg} text-${textColor}`,
222
237
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
223
238
  className: "text-sm",
224
239
  children: [
@@ -439,12 +454,6 @@ Object.defineProperty(exports, "TableWidget", {
439
454
  return TableWidget;
440
455
  }
441
456
  });
442
- Object.defineProperty(exports, "TableWidget_exports", {
443
- enumerable: true,
444
- get: function() {
445
- return TableWidget_exports;
446
- }
447
- });
448
457
  Object.defineProperty(exports, "tableWidgetPropertySchema", {
449
458
  enumerable: true,
450
459
  get: function() {
@@ -452,4 +461,4 @@ Object.defineProperty(exports, "tableWidgetPropertySchema", {
452
461
  }
453
462
  });
454
463
 
455
- //# sourceMappingURL=TableWidget-TfQfFHft.cjs.map
464
+ //# sourceMappingURL=TableWidget-BQNVZUkg.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TableWidget-BQNVZUkg.cjs","names":["MediaRenderer","getMediaPropsFromShareable","useWidgetInteraction","Input"],"sources":["../src/widgets/TableWidget.tsx"],"sourcesContent":["import { useState, useMemo, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n} from \"../core/fields\";\nimport { Input } from \"@fluid-app/ui-primitives\";\nimport {\n MediaRenderer,\n getMediaPropsFromShareable,\n} from \"../components/MediaRenderer\";\nimport { type ShareableItem } from \"@fluid-app/portal-core/types\";\nimport { useWidgetInteraction } from \"../contexts/WidgetInteractionContext\";\n\n// Column definition for the table\ntype ColumnDef = {\n key: string;\n label: string;\n sortable: boolean;\n render?: (value: unknown, item: ShareableItem) => React.ReactNode;\n};\n\nconst DEFAULT_DATA: ShareableItem[] = [];\n\n// ---------------------------------------------------------------------------\n// Column cell renderers\n// ---------------------------------------------------------------------------\n\nfunction ImageCellRenderer(_value: unknown, item: ShareableItem) {\n return (\n <div className=\"h-10 w-10 rounded object-cover\">\n <MediaRenderer {...getMediaPropsFromShareable(item)} />\n </div>\n );\n}\n\nfunction PriceCellRenderer(_value: unknown, item: ShareableItem) {\n return ((item.display_price as string) ?? item.price) || \"-\";\n}\n\nfunction StatusCellRenderer(value: unknown) {\n const status = String(value || \"unknown\").toLowerCase();\n const statusStyles: Record<string, string> = {\n active: \"bg-primary text-primary-foreground\",\n inactive: \"bg-secondary text-secondary-foreground\",\n unknown: \"bg-muted text-muted-foreground\",\n };\n return (\n <span\n className={`inline-flex rounded-full px-2 py-1 text-xs font-medium ${statusStyles[status] || \"bg-muted text-foreground\"}`}\n >\n {String(value || \"Unknown\")}\n </span>\n );\n}\n\n// Default columns for product data\nconst defaultColumns: ColumnDef[] = [\n {\n key: \"imageUrl\",\n label: \"Image\",\n sortable: false,\n render: ImageCellRenderer,\n },\n {\n key: \"title\",\n label: \"Title\",\n sortable: true,\n },\n {\n key: \"price\",\n label: \"Price\",\n sortable: true,\n render: PriceCellRenderer,\n },\n {\n key: \"status\",\n label: \"Status\",\n sortable: true,\n render: StatusCellRenderer,\n },\n];\n\ntype TableWidgetProps = ComponentProps<\"div\"> & {\n // Title\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n // Styling\n background?: BackgroundValue;\n alternatingColorEnabled?: boolean;\n textColor?: ColorOptions;\n headerBackgroundColor?: ColorOptions;\n headerTextColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n\n // Data\n data?: ShareableItem[];\n\n // Features\n filterEnabled?: boolean;\n sortingEnabled?: boolean;\n paginationEnabled?: boolean;\n maxRowsPerPage?: number;\n};\n\nexport function TableWidget({\n // Title defaults\n titleEnabled = true,\n titleText = \"Products\",\n titleFontSize = \"xl\",\n titleColor = \"foreground\",\n\n // Styling defaults\n background = {\n type: \"solid\",\n color: \"background\",\n },\n alternatingColorEnabled = true,\n textColor = \"foreground\",\n headerBackgroundColor = \"muted\",\n headerTextColor = \"foreground\",\n padding = 4,\n borderRadius = \"md\",\n\n // Data\n data = DEFAULT_DATA,\n\n // Feature defaults\n filterEnabled = true,\n sortingEnabled = true,\n paginationEnabled = true,\n maxRowsPerPage = 5,\n\n className,\n ...props\n}: TableWidgetProps): React.JSX.Element {\n const backgroundColor = background.color || \"background\";\n const isImageBackground = background.type === \"image\";\n const backgroundImage =\n (background.resource?.image_url || background.resource?.imageUrl) &&\n isImageBackground\n ? `url(${background.resource.image_url || background.resource.imageUrl})`\n : \"none\";\n const pageSize = maxRowsPerPage;\n\n // When using an image background, inner elements should be transparent\n // so the image shows through. Otherwise use the configured colors.\n const innerBg = isImageBackground\n ? \"bg-transparent\"\n : `bg-${backgroundColor}`;\n const innerBgAlt = isImageBackground\n ? \"bg-black/5\"\n : `bg-${backgroundColor}-400`;\n const innerBorder = isImageBackground\n ? \"border-white/20\"\n : `border-${backgroundColor}-600`;\n const headerBg = isImageBackground\n ? \"bg-black/10\"\n : `bg-${headerBackgroundColor}-400`;\n const headerBorder = isImageBackground\n ? \"border-white/20\"\n : `border-${headerBackgroundColor}-600`;\n const paginationBg = isImageBackground\n ? \"bg-black/10\"\n : `bg-${backgroundColor}-400`;\n\n // State for filtering, sorting, and pagination\n const [globalFilter, setGlobalFilter] = useState(\"\");\n const [sortConfig, setSortConfig] = useState<{\n key: string;\n direction: \"asc\" | \"desc\";\n } | null>(null);\n const [currentPage, setCurrentPage] = useState(1);\n\n const columns = defaultColumns;\n\n // Filter data\n const filteredData = useMemo(() => {\n let result = [...data];\n\n if (globalFilter) {\n const lowerFilter = globalFilter.toLowerCase();\n result = result.filter((item) =>\n columns.some((col) => {\n const value = item[col.key];\n return String(value ?? \"\")\n .toLowerCase()\n .includes(lowerFilter);\n }),\n );\n }\n\n return result;\n }, [data, globalFilter, columns]);\n\n // Sort data\n const sortedData = useMemo(() => {\n if (!sortConfig) return filteredData;\n\n return [...filteredData].sort((a, b) => {\n const aValue = a[sortConfig.key];\n const bValue = b[sortConfig.key];\n\n // Handle null/undefined\n if (aValue == null && bValue == null) return 0;\n if (aValue == null) return sortConfig.direction === \"asc\" ? 1 : -1;\n if (bValue == null) return sortConfig.direction === \"asc\" ? -1 : 1;\n\n // Compare values\n let comparison = 0;\n if (typeof aValue === \"number\" && typeof bValue === \"number\") {\n comparison = aValue - bValue;\n } else {\n comparison = String(aValue).localeCompare(String(bValue));\n }\n\n return sortConfig.direction === \"asc\" ? comparison : -comparison;\n });\n }, [filteredData, sortConfig]);\n\n // Paginate data\n const paginatedData = useMemo(() => {\n if (!paginationEnabled) return sortedData;\n\n const startIndex = (currentPage - 1) * pageSize;\n return sortedData.slice(startIndex, startIndex + pageSize);\n }, [sortedData, currentPage, pageSize, paginationEnabled]);\n\n const totalPages = Math.ceil(sortedData.length / pageSize);\n\n // Reset to page 1 when filters change\n const handleGlobalFilterChange = (value: string) => {\n setGlobalFilter(value);\n setCurrentPage(1);\n };\n\n // Handle sort\n const handleSort = (key: string) => {\n if (!sortingEnabled) return;\n\n setSortConfig((prev) => {\n if (prev?.key !== key) return { key, direction: \"asc\" };\n if (prev.direction === \"asc\") return { key, direction: \"desc\" };\n return null;\n });\n };\n\n // Get sort indicator\n const getSortIndicator = (key: string) => {\n if (sortConfig?.key !== key) return null;\n return sortConfig.direction === \"asc\" ? \" ↑\" : \" ↓\";\n };\n\n const { onItemClick } = useWidgetInteraction();\n\n // Empty state\n if (data.length === 0) {\n return (\n <div\n className={`@container rounded-${borderRadius} bg-${backgroundColor} bg-cover bg-center p-${padding} ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n <div className=\"text-muted-foreground flex min-h-[200px] flex-col items-center justify-center gap-2\">\n <div className=\"text-4xl\">📋</div>\n <p className=\"text-sm\">No data available</p>\n <p className=\"text-muted-foreground/70 text-xs\">\n Connect a data source to display table data\n </p>\n </div>\n </div>\n );\n }\n\n return (\n <div\n className={`@container overflow-hidden ${paginationEnabled ? \"\" : \"overflow-y-auto\"} rounded-${borderRadius} bg-${backgroundColor} bg-cover bg-center text-${textColor} ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n <div\n className={`flex items-center justify-between p-${padding} ${innerBg} space-x-2`}\n >\n {/* Title */}\n {titleEnabled && titleText && (\n <h2\n className={`text-${titleFontSize === \"md\" ? \"base\" : titleFontSize} font-bold text-${titleColor} min-w-0 truncate`}\n >\n {titleText}\n </h2>\n )}\n\n {/* Global Search */}\n {filterEnabled && (\n <Input\n type=\"text\"\n placeholder=\"Search all columns...\"\n value={globalFilter}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n handleGlobalFilterChange(e.target.value)\n }\n className={`w-full rounded-md border ${headerBorder} ${headerBg} ring-offset-muted px-3 py-2 text-sm placeholder:text-${headerTextColor}-900 focus-visible:ring-primary focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none md:w-64`}\n />\n )}\n </div>\n\n {/* Table */}\n <div className=\"overflow-x-auto\">\n <table className=\"w-full border-collapse\">\n <thead>\n <tr className={`${headerBg} ${headerBorder} border-y`}>\n {columns.map((col) => (\n <th\n key={col.key}\n className={`px-4 py-3 text-left text-sm font-semibold text-${headerTextColor} ${col.sortable && sortingEnabled ? \"cursor-pointer select-none hover:opacity-80\" : \"\"}`}\n {...(col.sortable && sortingEnabled\n ? {\n role: \"button\" as const,\n tabIndex: 0,\n onClick: () => handleSort(col.key),\n onKeyDown: (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleSort(col.key);\n }\n },\n }\n : {})}\n >\n <div className=\"flex flex-col gap-1\">\n <span>\n {col.label}\n {col.sortable &&\n sortingEnabled &&\n getSortIndicator(col.key)}\n </span>\n </div>\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {paginatedData.map((item, index) => (\n <tr\n key={item.id ?? index}\n className={`h-17 border-b ${innerBorder} last:border-none ${innerBg} ${alternatingColorEnabled ? `even:${innerBgAlt}` : \"\"} ${onItemClick ? \"cursor-pointer hover:opacity-80\" : \"\"}`}\n {...(onItemClick\n ? {\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 {columns.map((col) => (\n <td key={col.key} className=\"px-4 py-3 text-sm\">\n {col.render\n ? col.render(item[col.key], item)\n : String(item[col.key] ?? \"-\")}\n </td>\n ))}\n </tr>\n ))}\n {/* Empty rows to fill the last page for consistent pagination position */}\n {paginationEnabled &&\n paginatedData.length < pageSize &&\n paginatedData.length > 0 &&\n Array.from({ length: pageSize - paginatedData.length }).map(\n (_, index) => (\n <tr\n key={`empty-${index}`}\n className={`h-17 border-b ${innerBorder} last:border-none ${innerBg} ${alternatingColorEnabled ? `even:${innerBgAlt}` : \"\"}`}\n >\n {columns.map((col) => (\n <td key={col.key} className=\"px-4 py-3 text-sm\">\n &nbsp;\n </td>\n ))}\n </tr>\n ),\n )}\n </tbody>\n </table>\n </div>\n\n {/* No results message */}\n {paginatedData.length === 0 && data.length > 0 && (\n <div className={`py-8 text-center ${innerBg}`}>\n <p className=\"text-sm\">No results found</p>\n <p className=\"text-xs\">Try adjusting your search</p>\n </div>\n )}\n\n {/* Pagination */}\n {paginationEnabled && totalPages > 1 && (\n <div\n className={`flex flex-col items-center justify-between gap-2 border-t ${innerBorder} p-${padding} @md:flex-row ${paginationBg} text-${textColor}`}\n >\n <p className=\"text-sm\">\n Showing {(currentPage - 1) * pageSize + 1}-\n {Math.min(currentPage * pageSize, sortedData.length)} of{\" \"}\n {sortedData.length} results\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}\n disabled={currentPage === 1}\n className={`rounded-md border border-${headerBackgroundColor}-600 bg-${headerBackgroundColor} ring-offset-muted placeholder:text-muted-foreground focus-visible:ring-primary px-3 py-1 text-sm transition-opacity hover:opacity-80 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50`}\n >\n Previous\n </button>\n <span className=\"text-sm\">\n Page {currentPage} of {totalPages}\n </span>\n <button\n onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))}\n disabled={currentPage === totalPages}\n className={`rounded-md border border-${headerBackgroundColor}-600 bg-${headerBackgroundColor} ring-offset-muted placeholder:text-muted-foreground focus-visible:ring-primary px-3 py-1 text-sm transition-opacity hover:opacity-80 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50`}\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const tableWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"TableWidget\",\n displayName: \"Table Widget\",\n tabsConfig: [\n { id: \"styling\", label: \"Styling\" },\n { id: \"behavior\", label: \"Behavior\" },\n { id: \"data\", label: \"Data\" },\n ],\n dataSourceTargetProps: [\"data\"],\n fields: [\n // Content Tab - Title Group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed above the table\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Title text displayed above the table\",\n defaultValue: \"Products\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n label: \"Title Font Size\",\n defaultValue: \"xl\",\n key: \"titleFontSize\",\n description: \"Font size for the widget title\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n\n // Styling Tab - Design Group\n {\n type: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background for the table container\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"alternatingColorEnabled\",\n label: \"Enable Alternating Colors\",\n type: \"boolean\",\n description: \"Enable alternating colors for table rows\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n key: \"headerBackgroundColor\",\n label: \"Header Background\",\n description: \"Background color for the table header\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for table content\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"headerTextColor\",\n label: \"Header Text Color\",\n description: \"Text color for the table header\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the table container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the table container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n\n // Behavior Tab - Features Group\n {\n key: \"filterEnabled\",\n label: \"Enable Filters\",\n type: \"boolean\",\n description: \"Show global search and column filters\",\n defaultValue: true,\n tab: \"behavior\",\n group: \"Features\",\n },\n {\n key: \"sortingEnabled\",\n label: \"Enable Sorting\",\n type: \"boolean\",\n description: \"Allow sorting by clicking column headers\",\n defaultValue: true,\n tab: \"behavior\",\n group: \"Features\",\n },\n {\n key: \"paginationEnabled\",\n label: \"Enable Pagination\",\n type: \"boolean\",\n description: \"Split data into pages\",\n defaultValue: true,\n tab: \"behavior\",\n group: \"Features\",\n },\n {\n key: \"maxRowsPerPage\",\n label: \"Max Rows Per Page\",\n type: \"number\",\n description: \"Maximum number of rows to display per page\",\n min: 1,\n max: 50,\n step: 1,\n defaultValue: 5,\n tab: \"behavior\",\n group: \"Features\",\n requiresKeyToBeTrue: \"paginationEnabled\",\n },\n\n // Data Tab\n {\n key: \"dataSource\",\n label: \"Data Source\",\n type: \"dataSource\",\n description: \"Configure data source for the table\",\n tab: \"data\",\n group: \"Data Configuration\",\n },\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ const require_TableWidget = require("./TableWidget-BQNVZUkg.cjs");
2
+ exports.tableWidgetPropertySchema = require_TableWidget.tableWidgetPropertySchema;
@@ -1,6 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-wcPFST8Q.mjs";
2
2
  import { a as getFontSizeField, c as getPaddingField, i as getColorField, n as getBorderRadiusField } from "./fields-wPOk-SmZ.mjs";
3
3
  import { n as getMediaPropsFromShareable, t as MediaRenderer } from "./MediaRenderer-Uq90PZcY.mjs";
4
+ import { n as useWidgetInteraction } from "./WidgetInteractionContext-awLrJeAK.mjs";
4
5
  import { jsx, jsxs } from "react/jsx-runtime";
5
6
  import { useMemo, useState } from "react";
6
7
  import { Input } from "@fluid-app/ui-primitives";
@@ -60,8 +61,15 @@ function TableWidget({ titleEnabled = true, titleText = "Products", titleFontSiz
60
61
  color: "background"
61
62
  }, alternatingColorEnabled = true, textColor = "foreground", headerBackgroundColor = "muted", headerTextColor = "foreground", padding = 4, borderRadius = "md", data = DEFAULT_DATA, filterEnabled = true, sortingEnabled = true, paginationEnabled = true, maxRowsPerPage = 5, className, ...props }) {
62
63
  const backgroundColor = background.color || "background";
63
- const backgroundImage = (background.resource?.image_url || background.resource?.imageUrl) && background.type === "image" ? `url(${background.resource.image_url || background.resource.imageUrl})` : "none";
64
+ const isImageBackground = background.type === "image";
65
+ const backgroundImage = (background.resource?.image_url || background.resource?.imageUrl) && isImageBackground ? `url(${background.resource.image_url || background.resource.imageUrl})` : "none";
64
66
  const pageSize = maxRowsPerPage;
67
+ const innerBg = isImageBackground ? "bg-transparent" : `bg-${backgroundColor}`;
68
+ const innerBgAlt = isImageBackground ? "bg-black/5" : `bg-${backgroundColor}-400`;
69
+ const innerBorder = isImageBackground ? "border-white/20" : `border-${backgroundColor}-600`;
70
+ const headerBg = isImageBackground ? "bg-black/10" : `bg-${headerBackgroundColor}-400`;
71
+ const headerBorder = isImageBackground ? "border-white/20" : `border-${headerBackgroundColor}-600`;
72
+ const paginationBg = isImageBackground ? "bg-black/10" : `bg-${backgroundColor}-400`;
65
73
  const [globalFilter, setGlobalFilter] = useState("");
66
74
  const [sortConfig, setSortConfig] = useState(null);
67
75
  const [currentPage, setCurrentPage] = useState(1);
@@ -128,8 +136,9 @@ function TableWidget({ titleEnabled = true, titleText = "Products", titleFontSiz
128
136
  if (sortConfig?.key !== key) return null;
129
137
  return sortConfig.direction === "asc" ? " ↑" : " ↓";
130
138
  };
139
+ const { onItemClick } = useWidgetInteraction();
131
140
  if (data.length === 0) return /* @__PURE__ */ jsx("div", {
132
- className: `@container rounded-${borderRadius} bg-${backgroundColor} p-${padding} ${className}`,
141
+ className: `@container rounded-${borderRadius} bg-${backgroundColor} bg-cover bg-center p-${padding} ${className}`,
133
142
  style: { backgroundImage },
134
143
  ...props,
135
144
  children: /* @__PURE__ */ jsxs("div", {
@@ -151,21 +160,21 @@ function TableWidget({ titleEnabled = true, titleText = "Products", titleFontSiz
151
160
  })
152
161
  });
153
162
  return /* @__PURE__ */ jsxs("div", {
154
- className: `@container overflow-hidden ${paginationEnabled ? "" : "overflow-y-auto"} rounded-${borderRadius} text-${textColor} ${className}`,
163
+ className: `@container overflow-hidden ${paginationEnabled ? "" : "overflow-y-auto"} rounded-${borderRadius} bg-${backgroundColor} bg-cover bg-center text-${textColor} ${className}`,
155
164
  style: { backgroundImage },
156
165
  ...props,
157
166
  children: [
158
167
  /* @__PURE__ */ jsxs("div", {
159
- className: `flex items-center justify-between p-${padding} bg-${backgroundColor}`,
168
+ className: `flex items-center justify-between p-${padding} ${innerBg} space-x-2`,
160
169
  children: [titleEnabled && titleText && /* @__PURE__ */ jsx("h2", {
161
- className: `text-${titleFontSize === "md" ? "base" : titleFontSize} font-bold text-${titleColor}`,
170
+ className: `text-${titleFontSize === "md" ? "base" : titleFontSize} font-bold text-${titleColor} min-w-0 truncate`,
162
171
  children: titleText
163
172
  }), filterEnabled && /* @__PURE__ */ jsx(Input, {
164
173
  type: "text",
165
174
  placeholder: "Search all columns...",
166
175
  value: globalFilter,
167
176
  onChange: (e) => handleGlobalFilterChange(e.target.value),
168
- className: `w-full rounded-md border border-${headerBackgroundColor}-600 bg-${headerBackgroundColor}-400 ring-offset-muted px-3 py-2 text-sm placeholder:text-${headerTextColor}-900 focus-visible:ring-primary focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none md:w-64`
177
+ className: `w-full rounded-md border ${headerBorder} ${headerBg} ring-offset-muted px-3 py-2 text-sm placeholder:text-${headerTextColor}-900 focus-visible:ring-primary focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none md:w-64`
169
178
  })]
170
179
  }),
171
180
  /* @__PURE__ */ jsx("div", {
@@ -173,7 +182,7 @@ function TableWidget({ titleEnabled = true, titleText = "Products", titleFontSiz
173
182
  children: /* @__PURE__ */ jsxs("table", {
174
183
  className: "w-full border-collapse",
175
184
  children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", {
176
- className: `bg-${headerBackgroundColor}-400 border-${headerBackgroundColor}-600 border-y`,
185
+ className: `${headerBg} ${headerBorder} border-y`,
177
186
  children: columns.map((col) => /* @__PURE__ */ jsx("th", {
178
187
  className: `px-4 py-3 text-left text-sm font-semibold text-${headerTextColor} ${col.sortable && sortingEnabled ? "cursor-pointer select-none hover:opacity-80" : ""}`,
179
188
  ...col.sortable && sortingEnabled ? {
@@ -193,13 +202,23 @@ function TableWidget({ titleEnabled = true, titleText = "Products", titleFontSiz
193
202
  })
194
203
  }, col.key))
195
204
  }) }), /* @__PURE__ */ jsxs("tbody", { children: [paginatedData.map((item, index) => /* @__PURE__ */ jsx("tr", {
196
- className: `h-17 border-b border-${backgroundColor}-600 last:border-none bg-${backgroundColor} ${alternatingColorEnabled ? `even:bg-${backgroundColor}-400` : ""}`,
205
+ className: `h-17 border-b ${innerBorder} last:border-none ${innerBg} ${alternatingColorEnabled ? `even:${innerBgAlt}` : ""} ${onItemClick ? "cursor-pointer hover:opacity-80" : ""}`,
206
+ ...onItemClick ? {
207
+ tabIndex: 0,
208
+ onClick: () => onItemClick(item),
209
+ onKeyDown: (e) => {
210
+ if (e.key === "Enter" || e.key === " ") {
211
+ e.preventDefault();
212
+ onItemClick(item);
213
+ }
214
+ }
215
+ } : {},
197
216
  children: columns.map((col) => /* @__PURE__ */ jsx("td", {
198
217
  className: "px-4 py-3 text-sm",
199
218
  children: col.render ? col.render(item[col.key], item) : String(item[col.key] ?? "-")
200
219
  }, col.key))
201
220
  }, item.id ?? index)), paginationEnabled && paginatedData.length < pageSize && paginatedData.length > 0 && Array.from({ length: pageSize - paginatedData.length }).map((_, index) => /* @__PURE__ */ jsx("tr", {
202
- className: `h-17 border-b border-${backgroundColor}-600 last:border-none bg-${backgroundColor} ${alternatingColorEnabled ? `even:bg-${backgroundColor}-400` : ""}`,
221
+ className: `h-17 border-b ${innerBorder} last:border-none ${innerBg} ${alternatingColorEnabled ? `even:${innerBgAlt}` : ""}`,
203
222
  children: columns.map((col) => /* @__PURE__ */ jsx("td", {
204
223
  className: "px-4 py-3 text-sm",
205
224
  children: "\xA0"
@@ -208,7 +227,7 @@ function TableWidget({ titleEnabled = true, titleText = "Products", titleFontSiz
208
227
  })
209
228
  }),
210
229
  paginatedData.length === 0 && data.length > 0 && /* @__PURE__ */ jsxs("div", {
211
- className: `py-8 text-center bg-${backgroundColor}`,
230
+ className: `py-8 text-center ${innerBg}`,
212
231
  children: [/* @__PURE__ */ jsx("p", {
213
232
  className: "text-sm",
214
233
  children: "No results found"
@@ -218,7 +237,7 @@ function TableWidget({ titleEnabled = true, titleText = "Products", titleFontSiz
218
237
  })]
219
238
  }),
220
239
  paginationEnabled && totalPages > 1 && /* @__PURE__ */ jsxs("div", {
221
- className: `flex flex-col items-center justify-between gap-2 border-t border-${backgroundColor}-600 p-${padding} @md:flex-row bg-${backgroundColor}-400 text-${textColor}`,
240
+ className: `flex flex-col items-center justify-between gap-2 border-t ${innerBorder} p-${padding} @md:flex-row ${paginationBg} text-${textColor}`,
222
241
  children: [/* @__PURE__ */ jsxs("p", {
223
242
  className: "text-sm",
224
243
  children: [
@@ -435,4 +454,4 @@ const tableWidgetPropertySchema = {
435
454
  //#endregion
436
455
  export { TableWidget_exports as n, tableWidgetPropertySchema as r, TableWidget as t };
437
456
 
438
- //# sourceMappingURL=TableWidget--yLJTqoW.mjs.map
457
+ //# sourceMappingURL=TableWidget-bpvdvJHI.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TableWidget-bpvdvJHI.mjs","names":[],"sources":["../src/widgets/TableWidget.tsx"],"sourcesContent":["import { useState, useMemo, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n} from \"../core/fields\";\nimport { Input } from \"@fluid-app/ui-primitives\";\nimport {\n MediaRenderer,\n getMediaPropsFromShareable,\n} from \"../components/MediaRenderer\";\nimport { type ShareableItem } from \"@fluid-app/portal-core/types\";\nimport { useWidgetInteraction } from \"../contexts/WidgetInteractionContext\";\n\n// Column definition for the table\ntype ColumnDef = {\n key: string;\n label: string;\n sortable: boolean;\n render?: (value: unknown, item: ShareableItem) => React.ReactNode;\n};\n\nconst DEFAULT_DATA: ShareableItem[] = [];\n\n// ---------------------------------------------------------------------------\n// Column cell renderers\n// ---------------------------------------------------------------------------\n\nfunction ImageCellRenderer(_value: unknown, item: ShareableItem) {\n return (\n <div className=\"h-10 w-10 rounded object-cover\">\n <MediaRenderer {...getMediaPropsFromShareable(item)} />\n </div>\n );\n}\n\nfunction PriceCellRenderer(_value: unknown, item: ShareableItem) {\n return ((item.display_price as string) ?? item.price) || \"-\";\n}\n\nfunction StatusCellRenderer(value: unknown) {\n const status = String(value || \"unknown\").toLowerCase();\n const statusStyles: Record<string, string> = {\n active: \"bg-primary text-primary-foreground\",\n inactive: \"bg-secondary text-secondary-foreground\",\n unknown: \"bg-muted text-muted-foreground\",\n };\n return (\n <span\n className={`inline-flex rounded-full px-2 py-1 text-xs font-medium ${statusStyles[status] || \"bg-muted text-foreground\"}`}\n >\n {String(value || \"Unknown\")}\n </span>\n );\n}\n\n// Default columns for product data\nconst defaultColumns: ColumnDef[] = [\n {\n key: \"imageUrl\",\n label: \"Image\",\n sortable: false,\n render: ImageCellRenderer,\n },\n {\n key: \"title\",\n label: \"Title\",\n sortable: true,\n },\n {\n key: \"price\",\n label: \"Price\",\n sortable: true,\n render: PriceCellRenderer,\n },\n {\n key: \"status\",\n label: \"Status\",\n sortable: true,\n render: StatusCellRenderer,\n },\n];\n\ntype TableWidgetProps = ComponentProps<\"div\"> & {\n // Title\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n // Styling\n background?: BackgroundValue;\n alternatingColorEnabled?: boolean;\n textColor?: ColorOptions;\n headerBackgroundColor?: ColorOptions;\n headerTextColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n\n // Data\n data?: ShareableItem[];\n\n // Features\n filterEnabled?: boolean;\n sortingEnabled?: boolean;\n paginationEnabled?: boolean;\n maxRowsPerPage?: number;\n};\n\nexport function TableWidget({\n // Title defaults\n titleEnabled = true,\n titleText = \"Products\",\n titleFontSize = \"xl\",\n titleColor = \"foreground\",\n\n // Styling defaults\n background = {\n type: \"solid\",\n color: \"background\",\n },\n alternatingColorEnabled = true,\n textColor = \"foreground\",\n headerBackgroundColor = \"muted\",\n headerTextColor = \"foreground\",\n padding = 4,\n borderRadius = \"md\",\n\n // Data\n data = DEFAULT_DATA,\n\n // Feature defaults\n filterEnabled = true,\n sortingEnabled = true,\n paginationEnabled = true,\n maxRowsPerPage = 5,\n\n className,\n ...props\n}: TableWidgetProps): React.JSX.Element {\n const backgroundColor = background.color || \"background\";\n const isImageBackground = background.type === \"image\";\n const backgroundImage =\n (background.resource?.image_url || background.resource?.imageUrl) &&\n isImageBackground\n ? `url(${background.resource.image_url || background.resource.imageUrl})`\n : \"none\";\n const pageSize = maxRowsPerPage;\n\n // When using an image background, inner elements should be transparent\n // so the image shows through. Otherwise use the configured colors.\n const innerBg = isImageBackground\n ? \"bg-transparent\"\n : `bg-${backgroundColor}`;\n const innerBgAlt = isImageBackground\n ? \"bg-black/5\"\n : `bg-${backgroundColor}-400`;\n const innerBorder = isImageBackground\n ? \"border-white/20\"\n : `border-${backgroundColor}-600`;\n const headerBg = isImageBackground\n ? \"bg-black/10\"\n : `bg-${headerBackgroundColor}-400`;\n const headerBorder = isImageBackground\n ? \"border-white/20\"\n : `border-${headerBackgroundColor}-600`;\n const paginationBg = isImageBackground\n ? \"bg-black/10\"\n : `bg-${backgroundColor}-400`;\n\n // State for filtering, sorting, and pagination\n const [globalFilter, setGlobalFilter] = useState(\"\");\n const [sortConfig, setSortConfig] = useState<{\n key: string;\n direction: \"asc\" | \"desc\";\n } | null>(null);\n const [currentPage, setCurrentPage] = useState(1);\n\n const columns = defaultColumns;\n\n // Filter data\n const filteredData = useMemo(() => {\n let result = [...data];\n\n if (globalFilter) {\n const lowerFilter = globalFilter.toLowerCase();\n result = result.filter((item) =>\n columns.some((col) => {\n const value = item[col.key];\n return String(value ?? \"\")\n .toLowerCase()\n .includes(lowerFilter);\n }),\n );\n }\n\n return result;\n }, [data, globalFilter, columns]);\n\n // Sort data\n const sortedData = useMemo(() => {\n if (!sortConfig) return filteredData;\n\n return [...filteredData].sort((a, b) => {\n const aValue = a[sortConfig.key];\n const bValue = b[sortConfig.key];\n\n // Handle null/undefined\n if (aValue == null && bValue == null) return 0;\n if (aValue == null) return sortConfig.direction === \"asc\" ? 1 : -1;\n if (bValue == null) return sortConfig.direction === \"asc\" ? -1 : 1;\n\n // Compare values\n let comparison = 0;\n if (typeof aValue === \"number\" && typeof bValue === \"number\") {\n comparison = aValue - bValue;\n } else {\n comparison = String(aValue).localeCompare(String(bValue));\n }\n\n return sortConfig.direction === \"asc\" ? comparison : -comparison;\n });\n }, [filteredData, sortConfig]);\n\n // Paginate data\n const paginatedData = useMemo(() => {\n if (!paginationEnabled) return sortedData;\n\n const startIndex = (currentPage - 1) * pageSize;\n return sortedData.slice(startIndex, startIndex + pageSize);\n }, [sortedData, currentPage, pageSize, paginationEnabled]);\n\n const totalPages = Math.ceil(sortedData.length / pageSize);\n\n // Reset to page 1 when filters change\n const handleGlobalFilterChange = (value: string) => {\n setGlobalFilter(value);\n setCurrentPage(1);\n };\n\n // Handle sort\n const handleSort = (key: string) => {\n if (!sortingEnabled) return;\n\n setSortConfig((prev) => {\n if (prev?.key !== key) return { key, direction: \"asc\" };\n if (prev.direction === \"asc\") return { key, direction: \"desc\" };\n return null;\n });\n };\n\n // Get sort indicator\n const getSortIndicator = (key: string) => {\n if (sortConfig?.key !== key) return null;\n return sortConfig.direction === \"asc\" ? \" ↑\" : \" ↓\";\n };\n\n const { onItemClick } = useWidgetInteraction();\n\n // Empty state\n if (data.length === 0) {\n return (\n <div\n className={`@container rounded-${borderRadius} bg-${backgroundColor} bg-cover bg-center p-${padding} ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n <div className=\"text-muted-foreground flex min-h-[200px] flex-col items-center justify-center gap-2\">\n <div className=\"text-4xl\">📋</div>\n <p className=\"text-sm\">No data available</p>\n <p className=\"text-muted-foreground/70 text-xs\">\n Connect a data source to display table data\n </p>\n </div>\n </div>\n );\n }\n\n return (\n <div\n className={`@container overflow-hidden ${paginationEnabled ? \"\" : \"overflow-y-auto\"} rounded-${borderRadius} bg-${backgroundColor} bg-cover bg-center text-${textColor} ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n <div\n className={`flex items-center justify-between p-${padding} ${innerBg} space-x-2`}\n >\n {/* Title */}\n {titleEnabled && titleText && (\n <h2\n className={`text-${titleFontSize === \"md\" ? \"base\" : titleFontSize} font-bold text-${titleColor} min-w-0 truncate`}\n >\n {titleText}\n </h2>\n )}\n\n {/* Global Search */}\n {filterEnabled && (\n <Input\n type=\"text\"\n placeholder=\"Search all columns...\"\n value={globalFilter}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n handleGlobalFilterChange(e.target.value)\n }\n className={`w-full rounded-md border ${headerBorder} ${headerBg} ring-offset-muted px-3 py-2 text-sm placeholder:text-${headerTextColor}-900 focus-visible:ring-primary focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none md:w-64`}\n />\n )}\n </div>\n\n {/* Table */}\n <div className=\"overflow-x-auto\">\n <table className=\"w-full border-collapse\">\n <thead>\n <tr className={`${headerBg} ${headerBorder} border-y`}>\n {columns.map((col) => (\n <th\n key={col.key}\n className={`px-4 py-3 text-left text-sm font-semibold text-${headerTextColor} ${col.sortable && sortingEnabled ? \"cursor-pointer select-none hover:opacity-80\" : \"\"}`}\n {...(col.sortable && sortingEnabled\n ? {\n role: \"button\" as const,\n tabIndex: 0,\n onClick: () => handleSort(col.key),\n onKeyDown: (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleSort(col.key);\n }\n },\n }\n : {})}\n >\n <div className=\"flex flex-col gap-1\">\n <span>\n {col.label}\n {col.sortable &&\n sortingEnabled &&\n getSortIndicator(col.key)}\n </span>\n </div>\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {paginatedData.map((item, index) => (\n <tr\n key={item.id ?? index}\n className={`h-17 border-b ${innerBorder} last:border-none ${innerBg} ${alternatingColorEnabled ? `even:${innerBgAlt}` : \"\"} ${onItemClick ? \"cursor-pointer hover:opacity-80\" : \"\"}`}\n {...(onItemClick\n ? {\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 {columns.map((col) => (\n <td key={col.key} className=\"px-4 py-3 text-sm\">\n {col.render\n ? col.render(item[col.key], item)\n : String(item[col.key] ?? \"-\")}\n </td>\n ))}\n </tr>\n ))}\n {/* Empty rows to fill the last page for consistent pagination position */}\n {paginationEnabled &&\n paginatedData.length < pageSize &&\n paginatedData.length > 0 &&\n Array.from({ length: pageSize - paginatedData.length }).map(\n (_, index) => (\n <tr\n key={`empty-${index}`}\n className={`h-17 border-b ${innerBorder} last:border-none ${innerBg} ${alternatingColorEnabled ? `even:${innerBgAlt}` : \"\"}`}\n >\n {columns.map((col) => (\n <td key={col.key} className=\"px-4 py-3 text-sm\">\n &nbsp;\n </td>\n ))}\n </tr>\n ),\n )}\n </tbody>\n </table>\n </div>\n\n {/* No results message */}\n {paginatedData.length === 0 && data.length > 0 && (\n <div className={`py-8 text-center ${innerBg}`}>\n <p className=\"text-sm\">No results found</p>\n <p className=\"text-xs\">Try adjusting your search</p>\n </div>\n )}\n\n {/* Pagination */}\n {paginationEnabled && totalPages > 1 && (\n <div\n className={`flex flex-col items-center justify-between gap-2 border-t ${innerBorder} p-${padding} @md:flex-row ${paginationBg} text-${textColor}`}\n >\n <p className=\"text-sm\">\n Showing {(currentPage - 1) * pageSize + 1}-\n {Math.min(currentPage * pageSize, sortedData.length)} of{\" \"}\n {sortedData.length} results\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}\n disabled={currentPage === 1}\n className={`rounded-md border border-${headerBackgroundColor}-600 bg-${headerBackgroundColor} ring-offset-muted placeholder:text-muted-foreground focus-visible:ring-primary px-3 py-1 text-sm transition-opacity hover:opacity-80 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50`}\n >\n Previous\n </button>\n <span className=\"text-sm\">\n Page {currentPage} of {totalPages}\n </span>\n <button\n onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))}\n disabled={currentPage === totalPages}\n className={`rounded-md border border-${headerBackgroundColor}-600 bg-${headerBackgroundColor} ring-offset-muted placeholder:text-muted-foreground focus-visible:ring-primary px-3 py-1 text-sm transition-opacity hover:opacity-80 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50`}\n >\n Next\n </button>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const tableWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"TableWidget\",\n displayName: \"Table Widget\",\n tabsConfig: [\n { id: \"styling\", label: \"Styling\" },\n { id: \"behavior\", label: \"Behavior\" },\n { id: \"data\", label: \"Data\" },\n ],\n dataSourceTargetProps: [\"data\"],\n fields: [\n // Content Tab - Title Group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed above the table\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Title text displayed above the table\",\n defaultValue: \"Products\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n label: \"Title Font Size\",\n defaultValue: \"xl\",\n key: \"titleFontSize\",\n description: \"Font size for the widget title\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n\n // Styling Tab - Design Group\n {\n type: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background for the table container\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"alternatingColorEnabled\",\n label: \"Enable Alternating Colors\",\n type: \"boolean\",\n description: \"Enable alternating colors for table rows\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n key: \"headerBackgroundColor\",\n label: \"Header Background\",\n description: \"Background color for the table header\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for table content\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"headerTextColor\",\n label: \"Header Text Color\",\n description: \"Text color for the table header\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the table container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the table container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n\n // Behavior Tab - Features Group\n {\n key: \"filterEnabled\",\n label: \"Enable Filters\",\n type: \"boolean\",\n description: \"Show global search and column filters\",\n defaultValue: true,\n tab: \"behavior\",\n group: \"Features\",\n },\n {\n key: \"sortingEnabled\",\n label: \"Enable Sorting\",\n type: \"boolean\",\n description: \"Allow sorting by clicking column headers\",\n defaultValue: true,\n tab: \"behavior\",\n group: \"Features\",\n },\n {\n key: \"paginationEnabled\",\n label: \"Enable Pagination\",\n type: \"boolean\",\n description: \"Split data into pages\",\n defaultValue: true,\n tab: \"behavior\",\n group: \"Features\",\n },\n {\n key: \"maxRowsPerPage\",\n label: \"Max Rows Per Page\",\n type: \"number\",\n description: \"Maximum number of rows to display per page\",\n min: 1,\n max: 50,\n step: 1,\n defaultValue: 5,\n tab: \"behavior\",\n group: \"Features\",\n requiresKeyToBeTrue: \"paginationEnabled\",\n },\n\n // Data Tab\n {\n key: \"dataSource\",\n label: \"Data Source\",\n type: \"dataSource\",\n description: \"Configure data source for the table\",\n tab: \"data\",\n group: \"Data Configuration\",\n },\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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ACb,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;EAGF;GACE,MAAM;GACN,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD,cAAc;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,cAAc;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,cAAc;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,MAAM;GACN,OAAO;GACP,KAAK;GACL,OAAO;GACR;EACD,gBAAgB;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,qBAAqB;GACnB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EAGF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,KAAK;GACL,MAAM;GACN,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EAGD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACR;EACF;CACF"}
@@ -271,4 +271,4 @@ const toDoWidgetPropertySchema = {
271
271
  //#endregion
272
272
  export { ToDoWidget_exports as n, toDoWidgetPropertySchema as r, ToDoWidget as t };
273
273
 
274
- //# sourceMappingURL=ToDoWidget-D8YIsl7y.mjs.map
274
+ //# sourceMappingURL=ToDoWidget-4EZIWq_Z.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ToDoWidget-D8YIsl7y.mjs","names":[],"sources":["../src/hooks/use-todos.preview.ts","../src/hooks/use-todos.ts","../src/widgets/ToDoWidget.tsx"],"sourcesContent":["import type { Todo } from \"./use-todos.types\";\n\nconst now = new Date();\n\nfunction daysFromNow(days: number): string {\n const d = new Date(now);\n d.setDate(d.getDate() + days);\n return d.toISOString();\n}\n\nexport const PREVIEW_DATA: Todo[] = [\n {\n id: 1,\n body: \"Send follow-up email to new leads\",\n dueAt: daysFromNow(1),\n completedAt: null,\n createdAt: daysFromNow(-2),\n contactName: \"Sarah Johnson\",\n },\n {\n id: 2,\n body: \"Prepare slides for team training\",\n dueAt: daysFromNow(3),\n completedAt: null,\n createdAt: daysFromNow(-1),\n contactName: null,\n },\n {\n id: 3,\n body: \"Review monthly sales report\",\n dueAt: daysFromNow(-1),\n completedAt: null,\n createdAt: daysFromNow(-5),\n contactName: \"Mike Chen\",\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-todos.preview\";\nimport type { ApiTodo, Todo } from \"./use-todos.types\";\n\nexport type { TodoContact, ApiTodo, Todo } from \"./use-todos.types\";\n\nexport function useTodos(): UseQueryResult<Todo[], Error> {\n const { baseUrl, getApiHeaders } = useDataSourceConfig();\n const { isPreview } = useWidgetPreviewContext();\n\n return useQuery({\n queryKey: [\n \"portal-widget-use\",\n \"todos\",\n isPreview ? \"preview\" : baseUrl,\n ] as const,\n queryFn: async ({ signal }): Promise<Todo[]> => {\n const url = baseUrl ? `${baseUrl}/tasks` : \"/tasks\";\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 todos: ${response.status}`);\n }\n\n const data: ApiTodo[] = await response.json();\n return transformTodos(data);\n },\n enabled: !isPreview,\n ...(isPreview && { placeholderData: PREVIEW_DATA }),\n });\n}\n\nfunction transformTodos(rawData: ApiTodo[]): Todo[] {\n return rawData.map((todo) => ({\n id: todo.id,\n body: todo.body,\n dueAt: todo.due_at,\n completedAt: todo.completed_at,\n createdAt: todo.created_at,\n contactName: todo.contact\n ? `${todo.contact.first_name} ${todo.contact.last_name}`\n : null,\n }));\n}\n","import 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 { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\nimport { faListCheck, faPlus } from \"@fortawesome/pro-regular-svg-icons\";\nimport { useTodos } from \"../hooks/use-todos\";\nimport { ErrorState } from \"../components/error-state\";\n\ntype ToDoWidgetProps = 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 // Content\n maxItems?: number;\n};\n\nexport function ToDoWidget({\n // Title defaults\n titleEnabled = true,\n titleText = \"To-Do\",\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 // Content defaults\n maxItems = 5,\n\n className,\n ...props\n}: ToDoWidgetProps): 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: todos = [], isLoading, isError } = useTodos();\n\n // Use API data if available, otherwise fall back to demo data\n const displayTodos = todos.length > 0 ? todos : [];\n\n // Filter out completed tasks\n const activeTodos = displayTodos.filter((todo) => !todo.completedAt);\n const todosToShow = activeTodos.slice(0, maxItems);\n const remainingCount = activeTodos.length - todosToShow.length;\n const isEmpty = activeTodos.length === 0;\n\n return (\n <div\n className={`overflow-hidden rounded-${borderRadius} bg-${backgroundColor} text-${textColor} p-${padding} ${className ?? \"\"}`}\n style={{ backgroundImage }}\n {...props}\n >\n {/* Header */}\n <div className=\"mb-3 flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n {titleEnabled && titleText && (\n <h2\n className={`text-${titleFontSize} font-bold text-${titleColor}`}\n >\n {titleText}\n </h2>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n {!isEmpty && !isLoading && (\n <span className={`text-2xl font-bold text-${accentColor}`}>\n {activeTodos.length}\n </span>\n )}\n <div\n className={`flex h-10 w-10 shrink-0 items-center justify-center`}\n >\n <FontAwesomeIcon\n icon={faListCheck}\n className={`h-5 w-5 text-${accentColor}-foreground`}\n />\n </div>\n </div>\n </div>\n\n {/* Loading state */}\n {isLoading ? (\n <div className=\"flex min-h-[120px] items-center justify-center\">\n <div className=\"h-6 w-6 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n </div>\n ) : isError ? (\n /* Error state */\n <ErrorState />\n ) : isEmpty ? (\n /* Empty state */\n <div className=\"flex flex-col items-center justify-center py-8\">\n <p className={`text-center text-${textColor}/60`}>\n You&apos;ve got nothing else To-Do!\n </p>\n </div>\n ) : (\n /* Todo List */\n <>\n <div className=\"flex flex-col\">\n {todosToShow.map((todo, index) => (\n <div\n key={todo.id}\n className={`flex items-center gap-3 py-2.5 ${\n index !== todosToShow.length - 1\n ? `border-b border-${textColor}/10`\n : \"\"\n }`}\n >\n <input\n type=\"checkbox\"\n className={`h-5 w-5 rounded-full border-2 border-${textColor}/30 bg-transparent`}\n checked={!!todo.completedAt}\n readOnly\n />\n <span className=\"line-clamp-1 flex-1 text-sm\">{todo.body}</span>\n </div>\n ))}\n </div>\n\n {/* Footer */}\n <div className=\"mt-2 flex items-center justify-between\">\n {remainingCount > 0 && (\n <span className={`text-sm text-${textColor}/50 underline`}>\n {remainingCount} more task{remainingCount > 1 ? \"s\" : \"\"}\n </span>\n )}\n <div className=\"ml-auto\">\n <FontAwesomeIcon\n icon={faPlus}\n className={`h-5 w-5 text-${textColor}/50`}\n />\n </div>\n </div>\n </>\n )}\n </div>\n );\n}\n\nexport const toDoWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"ToDoWidget\",\n displayName: \"To-Do 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 todo list\",\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 todo list\",\n defaultValue: \"To-Do\",\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 todo items\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"accentColor\",\n label: \"Accent Color\",\n description: \"Color used for count badge and icon\",\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 {\n key: \"maxItems\",\n label: \"Max Items\",\n type: \"number\",\n description: \"Maximum number of todo items to display\",\n min: 1,\n max: 20,\n step: 1,\n defaultValue: 5,\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} as const satisfies WidgetPropertySchema;\n"],"mappings":"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"}
1
+ {"version":3,"file":"ToDoWidget-4EZIWq_Z.mjs","names":[],"sources":["../src/hooks/use-todos.preview.ts","../src/hooks/use-todos.ts","../src/widgets/ToDoWidget.tsx"],"sourcesContent":["import type { Todo } from \"./use-todos.types\";\n\nconst now = new Date();\n\nfunction daysFromNow(days: number): string {\n const d = new Date(now);\n d.setDate(d.getDate() + days);\n return d.toISOString();\n}\n\nexport const PREVIEW_DATA: Todo[] = [\n {\n id: 1,\n body: \"Send follow-up email to new leads\",\n dueAt: daysFromNow(1),\n completedAt: null,\n createdAt: daysFromNow(-2),\n contactName: \"Sarah Johnson\",\n },\n {\n id: 2,\n body: \"Prepare slides for team training\",\n dueAt: daysFromNow(3),\n completedAt: null,\n createdAt: daysFromNow(-1),\n contactName: null,\n },\n {\n id: 3,\n body: \"Review monthly sales report\",\n dueAt: daysFromNow(-1),\n completedAt: null,\n createdAt: daysFromNow(-5),\n contactName: \"Mike Chen\",\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-todos.preview\";\nimport type { ApiTodo, Todo } from \"./use-todos.types\";\n\nexport type { TodoContact, ApiTodo, Todo } from \"./use-todos.types\";\n\nexport function useTodos(): UseQueryResult<Todo[], Error> {\n const { baseUrl, getApiHeaders } = useDataSourceConfig();\n const { isPreview } = useWidgetPreviewContext();\n\n return useQuery({\n queryKey: [\n \"portal-widget-use\",\n \"todos\",\n isPreview ? \"preview\" : baseUrl,\n ] as const,\n queryFn: async ({ signal }): Promise<Todo[]> => {\n const url = baseUrl ? `${baseUrl}/tasks` : \"/tasks\";\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 todos: ${response.status}`);\n }\n\n const data: ApiTodo[] = await response.json();\n return transformTodos(data);\n },\n enabled: !isPreview,\n ...(isPreview && { placeholderData: PREVIEW_DATA }),\n });\n}\n\nfunction transformTodos(rawData: ApiTodo[]): Todo[] {\n return rawData.map((todo) => ({\n id: todo.id,\n body: todo.body,\n dueAt: todo.due_at,\n completedAt: todo.completed_at,\n createdAt: todo.created_at,\n contactName: todo.contact\n ? `${todo.contact.first_name} ${todo.contact.last_name}`\n : null,\n }));\n}\n","import 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 { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\nimport { faListCheck, faPlus } from \"@fortawesome/pro-regular-svg-icons\";\nimport { useTodos } from \"../hooks/use-todos\";\nimport { ErrorState } from \"../components/error-state\";\n\ntype ToDoWidgetProps = 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 // Content\n maxItems?: number;\n};\n\nexport function ToDoWidget({\n // Title defaults\n titleEnabled = true,\n titleText = \"To-Do\",\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 // Content defaults\n maxItems = 5,\n\n className,\n ...props\n}: ToDoWidgetProps): 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: todos = [], isLoading, isError } = useTodos();\n\n // Use API data if available, otherwise fall back to demo data\n const displayTodos = todos.length > 0 ? todos : [];\n\n // Filter out completed tasks\n const activeTodos = displayTodos.filter((todo) => !todo.completedAt);\n const todosToShow = activeTodos.slice(0, maxItems);\n const remainingCount = activeTodos.length - todosToShow.length;\n const isEmpty = activeTodos.length === 0;\n\n return (\n <div\n className={`overflow-hidden rounded-${borderRadius} bg-${backgroundColor} text-${textColor} p-${padding} ${className ?? \"\"}`}\n style={{ backgroundImage }}\n {...props}\n >\n {/* Header */}\n <div className=\"mb-3 flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n {titleEnabled && titleText && (\n <h2\n className={`text-${titleFontSize} font-bold text-${titleColor}`}\n >\n {titleText}\n </h2>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n {!isEmpty && !isLoading && (\n <span className={`text-2xl font-bold text-${accentColor}`}>\n {activeTodos.length}\n </span>\n )}\n <div\n className={`flex h-10 w-10 shrink-0 items-center justify-center`}\n >\n <FontAwesomeIcon\n icon={faListCheck}\n className={`h-5 w-5 text-${accentColor}-foreground`}\n />\n </div>\n </div>\n </div>\n\n {/* Loading state */}\n {isLoading ? (\n <div className=\"flex min-h-[120px] items-center justify-center\">\n <div className=\"h-6 w-6 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n </div>\n ) : isError ? (\n /* Error state */\n <ErrorState />\n ) : isEmpty ? (\n /* Empty state */\n <div className=\"flex flex-col items-center justify-center py-8\">\n <p className={`text-center text-${textColor}/60`}>\n You&apos;ve got nothing else To-Do!\n </p>\n </div>\n ) : (\n /* Todo List */\n <>\n <div className=\"flex flex-col\">\n {todosToShow.map((todo, index) => (\n <div\n key={todo.id}\n className={`flex items-center gap-3 py-2.5 ${\n index !== todosToShow.length - 1\n ? `border-b border-${textColor}/10`\n : \"\"\n }`}\n >\n <input\n type=\"checkbox\"\n className={`h-5 w-5 rounded-full border-2 border-${textColor}/30 bg-transparent`}\n checked={!!todo.completedAt}\n readOnly\n />\n <span className=\"line-clamp-1 flex-1 text-sm\">{todo.body}</span>\n </div>\n ))}\n </div>\n\n {/* Footer */}\n <div className=\"mt-2 flex items-center justify-between\">\n {remainingCount > 0 && (\n <span className={`text-sm text-${textColor}/50 underline`}>\n {remainingCount} more task{remainingCount > 1 ? \"s\" : \"\"}\n </span>\n )}\n <div className=\"ml-auto\">\n <FontAwesomeIcon\n icon={faPlus}\n className={`h-5 w-5 text-${textColor}/50`}\n />\n </div>\n </div>\n </>\n )}\n </div>\n );\n}\n\nexport const toDoWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"ToDoWidget\",\n displayName: \"To-Do 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 todo list\",\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 todo list\",\n defaultValue: \"To-Do\",\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 todo items\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"accentColor\",\n label: \"Accent Color\",\n description: \"Color used for count badge and icon\",\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 {\n key: \"maxItems\",\n label: \"Max Items\",\n type: \"number\",\n description: \"Maximum number of todo items to display\",\n min: 1,\n max: 20,\n step: 1,\n defaultValue: 5,\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} as const satisfies WidgetPropertySchema;\n"],"mappings":"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"}
@@ -288,4 +288,4 @@ Object.defineProperty(exports, "toDoWidgetPropertySchema", {
288
288
  }
289
289
  });
290
290
 
291
- //# sourceMappingURL=ToDoWidget-Dvs0GDkx.cjs.map
291
+ //# sourceMappingURL=ToDoWidget-D5BFKUrZ.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ToDoWidget-Dvs0GDkx.cjs","names":["FontAwesomeIcon","faListCheck","ErrorState","faPlus"],"sources":["../src/hooks/use-todos.preview.ts","../src/hooks/use-todos.ts","../src/widgets/ToDoWidget.tsx"],"sourcesContent":["import type { Todo } from \"./use-todos.types\";\n\nconst now = new Date();\n\nfunction daysFromNow(days: number): string {\n const d = new Date(now);\n d.setDate(d.getDate() + days);\n return d.toISOString();\n}\n\nexport const PREVIEW_DATA: Todo[] = [\n {\n id: 1,\n body: \"Send follow-up email to new leads\",\n dueAt: daysFromNow(1),\n completedAt: null,\n createdAt: daysFromNow(-2),\n contactName: \"Sarah Johnson\",\n },\n {\n id: 2,\n body: \"Prepare slides for team training\",\n dueAt: daysFromNow(3),\n completedAt: null,\n createdAt: daysFromNow(-1),\n contactName: null,\n },\n {\n id: 3,\n body: \"Review monthly sales report\",\n dueAt: daysFromNow(-1),\n completedAt: null,\n createdAt: daysFromNow(-5),\n contactName: \"Mike Chen\",\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-todos.preview\";\nimport type { ApiTodo, Todo } from \"./use-todos.types\";\n\nexport type { TodoContact, ApiTodo, Todo } from \"./use-todos.types\";\n\nexport function useTodos(): UseQueryResult<Todo[], Error> {\n const { baseUrl, getApiHeaders } = useDataSourceConfig();\n const { isPreview } = useWidgetPreviewContext();\n\n return useQuery({\n queryKey: [\n \"portal-widget-use\",\n \"todos\",\n isPreview ? \"preview\" : baseUrl,\n ] as const,\n queryFn: async ({ signal }): Promise<Todo[]> => {\n const url = baseUrl ? `${baseUrl}/tasks` : \"/tasks\";\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 todos: ${response.status}`);\n }\n\n const data: ApiTodo[] = await response.json();\n return transformTodos(data);\n },\n enabled: !isPreview,\n ...(isPreview && { placeholderData: PREVIEW_DATA }),\n });\n}\n\nfunction transformTodos(rawData: ApiTodo[]): Todo[] {\n return rawData.map((todo) => ({\n id: todo.id,\n body: todo.body,\n dueAt: todo.due_at,\n completedAt: todo.completed_at,\n createdAt: todo.created_at,\n contactName: todo.contact\n ? `${todo.contact.first_name} ${todo.contact.last_name}`\n : null,\n }));\n}\n","import 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 { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\nimport { faListCheck, faPlus } from \"@fortawesome/pro-regular-svg-icons\";\nimport { useTodos } from \"../hooks/use-todos\";\nimport { ErrorState } from \"../components/error-state\";\n\ntype ToDoWidgetProps = 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 // Content\n maxItems?: number;\n};\n\nexport function ToDoWidget({\n // Title defaults\n titleEnabled = true,\n titleText = \"To-Do\",\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 // Content defaults\n maxItems = 5,\n\n className,\n ...props\n}: ToDoWidgetProps): 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: todos = [], isLoading, isError } = useTodos();\n\n // Use API data if available, otherwise fall back to demo data\n const displayTodos = todos.length > 0 ? todos : [];\n\n // Filter out completed tasks\n const activeTodos = displayTodos.filter((todo) => !todo.completedAt);\n const todosToShow = activeTodos.slice(0, maxItems);\n const remainingCount = activeTodos.length - todosToShow.length;\n const isEmpty = activeTodos.length === 0;\n\n return (\n <div\n className={`overflow-hidden rounded-${borderRadius} bg-${backgroundColor} text-${textColor} p-${padding} ${className ?? \"\"}`}\n style={{ backgroundImage }}\n {...props}\n >\n {/* Header */}\n <div className=\"mb-3 flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n {titleEnabled && titleText && (\n <h2\n className={`text-${titleFontSize} font-bold text-${titleColor}`}\n >\n {titleText}\n </h2>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n {!isEmpty && !isLoading && (\n <span className={`text-2xl font-bold text-${accentColor}`}>\n {activeTodos.length}\n </span>\n )}\n <div\n className={`flex h-10 w-10 shrink-0 items-center justify-center`}\n >\n <FontAwesomeIcon\n icon={faListCheck}\n className={`h-5 w-5 text-${accentColor}-foreground`}\n />\n </div>\n </div>\n </div>\n\n {/* Loading state */}\n {isLoading ? (\n <div className=\"flex min-h-[120px] items-center justify-center\">\n <div className=\"h-6 w-6 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n </div>\n ) : isError ? (\n /* Error state */\n <ErrorState />\n ) : isEmpty ? (\n /* Empty state */\n <div className=\"flex flex-col items-center justify-center py-8\">\n <p className={`text-center text-${textColor}/60`}>\n You&apos;ve got nothing else To-Do!\n </p>\n </div>\n ) : (\n /* Todo List */\n <>\n <div className=\"flex flex-col\">\n {todosToShow.map((todo, index) => (\n <div\n key={todo.id}\n className={`flex items-center gap-3 py-2.5 ${\n index !== todosToShow.length - 1\n ? `border-b border-${textColor}/10`\n : \"\"\n }`}\n >\n <input\n type=\"checkbox\"\n className={`h-5 w-5 rounded-full border-2 border-${textColor}/30 bg-transparent`}\n checked={!!todo.completedAt}\n readOnly\n />\n <span className=\"line-clamp-1 flex-1 text-sm\">{todo.body}</span>\n </div>\n ))}\n </div>\n\n {/* Footer */}\n <div className=\"mt-2 flex items-center justify-between\">\n {remainingCount > 0 && (\n <span className={`text-sm text-${textColor}/50 underline`}>\n {remainingCount} more task{remainingCount > 1 ? \"s\" : \"\"}\n </span>\n )}\n <div className=\"ml-auto\">\n <FontAwesomeIcon\n icon={faPlus}\n className={`h-5 w-5 text-${textColor}/50`}\n />\n </div>\n </div>\n </>\n )}\n </div>\n );\n}\n\nexport const toDoWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"ToDoWidget\",\n displayName: \"To-Do 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 todo list\",\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 todo list\",\n defaultValue: \"To-Do\",\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 todo items\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"accentColor\",\n label: \"Accent Color\",\n description: \"Color used for count badge and icon\",\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 {\n key: \"maxItems\",\n label: \"Max Items\",\n type: \"number\",\n description: \"Maximum number of todo items to display\",\n min: 1,\n max: 20,\n step: 1,\n defaultValue: 5,\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} 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;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,KAAK;GACL,MAAM;GACN,cAAc;GACd,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;EACH;CACF"}
1
+ {"version":3,"file":"ToDoWidget-D5BFKUrZ.cjs","names":["FontAwesomeIcon","faListCheck","ErrorState","faPlus"],"sources":["../src/hooks/use-todos.preview.ts","../src/hooks/use-todos.ts","../src/widgets/ToDoWidget.tsx"],"sourcesContent":["import type { Todo } from \"./use-todos.types\";\n\nconst now = new Date();\n\nfunction daysFromNow(days: number): string {\n const d = new Date(now);\n d.setDate(d.getDate() + days);\n return d.toISOString();\n}\n\nexport const PREVIEW_DATA: Todo[] = [\n {\n id: 1,\n body: \"Send follow-up email to new leads\",\n dueAt: daysFromNow(1),\n completedAt: null,\n createdAt: daysFromNow(-2),\n contactName: \"Sarah Johnson\",\n },\n {\n id: 2,\n body: \"Prepare slides for team training\",\n dueAt: daysFromNow(3),\n completedAt: null,\n createdAt: daysFromNow(-1),\n contactName: null,\n },\n {\n id: 3,\n body: \"Review monthly sales report\",\n dueAt: daysFromNow(-1),\n completedAt: null,\n createdAt: daysFromNow(-5),\n contactName: \"Mike Chen\",\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-todos.preview\";\nimport type { ApiTodo, Todo } from \"./use-todos.types\";\n\nexport type { TodoContact, ApiTodo, Todo } from \"./use-todos.types\";\n\nexport function useTodos(): UseQueryResult<Todo[], Error> {\n const { baseUrl, getApiHeaders } = useDataSourceConfig();\n const { isPreview } = useWidgetPreviewContext();\n\n return useQuery({\n queryKey: [\n \"portal-widget-use\",\n \"todos\",\n isPreview ? \"preview\" : baseUrl,\n ] as const,\n queryFn: async ({ signal }): Promise<Todo[]> => {\n const url = baseUrl ? `${baseUrl}/tasks` : \"/tasks\";\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 todos: ${response.status}`);\n }\n\n const data: ApiTodo[] = await response.json();\n return transformTodos(data);\n },\n enabled: !isPreview,\n ...(isPreview && { placeholderData: PREVIEW_DATA }),\n });\n}\n\nfunction transformTodos(rawData: ApiTodo[]): Todo[] {\n return rawData.map((todo) => ({\n id: todo.id,\n body: todo.body,\n dueAt: todo.due_at,\n completedAt: todo.completed_at,\n createdAt: todo.created_at,\n contactName: todo.contact\n ? `${todo.contact.first_name} ${todo.contact.last_name}`\n : null,\n }));\n}\n","import 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 { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\nimport { faListCheck, faPlus } from \"@fortawesome/pro-regular-svg-icons\";\nimport { useTodos } from \"../hooks/use-todos\";\nimport { ErrorState } from \"../components/error-state\";\n\ntype ToDoWidgetProps = 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 // Content\n maxItems?: number;\n};\n\nexport function ToDoWidget({\n // Title defaults\n titleEnabled = true,\n titleText = \"To-Do\",\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 // Content defaults\n maxItems = 5,\n\n className,\n ...props\n}: ToDoWidgetProps): 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: todos = [], isLoading, isError } = useTodos();\n\n // Use API data if available, otherwise fall back to demo data\n const displayTodos = todos.length > 0 ? todos : [];\n\n // Filter out completed tasks\n const activeTodos = displayTodos.filter((todo) => !todo.completedAt);\n const todosToShow = activeTodos.slice(0, maxItems);\n const remainingCount = activeTodos.length - todosToShow.length;\n const isEmpty = activeTodos.length === 0;\n\n return (\n <div\n className={`overflow-hidden rounded-${borderRadius} bg-${backgroundColor} text-${textColor} p-${padding} ${className ?? \"\"}`}\n style={{ backgroundImage }}\n {...props}\n >\n {/* Header */}\n <div className=\"mb-3 flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n {titleEnabled && titleText && (\n <h2\n className={`text-${titleFontSize} font-bold text-${titleColor}`}\n >\n {titleText}\n </h2>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n {!isEmpty && !isLoading && (\n <span className={`text-2xl font-bold text-${accentColor}`}>\n {activeTodos.length}\n </span>\n )}\n <div\n className={`flex h-10 w-10 shrink-0 items-center justify-center`}\n >\n <FontAwesomeIcon\n icon={faListCheck}\n className={`h-5 w-5 text-${accentColor}-foreground`}\n />\n </div>\n </div>\n </div>\n\n {/* Loading state */}\n {isLoading ? (\n <div className=\"flex min-h-[120px] items-center justify-center\">\n <div className=\"h-6 w-6 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n </div>\n ) : isError ? (\n /* Error state */\n <ErrorState />\n ) : isEmpty ? (\n /* Empty state */\n <div className=\"flex flex-col items-center justify-center py-8\">\n <p className={`text-center text-${textColor}/60`}>\n You&apos;ve got nothing else To-Do!\n </p>\n </div>\n ) : (\n /* Todo List */\n <>\n <div className=\"flex flex-col\">\n {todosToShow.map((todo, index) => (\n <div\n key={todo.id}\n className={`flex items-center gap-3 py-2.5 ${\n index !== todosToShow.length - 1\n ? `border-b border-${textColor}/10`\n : \"\"\n }`}\n >\n <input\n type=\"checkbox\"\n className={`h-5 w-5 rounded-full border-2 border-${textColor}/30 bg-transparent`}\n checked={!!todo.completedAt}\n readOnly\n />\n <span className=\"line-clamp-1 flex-1 text-sm\">{todo.body}</span>\n </div>\n ))}\n </div>\n\n {/* Footer */}\n <div className=\"mt-2 flex items-center justify-between\">\n {remainingCount > 0 && (\n <span className={`text-sm text-${textColor}/50 underline`}>\n {remainingCount} more task{remainingCount > 1 ? \"s\" : \"\"}\n </span>\n )}\n <div className=\"ml-auto\">\n <FontAwesomeIcon\n icon={faPlus}\n className={`h-5 w-5 text-${textColor}/50`}\n />\n </div>\n </div>\n </>\n )}\n </div>\n );\n}\n\nexport const toDoWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"ToDoWidget\",\n displayName: \"To-Do 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 todo list\",\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 todo list\",\n defaultValue: \"To-Do\",\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 todo items\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"accentColor\",\n label: \"Accent Color\",\n description: \"Color used for count badge and icon\",\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 {\n key: \"maxItems\",\n label: \"Max Items\",\n type: \"number\",\n description: \"Maximum number of todo items to display\",\n min: 1,\n max: 20,\n step: 1,\n defaultValue: 5,\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} 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;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,KAAK;GACL,MAAM;GACN,cAAc;GACd,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;EACH;CACF"}
@@ -186,4 +186,4 @@ const videoWidgetPropertySchema = {
186
186
  //#endregion
187
187
  export { VideoWidget_exports as n, videoWidgetPropertySchema as r, VideoWidget as t };
188
188
 
189
- //# sourceMappingURL=VideoWidget-D_1kluGw.mjs.map
189
+ //# sourceMappingURL=VideoWidget-CYSOjVec.mjs.map