@medalsocial/meda 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/dist/calendar/calendar-toolbar.d.ts +2 -0
  2. package/dist/calendar/calendar-toolbar.js +22 -0
  3. package/dist/calendar/calendar.d.ts +2 -0
  4. package/dist/calendar/calendar.js +55 -0
  5. package/dist/calendar/day-view.d.ts +2 -0
  6. package/dist/calendar/day-view.js +40 -0
  7. package/dist/calendar/index.d.ts +6 -0
  8. package/dist/calendar/index.js +7 -0
  9. package/dist/calendar/internal/date.d.ts +26 -0
  10. package/dist/calendar/internal/date.js +107 -0
  11. package/dist/calendar/internal/day-cell.d.ts +15 -0
  12. package/dist/calendar/internal/day-cell.js +38 -0
  13. package/dist/calendar/internal/event-pill.d.ts +13 -0
  14. package/dist/calendar/internal/event-pill.js +30 -0
  15. package/dist/calendar/internal/time-slot.d.ts +17 -0
  16. package/dist/calendar/internal/time-slot.js +23 -0
  17. package/dist/calendar/month-view.d.ts +2 -0
  18. package/dist/calendar/month-view.js +46 -0
  19. package/dist/calendar/public.d.ts +6 -0
  20. package/dist/calendar/public.js +8 -0
  21. package/dist/calendar/types.d.ts +113 -0
  22. package/dist/calendar/types.js +15 -0
  23. package/dist/calendar/week-view.d.ts +2 -0
  24. package/dist/calendar/week-view.js +39 -0
  25. package/dist/chat/turn-card.js +10 -5
  26. package/dist/email-builder/block-error-boundary.d.ts +16 -0
  27. package/dist/email-builder/block-error-boundary.js +20 -0
  28. package/dist/email-builder/block-palette.d.ts +7 -0
  29. package/dist/email-builder/block-palette.js +22 -0
  30. package/dist/email-builder/block-registry.d.ts +15 -0
  31. package/dist/email-builder/block-registry.js +156 -0
  32. package/dist/email-builder/block-renderer.d.ts +5 -0
  33. package/dist/email-builder/block-renderer.js +40 -0
  34. package/dist/email-builder/block-renderers/button.d.ts +4 -0
  35. package/dist/email-builder/block-renderers/button.js +26 -0
  36. package/dist/email-builder/block-renderers/columns.d.ts +5 -0
  37. package/dist/email-builder/block-renderers/columns.js +27 -0
  38. package/dist/email-builder/block-renderers/divider.d.ts +4 -0
  39. package/dist/email-builder/block-renderers/divider.js +14 -0
  40. package/dist/email-builder/block-renderers/footer.d.ts +4 -0
  41. package/dist/email-builder/block-renderers/footer.js +12 -0
  42. package/dist/email-builder/block-renderers/heading.d.ts +4 -0
  43. package/dist/email-builder/block-renderers/heading.js +19 -0
  44. package/dist/email-builder/block-renderers/image.d.ts +4 -0
  45. package/dist/email-builder/block-renderers/image.js +18 -0
  46. package/dist/email-builder/block-renderers/social.d.ts +4 -0
  47. package/dist/email-builder/block-renderers/social.js +19 -0
  48. package/dist/email-builder/block-renderers/spacer.d.ts +4 -0
  49. package/dist/email-builder/block-renderers/spacer.js +5 -0
  50. package/dist/email-builder/block-renderers/text.d.ts +4 -0
  51. package/dist/email-builder/block-renderers/text.js +17 -0
  52. package/dist/email-builder/builder-canvas.d.ts +15 -0
  53. package/dist/email-builder/builder-canvas.js +26 -0
  54. package/dist/email-builder/builder-header.d.ts +9 -0
  55. package/dist/email-builder/builder-header.js +8 -0
  56. package/dist/email-builder/builder-left-tabs.d.ts +11 -0
  57. package/dist/email-builder/builder-left-tabs.js +19 -0
  58. package/dist/email-builder/email-builder.d.ts +3 -0
  59. package/dist/email-builder/email-builder.js +84 -0
  60. package/dist/email-builder/envelope-card.d.ts +7 -0
  61. package/dist/email-builder/envelope-card.js +16 -0
  62. package/dist/email-builder/floating-bar.d.ts +13 -0
  63. package/dist/email-builder/floating-bar.js +9 -0
  64. package/dist/email-builder/index.d.ts +4 -0
  65. package/dist/email-builder/index.js +12 -0
  66. package/dist/email-builder/internal/builder-state-utils.d.ts +7 -0
  67. package/dist/email-builder/internal/builder-state-utils.js +52 -0
  68. package/dist/email-builder/internal/dnd-wrapper.d.ts +10 -0
  69. package/dist/email-builder/internal/dnd-wrapper.js +9 -0
  70. package/dist/email-builder/internal/email-font-options.d.ts +5 -0
  71. package/dist/email-builder/internal/email-font-options.js +12 -0
  72. package/dist/email-builder/mobile-drawers.d.ts +10 -0
  73. package/dist/email-builder/mobile-drawers.js +7 -0
  74. package/dist/email-builder/mobile-tab-bar.d.ts +10 -0
  75. package/dist/email-builder/mobile-tab-bar.js +9 -0
  76. package/dist/email-builder/property-editors/_shared.d.ts +58 -0
  77. package/dist/email-builder/property-editors/_shared.js +52 -0
  78. package/dist/email-builder/property-editors/button-editor.d.ts +7 -0
  79. package/dist/email-builder/property-editors/button-editor.js +10 -0
  80. package/dist/email-builder/property-editors/columns-editor.d.ts +7 -0
  81. package/dist/email-builder/property-editors/columns-editor.js +15 -0
  82. package/dist/email-builder/property-editors/divider-editor.d.ts +7 -0
  83. package/dist/email-builder/property-editors/divider-editor.js +10 -0
  84. package/dist/email-builder/property-editors/footer-editor.d.ts +7 -0
  85. package/dist/email-builder/property-editors/footer-editor.js +6 -0
  86. package/dist/email-builder/property-editors/heading-editor.d.ts +7 -0
  87. package/dist/email-builder/property-editors/heading-editor.js +16 -0
  88. package/dist/email-builder/property-editors/image-editor.d.ts +8 -0
  89. package/dist/email-builder/property-editors/image-editor.js +17 -0
  90. package/dist/email-builder/property-editors/social-editor.d.ts +7 -0
  91. package/dist/email-builder/property-editors/social-editor.js +18 -0
  92. package/dist/email-builder/property-editors/spacer-editor.d.ts +7 -0
  93. package/dist/email-builder/property-editors/spacer-editor.js +6 -0
  94. package/dist/email-builder/property-editors/text-editor.d.ts +13 -0
  95. package/dist/email-builder/property-editors/text-editor.js +8 -0
  96. package/dist/email-builder/property-inspector.d.ts +11 -0
  97. package/dist/email-builder/property-inspector.js +42 -0
  98. package/dist/email-builder/public.d.ts +1 -0
  99. package/dist/email-builder/public.js +3 -0
  100. package/dist/email-builder/render-to-email-html.d.ts +11 -0
  101. package/dist/email-builder/render-to-email-html.js +219 -0
  102. package/dist/email-builder/starter-shell.d.ts +3 -0
  103. package/dist/email-builder/starter-shell.js +21 -0
  104. package/dist/email-builder/types.d.ts +182 -0
  105. package/dist/email-builder/types.js +41 -0
  106. package/dist/email-builder/view-controls.d.ts +10 -0
  107. package/dist/email-builder/view-controls.js +12 -0
  108. package/dist/index.d.ts +4 -0
  109. package/dist/index.js +4 -0
  110. package/dist/lib/format-time.js +2 -3
  111. package/dist/post-preview/index.d.ts +4 -0
  112. package/dist/post-preview/index.js +7 -0
  113. package/dist/post-preview/internal/avatar.d.ts +12 -0
  114. package/dist/post-preview/internal/avatar.js +21 -0
  115. package/dist/post-preview/internal/format-content.d.ts +12 -0
  116. package/dist/post-preview/internal/format-content.js +31 -0
  117. package/dist/post-preview/internal/platform-meta.d.ts +10 -0
  118. package/dist/post-preview/internal/platform-meta.js +18 -0
  119. package/dist/post-preview/internal/textarea.d.ts +8 -0
  120. package/dist/post-preview/internal/textarea.js +12 -0
  121. package/dist/post-preview/internal/use-swipe.d.ts +17 -0
  122. package/dist/post-preview/internal/use-swipe.js +29 -0
  123. package/dist/post-preview/platforms/bluesky.d.ts +15 -0
  124. package/dist/post-preview/platforms/bluesky.js +21 -0
  125. package/dist/post-preview/platforms/discord.d.ts +44 -0
  126. package/dist/post-preview/platforms/discord.js +32 -0
  127. package/dist/post-preview/platforms/facebook.d.ts +23 -0
  128. package/dist/post-preview/platforms/facebook.js +24 -0
  129. package/dist/post-preview/platforms/generic.d.ts +22 -0
  130. package/dist/post-preview/platforms/generic.js +28 -0
  131. package/dist/post-preview/platforms/google-business.d.ts +18 -0
  132. package/dist/post-preview/platforms/google-business.js +22 -0
  133. package/dist/post-preview/platforms/index.d.ts +24 -0
  134. package/dist/post-preview/platforms/index.js +13 -0
  135. package/dist/post-preview/platforms/instagram.d.ts +31 -0
  136. package/dist/post-preview/platforms/instagram.js +99 -0
  137. package/dist/post-preview/platforms/linkedin.d.ts +52 -0
  138. package/dist/post-preview/platforms/linkedin.js +131 -0
  139. package/dist/post-preview/platforms/telegram.d.ts +46 -0
  140. package/dist/post-preview/platforms/telegram.js +42 -0
  141. package/dist/post-preview/platforms/threads.d.ts +19 -0
  142. package/dist/post-preview/platforms/threads.js +24 -0
  143. package/dist/post-preview/platforms/tiktok.d.ts +18 -0
  144. package/dist/post-preview/platforms/tiktok.js +23 -0
  145. package/dist/post-preview/platforms/twitter.d.ts +40 -0
  146. package/dist/post-preview/platforms/twitter.js +132 -0
  147. package/dist/post-preview/platforms/youtube.d.ts +17 -0
  148. package/dist/post-preview/platforms/youtube.js +21 -0
  149. package/dist/post-preview/post-preview.d.ts +29 -0
  150. package/dist/post-preview/post-preview.js +70 -0
  151. package/dist/post-preview/public.d.ts +1 -0
  152. package/dist/post-preview/public.js +6 -0
  153. package/dist/post-preview/types.d.ts +82 -0
  154. package/dist/post-preview/types.js +1 -0
  155. package/dist/primitives/filter-rail.js +17 -2
  156. package/dist/shell/extras/shell-scrollable-content.js +2 -2
  157. package/dist/shell/extras/workbench-layout.js +24 -13
  158. package/dist/shell/right-panel.js +10 -1
  159. package/dist/shell/shell-header.js +1 -1
  160. package/dist/shell/theme-next-themes.js +2 -2
  161. package/dist/shell/theme.js +7 -1
  162. package/dist/timeline/lane-timeline.js +1 -1
  163. package/dist/timeline/scrub-bar.js +1 -1
  164. package/dist/timeline/timeline-tape.js +8 -5
  165. package/dist/voice/voice-orb-scene.js +4 -4
  166. package/dist/voice/voice-status-pill.js +8 -7
  167. package/dist/workflow-builder/edges/default-edge.d.ts +10 -0
  168. package/dist/workflow-builder/edges/default-edge.js +21 -0
  169. package/dist/workflow-builder/edges/index.d.ts +3 -0
  170. package/dist/workflow-builder/edges/index.js +5 -0
  171. package/dist/workflow-builder/index.d.ts +5 -0
  172. package/dist/workflow-builder/index.js +12 -0
  173. package/dist/workflow-builder/internal/trigger-icons.d.ts +4 -0
  174. package/dist/workflow-builder/internal/trigger-icons.js +43 -0
  175. package/dist/workflow-builder/internal/trigger-sentence.d.ts +14 -0
  176. package/dist/workflow-builder/internal/trigger-sentence.js +50 -0
  177. package/dist/workflow-builder/nodes/action-node.d.ts +3 -0
  178. package/dist/workflow-builder/nodes/action-node.js +7 -0
  179. package/dist/workflow-builder/nodes/base-node.d.ts +20 -0
  180. package/dist/workflow-builder/nodes/base-node.js +18 -0
  181. package/dist/workflow-builder/nodes/condition-node.d.ts +3 -0
  182. package/dist/workflow-builder/nodes/condition-node.js +11 -0
  183. package/dist/workflow-builder/nodes/delay-node.d.ts +3 -0
  184. package/dist/workflow-builder/nodes/delay-node.js +7 -0
  185. package/dist/workflow-builder/nodes/end-node.d.ts +3 -0
  186. package/dist/workflow-builder/nodes/end-node.js +7 -0
  187. package/dist/workflow-builder/nodes/index.d.ts +13 -0
  188. package/dist/workflow-builder/nodes/index.js +22 -0
  189. package/dist/workflow-builder/nodes/trigger-node.d.ts +3 -0
  190. package/dist/workflow-builder/nodes/trigger-node.js +8 -0
  191. package/dist/workflow-builder/public.d.ts +1 -0
  192. package/dist/workflow-builder/public.js +4 -0
  193. package/dist/workflow-builder/types.d.ts +140 -0
  194. package/dist/workflow-builder/types.js +18 -0
  195. package/dist/workflow-builder/workflow-builder.d.ts +10 -0
  196. package/dist/workflow-builder/workflow-builder.js +22 -0
  197. package/dist/workflow-builder/workflow-canvas.d.ts +26 -0
  198. package/dist/workflow-builder/workflow-canvas.js +25 -0
  199. package/dist/workflow-builder/workflow-card-compact.d.ts +2 -0
  200. package/dist/workflow-builder/workflow-card-compact.js +22 -0
  201. package/dist/workflow-builder/workflow-card.d.ts +2 -0
  202. package/dist/workflow-builder/workflow-card.js +44 -0
  203. package/dist/workflow-builder/workflow-header.d.ts +2 -0
  204. package/dist/workflow-builder/workflow-header.js +31 -0
  205. package/dist/workflow-builder/workflow-toolbox.d.ts +2 -0
  206. package/dist/workflow-builder/workflow-toolbox.js +19 -0
  207. package/package.json +72 -50
