@fluid-app/portal-sdk 0.1.446 → 0.1.448
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-DasX2RBc.cjs → CalendarWidget-Cq2SrfVW.cjs} +5 -34
- package/dist/CalendarWidget-Cq2SrfVW.cjs.map +1 -0
- package/dist/{CalendarWidget-BvXf1NlC.mjs → CalendarWidget-DwZ5hrXx.mjs} +5 -34
- package/dist/CalendarWidget-DwZ5hrXx.mjs.map +1 -0
- package/dist/{ContactsScreen-CbWOdrpK.cjs → ContactsScreen-C1kfIxoL.cjs} +1 -1
- package/dist/{ContactsScreen-BMnHQQQj.cjs → ContactsScreen-CBXOEkvz.cjs} +78 -17
- package/dist/ContactsScreen-CBXOEkvz.cjs.map +1 -0
- package/dist/{ContactsScreen-Ds-J6GFM.mjs → ContactsScreen-DjMBu144.mjs} +73 -18
- package/dist/ContactsScreen-DjMBu144.mjs.map +1 -0
- package/dist/{FluidProvider-DRyFjZ6v.cjs → FluidProvider-BWqJxZRi.cjs} +2 -2
- package/dist/{FluidProvider-DRyFjZ6v.cjs.map → FluidProvider-BWqJxZRi.cjs.map} +1 -1
- package/dist/{FluidProvider-hztxEA9v.mjs → FluidProvider-DTLXqi_x.mjs} +2 -2
- package/dist/{FluidProvider-hztxEA9v.mjs.map → FluidProvider-DTLXqi_x.mjs.map} +1 -1
- package/dist/{MessagingScreen-DP9lhGok.mjs → MessagingScreen-CtlOt_DB.mjs} +2 -2
- package/dist/{MessagingScreen-DP9lhGok.mjs.map → MessagingScreen-CtlOt_DB.mjs.map} +1 -1
- package/dist/{MessagingScreen-DuoVdCoN.mjs → MessagingScreen-CyG6ng9Q.mjs} +4 -4
- package/dist/{MessagingScreen-BcKMkp38.cjs → MessagingScreen-ledgZoSl.cjs} +2 -2
- package/dist/{MessagingScreen-BcKMkp38.cjs.map → MessagingScreen-ledgZoSl.cjs.map} +1 -1
- package/dist/{MessagingScreen-D9lMoFHp.cjs → MessagingScreen-nkmfBY4B.cjs} +4 -4
- package/dist/{OrdersScreen-BIaS_Rs5.mjs → OrdersScreen-CBghCpGM.mjs} +2 -2
- package/dist/{OrdersScreen-BIaS_Rs5.mjs.map → OrdersScreen-CBghCpGM.mjs.map} +1 -1
- package/dist/{OrdersScreen-9LZSY0r6.cjs → OrdersScreen-Czu93Plh.cjs} +2 -2
- package/dist/{OrdersScreen-9LZSY0r6.cjs.map → OrdersScreen-Czu93Plh.cjs.map} +1 -1
- package/dist/{OrdersScreen-C1QEm5aJ.cjs → OrdersScreen-DRLiFoMp.cjs} +4 -4
- package/dist/{OrdersScreen-DaKc0IWa.mjs → OrdersScreen-_JbOhHSb.mjs} +4 -4
- package/dist/{ProfileScreen-h6QFJYjT.mjs → ProfileScreen-2-dGMH-O.mjs} +5 -5
- package/dist/{ProfileScreen-C8efV745.cjs → ProfileScreen-BkzMjtjH.cjs} +5 -5
- package/dist/{ProfileScreen-BFUMx753.mjs → ProfileScreen-C8fMDZ_0.mjs} +3 -3
- package/dist/{ProfileScreen-BFUMx753.mjs.map → ProfileScreen-C8fMDZ_0.mjs.map} +1 -1
- package/dist/{ProfileScreen-CJ02u5_k.cjs → ProfileScreen-DW45SuKT.cjs} +3 -3
- package/dist/{ProfileScreen-CJ02u5_k.cjs.map → ProfileScreen-DW45SuKT.cjs.map} +1 -1
- package/dist/{ShopScreen-BQXHwKwM.mjs → ShopScreen-CBu3-hoU.mjs} +4 -4
- package/dist/{ShopScreen-BOv02SK-.cjs → ShopScreen-D5BncoY4.cjs} +4 -4
- package/dist/{ShopScreen-IBpCfhLT.cjs → ShopScreen-DeYgHEBX.cjs} +2 -2
- package/dist/{ShopScreen-IBpCfhLT.cjs.map → ShopScreen-DeYgHEBX.cjs.map} +1 -1
- package/dist/{ShopScreen-DOXyo3Vh.mjs → ShopScreen-kcwVg8Qr.mjs} +2 -2
- package/dist/{ShopScreen-DOXyo3Vh.mjs.map → ShopScreen-kcwVg8Qr.mjs.map} +1 -1
- package/dist/{SubscriptionsScreen-B2QSvJ-w.mjs → SubscriptionsScreen-Cz9JzpFs.mjs} +5 -5
- package/dist/{SubscriptionsScreen-D_YvnfPC.cjs → SubscriptionsScreen-YWbl8qCX.cjs} +5 -5
- package/dist/{SubscriptionsScreen-D8uE5QRT.cjs → SubscriptionsScreen-g9PPMEE5.cjs} +3 -3
- package/dist/{SubscriptionsScreen-D8uE5QRT.cjs.map → SubscriptionsScreen-g9PPMEE5.cjs.map} +1 -1
- package/dist/{SubscriptionsScreen-g7WC5AfX.mjs → SubscriptionsScreen-sMa-zAsf.mjs} +3 -3
- package/dist/{SubscriptionsScreen-g7WC5AfX.mjs.map → SubscriptionsScreen-sMa-zAsf.mjs.map} +1 -1
- package/dist/{build-widget-registry-BQ1Re7ib.cjs → build-widget-registry-B2BnMQtz.cjs} +3 -3
- package/dist/{build-widget-registry-BQ1Re7ib.cjs.map → build-widget-registry-B2BnMQtz.cjs.map} +1 -1
- package/dist/{build-widget-registry-CO8Mowhe.mjs → build-widget-registry-OF4YLt6-.mjs} +3 -3
- package/dist/{build-widget-registry-CO8Mowhe.mjs.map → build-widget-registry-OF4YLt6-.mjs.map} +1 -1
- package/dist/index.cjs +184 -138
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +184 -138
- package/dist/index.mjs.map +1 -1
- package/dist/{use-portal-card-add-3ds-flow-BESpmw-C.cjs → use-portal-card-add-3ds-flow-12az3gIu.cjs} +2 -2
- package/dist/{use-portal-card-add-3ds-flow-BESpmw-C.cjs.map → use-portal-card-add-3ds-flow-12az3gIu.cjs.map} +1 -1
- package/dist/{use-portal-card-add-3ds-flow-Ddn35rRp.mjs → use-portal-card-add-3ds-flow-Bg4HGIMG.mjs} +2 -2
- package/dist/{use-portal-card-add-3ds-flow-Ddn35rRp.mjs.map → use-portal-card-add-3ds-flow-Bg4HGIMG.mjs.map} +1 -1
- package/dist/utils/build-remote-widget-plugin-manifests.cjs +2 -2
- package/dist/utils/build-remote-widget-plugin-manifests.mjs +2 -2
- package/package.json +10 -10
- package/dist/CalendarWidget-BvXf1NlC.mjs.map +0 -1
- package/dist/CalendarWidget-DasX2RBc.cjs.map +0 -1
- package/dist/ContactsScreen-BMnHQQQj.cjs.map +0 -1
- package/dist/ContactsScreen-Ds-J6GFM.mjs.map +0 -1
|
@@ -189,23 +189,6 @@ const formatLongDateTime = (iso) => {
|
|
|
189
189
|
timeZoneName: "short"
|
|
190
190
|
})}`;
|
|
191
191
|
};
|
|
192
|
-
const safeTimeZone = (tz) => {
|
|
193
|
-
if (!tz) return void 0;
|
|
194
|
-
try {
|
|
195
|
-
new Intl.DateTimeFormat(void 0, { timeZone: tz });
|
|
196
|
-
return tz;
|
|
197
|
-
} catch {
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
};
|
|
201
|
-
const formatLongDate = (iso, timeZone) => {
|
|
202
|
-
return new Date(iso).toLocaleDateString("en-US", {
|
|
203
|
-
month: "short",
|
|
204
|
-
day: "numeric",
|
|
205
|
-
year: "numeric",
|
|
206
|
-
timeZone: safeTimeZone(timeZone)
|
|
207
|
-
});
|
|
208
|
-
};
|
|
209
192
|
const isSafeHttpUrl = (url) => {
|
|
210
193
|
try {
|
|
211
194
|
const parsed = new URL(url);
|
|
@@ -241,20 +224,15 @@ function EventCard({ event, accentColor, textColor }) {
|
|
|
241
224
|
const accentVar = `var(--color-${accentColor})`;
|
|
242
225
|
const barColor = event.color || accentVar;
|
|
243
226
|
const startDate = new Date(event.start);
|
|
244
|
-
const
|
|
245
|
-
const weekday = startDate.toLocaleDateString("en-US", {
|
|
246
|
-
weekday: "short",
|
|
247
|
-
timeZone: allDayTz
|
|
248
|
-
});
|
|
227
|
+
const weekday = startDate.toLocaleDateString("en-US", { weekday: "short" });
|
|
249
228
|
const monthDay = startDate.toLocaleDateString("en-US", {
|
|
250
229
|
month: "short",
|
|
251
|
-
day: "numeric"
|
|
252
|
-
timeZone: allDayTz
|
|
230
|
+
day: "numeric"
|
|
253
231
|
});
|
|
254
232
|
const status = deriveEventStatus(event);
|
|
255
233
|
const description = event.description?.body;
|
|
256
|
-
const startDisplay =
|
|
257
|
-
const endDisplay =
|
|
234
|
+
const startDisplay = formatLongDateTime(event.start);
|
|
235
|
+
const endDisplay = formatLongDateTime(event.end);
|
|
258
236
|
const statusToneClasses = status.tone === "live" ? `bg-${accentColor}/15 text-${accentColor}` : status.tone === "upcoming" ? `bg-${accentColor}/10 text-${accentColor}` : `bg-${textColor}/10 text-${textColor}/60`;
|
|
259
237
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
|
|
260
238
|
className: `relative overflow-hidden rounded-lg border border-${textColor}/10`,
|
|
@@ -414,13 +392,6 @@ function useCalendarNavigation(setSelectedDate) {
|
|
|
414
392
|
}
|
|
415
393
|
const eventDayAnchor = (event, useEnd = false) => {
|
|
416
394
|
const iso = useEnd ? event.end : event.start;
|
|
417
|
-
if (event.isAllDay) {
|
|
418
|
-
const parts = new Date(iso).toLocaleDateString("en-CA", { timeZone: safeTimeZone(event.timeZone) }).split("-");
|
|
419
|
-
const year = Number(parts[0]);
|
|
420
|
-
const month = Number(parts[1]);
|
|
421
|
-
const day = Number(parts[2]);
|
|
422
|
-
return new Date(year, month - 1, day);
|
|
423
|
-
}
|
|
424
395
|
return startOfDay(new Date(iso));
|
|
425
396
|
};
|
|
426
397
|
function useCalendarEventIndex(events, selectedDate) {
|
|
@@ -792,4 +763,4 @@ Object.defineProperty(exports, "calendarWidgetPropertySchema", {
|
|
|
792
763
|
}
|
|
793
764
|
});
|
|
794
765
|
|
|
795
|
-
//# sourceMappingURL=CalendarWidget-
|
|
766
|
+
//# sourceMappingURL=CalendarWidget-Cq2SrfVW.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CalendarWidget-Cq2SrfVW.cjs","names":["useWidgetsApi","useWidgetPreviewContext","useDataSourceRegistryConfig","Calendar","Link2","MapPin","borderWidthClasses","borderColorClasses","ErrorState","CalendarCheck","ChevronLeft","ChevronRight","ChevronsDown","ChevronsUp","getFontSizeField","getColorField","getPaddingField","getBorderRadiusField","getBorderWidthField","getBorderColorField"],"sources":["../../widgets/src/hooks/use-calendar-events.preview.ts","../../widgets/src/hooks/use-calendar-events.ts","../../widgets/src/widgets/CalendarWidget.tsx"],"sourcesContent":["import type { CalendarEvent } from \"@fluid-app/portal-core/widgets-api-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 { useWidgetsApi } from \"@fluid-app/portal-core/widgets-api-context\";\nimport { useWidgetPreviewContext } from \"@fluid-app/portal-react/data-sources/preview-context\";\nimport { useDataSourceRegistryConfig } from \"@fluid-app/portal-react/data-sources/registry-context\";\nimport { PREVIEW_DATA } from \"./use-calendar-events.preview\";\nimport type { CalendarEvent } from \"@fluid-app/portal-core/widgets-api-types\";\n\nexport type { CalendarEvent } from \"@fluid-app/portal-core/widgets-api-types\";\n\nexport function useCalendarEvents(): UseQueryResult<CalendarEvent[], Error> {\n const widgetsApi = useWidgetsApi();\n const { isPreview } = useWidgetPreviewContext();\n const { baseUrl } = useDataSourceRegistryConfig();\n\n return useQuery({\n queryKey: [\n \"portal-widget-use\",\n \"calendar-events\",\n isPreview ? \"preview\" : baseUrl,\n ] as const,\n queryFn: ({ signal }) => widgetsApi.fetchCalendarEvents(signal),\n enabled: !isPreview,\n ...(isPreview && { placeholderData: PREVIEW_DATA }),\n });\n}\n","import {\n useState,\n useMemo,\n useCallback,\n useRef,\n useEffect,\n type ComponentProps,\n} from \"react\";\nimport type React from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport {\n borderColorClasses,\n borderWidthClasses,\n getBorderColorField,\n getBorderRadiusField,\n getBorderWidthField,\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 Calendar,\n CalendarCheck,\n ChevronLeft,\n ChevronRight,\n ChevronsDown,\n ChevronsUp,\n Link2,\n MapPin,\n type LucideIcon,\n} from \"lucide-react\";\n\nconst DAY_NAMES = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"] as const;\n\nconst getDaysInMonth = (year: number, month: number): number =>\n new Date(year, month + 1, 0).getDate();\n\nconst getFirstDayOfMonth = (year: number, month: number): number =>\n new Date(year, month, 1).getDay();\n\nconst isSameDay = (a: Date, b: Date): boolean =>\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate();\n\nconst startOfDay = (d: Date): Date => {\n const x = new Date(d);\n x.setHours(0, 0, 0, 0);\n return x;\n};\n\nconst addDays = (d: Date, n: number): Date => {\n const x = new Date(d);\n x.setDate(x.getDate() + n);\n return x;\n};\n\nconst diffDays = (a: Date, b: Date): number => {\n const ms = startOfDay(a).getTime() - startOfDay(b).getTime();\n return Math.round(ms / 86400000);\n};\n\ntype DayCell = {\n date: Date | null;\n isToday: boolean;\n isCurrentMonth: boolean;\n};\n\nconst generateMonthGrid = (year: number, month: number): DayCell[] => {\n const daysInMonth = getDaysInMonth(year, month);\n const firstDay = getFirstDayOfMonth(year, month);\n const today = new Date();\n const cells: DayCell[] = [];\n\n for (let i = 0; i < firstDay; i++) {\n cells.push({ date: null, isToday: false, isCurrentMonth: false });\n }\n\n for (let day = 1; day <= daysInMonth; day++) {\n const date = new Date(year, month, day);\n cells.push({\n date,\n isToday: isSameDay(date, today),\n isCurrentMonth: true,\n });\n }\n\n return cells;\n};\n\nconst generateWeekGrid = (): Array<{ date: Date; isToday: boolean }> => {\n const today = new Date();\n const weekday = today.getDay();\n return Array.from({ length: 7 }, (_, i) => {\n const date = addDays(today, -weekday + i);\n return { date, isToday: isSameDay(date, today) };\n });\n};\n\nconst formatContextualDate = (\n date: Date,\n): { lead: string | null; detail: string } => {\n const today = new Date();\n const d = diffDays(date, today);\n const weekday = date.toLocaleDateString(\"en-US\", { weekday: \"short\" });\n const monthDay = date.toLocaleDateString(\"en-US\", {\n month: \"short\",\n day: \"numeric\",\n });\n if (d === 0) return { lead: \"Today\", detail: `${weekday}, ${monthDay}` };\n if (d === 1) return { lead: \"Tomorrow\", detail: `${weekday}, ${monthDay}` };\n if (d === -1) return { lead: \"Yesterday\", detail: `${weekday}, ${monthDay}` };\n return { lead: null, detail: `${weekday}, ${monthDay}` };\n};\n\ntype DayCellButtonProps = {\n date: Date;\n isToday: boolean;\n isSelected: boolean;\n eventCount: number;\n accentColor: ColorOptions;\n textColor: ColorOptions;\n showEventDensity: boolean;\n onClick: () => void;\n};\n\nfunction DayCellButton({\n date,\n isToday,\n isSelected,\n eventCount,\n accentColor,\n textColor,\n showEventDensity,\n onClick,\n}: DayCellButtonProps) {\n const dotCount = showEventDensity\n ? Math.min(eventCount, 3)\n : eventCount > 0\n ? 1\n : 0;\n\n const baseClasses =\n \"group relative flex aspect-square w-full flex-col items-center justify-center rounded-lg text-sm tabular-nums transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-0\";\n\n const stateClasses = isSelected\n ? `bg-${accentColor} text-${accentColor}-foreground focus-visible:ring-${accentColor}/40`\n : isToday\n ? `bg-${accentColor}/10 text-${accentColor} font-semibold hover:bg-${accentColor}/20 focus-visible:ring-${accentColor}/40`\n : `text-${textColor} hover:bg-${accentColor}/10 focus-visible:ring-${accentColor}/40`;\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label={date.toLocaleDateString(\"en-US\", {\n weekday: \"long\",\n month: \"long\",\n day: \"numeric\",\n })}\n aria-current={isToday ? \"date\" : undefined}\n aria-pressed={isSelected}\n className={`${baseClasses} ${stateClasses}`}\n >\n <span className=\"leading-none\">{date.getDate()}</span>\n {dotCount > 0 && (\n <span\n aria-hidden=\"true\"\n className=\"absolute bottom-0.5 flex items-center gap-[2px]\"\n >\n {Array.from({ length: dotCount }).map((_, i) => (\n <span\n key={i}\n className={`size-1 rounded-full ${\n isSelected\n ? `bg-${accentColor}-foreground/70`\n : `bg-${accentColor}`\n }`}\n />\n ))}\n </span>\n )}\n </button>\n );\n}\n\ntype EventCardProps = {\n event: CalendarEvent;\n accentColor: ColorOptions;\n textColor: ColorOptions;\n};\n\n// Events render in the viewer's own timezone (browser local) so the same time\n// reads consistently on Portal and mobile. timeZoneName \"short\" appends the\n// viewer's zone abbreviation (e.g. MST).\nconst formatLongDateTime = (iso: string): string => {\n const d = new Date(iso);\n const datePart = d.toLocaleDateString(\"en-US\", {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n });\n const timePart = d.toLocaleTimeString(\"en-US\", {\n hour: \"numeric\",\n minute: \"2-digit\",\n timeZoneName: \"short\",\n });\n return `${datePart} at ${timePart}`;\n};\n\nconst isSafeHttpUrl = (url: string): boolean => {\n try {\n const parsed = new URL(url);\n return parsed.protocol === \"http:\" || parsed.protocol === \"https:\";\n } catch {\n return false;\n }\n};\n\nconst deriveEventStatus = (\n event: CalendarEvent,\n): { label: string; tone: \"upcoming\" | \"live\" | \"past\" } => {\n const rawStatus = event.status?.trim();\n const normalized = rawStatus?.toLowerCase();\n if (rawStatus && normalized !== \"active\" && normalized !== \"confirmed\") {\n const label =\n rawStatus.charAt(0).toUpperCase() + rawStatus.slice(1).toLowerCase();\n return { label, tone: \"past\" };\n }\n const startMs = new Date(event.start).getTime();\n const endMs = new Date(event.end).getTime();\n const now = Date.now();\n if (now < startMs) return { label: \"Upcoming\", tone: \"upcoming\" };\n if (now <= endMs) return { label: \"Live\", tone: \"live\" };\n return { label: \"Past\", tone: \"past\" };\n};\n\nfunction EventCard({ event, accentColor, textColor }: EventCardProps) {\n const accentVar = `var(--color-${accentColor})`;\n const barColor = event.color || accentVar;\n const startDate = new Date(event.start);\n // All events, all-day included, render in the viewer's own timezone, so the\n // badge, start/end, and calendar cell agree with each other and with mobile.\n const weekday = startDate.toLocaleDateString(\"en-US\", {\n weekday: \"short\",\n });\n const monthDay = startDate.toLocaleDateString(\"en-US\", {\n month: \"short\",\n day: \"numeric\",\n });\n const status = deriveEventStatus(event);\n const description = event.description?.body;\n\n const startDisplay = formatLongDateTime(event.start);\n const endDisplay = formatLongDateTime(event.end);\n\n const statusToneClasses =\n status.tone === \"live\"\n ? `bg-${accentColor}/15 text-${accentColor}`\n : status.tone === \"upcoming\"\n ? `bg-${accentColor}/10 text-${accentColor}`\n : `bg-${textColor}/10 text-${textColor}/60`;\n\n return (\n <article\n className={`relative overflow-hidden rounded-lg border border-${textColor}/10`}\n >\n <span\n aria-hidden=\"true\"\n className=\"absolute inset-y-0 left-0 w-[3px]\"\n style={{ backgroundColor: barColor }}\n />\n\n {event.imageUrl && (\n <img\n src={event.imageUrl}\n alt=\"\"\n className=\"aspect-[16/7] w-full object-cover\"\n />\n )}\n\n <div className=\"flex flex-col gap-4 p-4 pl-5\">\n <div className=\"flex items-start gap-4\">\n <div\n className={`shrink-0 text-${textColor} leading-tight tabular-nums`}\n >\n <div className={`text-xs font-semibold text-${textColor}/55`}>\n {weekday}\n </div>\n <div className=\"text-2xl font-bold tracking-[-0.015em]\">\n {monthDay}\n </div>\n </div>\n\n <div className=\"min-w-0 flex-1\">\n <h4\n className={`text-base font-bold text-${textColor} leading-tight tracking-[-0.01em]`}\n >\n {event.title}\n </h4>\n {description && (\n <p\n className={`mt-1 text-sm leading-snug whitespace-pre-wrap text-${textColor}/65`}\n >\n {description}\n </p>\n )}\n </div>\n </div>\n\n <div className=\"flex flex-col gap-2.5\">\n <div className=\"flex items-start gap-2\">\n <Calendar\n className={`mt-0.5 size-4 shrink-0 text-${textColor}/55`}\n />\n <div\n className={`text-sm leading-snug text-${textColor}/80 tabular-nums`}\n >\n <div>\n <span className=\"font-semibold\">Start</span> {startDisplay}\n </div>\n <div>\n <span className=\"font-semibold\">End</span> {endDisplay}\n </div>\n </div>\n </div>\n\n <div>\n <span\n className={`inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-semibold ${statusToneClasses}`}\n >\n {status.label}\n </span>\n </div>\n\n {event.url && isSafeHttpUrl(event.url) && (\n <a\n href={event.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={`flex items-center gap-2 text-sm text-${accentColor} break-all hover:underline`}\n >\n <Link2 className={`size-4 shrink-0 text-${textColor}/55`} />\n <span>{event.url}</span>\n </a>\n )}\n\n {event.venue && (\n <a\n href={`https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(event.venue)}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={`flex items-start gap-2 text-sm text-${accentColor} hover:underline`}\n >\n <MapPin\n className={`mt-0.5 size-4 shrink-0 text-${textColor}/55`}\n />\n <span>{event.venue}</span>\n </a>\n )}\n </div>\n </div>\n </article>\n );\n}\n\ntype NavButtonProps = {\n icon: LucideIcon;\n label: string;\n variant: \"ghost\" | \"accent\";\n accentColor: ColorOptions;\n textColor: ColorOptions;\n onClick: () => void;\n};\n\nfunction NavButton({\n icon: Icon,\n label,\n variant,\n accentColor,\n textColor,\n onClick,\n}: NavButtonProps) {\n const classes =\n variant === \"accent\"\n ? `bg-${accentColor} text-${accentColor}-foreground hover:bg-${accentColor}/90 focus-visible:ring-${accentColor}/40`\n : `bg-${textColor}/5 text-${textColor} hover:bg-${textColor}/10 focus-visible:ring-${textColor}/20`;\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label={label}\n className={`flex size-8 items-center justify-center rounded-full text-[12px] transition-colors focus:outline-none focus-visible:ring-2 ${classes}`}\n >\n <Icon className=\"size-4\" />\n </button>\n );\n}\n\ntype CalendarView = {\n month: number;\n year: number;\n};\n\nconst getInitialCalendarView = (): CalendarView => {\n const now = new Date();\n return { month: now.getMonth(), year: now.getFullYear() };\n};\n\nfunction useCalendarNavigation(\n setSelectedDate: React.Dispatch<React.SetStateAction<Date | null>>,\n) {\n const [view, setView] = useState(getInitialCalendarView);\n const [gridTransitioning, setGridTransitioning] = useState(false);\n const transitionTimeoutRef = useRef<number | null>(null);\n\n useEffect(\n () => () => {\n if (transitionTimeoutRef.current !== null) {\n window.clearTimeout(transitionTimeoutRef.current);\n }\n },\n [],\n );\n\n const clearPendingTransition = useCallback(() => {\n if (transitionTimeoutRef.current !== null) {\n window.clearTimeout(transitionTimeoutRef.current);\n transitionTimeoutRef.current = null;\n }\n }, []);\n\n const navigate = useCallback(\n (direction: -1 | 1) => {\n clearPendingTransition();\n setGridTransitioning(true);\n transitionTimeoutRef.current = window.setTimeout(() => {\n setView((prev) => {\n const next = prev.month + direction;\n if (next < 0) return { month: 11, year: prev.year - 1 };\n if (next > 11) return { month: 0, year: prev.year + 1 };\n return { month: next, year: prev.year };\n });\n setGridTransitioning(false);\n transitionTimeoutRef.current = null;\n }, 120);\n },\n [clearPendingTransition],\n );\n\n const goToToday = useCallback(() => {\n clearPendingTransition();\n const now = new Date();\n setGridTransitioning(true);\n transitionTimeoutRef.current = window.setTimeout(() => {\n setView({ month: now.getMonth(), year: now.getFullYear() });\n setSelectedDate(now);\n setGridTransitioning(false);\n transitionTimeoutRef.current = null;\n }, 80);\n }, [clearPendingTransition, setSelectedDate]);\n\n return { view, gridTransitioning, navigate, goToToday };\n}\n\n// The local Date whose calendar day equals the event's day in the viewer's own\n// timezone, so the dot sits on the same day the card shows it starting. Builder,\n// preview, and live portal agree because all read the same start/end instant,\n// whichever adapter fetched it.\nconst eventDayAnchor = (event: CalendarEvent, useEnd = false): Date => {\n const iso = useEnd ? event.end : event.start;\n return startOfDay(new Date(iso));\n};\n\nfunction useCalendarEventIndex(\n events: CalendarEvent[],\n selectedDate: Date | null,\n) {\n const eventsByDate = useMemo(() => {\n const map = new Map<string, CalendarEvent[]>();\n for (const event of events) {\n const start = eventDayAnchor(event);\n const end = eventDayAnchor(event, true);\n for (let cur = start; cur <= end; cur = addDays(cur, 1)) {\n const key = `${cur.getFullYear()}-${cur.getMonth()}-${cur.getDate()}`;\n const list = map.get(key);\n if (list) {\n list.push(event);\n } else {\n map.set(key, [event]);\n }\n }\n }\n return map;\n }, [events]);\n\n const lookupEventsForDate = useCallback(\n (date: Date): CalendarEvent[] => {\n const key = `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;\n return eventsByDate.get(key) ?? [];\n },\n [eventsByDate],\n );\n\n const selectedDateEvents = useMemo(() => {\n if (!selectedDate) return [];\n return lookupEventsForDate(selectedDate);\n }, [selectedDate, lookupEventsForDate]);\n\n return { lookupEventsForDate, selectedDateEvents };\n}\n\ntype CalendarWidgetProps = ComponentProps<\"div\"> & {\n // Title\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n // Styling\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n\n // Premium polish (new, additive)\n showEventDensity?: boolean;\n showTodayButton?: boolean;\n weekendDim?: boolean;\n showYearEyebrow?: boolean;\n};\n\nexport function CalendarWidget({\n titleEnabled = true,\n titleText = \"Calendar\",\n titleFontSize = \"xl\",\n titleColor = \"foreground\",\n\n background = { type: \"solid\", color: \"background\" },\n textColor = \"foreground\",\n accentColor = \"primary\",\n padding = 4,\n borderRadius = \"md\",\n borderWidth = \"none\",\n borderColor = \"muted\",\n\n showEventDensity = true,\n showTodayButton = true,\n weekendDim = true,\n showYearEyebrow = true,\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\n const [isCollapsed, setIsCollapsed] = useState(false);\n const [selectedDate, setSelectedDate] = useState<Date | null>(\n () => new Date(),\n );\n const { view, gridTransitioning, navigate, goToToday } =\n useCalendarNavigation(setSelectedDate);\n const currentMonth = view.month;\n const currentYear = view.year;\n\n const { data: events = [], isLoading, isError } = useCalendarEvents();\n\n const monthGrid = useMemo(\n () => generateMonthGrid(currentYear, currentMonth),\n [currentYear, currentMonth],\n );\n const weekGrid = generateWeekGrid();\n const { lookupEventsForDate, selectedDateEvents } = useCalendarEventIndex(\n events,\n selectedDate,\n );\n\n const now = new Date();\n const viewingCurrentMonth =\n currentMonth === now.getMonth() && currentYear === now.getFullYear();\n\n const monthLabel = new Date(currentYear, currentMonth).toLocaleString(\n \"en-US\",\n { month: \"long\" },\n );\n const yearLabel = String(currentYear);\n\n const contextualDate = selectedDate\n ? formatContextualDate(selectedDate)\n : null;\n\n return (\n <div\n className={`@container overflow-hidden rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} bg-${backgroundColor} text-${textColor} ${className ?? \"\"}`}\n style={{ backgroundImage }}\n {...props}\n >\n {titleEnabled && titleText && (\n <div className={`p-${padding} pb-0`}>\n <h2\n className={`text-${titleFontSize} text-${titleColor} font-bold tracking-[-0.012em]`}\n >\n {titleText}\n </h2>\n </div>\n )}\n\n {isLoading ? (\n <div\n className={`flex min-h-[300px] items-center justify-center p-${padding}`}\n >\n <div className={`text-${accentColor}`}>\n <div className=\"size-8 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n </div>\n </div>\n ) : isError ? (\n <ErrorState />\n ) : (\n <div className={`p-${padding}`}>\n <div className=\"@md:flex @md:gap-6\">\n <div className=\"@md:flex-none\">\n {/* Header row: year eyebrow + month + asymmetric nav + Today pill */}\n <div className=\"mb-4 flex items-start justify-between gap-3\">\n <div className=\"flex min-w-0 flex-col\">\n {showYearEyebrow && (\n <span\n className={`text-[10px] font-bold tracking-[0.16em] uppercase text-${textColor}/55`}\n >\n {yearLabel}\n </span>\n )}\n <span\n className={`text-xl leading-tight font-bold tracking-[-0.015em] text-${textColor}`}\n >\n {monthLabel}\n </span>\n </div>\n\n <div className=\"flex shrink-0 items-center gap-1.5\">\n {showTodayButton && !viewingCurrentMonth && (\n <button\n type=\"button\"\n onClick={goToToday}\n className={`flex items-center gap-1 rounded-full bg-${accentColor}/10 px-2.5 py-1 text-[11px] font-semibold text-${accentColor} transition-colors hover:bg-${accentColor}/20 focus:outline-none focus-visible:ring-2 focus-visible:ring-${accentColor}/40`}\n >\n <CalendarCheck className=\"size-3\" />\n Today\n </button>\n )}\n <NavButton\n icon={ChevronLeft}\n label=\"Previous month\"\n variant=\"ghost\"\n accentColor={accentColor}\n textColor={textColor}\n onClick={() => navigate(-1)}\n />\n <NavButton\n icon={ChevronRight}\n label=\"Next month\"\n variant=\"accent\"\n accentColor={accentColor}\n textColor={textColor}\n onClick={() => navigate(1)}\n />\n </div>\n </div>\n\n {/* Day-of-week headers */}\n <div className=\"mb-2 grid grid-cols-7 gap-1 text-center\">\n {DAY_NAMES.map((day, idx) => {\n const isWeekend = idx === 0 || idx === 6;\n const dimmed = weekendDim && isWeekend;\n return (\n <div\n key={day}\n className={`text-[10px] font-semibold tracking-[0.12em] uppercase text-${textColor}/${dimmed ? \"40\" : \"55\"}`}\n >\n {day}\n </div>\n );\n })}\n </div>\n\n {/* Grid wrapper (opacity transitions on month navigate) */}\n <div\n className=\"transition-opacity duration-150 ease-out\"\n style={{ opacity: gridTransitioning ? 0.3 : 1 }}\n >\n {/* Collapsed week view on mobile */}\n {isCollapsed && (\n <div className=\"grid grid-cols-7 gap-1 @md:hidden\">\n {weekGrid.map(({ date, isToday }) => (\n <DayCellButton\n key={date.toISOString()}\n date={date}\n isToday={isToday}\n isSelected={\n !!selectedDate && isSameDay(selectedDate, date)\n }\n eventCount={lookupEventsForDate(date).length}\n accentColor={accentColor}\n textColor={textColor}\n showEventDensity={showEventDensity}\n onClick={() => setSelectedDate(date)}\n />\n ))}\n </div>\n )}\n\n {/* Month grid */}\n <div\n className={`grid grid-cols-7 gap-1 ${isCollapsed ? \"hidden @md:grid\" : \"grid\"}`}\n >\n {monthGrid.map((cell, idx) => {\n if (!cell.date) {\n return (\n <div key={`empty-${idx}`} className=\"aspect-square\" />\n );\n }\n const eventCount = lookupEventsForDate(cell.date).length;\n return (\n <DayCellButton\n key={cell.date.toISOString()}\n date={cell.date}\n isToday={cell.isToday}\n isSelected={\n !!selectedDate && isSameDay(selectedDate, cell.date)\n }\n eventCount={eventCount}\n accentColor={accentColor}\n textColor={textColor}\n showEventDensity={showEventDensity}\n onClick={() => setSelectedDate(cell.date)}\n />\n );\n })}\n </div>\n </div>\n\n {/* Mobile collapse toggle */}\n <button\n type=\"button\"\n onClick={() => setIsCollapsed(!isCollapsed)}\n className={`mt-2 flex w-full items-center justify-center gap-3 rounded-full p-1 text-${textColor}/40 transition-colors hover:text-${textColor}/60 @md:hidden`}\n aria-label={\n isCollapsed ? \"Expand calendar\" : \"Collapse calendar\"\n }\n >\n <div className={`h-px w-1/2 bg-${textColor}/20`} />\n {isCollapsed ? (\n <ChevronsDown className=\"size-3\" />\n ) : (\n <ChevronsUp className=\"size-3\" />\n )}\n <div className={`h-px w-1/2 bg-${textColor}/20`} />\n </button>\n </div>\n\n {/* Events rail */}\n <div\n className={`mt-4 min-w-0 border-${textColor}/10 @md:relative @md:mt-0 @md:flex-1 @md:border-l`}\n >\n <div className=\"@md:absolute @md:inset-0 @md:overflow-y-auto @md:pr-1 @md:pl-6\">\n {/* Context header */}\n {contextualDate && (\n <div className=\"mb-3\">\n {contextualDate.lead && (\n <div\n className={`text-[10px] font-bold tracking-[0.16em] uppercase text-${accentColor}`}\n >\n {contextualDate.lead}\n </div>\n )}\n <div\n className={`text-sm font-semibold text-${textColor} tabular-nums`}\n >\n {contextualDate.detail}\n </div>\n </div>\n )}\n\n {/* Events list with soft fade-in keyed by selected date */}\n <div\n key={selectedDate?.toISOString() ?? \"none\"}\n className=\"animate-in fade-in slide-in-from-bottom-2 flex flex-col gap-3 duration-200 ease-out\"\n >\n {selectedDateEvents.length > 0 ? (\n selectedDateEvents.map((event, idx) => (\n <EventCard\n key={`${event.id}-${idx}`}\n event={event}\n accentColor={accentColor}\n textColor={textColor}\n />\n ))\n ) : (\n <div\n className={`flex flex-col items-start gap-1 rounded-md border border-dashed border-${textColor}/15 px-3 py-3`}\n >\n <div className=\"flex items-center gap-1.5\">\n <CalendarCheck\n className={`size-3 text-${textColor}/40`}\n />\n <span\n className={`text-[11px] font-semibold text-${textColor}/60`}\n >\n Nothing scheduled\n </span>\n </div>\n <span className={`text-[11px] text-${textColor}/45`}>\n Enjoy the breather.\n </span>\n </div>\n )}\n </div>\n </div>\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 // 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 // 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:\n \"Drives today highlight, event dots, Today pill, and selected day\",\n defaultValue: \"primary\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the calendar container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the calendar container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the calendar container\",\n defaultValue: \"none\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the calendar container\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n\n // Polish group (new)\n {\n key: \"showYearEyebrow\",\n label: \"Year Eyebrow\",\n type: \"boolean\",\n description:\n \"Small uppercase year label above the month (e.g. '2026 / November').\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Polish\",\n },\n {\n key: \"showTodayButton\",\n label: \"Today Button\",\n type: \"boolean\",\n description: \"Show a 'Today' pill when viewing a different month.\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Polish\",\n },\n {\n key: \"showEventDensity\",\n label: \"Event Density Dots\",\n type: \"boolean\",\n description:\n \"Show 1–3 dots per day based on event count (off = single dot).\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Polish\",\n },\n {\n key: \"weekendDim\",\n label: \"Dim Weekends\",\n type: \"boolean\",\n description:\n \"Subtly dim the Sun/Sat day-of-week headers for visual rhythm.\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Polish\",\n },\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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CL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACFC,mBAAAA,qBAAqB;GACnB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACFC,mBAAAA,oBAAoB;GAClB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACFC,mBAAAA,oBAAoB;GAClB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EAGF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aACE;GACF,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aACE;GACF,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aACE;GACF,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACF;CACF"}
|
|
@@ -189,23 +189,6 @@ const formatLongDateTime = (iso) => {
|
|
|
189
189
|
timeZoneName: "short"
|
|
190
190
|
})}`;
|
|
191
191
|
};
|
|
192
|
-
const safeTimeZone = (tz) => {
|
|
193
|
-
if (!tz) return void 0;
|
|
194
|
-
try {
|
|
195
|
-
new Intl.DateTimeFormat(void 0, { timeZone: tz });
|
|
196
|
-
return tz;
|
|
197
|
-
} catch {
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
};
|
|
201
|
-
const formatLongDate = (iso, timeZone) => {
|
|
202
|
-
return new Date(iso).toLocaleDateString("en-US", {
|
|
203
|
-
month: "short",
|
|
204
|
-
day: "numeric",
|
|
205
|
-
year: "numeric",
|
|
206
|
-
timeZone: safeTimeZone(timeZone)
|
|
207
|
-
});
|
|
208
|
-
};
|
|
209
192
|
const isSafeHttpUrl = (url) => {
|
|
210
193
|
try {
|
|
211
194
|
const parsed = new URL(url);
|
|
@@ -241,20 +224,15 @@ function EventCard({ event, accentColor, textColor }) {
|
|
|
241
224
|
const accentVar = `var(--color-${accentColor})`;
|
|
242
225
|
const barColor = event.color || accentVar;
|
|
243
226
|
const startDate = new Date(event.start);
|
|
244
|
-
const
|
|
245
|
-
const weekday = startDate.toLocaleDateString("en-US", {
|
|
246
|
-
weekday: "short",
|
|
247
|
-
timeZone: allDayTz
|
|
248
|
-
});
|
|
227
|
+
const weekday = startDate.toLocaleDateString("en-US", { weekday: "short" });
|
|
249
228
|
const monthDay = startDate.toLocaleDateString("en-US", {
|
|
250
229
|
month: "short",
|
|
251
|
-
day: "numeric"
|
|
252
|
-
timeZone: allDayTz
|
|
230
|
+
day: "numeric"
|
|
253
231
|
});
|
|
254
232
|
const status = deriveEventStatus(event);
|
|
255
233
|
const description = event.description?.body;
|
|
256
|
-
const startDisplay =
|
|
257
|
-
const endDisplay =
|
|
234
|
+
const startDisplay = formatLongDateTime(event.start);
|
|
235
|
+
const endDisplay = formatLongDateTime(event.end);
|
|
258
236
|
const statusToneClasses = status.tone === "live" ? `bg-${accentColor}/15 text-${accentColor}` : status.tone === "upcoming" ? `bg-${accentColor}/10 text-${accentColor}` : `bg-${textColor}/10 text-${textColor}/60`;
|
|
259
237
|
return /* @__PURE__ */ jsxs("article", {
|
|
260
238
|
className: `relative overflow-hidden rounded-lg border border-${textColor}/10`,
|
|
@@ -414,13 +392,6 @@ function useCalendarNavigation(setSelectedDate) {
|
|
|
414
392
|
}
|
|
415
393
|
const eventDayAnchor = (event, useEnd = false) => {
|
|
416
394
|
const iso = useEnd ? event.end : event.start;
|
|
417
|
-
if (event.isAllDay) {
|
|
418
|
-
const parts = new Date(iso).toLocaleDateString("en-CA", { timeZone: safeTimeZone(event.timeZone) }).split("-");
|
|
419
|
-
const year = Number(parts[0]);
|
|
420
|
-
const month = Number(parts[1]);
|
|
421
|
-
const day = Number(parts[2]);
|
|
422
|
-
return new Date(year, month - 1, day);
|
|
423
|
-
}
|
|
424
395
|
return startOfDay(new Date(iso));
|
|
425
396
|
};
|
|
426
397
|
function useCalendarEventIndex(events, selectedDate) {
|
|
@@ -775,4 +746,4 @@ const calendarWidgetPropertySchema = {
|
|
|
775
746
|
//#endregion
|
|
776
747
|
export { CalendarWidget_exports as n, calendarWidgetPropertySchema as r, CalendarWidget as t };
|
|
777
748
|
|
|
778
|
-
//# sourceMappingURL=CalendarWidget-
|
|
749
|
+
//# sourceMappingURL=CalendarWidget-DwZ5hrXx.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CalendarWidget-DwZ5hrXx.mjs","names":[],"sources":["../../widgets/src/hooks/use-calendar-events.preview.ts","../../widgets/src/hooks/use-calendar-events.ts","../../widgets/src/widgets/CalendarWidget.tsx"],"sourcesContent":["import type { CalendarEvent } from \"@fluid-app/portal-core/widgets-api-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 { useWidgetsApi } from \"@fluid-app/portal-core/widgets-api-context\";\nimport { useWidgetPreviewContext } from \"@fluid-app/portal-react/data-sources/preview-context\";\nimport { useDataSourceRegistryConfig } from \"@fluid-app/portal-react/data-sources/registry-context\";\nimport { PREVIEW_DATA } from \"./use-calendar-events.preview\";\nimport type { CalendarEvent } from \"@fluid-app/portal-core/widgets-api-types\";\n\nexport type { CalendarEvent } from \"@fluid-app/portal-core/widgets-api-types\";\n\nexport function useCalendarEvents(): UseQueryResult<CalendarEvent[], Error> {\n const widgetsApi = useWidgetsApi();\n const { isPreview } = useWidgetPreviewContext();\n const { baseUrl } = useDataSourceRegistryConfig();\n\n return useQuery({\n queryKey: [\n \"portal-widget-use\",\n \"calendar-events\",\n isPreview ? \"preview\" : baseUrl,\n ] as const,\n queryFn: ({ signal }) => widgetsApi.fetchCalendarEvents(signal),\n enabled: !isPreview,\n ...(isPreview && { placeholderData: PREVIEW_DATA }),\n });\n}\n","import {\n useState,\n useMemo,\n useCallback,\n useRef,\n useEffect,\n type ComponentProps,\n} from \"react\";\nimport type React from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/portal-core/registries\";\nimport {\n borderColorClasses,\n borderWidthClasses,\n getBorderColorField,\n getBorderRadiusField,\n getBorderWidthField,\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 Calendar,\n CalendarCheck,\n ChevronLeft,\n ChevronRight,\n ChevronsDown,\n ChevronsUp,\n Link2,\n MapPin,\n type LucideIcon,\n} from \"lucide-react\";\n\nconst DAY_NAMES = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"] as const;\n\nconst getDaysInMonth = (year: number, month: number): number =>\n new Date(year, month + 1, 0).getDate();\n\nconst getFirstDayOfMonth = (year: number, month: number): number =>\n new Date(year, month, 1).getDay();\n\nconst isSameDay = (a: Date, b: Date): boolean =>\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate();\n\nconst startOfDay = (d: Date): Date => {\n const x = new Date(d);\n x.setHours(0, 0, 0, 0);\n return x;\n};\n\nconst addDays = (d: Date, n: number): Date => {\n const x = new Date(d);\n x.setDate(x.getDate() + n);\n return x;\n};\n\nconst diffDays = (a: Date, b: Date): number => {\n const ms = startOfDay(a).getTime() - startOfDay(b).getTime();\n return Math.round(ms / 86400000);\n};\n\ntype DayCell = {\n date: Date | null;\n isToday: boolean;\n isCurrentMonth: boolean;\n};\n\nconst generateMonthGrid = (year: number, month: number): DayCell[] => {\n const daysInMonth = getDaysInMonth(year, month);\n const firstDay = getFirstDayOfMonth(year, month);\n const today = new Date();\n const cells: DayCell[] = [];\n\n for (let i = 0; i < firstDay; i++) {\n cells.push({ date: null, isToday: false, isCurrentMonth: false });\n }\n\n for (let day = 1; day <= daysInMonth; day++) {\n const date = new Date(year, month, day);\n cells.push({\n date,\n isToday: isSameDay(date, today),\n isCurrentMonth: true,\n });\n }\n\n return cells;\n};\n\nconst generateWeekGrid = (): Array<{ date: Date; isToday: boolean }> => {\n const today = new Date();\n const weekday = today.getDay();\n return Array.from({ length: 7 }, (_, i) => {\n const date = addDays(today, -weekday + i);\n return { date, isToday: isSameDay(date, today) };\n });\n};\n\nconst formatContextualDate = (\n date: Date,\n): { lead: string | null; detail: string } => {\n const today = new Date();\n const d = diffDays(date, today);\n const weekday = date.toLocaleDateString(\"en-US\", { weekday: \"short\" });\n const monthDay = date.toLocaleDateString(\"en-US\", {\n month: \"short\",\n day: \"numeric\",\n });\n if (d === 0) return { lead: \"Today\", detail: `${weekday}, ${monthDay}` };\n if (d === 1) return { lead: \"Tomorrow\", detail: `${weekday}, ${monthDay}` };\n if (d === -1) return { lead: \"Yesterday\", detail: `${weekday}, ${monthDay}` };\n return { lead: null, detail: `${weekday}, ${monthDay}` };\n};\n\ntype DayCellButtonProps = {\n date: Date;\n isToday: boolean;\n isSelected: boolean;\n eventCount: number;\n accentColor: ColorOptions;\n textColor: ColorOptions;\n showEventDensity: boolean;\n onClick: () => void;\n};\n\nfunction DayCellButton({\n date,\n isToday,\n isSelected,\n eventCount,\n accentColor,\n textColor,\n showEventDensity,\n onClick,\n}: DayCellButtonProps) {\n const dotCount = showEventDensity\n ? Math.min(eventCount, 3)\n : eventCount > 0\n ? 1\n : 0;\n\n const baseClasses =\n \"group relative flex aspect-square w-full flex-col items-center justify-center rounded-lg text-sm tabular-nums transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-0\";\n\n const stateClasses = isSelected\n ? `bg-${accentColor} text-${accentColor}-foreground focus-visible:ring-${accentColor}/40`\n : isToday\n ? `bg-${accentColor}/10 text-${accentColor} font-semibold hover:bg-${accentColor}/20 focus-visible:ring-${accentColor}/40`\n : `text-${textColor} hover:bg-${accentColor}/10 focus-visible:ring-${accentColor}/40`;\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label={date.toLocaleDateString(\"en-US\", {\n weekday: \"long\",\n month: \"long\",\n day: \"numeric\",\n })}\n aria-current={isToday ? \"date\" : undefined}\n aria-pressed={isSelected}\n className={`${baseClasses} ${stateClasses}`}\n >\n <span className=\"leading-none\">{date.getDate()}</span>\n {dotCount > 0 && (\n <span\n aria-hidden=\"true\"\n className=\"absolute bottom-0.5 flex items-center gap-[2px]\"\n >\n {Array.from({ length: dotCount }).map((_, i) => (\n <span\n key={i}\n className={`size-1 rounded-full ${\n isSelected\n ? `bg-${accentColor}-foreground/70`\n : `bg-${accentColor}`\n }`}\n />\n ))}\n </span>\n )}\n </button>\n );\n}\n\ntype EventCardProps = {\n event: CalendarEvent;\n accentColor: ColorOptions;\n textColor: ColorOptions;\n};\n\n// Events render in the viewer's own timezone (browser local) so the same time\n// reads consistently on Portal and mobile. timeZoneName \"short\" appends the\n// viewer's zone abbreviation (e.g. MST).\nconst formatLongDateTime = (iso: string): string => {\n const d = new Date(iso);\n const datePart = d.toLocaleDateString(\"en-US\", {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n });\n const timePart = d.toLocaleTimeString(\"en-US\", {\n hour: \"numeric\",\n minute: \"2-digit\",\n timeZoneName: \"short\",\n });\n return `${datePart} at ${timePart}`;\n};\n\nconst isSafeHttpUrl = (url: string): boolean => {\n try {\n const parsed = new URL(url);\n return parsed.protocol === \"http:\" || parsed.protocol === \"https:\";\n } catch {\n return false;\n }\n};\n\nconst deriveEventStatus = (\n event: CalendarEvent,\n): { label: string; tone: \"upcoming\" | \"live\" | \"past\" } => {\n const rawStatus = event.status?.trim();\n const normalized = rawStatus?.toLowerCase();\n if (rawStatus && normalized !== \"active\" && normalized !== \"confirmed\") {\n const label =\n rawStatus.charAt(0).toUpperCase() + rawStatus.slice(1).toLowerCase();\n return { label, tone: \"past\" };\n }\n const startMs = new Date(event.start).getTime();\n const endMs = new Date(event.end).getTime();\n const now = Date.now();\n if (now < startMs) return { label: \"Upcoming\", tone: \"upcoming\" };\n if (now <= endMs) return { label: \"Live\", tone: \"live\" };\n return { label: \"Past\", tone: \"past\" };\n};\n\nfunction EventCard({ event, accentColor, textColor }: EventCardProps) {\n const accentVar = `var(--color-${accentColor})`;\n const barColor = event.color || accentVar;\n const startDate = new Date(event.start);\n // All events, all-day included, render in the viewer's own timezone, so the\n // badge, start/end, and calendar cell agree with each other and with mobile.\n const weekday = startDate.toLocaleDateString(\"en-US\", {\n weekday: \"short\",\n });\n const monthDay = startDate.toLocaleDateString(\"en-US\", {\n month: \"short\",\n day: \"numeric\",\n });\n const status = deriveEventStatus(event);\n const description = event.description?.body;\n\n const startDisplay = formatLongDateTime(event.start);\n const endDisplay = formatLongDateTime(event.end);\n\n const statusToneClasses =\n status.tone === \"live\"\n ? `bg-${accentColor}/15 text-${accentColor}`\n : status.tone === \"upcoming\"\n ? `bg-${accentColor}/10 text-${accentColor}`\n : `bg-${textColor}/10 text-${textColor}/60`;\n\n return (\n <article\n className={`relative overflow-hidden rounded-lg border border-${textColor}/10`}\n >\n <span\n aria-hidden=\"true\"\n className=\"absolute inset-y-0 left-0 w-[3px]\"\n style={{ backgroundColor: barColor }}\n />\n\n {event.imageUrl && (\n <img\n src={event.imageUrl}\n alt=\"\"\n className=\"aspect-[16/7] w-full object-cover\"\n />\n )}\n\n <div className=\"flex flex-col gap-4 p-4 pl-5\">\n <div className=\"flex items-start gap-4\">\n <div\n className={`shrink-0 text-${textColor} leading-tight tabular-nums`}\n >\n <div className={`text-xs font-semibold text-${textColor}/55`}>\n {weekday}\n </div>\n <div className=\"text-2xl font-bold tracking-[-0.015em]\">\n {monthDay}\n </div>\n </div>\n\n <div className=\"min-w-0 flex-1\">\n <h4\n className={`text-base font-bold text-${textColor} leading-tight tracking-[-0.01em]`}\n >\n {event.title}\n </h4>\n {description && (\n <p\n className={`mt-1 text-sm leading-snug whitespace-pre-wrap text-${textColor}/65`}\n >\n {description}\n </p>\n )}\n </div>\n </div>\n\n <div className=\"flex flex-col gap-2.5\">\n <div className=\"flex items-start gap-2\">\n <Calendar\n className={`mt-0.5 size-4 shrink-0 text-${textColor}/55`}\n />\n <div\n className={`text-sm leading-snug text-${textColor}/80 tabular-nums`}\n >\n <div>\n <span className=\"font-semibold\">Start</span> {startDisplay}\n </div>\n <div>\n <span className=\"font-semibold\">End</span> {endDisplay}\n </div>\n </div>\n </div>\n\n <div>\n <span\n className={`inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-semibold ${statusToneClasses}`}\n >\n {status.label}\n </span>\n </div>\n\n {event.url && isSafeHttpUrl(event.url) && (\n <a\n href={event.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={`flex items-center gap-2 text-sm text-${accentColor} break-all hover:underline`}\n >\n <Link2 className={`size-4 shrink-0 text-${textColor}/55`} />\n <span>{event.url}</span>\n </a>\n )}\n\n {event.venue && (\n <a\n href={`https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(event.venue)}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={`flex items-start gap-2 text-sm text-${accentColor} hover:underline`}\n >\n <MapPin\n className={`mt-0.5 size-4 shrink-0 text-${textColor}/55`}\n />\n <span>{event.venue}</span>\n </a>\n )}\n </div>\n </div>\n </article>\n );\n}\n\ntype NavButtonProps = {\n icon: LucideIcon;\n label: string;\n variant: \"ghost\" | \"accent\";\n accentColor: ColorOptions;\n textColor: ColorOptions;\n onClick: () => void;\n};\n\nfunction NavButton({\n icon: Icon,\n label,\n variant,\n accentColor,\n textColor,\n onClick,\n}: NavButtonProps) {\n const classes =\n variant === \"accent\"\n ? `bg-${accentColor} text-${accentColor}-foreground hover:bg-${accentColor}/90 focus-visible:ring-${accentColor}/40`\n : `bg-${textColor}/5 text-${textColor} hover:bg-${textColor}/10 focus-visible:ring-${textColor}/20`;\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label={label}\n className={`flex size-8 items-center justify-center rounded-full text-[12px] transition-colors focus:outline-none focus-visible:ring-2 ${classes}`}\n >\n <Icon className=\"size-4\" />\n </button>\n );\n}\n\ntype CalendarView = {\n month: number;\n year: number;\n};\n\nconst getInitialCalendarView = (): CalendarView => {\n const now = new Date();\n return { month: now.getMonth(), year: now.getFullYear() };\n};\n\nfunction useCalendarNavigation(\n setSelectedDate: React.Dispatch<React.SetStateAction<Date | null>>,\n) {\n const [view, setView] = useState(getInitialCalendarView);\n const [gridTransitioning, setGridTransitioning] = useState(false);\n const transitionTimeoutRef = useRef<number | null>(null);\n\n useEffect(\n () => () => {\n if (transitionTimeoutRef.current !== null) {\n window.clearTimeout(transitionTimeoutRef.current);\n }\n },\n [],\n );\n\n const clearPendingTransition = useCallback(() => {\n if (transitionTimeoutRef.current !== null) {\n window.clearTimeout(transitionTimeoutRef.current);\n transitionTimeoutRef.current = null;\n }\n }, []);\n\n const navigate = useCallback(\n (direction: -1 | 1) => {\n clearPendingTransition();\n setGridTransitioning(true);\n transitionTimeoutRef.current = window.setTimeout(() => {\n setView((prev) => {\n const next = prev.month + direction;\n if (next < 0) return { month: 11, year: prev.year - 1 };\n if (next > 11) return { month: 0, year: prev.year + 1 };\n return { month: next, year: prev.year };\n });\n setGridTransitioning(false);\n transitionTimeoutRef.current = null;\n }, 120);\n },\n [clearPendingTransition],\n );\n\n const goToToday = useCallback(() => {\n clearPendingTransition();\n const now = new Date();\n setGridTransitioning(true);\n transitionTimeoutRef.current = window.setTimeout(() => {\n setView({ month: now.getMonth(), year: now.getFullYear() });\n setSelectedDate(now);\n setGridTransitioning(false);\n transitionTimeoutRef.current = null;\n }, 80);\n }, [clearPendingTransition, setSelectedDate]);\n\n return { view, gridTransitioning, navigate, goToToday };\n}\n\n// The local Date whose calendar day equals the event's day in the viewer's own\n// timezone, so the dot sits on the same day the card shows it starting. Builder,\n// preview, and live portal agree because all read the same start/end instant,\n// whichever adapter fetched it.\nconst eventDayAnchor = (event: CalendarEvent, useEnd = false): Date => {\n const iso = useEnd ? event.end : event.start;\n return startOfDay(new Date(iso));\n};\n\nfunction useCalendarEventIndex(\n events: CalendarEvent[],\n selectedDate: Date | null,\n) {\n const eventsByDate = useMemo(() => {\n const map = new Map<string, CalendarEvent[]>();\n for (const event of events) {\n const start = eventDayAnchor(event);\n const end = eventDayAnchor(event, true);\n for (let cur = start; cur <= end; cur = addDays(cur, 1)) {\n const key = `${cur.getFullYear()}-${cur.getMonth()}-${cur.getDate()}`;\n const list = map.get(key);\n if (list) {\n list.push(event);\n } else {\n map.set(key, [event]);\n }\n }\n }\n return map;\n }, [events]);\n\n const lookupEventsForDate = useCallback(\n (date: Date): CalendarEvent[] => {\n const key = `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;\n return eventsByDate.get(key) ?? [];\n },\n [eventsByDate],\n );\n\n const selectedDateEvents = useMemo(() => {\n if (!selectedDate) return [];\n return lookupEventsForDate(selectedDate);\n }, [selectedDate, lookupEventsForDate]);\n\n return { lookupEventsForDate, selectedDateEvents };\n}\n\ntype CalendarWidgetProps = ComponentProps<\"div\"> & {\n // Title\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n // Styling\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n\n // Premium polish (new, additive)\n showEventDensity?: boolean;\n showTodayButton?: boolean;\n weekendDim?: boolean;\n showYearEyebrow?: boolean;\n};\n\nexport function CalendarWidget({\n titleEnabled = true,\n titleText = \"Calendar\",\n titleFontSize = \"xl\",\n titleColor = \"foreground\",\n\n background = { type: \"solid\", color: \"background\" },\n textColor = \"foreground\",\n accentColor = \"primary\",\n padding = 4,\n borderRadius = \"md\",\n borderWidth = \"none\",\n borderColor = \"muted\",\n\n showEventDensity = true,\n showTodayButton = true,\n weekendDim = true,\n showYearEyebrow = true,\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\n const [isCollapsed, setIsCollapsed] = useState(false);\n const [selectedDate, setSelectedDate] = useState<Date | null>(\n () => new Date(),\n );\n const { view, gridTransitioning, navigate, goToToday } =\n useCalendarNavigation(setSelectedDate);\n const currentMonth = view.month;\n const currentYear = view.year;\n\n const { data: events = [], isLoading, isError } = useCalendarEvents();\n\n const monthGrid = useMemo(\n () => generateMonthGrid(currentYear, currentMonth),\n [currentYear, currentMonth],\n );\n const weekGrid = generateWeekGrid();\n const { lookupEventsForDate, selectedDateEvents } = useCalendarEventIndex(\n events,\n selectedDate,\n );\n\n const now = new Date();\n const viewingCurrentMonth =\n currentMonth === now.getMonth() && currentYear === now.getFullYear();\n\n const monthLabel = new Date(currentYear, currentMonth).toLocaleString(\n \"en-US\",\n { month: \"long\" },\n );\n const yearLabel = String(currentYear);\n\n const contextualDate = selectedDate\n ? formatContextualDate(selectedDate)\n : null;\n\n return (\n <div\n className={`@container overflow-hidden rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} bg-${backgroundColor} text-${textColor} ${className ?? \"\"}`}\n style={{ backgroundImage }}\n {...props}\n >\n {titleEnabled && titleText && (\n <div className={`p-${padding} pb-0`}>\n <h2\n className={`text-${titleFontSize} text-${titleColor} font-bold tracking-[-0.012em]`}\n >\n {titleText}\n </h2>\n </div>\n )}\n\n {isLoading ? (\n <div\n className={`flex min-h-[300px] items-center justify-center p-${padding}`}\n >\n <div className={`text-${accentColor}`}>\n <div className=\"size-8 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n </div>\n </div>\n ) : isError ? (\n <ErrorState />\n ) : (\n <div className={`p-${padding}`}>\n <div className=\"@md:flex @md:gap-6\">\n <div className=\"@md:flex-none\">\n {/* Header row: year eyebrow + month + asymmetric nav + Today pill */}\n <div className=\"mb-4 flex items-start justify-between gap-3\">\n <div className=\"flex min-w-0 flex-col\">\n {showYearEyebrow && (\n <span\n className={`text-[10px] font-bold tracking-[0.16em] uppercase text-${textColor}/55`}\n >\n {yearLabel}\n </span>\n )}\n <span\n className={`text-xl leading-tight font-bold tracking-[-0.015em] text-${textColor}`}\n >\n {monthLabel}\n </span>\n </div>\n\n <div className=\"flex shrink-0 items-center gap-1.5\">\n {showTodayButton && !viewingCurrentMonth && (\n <button\n type=\"button\"\n onClick={goToToday}\n className={`flex items-center gap-1 rounded-full bg-${accentColor}/10 px-2.5 py-1 text-[11px] font-semibold text-${accentColor} transition-colors hover:bg-${accentColor}/20 focus:outline-none focus-visible:ring-2 focus-visible:ring-${accentColor}/40`}\n >\n <CalendarCheck className=\"size-3\" />\n Today\n </button>\n )}\n <NavButton\n icon={ChevronLeft}\n label=\"Previous month\"\n variant=\"ghost\"\n accentColor={accentColor}\n textColor={textColor}\n onClick={() => navigate(-1)}\n />\n <NavButton\n icon={ChevronRight}\n label=\"Next month\"\n variant=\"accent\"\n accentColor={accentColor}\n textColor={textColor}\n onClick={() => navigate(1)}\n />\n </div>\n </div>\n\n {/* Day-of-week headers */}\n <div className=\"mb-2 grid grid-cols-7 gap-1 text-center\">\n {DAY_NAMES.map((day, idx) => {\n const isWeekend = idx === 0 || idx === 6;\n const dimmed = weekendDim && isWeekend;\n return (\n <div\n key={day}\n className={`text-[10px] font-semibold tracking-[0.12em] uppercase text-${textColor}/${dimmed ? \"40\" : \"55\"}`}\n >\n {day}\n </div>\n );\n })}\n </div>\n\n {/* Grid wrapper (opacity transitions on month navigate) */}\n <div\n className=\"transition-opacity duration-150 ease-out\"\n style={{ opacity: gridTransitioning ? 0.3 : 1 }}\n >\n {/* Collapsed week view on mobile */}\n {isCollapsed && (\n <div className=\"grid grid-cols-7 gap-1 @md:hidden\">\n {weekGrid.map(({ date, isToday }) => (\n <DayCellButton\n key={date.toISOString()}\n date={date}\n isToday={isToday}\n isSelected={\n !!selectedDate && isSameDay(selectedDate, date)\n }\n eventCount={lookupEventsForDate(date).length}\n accentColor={accentColor}\n textColor={textColor}\n showEventDensity={showEventDensity}\n onClick={() => setSelectedDate(date)}\n />\n ))}\n </div>\n )}\n\n {/* Month grid */}\n <div\n className={`grid grid-cols-7 gap-1 ${isCollapsed ? \"hidden @md:grid\" : \"grid\"}`}\n >\n {monthGrid.map((cell, idx) => {\n if (!cell.date) {\n return (\n <div key={`empty-${idx}`} className=\"aspect-square\" />\n );\n }\n const eventCount = lookupEventsForDate(cell.date).length;\n return (\n <DayCellButton\n key={cell.date.toISOString()}\n date={cell.date}\n isToday={cell.isToday}\n isSelected={\n !!selectedDate && isSameDay(selectedDate, cell.date)\n }\n eventCount={eventCount}\n accentColor={accentColor}\n textColor={textColor}\n showEventDensity={showEventDensity}\n onClick={() => setSelectedDate(cell.date)}\n />\n );\n })}\n </div>\n </div>\n\n {/* Mobile collapse toggle */}\n <button\n type=\"button\"\n onClick={() => setIsCollapsed(!isCollapsed)}\n className={`mt-2 flex w-full items-center justify-center gap-3 rounded-full p-1 text-${textColor}/40 transition-colors hover:text-${textColor}/60 @md:hidden`}\n aria-label={\n isCollapsed ? \"Expand calendar\" : \"Collapse calendar\"\n }\n >\n <div className={`h-px w-1/2 bg-${textColor}/20`} />\n {isCollapsed ? (\n <ChevronsDown className=\"size-3\" />\n ) : (\n <ChevronsUp className=\"size-3\" />\n )}\n <div className={`h-px w-1/2 bg-${textColor}/20`} />\n </button>\n </div>\n\n {/* Events rail */}\n <div\n className={`mt-4 min-w-0 border-${textColor}/10 @md:relative @md:mt-0 @md:flex-1 @md:border-l`}\n >\n <div className=\"@md:absolute @md:inset-0 @md:overflow-y-auto @md:pr-1 @md:pl-6\">\n {/* Context header */}\n {contextualDate && (\n <div className=\"mb-3\">\n {contextualDate.lead && (\n <div\n className={`text-[10px] font-bold tracking-[0.16em] uppercase text-${accentColor}`}\n >\n {contextualDate.lead}\n </div>\n )}\n <div\n className={`text-sm font-semibold text-${textColor} tabular-nums`}\n >\n {contextualDate.detail}\n </div>\n </div>\n )}\n\n {/* Events list with soft fade-in keyed by selected date */}\n <div\n key={selectedDate?.toISOString() ?? \"none\"}\n className=\"animate-in fade-in slide-in-from-bottom-2 flex flex-col gap-3 duration-200 ease-out\"\n >\n {selectedDateEvents.length > 0 ? (\n selectedDateEvents.map((event, idx) => (\n <EventCard\n key={`${event.id}-${idx}`}\n event={event}\n accentColor={accentColor}\n textColor={textColor}\n />\n ))\n ) : (\n <div\n className={`flex flex-col items-start gap-1 rounded-md border border-dashed border-${textColor}/15 px-3 py-3`}\n >\n <div className=\"flex items-center gap-1.5\">\n <CalendarCheck\n className={`size-3 text-${textColor}/40`}\n />\n <span\n className={`text-[11px] font-semibold text-${textColor}/60`}\n >\n Nothing scheduled\n </span>\n </div>\n <span className={`text-[11px] text-${textColor}/45`}>\n Enjoy the breather.\n </span>\n </div>\n )}\n </div>\n </div>\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 // 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 // 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:\n \"Drives today highlight, event dots, Today pill, and selected day\",\n defaultValue: \"primary\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the calendar container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the calendar container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the calendar container\",\n defaultValue: \"none\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the calendar container\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n\n // Polish group (new)\n {\n key: \"showYearEyebrow\",\n label: \"Year Eyebrow\",\n type: \"boolean\",\n description:\n \"Small uppercase year label above the month (e.g. '2026 / November').\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Polish\",\n },\n {\n key: \"showTodayButton\",\n label: \"Today Button\",\n type: \"boolean\",\n description: \"Show a 'Today' pill when viewing a different month.\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Polish\",\n },\n {\n key: \"showEventDensity\",\n label: \"Event Density Dots\",\n type: \"boolean\",\n description:\n \"Show 1–3 dots per day based on event count (off = single dot).\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Polish\",\n },\n {\n key: \"weekendDim\",\n label: \"Dim Weekends\",\n type: \"boolean\",\n description:\n \"Subtly dim the Sun/Sat day-of-week headers for visual rhythm.\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Polish\",\n },\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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;mBAAM;SAE9C,CAAA,CACH;;OAEJ,EA/BC,cAAc,aAAa,IAAI,OA+BhC,CACF;;KACF,CAAA,CACF;;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,aACE;GACF,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;EACF,oBAAoB;GAClB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,oBAAoB;GAClB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EAGF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aACE;GACF,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aACE;GACF,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aACE;GACF,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACF;CACF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require("./chunk-9hOWP6kD.cjs");
|
|
2
2
|
require("./ContactsTranslationBridge-BvkMkPED.cjs");
|
|
3
|
-
const require_ContactsScreen = require("./ContactsScreen-
|
|
3
|
+
const require_ContactsScreen = require("./ContactsScreen-CBXOEkvz.cjs");
|
|
4
4
|
require("./static-dict-adapter-Dk_ZWOUI.cjs");
|
|
5
5
|
require("./translation-api-context-factory-DkXq_vPq.cjs");
|
|
6
6
|
require("./task-composer-form-oKkUtTAg.cjs");
|
|
@@ -16,6 +16,7 @@ let react_jsx_runtime = require("react/jsx-runtime");
|
|
|
16
16
|
let zod = require("zod");
|
|
17
17
|
let lucide_react = require("lucide-react");
|
|
18
18
|
let react_hook_form = require("react-hook-form");
|
|
19
|
+
let _fluid_app_ui_components_components_MobileBottomSheet = require("@fluid-app/ui-components/components/MobileBottomSheet");
|
|
19
20
|
let _fluid_app_ui_components_components_Combobox = require("@fluid-app/ui-components/components/Combobox");
|
|
20
21
|
//#region ../../platform/api-client-core/src/parse-api-errors.ts
|
|
21
22
|
/**
|
|
@@ -484,6 +485,22 @@ var Sub2 = ContextMenuSub$1;
|
|
|
484
485
|
var SubTrigger2 = ContextMenuSubTrigger$1;
|
|
485
486
|
var SubContent2 = ContextMenuSubContent$1;
|
|
486
487
|
//#endregion
|
|
488
|
+
//#region ../react/src/shell/use-mobile.ts
|
|
489
|
+
const MOBILE_BREAKPOINT$1 = 768;
|
|
490
|
+
function useIsMobile$1() {
|
|
491
|
+
const [isMobile, setIsMobile] = (0, react.useState)(false);
|
|
492
|
+
(0, react.useEffect)(() => {
|
|
493
|
+
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT$1 - 1}px)`);
|
|
494
|
+
const onChange = () => {
|
|
495
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT$1);
|
|
496
|
+
};
|
|
497
|
+
mql.addEventListener("change", onChange);
|
|
498
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT$1);
|
|
499
|
+
return () => mql.removeEventListener("change", onChange);
|
|
500
|
+
}, []);
|
|
501
|
+
return isMobile;
|
|
502
|
+
}
|
|
503
|
+
//#endregion
|
|
487
504
|
//#region ../../contacts/ui/src/portal/hooks/groups/invalidate-contact-caches.ts
|
|
488
505
|
function invalidateContactCaches(queryClient) {
|
|
489
506
|
queryClient.invalidateQueries({ queryKey: require_task_composer_form.CONTACTS_QUERY_KEYS.all("contacts") });
|
|
@@ -1496,6 +1513,7 @@ const ContactDetailsForm = ({ className, countries = DEFAULT_COUNTRIES, renderAv
|
|
|
1496
1513
|
}) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.SelectContent, {
|
|
1497
1514
|
position: "popper",
|
|
1498
1515
|
sideOffset: 4,
|
|
1516
|
+
className: "z-[1060]",
|
|
1499
1517
|
children: effectiveStatusOptions.map((opt) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.SelectItem, {
|
|
1500
1518
|
value: opt.value,
|
|
1501
1519
|
children: opt.name
|
|
@@ -1591,7 +1609,8 @@ const ContactDetailsForm = ({ className, countries = DEFAULT_COUNTRIES, renderAv
|
|
|
1591
1609
|
})),
|
|
1592
1610
|
value: field.value ?? "",
|
|
1593
1611
|
onValueChange: field.onChange,
|
|
1594
|
-
placeholder: t("placeholder_country")
|
|
1612
|
+
placeholder: t("placeholder_country"),
|
|
1613
|
+
zIndex: 1060
|
|
1595
1614
|
}) }),
|
|
1596
1615
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.FormMessage, {})
|
|
1597
1616
|
] })
|
|
@@ -4868,7 +4887,8 @@ const CREATE_DEFAULT_VALUES = {
|
|
|
4868
4887
|
metadata: {},
|
|
4869
4888
|
affiliate: {}
|
|
4870
4889
|
};
|
|
4871
|
-
function ContactCreateView({ onNavigate, onCreateContact }) {
|
|
4890
|
+
function ContactCreateView({ onNavigate, onCreateContact, asSheet = false }) {
|
|
4891
|
+
const { t } = require_task_composer_form.useContactsTranslation();
|
|
4872
4892
|
const formRef = (0, react.useRef)(null);
|
|
4873
4893
|
const { locale } = require_static_dict_adapter.useActiveLocale();
|
|
4874
4894
|
const countriesAdapter = require_ContactsTranslationBridge.useCountriesApi();
|
|
@@ -4901,13 +4921,42 @@ function ContactCreateView({ onNavigate, onCreateContact }) {
|
|
|
4901
4921
|
if (affiliate && Object.keys(affiliate).length > 0) payload.affiliate = affiliate;
|
|
4902
4922
|
mutate(payload);
|
|
4903
4923
|
}, () => {}), [methods, mutate]);
|
|
4924
|
+
const handleNavigateToList = (0, react.useCallback)(() => {
|
|
4925
|
+
onNavigate({
|
|
4926
|
+
view: "browse",
|
|
4927
|
+
selectedContactId: null
|
|
4928
|
+
});
|
|
4929
|
+
}, [onNavigate]);
|
|
4930
|
+
if (asSheet) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_fluid_app_ui_components_components_MobileBottomSheet.MobileBottomSheet, {
|
|
4931
|
+
open: true,
|
|
4932
|
+
onOpenChange: (nextOpen) => {
|
|
4933
|
+
if (!nextOpen) handleNavigateToList();
|
|
4934
|
+
},
|
|
4935
|
+
title: t("breadcrumb_new"),
|
|
4936
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_hook_form.FormProvider, {
|
|
4937
|
+
...methods,
|
|
4938
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
|
|
4939
|
+
ref: formRef,
|
|
4940
|
+
onSubmit,
|
|
4941
|
+
className: "space-y-6 px-2 pb-2",
|
|
4942
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContactDetailsForm, { countries: countryOptions }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4943
|
+
className: "flex justify-end gap-2",
|
|
4944
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Button, {
|
|
4945
|
+
type: "button",
|
|
4946
|
+
variant: "outline",
|
|
4947
|
+
onClick: handleNavigateToList,
|
|
4948
|
+
children: t("cancel")
|
|
4949
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Button, {
|
|
4950
|
+
type: "submit",
|
|
4951
|
+
disabled: mutation.isPending,
|
|
4952
|
+
children: mutation.isPending ? t("adding") : t("add_contact")
|
|
4953
|
+
})]
|
|
4954
|
+
})]
|
|
4955
|
+
})
|
|
4956
|
+
})
|
|
4957
|
+
});
|
|
4904
4958
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContactCreateScreen, {
|
|
4905
|
-
onNavigateToList:
|
|
4906
|
-
onNavigate({
|
|
4907
|
-
view: "browse",
|
|
4908
|
-
selectedContactId: null
|
|
4909
|
-
});
|
|
4910
|
-
}, [onNavigate]),
|
|
4959
|
+
onNavigateToList: handleNavigateToList,
|
|
4911
4960
|
onSubmit: () => formRef.current?.requestSubmit(),
|
|
4912
4961
|
isPending: mutation.isPending,
|
|
4913
4962
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_hook_form.FormProvider, {
|
|
@@ -4927,6 +4976,7 @@ function ContactCreateView({ onNavigate, onCreateContact }) {
|
|
|
4927
4976
|
function ContactsScreen({ onContactSelect, onCreateContact, background, textColor, accentColor, padding, borderRadius, defaultViewMode, ...divProps }) {
|
|
4928
4977
|
const { currentSlug, navigate } = require_AppNavigationContext.useAppNavigation();
|
|
4929
4978
|
const subPage = currentSlug.split("/")[1];
|
|
4979
|
+
const isMobile = useIsMobile$1();
|
|
4930
4980
|
const [nav, setNav] = (0, react.useState)({
|
|
4931
4981
|
view: "browse",
|
|
4932
4982
|
selectedContactId: null
|
|
@@ -4950,6 +5000,10 @@ function ContactsScreen({ onContactSelect, onCreateContact, background, textColo
|
|
|
4950
5000
|
const handleManageGroups = (0, react.useCallback)(() => {
|
|
4951
5001
|
navigate("contacts/manage-groups");
|
|
4952
5002
|
}, [navigate]);
|
|
5003
|
+
const handleCreateNavigate = (0, react.useCallback)((state) => {
|
|
5004
|
+
setNav(state);
|
|
5005
|
+
if (state.view === "browse" && state.selectedContactId) setHighlightContactId(state.selectedContactId);
|
|
5006
|
+
}, []);
|
|
4953
5007
|
const [createGroupOpen, setCreateGroupOpen] = (0, react.useState)(false);
|
|
4954
5008
|
const [highlightGroupName, setHighlightGroupName] = (0, react.useState)(null);
|
|
4955
5009
|
(0, react.useEffect)(() => {
|
|
@@ -4972,21 +5026,22 @@ function ContactsScreen({ onContactSelect, onCreateContact, background, textColo
|
|
|
4972
5026
|
});
|
|
4973
5027
|
navigate("contacts");
|
|
4974
5028
|
}
|
|
4975
|
-
}) : nav.view === "new" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContactCreateView, {
|
|
4976
|
-
onNavigate:
|
|
4977
|
-
setNav(state);
|
|
4978
|
-
if (state.view === "browse" && state.selectedContactId) setHighlightContactId(state.selectedContactId);
|
|
4979
|
-
},
|
|
5029
|
+
}) : nav.view === "new" && !isMobile ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContactCreateView, {
|
|
5030
|
+
onNavigate: handleCreateNavigate,
|
|
4980
5031
|
onCreateContact
|
|
4981
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContactBrowseView, {
|
|
4982
|
-
selectedContactId: nav.selectedContactId,
|
|
5032
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContactBrowseView, {
|
|
5033
|
+
selectedContactId: nav.view === "browse" ? nav.selectedContactId : null,
|
|
4983
5034
|
highlightContactId,
|
|
4984
5035
|
onSelect: handleSelect,
|
|
4985
5036
|
onAdd: handleAdd,
|
|
4986
5037
|
onManageGroups: handleManageGroups,
|
|
4987
5038
|
onCreateGroup: handleCreateGroup,
|
|
4988
5039
|
highlightGroupName
|
|
4989
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
5040
|
+
}), nav.view === "new" && isMobile ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContactCreateView, {
|
|
5041
|
+
asSheet: true,
|
|
5042
|
+
onNavigate: handleCreateNavigate,
|
|
5043
|
+
onCreateContact
|
|
5044
|
+
}) : null] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GroupDialog, {
|
|
4990
5045
|
mode: "create",
|
|
4991
5046
|
open: createGroupOpen,
|
|
4992
5047
|
onOpenChange: (open) => setCreateGroupOpen(open),
|
|
@@ -5018,5 +5073,11 @@ Object.defineProperty(exports, "contactsScreenPropertySchema", {
|
|
|
5018
5073
|
return contactsScreenPropertySchema;
|
|
5019
5074
|
}
|
|
5020
5075
|
});
|
|
5076
|
+
Object.defineProperty(exports, "useIsMobile", {
|
|
5077
|
+
enumerable: true,
|
|
5078
|
+
get: function() {
|
|
5079
|
+
return useIsMobile$1;
|
|
5080
|
+
}
|
|
5081
|
+
});
|
|
5021
5082
|
|
|
5022
|
-
//# sourceMappingURL=ContactsScreen-
|
|
5083
|
+
//# sourceMappingURL=ContactsScreen-CBXOEkvz.cjs.map
|