@fluid-app/portal-widgets 0.1.20 → 0.1.22
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.
- package/dist/{CalendarWidget-DW7q6Q7_.cjs → CalendarWidget-BfBvIACH.cjs} +5 -6
- package/dist/CalendarWidget-BfBvIACH.cjs.map +1 -0
- package/dist/{CalendarWidget-DAHnT9Wn.mjs → CalendarWidget-zAxc3BTd.mjs} +5 -6
- package/dist/CalendarWidget-zAxc3BTd.mjs.map +1 -0
- package/dist/{CarouselWidget-PEm6vktC.cjs → CarouselWidget-D51Kz6r8.cjs} +3 -3
- package/dist/{CarouselWidget-PEm6vktC.cjs.map → CarouselWidget-D51Kz6r8.cjs.map} +1 -1
- package/dist/{CarouselWidget-MOGejQHD.mjs → CarouselWidget-DFmVlZlT.mjs} +3 -3
- package/dist/{CarouselWidget-MOGejQHD.mjs.map → CarouselWidget-DFmVlZlT.mjs.map} +1 -1
- package/dist/{CatchUpWidget-vEP5scfy.mjs → CatchUpWidget-CAmpqiDr.mjs} +4 -12
- package/dist/CatchUpWidget-CAmpqiDr.mjs.map +1 -0
- package/dist/{CatchUpWidget-CZMptzf8.cjs → CatchUpWidget-eAe6e6SA.cjs} +4 -12
- package/dist/CatchUpWidget-eAe6e6SA.cjs.map +1 -0
- package/dist/{EmbedWidget-RuCm5uOj.mjs → EmbedWidget-CZanYM7p.mjs} +4 -11
- package/dist/EmbedWidget-CZanYM7p.mjs.map +1 -0
- package/dist/{EmbedWidget-BENxbwxX.cjs → EmbedWidget-I-vrAy02.cjs} +4 -11
- package/dist/EmbedWidget-I-vrAy02.cjs.map +1 -0
- package/dist/{ImageWidget--owpCpb0.mjs → ImageWidget-CJzO7yV9.mjs} +2 -2
- package/dist/{ImageWidget--owpCpb0.mjs.map → ImageWidget-CJzO7yV9.mjs.map} +1 -1
- package/dist/{ImageWidget-B2stGyqB.cjs → ImageWidget-CR-dZIET.cjs} +2 -2
- package/dist/{ImageWidget-B2stGyqB.cjs.map → ImageWidget-CR-dZIET.cjs.map} +1 -1
- package/dist/{ListWidget-C0RDtImi.cjs → ListWidget-B0W-5BLL.cjs} +1 -1
- package/dist/{ListWidget-DdvuIQXy.mjs → ListWidget-Bld9LfFO.mjs} +3 -3
- package/dist/{ListWidget-DdvuIQXy.mjs.map → ListWidget-Bld9LfFO.mjs.map} +1 -1
- package/dist/{ListWidget-DPVLRWoB.cjs → ListWidget-dib-Tl8j.cjs} +3 -3
- package/dist/{ListWidget-DPVLRWoB.cjs.map → ListWidget-dib-Tl8j.cjs.map} +1 -1
- package/dist/{MediaRenderer-CcJvyOJ1.cjs → MediaRenderer-Crlzjyvh.cjs} +3 -7
- package/dist/MediaRenderer-Crlzjyvh.cjs.map +1 -0
- package/dist/{MediaRenderer-Uq90PZcY.mjs → MediaRenderer-CrvEIBKa.mjs} +3 -7
- package/dist/MediaRenderer-CrvEIBKa.mjs.map +1 -0
- package/dist/{NestedWidget-DoevHJKG.mjs → NestedWidget-CC2iiuYe.mjs} +3 -3
- package/dist/{NestedWidget-DoevHJKG.mjs.map → NestedWidget-CC2iiuYe.mjs.map} +1 -1
- package/dist/{NestedWidget-DjZYPLc7.cjs → NestedWidget-CM6a_uhX.cjs} +1 -1
- package/dist/{NestedWidget-DszMmpt7.cjs → NestedWidget-Dbomg7kK.cjs} +3 -3
- package/dist/{NestedWidget-DszMmpt7.cjs.map → NestedWidget-Dbomg7kK.cjs.map} +1 -1
- package/dist/{QuickShareWidget-CdvP1eRx.mjs → QuickShareWidget-2UgfRO1A.mjs} +5 -15
- package/dist/QuickShareWidget-2UgfRO1A.mjs.map +1 -0
- package/dist/{QuickShareWidget-Dg2OcMYg.cjs → QuickShareWidget-D61LGZSP.cjs} +5 -15
- package/dist/QuickShareWidget-D61LGZSP.cjs.map +1 -0
- package/dist/{RecentActivityWidget-RGChzfaD.cjs → RecentActivityWidget-DgduzsLQ.cjs} +39 -35
- package/dist/RecentActivityWidget-DgduzsLQ.cjs.map +1 -0
- package/dist/{RecentActivityWidget-Cj-vLOGu.mjs → RecentActivityWidget-ie7NPVyP.mjs} +38 -35
- package/dist/RecentActivityWidget-ie7NPVyP.mjs.map +1 -0
- package/dist/{SpacerWidget-DxR5K3hp.mjs → SpacerWidget-C3bosaHh.mjs} +3 -4
- package/dist/SpacerWidget-C3bosaHh.mjs.map +1 -0
- package/dist/{SpacerWidget-BdVf_Yqm.cjs → SpacerWidget-DyPRcRp7.cjs} +3 -4
- package/dist/SpacerWidget-DyPRcRp7.cjs.map +1 -0
- package/dist/{TableWidget-amUotAZN.cjs → TableWidget-BfYbPHK6.cjs} +1 -1
- package/dist/{TableWidget-bpvdvJHI.mjs → TableWidget-CGgzjcyK.mjs} +2 -2
- package/dist/{TableWidget-bpvdvJHI.mjs.map → TableWidget-CGgzjcyK.mjs.map} +1 -1
- package/dist/{TableWidget-BQNVZUkg.cjs → TableWidget-De_y_YBQ.cjs} +2 -2
- package/dist/{TableWidget-BQNVZUkg.cjs.map → TableWidget-De_y_YBQ.cjs.map} +1 -1
- package/dist/{ToDoWidget-D5BFKUrZ.cjs → ToDoWidget-B68qKav6.cjs} +4 -11
- package/dist/ToDoWidget-B68qKav6.cjs.map +1 -0
- package/dist/{ToDoWidget-4EZIWq_Z.mjs → ToDoWidget-Dp8UNmip.mjs} +4 -11
- package/dist/ToDoWidget-Dp8UNmip.mjs.map +1 -0
- package/dist/{VideoWidget-CqRHfFnI.cjs → VideoWidget-CU5OK-Ju.cjs} +2 -2
- package/dist/{VideoWidget-CqRHfFnI.cjs.map → VideoWidget-CU5OK-Ju.cjs.map} +1 -1
- package/dist/{VideoWidget-CYSOjVec.mjs → VideoWidget-DGR1U6CQ.mjs} +2 -2
- package/dist/{VideoWidget-CYSOjVec.mjs.map → VideoWidget-DGR1U6CQ.mjs.map} +1 -1
- package/dist/core/index.cjs +1 -1
- package/dist/core/index.d.cts.map +1 -1
- package/dist/core/index.d.mts.map +1 -1
- package/dist/core/index.mjs +1 -1
- package/dist/{scroll-arrows-BZIlsE_x.cjs → scroll-arrows-4aTDqcAw.cjs} +4 -11
- package/dist/scroll-arrows-4aTDqcAw.cjs.map +1 -0
- package/dist/{scroll-arrows-BevCYRNT.mjs → scroll-arrows-CTQrIV6z.mjs} +4 -11
- package/dist/scroll-arrows-CTQrIV6z.mjs.map +1 -0
- package/dist/ui/index.cjs +1 -1
- package/dist/ui/index.d.cts.map +1 -1
- package/dist/ui/index.d.mts.map +1 -1
- package/dist/ui/index.mjs +1 -1
- package/dist/widgets/index.cjs +26 -26
- package/dist/widgets/index.d.cts.map +1 -1
- package/dist/widgets/index.d.mts.map +1 -1
- package/dist/widgets/index.mjs +26 -26
- package/package.json +4 -6
- package/dist/CalendarWidget-DAHnT9Wn.mjs.map +0 -1
- package/dist/CalendarWidget-DW7q6Q7_.cjs.map +0 -1
- package/dist/CatchUpWidget-CZMptzf8.cjs.map +0 -1
- package/dist/CatchUpWidget-vEP5scfy.mjs.map +0 -1
- package/dist/EmbedWidget-BENxbwxX.cjs.map +0 -1
- package/dist/EmbedWidget-RuCm5uOj.mjs.map +0 -1
- package/dist/MediaRenderer-CcJvyOJ1.cjs.map +0 -1
- package/dist/MediaRenderer-Uq90PZcY.mjs.map +0 -1
- package/dist/QuickShareWidget-CdvP1eRx.mjs.map +0 -1
- package/dist/QuickShareWidget-Dg2OcMYg.cjs.map +0 -1
- package/dist/RecentActivityWidget-Cj-vLOGu.mjs.map +0 -1
- package/dist/RecentActivityWidget-RGChzfaD.cjs.map +0 -1
- package/dist/SpacerWidget-BdVf_Yqm.cjs.map +0 -1
- package/dist/SpacerWidget-DxR5K3hp.mjs.map +0 -1
- package/dist/ToDoWidget-4EZIWq_Z.mjs.map +0 -1
- package/dist/ToDoWidget-D5BFKUrZ.cjs.map +0 -1
- package/dist/scroll-arrows-BZIlsE_x.cjs.map +0 -1
- package/dist/scroll-arrows-BevCYRNT.mjs.map +0 -1
|
@@ -5,8 +5,7 @@ let react = require("react");
|
|
|
5
5
|
let _tanstack_react_query = require("@tanstack/react-query");
|
|
6
6
|
let _fluid_app_portal_core_data_sources_context = require("@fluid-app/portal-core/data-sources/context");
|
|
7
7
|
let _fluid_app_portal_core_data_sources_preview_context = require("@fluid-app/portal-core/data-sources/preview-context");
|
|
8
|
-
let
|
|
9
|
-
let _fortawesome_pro_regular_svg_icons = require("@fortawesome/pro-regular-svg-icons");
|
|
8
|
+
let lucide_react = require("lucide-react");
|
|
10
9
|
let _fluid_app_portal_core_registries = require("@fluid-app/portal-core/registries");
|
|
11
10
|
//#region src/hooks/use-calendar-events.preview.ts
|
|
12
11
|
const today = /* @__PURE__ */ new Date();
|
|
@@ -241,7 +240,7 @@ function CalendarWidget({ titleEnabled = true, titleText = "Calendar", titleFont
|
|
|
241
240
|
onClick: goToPrevMonth,
|
|
242
241
|
className: "hover:bg-foreground/10 rounded-full p-1",
|
|
243
242
|
"aria-label": "Previous month",
|
|
244
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
243
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronLeft, { className: "size-4" })
|
|
245
244
|
}),
|
|
246
245
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
247
246
|
className: "text-base font-semibold",
|
|
@@ -251,7 +250,7 @@ function CalendarWidget({ titleEnabled = true, titleText = "Calendar", titleFont
|
|
|
251
250
|
onClick: goToNextMonth,
|
|
252
251
|
className: "hover:bg-foreground/10 rounded-full p-1",
|
|
253
252
|
"aria-label": "Next month",
|
|
254
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
253
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronRight, { className: "size-4" })
|
|
255
254
|
})
|
|
256
255
|
]
|
|
257
256
|
}),
|
|
@@ -294,7 +293,7 @@ function CalendarWidget({ titleEnabled = true, titleText = "Calendar", titleFont
|
|
|
294
293
|
"aria-label": isCollapsed ? "Expand calendar" : "Collapse calendar",
|
|
295
294
|
children: [
|
|
296
295
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: `h-1 w-1/2 bg-${textColor}/50` }),
|
|
297
|
-
isCollapsed ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
296
|
+
isCollapsed ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronsDown, { className: "size-4" }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronsUp, { className: "size-4" }),
|
|
298
297
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: `h-1 w-1/2 bg-${textColor}/50` })
|
|
299
298
|
]
|
|
300
299
|
})
|
|
@@ -438,4 +437,4 @@ Object.defineProperty(exports, "calendarWidgetPropertySchema", {
|
|
|
438
437
|
}
|
|
439
438
|
});
|
|
440
439
|
|
|
441
|
-
//# sourceMappingURL=CalendarWidget-
|
|
440
|
+
//# sourceMappingURL=CalendarWidget-BfBvIACH.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CalendarWidget-BfBvIACH.cjs","names":["ErrorState","ChevronLeft","ChevronRight","ChevronsDown","ChevronsUp"],"sources":["../src/hooks/use-calendar-events.preview.ts","../src/hooks/use-calendar-events.ts","../src/widgets/CalendarWidget.tsx"],"sourcesContent":["import type { CalendarEvent } from \"./use-calendar-events.types\";\n\nconst today = new Date();\nconst inTwoDays = new Date(today);\ninTwoDays.setDate(inTwoDays.getDate() + 2);\n\nfunction toISO(date: Date, hours: number, minutes = 0): string {\n const d = new Date(date);\n d.setHours(hours, minutes, 0, 0);\n return d.toISOString();\n}\n\nfunction toDateString(date: Date): string {\n return date.toISOString().split(\"T\")[0]!;\n}\n\nexport const PREVIEW_DATA: CalendarEvent[] = [\n {\n id: 1,\n title: \"Team Strategy Call\",\n start: toISO(today, 9, 0),\n end: toISO(today, 10, 0),\n status: \"active\",\n color: \"#4f46e5\",\n },\n {\n id: 2,\n title: \"Product Launch Webinar\",\n start: toISO(today, 14, 0),\n end: toISO(today, 15, 30),\n status: \"active\",\n color: \"#0891b2\",\n venue: \"Zoom\",\n },\n {\n id: 3,\n title: \"Annual Leadership Summit\",\n start: `${toDateString(inTwoDays)}T00:00:00.000Z`,\n end: `${toDateString(inTwoDays)}T23:59:59.000Z`,\n status: \"active\",\n color: \"#059669\",\n isAllDay: true,\n venue: \"Convention Center\",\n },\n];\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useDataSourceConfig } from \"@fluid-app/portal-core/data-sources/context\";\nimport { useWidgetPreviewContext } from \"@fluid-app/portal-core/data-sources/preview-context\";\nimport { PREVIEW_DATA } from \"./use-calendar-events.preview\";\n\nimport type { CalendarEvent } from \"./use-calendar-events.types\";\n\nexport type { CalendarEvent } from \"./use-calendar-events.types\";\n\nexport function useCalendarEvents(): UseQueryResult<CalendarEvent[], Error> {\n const { baseUrl, getApiHeaders } = useDataSourceConfig();\n const { isPreview } = useWidgetPreviewContext();\n\n return useQuery({\n queryKey: [\n \"portal-widget-use\",\n \"calendar-events\",\n isPreview ? \"preview\" : baseUrl,\n ] as const,\n queryFn: async ({ signal }): Promise<CalendarEvent[]> => {\n const url = baseUrl\n ? `${baseUrl}/events.json?event_timeline=upcoming`\n : \"/events.json?event_timeline=upcoming\";\n const response = await fetch(url, {\n headers: {\n \"content-type\": \"application/json\",\n ...getApiHeaders?.(),\n },\n signal,\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch calendar events: ${response.status}`);\n }\n\n return response.json();\n },\n enabled: !isPreview,\n ...(isPreview && { placeholderData: PREVIEW_DATA }),\n });\n}\n","import { useState, useMemo, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n} from \"../core/fields\";\nimport {\n useCalendarEvents,\n type CalendarEvent,\n} from \"../hooks/use-calendar-events\";\nimport { ErrorState } from \"../components/error-state\";\nimport {\n ChevronLeft,\n ChevronRight,\n ChevronsDown,\n ChevronsUp,\n} from \"lucide-react\";\n\n// Utility to get days in a month\nconst getDaysInMonth = (year: number, month: number) => {\n return new Date(year, month + 1, 0).getDate();\n};\n\n// Utility to get the first day of month (0 = Sunday, 1 = Monday, etc.)\nconst getFirstDayOfMonth = (year: number, month: number) => {\n return new Date(year, month, 1).getDay();\n};\n\n// Generate calendar grid for a month\nconst generateMonthGrid = (year: number, month: number) => {\n const daysInMonth = getDaysInMonth(year, month);\n const firstDay = getFirstDayOfMonth(year, month);\n const today = new Date();\n\n const days: Array<{\n date: Date | null;\n isToday: boolean;\n isCurrentMonth: boolean;\n }> = [];\n\n // Add empty slots for days before the 1st\n for (let i = 0; i < firstDay; i++) {\n days.push({ date: null, isToday: false, isCurrentMonth: false });\n }\n\n // Add days of the month\n for (let day = 1; day <= daysInMonth; day++) {\n const date = new Date(year, month, day);\n const isToday =\n date.getDate() === today.getDate() &&\n date.getMonth() === today.getMonth() &&\n date.getFullYear() === today.getFullYear();\n days.push({ date, isToday, isCurrentMonth: true });\n }\n\n return days;\n};\n\n// Generate week grid for current week\nconst generateWeekGrid = () => {\n const today = new Date();\n const currentDay = today.getDay();\n const days: Array<{\n date: Date;\n isToday: boolean;\n }> = [];\n\n for (let i = 0; i < 7; i++) {\n const date = new Date(today);\n date.setDate(today.getDate() - currentDay + i);\n days.push({\n date,\n isToday: date.toDateString() === today.toDateString(),\n });\n }\n\n return days;\n};\n\n// Get events for a specific date\nconst getEventsForDate = (date: Date, events: CalendarEvent[]) => {\n const dayStart = new Date(date);\n dayStart.setHours(0, 0, 0, 0);\n const dayEnd = new Date(date);\n dayEnd.setHours(23, 59, 59, 999);\n\n return events.filter((event) => {\n const eventStart = new Date(event.start);\n const eventEnd = new Date(event.end);\n return eventStart <= dayEnd && eventEnd >= dayStart;\n });\n};\n\n// Check if a date has events\nconst hasEventsOnDate = (date: Date | null, events: CalendarEvent[]) => {\n if (!date) return false;\n return getEventsForDate(date, events).length > 0;\n};\n\n// Event item component\nconst EventItem = ({\n title,\n start,\n end,\n color,\n isAllDay,\n accentColor,\n}: CalendarEvent & { accentColor?: string }) => {\n const startTime = new Date(start).toLocaleTimeString(\"en-US\", {\n hour: \"numeric\",\n minute: \"2-digit\",\n });\n const endTime = new Date(end).toLocaleTimeString(\"en-US\", {\n hour: \"numeric\",\n minute: \"2-digit\",\n });\n\n return (\n <div className=\"flex gap-x-2\">\n <div\n className=\"w-0.5 shrink-0 rounded-full\"\n style={{ backgroundColor: color || accentColor }}\n />\n <div className=\"min-w-0 flex-1\">\n <div className=\"truncate text-sm font-medium\">{title}</div>\n <div className=\"text-xs opacity-60\">\n {isAllDay ? \"All day\" : `${startTime} - ${endTime}`}\n </div>\n </div>\n </div>\n );\n};\n\nconst dayNames = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"];\n\ntype DayButtonProps = {\n date: Date;\n isToday: boolean;\n isSelected: boolean;\n hasEvents: boolean;\n accentColor: string;\n onClick: () => void;\n extraClassName?: string;\n};\n\nfunction DayButton({\n date,\n isToday,\n isSelected,\n hasEvents,\n accentColor,\n onClick,\n extraClassName = \"\",\n}: DayButtonProps) {\n return (\n <button\n onClick={onClick}\n className={`relative flex aspect-square items-center justify-center rounded-full text-sm transition-colors ${\n isSelected\n ? `bg-${accentColor} text-${accentColor}-foreground`\n : isToday\n ? `bg-${accentColor}/30 text-${accentColor}-foreground hover:bg-${accentColor}/50`\n : `hover:bg-${accentColor}/50 hover:text-${accentColor}-foreground`\n } ${extraClassName}`}\n >\n {date.getDate()}\n {hasEvents && (\n <div\n className={`absolute bottom-1 h-1 w-1 rounded-full bg-${accentColor}`}\n />\n )}\n </button>\n );\n}\n\ntype CalendarWidgetProps = ComponentProps<\"div\"> & {\n // Title\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n // Styling\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n};\n\nexport function CalendarWidget({\n // Title defaults\n titleEnabled = true,\n titleText = \"Calendar\",\n titleFontSize = \"xl\",\n titleColor = \"foreground\",\n\n // Styling defaults\n background = {\n type: \"solid\",\n color: \"background\",\n },\n textColor = \"foreground\",\n accentColor = \"primary\",\n padding = 4,\n borderRadius = \"md\",\n\n className,\n ...props\n}: CalendarWidgetProps): React.JSX.Element {\n const backgroundColor = background.color || \"background\";\n const backgroundImage =\n (background.resource?.image_url || background.resource?.imageUrl) &&\n background.type === \"image\"\n ? `url(${background.resource.image_url || background.resource.imageUrl})`\n : \"none\";\n const today = new Date();\n const [currentMonth, setCurrentMonth] = useState(today.getMonth());\n const [currentYear, setCurrentYear] = useState(today.getFullYear());\n const [isCollapsed, setIsCollapsed] = useState(false);\n const [selectedDate, setSelectedDate] = useState<Date | null>(today);\n\n const { data: events = [], isLoading, isError } = useCalendarEvents();\n\n // Generate calendar grids\n const monthGrid = useMemo(\n () => generateMonthGrid(currentYear, currentMonth),\n [currentYear, currentMonth],\n );\n const weekGrid = useMemo(() => generateWeekGrid(), []);\n\n // Get events for selected date\n const selectedDateEvents = useMemo(() => {\n if (!selectedDate) return [];\n return getEventsForDate(selectedDate, events);\n }, [selectedDate, events]);\n\n // Navigation handlers\n const goToPrevMonth = () => {\n if (currentMonth === 0) {\n setCurrentMonth(11);\n setCurrentYear(currentYear - 1);\n } else {\n setCurrentMonth(currentMonth - 1);\n }\n };\n\n const goToNextMonth = () => {\n if (currentMonth === 11) {\n setCurrentMonth(0);\n setCurrentYear(currentYear + 1);\n } else {\n setCurrentMonth(currentMonth + 1);\n }\n };\n\n const monthYearLabel = new Date(currentYear, currentMonth).toLocaleString(\n \"en-US\",\n {\n month: \"long\",\n year: \"numeric\",\n },\n );\n\n return (\n <div\n className={`@container overflow-hidden rounded-${borderRadius} bg-${backgroundColor} text-${textColor} ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n {/* Title */}\n {titleEnabled && titleText && (\n <div className={`p-${padding} pb-0`}>\n <h2 className={`text-${titleFontSize} font-bold text-${titleColor}`}>\n {titleText}\n </h2>\n </div>\n )}\n\n {/* Loading state */}\n {isLoading ? (\n <div\n className={`flex min-h-[300px] items-center justify-center p-${padding}`}\n >\n <div className=\"h-8 w-8 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n </div>\n ) : isError ? (\n /* Error state */\n <ErrorState />\n ) : (\n <div className={`p-${padding}`}>\n {/* Desktop: Side by side layout */}\n <div className=\"@md:flex @md:gap-6\">\n {/* Calendar Section */}\n <div className=\"@md:flex-none\">\n {/* Month/Year Header with Navigation */}\n <div className=\"mb-4 flex items-center justify-between\">\n <button\n onClick={goToPrevMonth}\n className=\"hover:bg-foreground/10 rounded-full p-1\"\n aria-label=\"Previous month\"\n >\n <ChevronLeft className=\"size-4\" />\n </button>\n\n <span className=\"text-base font-semibold\">\n {monthYearLabel}\n </span>\n\n <button\n onClick={goToNextMonth}\n className=\"hover:bg-foreground/10 rounded-full p-1\"\n aria-label=\"Next month\"\n >\n <ChevronRight className=\"size-4\" />\n </button>\n </div>\n\n {/* Day Headers */}\n <div className=\"mb-2 grid grid-cols-7 gap-1 text-center\">\n {dayNames.map((day, idx) => (\n <div\n key={idx}\n className=\"text-xs font-medium uppercase opacity-60\"\n >\n {day}\n </div>\n ))}\n </div>\n\n {/* Calendar Grid - Week view on mobile when collapsed */}\n {isCollapsed && (\n <div className=\"grid grid-cols-7 gap-1 @md:hidden\">\n {weekGrid.map(({ date, isToday }, idx) => (\n <DayButton\n key={idx}\n date={date}\n isToday={isToday}\n isSelected={\n selectedDate?.toDateString() === date.toDateString()\n }\n hasEvents={hasEventsOnDate(date, events)}\n accentColor={accentColor}\n onClick={() => setSelectedDate(date)}\n />\n ))}\n </div>\n )}\n\n {/* Month view (always on desktop, when not collapsed on mobile) */}\n <div\n className={`grid grid-cols-7 gap-1 ${isCollapsed ? \"hidden @md:grid\" : \"grid\"}`}\n >\n {monthGrid.map((day, idx) => {\n if (!day.date) {\n return <div key={idx} className=\"aspect-square\" />;\n }\n\n return (\n <DayButton\n key={idx}\n date={day.date}\n isToday={day.isToday}\n isSelected={\n selectedDate?.toDateString() === day.date.toDateString()\n }\n hasEvents={hasEventsOnDate(day.date, events)}\n accentColor={accentColor}\n onClick={() => setSelectedDate(day.date)}\n extraClassName=\"p-2 @md:m-3\"\n />\n );\n })}\n </div>\n\n {/* Mobile collapse toggle */}\n <button\n onClick={() => setIsCollapsed(!isCollapsed)}\n className={`ml-2 flex w-full items-center justify-center gap-3 rounded-full p-1 text-${textColor}/50 @md:hidden`}\n aria-label={\n isCollapsed ? \"Expand calendar\" : \"Collapse calendar\"\n }\n >\n <div className={`h-1 w-1/2 bg-${textColor}/50`} />\n {isCollapsed ? (\n <ChevronsDown className=\"size-4\" />\n ) : (\n <ChevronsUp className=\"size-4\" />\n )}\n <div className={`h-1 w-1/2 bg-${textColor}/50`} />\n </button>\n </div>\n\n {/* Events Panel */}\n <div className=\"border-muted mt-4 pt-4 @md:mt-0 @md:w-56 @md:border-l @md:pt-0 @md:pl-6\">\n <div className=\"mb-2 text-sm font-medium opacity-60\">\n {selectedDate\n ? selectedDate.toLocaleDateString(\"en-US\", {\n weekday: \"long\",\n month: \"short\",\n day: \"numeric\",\n })\n : \"Select a date\"}\n </div>\n\n {selectedDateEvents.length > 0 ? (\n <div className=\"flex flex-col gap-3\">\n {selectedDateEvents.map((event, idx) => (\n <EventItem\n key={`${event.id}-${idx}`}\n {...event}\n accentColor={`var(--${accentColor})`}\n />\n ))}\n </div>\n ) : (\n <div className=\"text-sm opacity-50\">No events</div>\n )}\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const calendarWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"CalendarWidget\",\n displayName: \"Calendar Widget\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [\n // Styling Tab - Title Group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed above the calendar\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Title text displayed above the calendar\",\n defaultValue: \"Calendar\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n key: \"titleFontSize\",\n label: \"Title Font Size\",\n description: \"Font size for the widget title\",\n defaultValue: \"xl\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n\n // Styling Tab - Design Group\n {\n type: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background for the calendar container\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for calendar content\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"accentColor\",\n label: \"Accent Color\",\n description: \"Color used for today highlight and event indicators\",\n defaultValue: \"primary\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the calendar container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the calendar container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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L,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;GACP,qBAAqB;GACtB;0DACgB;GACf,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;uDACY;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;EAGF;GACE,MAAM;GACN,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;uDACa;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;uDACY;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,MAAM;GACN,OAAO;GACP,KAAK;GACL,OAAO;GACR;yDACe;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;8DACmB;GACnB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACH;CACF"}
|
|
@@ -6,8 +6,7 @@ import { useMemo, useState } from "react";
|
|
|
6
6
|
import { useQuery } from "@tanstack/react-query";
|
|
7
7
|
import { useDataSourceConfig } from "@fluid-app/portal-core/data-sources/context";
|
|
8
8
|
import { useWidgetPreviewContext } from "@fluid-app/portal-core/data-sources/preview-context";
|
|
9
|
-
import {
|
|
10
|
-
import { faChevronLeft, faChevronRight, faChevronsDown, faChevronsUp } from "@fortawesome/pro-regular-svg-icons";
|
|
9
|
+
import { ChevronLeft, ChevronRight, ChevronsDown, ChevronsUp } from "lucide-react";
|
|
11
10
|
//#region src/hooks/use-calendar-events.preview.ts
|
|
12
11
|
const today = /* @__PURE__ */ new Date();
|
|
13
12
|
const inTwoDays = new Date(today);
|
|
@@ -241,7 +240,7 @@ function CalendarWidget({ titleEnabled = true, titleText = "Calendar", titleFont
|
|
|
241
240
|
onClick: goToPrevMonth,
|
|
242
241
|
className: "hover:bg-foreground/10 rounded-full p-1",
|
|
243
242
|
"aria-label": "Previous month",
|
|
244
|
-
children: /* @__PURE__ */ jsx(
|
|
243
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4" })
|
|
245
244
|
}),
|
|
246
245
|
/* @__PURE__ */ jsx("span", {
|
|
247
246
|
className: "text-base font-semibold",
|
|
@@ -251,7 +250,7 @@ function CalendarWidget({ titleEnabled = true, titleText = "Calendar", titleFont
|
|
|
251
250
|
onClick: goToNextMonth,
|
|
252
251
|
className: "hover:bg-foreground/10 rounded-full p-1",
|
|
253
252
|
"aria-label": "Next month",
|
|
254
|
-
children: /* @__PURE__ */ jsx(
|
|
253
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-4" })
|
|
255
254
|
})
|
|
256
255
|
]
|
|
257
256
|
}),
|
|
@@ -294,7 +293,7 @@ function CalendarWidget({ titleEnabled = true, titleText = "Calendar", titleFont
|
|
|
294
293
|
"aria-label": isCollapsed ? "Expand calendar" : "Collapse calendar",
|
|
295
294
|
children: [
|
|
296
295
|
/* @__PURE__ */ jsx("div", { className: `h-1 w-1/2 bg-${textColor}/50` }),
|
|
297
|
-
isCollapsed ? /* @__PURE__ */ jsx(
|
|
296
|
+
isCollapsed ? /* @__PURE__ */ jsx(ChevronsDown, { className: "size-4" }) : /* @__PURE__ */ jsx(ChevronsUp, { className: "size-4" }),
|
|
298
297
|
/* @__PURE__ */ jsx("div", { className: `h-1 w-1/2 bg-${textColor}/50` })
|
|
299
298
|
]
|
|
300
299
|
})
|
|
@@ -421,4 +420,4 @@ const calendarWidgetPropertySchema = {
|
|
|
421
420
|
//#endregion
|
|
422
421
|
export { CalendarWidget_exports as n, calendarWidgetPropertySchema as r, CalendarWidget as t };
|
|
423
422
|
|
|
424
|
-
//# sourceMappingURL=CalendarWidget-
|
|
423
|
+
//# sourceMappingURL=CalendarWidget-zAxc3BTd.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CalendarWidget-zAxc3BTd.mjs","names":[],"sources":["../src/hooks/use-calendar-events.preview.ts","../src/hooks/use-calendar-events.ts","../src/widgets/CalendarWidget.tsx"],"sourcesContent":["import type { CalendarEvent } from \"./use-calendar-events.types\";\n\nconst today = new Date();\nconst inTwoDays = new Date(today);\ninTwoDays.setDate(inTwoDays.getDate() + 2);\n\nfunction toISO(date: Date, hours: number, minutes = 0): string {\n const d = new Date(date);\n d.setHours(hours, minutes, 0, 0);\n return d.toISOString();\n}\n\nfunction toDateString(date: Date): string {\n return date.toISOString().split(\"T\")[0]!;\n}\n\nexport const PREVIEW_DATA: CalendarEvent[] = [\n {\n id: 1,\n title: \"Team Strategy Call\",\n start: toISO(today, 9, 0),\n end: toISO(today, 10, 0),\n status: \"active\",\n color: \"#4f46e5\",\n },\n {\n id: 2,\n title: \"Product Launch Webinar\",\n start: toISO(today, 14, 0),\n end: toISO(today, 15, 30),\n status: \"active\",\n color: \"#0891b2\",\n venue: \"Zoom\",\n },\n {\n id: 3,\n title: \"Annual Leadership Summit\",\n start: `${toDateString(inTwoDays)}T00:00:00.000Z`,\n end: `${toDateString(inTwoDays)}T23:59:59.000Z`,\n status: \"active\",\n color: \"#059669\",\n isAllDay: true,\n venue: \"Convention Center\",\n },\n];\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useDataSourceConfig } from \"@fluid-app/portal-core/data-sources/context\";\nimport { useWidgetPreviewContext } from \"@fluid-app/portal-core/data-sources/preview-context\";\nimport { PREVIEW_DATA } from \"./use-calendar-events.preview\";\n\nimport type { CalendarEvent } from \"./use-calendar-events.types\";\n\nexport type { CalendarEvent } from \"./use-calendar-events.types\";\n\nexport function useCalendarEvents(): UseQueryResult<CalendarEvent[], Error> {\n const { baseUrl, getApiHeaders } = useDataSourceConfig();\n const { isPreview } = useWidgetPreviewContext();\n\n return useQuery({\n queryKey: [\n \"portal-widget-use\",\n \"calendar-events\",\n isPreview ? \"preview\" : baseUrl,\n ] as const,\n queryFn: async ({ signal }): Promise<CalendarEvent[]> => {\n const url = baseUrl\n ? `${baseUrl}/events.json?event_timeline=upcoming`\n : \"/events.json?event_timeline=upcoming\";\n const response = await fetch(url, {\n headers: {\n \"content-type\": \"application/json\",\n ...getApiHeaders?.(),\n },\n signal,\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch calendar events: ${response.status}`);\n }\n\n return response.json();\n },\n enabled: !isPreview,\n ...(isPreview && { placeholderData: PREVIEW_DATA }),\n });\n}\n","import { useState, useMemo, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n} from \"../core/fields\";\nimport {\n useCalendarEvents,\n type CalendarEvent,\n} from \"../hooks/use-calendar-events\";\nimport { ErrorState } from \"../components/error-state\";\nimport {\n ChevronLeft,\n ChevronRight,\n ChevronsDown,\n ChevronsUp,\n} from \"lucide-react\";\n\n// Utility to get days in a month\nconst getDaysInMonth = (year: number, month: number) => {\n return new Date(year, month + 1, 0).getDate();\n};\n\n// Utility to get the first day of month (0 = Sunday, 1 = Monday, etc.)\nconst getFirstDayOfMonth = (year: number, month: number) => {\n return new Date(year, month, 1).getDay();\n};\n\n// Generate calendar grid for a month\nconst generateMonthGrid = (year: number, month: number) => {\n const daysInMonth = getDaysInMonth(year, month);\n const firstDay = getFirstDayOfMonth(year, month);\n const today = new Date();\n\n const days: Array<{\n date: Date | null;\n isToday: boolean;\n isCurrentMonth: boolean;\n }> = [];\n\n // Add empty slots for days before the 1st\n for (let i = 0; i < firstDay; i++) {\n days.push({ date: null, isToday: false, isCurrentMonth: false });\n }\n\n // Add days of the month\n for (let day = 1; day <= daysInMonth; day++) {\n const date = new Date(year, month, day);\n const isToday =\n date.getDate() === today.getDate() &&\n date.getMonth() === today.getMonth() &&\n date.getFullYear() === today.getFullYear();\n days.push({ date, isToday, isCurrentMonth: true });\n }\n\n return days;\n};\n\n// Generate week grid for current week\nconst generateWeekGrid = () => {\n const today = new Date();\n const currentDay = today.getDay();\n const days: Array<{\n date: Date;\n isToday: boolean;\n }> = [];\n\n for (let i = 0; i < 7; i++) {\n const date = new Date(today);\n date.setDate(today.getDate() - currentDay + i);\n days.push({\n date,\n isToday: date.toDateString() === today.toDateString(),\n });\n }\n\n return days;\n};\n\n// Get events for a specific date\nconst getEventsForDate = (date: Date, events: CalendarEvent[]) => {\n const dayStart = new Date(date);\n dayStart.setHours(0, 0, 0, 0);\n const dayEnd = new Date(date);\n dayEnd.setHours(23, 59, 59, 999);\n\n return events.filter((event) => {\n const eventStart = new Date(event.start);\n const eventEnd = new Date(event.end);\n return eventStart <= dayEnd && eventEnd >= dayStart;\n });\n};\n\n// Check if a date has events\nconst hasEventsOnDate = (date: Date | null, events: CalendarEvent[]) => {\n if (!date) return false;\n return getEventsForDate(date, events).length > 0;\n};\n\n// Event item component\nconst EventItem = ({\n title,\n start,\n end,\n color,\n isAllDay,\n accentColor,\n}: CalendarEvent & { accentColor?: string }) => {\n const startTime = new Date(start).toLocaleTimeString(\"en-US\", {\n hour: \"numeric\",\n minute: \"2-digit\",\n });\n const endTime = new Date(end).toLocaleTimeString(\"en-US\", {\n hour: \"numeric\",\n minute: \"2-digit\",\n });\n\n return (\n <div className=\"flex gap-x-2\">\n <div\n className=\"w-0.5 shrink-0 rounded-full\"\n style={{ backgroundColor: color || accentColor }}\n />\n <div className=\"min-w-0 flex-1\">\n <div className=\"truncate text-sm font-medium\">{title}</div>\n <div className=\"text-xs opacity-60\">\n {isAllDay ? \"All day\" : `${startTime} - ${endTime}`}\n </div>\n </div>\n </div>\n );\n};\n\nconst dayNames = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"];\n\ntype DayButtonProps = {\n date: Date;\n isToday: boolean;\n isSelected: boolean;\n hasEvents: boolean;\n accentColor: string;\n onClick: () => void;\n extraClassName?: string;\n};\n\nfunction DayButton({\n date,\n isToday,\n isSelected,\n hasEvents,\n accentColor,\n onClick,\n extraClassName = \"\",\n}: DayButtonProps) {\n return (\n <button\n onClick={onClick}\n className={`relative flex aspect-square items-center justify-center rounded-full text-sm transition-colors ${\n isSelected\n ? `bg-${accentColor} text-${accentColor}-foreground`\n : isToday\n ? `bg-${accentColor}/30 text-${accentColor}-foreground hover:bg-${accentColor}/50`\n : `hover:bg-${accentColor}/50 hover:text-${accentColor}-foreground`\n } ${extraClassName}`}\n >\n {date.getDate()}\n {hasEvents && (\n <div\n className={`absolute bottom-1 h-1 w-1 rounded-full bg-${accentColor}`}\n />\n )}\n </button>\n );\n}\n\ntype CalendarWidgetProps = ComponentProps<\"div\"> & {\n // Title\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n // Styling\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n};\n\nexport function CalendarWidget({\n // Title defaults\n titleEnabled = true,\n titleText = \"Calendar\",\n titleFontSize = \"xl\",\n titleColor = \"foreground\",\n\n // Styling defaults\n background = {\n type: \"solid\",\n color: \"background\",\n },\n textColor = \"foreground\",\n accentColor = \"primary\",\n padding = 4,\n borderRadius = \"md\",\n\n className,\n ...props\n}: CalendarWidgetProps): React.JSX.Element {\n const backgroundColor = background.color || \"background\";\n const backgroundImage =\n (background.resource?.image_url || background.resource?.imageUrl) &&\n background.type === \"image\"\n ? `url(${background.resource.image_url || background.resource.imageUrl})`\n : \"none\";\n const today = new Date();\n const [currentMonth, setCurrentMonth] = useState(today.getMonth());\n const [currentYear, setCurrentYear] = useState(today.getFullYear());\n const [isCollapsed, setIsCollapsed] = useState(false);\n const [selectedDate, setSelectedDate] = useState<Date | null>(today);\n\n const { data: events = [], isLoading, isError } = useCalendarEvents();\n\n // Generate calendar grids\n const monthGrid = useMemo(\n () => generateMonthGrid(currentYear, currentMonth),\n [currentYear, currentMonth],\n );\n const weekGrid = useMemo(() => generateWeekGrid(), []);\n\n // Get events for selected date\n const selectedDateEvents = useMemo(() => {\n if (!selectedDate) return [];\n return getEventsForDate(selectedDate, events);\n }, [selectedDate, events]);\n\n // Navigation handlers\n const goToPrevMonth = () => {\n if (currentMonth === 0) {\n setCurrentMonth(11);\n setCurrentYear(currentYear - 1);\n } else {\n setCurrentMonth(currentMonth - 1);\n }\n };\n\n const goToNextMonth = () => {\n if (currentMonth === 11) {\n setCurrentMonth(0);\n setCurrentYear(currentYear + 1);\n } else {\n setCurrentMonth(currentMonth + 1);\n }\n };\n\n const monthYearLabel = new Date(currentYear, currentMonth).toLocaleString(\n \"en-US\",\n {\n month: \"long\",\n year: \"numeric\",\n },\n );\n\n return (\n <div\n className={`@container overflow-hidden rounded-${borderRadius} bg-${backgroundColor} text-${textColor} ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n {/* Title */}\n {titleEnabled && titleText && (\n <div className={`p-${padding} pb-0`}>\n <h2 className={`text-${titleFontSize} font-bold text-${titleColor}`}>\n {titleText}\n </h2>\n </div>\n )}\n\n {/* Loading state */}\n {isLoading ? (\n <div\n className={`flex min-h-[300px] items-center justify-center p-${padding}`}\n >\n <div className=\"h-8 w-8 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n </div>\n ) : isError ? (\n /* Error state */\n <ErrorState />\n ) : (\n <div className={`p-${padding}`}>\n {/* Desktop: Side by side layout */}\n <div className=\"@md:flex @md:gap-6\">\n {/* Calendar Section */}\n <div className=\"@md:flex-none\">\n {/* Month/Year Header with Navigation */}\n <div className=\"mb-4 flex items-center justify-between\">\n <button\n onClick={goToPrevMonth}\n className=\"hover:bg-foreground/10 rounded-full p-1\"\n aria-label=\"Previous month\"\n >\n <ChevronLeft className=\"size-4\" />\n </button>\n\n <span className=\"text-base font-semibold\">\n {monthYearLabel}\n </span>\n\n <button\n onClick={goToNextMonth}\n className=\"hover:bg-foreground/10 rounded-full p-1\"\n aria-label=\"Next month\"\n >\n <ChevronRight className=\"size-4\" />\n </button>\n </div>\n\n {/* Day Headers */}\n <div className=\"mb-2 grid grid-cols-7 gap-1 text-center\">\n {dayNames.map((day, idx) => (\n <div\n key={idx}\n className=\"text-xs font-medium uppercase opacity-60\"\n >\n {day}\n </div>\n ))}\n </div>\n\n {/* Calendar Grid - Week view on mobile when collapsed */}\n {isCollapsed && (\n <div className=\"grid grid-cols-7 gap-1 @md:hidden\">\n {weekGrid.map(({ date, isToday }, idx) => (\n <DayButton\n key={idx}\n date={date}\n isToday={isToday}\n isSelected={\n selectedDate?.toDateString() === date.toDateString()\n }\n hasEvents={hasEventsOnDate(date, events)}\n accentColor={accentColor}\n onClick={() => setSelectedDate(date)}\n />\n ))}\n </div>\n )}\n\n {/* Month view (always on desktop, when not collapsed on mobile) */}\n <div\n className={`grid grid-cols-7 gap-1 ${isCollapsed ? \"hidden @md:grid\" : \"grid\"}`}\n >\n {monthGrid.map((day, idx) => {\n if (!day.date) {\n return <div key={idx} className=\"aspect-square\" />;\n }\n\n return (\n <DayButton\n key={idx}\n date={day.date}\n isToday={day.isToday}\n isSelected={\n selectedDate?.toDateString() === day.date.toDateString()\n }\n hasEvents={hasEventsOnDate(day.date, events)}\n accentColor={accentColor}\n onClick={() => setSelectedDate(day.date)}\n extraClassName=\"p-2 @md:m-3\"\n />\n );\n })}\n </div>\n\n {/* Mobile collapse toggle */}\n <button\n onClick={() => setIsCollapsed(!isCollapsed)}\n className={`ml-2 flex w-full items-center justify-center gap-3 rounded-full p-1 text-${textColor}/50 @md:hidden`}\n aria-label={\n isCollapsed ? \"Expand calendar\" : \"Collapse calendar\"\n }\n >\n <div className={`h-1 w-1/2 bg-${textColor}/50`} />\n {isCollapsed ? (\n <ChevronsDown className=\"size-4\" />\n ) : (\n <ChevronsUp className=\"size-4\" />\n )}\n <div className={`h-1 w-1/2 bg-${textColor}/50`} />\n </button>\n </div>\n\n {/* Events Panel */}\n <div className=\"border-muted mt-4 pt-4 @md:mt-0 @md:w-56 @md:border-l @md:pt-0 @md:pl-6\">\n <div className=\"mb-2 text-sm font-medium opacity-60\">\n {selectedDate\n ? selectedDate.toLocaleDateString(\"en-US\", {\n weekday: \"long\",\n month: \"short\",\n day: \"numeric\",\n })\n : \"Select a date\"}\n </div>\n\n {selectedDateEvents.length > 0 ? (\n <div className=\"flex flex-col gap-3\">\n {selectedDateEvents.map((event, idx) => (\n <EventItem\n key={`${event.id}-${idx}`}\n {...event}\n accentColor={`var(--${accentColor})`}\n />\n ))}\n </div>\n ) : (\n <div className=\"text-sm opacity-50\">No events</div>\n )}\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const calendarWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"CalendarWidget\",\n displayName: \"Calendar Widget\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [\n // Styling Tab - Title Group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed above the calendar\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Title text displayed above the calendar\",\n defaultValue: \"Calendar\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n key: \"titleFontSize\",\n label: \"Title Font Size\",\n description: \"Font size for the widget title\",\n defaultValue: \"xl\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n\n // Styling Tab - Design Group\n {\n type: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background for the calendar container\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for calendar content\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"accentColor\",\n label: \"Accent Color\",\n description: \"Color used for today highlight and event indicators\",\n defaultValue: \"primary\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the calendar container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the calendar container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":";;;;;;;;;;AAEA,MAAM,wBAAQ,IAAI,MAAM;AACxB,MAAM,YAAY,IAAI,KAAK,MAAM;AACjC,UAAU,QAAQ,UAAU,SAAS,GAAG,EAAE;AAE1C,SAAS,MAAM,MAAY,OAAe,UAAU,GAAW;CAC7D,MAAM,IAAI,IAAI,KAAK,KAAK;AACxB,GAAE,SAAS,OAAO,SAAS,GAAG,EAAE;AAChC,QAAO,EAAE,aAAa;;AAGxB,SAAS,aAAa,MAAoB;AACxC,QAAO,KAAK,aAAa,CAAC,MAAM,IAAI,CAAC;;AAGvC,MAAa,eAAgC;CAC3C;EACE,IAAI;EACJ,OAAO;EACP,OAAO,MAAM,OAAO,GAAG,EAAE;EACzB,KAAK,MAAM,OAAO,IAAI,EAAE;EACxB,QAAQ;EACR,OAAO;EACR;CACD;EACE,IAAI;EACJ,OAAO;EACP,OAAO,MAAM,OAAO,IAAI,EAAE;EAC1B,KAAK,MAAM,OAAO,IAAI,GAAG;EACzB,QAAQ;EACR,OAAO;EACP,OAAO;EACR;CACD;EACE,IAAI;EACJ,OAAO;EACP,OAAO,GAAG,aAAa,UAAU,CAAC;EAClC,KAAK,GAAG,aAAa,UAAU,CAAC;EAChC,QAAQ;EACR,OAAO;EACP,UAAU;EACV,OAAO;EACR;CACF;;;ACnCD,SAAgB,oBAA4D;CAC1E,MAAM,EAAE,SAAS,kBAAkB,qBAAqB;CACxD,MAAM,EAAE,cAAc,yBAAyB;AAE/C,QAAO,SAAS;EACd,UAAU;GACR;GACA;GACA,YAAY,YAAY;GACzB;EACD,SAAS,OAAO,EAAE,aAAuC;GACvD,MAAM,MAAM,UACR,GAAG,QAAQ,wCACX;GACJ,MAAM,WAAW,MAAM,MAAM,KAAK;IAChC,SAAS;KACP,gBAAgB;KAChB,GAAG,iBAAiB;KACrB;IACD;IACD,CAAC;AAEF,OAAI,CAAC,SAAS,GACZ,OAAM,IAAI,MAAM,oCAAoC,SAAS,SAAS;AAGxE,UAAO,SAAS,MAAM;;EAExB,SAAS,CAAC;EACV,GAAI,aAAa,EAAE,iBAAiB,cAAc;EACnD,CAAC;;;;;;;;ACVJ,MAAM,kBAAkB,MAAc,UAAkB;AACtD,QAAO,IAAI,KAAK,MAAM,QAAQ,GAAG,EAAE,CAAC,SAAS;;AAI/C,MAAM,sBAAsB,MAAc,UAAkB;AAC1D,QAAO,IAAI,KAAK,MAAM,OAAO,EAAE,CAAC,QAAQ;;AAI1C,MAAM,qBAAqB,MAAc,UAAkB;CACzD,MAAM,cAAc,eAAe,MAAM,MAAM;CAC/C,MAAM,WAAW,mBAAmB,MAAM,MAAM;CAChD,MAAM,wBAAQ,IAAI,MAAM;CAExB,MAAM,OAID,EAAE;AAGP,MAAK,IAAI,IAAI,GAAG,IAAI,UAAU,IAC5B,MAAK,KAAK;EAAE,MAAM;EAAM,SAAS;EAAO,gBAAgB;EAAO,CAAC;AAIlE,MAAK,IAAI,MAAM,GAAG,OAAO,aAAa,OAAO;EAC3C,MAAM,OAAO,IAAI,KAAK,MAAM,OAAO,IAAI;EACvC,MAAM,UACJ,KAAK,SAAS,KAAK,MAAM,SAAS,IAClC,KAAK,UAAU,KAAK,MAAM,UAAU,IACpC,KAAK,aAAa,KAAK,MAAM,aAAa;AAC5C,OAAK,KAAK;GAAE;GAAM;GAAS,gBAAgB;GAAM,CAAC;;AAGpD,QAAO;;AAIT,MAAM,yBAAyB;CAC7B,MAAM,wBAAQ,IAAI,MAAM;CACxB,MAAM,aAAa,MAAM,QAAQ;CACjC,MAAM,OAGD,EAAE;AAEP,MAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;EAC1B,MAAM,OAAO,IAAI,KAAK,MAAM;AAC5B,OAAK,QAAQ,MAAM,SAAS,GAAG,aAAa,EAAE;AAC9C,OAAK,KAAK;GACR;GACA,SAAS,KAAK,cAAc,KAAK,MAAM,cAAc;GACtD,CAAC;;AAGJ,QAAO;;AAIT,MAAM,oBAAoB,MAAY,WAA4B;CAChE,MAAM,WAAW,IAAI,KAAK,KAAK;AAC/B,UAAS,SAAS,GAAG,GAAG,GAAG,EAAE;CAC7B,MAAM,SAAS,IAAI,KAAK,KAAK;AAC7B,QAAO,SAAS,IAAI,IAAI,IAAI,IAAI;AAEhC,QAAO,OAAO,QAAQ,UAAU;EAC9B,MAAM,aAAa,IAAI,KAAK,MAAM,MAAM;EACxC,MAAM,WAAW,IAAI,KAAK,MAAM,IAAI;AACpC,SAAO,cAAc,UAAU,YAAY;GAC3C;;AAIJ,MAAM,mBAAmB,MAAmB,WAA4B;AACtE,KAAI,CAAC,KAAM,QAAO;AAClB,QAAO,iBAAiB,MAAM,OAAO,CAAC,SAAS;;AAIjD,MAAM,aAAa,EACjB,OACA,OACA,KACA,OACA,UACA,kBAC8C;CAC9C,MAAM,YAAY,IAAI,KAAK,MAAM,CAAC,mBAAmB,SAAS;EAC5D,MAAM;EACN,QAAQ;EACT,CAAC;CACF,MAAM,UAAU,IAAI,KAAK,IAAI,CAAC,mBAAmB,SAAS;EACxD,MAAM;EACN,QAAQ;EACT,CAAC;AAEF,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,OAAD;GACE,WAAU;GACV,OAAO,EAAE,iBAAiB,SAAS,aAAa;GAChD,CAAA,EACF,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,OAAD;IAAK,WAAU;cAAgC;IAAY,CAAA,EAC3D,oBAAC,OAAD;IAAK,WAAU;cACZ,WAAW,YAAY,GAAG,UAAU,KAAK;IACtC,CAAA,CACF;KACF;;;AAIV,MAAM,WAAW;CAAC;CAAO;CAAO;CAAO;CAAO;CAAO;CAAO;CAAM;AAYlE,SAAS,UAAU,EACjB,MACA,SACA,YACA,WACA,aACA,SACA,iBAAiB,MACA;AACjB,QACE,qBAAC,UAAD;EACW;EACT,WAAW,kGACT,aACI,MAAM,YAAY,QAAQ,YAAY,eACtC,UACE,MAAM,YAAY,WAAW,YAAY,uBAAuB,YAAY,OAC5E,YAAY,YAAY,iBAAiB,YAAY,aAC5D,GAAG;YARN,CAUG,KAAK,SAAS,EACd,aACC,oBAAC,OAAD,EACE,WAAW,6CAA6C,eACxD,CAAA,CAEG;;;AAmBb,SAAgB,eAAe,EAE7B,eAAe,MACf,YAAY,YACZ,gBAAgB,MAChB,aAAa,cAGb,aAAa;CACX,MAAM;CACN,OAAO;CACR,EACD,YAAY,cACZ,cAAc,WACd,UAAU,GACV,eAAe,MAEf,WACA,GAAG,SACsC;CACzC,MAAM,kBAAkB,WAAW,SAAS;CAC5C,MAAM,mBACH,WAAW,UAAU,aAAa,WAAW,UAAU,aACxD,WAAW,SAAS,UAChB,OAAO,WAAW,SAAS,aAAa,WAAW,SAAS,SAAS,KACrE;CACN,MAAM,wBAAQ,IAAI,MAAM;CACxB,MAAM,CAAC,cAAc,mBAAmB,SAAS,MAAM,UAAU,CAAC;CAClE,MAAM,CAAC,aAAa,kBAAkB,SAAS,MAAM,aAAa,CAAC;CACnE,MAAM,CAAC,aAAa,kBAAkB,SAAS,MAAM;CACrD,MAAM,CAAC,cAAc,mBAAmB,SAAsB,MAAM;CAEpE,MAAM,EAAE,MAAM,SAAS,EAAE,EAAE,WAAW,YAAY,mBAAmB;CAGrE,MAAM,YAAY,cACV,kBAAkB,aAAa,aAAa,EAClD,CAAC,aAAa,aAAa,CAC5B;CACD,MAAM,WAAW,cAAc,kBAAkB,EAAE,EAAE,CAAC;CAGtD,MAAM,qBAAqB,cAAc;AACvC,MAAI,CAAC,aAAc,QAAO,EAAE;AAC5B,SAAO,iBAAiB,cAAc,OAAO;IAC5C,CAAC,cAAc,OAAO,CAAC;CAG1B,MAAM,sBAAsB;AAC1B,MAAI,iBAAiB,GAAG;AACtB,mBAAgB,GAAG;AACnB,kBAAe,cAAc,EAAE;QAE/B,iBAAgB,eAAe,EAAE;;CAIrC,MAAM,sBAAsB;AAC1B,MAAI,iBAAiB,IAAI;AACvB,mBAAgB,EAAE;AAClB,kBAAe,cAAc,EAAE;QAE/B,iBAAgB,eAAe,EAAE;;CAIrC,MAAM,iBAAiB,IAAI,KAAK,aAAa,aAAa,CAAC,eACzD,SACA;EACE,OAAO;EACP,MAAM;EACP,CACF;AAED,QACE,qBAAC,OAAD;EACE,WAAW,sCAAsC,aAAa,MAAM,gBAAgB,QAAQ,UAAU,GAAG;EACzG,OAAO,EAAE,iBAAiB;EAC1B,GAAI;YAHN,CAMG,gBAAgB,aACf,oBAAC,OAAD;GAAK,WAAW,KAAK,QAAQ;aAC3B,oBAAC,MAAD;IAAI,WAAW,QAAQ,cAAc,kBAAkB;cACpD;IACE,CAAA;GACD,CAAA,EAIP,YACC,oBAAC,OAAD;GACE,WAAW,oDAAoD;aAE/D,oBAAC,OAAD,EAAK,WAAU,kFAAmF,CAAA;GAC9F,CAAA,GACJ,UAEF,oBAAC,YAAD,EAAc,CAAA,GAEd,oBAAC,OAAD;GAAK,WAAW,KAAK;aAEnB,qBAAC,OAAD;IAAK,WAAU;cAAf,CAEE,qBAAC,OAAD;KAAK,WAAU;eAAf;MAEE,qBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,oBAAC,UAAD;SACE,SAAS;SACT,WAAU;SACV,cAAW;mBAEX,oBAAC,aAAD,EAAa,WAAU,UAAW,CAAA;SAC3B,CAAA;QAET,oBAAC,QAAD;SAAM,WAAU;mBACb;SACI,CAAA;QAEP,oBAAC,UAAD;SACE,SAAS;SACT,WAAU;SACV,cAAW;mBAEX,oBAAC,cAAD,EAAc,WAAU,UAAW,CAAA;SAC5B,CAAA;QACL;;MAGN,oBAAC,OAAD;OAAK,WAAU;iBACZ,SAAS,KAAK,KAAK,QAClB,oBAAC,OAAD;QAEE,WAAU;kBAET;QACG,EAJC,IAID,CACN;OACE,CAAA;MAGL,eACC,oBAAC,OAAD;OAAK,WAAU;iBACZ,SAAS,KAAK,EAAE,MAAM,WAAW,QAChC,oBAAC,WAAD;QAEQ;QACG;QACT,YACE,cAAc,cAAc,KAAK,KAAK,cAAc;QAEtD,WAAW,gBAAgB,MAAM,OAAO;QAC3B;QACb,eAAe,gBAAgB,KAAK;QACpC,EATK,IASL,CACF;OACE,CAAA;MAIR,oBAAC,OAAD;OACE,WAAW,0BAA0B,cAAc,oBAAoB;iBAEtE,UAAU,KAAK,KAAK,QAAQ;AAC3B,YAAI,CAAC,IAAI,KACP,QAAO,oBAAC,OAAD,EAAe,WAAU,iBAAkB,EAAjC,IAAiC;AAGpD,eACE,oBAAC,WAAD;SAEE,MAAM,IAAI;SACV,SAAS,IAAI;SACb,YACE,cAAc,cAAc,KAAK,IAAI,KAAK,cAAc;SAE1D,WAAW,gBAAgB,IAAI,MAAM,OAAO;SAC/B;SACb,eAAe,gBAAgB,IAAI,KAAK;SACxC,gBAAe;SACf,EAVK,IAUL;SAEJ;OACE,CAAA;MAGN,qBAAC,UAAD;OACE,eAAe,eAAe,CAAC,YAAY;OAC3C,WAAW,4EAA4E,UAAU;OACjG,cACE,cAAc,oBAAoB;iBAJtC;QAOE,oBAAC,OAAD,EAAK,WAAW,gBAAgB,UAAU,MAAQ,CAAA;QACjD,cACC,oBAAC,cAAD,EAAc,WAAU,UAAW,CAAA,GAEnC,oBAAC,YAAD,EAAY,WAAU,UAAW,CAAA;QAEnC,oBAAC,OAAD,EAAK,WAAW,gBAAgB,UAAU,MAAQ,CAAA;QAC3C;;MACL;QAGN,qBAAC,OAAD;KAAK,WAAU;eAAf,CACE,oBAAC,OAAD;MAAK,WAAU;gBACZ,eACG,aAAa,mBAAmB,SAAS;OACvC,SAAS;OACT,OAAO;OACP,KAAK;OACN,CAAC,GACF;MACA,CAAA,EAEL,mBAAmB,SAAS,IAC3B,oBAAC,OAAD;MAAK,WAAU;gBACZ,mBAAmB,KAAK,OAAO,QAC9B,oBAAC,WAAD;OAEE,GAAI;OACJ,aAAa,SAAS,YAAY;OAClC,EAHK,GAAG,MAAM,GAAG,GAAG,MAGpB,CACF;MACE,CAAA,GAEN,oBAAC,OAAD;MAAK,WAAU;gBAAqB;MAAe,CAAA,CAEjD;OACF;;GACF,CAAA,CAEJ;;;AAIV,MAAa,+BAAqD;CAChE,YAAY;CACZ,aAAa;CACb,YAAY,CAAC;EAAE,IAAI;EAAW,OAAO;EAAW,CAAC;CACjD,QAAQ;EAEN;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;GACP,qBAAqB;GACtB;EACD,iBAAiB;GACf,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;EACF,cAAc;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;EAGF;GACE,MAAM;GACN,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD,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;EACH;CACF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-CZWwpsFl.cjs");
|
|
2
|
-
const require_scroll_arrows = require("./scroll-arrows-
|
|
3
|
-
const require_MediaRenderer = require("./MediaRenderer-
|
|
2
|
+
const require_scroll_arrows = require("./scroll-arrows-4aTDqcAw.cjs");
|
|
3
|
+
const require_MediaRenderer = require("./MediaRenderer-Crlzjyvh.cjs");
|
|
4
4
|
let _fluid_app_portal_core_registries = require("@fluid-app/portal-core/registries");
|
|
5
5
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
6
6
|
let react = require("react");
|
|
@@ -468,4 +468,4 @@ Object.defineProperty(exports, "carouselWidgetPropertySchema", {
|
|
|
468
468
|
}
|
|
469
469
|
});
|
|
470
470
|
|
|
471
|
-
//# sourceMappingURL=CarouselWidget-
|
|
471
|
+
//# sourceMappingURL=CarouselWidget-D51Kz6r8.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CarouselWidget-PEm6vktC.cjs","names":["MediaRenderer","getMediaPropsFromWidgetSchema","DOMPurify","Button","ScrollArrows"],"sources":["../src/widgets/CarouselWidget.tsx"],"sourcesContent":["import DOMPurify from \"dompurify\";\nimport { Button } from \"@fluid-app/ui-primitives\";\nimport { ScrollArrows } from \"../ui/scroll-arrows\";\nimport type { ComponentProps } from \"react\";\nimport { useEffect, useState, useCallback } from \"react\";\nimport type React from \"react\";\nimport {\n MediaRenderer,\n getMediaPropsFromWidgetSchema,\n} from \"../components/MediaRenderer\";\nimport type {\n WidgetSchema,\n BorderRadiusOptions,\n ColorOptions,\n AlignOptions,\n FontSizeOptions,\n PaddingOptions,\n ButtonSizeOptions,\n} from \"@fluid-app/portal-core/types\";\nimport {\n getHeightField,\n type WidgetPropertySchema,\n} from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n getButtonSizeField,\n} from \"../core/fields\";\n\nconst DEFAULT_SLIDES: CarouselSlide[] = [];\n\ntype CarouselSlide = {\n id: string;\n content: WidgetSchema;\n title?: string;\n description?: string;\n buttonEnabled?: boolean;\n buttonText?: string;\n buttonVariant?:\n | \"default\"\n | \"secondary\"\n | \"outline\"\n | \"destructive\"\n | \"ghost\"\n | \"link\";\n buttonLink?: string;\n};\n\ntype CarouselWidgetProps = ComponentProps<\"div\"> & {\n slides?: CarouselSlide[];\n autoScrollInterval?: number;\n enableAutoScroll?: boolean;\n\n // Layout\n align?: AlignOptions;\n carouselHeight?: string;\n borderRadius?: BorderRadiusOptions;\n padding?: PaddingOptions;\n\n // Text Styling\n headerSize?: FontSizeOptions;\n headerColor?: ColorOptions;\n textSize?: FontSizeOptions;\n textColor?: ColorOptions;\n textWidth?: string;\n\n // Button\n showButton?: boolean;\n buttonColor?: ColorOptions;\n buttonSize?: ButtonSizeOptions;\n\n // Overlay\n overlayEnabled?: boolean;\n overlayType?: \"solid\" | \"gradient\";\n overlayIntensity?: number;\n};\n\nexport function CarouselWidget({\n slides = DEFAULT_SLIDES,\n autoScrollInterval = 3000,\n enableAutoScroll = false,\n carouselHeight = \"400px\",\n align = { vertical: \"bottom\", horizontal: \"left\" },\n overlayIntensity = 40,\n borderRadius = \"none\",\n padding = 0,\n textWidth = \"100%\",\n headerSize = \"lg\",\n headerColor = \"background\",\n textSize = \"md\",\n textColor = \"background\",\n showButton = true,\n buttonColor = \"background\",\n buttonSize = \"default\",\n overlayEnabled = true,\n overlayType = \"solid\",\n className,\n ...props\n}: CarouselWidgetProps): React.JSX.Element {\n const [currentIndex, setCurrentIndex] = useState(0);\n const [isHovered, setIsHovered] = useState(false);\n\n const hasSlides = slides.length > 0;\n const totalSlides = slides.length;\n\n const goToNext = useCallback(() => {\n if (!hasSlides) return;\n setCurrentIndex((prev) => {\n if (prev === totalSlides - 1) {\n return 0;\n }\n return prev + 1;\n });\n }, [hasSlides, totalSlides]);\n\n const goToPrevious = useCallback(() => {\n if (!hasSlides) return;\n setCurrentIndex((prev) => {\n if (prev === 0) {\n return totalSlides - 1;\n }\n return prev - 1;\n });\n }, [hasSlides, totalSlides]);\n\n const goToSlide = useCallback(\n (index: number) => {\n if (!hasSlides) return;\n if (index >= 0 && index < totalSlides) {\n setCurrentIndex(index);\n }\n },\n [hasSlides, totalSlides],\n );\n\n // Auto-scroll effect\n useEffect(() => {\n if (!enableAutoScroll || !hasSlides || isHovered) return;\n\n const intervalId = setInterval(() => {\n goToNext();\n }, autoScrollInterval);\n\n return () => clearInterval(intervalId);\n }, [enableAutoScroll, autoScrollInterval, hasSlides, isHovered, goToNext]);\n\n // Reset to first slide if slides change\n useEffect(() => {\n if (currentIndex >= totalSlides && totalSlides > 0) {\n setCurrentIndex(0);\n }\n }, [totalSlides, currentIndex]);\n\n if (!hasSlides) {\n return (\n <div\n className={`rounded-${borderRadius} ${className} w-full overflow-hidden`}\n style={{ minHeight: carouselHeight }}\n {...props}\n >\n <div\n className=\"bg-muted flex h-full w-full items-center justify-center\"\n style={{ minHeight: carouselHeight }}\n >\n <div className=\"text-muted-foreground flex flex-col items-center gap-2\">\n <div className=\"text-4xl\">🎠</div>\n <p className=\"text-sm\">No slides added</p>\n <p className=\"text-muted-foreground/70 text-xs\">\n Add slides to create a carousel\n </p>\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div\n className={`relative w-full overflow-hidden rounded-${borderRadius} ${className}`}\n style={{ minHeight: carouselHeight }}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n {...props}\n >\n {/* Slides Container */}\n <div\n className=\"relative h-full w-full\"\n style={{ minHeight: carouselHeight }}\n >\n <div\n className=\"flex h-full transition-transform duration-500 ease-in-out\"\n style={{\n transform: `translateX(-${currentIndex * 100}%)`,\n }}\n >\n {slides.map((slide) => (\n <div\n key={slide.id}\n className=\"relative h-full w-full flex-shrink-0\"\n style={{ minWidth: \"100%\", minHeight: carouselHeight }}\n >\n {/* Background image/content layer */}\n <div className=\"absolute inset-0 h-full w-full\">\n <MediaRenderer\n {...getMediaPropsFromWidgetSchema(slide.content)}\n />\n </div>\n\n {/* Dark overlay for text readability */}\n {overlayEnabled && (\n <div\n className={`absolute inset-0 z-9 ${\n overlayType === \"gradient\"\n ? \"bg-gradient-to-t from-black to-transparent\"\n : \"bg-black\"\n }`}\n style={{\n opacity:\n (Number(String(overlayIntensity).replace(\"%\", \"\")) ||\n 40) / 100,\n }}\n />\n )}\n\n {/* Content box */}\n <div\n className={`absolute inset-x-0 z-10 flex px-3 ${\n align.horizontal === \"left\"\n ? \"justify-start\"\n : align.horizontal === \"center\"\n ? \"justify-center\"\n : \"justify-end\"\n } ${\n align.vertical === \"top\"\n ? \"top-0 pt-13\"\n : align.vertical === \"center\"\n ? \"top-1/2 -translate-y-1/2\"\n : \"bottom-0 pb-13\"\n }`}\n >\n <div\n className={`p-${padding} flex flex-col gap-3`}\n style={{ maxWidth: textWidth }}\n >\n {/* Heading and text */}\n <div className={`flex flex-col text-${align.horizontal}`}>\n {slide.title && (\n <h2\n className={`mb-2 leading-tight font-bold text-${headerColor} text-${headerSize === \"md\" ? \"base\" : headerSize}`}\n >\n {slide.title}\n </h2>\n )}\n {slide.description && (\n <div\n className={`leading-snug text-${textColor} text-${textSize === \"md\" ? \"base\" : textSize} line-clamp-2`}\n dangerouslySetInnerHTML={{\n __html: DOMPurify.sanitize(slide.description, {\n ALLOWED_TAGS: [\n \"br\",\n \"strong\",\n \"em\",\n \"b\",\n \"i\",\n \"ul\",\n \"ol\",\n \"li\",\n \"p\",\n ],\n ALLOWED_ATTR: [],\n }),\n }}\n />\n )}\n </div>\n\n {/* Button */}\n {slide.buttonText && slide.buttonEnabled && showButton && (\n <div className={`text-${align.horizontal}`}>\n <Button\n size={buttonSize}\n className={`rounded-md py-1 font-semibold bg-${buttonColor} text-${buttonColor}-foreground hover:bg-${buttonColor}/90`}\n asChild\n >\n <a href={slide.buttonLink}>{slide.buttonText}</a>\n </Button>\n </div>\n )}\n </div>\n </div>\n </div>\n ))}\n </div>\n </div>\n {/* Dots and Navigation */}\n {totalSlides > 1 && (\n <div\n className={`p-${padding} absolute bottom-0 z-10 flex w-full items-center justify-between ${align.horizontal === \"center\" ? \"h-full\" : \"\"}`}\n >\n {/* Pagination dots - always at bottom */}\n <div\n className={`flex items-center ${\n align.horizontal === \"center\"\n ? `p-${padding} absolute inset-x-0 bottom-3 justify-center`\n : \"\"\n }`}\n >\n <div\n className={`flex items-center gap-2 ${\n align.horizontal === \"center\" ? \"justify-center\" : \"\"\n }`}\n >\n {slides.map((_, index) => (\n <button\n key={`dot-${index}`}\n className={`h-[6px] w-[6px] rounded-full transition-colors ${\n index === currentIndex\n ? \"bg-background\"\n : \"bg-background/40 hover:bg-background/60\"\n }`}\n onClick={() => goToSlide(index)}\n aria-label={`Go to slide ${index + 1}`}\n aria-current={index === currentIndex ? \"true\" : \"false\"}\n />\n ))}\n </div>\n </div>\n\n {/* Navigation arrows - position changes based on alignment */}\n <div\n className={`flex items-center gap-[10px] ${\n align.horizontal === \"center\"\n ? `absolute inset-x-0 top-1/2 justify-between px-${padding}`\n : \"\"\n }`}\n >\n <ScrollArrows onPrevious={goToPrevious} onNext={goToNext} />\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const carouselWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"CarouselWidget\",\n displayName: \"Carousel\",\n tabsConfig: [\n { id: \"styling\", label: \"Styling\" },\n { id: \"behavior\", label: \"Behavior\" },\n { id: \"data\", label: \"Data\" },\n ],\n dataSourceTargetProps: [\"slides\"],\n fields: [\n // Styling tab - Text Styling group\n getFontSizeField({\n defaultValue: \"lg\",\n key: \"headerSize\",\n label: \"Header Font Size\",\n description: \"Font size for the slide header\",\n tab: \"styling\",\n group: \"Text Styling\",\n }),\n getColorField({\n defaultValue: \"background\",\n key: \"headerColor\",\n label: \"Header Color\",\n description: \"Color variant for the slide header\",\n tab: \"styling\",\n group: \"Text Styling\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Text Styling\",\n },\n getFontSizeField({\n defaultValue: \"md\",\n key: \"textSize\",\n label: \"Text Font Size\",\n description: \"Font size for the slide text\",\n tab: \"styling\",\n group: \"Text Styling\",\n }),\n getColorField({\n defaultValue: \"background\",\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Color variant for the slide text\",\n tab: \"styling\",\n group: \"Text Styling\",\n }),\n // Styling tab - Layout group\n {\n key: \"align\",\n label: \"Alignment\",\n type: \"alignment\",\n description: \"Alignment of the carousel content\",\n defaultValue: { vertical: \"bottom\", horizontal: \"left\" },\n options: {\n verticalEnabled: true,\n horizontalEnabled: true,\n },\n tab: \"styling\",\n group: \"Layout\",\n },\n {\n key: \"textWidth\",\n label: \"Content Width\",\n type: \"cssUnit\",\n description: \"Maximum width for slide content\",\n defaultValue: \"100%\",\n allowedUnits: [\"px\", \"rem\", \"%\"],\n defaultUnit: \"%\",\n minByUnit: { px: 50, rem: 3, \"%\": 10 },\n maxByUnit: { px: 1200, rem: 75, \"%\": 100 },\n stepByUnit: { px: 10, rem: 1, \"%\": 1 },\n tab: \"styling\",\n group: \"Layout\",\n },\n // Styling tab - Design group\n getHeightField({\n key: \"carouselHeight\",\n label: \"Carousel Height\",\n description: \"Height of the carousel\",\n defaultValue: \"400px\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator2\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getBorderRadiusField({\n defaultValue: \"md\",\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Rounded corners for the carousel\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getPaddingField({\n defaultValue: 4,\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding for the carousel\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"overlayEnabled\",\n label: \"Enable Overlay\",\n type: \"boolean\",\n description: \"Add background overlay to slide content\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"overlayType\",\n label: \"Overlay Type\",\n type: \"buttonGroup\",\n description: \"Type of overlay to add to the slide content\",\n defaultValue: \"gradient\",\n options: [\n { label: \"Solid\", value: \"solid\" },\n { label: \"Gradient\", value: \"gradient\" },\n ],\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"overlayEnabled\",\n },\n {\n key: \"overlayIntensity\",\n label: \"Overlay Intensity\",\n type: \"slider\",\n description: \"Opacity of the overlay background (0-100)\",\n min: 0,\n max: 100,\n step: 5,\n defaultValue: 50,\n unit: \"%\",\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"overlayEnabled\",\n },\n {\n key: \"showButton\",\n label: \"Show Button\",\n type: \"boolean\",\n description: \"Display the button in slide content\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n defaultValue: \"primary\",\n key: \"buttonColor\",\n label: \"Button Color\",\n description: \"Color variant for the slide button\",\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"showButton\",\n }),\n getButtonSizeField({\n defaultValue: \"default\",\n key: \"buttonSize\",\n label: \"Button Size\",\n description: \"Size of the slide button\",\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"showButton\",\n }),\n // Behavior tab - Auto-Scroll group\n {\n key: \"enableAutoScroll\",\n label: \"Enable Auto-Scroll\",\n type: \"boolean\",\n description: \"Automatically advance to the next slide\",\n defaultValue: false,\n tab: \"behavior\",\n group: \"Auto-Scroll\",\n },\n {\n key: \"autoScrollInterval\",\n label: \"Auto-Scroll Interval (ms)\",\n type: \"number\",\n description: \"Time in milliseconds between automatic slide transitions\",\n min: 1000,\n max: 10000,\n step: 500,\n defaultValue: 3000,\n tab: \"behavior\",\n group: \"Auto-Scroll\",\n requiresKeyToBeTrue: \"enableAutoScroll\",\n },\n // Data tab - Data Configuration group\n {\n key: \"dataSource\",\n label: \"Data Source\",\n type: \"dataSource\",\n description: \"\",\n tab: \"data\",\n group: \"Data Configuration\",\n },\n ],\n // Per-item configuration schema for custom data sources\n itemConfigSchema: {\n description: \"Configure settings for this slide\",\n fields: [\n {\n key: \"title\",\n label: \"Custom Title\",\n type: \"text\",\n description: \"Override the item's title for this slide\",\n },\n {\n key: \"description\",\n label: \"Custom Description\",\n type: \"textarea\",\n description: \"Override the item's description for this slide\",\n rows: 3,\n },\n {\n key: \"buttonEnabled\",\n label: \"Show Button\",\n type: \"boolean\",\n description: \"Show the button in the slide\",\n defaultValue: false,\n },\n {\n key: \"buttonText\",\n label: \"Button Text\",\n type: \"text\",\n description: \"Text to display on the slide button\",\n requiresKeyToBeTrue: \"buttonEnabled\",\n },\n {\n key: \"buttonLink\",\n label: \"Button Link\",\n type: \"text\",\n description: \"URL for the slide button\",\n requiresKeyToBeTrue: \"buttonEnabled\",\n },\n ],\n },\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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IAAG,KAAK;IAAG;GACtC,KAAK;GACL,OAAO;GACR;wDAEc;GACb,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,MAAM;GACN,OAAO;GACP,KAAK;GACL,OAAO;GACR;8DACoB;GACnB,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;yDACc;GACd,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EACF;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,SAAS,CACP;IAAE,OAAO;IAAS,OAAO;IAAS,EAClC;IAAE,OAAO;IAAY,OAAO;IAAY,CACzC;GACD,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,KAAK;GACL,MAAM;GACN,cAAc;GACd,MAAM;GACN,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;uDACa;GACZ,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;4DACiB;GACjB,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;EAEF;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;EAED;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACR;EACF;CAED,kBAAkB;EAChB,aAAa;EACb,QAAQ;GACN;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACb,MAAM;IACP;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACb,cAAc;IACf;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACb,qBAAqB;IACtB;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACb,qBAAqB;IACtB;GACF;EACF;CACF"}
|
|
1
|
+
{"version":3,"file":"CarouselWidget-D51Kz6r8.cjs","names":["MediaRenderer","getMediaPropsFromWidgetSchema","DOMPurify","Button","ScrollArrows"],"sources":["../src/widgets/CarouselWidget.tsx"],"sourcesContent":["import DOMPurify from \"dompurify\";\nimport { Button } from \"@fluid-app/ui-primitives\";\nimport { ScrollArrows } from \"../ui/scroll-arrows\";\nimport type { ComponentProps } from \"react\";\nimport { useEffect, useState, useCallback } from \"react\";\nimport type React from \"react\";\nimport {\n MediaRenderer,\n getMediaPropsFromWidgetSchema,\n} from \"../components/MediaRenderer\";\nimport type {\n WidgetSchema,\n BorderRadiusOptions,\n ColorOptions,\n AlignOptions,\n FontSizeOptions,\n PaddingOptions,\n ButtonSizeOptions,\n} from \"@fluid-app/portal-core/types\";\nimport {\n getHeightField,\n type WidgetPropertySchema,\n} from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n getButtonSizeField,\n} from \"../core/fields\";\n\nconst DEFAULT_SLIDES: CarouselSlide[] = [];\n\ntype CarouselSlide = {\n id: string;\n content: WidgetSchema;\n title?: string;\n description?: string;\n buttonEnabled?: boolean;\n buttonText?: string;\n buttonVariant?:\n | \"default\"\n | \"secondary\"\n | \"outline\"\n | \"destructive\"\n | \"ghost\"\n | \"link\";\n buttonLink?: string;\n};\n\ntype CarouselWidgetProps = ComponentProps<\"div\"> & {\n slides?: CarouselSlide[];\n autoScrollInterval?: number;\n enableAutoScroll?: boolean;\n\n // Layout\n align?: AlignOptions;\n carouselHeight?: string;\n borderRadius?: BorderRadiusOptions;\n padding?: PaddingOptions;\n\n // Text Styling\n headerSize?: FontSizeOptions;\n headerColor?: ColorOptions;\n textSize?: FontSizeOptions;\n textColor?: ColorOptions;\n textWidth?: string;\n\n // Button\n showButton?: boolean;\n buttonColor?: ColorOptions;\n buttonSize?: ButtonSizeOptions;\n\n // Overlay\n overlayEnabled?: boolean;\n overlayType?: \"solid\" | \"gradient\";\n overlayIntensity?: number;\n};\n\nexport function CarouselWidget({\n slides = DEFAULT_SLIDES,\n autoScrollInterval = 3000,\n enableAutoScroll = false,\n carouselHeight = \"400px\",\n align = { vertical: \"bottom\", horizontal: \"left\" },\n overlayIntensity = 40,\n borderRadius = \"none\",\n padding = 0,\n textWidth = \"100%\",\n headerSize = \"lg\",\n headerColor = \"background\",\n textSize = \"md\",\n textColor = \"background\",\n showButton = true,\n buttonColor = \"background\",\n buttonSize = \"default\",\n overlayEnabled = true,\n overlayType = \"solid\",\n className,\n ...props\n}: CarouselWidgetProps): React.JSX.Element {\n const [currentIndex, setCurrentIndex] = useState(0);\n const [isHovered, setIsHovered] = useState(false);\n\n const hasSlides = slides.length > 0;\n const totalSlides = slides.length;\n\n const goToNext = useCallback(() => {\n if (!hasSlides) return;\n setCurrentIndex((prev) => {\n if (prev === totalSlides - 1) {\n return 0;\n }\n return prev + 1;\n });\n }, [hasSlides, totalSlides]);\n\n const goToPrevious = useCallback(() => {\n if (!hasSlides) return;\n setCurrentIndex((prev) => {\n if (prev === 0) {\n return totalSlides - 1;\n }\n return prev - 1;\n });\n }, [hasSlides, totalSlides]);\n\n const goToSlide = useCallback(\n (index: number) => {\n if (!hasSlides) return;\n if (index >= 0 && index < totalSlides) {\n setCurrentIndex(index);\n }\n },\n [hasSlides, totalSlides],\n );\n\n // Auto-scroll effect\n useEffect(() => {\n if (!enableAutoScroll || !hasSlides || isHovered) return;\n\n const intervalId = setInterval(() => {\n goToNext();\n }, autoScrollInterval);\n\n return () => clearInterval(intervalId);\n }, [enableAutoScroll, autoScrollInterval, hasSlides, isHovered, goToNext]);\n\n // Reset to first slide if slides change\n useEffect(() => {\n if (currentIndex >= totalSlides && totalSlides > 0) {\n setCurrentIndex(0);\n }\n }, [totalSlides, currentIndex]);\n\n if (!hasSlides) {\n return (\n <div\n className={`rounded-${borderRadius} ${className} w-full overflow-hidden`}\n style={{ minHeight: carouselHeight }}\n {...props}\n >\n <div\n className=\"bg-muted flex h-full w-full items-center justify-center\"\n style={{ minHeight: carouselHeight }}\n >\n <div className=\"text-muted-foreground flex flex-col items-center gap-2\">\n <div className=\"text-4xl\">🎠</div>\n <p className=\"text-sm\">No slides added</p>\n <p className=\"text-muted-foreground/70 text-xs\">\n Add slides to create a carousel\n </p>\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div\n className={`relative w-full overflow-hidden rounded-${borderRadius} ${className}`}\n style={{ minHeight: carouselHeight }}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n {...props}\n >\n {/* Slides Container */}\n <div\n className=\"relative h-full w-full\"\n style={{ minHeight: carouselHeight }}\n >\n <div\n className=\"flex h-full transition-transform duration-500 ease-in-out\"\n style={{\n transform: `translateX(-${currentIndex * 100}%)`,\n }}\n >\n {slides.map((slide) => (\n <div\n key={slide.id}\n className=\"relative h-full w-full flex-shrink-0\"\n style={{ minWidth: \"100%\", minHeight: carouselHeight }}\n >\n {/* Background image/content layer */}\n <div className=\"absolute inset-0 h-full w-full\">\n <MediaRenderer\n {...getMediaPropsFromWidgetSchema(slide.content)}\n />\n </div>\n\n {/* Dark overlay for text readability */}\n {overlayEnabled && (\n <div\n className={`absolute inset-0 z-9 ${\n overlayType === \"gradient\"\n ? \"bg-gradient-to-t from-black to-transparent\"\n : \"bg-black\"\n }`}\n style={{\n opacity:\n (Number(String(overlayIntensity).replace(\"%\", \"\")) ||\n 40) / 100,\n }}\n />\n )}\n\n {/* Content box */}\n <div\n className={`absolute inset-x-0 z-10 flex px-3 ${\n align.horizontal === \"left\"\n ? \"justify-start\"\n : align.horizontal === \"center\"\n ? \"justify-center\"\n : \"justify-end\"\n } ${\n align.vertical === \"top\"\n ? \"top-0 pt-13\"\n : align.vertical === \"center\"\n ? \"top-1/2 -translate-y-1/2\"\n : \"bottom-0 pb-13\"\n }`}\n >\n <div\n className={`p-${padding} flex flex-col gap-3`}\n style={{ maxWidth: textWidth }}\n >\n {/* Heading and text */}\n <div className={`flex flex-col text-${align.horizontal}`}>\n {slide.title && (\n <h2\n className={`mb-2 leading-tight font-bold text-${headerColor} text-${headerSize === \"md\" ? \"base\" : headerSize}`}\n >\n {slide.title}\n </h2>\n )}\n {slide.description && (\n <div\n className={`leading-snug text-${textColor} text-${textSize === \"md\" ? \"base\" : textSize} line-clamp-2`}\n dangerouslySetInnerHTML={{\n __html: DOMPurify.sanitize(slide.description, {\n ALLOWED_TAGS: [\n \"br\",\n \"strong\",\n \"em\",\n \"b\",\n \"i\",\n \"ul\",\n \"ol\",\n \"li\",\n \"p\",\n ],\n ALLOWED_ATTR: [],\n }),\n }}\n />\n )}\n </div>\n\n {/* Button */}\n {slide.buttonText && slide.buttonEnabled && showButton && (\n <div className={`text-${align.horizontal}`}>\n <Button\n size={buttonSize}\n className={`rounded-md py-1 font-semibold bg-${buttonColor} text-${buttonColor}-foreground hover:bg-${buttonColor}/90`}\n asChild\n >\n <a href={slide.buttonLink}>{slide.buttonText}</a>\n </Button>\n </div>\n )}\n </div>\n </div>\n </div>\n ))}\n </div>\n </div>\n {/* Dots and Navigation */}\n {totalSlides > 1 && (\n <div\n className={`p-${padding} absolute bottom-0 z-10 flex w-full items-center justify-between ${align.horizontal === \"center\" ? \"h-full\" : \"\"}`}\n >\n {/* Pagination dots - always at bottom */}\n <div\n className={`flex items-center ${\n align.horizontal === \"center\"\n ? `p-${padding} absolute inset-x-0 bottom-3 justify-center`\n : \"\"\n }`}\n >\n <div\n className={`flex items-center gap-2 ${\n align.horizontal === \"center\" ? \"justify-center\" : \"\"\n }`}\n >\n {slides.map((_, index) => (\n <button\n key={`dot-${index}`}\n className={`h-[6px] w-[6px] rounded-full transition-colors ${\n index === currentIndex\n ? \"bg-background\"\n : \"bg-background/40 hover:bg-background/60\"\n }`}\n onClick={() => goToSlide(index)}\n aria-label={`Go to slide ${index + 1}`}\n aria-current={index === currentIndex ? \"true\" : \"false\"}\n />\n ))}\n </div>\n </div>\n\n {/* Navigation arrows - position changes based on alignment */}\n <div\n className={`flex items-center gap-[10px] ${\n align.horizontal === \"center\"\n ? `absolute inset-x-0 top-1/2 justify-between px-${padding}`\n : \"\"\n }`}\n >\n <ScrollArrows onPrevious={goToPrevious} onNext={goToNext} />\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const carouselWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"CarouselWidget\",\n displayName: \"Carousel\",\n tabsConfig: [\n { id: \"styling\", label: \"Styling\" },\n { id: \"behavior\", label: \"Behavior\" },\n { id: \"data\", label: \"Data\" },\n ],\n dataSourceTargetProps: [\"slides\"],\n fields: [\n // Styling tab - Text Styling group\n getFontSizeField({\n defaultValue: \"lg\",\n key: \"headerSize\",\n label: \"Header Font Size\",\n description: \"Font size for the slide header\",\n tab: \"styling\",\n group: \"Text Styling\",\n }),\n getColorField({\n defaultValue: \"background\",\n key: \"headerColor\",\n label: \"Header Color\",\n description: \"Color variant for the slide header\",\n tab: \"styling\",\n group: \"Text Styling\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Text Styling\",\n },\n getFontSizeField({\n defaultValue: \"md\",\n key: \"textSize\",\n label: \"Text Font Size\",\n description: \"Font size for the slide text\",\n tab: \"styling\",\n group: \"Text Styling\",\n }),\n getColorField({\n defaultValue: \"background\",\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Color variant for the slide text\",\n tab: \"styling\",\n group: \"Text Styling\",\n }),\n // Styling tab - Layout group\n {\n key: \"align\",\n label: \"Alignment\",\n type: \"alignment\",\n description: \"Alignment of the carousel content\",\n defaultValue: { vertical: \"bottom\", horizontal: \"left\" },\n options: {\n verticalEnabled: true,\n horizontalEnabled: true,\n },\n tab: \"styling\",\n group: \"Layout\",\n },\n {\n key: \"textWidth\",\n label: \"Content Width\",\n type: \"cssUnit\",\n description: \"Maximum width for slide content\",\n defaultValue: \"100%\",\n allowedUnits: [\"px\", \"rem\", \"%\"],\n defaultUnit: \"%\",\n minByUnit: { px: 50, rem: 3, \"%\": 10 },\n maxByUnit: { px: 1200, rem: 75, \"%\": 100 },\n stepByUnit: { px: 10, rem: 1, \"%\": 1 },\n tab: \"styling\",\n group: \"Layout\",\n },\n // Styling tab - Design group\n getHeightField({\n key: \"carouselHeight\",\n label: \"Carousel Height\",\n description: \"Height of the carousel\",\n defaultValue: \"400px\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator2\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getBorderRadiusField({\n defaultValue: \"md\",\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Rounded corners for the carousel\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getPaddingField({\n defaultValue: 4,\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding for the carousel\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"overlayEnabled\",\n label: \"Enable Overlay\",\n type: \"boolean\",\n description: \"Add background overlay to slide content\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"overlayType\",\n label: \"Overlay Type\",\n type: \"buttonGroup\",\n description: \"Type of overlay to add to the slide content\",\n defaultValue: \"gradient\",\n options: [\n { label: \"Solid\", value: \"solid\" },\n { label: \"Gradient\", value: \"gradient\" },\n ],\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"overlayEnabled\",\n },\n {\n key: \"overlayIntensity\",\n label: \"Overlay Intensity\",\n type: \"slider\",\n description: \"Opacity of the overlay background (0-100)\",\n min: 0,\n max: 100,\n step: 5,\n defaultValue: 50,\n unit: \"%\",\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"overlayEnabled\",\n },\n {\n key: \"showButton\",\n label: \"Show Button\",\n type: \"boolean\",\n description: \"Display the button in slide content\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n defaultValue: \"primary\",\n key: \"buttonColor\",\n label: \"Button Color\",\n description: \"Color variant for the slide button\",\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"showButton\",\n }),\n getButtonSizeField({\n defaultValue: \"default\",\n key: \"buttonSize\",\n label: \"Button Size\",\n description: \"Size of the slide button\",\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"showButton\",\n }),\n // Behavior tab - Auto-Scroll group\n {\n key: \"enableAutoScroll\",\n label: \"Enable Auto-Scroll\",\n type: \"boolean\",\n description: \"Automatically advance to the next slide\",\n defaultValue: false,\n tab: \"behavior\",\n group: \"Auto-Scroll\",\n },\n {\n key: \"autoScrollInterval\",\n label: \"Auto-Scroll Interval (ms)\",\n type: \"number\",\n description: \"Time in milliseconds between automatic slide transitions\",\n min: 1000,\n max: 10000,\n step: 500,\n defaultValue: 3000,\n tab: \"behavior\",\n group: \"Auto-Scroll\",\n requiresKeyToBeTrue: \"enableAutoScroll\",\n },\n // Data tab - Data Configuration group\n {\n key: \"dataSource\",\n label: \"Data Source\",\n type: \"dataSource\",\n description: \"\",\n tab: \"data\",\n group: \"Data Configuration\",\n },\n ],\n // Per-item configuration schema for custom data sources\n itemConfigSchema: {\n description: \"Configure settings for this slide\",\n fields: [\n {\n key: \"title\",\n label: \"Custom Title\",\n type: \"text\",\n description: \"Override the item's title for this slide\",\n },\n {\n key: \"description\",\n label: \"Custom Description\",\n type: \"textarea\",\n description: \"Override the item's description for this slide\",\n rows: 3,\n },\n {\n key: \"buttonEnabled\",\n label: \"Show Button\",\n type: \"boolean\",\n description: \"Show the button in the slide\",\n defaultValue: false,\n },\n {\n key: \"buttonText\",\n label: \"Button Text\",\n type: \"text\",\n description: \"Text to display on the slide button\",\n requiresKeyToBeTrue: \"buttonEnabled\",\n },\n {\n key: \"buttonLink\",\n label: \"Button Link\",\n type: \"text\",\n description: \"URL for the slide button\",\n requiresKeyToBeTrue: \"buttonEnabled\",\n },\n ],\n },\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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IAAG,KAAK;IAAG;GACtC,KAAK;GACL,OAAO;GACR;wDAEc;GACb,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,MAAM;GACN,OAAO;GACP,KAAK;GACL,OAAO;GACR;8DACoB;GACnB,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;yDACc;GACd,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EACF;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,SAAS,CACP;IAAE,OAAO;IAAS,OAAO;IAAS,EAClC;IAAE,OAAO;IAAY,OAAO;IAAY,CACzC;GACD,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,KAAK;GACL,MAAM;GACN,cAAc;GACd,MAAM;GACN,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;uDACa;GACZ,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;4DACiB;GACjB,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;EAEF;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;EAED;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACR;EACF;CAED,kBAAkB;EAChB,aAAa;EACb,QAAQ;GACN;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACb,MAAM;IACP;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACb,cAAc;IACf;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACb,qBAAqB;IACtB;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACb,qBAAqB;IACtB;GACF;EACF;CACF"}
|
|
@@ -1,7 +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$1, r as getButtonSizeField } from "./fields-wPOk-SmZ.mjs";
|
|
3
|
-
import { t as ScrollArrows } from "./scroll-arrows-
|
|
4
|
-
import { r as getMediaPropsFromWidgetSchema, t as MediaRenderer } from "./MediaRenderer-
|
|
3
|
+
import { t as ScrollArrows } from "./scroll-arrows-CTQrIV6z.mjs";
|
|
4
|
+
import { r as getMediaPropsFromWidgetSchema, t as MediaRenderer } from "./MediaRenderer-CrvEIBKa.mjs";
|
|
5
5
|
import { getHeightField } from "@fluid-app/portal-core/registries";
|
|
6
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
import { useCallback, useEffect, useState } from "react";
|
|
@@ -451,4 +451,4 @@ const carouselWidgetPropertySchema = {
|
|
|
451
451
|
//#endregion
|
|
452
452
|
export { CarouselWidget_exports as n, carouselWidgetPropertySchema as r, CarouselWidget as t };
|
|
453
453
|
|
|
454
|
-
//# sourceMappingURL=CarouselWidget-
|
|
454
|
+
//# sourceMappingURL=CarouselWidget-DFmVlZlT.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CarouselWidget-MOGejQHD.mjs","names":["getBorderRadiusField"],"sources":["../src/widgets/CarouselWidget.tsx"],"sourcesContent":["import DOMPurify from \"dompurify\";\nimport { Button } from \"@fluid-app/ui-primitives\";\nimport { ScrollArrows } from \"../ui/scroll-arrows\";\nimport type { ComponentProps } from \"react\";\nimport { useEffect, useState, useCallback } from \"react\";\nimport type React from \"react\";\nimport {\n MediaRenderer,\n getMediaPropsFromWidgetSchema,\n} from \"../components/MediaRenderer\";\nimport type {\n WidgetSchema,\n BorderRadiusOptions,\n ColorOptions,\n AlignOptions,\n FontSizeOptions,\n PaddingOptions,\n ButtonSizeOptions,\n} from \"@fluid-app/portal-core/types\";\nimport {\n getHeightField,\n type WidgetPropertySchema,\n} from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n getButtonSizeField,\n} from \"../core/fields\";\n\nconst DEFAULT_SLIDES: CarouselSlide[] = [];\n\ntype CarouselSlide = {\n id: string;\n content: WidgetSchema;\n title?: string;\n description?: string;\n buttonEnabled?: boolean;\n buttonText?: string;\n buttonVariant?:\n | \"default\"\n | \"secondary\"\n | \"outline\"\n | \"destructive\"\n | \"ghost\"\n | \"link\";\n buttonLink?: string;\n};\n\ntype CarouselWidgetProps = ComponentProps<\"div\"> & {\n slides?: CarouselSlide[];\n autoScrollInterval?: number;\n enableAutoScroll?: boolean;\n\n // Layout\n align?: AlignOptions;\n carouselHeight?: string;\n borderRadius?: BorderRadiusOptions;\n padding?: PaddingOptions;\n\n // Text Styling\n headerSize?: FontSizeOptions;\n headerColor?: ColorOptions;\n textSize?: FontSizeOptions;\n textColor?: ColorOptions;\n textWidth?: string;\n\n // Button\n showButton?: boolean;\n buttonColor?: ColorOptions;\n buttonSize?: ButtonSizeOptions;\n\n // Overlay\n overlayEnabled?: boolean;\n overlayType?: \"solid\" | \"gradient\";\n overlayIntensity?: number;\n};\n\nexport function CarouselWidget({\n slides = DEFAULT_SLIDES,\n autoScrollInterval = 3000,\n enableAutoScroll = false,\n carouselHeight = \"400px\",\n align = { vertical: \"bottom\", horizontal: \"left\" },\n overlayIntensity = 40,\n borderRadius = \"none\",\n padding = 0,\n textWidth = \"100%\",\n headerSize = \"lg\",\n headerColor = \"background\",\n textSize = \"md\",\n textColor = \"background\",\n showButton = true,\n buttonColor = \"background\",\n buttonSize = \"default\",\n overlayEnabled = true,\n overlayType = \"solid\",\n className,\n ...props\n}: CarouselWidgetProps): React.JSX.Element {\n const [currentIndex, setCurrentIndex] = useState(0);\n const [isHovered, setIsHovered] = useState(false);\n\n const hasSlides = slides.length > 0;\n const totalSlides = slides.length;\n\n const goToNext = useCallback(() => {\n if (!hasSlides) return;\n setCurrentIndex((prev) => {\n if (prev === totalSlides - 1) {\n return 0;\n }\n return prev + 1;\n });\n }, [hasSlides, totalSlides]);\n\n const goToPrevious = useCallback(() => {\n if (!hasSlides) return;\n setCurrentIndex((prev) => {\n if (prev === 0) {\n return totalSlides - 1;\n }\n return prev - 1;\n });\n }, [hasSlides, totalSlides]);\n\n const goToSlide = useCallback(\n (index: number) => {\n if (!hasSlides) return;\n if (index >= 0 && index < totalSlides) {\n setCurrentIndex(index);\n }\n },\n [hasSlides, totalSlides],\n );\n\n // Auto-scroll effect\n useEffect(() => {\n if (!enableAutoScroll || !hasSlides || isHovered) return;\n\n const intervalId = setInterval(() => {\n goToNext();\n }, autoScrollInterval);\n\n return () => clearInterval(intervalId);\n }, [enableAutoScroll, autoScrollInterval, hasSlides, isHovered, goToNext]);\n\n // Reset to first slide if slides change\n useEffect(() => {\n if (currentIndex >= totalSlides && totalSlides > 0) {\n setCurrentIndex(0);\n }\n }, [totalSlides, currentIndex]);\n\n if (!hasSlides) {\n return (\n <div\n className={`rounded-${borderRadius} ${className} w-full overflow-hidden`}\n style={{ minHeight: carouselHeight }}\n {...props}\n >\n <div\n className=\"bg-muted flex h-full w-full items-center justify-center\"\n style={{ minHeight: carouselHeight }}\n >\n <div className=\"text-muted-foreground flex flex-col items-center gap-2\">\n <div className=\"text-4xl\">🎠</div>\n <p className=\"text-sm\">No slides added</p>\n <p className=\"text-muted-foreground/70 text-xs\">\n Add slides to create a carousel\n </p>\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div\n className={`relative w-full overflow-hidden rounded-${borderRadius} ${className}`}\n style={{ minHeight: carouselHeight }}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n {...props}\n >\n {/* Slides Container */}\n <div\n className=\"relative h-full w-full\"\n style={{ minHeight: carouselHeight }}\n >\n <div\n className=\"flex h-full transition-transform duration-500 ease-in-out\"\n style={{\n transform: `translateX(-${currentIndex * 100}%)`,\n }}\n >\n {slides.map((slide) => (\n <div\n key={slide.id}\n className=\"relative h-full w-full flex-shrink-0\"\n style={{ minWidth: \"100%\", minHeight: carouselHeight }}\n >\n {/* Background image/content layer */}\n <div className=\"absolute inset-0 h-full w-full\">\n <MediaRenderer\n {...getMediaPropsFromWidgetSchema(slide.content)}\n />\n </div>\n\n {/* Dark overlay for text readability */}\n {overlayEnabled && (\n <div\n className={`absolute inset-0 z-9 ${\n overlayType === \"gradient\"\n ? \"bg-gradient-to-t from-black to-transparent\"\n : \"bg-black\"\n }`}\n style={{\n opacity:\n (Number(String(overlayIntensity).replace(\"%\", \"\")) ||\n 40) / 100,\n }}\n />\n )}\n\n {/* Content box */}\n <div\n className={`absolute inset-x-0 z-10 flex px-3 ${\n align.horizontal === \"left\"\n ? \"justify-start\"\n : align.horizontal === \"center\"\n ? \"justify-center\"\n : \"justify-end\"\n } ${\n align.vertical === \"top\"\n ? \"top-0 pt-13\"\n : align.vertical === \"center\"\n ? \"top-1/2 -translate-y-1/2\"\n : \"bottom-0 pb-13\"\n }`}\n >\n <div\n className={`p-${padding} flex flex-col gap-3`}\n style={{ maxWidth: textWidth }}\n >\n {/* Heading and text */}\n <div className={`flex flex-col text-${align.horizontal}`}>\n {slide.title && (\n <h2\n className={`mb-2 leading-tight font-bold text-${headerColor} text-${headerSize === \"md\" ? \"base\" : headerSize}`}\n >\n {slide.title}\n </h2>\n )}\n {slide.description && (\n <div\n className={`leading-snug text-${textColor} text-${textSize === \"md\" ? \"base\" : textSize} line-clamp-2`}\n dangerouslySetInnerHTML={{\n __html: DOMPurify.sanitize(slide.description, {\n ALLOWED_TAGS: [\n \"br\",\n \"strong\",\n \"em\",\n \"b\",\n \"i\",\n \"ul\",\n \"ol\",\n \"li\",\n \"p\",\n ],\n ALLOWED_ATTR: [],\n }),\n }}\n />\n )}\n </div>\n\n {/* Button */}\n {slide.buttonText && slide.buttonEnabled && showButton && (\n <div className={`text-${align.horizontal}`}>\n <Button\n size={buttonSize}\n className={`rounded-md py-1 font-semibold bg-${buttonColor} text-${buttonColor}-foreground hover:bg-${buttonColor}/90`}\n asChild\n >\n <a href={slide.buttonLink}>{slide.buttonText}</a>\n </Button>\n </div>\n )}\n </div>\n </div>\n </div>\n ))}\n </div>\n </div>\n {/* Dots and Navigation */}\n {totalSlides > 1 && (\n <div\n className={`p-${padding} absolute bottom-0 z-10 flex w-full items-center justify-between ${align.horizontal === \"center\" ? \"h-full\" : \"\"}`}\n >\n {/* Pagination dots - always at bottom */}\n <div\n className={`flex items-center ${\n align.horizontal === \"center\"\n ? `p-${padding} absolute inset-x-0 bottom-3 justify-center`\n : \"\"\n }`}\n >\n <div\n className={`flex items-center gap-2 ${\n align.horizontal === \"center\" ? \"justify-center\" : \"\"\n }`}\n >\n {slides.map((_, index) => (\n <button\n key={`dot-${index}`}\n className={`h-[6px] w-[6px] rounded-full transition-colors ${\n index === currentIndex\n ? \"bg-background\"\n : \"bg-background/40 hover:bg-background/60\"\n }`}\n onClick={() => goToSlide(index)}\n aria-label={`Go to slide ${index + 1}`}\n aria-current={index === currentIndex ? \"true\" : \"false\"}\n />\n ))}\n </div>\n </div>\n\n {/* Navigation arrows - position changes based on alignment */}\n <div\n className={`flex items-center gap-[10px] ${\n align.horizontal === \"center\"\n ? `absolute inset-x-0 top-1/2 justify-between px-${padding}`\n : \"\"\n }`}\n >\n <ScrollArrows onPrevious={goToPrevious} onNext={goToNext} />\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const carouselWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"CarouselWidget\",\n displayName: \"Carousel\",\n tabsConfig: [\n { id: \"styling\", label: \"Styling\" },\n { id: \"behavior\", label: \"Behavior\" },\n { id: \"data\", label: \"Data\" },\n ],\n dataSourceTargetProps: [\"slides\"],\n fields: [\n // Styling tab - Text Styling group\n getFontSizeField({\n defaultValue: \"lg\",\n key: \"headerSize\",\n label: \"Header Font Size\",\n description: \"Font size for the slide header\",\n tab: \"styling\",\n group: \"Text Styling\",\n }),\n getColorField({\n defaultValue: \"background\",\n key: \"headerColor\",\n label: \"Header Color\",\n description: \"Color variant for the slide header\",\n tab: \"styling\",\n group: \"Text Styling\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Text Styling\",\n },\n getFontSizeField({\n defaultValue: \"md\",\n key: \"textSize\",\n label: \"Text Font Size\",\n description: \"Font size for the slide text\",\n tab: \"styling\",\n group: \"Text Styling\",\n }),\n getColorField({\n defaultValue: \"background\",\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Color variant for the slide text\",\n tab: \"styling\",\n group: \"Text Styling\",\n }),\n // Styling tab - Layout group\n {\n key: \"align\",\n label: \"Alignment\",\n type: \"alignment\",\n description: \"Alignment of the carousel content\",\n defaultValue: { vertical: \"bottom\", horizontal: \"left\" },\n options: {\n verticalEnabled: true,\n horizontalEnabled: true,\n },\n tab: \"styling\",\n group: \"Layout\",\n },\n {\n key: \"textWidth\",\n label: \"Content Width\",\n type: \"cssUnit\",\n description: \"Maximum width for slide content\",\n defaultValue: \"100%\",\n allowedUnits: [\"px\", \"rem\", \"%\"],\n defaultUnit: \"%\",\n minByUnit: { px: 50, rem: 3, \"%\": 10 },\n maxByUnit: { px: 1200, rem: 75, \"%\": 100 },\n stepByUnit: { px: 10, rem: 1, \"%\": 1 },\n tab: \"styling\",\n group: \"Layout\",\n },\n // Styling tab - Design group\n getHeightField({\n key: \"carouselHeight\",\n label: \"Carousel Height\",\n description: \"Height of the carousel\",\n defaultValue: \"400px\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator2\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getBorderRadiusField({\n defaultValue: \"md\",\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Rounded corners for the carousel\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getPaddingField({\n defaultValue: 4,\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding for the carousel\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"overlayEnabled\",\n label: \"Enable Overlay\",\n type: \"boolean\",\n description: \"Add background overlay to slide content\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"overlayType\",\n label: \"Overlay Type\",\n type: \"buttonGroup\",\n description: \"Type of overlay to add to the slide content\",\n defaultValue: \"gradient\",\n options: [\n { label: \"Solid\", value: \"solid\" },\n { label: \"Gradient\", value: \"gradient\" },\n ],\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"overlayEnabled\",\n },\n {\n key: \"overlayIntensity\",\n label: \"Overlay Intensity\",\n type: \"slider\",\n description: \"Opacity of the overlay background (0-100)\",\n min: 0,\n max: 100,\n step: 5,\n defaultValue: 50,\n unit: \"%\",\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"overlayEnabled\",\n },\n {\n key: \"showButton\",\n label: \"Show Button\",\n type: \"boolean\",\n description: \"Display the button in slide content\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n defaultValue: \"primary\",\n key: \"buttonColor\",\n label: \"Button Color\",\n description: \"Color variant for the slide button\",\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"showButton\",\n }),\n getButtonSizeField({\n defaultValue: \"default\",\n key: \"buttonSize\",\n label: \"Button Size\",\n description: \"Size of the slide button\",\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"showButton\",\n }),\n // Behavior tab - Auto-Scroll group\n {\n key: \"enableAutoScroll\",\n label: \"Enable Auto-Scroll\",\n type: \"boolean\",\n description: \"Automatically advance to the next slide\",\n defaultValue: false,\n tab: \"behavior\",\n group: \"Auto-Scroll\",\n },\n {\n key: \"autoScrollInterval\",\n label: \"Auto-Scroll Interval (ms)\",\n type: \"number\",\n description: \"Time in milliseconds between automatic slide transitions\",\n min: 1000,\n max: 10000,\n step: 500,\n defaultValue: 3000,\n tab: \"behavior\",\n group: \"Auto-Scroll\",\n requiresKeyToBeTrue: \"enableAutoScroll\",\n },\n // Data tab - Data Configuration group\n {\n key: \"dataSource\",\n label: \"Data Source\",\n type: \"dataSource\",\n description: \"\",\n tab: \"data\",\n group: \"Data Configuration\",\n },\n ],\n // Per-item configuration schema for custom data sources\n itemConfigSchema: {\n description: \"Configure settings for this slide\",\n fields: [\n {\n key: \"title\",\n label: \"Custom Title\",\n type: \"text\",\n description: \"Override the item's title for this slide\",\n },\n {\n key: \"description\",\n label: \"Custom Description\",\n type: \"textarea\",\n description: \"Override the item's description for this slide\",\n rows: 3,\n },\n {\n key: \"buttonEnabled\",\n label: \"Show Button\",\n type: \"boolean\",\n description: \"Show the button in the slide\",\n defaultValue: false,\n },\n {\n key: \"buttonText\",\n label: \"Button Text\",\n type: \"text\",\n description: \"Text to display on the slide button\",\n requiresKeyToBeTrue: \"buttonEnabled\",\n },\n {\n key: \"buttonLink\",\n label: \"Button Link\",\n type: \"text\",\n description: \"URL for the slide button\",\n requiresKeyToBeTrue: \"buttonEnabled\",\n },\n ],\n },\n} as const satisfies WidgetPropertySchema;\n"],"mappings":";;;;;;;;;;;;;;AA+BA,MAAM,iBAAkC,EAAE;AAgD1C,SAAgB,eAAe,EAC7B,SAAS,gBACT,qBAAqB,KACrB,mBAAmB,OACnB,iBAAiB,SACjB,QAAQ;CAAE,UAAU;CAAU,YAAY;CAAQ,EAClD,mBAAmB,IACnB,eAAe,QACf,UAAU,GACV,YAAY,QACZ,aAAa,MACb,cAAc,cACd,WAAW,MACX,YAAY,cACZ,aAAa,MACb,cAAc,cACd,aAAa,WACb,iBAAiB,MACjB,cAAc,SACd,WACA,GAAG,SACsC;CACzC,MAAM,CAAC,cAAc,mBAAmB,SAAS,EAAE;CACnD,MAAM,CAAC,WAAW,gBAAgB,SAAS,MAAM;CAEjD,MAAM,YAAY,OAAO,SAAS;CAClC,MAAM,cAAc,OAAO;CAE3B,MAAM,WAAW,kBAAkB;AACjC,MAAI,CAAC,UAAW;AAChB,mBAAiB,SAAS;AACxB,OAAI,SAAS,cAAc,EACzB,QAAO;AAET,UAAO,OAAO;IACd;IACD,CAAC,WAAW,YAAY,CAAC;CAE5B,MAAM,eAAe,kBAAkB;AACrC,MAAI,CAAC,UAAW;AAChB,mBAAiB,SAAS;AACxB,OAAI,SAAS,EACX,QAAO,cAAc;AAEvB,UAAO,OAAO;IACd;IACD,CAAC,WAAW,YAAY,CAAC;CAE5B,MAAM,YAAY,aACf,UAAkB;AACjB,MAAI,CAAC,UAAW;AAChB,MAAI,SAAS,KAAK,QAAQ,YACxB,iBAAgB,MAAM;IAG1B,CAAC,WAAW,YAAY,CACzB;AAGD,iBAAgB;AACd,MAAI,CAAC,oBAAoB,CAAC,aAAa,UAAW;EAElD,MAAM,aAAa,kBAAkB;AACnC,aAAU;KACT,mBAAmB;AAEtB,eAAa,cAAc,WAAW;IACrC;EAAC;EAAkB;EAAoB;EAAW;EAAW;EAAS,CAAC;AAG1E,iBAAgB;AACd,MAAI,gBAAgB,eAAe,cAAc,EAC/C,iBAAgB,EAAE;IAEnB,CAAC,aAAa,aAAa,CAAC;AAE/B,KAAI,CAAC,UACH,QACE,oBAAC,OAAD;EACE,WAAW,WAAW,aAAa,GAAG,UAAU;EAChD,OAAO,EAAE,WAAW,gBAAgB;EACpC,GAAI;YAEJ,oBAAC,OAAD;GACE,WAAU;GACV,OAAO,EAAE,WAAW,gBAAgB;aAEpC,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,OAAD;MAAK,WAAU;gBAAW;MAAQ,CAAA;KAClC,oBAAC,KAAD;MAAG,WAAU;gBAAU;MAAmB,CAAA;KAC1C,oBAAC,KAAD;MAAG,WAAU;gBAAmC;MAE5C,CAAA;KACA;;GACF,CAAA;EACF,CAAA;AAIV,QACE,qBAAC,OAAD;EACE,WAAW,2CAA2C,aAAa,GAAG;EACtE,OAAO,EAAE,WAAW,gBAAgB;EACpC,oBAAoB,aAAa,KAAK;EACtC,oBAAoB,aAAa,MAAM;EACvC,GAAI;YALN,CAQE,oBAAC,OAAD;GACE,WAAU;GACV,OAAO,EAAE,WAAW,gBAAgB;aAEpC,oBAAC,OAAD;IACE,WAAU;IACV,OAAO,EACL,WAAW,eAAe,eAAe,IAAI,KAC9C;cAEA,OAAO,KAAK,UACX,qBAAC,OAAD;KAEE,WAAU;KACV,OAAO;MAAE,UAAU;MAAQ,WAAW;MAAgB;eAHxD;MAME,oBAAC,OAAD;OAAK,WAAU;iBACb,oBAAC,eAAD,EACE,GAAI,8BAA8B,MAAM,QAAQ,EAChD,CAAA;OACE,CAAA;MAGL,kBACC,oBAAC,OAAD;OACE,WAAW,wBACT,gBAAgB,aACZ,+CACA;OAEN,OAAO,EACL,UACG,OAAO,OAAO,iBAAiB,CAAC,QAAQ,KAAK,GAAG,CAAC,IAChD,MAAM,KACX;OACD,CAAA;MAIJ,oBAAC,OAAD;OACE,WAAW,qCACT,MAAM,eAAe,SACjB,kBACA,MAAM,eAAe,WACnB,mBACA,cACP,GACC,MAAM,aAAa,QACf,gBACA,MAAM,aAAa,WACjB,6BACA;iBAGR,qBAAC,OAAD;QACE,WAAW,KAAK,QAAQ;QACxB,OAAO,EAAE,UAAU,WAAW;kBAFhC,CAKE,qBAAC,OAAD;SAAK,WAAW,sBAAsB,MAAM;mBAA5C,CACG,MAAM,SACL,oBAAC,MAAD;UACE,WAAW,qCAAqC,YAAY,QAAQ,eAAe,OAAO,SAAS;oBAElG,MAAM;UACJ,CAAA,EAEN,MAAM,eACL,oBAAC,OAAD;UACE,WAAW,qBAAqB,UAAU,QAAQ,aAAa,OAAO,SAAS,SAAS;UACxF,yBAAyB,EACvB,QAAQ,UAAU,SAAS,MAAM,aAAa;WAC5C,cAAc;YACZ;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACD;WACD,cAAc,EAAE;WACjB,CAAC,EACH;UACD,CAAA,CAEA;YAGL,MAAM,cAAc,MAAM,iBAAiB,cAC1C,oBAAC,OAAD;SAAK,WAAW,QAAQ,MAAM;mBAC5B,oBAAC,QAAD;UACE,MAAM;UACN,WAAW,oCAAoC,YAAY,QAAQ,YAAY,uBAAuB,YAAY;UAClH,SAAA;oBAEA,oBAAC,KAAD;WAAG,MAAM,MAAM;qBAAa,MAAM;WAAe,CAAA;UAC1C,CAAA;SACL,CAAA,CAEJ;;OACF,CAAA;MACF;OA7FC,MAAM,GA6FP,CACN;IACE,CAAA;GACF,CAAA,EAEL,cAAc,KACb,qBAAC,OAAD;GACE,WAAW,KAAK,QAAQ,mEAAmE,MAAM,eAAe,WAAW,WAAW;aADxI,CAIE,oBAAC,OAAD;IACE,WAAW,qBACT,MAAM,eAAe,WACjB,KAAK,QAAQ,+CACb;cAGN,oBAAC,OAAD;KACE,WAAW,2BACT,MAAM,eAAe,WAAW,mBAAmB;eAGpD,OAAO,KAAK,GAAG,UACd,oBAAC,UAAD;MAEE,WAAW,kDACT,UAAU,eACN,kBACA;MAEN,eAAe,UAAU,MAAM;MAC/B,cAAY,eAAe,QAAQ;MACnC,gBAAc,UAAU,eAAe,SAAS;MAChD,EATK,OAAO,QASZ,CACF;KACE,CAAA;IACF,CAAA,EAGN,oBAAC,OAAD;IACE,WAAW,gCACT,MAAM,eAAe,WACjB,iDAAiD,YACjD;cAGN,oBAAC,cAAD;KAAc,YAAY;KAAc,QAAQ;KAAY,CAAA;IACxD,CAAA,CACF;KAEJ;;;AAIV,MAAa,+BAAqD;CAChE,YAAY;CACZ,aAAa;CACb,YAAY;EACV;GAAE,IAAI;GAAW,OAAO;GAAW;EACnC;GAAE,IAAI;GAAY,OAAO;GAAY;EACrC;GAAE,IAAI;GAAQ,OAAO;GAAQ;EAC9B;CACD,uBAAuB,CAAC,SAAS;CACjC,QAAQ;EAEN,iBAAiB;GACf,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EACF,cAAc;GACZ,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,MAAM;GACN,OAAO;GACP,KAAK;GACL,OAAO;GACR;EACD,iBAAiB;GACf,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EACF,cAAc;GACZ,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EAEF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;IAAE,UAAU;IAAU,YAAY;IAAQ;GACxD,SAAS;IACP,iBAAiB;IACjB,mBAAmB;IACpB;GACD,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,cAAc;IAAC;IAAM;IAAO;IAAI;GAChC,aAAa;GACb,WAAW;IAAE,IAAI;IAAI,KAAK;IAAG,KAAK;IAAI;GACtC,WAAW;IAAE,IAAI;IAAM,KAAK;IAAI,KAAK;IAAK;GAC1C,YAAY;IAAE,IAAI;IAAI,KAAK;IAAG,KAAK;IAAG;GACtC,KAAK;GACL,OAAO;GACR;EAED,eAAe;GACb,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,MAAM;GACN,OAAO;GACP,KAAK;GACL,OAAO;GACR;EACDA,uBAAqB;GACnB,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EACF,gBAAgB;GACd,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EACF;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,SAAS,CACP;IAAE,OAAO;IAAS,OAAO;IAAS,EAClC;IAAE,OAAO;IAAY,OAAO;IAAY,CACzC;GACD,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,KAAK;GACL,MAAM;GACN,cAAc;GACd,MAAM;GACN,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD,cAAc;GACZ,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;EACF,mBAAmB;GACjB,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;EAEF;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;EAED;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACR;EACF;CAED,kBAAkB;EAChB,aAAa;EACb,QAAQ;GACN;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACb,MAAM;IACP;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACb,cAAc;IACf;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACb,qBAAqB;IACtB;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACb,qBAAqB;IACtB;GACF;EACF;CACF"}
|
|
1
|
+
{"version":3,"file":"CarouselWidget-DFmVlZlT.mjs","names":["getBorderRadiusField"],"sources":["../src/widgets/CarouselWidget.tsx"],"sourcesContent":["import DOMPurify from \"dompurify\";\nimport { Button } from \"@fluid-app/ui-primitives\";\nimport { ScrollArrows } from \"../ui/scroll-arrows\";\nimport type { ComponentProps } from \"react\";\nimport { useEffect, useState, useCallback } from \"react\";\nimport type React from \"react\";\nimport {\n MediaRenderer,\n getMediaPropsFromWidgetSchema,\n} from \"../components/MediaRenderer\";\nimport type {\n WidgetSchema,\n BorderRadiusOptions,\n ColorOptions,\n AlignOptions,\n FontSizeOptions,\n PaddingOptions,\n ButtonSizeOptions,\n} from \"@fluid-app/portal-core/types\";\nimport {\n getHeightField,\n type WidgetPropertySchema,\n} from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n getButtonSizeField,\n} from \"../core/fields\";\n\nconst DEFAULT_SLIDES: CarouselSlide[] = [];\n\ntype CarouselSlide = {\n id: string;\n content: WidgetSchema;\n title?: string;\n description?: string;\n buttonEnabled?: boolean;\n buttonText?: string;\n buttonVariant?:\n | \"default\"\n | \"secondary\"\n | \"outline\"\n | \"destructive\"\n | \"ghost\"\n | \"link\";\n buttonLink?: string;\n};\n\ntype CarouselWidgetProps = ComponentProps<\"div\"> & {\n slides?: CarouselSlide[];\n autoScrollInterval?: number;\n enableAutoScroll?: boolean;\n\n // Layout\n align?: AlignOptions;\n carouselHeight?: string;\n borderRadius?: BorderRadiusOptions;\n padding?: PaddingOptions;\n\n // Text Styling\n headerSize?: FontSizeOptions;\n headerColor?: ColorOptions;\n textSize?: FontSizeOptions;\n textColor?: ColorOptions;\n textWidth?: string;\n\n // Button\n showButton?: boolean;\n buttonColor?: ColorOptions;\n buttonSize?: ButtonSizeOptions;\n\n // Overlay\n overlayEnabled?: boolean;\n overlayType?: \"solid\" | \"gradient\";\n overlayIntensity?: number;\n};\n\nexport function CarouselWidget({\n slides = DEFAULT_SLIDES,\n autoScrollInterval = 3000,\n enableAutoScroll = false,\n carouselHeight = \"400px\",\n align = { vertical: \"bottom\", horizontal: \"left\" },\n overlayIntensity = 40,\n borderRadius = \"none\",\n padding = 0,\n textWidth = \"100%\",\n headerSize = \"lg\",\n headerColor = \"background\",\n textSize = \"md\",\n textColor = \"background\",\n showButton = true,\n buttonColor = \"background\",\n buttonSize = \"default\",\n overlayEnabled = true,\n overlayType = \"solid\",\n className,\n ...props\n}: CarouselWidgetProps): React.JSX.Element {\n const [currentIndex, setCurrentIndex] = useState(0);\n const [isHovered, setIsHovered] = useState(false);\n\n const hasSlides = slides.length > 0;\n const totalSlides = slides.length;\n\n const goToNext = useCallback(() => {\n if (!hasSlides) return;\n setCurrentIndex((prev) => {\n if (prev === totalSlides - 1) {\n return 0;\n }\n return prev + 1;\n });\n }, [hasSlides, totalSlides]);\n\n const goToPrevious = useCallback(() => {\n if (!hasSlides) return;\n setCurrentIndex((prev) => {\n if (prev === 0) {\n return totalSlides - 1;\n }\n return prev - 1;\n });\n }, [hasSlides, totalSlides]);\n\n const goToSlide = useCallback(\n (index: number) => {\n if (!hasSlides) return;\n if (index >= 0 && index < totalSlides) {\n setCurrentIndex(index);\n }\n },\n [hasSlides, totalSlides],\n );\n\n // Auto-scroll effect\n useEffect(() => {\n if (!enableAutoScroll || !hasSlides || isHovered) return;\n\n const intervalId = setInterval(() => {\n goToNext();\n }, autoScrollInterval);\n\n return () => clearInterval(intervalId);\n }, [enableAutoScroll, autoScrollInterval, hasSlides, isHovered, goToNext]);\n\n // Reset to first slide if slides change\n useEffect(() => {\n if (currentIndex >= totalSlides && totalSlides > 0) {\n setCurrentIndex(0);\n }\n }, [totalSlides, currentIndex]);\n\n if (!hasSlides) {\n return (\n <div\n className={`rounded-${borderRadius} ${className} w-full overflow-hidden`}\n style={{ minHeight: carouselHeight }}\n {...props}\n >\n <div\n className=\"bg-muted flex h-full w-full items-center justify-center\"\n style={{ minHeight: carouselHeight }}\n >\n <div className=\"text-muted-foreground flex flex-col items-center gap-2\">\n <div className=\"text-4xl\">🎠</div>\n <p className=\"text-sm\">No slides added</p>\n <p className=\"text-muted-foreground/70 text-xs\">\n Add slides to create a carousel\n </p>\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div\n className={`relative w-full overflow-hidden rounded-${borderRadius} ${className}`}\n style={{ minHeight: carouselHeight }}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n {...props}\n >\n {/* Slides Container */}\n <div\n className=\"relative h-full w-full\"\n style={{ minHeight: carouselHeight }}\n >\n <div\n className=\"flex h-full transition-transform duration-500 ease-in-out\"\n style={{\n transform: `translateX(-${currentIndex * 100}%)`,\n }}\n >\n {slides.map((slide) => (\n <div\n key={slide.id}\n className=\"relative h-full w-full flex-shrink-0\"\n style={{ minWidth: \"100%\", minHeight: carouselHeight }}\n >\n {/* Background image/content layer */}\n <div className=\"absolute inset-0 h-full w-full\">\n <MediaRenderer\n {...getMediaPropsFromWidgetSchema(slide.content)}\n />\n </div>\n\n {/* Dark overlay for text readability */}\n {overlayEnabled && (\n <div\n className={`absolute inset-0 z-9 ${\n overlayType === \"gradient\"\n ? \"bg-gradient-to-t from-black to-transparent\"\n : \"bg-black\"\n }`}\n style={{\n opacity:\n (Number(String(overlayIntensity).replace(\"%\", \"\")) ||\n 40) / 100,\n }}\n />\n )}\n\n {/* Content box */}\n <div\n className={`absolute inset-x-0 z-10 flex px-3 ${\n align.horizontal === \"left\"\n ? \"justify-start\"\n : align.horizontal === \"center\"\n ? \"justify-center\"\n : \"justify-end\"\n } ${\n align.vertical === \"top\"\n ? \"top-0 pt-13\"\n : align.vertical === \"center\"\n ? \"top-1/2 -translate-y-1/2\"\n : \"bottom-0 pb-13\"\n }`}\n >\n <div\n className={`p-${padding} flex flex-col gap-3`}\n style={{ maxWidth: textWidth }}\n >\n {/* Heading and text */}\n <div className={`flex flex-col text-${align.horizontal}`}>\n {slide.title && (\n <h2\n className={`mb-2 leading-tight font-bold text-${headerColor} text-${headerSize === \"md\" ? \"base\" : headerSize}`}\n >\n {slide.title}\n </h2>\n )}\n {slide.description && (\n <div\n className={`leading-snug text-${textColor} text-${textSize === \"md\" ? \"base\" : textSize} line-clamp-2`}\n dangerouslySetInnerHTML={{\n __html: DOMPurify.sanitize(slide.description, {\n ALLOWED_TAGS: [\n \"br\",\n \"strong\",\n \"em\",\n \"b\",\n \"i\",\n \"ul\",\n \"ol\",\n \"li\",\n \"p\",\n ],\n ALLOWED_ATTR: [],\n }),\n }}\n />\n )}\n </div>\n\n {/* Button */}\n {slide.buttonText && slide.buttonEnabled && showButton && (\n <div className={`text-${align.horizontal}`}>\n <Button\n size={buttonSize}\n className={`rounded-md py-1 font-semibold bg-${buttonColor} text-${buttonColor}-foreground hover:bg-${buttonColor}/90`}\n asChild\n >\n <a href={slide.buttonLink}>{slide.buttonText}</a>\n </Button>\n </div>\n )}\n </div>\n </div>\n </div>\n ))}\n </div>\n </div>\n {/* Dots and Navigation */}\n {totalSlides > 1 && (\n <div\n className={`p-${padding} absolute bottom-0 z-10 flex w-full items-center justify-between ${align.horizontal === \"center\" ? \"h-full\" : \"\"}`}\n >\n {/* Pagination dots - always at bottom */}\n <div\n className={`flex items-center ${\n align.horizontal === \"center\"\n ? `p-${padding} absolute inset-x-0 bottom-3 justify-center`\n : \"\"\n }`}\n >\n <div\n className={`flex items-center gap-2 ${\n align.horizontal === \"center\" ? \"justify-center\" : \"\"\n }`}\n >\n {slides.map((_, index) => (\n <button\n key={`dot-${index}`}\n className={`h-[6px] w-[6px] rounded-full transition-colors ${\n index === currentIndex\n ? \"bg-background\"\n : \"bg-background/40 hover:bg-background/60\"\n }`}\n onClick={() => goToSlide(index)}\n aria-label={`Go to slide ${index + 1}`}\n aria-current={index === currentIndex ? \"true\" : \"false\"}\n />\n ))}\n </div>\n </div>\n\n {/* Navigation arrows - position changes based on alignment */}\n <div\n className={`flex items-center gap-[10px] ${\n align.horizontal === \"center\"\n ? `absolute inset-x-0 top-1/2 justify-between px-${padding}`\n : \"\"\n }`}\n >\n <ScrollArrows onPrevious={goToPrevious} onNext={goToNext} />\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const carouselWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"CarouselWidget\",\n displayName: \"Carousel\",\n tabsConfig: [\n { id: \"styling\", label: \"Styling\" },\n { id: \"behavior\", label: \"Behavior\" },\n { id: \"data\", label: \"Data\" },\n ],\n dataSourceTargetProps: [\"slides\"],\n fields: [\n // Styling tab - Text Styling group\n getFontSizeField({\n defaultValue: \"lg\",\n key: \"headerSize\",\n label: \"Header Font Size\",\n description: \"Font size for the slide header\",\n tab: \"styling\",\n group: \"Text Styling\",\n }),\n getColorField({\n defaultValue: \"background\",\n key: \"headerColor\",\n label: \"Header Color\",\n description: \"Color variant for the slide header\",\n tab: \"styling\",\n group: \"Text Styling\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Text Styling\",\n },\n getFontSizeField({\n defaultValue: \"md\",\n key: \"textSize\",\n label: \"Text Font Size\",\n description: \"Font size for the slide text\",\n tab: \"styling\",\n group: \"Text Styling\",\n }),\n getColorField({\n defaultValue: \"background\",\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Color variant for the slide text\",\n tab: \"styling\",\n group: \"Text Styling\",\n }),\n // Styling tab - Layout group\n {\n key: \"align\",\n label: \"Alignment\",\n type: \"alignment\",\n description: \"Alignment of the carousel content\",\n defaultValue: { vertical: \"bottom\", horizontal: \"left\" },\n options: {\n verticalEnabled: true,\n horizontalEnabled: true,\n },\n tab: \"styling\",\n group: \"Layout\",\n },\n {\n key: \"textWidth\",\n label: \"Content Width\",\n type: \"cssUnit\",\n description: \"Maximum width for slide content\",\n defaultValue: \"100%\",\n allowedUnits: [\"px\", \"rem\", \"%\"],\n defaultUnit: \"%\",\n minByUnit: { px: 50, rem: 3, \"%\": 10 },\n maxByUnit: { px: 1200, rem: 75, \"%\": 100 },\n stepByUnit: { px: 10, rem: 1, \"%\": 1 },\n tab: \"styling\",\n group: \"Layout\",\n },\n // Styling tab - Design group\n getHeightField({\n key: \"carouselHeight\",\n label: \"Carousel Height\",\n description: \"Height of the carousel\",\n defaultValue: \"400px\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator2\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getBorderRadiusField({\n defaultValue: \"md\",\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Rounded corners for the carousel\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getPaddingField({\n defaultValue: 4,\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding for the carousel\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"overlayEnabled\",\n label: \"Enable Overlay\",\n type: \"boolean\",\n description: \"Add background overlay to slide content\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"overlayType\",\n label: \"Overlay Type\",\n type: \"buttonGroup\",\n description: \"Type of overlay to add to the slide content\",\n defaultValue: \"gradient\",\n options: [\n { label: \"Solid\", value: \"solid\" },\n { label: \"Gradient\", value: \"gradient\" },\n ],\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"overlayEnabled\",\n },\n {\n key: \"overlayIntensity\",\n label: \"Overlay Intensity\",\n type: \"slider\",\n description: \"Opacity of the overlay background (0-100)\",\n min: 0,\n max: 100,\n step: 5,\n defaultValue: 50,\n unit: \"%\",\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"overlayEnabled\",\n },\n {\n key: \"showButton\",\n label: \"Show Button\",\n type: \"boolean\",\n description: \"Display the button in slide content\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n defaultValue: \"primary\",\n key: \"buttonColor\",\n label: \"Button Color\",\n description: \"Color variant for the slide button\",\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"showButton\",\n }),\n getButtonSizeField({\n defaultValue: \"default\",\n key: \"buttonSize\",\n label: \"Button Size\",\n description: \"Size of the slide button\",\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"showButton\",\n }),\n // Behavior tab - Auto-Scroll group\n {\n key: \"enableAutoScroll\",\n label: \"Enable Auto-Scroll\",\n type: \"boolean\",\n description: \"Automatically advance to the next slide\",\n defaultValue: false,\n tab: \"behavior\",\n group: \"Auto-Scroll\",\n },\n {\n key: \"autoScrollInterval\",\n label: \"Auto-Scroll Interval (ms)\",\n type: \"number\",\n description: \"Time in milliseconds between automatic slide transitions\",\n min: 1000,\n max: 10000,\n step: 500,\n defaultValue: 3000,\n tab: \"behavior\",\n group: \"Auto-Scroll\",\n requiresKeyToBeTrue: \"enableAutoScroll\",\n },\n // Data tab - Data Configuration group\n {\n key: \"dataSource\",\n label: \"Data Source\",\n type: \"dataSource\",\n description: \"\",\n tab: \"data\",\n group: \"Data Configuration\",\n },\n ],\n // Per-item configuration schema for custom data sources\n itemConfigSchema: {\n description: \"Configure settings for this slide\",\n fields: [\n {\n key: \"title\",\n label: \"Custom Title\",\n type: \"text\",\n description: \"Override the item's title for this slide\",\n },\n {\n key: \"description\",\n label: \"Custom Description\",\n type: \"textarea\",\n description: \"Override the item's description for this slide\",\n rows: 3,\n },\n {\n key: \"buttonEnabled\",\n label: \"Show Button\",\n type: \"boolean\",\n description: \"Show the button in the slide\",\n defaultValue: false,\n },\n {\n key: \"buttonText\",\n label: \"Button Text\",\n type: \"text\",\n description: \"Text to display on the slide button\",\n requiresKeyToBeTrue: \"buttonEnabled\",\n },\n {\n key: \"buttonLink\",\n label: \"Button Link\",\n type: \"text\",\n description: \"URL for the slide button\",\n requiresKeyToBeTrue: \"buttonEnabled\",\n },\n ],\n },\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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OAAO;IAAY,OAAO;IAAY,CACzC;GACD,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,KAAK;GACL,MAAM;GACN,cAAc;GACd,MAAM;GACN,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD,cAAc;GACZ,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;EACF,mBAAmB;GACjB,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;EAEF;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;EAED;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACR;EACF;CAED,kBAAkB;EAChB,aAAa;EACb,QAAQ;GACN;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACd;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACb,MAAM;IACP;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACb,cAAc;IACf;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACb,qBAAqB;IACtB;GACD;IACE,KAAK;IACL,OAAO;IACP,MAAM;IACN,aAAa;IACb,qBAAqB;IACtB;GACF;EACF;CACF"}
|
|
@@ -5,8 +5,7 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
5
5
|
import { useQuery } from "@tanstack/react-query";
|
|
6
6
|
import { useDataSourceConfig } from "@fluid-app/portal-core/data-sources/context";
|
|
7
7
|
import { useWidgetPreviewContext } from "@fluid-app/portal-core/data-sources/preview-context";
|
|
8
|
-
import {
|
|
9
|
-
import { faSparkles, faSpinnerThird } from "@fortawesome/pro-regular-svg-icons";
|
|
8
|
+
import { Loader2, Sparkles } from "lucide-react";
|
|
10
9
|
//#region src/hooks/use-catchups.preview.ts
|
|
11
10
|
const PREVIEW_DATA = [
|
|
12
11
|
{
|
|
@@ -95,18 +94,11 @@ function CatchUpWidget({ titleEnabled = true, titleText = "Catch Ups", titleFont
|
|
|
95
94
|
})]
|
|
96
95
|
}), isLoading ? /* @__PURE__ */ jsx("div", {
|
|
97
96
|
className: "flex min-h-[150px] flex-1 items-center justify-center",
|
|
98
|
-
children: /* @__PURE__ */ jsx(
|
|
99
|
-
icon: faSpinnerThird,
|
|
100
|
-
spin: true,
|
|
101
|
-
className: `h-8 w-8 text-${accentColor}`
|
|
102
|
-
})
|
|
97
|
+
children: /* @__PURE__ */ jsx(Loader2, { className: `h-8 w-8 animate-spin text-${accentColor}` })
|
|
103
98
|
}) : isError ? /* @__PURE__ */ jsx(ErrorState, {}) : data.length === 0 ? /* @__PURE__ */ jsxs("div", {
|
|
104
99
|
className: "flex min-h-[150px] flex-1 flex-col items-center justify-center gap-2",
|
|
105
100
|
children: [
|
|
106
|
-
/* @__PURE__ */ jsx(
|
|
107
|
-
icon: faSparkles,
|
|
108
|
-
className: `h-8 w-8 text-${accentColor}`
|
|
109
|
-
}),
|
|
101
|
+
/* @__PURE__ */ jsx(Sparkles, { className: `h-8 w-8 text-${accentColor}` }),
|
|
110
102
|
/* @__PURE__ */ jsx("p", {
|
|
111
103
|
className: "text-center font-semibold",
|
|
112
104
|
children: "You're all caught up."
|
|
@@ -244,4 +236,4 @@ const catchUpWidgetPropertySchema = {
|
|
|
244
236
|
//#endregion
|
|
245
237
|
export { CatchUpWidget_exports as n, catchUpWidgetPropertySchema as r, CatchUpWidget as t };
|
|
246
238
|
|
|
247
|
-
//# sourceMappingURL=CatchUpWidget-
|
|
239
|
+
//# sourceMappingURL=CatchUpWidget-CAmpqiDr.mjs.map
|