@@ -0,0 +1,2 @@
1
+ import { type CalendarToolbarProps } from './types.js';
2
+ export declare function CalendarToolbar({ date, view, onPrev, onNext, onToday, onViewChange, periodLabel, showViewSwitcher, locale, labels: labelOverrides, className, }: CalendarToolbarProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,22 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { ChevronLeft, ChevronRight } from 'lucide-react';
4
+ import { cn } from '../lib/utils.js';
5
+ import { formatMonthYear } from './internal/date.js';
6
+ import { DEFAULT_CALENDAR_LABELS } from './types.js';
7
+ const VIEW_ORDER = ['day', 'week', 'month'];
8
+ export function CalendarToolbar({ date, view, onPrev, onNext, onToday, onViewChange, periodLabel, showViewSwitcher = true, locale = 'en-US', labels: labelOverrides, className, }) {
9
+ const labels = { ...DEFAULT_CALENDAR_LABELS, ...labelOverrides };
10
+ const title = periodLabel ?? formatMonthYear(date, locale);
11
+ const viewLabel = {
12
+ day: labels.dayView,
13
+ week: labels.weekView,
14
+ month: labels.monthView,
15
+ };
16
+ return (_jsxs("div", { "data-slot": "calendar-toolbar", className: cn('flex flex-wrap items-center gap-2 border-border/70 border-b pb-2 text-left', className), children: [_jsxs("div", { className: "flex min-w-0 flex-1 flex-wrap items-center gap-1.5", children: [_jsx("button", { type: "button", onClick: onToday, className: cn('inline-flex h-9 min-h-[44px] min-w-[44px] items-center justify-center rounded-md border border-border bg-background px-3 font-medium text-xs', 'hover:bg-accent hover:text-accent-foreground'), children: labels.today }), _jsxs("div", { className: "inline-flex items-center rounded-md border border-border/70", children: [_jsx("button", { type: "button", onClick: onPrev, "aria-label": labels.previous, className: cn('inline-flex size-11 min-h-[44px] min-w-[44px] items-center justify-center rounded-l-md', 'text-muted-foreground hover:bg-accent hover:text-accent-foreground'), children: _jsx(ChevronLeft, { className: "size-4" }) }), _jsx("button", { type: "button", onClick: onNext, "aria-label": labels.next, className: cn('inline-flex size-11 min-h-[44px] min-w-[44px] items-center justify-center rounded-r-md border-border border-l', 'text-muted-foreground hover:bg-accent hover:text-accent-foreground'), children: _jsx(ChevronRight, { className: "size-4" }) })] }), _jsx("div", { className: "min-w-0", children: _jsx("p", { className: "truncate font-semibold text-foreground text-sm leading-tight @md/calendar:text-base", children: title }) })] }), showViewSwitcher && onViewChange && (_jsx("div", { className: "inline-flex rounded-md border border-border/70", children: VIEW_ORDER.map((v) => {
17
+ const isActive = v === view;
18
+ return (_jsx("button", { type: "button", "aria-pressed": isActive, onClick: () => onViewChange(v), className: cn('inline-flex h-9 min-h-[44px] min-w-[44px] items-center justify-center px-3 font-medium text-xs', 'first:rounded-l-md last:rounded-r-md not-last:border-border not-last:border-r', isActive
19
+ ? 'bg-primary text-primary-foreground'
20
+ : 'text-muted-foreground hover:bg-accent hover:text-accent-foreground'), children: viewLabel[v] }, v));
21
+ }) }))] }));
22
+ }
@@ -0,0 +1,2 @@
1
+ import { type CalendarProps } from './types.js';
2
+ export declare function Calendar({ view, date, events, onDateChange, onViewChange, onEventClick, onSlotClick, weekStartsOn, locale, labels: labelOverrides, className, renderEvent, }: CalendarProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,55 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useCallback } from 'react';
4
+ import { cn } from '../lib/utils.js';
5
+ import { CalendarToolbar } from './calendar-toolbar.js';
6
+ import { DayView } from './day-view.js';
7
+ import { addDays, addMonths } from './internal/date.js';
8
+ import { MonthView } from './month-view.js';
9
+ import { DEFAULT_CALENDAR_LABELS } from './types.js';
10
+ import { WeekView } from './week-view.js';
11
+ export function Calendar({ view = 'month', date, events, onDateChange, onViewChange, onEventClick, onSlotClick, weekStartsOn = 0, locale = 'en-US', labels: labelOverrides, className, renderEvent, }) {
12
+ const labels = { ...DEFAULT_CALENDAR_LABELS, ...labelOverrides };
13
+ const handlePrev = useCallback(() => {
14
+ if (!onDateChange)
15
+ return;
16
+ if (view === 'month') {
17
+ onDateChange(addMonths(date, -1));
18
+ }
19
+ else if (view === 'week') {
20
+ onDateChange(addDays(date, -7));
21
+ }
22
+ else {
23
+ onDateChange(addDays(date, -1));
24
+ }
25
+ }, [view, date, onDateChange]);
26
+ const handleNext = useCallback(() => {
27
+ if (!onDateChange)
28
+ return;
29
+ if (view === 'month') {
30
+ onDateChange(addMonths(date, 1));
31
+ }
32
+ else if (view === 'week') {
33
+ onDateChange(addDays(date, 7));
34
+ }
35
+ else {
36
+ onDateChange(addDays(date, 1));
37
+ }
38
+ }, [view, date, onDateChange]);
39
+ const handleToday = useCallback(() => {
40
+ onDateChange?.(new Date());
41
+ }, [onDateChange]);
42
+ const handleViewChange = useCallback((next) => {
43
+ onViewChange?.(next);
44
+ }, [onViewChange]);
45
+ const sharedProps = {
46
+ date,
47
+ events,
48
+ onEventClick,
49
+ onSlotClick,
50
+ locale,
51
+ labels,
52
+ renderEvent,
53
+ };
54
+ return (_jsxs("div", { "data-slot": "calendar", className: cn('@container/calendar flex flex-col gap-3', className), children: [_jsx(CalendarToolbar, { date: date, view: view, onPrev: handlePrev, onNext: handleNext, onToday: handleToday, onViewChange: onViewChange ? handleViewChange : undefined, locale: locale, labels: labels }), view === 'month' && (_jsx(MonthView, { ...sharedProps, weekStartsOn: weekStartsOn, onDateClick: onDateChange ? (d) => onDateChange(d) : undefined })), view === 'week' && (_jsx(WeekView, { ...sharedProps, weekStartsOn: weekStartsOn, onDateClick: onDateChange ? (d) => onDateChange(d) : undefined })), view === 'day' && _jsx(DayView, { ...sharedProps })] }));
55
+ }
@@ -0,0 +1,2 @@
1
+ import { type DayViewProps } from './types.js';
2
+ export declare function DayView({ date, events, onEventClick, onSlotClick, locale, labels: labelOverrides, className, renderEvent, }: DayViewProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,40 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useMemo } from 'react';
4
+ import { cn } from '../lib/utils.js';
5
+ import { formatDate, formatHour, getDateKey, getHoursOfDay, isToday } from './internal/date.js';
6
+ import { TimeSlot } from './internal/time-slot.js';
7
+ import { DEFAULT_CALENDAR_LABELS } from './types.js';
8
+ export function DayView({ date, events, onEventClick, onSlotClick, locale = 'en-US', labels: labelOverrides, className, renderEvent, }) {
9
+ const labels = { ...DEFAULT_CALENDAR_LABELS, ...labelOverrides };
10
+ const hours = useMemo(() => getHoursOfDay(), []);
11
+ const isTodayDate = isToday(date);
12
+ const eventsByHour = useMemo(() => {
13
+ const map = new Map();
14
+ const dateKey = getDateKey(date);
15
+ for (const event of events) {
16
+ if (event.allDay)
17
+ continue;
18
+ if (getDateKey(event.start) !== dateKey)
19
+ continue;
20
+ const hour = event.start.getHours();
21
+ const existing = map.get(hour) ?? [];
22
+ existing.push(event);
23
+ map.set(hour, existing);
24
+ }
25
+ for (const [hour, items] of map.entries()) {
26
+ items.sort((a, b) => a.start.getTime() - b.start.getTime());
27
+ map.set(hour, items);
28
+ }
29
+ return map;
30
+ }, [events, date]);
31
+ const totalEvents = useMemo(() => {
32
+ let count = 0;
33
+ for (const list of eventsByHour.values())
34
+ count += list.length;
35
+ return count;
36
+ }, [eventsByHour]);
37
+ return (_jsxs("section", { "data-slot": "calendar-day-view", "aria-label": labels.dayView, className: cn('@container/calendar overflow-hidden rounded-lg border border-border bg-background', className), children: [_jsx("div", { className: cn('border-border border-b bg-muted/50 px-4 py-3', isTodayDate && 'bg-primary/5'), children: _jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("div", { children: [_jsx("h3", { className: cn('font-semibold text-lg', isTodayDate ? 'text-primary' : 'text-foreground'), children: formatDate(date, { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' }, locale) }), isTodayDate && (_jsx("span", { className: "font-medium text-primary text-xs", children: labels.today }))] }), _jsx("div", { className: "text-muted-foreground text-sm", children: labels.eventCountLabel(totalEvents) })] }) }), _jsx("div", {
38
+ // biome-ignore lint/a11y/noNoninteractiveTabindex: scrollable region needs keyboard focus per WCAG (axe scrollable-region-focusable)
39
+ tabIndex: 0, className: "max-h-[36rem] overflow-y-auto focus:outline-none focus-visible:ring-2 focus-visible:ring-primary", children: hours.map((hour) => (_jsxs("div", { className: "grid grid-cols-[80px_1fr]", children: [_jsx("div", { className: "border-border border-r border-b px-3 py-3 text-right text-muted-foreground text-xs", children: formatHour(hour, locale) }), _jsx(TimeSlot, { date: date, hour: hour, events: eventsByHour.get(hour) ?? [], onSlotClick: onSlotClick, onEventClick: onEventClick, renderEvent: renderEvent, variant: "day" })] }, `row-${hour}`))) })] }));
40
+ }
@@ -0,0 +1,6 @@
1
+ export { Calendar } from './calendar.js';
2
+ export { CalendarToolbar } from './calendar-toolbar.js';
3
+ export { DayView } from './day-view.js';
4
+ export { MonthView } from './month-view.js';
5
+ export { type CalendarEvent, type CalendarLabels, type CalendarProps, type CalendarToolbarProps, type CalendarView, type DayViewProps, DEFAULT_CALENDAR_LABELS, type MonthViewProps, type WeekViewProps, } from './types.js';
6
+ export { WeekView } from './week-view.js';
@@ -0,0 +1,7 @@
1
+ // Subpath barrel for @medalsocial/meda/calendar.
2
+ export { Calendar } from './calendar.js';
3
+ export { CalendarToolbar } from './calendar-toolbar.js';
4
+ export { DayView } from './day-view.js';
5
+ export { MonthView } from './month-view.js';
6
+ export { DEFAULT_CALENDAR_LABELS, } from './types.js';
7
+ export { WeekView } from './week-view.js';
@@ -0,0 +1,26 @@
1
+ export type ResolvedWeekStartsOn = 0 | 1 | 2 | 3 | 4 | 5 | 6;
2
+ export declare function startOfDay(date: Date): Date;
3
+ export declare function endOfDay(date: Date): Date;
4
+ export declare function addDays(date: Date, amount: number): Date;
5
+ export declare function addMonths(date: Date, amount: number): Date;
6
+ export declare function startOfWeek(date: Date, weekStartsOn?: ResolvedWeekStartsOn): Date;
7
+ export declare function startOfMonth(date: Date): Date;
8
+ export declare function endOfMonth(date: Date): Date;
9
+ export declare function isSameDay(a: Date, b: Date): boolean;
10
+ export declare function isSameMonth(a: Date, b: Date): boolean;
11
+ export declare function isToday(date: Date, now?: Date): boolean;
12
+ export declare function isPast(date: Date, now?: Date): boolean;
13
+ export declare function setHours(date: Date, hour: number): Date;
14
+ export declare function getDateKey(input: Date | number): string;
15
+ export declare function getHoursOfDay(): number[];
16
+ export declare function getWeekDays(date: Date, weekStartsOn?: ResolvedWeekStartsOn): Date[];
17
+ /**
18
+ * Returns the 6-week (42 day) grid of dates for a month-view calendar.
19
+ * Always includes the trailing days of the previous month and leading days
20
+ * of the next month so the grid is always 7×6.
21
+ */
22
+ export declare function getMonthCalendarDays(date: Date, weekStartsOn?: ResolvedWeekStartsOn): Date[];
23
+ export declare function formatHour(hour: number, locale?: string): string;
24
+ export declare function formatDayOfWeek(date: Date, locale?: string, variant?: 'narrow' | 'short' | 'long'): string;
25
+ export declare function formatMonthYear(date: Date, locale?: string): string;
26
+ export declare function formatDate(date: Date, options: Intl.DateTimeFormatOptions, locale?: string): string;
@@ -0,0 +1,107 @@
1
+ // Small set of timezone-naive date helpers used by the calendar surface.
2
+ // These intentionally operate on local-time semantics (consumer-facing
3
+ // calendars are local-time by default). Add tz-awareness later if needed.
4
+ export function startOfDay(date) {
5
+ const d = new Date(date);
6
+ d.setHours(0, 0, 0, 0);
7
+ return d;
8
+ }
9
+ export function endOfDay(date) {
10
+ const d = new Date(date);
11
+ d.setHours(23, 59, 59, 999);
12
+ return d;
13
+ }
14
+ export function addDays(date, amount) {
15
+ const d = new Date(date);
16
+ d.setDate(d.getDate() + amount);
17
+ return d;
18
+ }
19
+ export function addMonths(date, amount) {
20
+ const d = new Date(date);
21
+ const day = d.getDate();
22
+ d.setDate(1);
23
+ d.setMonth(d.getMonth() + amount);
24
+ // Clamp to end-of-month if original day overflows
25
+ const lastDay = new Date(d.getFullYear(), d.getMonth() + 1, 0).getDate();
26
+ d.setDate(Math.min(day, lastDay));
27
+ return d;
28
+ }
29
+ export function startOfWeek(date, weekStartsOn = 0) {
30
+ const d = startOfDay(date);
31
+ const diff = (d.getDay() - weekStartsOn + 7) % 7;
32
+ d.setDate(d.getDate() - diff);
33
+ return d;
34
+ }
35
+ export function startOfMonth(date) {
36
+ const d = startOfDay(date);
37
+ d.setDate(1);
38
+ return d;
39
+ }
40
+ export function endOfMonth(date) {
41
+ const d = startOfDay(date);
42
+ d.setMonth(d.getMonth() + 1);
43
+ d.setDate(0);
44
+ d.setHours(23, 59, 59, 999);
45
+ return d;
46
+ }
47
+ export function isSameDay(a, b) {
48
+ return (a.getFullYear() === b.getFullYear() &&
49
+ a.getMonth() === b.getMonth() &&
50
+ a.getDate() === b.getDate());
51
+ }
52
+ export function isSameMonth(a, b) {
53
+ return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth();
54
+ }
55
+ export function isToday(date, now = new Date()) {
56
+ return isSameDay(date, now);
57
+ }
58
+ export function isPast(date, now = new Date()) {
59
+ return date.getTime() < startOfDay(now).getTime();
60
+ }
61
+ export function setHours(date, hour) {
62
+ const d = new Date(date);
63
+ d.setHours(hour, 0, 0, 0);
64
+ return d;
65
+ }
66
+ export function getDateKey(input) {
67
+ const d = input instanceof Date ? input : new Date(input);
68
+ // YYYY-MM-DD in local time
69
+ const y = d.getFullYear();
70
+ const m = `${d.getMonth() + 1}`.padStart(2, '0');
71
+ const day = `${d.getDate()}`.padStart(2, '0');
72
+ return `${y}-${m}-${day}`;
73
+ }
74
+ export function getHoursOfDay() {
75
+ return Array.from({ length: 24 }, (_, i) => i);
76
+ }
77
+ export function getWeekDays(date, weekStartsOn = 0) {
78
+ const start = startOfWeek(date, weekStartsOn);
79
+ return Array.from({ length: 7 }, (_, i) => addDays(start, i));
80
+ }
81
+ /**
82
+ * Returns the 6-week (42 day) grid of dates for a month-view calendar.
83
+ * Always includes the trailing days of the previous month and leading days
84
+ * of the next month so the grid is always 7×6.
85
+ */
86
+ export function getMonthCalendarDays(date, weekStartsOn = 0) {
87
+ const monthStart = startOfMonth(date);
88
+ const gridStart = startOfWeek(monthStart, weekStartsOn);
89
+ return Array.from({ length: 42 }, (_, i) => addDays(gridStart, i));
90
+ }
91
+ export function formatHour(hour, locale = 'en-US') {
92
+ const d = new Date();
93
+ d.setHours(hour, 0, 0, 0);
94
+ return new Intl.DateTimeFormat(locale, {
95
+ hour: 'numeric',
96
+ hour12: true,
97
+ }).format(d);
98
+ }
99
+ export function formatDayOfWeek(date, locale = 'en-US', variant = 'short') {
100
+ return new Intl.DateTimeFormat(locale, { weekday: variant }).format(date);
101
+ }
102
+ export function formatMonthYear(date, locale = 'en-US') {
103
+ return new Intl.DateTimeFormat(locale, { month: 'long', year: 'numeric' }).format(date);
104
+ }
105
+ export function formatDate(date, options, locale = 'en-US') {
106
+ return new Intl.DateTimeFormat(locale, options).format(date);
107
+ }
@@ -0,0 +1,15 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { CalendarEvent, CalendarLabels } from '../types.js';
3
+ interface DayCellProps {
4
+ date: Date;
5
+ currentMonth: Date;
6
+ events: CalendarEvent[];
7
+ onCellClick?: (date: Date) => void;
8
+ onEventClick?: (event: CalendarEvent) => void;
9
+ onMoreClick?: (date: Date, anchorEl?: HTMLElement) => void;
10
+ labels: CalendarLabels;
11
+ renderEvent?: (event: CalendarEvent) => ReactNode;
12
+ }
13
+ declare function DayCellBase({ date, currentMonth, events, onCellClick, onEventClick, onMoreClick, labels, renderEvent, }: DayCellProps): import("react/jsx-runtime").JSX.Element;
14
+ export declare const DayCell: import("react").MemoExoticComponent<typeof DayCellBase>;
15
+ export {};
@@ -0,0 +1,38 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { memo } from 'react';
4
+ import { cn } from '../../lib/utils.js';
5
+ import { isPast, isSameMonth, isToday } from './date.js';
6
+ import { EventPill } from './event-pill.js';
7
+ const MAX_VISIBLE_ITEMS = 3;
8
+ function DayCellBase({ date, currentMonth, events, onCellClick, onEventClick, onMoreClick, labels, renderEvent, }) {
9
+ const isCurrentMonth = isSameMonth(date, currentMonth);
10
+ const isTodayDate = isToday(date);
11
+ const isPastDate = isPast(date);
12
+ const dayNumber = date.getDate();
13
+ const visibleEvents = events.slice(0, MAX_VISIBLE_ITEMS);
14
+ const hiddenCount = events.length - MAX_VISIBLE_ITEMS;
15
+ const isCellInteractive = typeof onCellClick === 'function';
16
+ let dayNumberClass;
17
+ if (isTodayDate) {
18
+ dayNumberClass = 'border border-primary/40 bg-primary/15 text-primary';
19
+ }
20
+ else if (isCurrentMonth) {
21
+ dayNumberClass = 'text-foreground';
22
+ }
23
+ else {
24
+ dayNumberClass = 'text-muted-foreground';
25
+ }
26
+ return (_jsxs("div", { "data-slot": "calendar-day-cell", "data-today": isTodayDate ? 'true' : undefined, onClick: isCellInteractive
27
+ ? (event) => {
28
+ const target = event.target;
29
+ if (target.closest('[data-calendar-item="true"]'))
30
+ return;
31
+ onCellClick(date);
32
+ }
33
+ : undefined, className: cn('group relative flex min-h-[5.5rem] flex-col gap-1 border-border border-r border-b p-1.5 transition-colors', '@md/calendar:min-h-[6.75rem]', isCurrentMonth ? 'bg-background' : 'bg-muted/30', isPastDate && isCurrentMonth && 'bg-muted/20', isTodayDate && 'border-primary/30 bg-primary/5', 'hover:bg-accent/30', isCellInteractive && 'cursor-pointer'), children: [_jsx("div", { className: "flex items-center justify-between", children: _jsx("span", { className: cn('inline-flex size-6 items-center justify-center rounded-full font-medium text-xs', dayNumberClass), children: dayNumber }) }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [visibleEvents.map((event) => (_jsx("div", { children: renderEvent ? renderEvent(event) : _jsx(EventPill, { event: event, onClick: onEventClick }) }, event.id))), hiddenCount > 0 && (_jsx("button", { type: "button", onClick: (event) => {
34
+ event.stopPropagation();
35
+ onMoreClick?.(date, event.currentTarget);
36
+ }, className: cn('min-h-[24px] w-full rounded px-1 py-0.5 text-left font-medium text-[11px]', 'text-primary transition-colors hover:bg-primary/10'), children: labels.moreCount(hiddenCount) }))] })] }));
37
+ }
38
+ export const DayCell = memo(DayCellBase);
@@ -0,0 +1,13 @@
1
+ import type { CalendarEvent } from '../types.js';
2
+ interface EventPillProps {
3
+ event: CalendarEvent;
4
+ onClick?: (event: CalendarEvent) => void;
5
+ variant?: 'compact' | 'full';
6
+ className?: string;
7
+ }
8
+ /**
9
+ * Default compact event pill used inside calendar cells/slots when the
10
+ * consumer does not pass a custom `renderEvent` callback.
11
+ */
12
+ export declare function EventPill({ event, onClick, variant, className }: EventPillProps): import("react/jsx-runtime").JSX.Element;
13
+ export {};
@@ -0,0 +1,30 @@
1
+ 'use client';
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { cn } from '../../lib/utils.js';
4
+ /**
5
+ * Default compact event pill used inside calendar cells/slots when the
6
+ * consumer does not pass a custom `renderEvent` callback.
7
+ */
8
+ export function EventPill({ event, onClick, variant = 'compact', className }) {
9
+ const isInteractive = typeof onClick === 'function';
10
+ // Apply consumer color as the left-border accent only — using it as a
11
+ // background risks color-contrast failures with the default foreground
12
+ // text. Consumers wanting full color fills should pass a custom renderEvent.
13
+ const style = event.color ? { borderLeftColor: event.color } : undefined;
14
+ const content = variant === 'compact' ? (_jsx("span", { className: "block truncate font-medium text-[11px] leading-tight", children: event.title })) : (_jsxs(_Fragment, { children: [_jsx("span", { className: "block truncate font-medium text-xs leading-tight", children: event.title }), event.allDay ? null : (_jsx("span", { className: "block text-[10px] text-muted-foreground tabular-nums", children: formatRange(event) }))] }));
15
+ if (isInteractive) {
16
+ return (_jsx("button", { type: "button", "data-slot": "calendar-event", "data-calendar-item": "true", onClick: (e) => {
17
+ e.stopPropagation();
18
+ onClick(event);
19
+ }, style: style, className: cn('block w-full min-h-[24px] rounded border-l-2 bg-accent px-1.5 py-0.5 text-left', 'border-primary text-accent-foreground transition-colors', 'hover:bg-accent/80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary', className), children: content }));
20
+ }
21
+ return (_jsx("div", { "data-slot": "calendar-event", "data-calendar-item": "true", style: style, className: cn('block w-full min-h-[24px] rounded border-l-2 bg-accent px-1.5 py-0.5', 'border-primary text-accent-foreground', className), children: content }));
22
+ }
23
+ function formatRange(event) {
24
+ const start = event.start;
25
+ const end = event.end;
26
+ const fmt = (d) => new Intl.DateTimeFormat('en-US', { hour: 'numeric', minute: '2-digit', hour12: true }).format(d);
27
+ if (!end)
28
+ return fmt(start);
29
+ return `${fmt(start)} – ${fmt(end)}`;
30
+ }
@@ -0,0 +1,17 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { CalendarEvent } from '../types.js';
3
+ interface TimeSlotProps {
4
+ date: Date;
5
+ hour: number;
6
+ events: CalendarEvent[];
7
+ onSlotClick?: (slot: {
8
+ start: Date;
9
+ end: Date;
10
+ }) => void;
11
+ onEventClick?: (event: CalendarEvent) => void;
12
+ renderEvent?: (event: CalendarEvent) => ReactNode;
13
+ variant?: 'week' | 'day';
14
+ }
15
+ declare function TimeSlotBase({ date, hour, events, onSlotClick, onEventClick, renderEvent, variant, }: TimeSlotProps): import("react/jsx-runtime").JSX.Element;
16
+ export declare const TimeSlot: import("react").MemoExoticComponent<typeof TimeSlotBase>;
17
+ export {};
@@ -0,0 +1,23 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { memo } from 'react';
4
+ import { cn } from '../../lib/utils.js';
5
+ import { isPast, isToday, setHours } from './date.js';
6
+ import { EventPill } from './event-pill.js';
7
+ function TimeSlotBase({ date, hour, events, onSlotClick, onEventClick, renderEvent, variant = 'week', }) {
8
+ const slotStart = setHours(date, hour);
9
+ const slotEnd = setHours(date, hour + 1);
10
+ const isPastSlot = isPast(slotStart) || (isToday(date) && hour < new Date().getHours());
11
+ const isTodayDate = isToday(date);
12
+ const isCurrentHour = isTodayDate && hour === new Date().getHours();
13
+ const isInteractive = typeof onSlotClick === 'function';
14
+ return (_jsxs("div", { "data-slot": "calendar-time-slot", "data-current-hour": isCurrentHour ? 'true' : undefined, onClick: isInteractive
15
+ ? (event) => {
16
+ const target = event.target;
17
+ if (target.closest('[data-calendar-item="true"]'))
18
+ return;
19
+ onSlotClick({ start: slotStart, end: slotEnd });
20
+ }
21
+ : undefined, className: cn('group relative border-border border-b p-1 transition-colors', variant === 'week' ? 'min-h-[44px] border-r last:border-r-0' : 'min-h-[60px]', isPastSlot ? 'bg-muted/20' : 'bg-background', isCurrentHour && 'bg-primary/5', !isPastSlot && 'hover:bg-accent/30', isInteractive && 'cursor-pointer'), children: [isCurrentHour && (_jsx("div", { className: "pointer-events-none absolute top-1/2 right-0 left-0 z-10 -translate-y-1/2", children: _jsx("div", { className: "relative h-0.5 bg-primary", children: _jsx("div", { className: "absolute -top-1 -left-1 size-2.5 rounded-full bg-primary" }) }) })), _jsx("div", { className: "flex flex-col gap-1", children: events.map((event) => (_jsx("div", { children: renderEvent ? renderEvent(event) : _jsx(EventPill, { event: event, onClick: onEventClick }) }, event.id))) })] }));
22
+ }
23
+ export const TimeSlot = memo(TimeSlotBase);
@@ -0,0 +1,2 @@
1
+ import { type MonthViewProps } from './types.js';
2
+ export declare function MonthView({ date, events, onEventClick, onDateClick, onSlotClick, weekStartsOn, locale, labels: labelOverrides, className, renderEvent, }: MonthViewProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,46 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useMemo } from 'react';
4
+ import { cn } from '../lib/utils.js';
5
+ import { addDays, formatDayOfWeek, getDateKey, getMonthCalendarDays, startOfWeek, } from './internal/date.js';
6
+ import { DayCell } from './internal/day-cell.js';
7
+ import { DEFAULT_CALENDAR_LABELS } from './types.js';
8
+ export function MonthView({ date, events, onEventClick, onDateClick, onSlotClick, weekStartsOn = 0, locale = 'en-US', labels: labelOverrides, className, renderEvent, }) {
9
+ const labels = { ...DEFAULT_CALENDAR_LABELS, ...labelOverrides };
10
+ const calendarDays = useMemo(() => getMonthCalendarDays(date, weekStartsOn), [date, weekStartsOn]);
11
+ const eventsByDate = useMemo(() => {
12
+ const map = new Map();
13
+ for (const event of events) {
14
+ const key = getDateKey(event.start);
15
+ const existing = map.get(key) ?? [];
16
+ existing.push(event);
17
+ map.set(key, existing);
18
+ }
19
+ for (const [key, dayEvents] of map.entries()) {
20
+ dayEvents.sort((a, b) => a.start.getTime() - b.start.getTime());
21
+ map.set(key, dayEvents);
22
+ }
23
+ return map;
24
+ }, [events]);
25
+ const weekDays = useMemo(() => {
26
+ const baseDate = startOfWeek(new Date(2024, 0, 7), weekStartsOn);
27
+ return Array.from({ length: 7 }, (_, i) => formatDayOfWeek(addDays(baseDate, i), locale, 'short'));
28
+ }, [locale, weekStartsOn]);
29
+ let cellClick;
30
+ if (onDateClick) {
31
+ cellClick = (d) => onDateClick(d);
32
+ }
33
+ else if (onSlotClick) {
34
+ cellClick = (d) => {
35
+ const start = new Date(d);
36
+ start.setHours(0, 0, 0, 0);
37
+ const end = new Date(d);
38
+ end.setHours(23, 59, 59, 999);
39
+ onSlotClick({ start, end });
40
+ };
41
+ }
42
+ else {
43
+ cellClick = undefined;
44
+ }
45
+ return (_jsxs("div", { "data-slot": "calendar-month-view", className: cn('@container/calendar overflow-hidden rounded-md border border-border bg-background', className), children: [_jsx("div", { className: "grid grid-cols-7 border-border border-b bg-muted/40", children: weekDays.map((day) => (_jsx("div", { className: "border-border border-r px-1 py-1.5 text-center font-medium text-muted-foreground text-[11px] uppercase tracking-wide last:border-r-0", children: day }, `header-${day}`))) }), _jsx("div", { className: "grid grid-cols-7", children: calendarDays.map((d) => (_jsx(DayCell, { date: d, currentMonth: date, events: eventsByDate.get(getDateKey(d)) ?? [], onCellClick: cellClick, onEventClick: onEventClick, onMoreClick: onDateClick, labels: labels, renderEvent: renderEvent }, `day-${getDateKey(d)}`))) })] }));
46
+ }
@@ -0,0 +1,6 @@
1
+ export { Calendar } from './calendar.js';
2
+ export { CalendarToolbar } from './calendar-toolbar.js';
3
+ export { DayView } from './day-view.js';
4
+ export { MonthView } from './month-view.js';
5
+ export { type CalendarEvent, type CalendarLabels, type CalendarProps, type CalendarToolbarProps, type CalendarView, type DayViewProps, DEFAULT_CALENDAR_LABELS, type MonthViewProps, type WeekViewProps, } from './types.js';
6
+ export { WeekView } from './week-view.js';
@@ -0,0 +1,8 @@
1
+ // Root re-export for @medalsocial/meda — keeps the calendar surface accessible
2
+ // from the package root in addition to the @medalsocial/meda/calendar subpath.
3
+ export { Calendar } from './calendar.js';
4
+ export { CalendarToolbar } from './calendar-toolbar.js';
5
+ export { DayView } from './day-view.js';
6
+ export { MonthView } from './month-view.js';
7
+ export { DEFAULT_CALENDAR_LABELS, } from './types.js';
8
+ export { WeekView } from './week-view.js';
@@ -0,0 +1,113 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { ResolvedWeekStartsOn } from './internal/date.js';
3
+ export type CalendarView = 'month' | 'week' | 'day';
4
+ export interface CalendarEvent {
5
+ id: string;
6
+ title: string;
7
+ /** Event start time. */
8
+ start: Date;
9
+ /** Event end time. Optional; defaults to start + 1h when used. */
10
+ end?: Date;
11
+ /** Optional brand color, any CSS color string (hex, rgb, var()). */
12
+ color?: string;
13
+ /** Render as an all-day event (skips hour bucketing in week/day views). */
14
+ allDay?: boolean;
15
+ /** Consumer-defined extra payload — passed back via callbacks. */
16
+ data?: unknown;
17
+ }
18
+ export interface CalendarLabels {
19
+ today: string;
20
+ previous: string;
21
+ next: string;
22
+ monthView: string;
23
+ weekView: string;
24
+ dayView: string;
25
+ noEvents: string;
26
+ /** Called as `moreCount(n)` to render "+N more" labels. */
27
+ moreCount: (count: number) => string;
28
+ /** Called as `eventCountLabel(n)` to render "N events" descriptions. */
29
+ eventCountLabel: (count: number) => string;
30
+ addEvent: string;
31
+ viewDay: string;
32
+ close: string;
33
+ }
34
+ export declare const DEFAULT_CALENDAR_LABELS: CalendarLabels;
35
+ export interface CalendarProps {
36
+ view?: CalendarView;
37
+ /** Currently focused date. */
38
+ date: Date;
39
+ events: CalendarEvent[];
40
+ onDateChange?: (date: Date) => void;
41
+ onViewChange?: (view: CalendarView) => void;
42
+ onEventClick?: (event: CalendarEvent) => void;
43
+ /** Fires when the user clicks a free time slot (week/day view) or a date cell (month view). */
44
+ onSlotClick?: (slot: {
45
+ start: Date;
46
+ end: Date;
47
+ }) => void;
48
+ /** First day of the week. 0 = Sunday, 1 = Monday. Default 0. */
49
+ weekStartsOn?: ResolvedWeekStartsOn;
50
+ /** BCP-47 locale for header formatting. Default 'en-US'. */
51
+ locale?: string;
52
+ labels?: Partial<CalendarLabels>;
53
+ className?: string;
54
+ /** Optional custom event renderer. */
55
+ renderEvent?: (event: CalendarEvent) => ReactNode;
56
+ }
57
+ export interface MonthViewProps {
58
+ date: Date;
59
+ events: CalendarEvent[];
60
+ onEventClick?: (event: CalendarEvent) => void;
61
+ onDateClick?: (date: Date) => void;
62
+ onSlotClick?: (slot: {
63
+ start: Date;
64
+ end: Date;
65
+ }) => void;
66
+ weekStartsOn?: ResolvedWeekStartsOn;
67
+ locale?: string;
68
+ labels?: Partial<CalendarLabels>;
69
+ className?: string;
70
+ renderEvent?: (event: CalendarEvent) => ReactNode;
71
+ }
72
+ export interface WeekViewProps {
73
+ date: Date;
74
+ events: CalendarEvent[];
75
+ onEventClick?: (event: CalendarEvent) => void;
76
+ onSlotClick?: (slot: {
77
+ start: Date;
78
+ end: Date;
79
+ }) => void;
80
+ onDateClick?: (date: Date) => void;
81
+ weekStartsOn?: ResolvedWeekStartsOn;
82
+ locale?: string;
83
+ labels?: Partial<CalendarLabels>;
84
+ className?: string;
85
+ renderEvent?: (event: CalendarEvent) => ReactNode;
86
+ }
87
+ export interface DayViewProps {
88
+ date: Date;
89
+ events: CalendarEvent[];
90
+ onEventClick?: (event: CalendarEvent) => void;
91
+ onSlotClick?: (slot: {
92
+ start: Date;
93
+ end: Date;
94
+ }) => void;
95
+ locale?: string;
96
+ labels?: Partial<CalendarLabels>;
97
+ className?: string;
98
+ renderEvent?: (event: CalendarEvent) => ReactNode;
99
+ }
100
+ export interface CalendarToolbarProps {
101
+ date: Date;
102
+ view: CalendarView;
103
+ onPrev: () => void;
104
+ onNext: () => void;
105
+ onToday: () => void;
106
+ onViewChange?: (view: CalendarView) => void;
107
+ /** Override the auto-formatted period title (e.g. "April 2026"). */
108
+ periodLabel?: string;
109
+ showViewSwitcher?: boolean;
110
+ locale?: string;
111
+ labels?: Partial<CalendarLabels>;
112
+ className?: string;
113
+ }
@@ -0,0 +1,15 @@
1
+ // Public types for the @medalsocial/meda/calendar surface.
2
+ export const DEFAULT_CALENDAR_LABELS = {
3
+ today: 'Today',
4
+ previous: 'Previous',
5
+ next: 'Next',
6
+ monthView: 'Month',
7
+ weekView: 'Week',
8
+ dayView: 'Day',
9
+ noEvents: 'No events',
10
+ moreCount: (count) => `+${count} more`,
11
+ eventCountLabel: (count) => `${count} ${count === 1 ? 'event' : 'events'}`,
12
+ addEvent: 'Add event',
13
+ viewDay: 'View day',
14
+ close: 'Close',
15
+ };
@@ -0,0 +1,2 @@
1
+ import { type WeekViewProps } from './types.js';
2
+ export declare function WeekView({ date, events, onEventClick, onSlotClick, onDateClick, weekStartsOn, locale, labels: labelOverrides, className, renderEvent, }: WeekViewProps): import("react/jsx-runtime").JSX.Element;