@dayflow/plugin-sidebar 1.0.2 → 1.1.1

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/README.md CHANGED
@@ -2,8 +2,7 @@
2
2
 
3
3
  **English** | [中文](README.zh.md) | [日本語](README.ja.md) | [Getting Started & Contributing](CONTRIBUTING.md)
4
4
 
5
- A flexible and feature-rich calendar component library for React applications with drag-and-drop support, multiple
6
- views, and plugin architecture.
5
+ A flexible and feature-rich calendar component library for **React, Vue, Angular, and Svelte** with drag-and-drop support, multiple views, and plugin architecture.
7
6
 
8
7
  [![npm](https://img.shields.io/npm/v/@dayflow/core?logo=npm&color=blue&label=version)](https://www.npmjs.com/package/@dayflow/core)
9
8
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen?logo=github)](https://github.com/dayflow-js/dayflow/pulls)
@@ -12,21 +11,51 @@ views, and plugin architecture.
12
11
 
13
12
  ## Features
14
13
 
15
- ### Monthly, Weekly, Daily and Various View Types
14
+ ### Daily, Weekly, Monthly and Yearly View Types
16
15
 
17
- | Monthly | Weekly |
18
- | --------------------------------------- | -------------------------------------- |
19
- | ![image](https://raw.githubusercontent.com/dayflow-js/calendar/main/assets/images/MonthView.png) | ![image](https://raw.githubusercontent.com/dayflow-js/calendar/main/assets/images/WeekView.png) |
16
+ #### Day View
20
17
 
21
- | Daily | Event Stack Level |
22
- | ------------------------------------- | ---------------------------------------- |
23
- | ![image](https://raw.githubusercontent.com/dayflow-js/calendar/main/assets/images/DayView.png) | ![image](https://raw.githubusercontent.com/dayflow-js/calendar/main/assets/images/stackLevel.png) |
18
+ ![Day View](https://raw.githubusercontent.com/dayflow-js/calendar/main/assets/images/DayView.png)
24
19
 
25
- ### Default Panel (with multiple Event Detail Panel options available)
20
+ #### Week View
26
21
 
27
- | Detail Popup | Detail Dialog |
28
- | ----------------------------------- | ------------------------------------ |
29
- | ![image](https://raw.githubusercontent.com/dayflow-js/calendar/main/assets/images/popup.png) | ![image](https://raw.githubusercontent.com/dayflow-js/calendar/main/assets/images/dialog.png) |
22
+ ![Week View](https://raw.githubusercontent.com/dayflow-js/calendar/main/assets/images/WeekView.png)
23
+
24
+ #### Month View
25
+
26
+ ![Month View](https://raw.githubusercontent.com/dayflow-js/calendar/main/assets/images/MonthView.png)
27
+
28
+ #### Year View(Fixed-Week)
29
+
30
+ ![Year View](https://raw.githubusercontent.com/dayflow-js/calendar/main/assets/images/Year-Fixed-Week.png)
31
+
32
+ #### Year View(Year-Canvas)
33
+
34
+ ![Year Canvas View](https://raw.githubusercontent.com/dayflow-js/calendar/main/assets/images/Year-Canvas.png)
35
+
36
+ ### Mobile View Support
37
+
38
+ #### Mobile Day & Year View
39
+
40
+ ![Mobile Day and Year View](https://raw.githubusercontent.com/dayflow-js/calendar/main/assets/images/Mobile-Day-Year.png)
41
+
42
+ #### Mobile Week & Month View
43
+
44
+ ![Mobile Week and Month View](https://raw.githubusercontent.com/dayflow-js/calendar/main/assets/images/Mobile-Week-Month.png)
45
+
46
+ ### Multiple Event Detail Panel options
47
+
48
+ #### Detail Popup
49
+
50
+ ![Popup](https://raw.githubusercontent.com/dayflow-js/calendar/main/assets/images/popup.png)
51
+
52
+ #### Detail Dialog
53
+
54
+ ![Dialog](https://raw.githubusercontent.com/dayflow-js/calendar/main/assets/images/dialog.png)
55
+
56
+ ### Dark Mode Support
57
+
58
+ ![Dark Mode](https://raw.githubusercontent.com/dayflow-js/calendar/main/assets/images/DarkMode.png)
30
59
 
31
60
  ### Easy to resize and drag
32
61
 
package/dist/index.d.ts CHANGED
@@ -13,14 +13,12 @@ interface CalendarSidebarRenderProps {
13
13
  editingCalendarId?: string | null;
14
14
  setEditingCalendarId?: (id: string | null) => void;
15
15
  onCreateCalendar?: () => void;
16
- colorPickerMode?: 'default' | 'custom';
17
16
  }
18
17
  interface SidebarPluginConfig {
19
18
  width?: number | string;
20
19
  miniWidth?: string;
21
20
  initialCollapsed?: boolean;
22
21
  createCalendarMode?: 'inline' | 'modal';
23
- colorPickerMode?: 'default' | 'custom';
24
22
  render?: (props: CalendarSidebarRenderProps) => TNode;
25
23
  renderCalendarContextMenu?: (calendar: CalendarType, onClose: () => void) => TNode;
26
24
  renderCreateCalendarDialog?: (props: CreateCalendarDialogProps) => TNode;
package/dist/index.esm.js CHANGED
@@ -1,6 +1,6 @@
1
+ import { useLocale, createPortal, cancelButton, ChevronsUpDown, Check, ChevronRight, sidebarHeader, sidebarHeaderToggle, PanelRightClose, PanelRightOpen, sidebarHeaderTitle, getCalendarColorsForHex, generateUniKey, downloadICS, MiniCalendar, ContextMenu, ContentSlot, ContextMenuLabel, ContextMenuItem, ContextMenuSeparator, ContextMenuColorPicker, DefaultColorPicker, BlossomColorPicker, importICSFile, sidebarContainer, normalizeCssWidth, registerSidebarImplementation, CreateCalendarDialog } from '@dayflow/core';
1
2
  import { options, Fragment, h } from 'preact';
2
3
  import { useState, useRef, useCallback, useEffect, useMemo } from 'preact/hooks';
3
- import { useLocale, sidebarHeader, sidebarHeaderToggle, PanelRightClose, PanelRightOpen, sidebarHeaderTitle, ChevronRight, createPortal, cancelButton, ChevronsUpDown, Check, getCalendarColorsForHex, generateUniKey, downloadICS, MiniCalendar, ContextMenu, ContentSlot, ContextMenuLabel, ContextMenuItem, ContextMenuSeparator, ContextMenuColorPicker, BlossomColorPicker, DefaultColorPicker, importICSFile, sidebarContainer, normalizeCssWidth, registerSidebarImplementation, CreateCalendarDialog } from '@dayflow/core';
4
4
  import { hexToHsl, lightnessToSliderValue } from '@dayflow/blossom-color-picker';
5
5
 
6
6
  /******************************************************************************
@@ -37,11 +37,6 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
37
37
 
38
38
  var f=0;function u(e,t,n,o,i,u){t||(t={});var a,c,p=t;if("ref"in p)for(c in p={},t)"ref"==c?a=t[c]:p[c]=t[c];var l={type:e,props:p,key:n,ref:a,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:--f,__i:-1,__u:0,__source:i,__self:u};if("function"==typeof e&&(a=e.defaultProps))for(c in a) void 0===p[c]&&(p[c]=a[c]);return options.vnode&&options.vnode(l),l}
39
39
 
40
- const SidebarHeader = ({ isCollapsed, onCollapseToggle, }) => {
41
- const { t } = useLocale();
42
- return (u("div", { className: sidebarHeader, children: [u("button", { type: "button", "aria-label": isCollapsed ? t('expandSidebar') : t('collapseSidebar'), className: sidebarHeaderToggle, onClick: onCollapseToggle, children: isCollapsed ? (u(PanelRightClose, { className: "h-4 w-4 text-gray-500 dark:text-gray-400" })) : (u(PanelRightOpen, { className: "h-4 w-4 text-gray-500 dark:text-gray-400" })) }), !isCollapsed && (u("div", { className: "flex flex-1 justify-between items-center ml-3", children: u("span", { className: sidebarHeaderTitle, children: t('calendars') }) }))] }));
43
- };
44
-
45
40
  const getCalendarInitials = (calendar) => {
46
41
  if (calendar.icon) {
47
42
  return calendar.icon;
@@ -70,9 +65,11 @@ const CalendarList = ({ calendars, onToggleVisibility, onReorder, onRename, onCo
70
65
  calendarColors: calendar.colors,
71
66
  calendarIcon: calendar.icon,
72
67
  };
73
- e.dataTransfer.setData('application/x-dayflow-calendar', JSON.stringify(dragData));
74
- e.dataTransfer.effectAllowed = 'copy';
75
- }, [editingId]);
68
+ if (e.dataTransfer) {
69
+ e.dataTransfer.setData('application/x-dayflow-calendar', JSON.stringify(dragData));
70
+ e.dataTransfer.effectAllowed = 'copy';
71
+ }
72
+ }, [editingId, isDraggable]);
76
73
  const handleDragEnd = useCallback(() => {
77
74
  setDraggedCalendarId(null);
78
75
  setDropTarget(null);
@@ -172,7 +169,7 @@ const CalendarList = ({ calendars, onToggleVisibility, onReorder, onRename, onCo
172
169
  }
173
170
  }
174
171
  }, [editingId, calendars]);
175
- return (u("div", { className: "df-calendar-list flex-1 overflow-y-auto px-2 pb-3", children: u("ul", { className: "space-y-1 relative", children: calendars.map(calendar => {
172
+ return (u("div", { className: 'df-calendar-list flex-1 overflow-y-auto px-2 pb-3', children: u("ul", { className: 'relative space-y-1', children: calendars.map(calendar => {
176
173
  var _a;
177
174
  const isVisible = calendar.isVisible !== false;
178
175
  const calendarColor = ((_a = calendar.colors) === null || _a === void 0 ? void 0 : _a.lineColor) || '#3b82f6';
@@ -180,69 +177,23 @@ const CalendarList = ({ calendars, onToggleVisibility, onReorder, onRename, onCo
180
177
  const isDropTarget = (dropTarget === null || dropTarget === void 0 ? void 0 : dropTarget.id) === calendar.id;
181
178
  const isActive = activeContextMenuCalendarId === calendar.id ||
182
179
  editingId === calendar.id;
183
- return (u("li", { className: "df-calendar-list-item relative", onDragOver: e => handleDragOver(e, calendar.id), onDragLeave: handleDragLeave, onDrop: () => handleDrop(calendar), onContextMenu: e => onContextMenu(e, calendar.id), children: [isDropTarget && dropTarget.position === 'top' && (u("div", { className: "absolute top-0 left-0 right-0 h-0.5 bg-primary z-10 pointer-events-none" })), u("div", { draggable: isDraggable && !editingId, onDragStart: e => handleDragStart(calendar, e), onDragEnd: handleDragEnd, className: `rounded transition ${draggedCalendarId === calendar.id ? 'opacity-50' : ''} ${isDraggable ? 'cursor-grab' : 'cursor-default'}`, children: u("div", { className: `group flex items-center rounded px-2 py-2 transition hover:bg-gray-100 dark:hover:bg-slate-800 ${isActive ? 'bg-gray-100 dark:bg-slate-800' : ''}`, title: calendar.name, children: [u("input", { type: "checkbox", className: "calendar-checkbox cursor-pointer shrink-0", style: {
180
+ return (u("li", { className: 'df-calendar-list-item relative', onDragOver: e => handleDragOver(e, calendar.id), onDragLeave: handleDragLeave, onDrop: () => handleDrop(calendar), onContextMenu: e => onContextMenu(e, calendar.id), children: [isDropTarget && dropTarget.position === 'top' && (u("div", { className: 'pointer-events-none absolute top-0 right-0 left-0 z-10 h-0.5 bg-primary' })), u("div", { draggable: isDraggable && !editingId, onDragStart: e => handleDragStart(calendar, e), onDragEnd: handleDragEnd, className: `rounded transition ${draggedCalendarId === calendar.id ? 'opacity-50' : ''} ${isDraggable ? 'cursor-grab' : 'cursor-default'}`, children: u("div", { className: `group flex items-center rounded px-2 py-2 transition hover:bg-gray-100 dark:hover:bg-slate-800 ${isActive ? 'bg-gray-100 dark:bg-slate-800' : ''}`, title: calendar.name, children: [u("input", { type: 'checkbox', className: 'calendar-checkbox shrink-0 cursor-pointer', style: {
184
181
  '--checkbox-color': calendarColor,
185
- }, checked: isVisible, onChange: event => onToggleVisibility(calendar.id, event.target.checked) }), showIcon && (u("span", { className: "ml-2 flex h-5 w-5 shrink-0 items-center justify-center text-xs font-semibold text-white", "aria-hidden": "true", children: getCalendarInitials(calendar) })), editingId === calendar.id ? (u("input", { ref: editInputRef, type: "text", value: editingName, onChange: e => setEditingName(e.target.value), onBlur: handleRenameSave, onKeyDown: handleRenameKeyDown, className: "ml-2 flex-1 min-w-0 h-5 rounded bg-white px-0 py-0 text-sm text-gray-900 focus:outline-none dark:bg-slate-700 dark:text-gray-100", onClick: e => e.stopPropagation() })) : (u("span", { className: "flex-1 pl-1 truncate text-sm text-gray-700 group-hover:text-gray-900 dark:text-gray-200 dark:group-hover:text-white ml-2", onDblClick: () => handleRenameStart(calendar), children: calendar.name || calendar.id }))] }) }), isDropTarget && dropTarget.position === 'bottom' && (u("div", { className: "absolute bottom-0 left-0 right-0 h-0.5 bg-primary z-10 pointer-events-none" }))] }, calendar.id));
182
+ }, checked: isVisible, onChange: event => onToggleVisibility(calendar.id, event.target.checked) }), showIcon && (u("span", { className: 'ml-2 flex h-5 w-5 shrink-0 items-center justify-center text-xs font-semibold text-white', "aria-hidden": 'true', children: getCalendarInitials(calendar) })), editingId === calendar.id ? (u("input", { ref: editInputRef, type: 'text', value: editingName, onChange: e => setEditingName(e.target.value), onBlur: handleRenameSave, onKeyDown: handleRenameKeyDown, className: 'ml-2 h-5 min-w-0 flex-1 rounded bg-white px-0 py-0 text-sm text-gray-900 focus:outline-none dark:bg-slate-700 dark:text-gray-100', onClick: e => e.stopPropagation() })) : (u("span", { className: 'ml-2 flex-1 truncate pl-1 text-sm text-gray-700 group-hover:text-gray-900 dark:text-gray-200 dark:group-hover:text-white', onDblClick: () => handleRenameStart(calendar), children: calendar.name || calendar.id }))] }) }), isDropTarget && dropTarget.position === 'bottom' && (u("div", { className: 'pointer-events-none absolute right-0 bottom-0 left-0 z-10 h-0.5 bg-primary' }))] }, calendar.id));
186
183
  }) }) }));
187
184
  };
188
185
 
189
- const MergeMenuItem = ({ calendars, currentCalendarId, onMergeSelect, }) => {
190
- const { t } = useLocale();
191
- const [isHovered, setIsHovered] = useState(false);
192
- const itemRef = useRef(null);
193
- const submenuRef = useRef(null);
194
- const [position, setPosition] = useState({ x: 0, y: 0 });
195
- const timeoutRef = useRef();
196
- const handleMouseEnter = () => {
197
- if (timeoutRef.current)
198
- clearTimeout(timeoutRef.current);
199
- if (itemRef.current) {
200
- const rect = itemRef.current.getBoundingClientRect();
201
- setPosition({ x: rect.right, y: rect.top });
202
- }
203
- setIsHovered(true);
204
- };
205
- const handleMouseLeave = () => {
206
- timeoutRef.current = setTimeout(() => {
207
- setIsHovered(false);
208
- }, 100);
209
- };
210
- useEffect(() => {
211
- const el = submenuRef.current;
212
- if (el) {
213
- const stopPropagation = (e) => e.stopPropagation();
214
- el.addEventListener('mousedown', stopPropagation);
215
- return () => {
216
- el.removeEventListener('mousedown', stopPropagation);
217
- };
218
- }
219
- }, [isHovered]);
220
- const availableCalendars = calendars.filter(c => c.id !== currentCalendarId);
221
- if (availableCalendars.length === 0)
222
- return null;
223
- return (u(Fragment, { children: [u("div", { ref: itemRef, className: "relative flex cursor-default select-none items-center justify-between rounded-sm px-3 py-0.5 text-[12px] outline-none hover:bg-primary hover:text-white dark:text-slate-200 dark:hover:bg-primary dark:hover:text-white transition-colors", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [u("span", { children: t('merge') }), u(ChevronRight, { className: "h-4 w-4" })] }), isHovered &&
224
- createPortal(u("div", { ref: submenuRef, "data-submenu-content": "true", className: "fixed z-60 min-w-48 overflow-hidden rounded-md border border-slate-200 bg-white p-1 shadow-md dark:border-slate-800 dark:bg-slate-950 animate-in fade-in-0 zoom-in-95 duration-100", style: { top: position.y, left: position.x }, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onMouseDown: e => e.stopPropagation(), children: availableCalendars.map(calendar => (u("div", { className: "flex items-center cursor-pointer rounded-sm px-3 py-1 text-[12px] text-slate-900 hover:bg-primary hover:text-white dark:text-slate-50 dark:hover:bg-primary dark:hover:text-white transition-colors", onClick: e => {
225
- e.stopPropagation();
226
- onMergeSelect(calendar.id);
227
- }, children: [u("div", { className: "mr-2 h-3 w-3 rounded-sm shrink-0", style: { backgroundColor: calendar.colors.lineColor } }), u("span", { className: "truncate", children: calendar.name || calendar.id })] }, calendar.id))) }), document.body)] }));
228
- };
229
-
230
- const MergeCalendarDialog = ({ sourceName, targetName, onConfirm, onCancel, }) => {
231
- const { t } = useLocale();
232
- return (u("div", { className: "fixed inset-0 z-100 flex items-center justify-center bg-black/50", children: u("div", { className: "w-full max-w-md rounded-lg p-6 shadow-xl bg-background", children: [u("h2", { className: "text-lg font-semibold text-gray-900 dark:text-white", children: t('mergeConfirmTitle', { sourceName, targetName }) }), u("p", { className: "mt-3 text-sm text-gray-600 dark:text-gray-300", children: t('mergeConfirmMessage', { sourceName, targetName }) }), u("div", { className: "mt-6 flex justify-end gap-3", children: [u("button", { type: "button", onClick: onCancel, className: cancelButton, children: t('cancel') }), u("button", { type: "button", onClick: onConfirm, className: "rounded-md bg-destructive px-3 py-2 text-xs font-medium text-destructive-foreground hover:bg-destructive/90", children: t('merge') })] })] }) }));
233
- };
234
-
235
186
  const DeleteCalendarDialog = ({ calendarId, calendarName, calendars, step, onStepChange, onConfirmDelete, onCancel, onMergeSelect, }) => {
236
187
  const [showMergeDropdown, setShowMergeDropdown] = useState(false);
237
188
  const { t } = useLocale();
238
- return createPortal(u("div", { className: "fixed inset-0 z-[9999] flex items-center justify-center bg-black/50", children: u("div", { className: "w-full max-w-md rounded-lg p-6 shadow-xl bg-background", children: step === 'initial' ? (u(Fragment, { children: [u("h2", { className: "text-lg font-semibold text-gray-900 dark:text-white", children: t('deleteCalendar', { calendarName }) }), u("p", { className: "mt-3 text-sm text-gray-600 dark:text-gray-300", children: t('deleteCalendarMessage', { calendarName }) }), u("div", { className: "mt-6 flex justify-between items-center", children: [u("div", { className: "relative", children: [u("button", { type: "button", onClick: () => setShowMergeDropdown(!showMergeDropdown), className: "flex items-center gap-1 rounded-md border border-gray-300 px-4 py-2 text-xs font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:text-gray-200 dark:hover:bg-slate-700", children: t('merge') }), showMergeDropdown && (u("div", { className: "absolute left-0 top-full mt-1 min-w-full w-max rounded-md border border-gray-200 bg-background shadow-lg dark:border-slate-700 z-10 max-h-60 overflow-y-auto", children: calendars
189
+ return createPortal(u("div", { className: 'fixed inset-0 z-[9999] flex items-center justify-center bg-black/50', children: u("div", { className: 'w-full max-w-md rounded-lg bg-background p-6 shadow-xl', children: step === 'initial' ? (u(Fragment, { children: [u("h2", { className: 'text-lg font-semibold text-gray-900 dark:text-white', children: t('deleteCalendar', { calendarName }) }), u("p", { className: 'mt-3 text-sm text-gray-600 dark:text-gray-300', children: t('deleteCalendarMessage', { calendarName }) }), u("div", { className: 'mt-6 flex items-center justify-between', children: [u("div", { className: 'relative', children: [u("button", { type: 'button', onClick: () => setShowMergeDropdown(!showMergeDropdown), className: 'flex items-center gap-1 rounded-md border border-gray-300 px-4 py-2 text-xs font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:text-gray-200 dark:hover:bg-slate-700', children: t('merge') }), showMergeDropdown && (u("div", { className: 'absolute top-full left-0 z-10 mt-1 max-h-60 w-max min-w-full overflow-y-auto rounded-md border border-gray-200 bg-background shadow-lg dark:border-slate-700', children: calendars
239
190
  .filter(c => c.id !== calendarId)
240
- .map(calendar => (u("div", { className: "flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-slate-700 cursor-pointer", onClick: () => {
191
+ .map(calendar => (u("div", { className: 'flex cursor-pointer items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-slate-700', onClick: () => {
241
192
  onMergeSelect(calendar.id);
242
193
  setShowMergeDropdown(false);
243
- }, children: [u("div", { className: "mr-2 h-3 w-3 rounded-sm shrink-0", style: {
194
+ }, children: [u("div", { className: 'mr-2 h-3 w-3 shrink-0 rounded-sm', style: {
244
195
  backgroundColor: calendar.colors.lineColor,
245
- } }), u("span", { className: "whitespace-nowrap", children: calendar.name || calendar.id })] }, calendar.id))) }))] }), u("div", { className: "flex gap-3", children: [u("button", { type: "button", onClick: onCancel, className: cancelButton, children: t('cancel') }), u("button", { type: "button", onClick: () => onStepChange('confirm_delete'), className: "rounded-md bg-destructive px-4 py-2 text-xs font-medium text-destructive-foreground hover:bg-destructive/90", children: t('delete') })] })] })] })) : (u(Fragment, { children: [u("h2", { className: "text-lg font-semibold text-gray-900 dark:text-white", children: t('confirmDeleteTitle', { calendarName }) }), u("p", { className: "mt-3 text-sm text-gray-600 dark:text-gray-300", children: t('confirmDeleteMessage') }), u("div", { className: "mt-6 flex justify-end gap-3", children: [u("button", { type: "button", onClick: onCancel, className: "rounded-md bg-background border border-border px-3 py-2 text-xs font-medium text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-slate-700", children: t('cancel') }), u("button", { type: "button", onClick: onConfirmDelete, className: "rounded-md bg-destructive px-3 py-2 text-xs font-medium text-destructive-foreground hover:bg-destructive/90", children: t('delete') })] })] })) }) }), document.body);
196
+ } }), u("span", { className: 'whitespace-nowrap', children: calendar.name || calendar.id })] }, calendar.id))) }))] }), u("div", { className: 'flex gap-3', children: [u("button", { type: 'button', onClick: onCancel, className: cancelButton, children: t('cancel') }), u("button", { type: 'button', onClick: () => onStepChange('confirm_delete'), className: 'rounded-md bg-destructive px-4 py-2 text-xs font-medium text-destructive-foreground hover:bg-destructive/90', children: t('delete') })] })] })] })) : (u(Fragment, { children: [u("h2", { className: 'text-lg font-semibold text-gray-900 dark:text-white', children: t('confirmDeleteTitle', { calendarName }) }), u("p", { className: 'mt-3 text-sm text-gray-600 dark:text-gray-300', children: t('confirmDeleteMessage') }), u("div", { className: 'mt-6 flex justify-end gap-3', children: [u("button", { type: 'button', onClick: onCancel, className: 'rounded-md border border-border bg-background px-3 py-2 text-xs font-medium text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-slate-700', children: t('cancel') }), u("button", { type: 'button', onClick: onConfirmDelete, className: 'rounded-md bg-destructive px-3 py-2 text-xs font-medium text-destructive-foreground hover:bg-destructive/90', children: t('delete') })] })] })) }) }), document.body);
246
197
  };
247
198
 
248
199
  const NEW_CALENDAR_ID = 'new-calendar';
@@ -288,25 +239,78 @@ const ImportCalendarDialog = ({ calendars, filename, onConfirm, onCancel, }) =>
288
239
  const rect = (_a = triggerRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
289
240
  if (!rect)
290
241
  return null;
291
- return createPortal(u("div", { ref: dropdownRef, className: `fixed z-110 mt-1 max-h-60 overflow-y-auto rounded-md bg-white shadow-lg border border-gray-200 dark:border-slate-700 dark:bg-slate-800 transition-all duration-200 origin-top ${isOpen ? 'opacity-100 scale-100' : 'opacity-0 scale-95'}`, style: {
242
+ return createPortal(u("div", { ref: dropdownRef, className: `fixed z-110 mt-1 max-h-60 origin-top overflow-y-auto rounded-md border border-gray-200 bg-white shadow-lg transition-all duration-200 dark:border-slate-700 dark:bg-slate-800 ${isOpen ? 'scale-100 opacity-100' : 'scale-95 opacity-0'}`, style: {
292
243
  top: rect.bottom,
293
244
  left: rect.left,
294
245
  width: rect.width,
295
- }, children: u("div", { className: "py-1", children: [calendars.map(calendar => (u("div", { className: `flex items-center px-3 py-2 cursor-pointer hover:bg-gray-100 dark:hover:bg-slate-700 ${selectedCalendarId === calendar.id ? 'bg-primary/10' : ''}`, onClick: () => handleSelect(calendar.id), children: [u("div", { className: "mr-3 h-3 w-3 shrink-0 rounded-sm", style: { backgroundColor: calendar.colors.lineColor } }), u("span", { className: `flex-1 text-sm truncate ${selectedCalendarId === calendar.id ? 'font-medium text-primary' : 'text-gray-700 dark:text-gray-200'}`, children: calendar.name || calendar.id }), selectedCalendarId === calendar.id && (u(Check, { className: "ml-2 w-4 h-4 text-primary shrink-0" }))] }, calendar.id))), u("div", { className: "border-t border-gray-100 dark:border-slate-700 my-1" }), u("div", { className: `flex items-center px-3 py-2 cursor-pointer hover:bg-gray-100 dark:hover:bg-slate-700 ${isNewSelected ? 'bg-primary/10' : ''}`, onClick: () => handleSelect(NEW_CALENDAR_ID), children: [u("span", { className: `flex-1 text-sm truncate ${isNewSelected ? 'font-medium text-primary' : 'text-gray-700 dark:text-gray-200 pl-6'}`, children: [t('newCalendar') || 'New Calendar', ": ", filename] }), isNewSelected && (u(Check, { className: "ml-2 w-4 h-4 text-primary shrink-0" }))] })] }) }), document.body);
246
+ }, children: u("div", { className: 'py-1', children: [calendars.map(calendar => (u("div", { className: `flex cursor-pointer items-center px-3 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 ${selectedCalendarId === calendar.id ? 'bg-primary/10' : ''}`, onClick: () => handleSelect(calendar.id), children: [u("div", { className: 'mr-3 h-3 w-3 shrink-0 rounded-sm', style: { backgroundColor: calendar.colors.lineColor } }), u("span", { className: `flex-1 truncate text-sm ${selectedCalendarId === calendar.id ? 'font-medium text-primary' : 'text-gray-700 dark:text-gray-200'}`, children: calendar.name || calendar.id }), selectedCalendarId === calendar.id && (u(Check, { className: 'ml-2 h-4 w-4 shrink-0 text-primary' }))] }, calendar.id))), u("div", { className: 'my-1 border-t border-gray-100 dark:border-slate-700' }), u("div", { className: `flex cursor-pointer items-center px-3 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 ${isNewSelected ? 'bg-primary/10' : ''}`, onClick: () => handleSelect(NEW_CALENDAR_ID), children: [u("span", { className: `flex-1 truncate text-sm ${isNewSelected ? 'font-medium text-primary' : 'pl-6 text-gray-700 dark:text-gray-200'}`, children: [t('newCalendar') || 'New Calendar', ": ", filename] }), isNewSelected && (u(Check, { className: 'ml-2 h-4 w-4 shrink-0 text-primary' }))] })] }) }), document.body);
296
247
  };
297
- return (u("div", { className: "fixed inset-0 z-100 flex items-center justify-center bg-black/50", children: u("div", { className: "w-full max-w-md rounded-lg bg-white p-6 shadow-xl dark:bg-slate-900", children: [u("h2", { className: "mb-4 text-lg font-semibold text-gray-900 dark:text-white", children: t('addSchedule') || 'Add Schedule' }), u("p", { className: "mb-4 text-sm text-gray-600 dark:text-gray-300", children: t('importCalendarMessage') ||
298
- 'This calendar contains new events. Please select a target calendar.' }), u("div", { className: "relative", children: [u("button", { ref: triggerRef, type: "button", className: "flex items-center w-full border border-gray-300 dark:border-gray-600 rounded-md px-3 py-2 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors shadow-sm", onClick: () => setIsOpen(!isOpen), children: [!isNewSelected && selectedCalendar && (u("div", { className: "mr-3 h-3 w-3 shrink-0 rounded-sm", style: { backgroundColor: selectedCalendar.colors.lineColor } })), u("span", { className: `text-sm font-medium text-gray-700 dark:text-gray-200 flex-1 text-left truncate ${isNewSelected ? 'pl-0' : ''}`, children: isNewSelected
248
+ return (u("div", { className: 'fixed inset-0 z-100 flex items-center justify-center bg-black/50', children: u("div", { className: 'w-full max-w-md rounded-lg bg-white p-6 shadow-xl dark:bg-slate-900', children: [u("h2", { className: 'mb-4 text-lg font-semibold text-gray-900 dark:text-white', children: t('addSchedule') || 'Add Schedule' }), u("p", { className: 'mb-4 text-sm text-gray-600 dark:text-gray-300', children: t('importCalendarMessage') ||
249
+ 'This calendar contains new events. Please select a target calendar.' }), u("div", { className: 'relative', children: [u("button", { ref: triggerRef, type: 'button', className: 'flex w-full items-center rounded-md border border-gray-300 px-3 py-2 shadow-sm transition-colors hover:bg-gray-50 dark:border-gray-600 dark:hover:bg-gray-800', onClick: () => setIsOpen(!isOpen), children: [!isNewSelected && selectedCalendar && (u("div", { className: 'mr-3 h-3 w-3 shrink-0 rounded-sm', style: { backgroundColor: selectedCalendar.colors.lineColor } })), u("span", { className: `flex-1 truncate text-left text-sm font-medium text-gray-700 dark:text-gray-200 ${isNewSelected ? 'pl-0' : ''}`, children: isNewSelected
299
250
  ? `${t('newCalendar')}: ${filename}`
300
- : (selectedCalendar === null || selectedCalendar === void 0 ? void 0 : selectedCalendar.name) || (selectedCalendar === null || selectedCalendar === void 0 ? void 0 : selectedCalendar.id) }), u(ChevronsUpDown, { className: "w-4 h-4 text-gray-400 shrink-0 ml-2" })] }), renderDropdown()] }), u("div", { className: "mt-8 flex justify-end gap-3", children: [u("button", { type: "button", onClick: onCancel, className: cancelButton, children: t('cancel') || 'Cancel' }), u("button", { type: "button", onClick: () => onConfirm(selectedCalendarId), className: "rounded-md bg-primary px-6 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors shadow-sm", children: t('ok') || 'OK' })] })] }) }));
251
+ : (selectedCalendar === null || selectedCalendar === void 0 ? void 0 : selectedCalendar.name) || (selectedCalendar === null || selectedCalendar === void 0 ? void 0 : selectedCalendar.id) }), u(ChevronsUpDown, { className: 'ml-2 h-4 w-4 shrink-0 text-gray-400' })] }), renderDropdown()] }), u("div", { className: 'mt-8 flex justify-end gap-3', children: [u("button", { type: 'button', onClick: onCancel, className: cancelButton, children: t('cancel') || 'Cancel' }), u("button", { type: 'button', onClick: () => onConfirm(selectedCalendarId), className: 'rounded-md bg-primary px-6 py-2 text-sm font-medium text-primary-foreground shadow-sm transition-colors hover:bg-primary/90', children: t('ok') || 'OK' })] })] }) }));
252
+ };
253
+
254
+ const MergeCalendarDialog = ({ sourceName, targetName, onConfirm, onCancel, }) => {
255
+ const { t } = useLocale();
256
+ return (u("div", { className: 'fixed inset-0 z-100 flex items-center justify-center bg-black/50', children: u("div", { className: 'w-full max-w-md rounded-lg bg-background p-6 shadow-xl', children: [u("h2", { className: 'text-lg font-semibold text-gray-900 dark:text-white', children: t('mergeConfirmTitle', { sourceName, targetName }) }), u("p", { className: 'mt-3 text-sm text-gray-600 dark:text-gray-300', children: t('mergeConfirmMessage', { sourceName, targetName }) }), u("div", { className: 'mt-6 flex justify-end gap-3', children: [u("button", { type: 'button', onClick: onCancel, className: cancelButton, children: t('cancel') }), u("button", { type: 'button', onClick: onConfirm, className: 'rounded-md bg-destructive px-3 py-2 text-xs font-medium text-destructive-foreground hover:bg-destructive/90', children: t('merge') })] })] }) }));
301
257
  };
302
258
 
303
- const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCollapsed, setCollapsed, renderCalendarContextMenu, editingCalendarId: propEditingCalendarId, setEditingCalendarId: propSetEditingCalendarId, onCreateCalendar, colorPickerMode = 'default', }) => {
259
+ const stopPropagation = (e) => e.stopPropagation();
260
+ const MergeMenuItem = ({ calendars, currentCalendarId, onMergeSelect, }) => {
261
+ const { t } = useLocale();
262
+ const [isHovered, setIsHovered] = useState(false);
263
+ const itemRef = useRef(null);
264
+ const submenuRef = useRef(null);
265
+ const [position, setPosition] = useState({ x: 0, y: 0 });
266
+ const timeoutRef = useRef();
267
+ const handleMouseEnter = () => {
268
+ if (timeoutRef.current)
269
+ clearTimeout(timeoutRef.current);
270
+ if (itemRef.current) {
271
+ const rect = itemRef.current.getBoundingClientRect();
272
+ setPosition({ x: rect.right, y: rect.top });
273
+ }
274
+ setIsHovered(true);
275
+ };
276
+ const handleMouseLeave = () => {
277
+ timeoutRef.current = setTimeout(() => {
278
+ setIsHovered(false);
279
+ }, 100);
280
+ };
281
+ useEffect(() => {
282
+ const el = submenuRef.current;
283
+ if (el) {
284
+ el.addEventListener('mousedown', stopPropagation);
285
+ return () => {
286
+ el.removeEventListener('mousedown', stopPropagation);
287
+ };
288
+ }
289
+ }, [isHovered]);
290
+ const availableCalendars = calendars.filter(c => c.id !== currentCalendarId);
291
+ if (availableCalendars.length === 0)
292
+ return null;
293
+ return (u(Fragment, { children: [u("div", { ref: itemRef, className: 'relative flex cursor-default items-center justify-between rounded-sm px-3 py-0.5 text-[12px] transition-colors outline-none select-none hover:bg-primary hover:text-white dark:text-slate-200 dark:hover:bg-primary dark:hover:text-white', onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [u("span", { children: t('merge') }), u(ChevronRight, { className: 'h-4 w-4' })] }), isHovered &&
294
+ createPortal(u("div", { ref: submenuRef, "data-submenu-content": 'true', className: 'animate-in fade-in-0 zoom-in-95 fixed z-60 min-w-48 overflow-hidden rounded-md border border-slate-200 bg-white p-1 shadow-md duration-100 dark:border-slate-800 dark:bg-slate-950', style: { top: position.y, left: position.x }, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onMouseDown: e => e.stopPropagation(), children: availableCalendars.map(calendar => (u("div", { className: 'flex cursor-pointer items-center rounded-sm px-3 py-1 text-[12px] text-slate-900 transition-colors hover:bg-primary hover:text-white dark:text-slate-50 dark:hover:bg-primary dark:hover:text-white', onClick: e => {
295
+ e.stopPropagation();
296
+ onMergeSelect(calendar.id);
297
+ }, children: [u("div", { className: 'mr-2 h-3 w-3 shrink-0 rounded-sm', style: { backgroundColor: calendar.colors.lineColor } }), u("span", { className: 'truncate', children: calendar.name || calendar.id })] }, calendar.id))) }), document.body)] }));
298
+ };
299
+
300
+ const SidebarHeader = ({ isCollapsed, onCollapseToggle, }) => {
301
+ const { t } = useLocale();
302
+ return (u("div", { className: sidebarHeader, children: [u("button", { type: 'button', "aria-label": isCollapsed ? t('expandSidebar') : t('collapseSidebar'), className: sidebarHeaderToggle, onClick: onCollapseToggle, children: isCollapsed ? (u(PanelRightClose, { className: 'h-4 w-4 text-gray-500 dark:text-gray-400' })) : (u(PanelRightOpen, { className: 'h-4 w-4 text-gray-500 dark:text-gray-400' })) }), !isCollapsed && (u("div", { className: 'ml-3 flex flex-1 items-center justify-between', children: u("span", { className: sidebarHeaderTitle, children: t('calendars') }) }))] }));
303
+ };
304
+
305
+ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCollapsed, setCollapsed, renderCalendarContextMenu, editingCalendarId: propEditingCalendarId, setEditingCalendarId: propSetEditingCalendarId, onCreateCalendar, }) => {
304
306
  var _a, _b, _c, _d;
305
307
  const { t } = useLocale();
308
+ // Detect if custom color picker slot is provided
309
+ const hasCustomPicker = app.state.overrides.includes('colorPicker');
306
310
  const [localEditingCalendarId, setLocalEditingCalendarId] = useState(null);
307
- const editingCalendarId = propEditingCalendarId !== undefined
308
- ? propEditingCalendarId
309
- : localEditingCalendarId;
311
+ const editingCalendarId = propEditingCalendarId === undefined
312
+ ? localEditingCalendarId
313
+ : propEditingCalendarId;
310
314
  const setEditingCalendarId = propSetEditingCalendarId || setLocalEditingCalendarId;
311
315
  // File input ref for import
312
316
  const fileInputRef = useRef(null);
@@ -443,7 +447,7 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
443
447
  }, [handleCloseSidebarContextMenu]);
444
448
  const handleFileChange = useCallback((e) => __awaiter(void 0, void 0, void 0, function* () {
445
449
  var _a;
446
- const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
450
+ const file = (_a = e.currentTarget.files) === null || _a === void 0 ? void 0 : _a[0];
447
451
  if (!file)
448
452
  return;
449
453
  const result = yield importICSFile(file);
@@ -522,42 +526,53 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
522
526
  const readOnlyConfig = app.getReadOnlyConfig();
523
527
  const isEditable = !app.state.readOnly;
524
528
  const isDraggable = readOnlyConfig.draggable !== false;
525
- return (u("div", { className: sidebarContainer, onContextMenu: isEditable ? handleSidebarContextMenu : undefined, children: [u(SidebarHeader, { isCollapsed: isCollapsed, onCollapseToggle: () => setCollapsed(!isCollapsed) }), !isCollapsed ? (u(Fragment, { children: [u(CalendarList, { calendars: calendars, onToggleVisibility: toggleCalendarVisibility, onReorder: isDraggable ? app.reorderCalendars : () => { }, onRename: isEditable
526
- ? (id, newName) => app.updateCalendar(id, { name: newName })
527
- : () => { }, onContextMenu: isEditable ? handleContextMenu : () => { }, editingId: editingCalendarId, setEditingId: setEditingCalendarId, activeContextMenuCalendarId: contextMenu === null || contextMenu === void 0 ? void 0 : contextMenu.calendarId, isDraggable: isDraggable, isEditable: isEditable }), u("div", { className: "border-t border-gray-200 dark:border-slate-800", children: u(MiniCalendar, { visibleMonth: app.getVisibleMonth(), currentDate: app.getCurrentDate(), showHeader: true, onMonthChange: handleMonthChange, onDateSelect: date => app.setCurrentDate(date) }) })] })) : (u(CalendarList, { calendars: calendars, onToggleVisibility: toggleCalendarVisibility, onReorder: isDraggable ? app.reorderCalendars : () => { }, onRename: isEditable
529
+ return (u("div", { className: sidebarContainer, onContextMenu: isEditable ? handleSidebarContextMenu : undefined, children: [u(SidebarHeader, { isCollapsed: isCollapsed, onCollapseToggle: () => setCollapsed(!isCollapsed) }), isCollapsed ? (u(CalendarList, { calendars: calendars, onToggleVisibility: toggleCalendarVisibility, onReorder: isDraggable
530
+ ? app.reorderCalendars
531
+ : () => {
532
+ /* noop */
533
+ }, onRename: isEditable
528
534
  ? (id, newName) => app.updateCalendar(id, { name: newName })
529
- : () => { }, onContextMenu: isEditable ? handleContextMenu : () => { }, editingId: editingCalendarId, setEditingId: setEditingCalendarId, activeContextMenuCalendarId: contextMenu === null || contextMenu === void 0 ? void 0 : contextMenu.calendarId, isDraggable: isDraggable, isEditable: isEditable })), contextMenu && (u(ContextMenu, { ref: contextMenuRef, x: contextMenu.x, y: contextMenu.y, onClose: handleCloseContextMenu, className: "w-64 p-2", children: u(ContentSlot, { generatorName: "calendarContextMenu", generatorArgs: {
535
+ : () => {
536
+ /* noop */
537
+ }, onContextMenu: isEditable
538
+ ? handleContextMenu
539
+ : () => {
540
+ /* noop */
541
+ }, editingId: editingCalendarId, setEditingId: setEditingCalendarId, activeContextMenuCalendarId: contextMenu === null || contextMenu === void 0 ? void 0 : contextMenu.calendarId, isDraggable: isDraggable, isEditable: isEditable })) : (u(Fragment, { children: [u(CalendarList, { calendars: calendars, onToggleVisibility: toggleCalendarVisibility, onReorder: isDraggable
542
+ ? app.reorderCalendars
543
+ : () => {
544
+ /* noop */
545
+ }, onRename: isEditable
546
+ ? (id, newName) => app.updateCalendar(id, { name: newName })
547
+ : () => {
548
+ /* noop */
549
+ }, onContextMenu: isEditable
550
+ ? handleContextMenu
551
+ : () => {
552
+ /* noop */
553
+ }, editingId: editingCalendarId, setEditingId: setEditingCalendarId, activeContextMenuCalendarId: contextMenu === null || contextMenu === void 0 ? void 0 : contextMenu.calendarId, isDraggable: isDraggable, isEditable: isEditable }), u("div", { className: 'border-t border-gray-200 dark:border-slate-800', children: u(MiniCalendar, { visibleMonth: app.getVisibleMonth(), currentDate: app.getCurrentDate(), showHeader: true, onMonthChange: handleMonthChange, onDateSelect: date => app.setCurrentDate(date) }) })] })), contextMenu && (u(ContextMenu, { ref: contextMenuRef, x: contextMenu.x, y: contextMenu.y, onClose: handleCloseContextMenu, className: 'w-64 p-2', children: u(ContentSlot, { generatorName: 'calendarContextMenu', generatorArgs: {
530
554
  calendar: calendars.find(c => c.id === contextMenu.calendarId),
531
555
  onClose: handleCloseContextMenu,
532
556
  }, defaultContent: renderCalendarContextMenu ? (renderCalendarContextMenu(calendars.find(c => c.id === contextMenu.calendarId), handleCloseContextMenu)) : (u(Fragment, { children: [u(ContextMenuLabel, { children: t('calendarOptions') }), u(MergeMenuItem, { calendars: calendars, currentCalendarId: contextMenu.calendarId, onMergeSelect: handleMergeSelect }), u(ContextMenuItem, { onClick: handleDeleteCalendar, children: t('delete') }), u(ContextMenuItem, { onClick: handleExportCalendar, children: t('exportCalendar') || 'Export Calendar' }), u(ContextMenuSeparator, {}), u(ContextMenuColorPicker, { selectedColor: (_d = calendars.find(c => c.id === contextMenu.calendarId)) === null || _d === void 0 ? void 0 : _d.colors.lineColor, onSelect: handleColorSelect, onCustomColor: handleCustomColor })] })) }) })), sidebarContextMenu &&
533
- createPortal(u(ContextMenu, { x: sidebarContextMenu.x, y: sidebarContextMenu.y, onClose: handleCloseSidebarContextMenu, className: "w-max p-2", children: [u(ContextMenuItem, { onClick: () => {
557
+ createPortal(u(ContextMenu, { x: sidebarContextMenu.x, y: sidebarContextMenu.y, onClose: handleCloseSidebarContextMenu, className: 'w-max p-2', children: [u(ContextMenuItem, { onClick: () => {
534
558
  onCreateCalendar === null || onCreateCalendar === void 0 ? void 0 : onCreateCalendar();
535
559
  handleCloseSidebarContextMenu();
536
560
  }, children: t('newCalendar') || 'New Calendar' }), u(ContextMenuItem, { onClick: handleImportClick, children: t('importCalendar') || 'Import Calendar' }), u(ContextMenuItem, { onClick: () => {
537
561
  app.triggerRender();
538
562
  handleCloseSidebarContextMenu();
539
- }, children: t('refreshAll') || 'Refresh All' })] }), document.body), u("input", { ref: fileInputRef, type: "file", accept: ".ics", style: { display: 'none' }, onChange: handleFileChange }), importState &&
563
+ }, children: t('refreshAll') || 'Refresh All' })] }), document.body), u("input", { ref: fileInputRef, type: 'file', accept: '.ics', style: { display: 'none' }, onChange: handleFileChange }), importState &&
540
564
  createPortal(u(ImportCalendarDialog, { calendars: calendars, filename: importState.filename, onConfirm: handleImportConfirm, onCancel: () => setImportState(null) }), document.body), mergeState &&
541
565
  createPortal(u(MergeCalendarDialog, { sourceName: sourceCalendarName, targetName: targetCalendarName, onConfirm: handleMergeConfirm, onCancel: () => setMergeState(null) }), document.body), deleteState &&
542
566
  createPortal(u(DeleteCalendarDialog, { calendarId: deleteState.calendarId, calendarName: deleteCalendarName, calendars: calendars, step: deleteState.step, onStepChange: step => setDeleteState(prev => (prev ? Object.assign(Object.assign({}, prev), { step }) : null)), onConfirmDelete: handleConfirmDelete, onCancel: () => setDeleteState(null), onMergeSelect: handleDeleteMergeSelect }), document.body), customColorPicker &&
543
- createPortal(u("div", { className: "fixed inset-0 z-50", onMouseDown: () => {
567
+ createPortal(u("div", { className: 'fixed inset-0 z-50', onMouseDown: () => {
544
568
  app.updateCalendar(customColorPicker.calendarId, {});
545
569
  setCustomColorPicker(null);
546
- }, children: u("div", { className: "absolute flex items-center justify-center", style: {
570
+ }, children: u("div", { className: 'absolute', style: {
547
571
  top: customColorPicker.y,
548
572
  left: customColorPicker.x,
549
- transform: 'translate(280%, -50%)',
550
- }, onMouseDown: e => e.stopPropagation(), children: colorPickerMode === 'custom' ? (u(BlossomColorPicker, { defaultValue: customColorPicker.initialColor, coreSize: 28, petalSize: 28, initialExpanded: true, adaptivePositioning: true, openOnHover: false, onChange: color => {
551
- const { colors, darkColors } = getCalendarColorsForHex(color.hex);
552
- app.updateCalendar(customColorPicker.calendarId, {
553
- colors,
554
- darkColors,
555
- }, true);
556
- }, onCollapse: () => {
557
- app.updateCalendar(customColorPicker.calendarId, {});
558
- setCustomColorPicker(null);
559
- } })) : (u(ContentSlot, { generatorName: "colorPicker", generatorArgs: {
560
- variant: 'sketch', // TODO: change name
573
+ zIndex: 10002,
574
+ transform: 'translate(40px, -50%)', // Move it to the right of the checkbox/dot
575
+ }, onMouseDown: e => e.stopPropagation(), children: hasCustomPicker ? (u(ContentSlot, { generatorName: 'colorPicker', generatorArgs: {
561
576
  color: customColorPicker.currentColor,
562
577
  onChange: (color) => {
563
578
  setCustomColorPicker(prev => prev ? Object.assign(Object.assign({}, prev), { currentColor: color.hex }) : null);
@@ -574,17 +589,26 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
574
589
  darkColors,
575
590
  });
576
591
  },
577
- }, defaultContent: u(DefaultColorPicker, { color: customColorPicker.currentColor, onChange: (color, isPending) => {
578
- setCustomColorPicker(prev => prev ? Object.assign(Object.assign({}, prev), { currentColor: color.hex }) : null);
579
- const { colors, darkColors } = getCalendarColorsForHex(color.hex);
580
- app.updateCalendar(customColorPicker.calendarId, {
581
- colors,
582
- darkColors,
583
- }, isPending);
584
- }, onClose: () => {
585
- app.updateCalendar(customColorPicker.calendarId, {});
586
- setCustomColorPicker(null);
587
- } }) })) }) }), document.body)] }));
592
+ }, defaultContent: u("div", { className: 'rounded-lg border border-gray-200 bg-white p-3 shadow-xl dark:border-gray-700 dark:bg-slate-900', children: u(DefaultColorPicker, { color: customColorPicker.currentColor, onChange: (color, isPending) => {
593
+ setCustomColorPicker(prev => prev ? Object.assign(Object.assign({}, prev), { currentColor: color.hex }) : null);
594
+ const { colors, darkColors } = getCalendarColorsForHex(color.hex);
595
+ app.updateCalendar(customColorPicker.calendarId, {
596
+ colors,
597
+ darkColors,
598
+ }, isPending);
599
+ }, onClose: () => {
600
+ app.updateCalendar(customColorPicker.calendarId, {});
601
+ setCustomColorPicker(null);
602
+ } }) }) })) : (u(BlossomColorPicker, { defaultValue: customColorPicker.initialColor, coreSize: 28, petalSize: 28, initialExpanded: true, adaptivePositioning: true, openOnHover: false, onChange: color => {
603
+ const { colors, darkColors } = getCalendarColorsForHex(color.hex);
604
+ app.updateCalendar(customColorPicker.calendarId, {
605
+ colors,
606
+ darkColors,
607
+ }, true);
608
+ }, onCollapse: () => {
609
+ app.updateCalendar(customColorPicker.calendarId, {});
610
+ setCustomColorPicker(null);
611
+ } })) }) }), document.body)] }));
588
612
  };
589
613
 
590
614
  const DEFAULT_SIDEBAR_WIDTH = '240px';
@@ -613,11 +637,9 @@ function createSidebarPlugin(config = {}) {
613
637
  const refreshSidebar = useCallback(() => {
614
638
  setSidebarVersion(prev => prev + 1);
615
639
  }, []);
616
- useEffect(() => {
617
- return app.subscribe(() => {
618
- refreshSidebar();
619
- });
620
- }, [app, refreshSidebar]);
640
+ useEffect(() => app.subscribe(() => {
641
+ refreshSidebar();
642
+ }), [app, refreshSidebar]);
621
643
  const calendars = useMemo(() => app.getCalendars(), [app, sidebarVersion]);
622
644
  const handleToggleCalendarVisibility = useCallback((calendarId, visible) => {
623
645
  app.setCalendarVisibility(calendarId, visible);
@@ -661,7 +683,6 @@ function createSidebarPlugin(config = {}) {
661
683
  editingCalendarId,
662
684
  setEditingCalendarId,
663
685
  onCreateCalendar: handleCreateCalendar,
664
- colorPickerMode: config.colorPickerMode,
665
686
  }), [
666
687
  app,
667
688
  calendars,
@@ -673,14 +694,13 @@ function createSidebarPlugin(config = {}) {
673
694
  config,
674
695
  ]);
675
696
  const renderContent = () => {
676
- var _a;
677
697
  if (config.render) {
678
698
  return h(ContentSlot, {
679
699
  generatorName: 'sidebar',
680
700
  generatorArgs: sidebarProps,
681
701
  });
682
702
  }
683
- return h(DefaultCalendarSidebar, Object.assign(Object.assign({}, sidebarProps), { colorPickerMode: (_a = config.colorPickerMode) !== null && _a !== void 0 ? _a : sidebarProps.colorPickerMode }));
703
+ return h(DefaultCalendarSidebar, Object.assign({}, sidebarProps));
684
704
  };
685
705
  const renderExtraContent = () => {
686
706
  if (!showCreateDialog)
@@ -694,7 +714,7 @@ function createSidebarPlugin(config = {}) {
694
714
  const generatorArgs = {
695
715
  onClose,
696
716
  onCreate,
697
- colorPickerMode: config.colorPickerMode,
717
+ app,
698
718
  };
699
719
  return h(ContentSlot, {
700
720
  generatorName: 'createCalendarDialog',
@@ -702,7 +722,7 @@ function createSidebarPlugin(config = {}) {
702
722
  defaultContent: h(CreateCalendarDialog, {
703
723
  onClose,
704
724
  onCreate,
705
- colorPickerMode: config.colorPickerMode,
725
+ app,
706
726
  }),
707
727
  });
708
728
  };
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
+ var core = require('@dayflow/core');
3
4
  var preact = require('preact');
4
5
  var hooks = require('preact/hooks');
5
- var core = require('@dayflow/core');
6
6
  var blossomColorPicker = require('@dayflow/blossom-color-picker');
7
7
 
8
8
  /******************************************************************************
@@ -39,11 +39,6 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
39
39
 
40
40
  var f=0;function u(e,t,n,o,i,u){t||(t={});var a,c,p=t;if("ref"in p)for(c in p={},t)"ref"==c?a=t[c]:p[c]=t[c];var l={type:e,props:p,key:n,ref:a,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:--f,__i:-1,__u:0,__source:i,__self:u};if("function"==typeof e&&(a=e.defaultProps))for(c in a) void 0===p[c]&&(p[c]=a[c]);return preact.options.vnode&&preact.options.vnode(l),l}
41
41
 
42
- const SidebarHeader = ({ isCollapsed, onCollapseToggle, }) => {
43
- const { t } = core.useLocale();
44
- return (u("div", { className: core.sidebarHeader, children: [u("button", { type: "button", "aria-label": isCollapsed ? t('expandSidebar') : t('collapseSidebar'), className: core.sidebarHeaderToggle, onClick: onCollapseToggle, children: isCollapsed ? (u(core.PanelRightClose, { className: "h-4 w-4 text-gray-500 dark:text-gray-400" })) : (u(core.PanelRightOpen, { className: "h-4 w-4 text-gray-500 dark:text-gray-400" })) }), !isCollapsed && (u("div", { className: "flex flex-1 justify-between items-center ml-3", children: u("span", { className: core.sidebarHeaderTitle, children: t('calendars') }) }))] }));
45
- };
46
-
47
42
  const getCalendarInitials = (calendar) => {
48
43
  if (calendar.icon) {
49
44
  return calendar.icon;
@@ -72,9 +67,11 @@ const CalendarList = ({ calendars, onToggleVisibility, onReorder, onRename, onCo
72
67
  calendarColors: calendar.colors,
73
68
  calendarIcon: calendar.icon,
74
69
  };
75
- e.dataTransfer.setData('application/x-dayflow-calendar', JSON.stringify(dragData));
76
- e.dataTransfer.effectAllowed = 'copy';
77
- }, [editingId]);
70
+ if (e.dataTransfer) {
71
+ e.dataTransfer.setData('application/x-dayflow-calendar', JSON.stringify(dragData));
72
+ e.dataTransfer.effectAllowed = 'copy';
73
+ }
74
+ }, [editingId, isDraggable]);
78
75
  const handleDragEnd = hooks.useCallback(() => {
79
76
  setDraggedCalendarId(null);
80
77
  setDropTarget(null);
@@ -174,7 +171,7 @@ const CalendarList = ({ calendars, onToggleVisibility, onReorder, onRename, onCo
174
171
  }
175
172
  }
176
173
  }, [editingId, calendars]);
177
- return (u("div", { className: "df-calendar-list flex-1 overflow-y-auto px-2 pb-3", children: u("ul", { className: "space-y-1 relative", children: calendars.map(calendar => {
174
+ return (u("div", { className: 'df-calendar-list flex-1 overflow-y-auto px-2 pb-3', children: u("ul", { className: 'relative space-y-1', children: calendars.map(calendar => {
178
175
  var _a;
179
176
  const isVisible = calendar.isVisible !== false;
180
177
  const calendarColor = ((_a = calendar.colors) === null || _a === void 0 ? void 0 : _a.lineColor) || '#3b82f6';
@@ -182,69 +179,23 @@ const CalendarList = ({ calendars, onToggleVisibility, onReorder, onRename, onCo
182
179
  const isDropTarget = (dropTarget === null || dropTarget === void 0 ? void 0 : dropTarget.id) === calendar.id;
183
180
  const isActive = activeContextMenuCalendarId === calendar.id ||
184
181
  editingId === calendar.id;
185
- return (u("li", { className: "df-calendar-list-item relative", onDragOver: e => handleDragOver(e, calendar.id), onDragLeave: handleDragLeave, onDrop: () => handleDrop(calendar), onContextMenu: e => onContextMenu(e, calendar.id), children: [isDropTarget && dropTarget.position === 'top' && (u("div", { className: "absolute top-0 left-0 right-0 h-0.5 bg-primary z-10 pointer-events-none" })), u("div", { draggable: isDraggable && !editingId, onDragStart: e => handleDragStart(calendar, e), onDragEnd: handleDragEnd, className: `rounded transition ${draggedCalendarId === calendar.id ? 'opacity-50' : ''} ${isDraggable ? 'cursor-grab' : 'cursor-default'}`, children: u("div", { className: `group flex items-center rounded px-2 py-2 transition hover:bg-gray-100 dark:hover:bg-slate-800 ${isActive ? 'bg-gray-100 dark:bg-slate-800' : ''}`, title: calendar.name, children: [u("input", { type: "checkbox", className: "calendar-checkbox cursor-pointer shrink-0", style: {
182
+ return (u("li", { className: 'df-calendar-list-item relative', onDragOver: e => handleDragOver(e, calendar.id), onDragLeave: handleDragLeave, onDrop: () => handleDrop(calendar), onContextMenu: e => onContextMenu(e, calendar.id), children: [isDropTarget && dropTarget.position === 'top' && (u("div", { className: 'pointer-events-none absolute top-0 right-0 left-0 z-10 h-0.5 bg-primary' })), u("div", { draggable: isDraggable && !editingId, onDragStart: e => handleDragStart(calendar, e), onDragEnd: handleDragEnd, className: `rounded transition ${draggedCalendarId === calendar.id ? 'opacity-50' : ''} ${isDraggable ? 'cursor-grab' : 'cursor-default'}`, children: u("div", { className: `group flex items-center rounded px-2 py-2 transition hover:bg-gray-100 dark:hover:bg-slate-800 ${isActive ? 'bg-gray-100 dark:bg-slate-800' : ''}`, title: calendar.name, children: [u("input", { type: 'checkbox', className: 'calendar-checkbox shrink-0 cursor-pointer', style: {
186
183
  '--checkbox-color': calendarColor,
187
- }, checked: isVisible, onChange: event => onToggleVisibility(calendar.id, event.target.checked) }), showIcon && (u("span", { className: "ml-2 flex h-5 w-5 shrink-0 items-center justify-center text-xs font-semibold text-white", "aria-hidden": "true", children: getCalendarInitials(calendar) })), editingId === calendar.id ? (u("input", { ref: editInputRef, type: "text", value: editingName, onChange: e => setEditingName(e.target.value), onBlur: handleRenameSave, onKeyDown: handleRenameKeyDown, className: "ml-2 flex-1 min-w-0 h-5 rounded bg-white px-0 py-0 text-sm text-gray-900 focus:outline-none dark:bg-slate-700 dark:text-gray-100", onClick: e => e.stopPropagation() })) : (u("span", { className: "flex-1 pl-1 truncate text-sm text-gray-700 group-hover:text-gray-900 dark:text-gray-200 dark:group-hover:text-white ml-2", onDblClick: () => handleRenameStart(calendar), children: calendar.name || calendar.id }))] }) }), isDropTarget && dropTarget.position === 'bottom' && (u("div", { className: "absolute bottom-0 left-0 right-0 h-0.5 bg-primary z-10 pointer-events-none" }))] }, calendar.id));
184
+ }, checked: isVisible, onChange: event => onToggleVisibility(calendar.id, event.target.checked) }), showIcon && (u("span", { className: 'ml-2 flex h-5 w-5 shrink-0 items-center justify-center text-xs font-semibold text-white', "aria-hidden": 'true', children: getCalendarInitials(calendar) })), editingId === calendar.id ? (u("input", { ref: editInputRef, type: 'text', value: editingName, onChange: e => setEditingName(e.target.value), onBlur: handleRenameSave, onKeyDown: handleRenameKeyDown, className: 'ml-2 h-5 min-w-0 flex-1 rounded bg-white px-0 py-0 text-sm text-gray-900 focus:outline-none dark:bg-slate-700 dark:text-gray-100', onClick: e => e.stopPropagation() })) : (u("span", { className: 'ml-2 flex-1 truncate pl-1 text-sm text-gray-700 group-hover:text-gray-900 dark:text-gray-200 dark:group-hover:text-white', onDblClick: () => handleRenameStart(calendar), children: calendar.name || calendar.id }))] }) }), isDropTarget && dropTarget.position === 'bottom' && (u("div", { className: 'pointer-events-none absolute right-0 bottom-0 left-0 z-10 h-0.5 bg-primary' }))] }, calendar.id));
188
185
  }) }) }));
189
186
  };
190
187
 
191
- const MergeMenuItem = ({ calendars, currentCalendarId, onMergeSelect, }) => {
192
- const { t } = core.useLocale();
193
- const [isHovered, setIsHovered] = hooks.useState(false);
194
- const itemRef = hooks.useRef(null);
195
- const submenuRef = hooks.useRef(null);
196
- const [position, setPosition] = hooks.useState({ x: 0, y: 0 });
197
- const timeoutRef = hooks.useRef();
198
- const handleMouseEnter = () => {
199
- if (timeoutRef.current)
200
- clearTimeout(timeoutRef.current);
201
- if (itemRef.current) {
202
- const rect = itemRef.current.getBoundingClientRect();
203
- setPosition({ x: rect.right, y: rect.top });
204
- }
205
- setIsHovered(true);
206
- };
207
- const handleMouseLeave = () => {
208
- timeoutRef.current = setTimeout(() => {
209
- setIsHovered(false);
210
- }, 100);
211
- };
212
- hooks.useEffect(() => {
213
- const el = submenuRef.current;
214
- if (el) {
215
- const stopPropagation = (e) => e.stopPropagation();
216
- el.addEventListener('mousedown', stopPropagation);
217
- return () => {
218
- el.removeEventListener('mousedown', stopPropagation);
219
- };
220
- }
221
- }, [isHovered]);
222
- const availableCalendars = calendars.filter(c => c.id !== currentCalendarId);
223
- if (availableCalendars.length === 0)
224
- return null;
225
- return (u(preact.Fragment, { children: [u("div", { ref: itemRef, className: "relative flex cursor-default select-none items-center justify-between rounded-sm px-3 py-0.5 text-[12px] outline-none hover:bg-primary hover:text-white dark:text-slate-200 dark:hover:bg-primary dark:hover:text-white transition-colors", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [u("span", { children: t('merge') }), u(core.ChevronRight, { className: "h-4 w-4" })] }), isHovered &&
226
- core.createPortal(u("div", { ref: submenuRef, "data-submenu-content": "true", className: "fixed z-60 min-w-48 overflow-hidden rounded-md border border-slate-200 bg-white p-1 shadow-md dark:border-slate-800 dark:bg-slate-950 animate-in fade-in-0 zoom-in-95 duration-100", style: { top: position.y, left: position.x }, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onMouseDown: e => e.stopPropagation(), children: availableCalendars.map(calendar => (u("div", { className: "flex items-center cursor-pointer rounded-sm px-3 py-1 text-[12px] text-slate-900 hover:bg-primary hover:text-white dark:text-slate-50 dark:hover:bg-primary dark:hover:text-white transition-colors", onClick: e => {
227
- e.stopPropagation();
228
- onMergeSelect(calendar.id);
229
- }, children: [u("div", { className: "mr-2 h-3 w-3 rounded-sm shrink-0", style: { backgroundColor: calendar.colors.lineColor } }), u("span", { className: "truncate", children: calendar.name || calendar.id })] }, calendar.id))) }), document.body)] }));
230
- };
231
-
232
- const MergeCalendarDialog = ({ sourceName, targetName, onConfirm, onCancel, }) => {
233
- const { t } = core.useLocale();
234
- return (u("div", { className: "fixed inset-0 z-100 flex items-center justify-center bg-black/50", children: u("div", { className: "w-full max-w-md rounded-lg p-6 shadow-xl bg-background", children: [u("h2", { className: "text-lg font-semibold text-gray-900 dark:text-white", children: t('mergeConfirmTitle', { sourceName, targetName }) }), u("p", { className: "mt-3 text-sm text-gray-600 dark:text-gray-300", children: t('mergeConfirmMessage', { sourceName, targetName }) }), u("div", { className: "mt-6 flex justify-end gap-3", children: [u("button", { type: "button", onClick: onCancel, className: core.cancelButton, children: t('cancel') }), u("button", { type: "button", onClick: onConfirm, className: "rounded-md bg-destructive px-3 py-2 text-xs font-medium text-destructive-foreground hover:bg-destructive/90", children: t('merge') })] })] }) }));
235
- };
236
-
237
188
  const DeleteCalendarDialog = ({ calendarId, calendarName, calendars, step, onStepChange, onConfirmDelete, onCancel, onMergeSelect, }) => {
238
189
  const [showMergeDropdown, setShowMergeDropdown] = hooks.useState(false);
239
190
  const { t } = core.useLocale();
240
- return core.createPortal(u("div", { className: "fixed inset-0 z-[9999] flex items-center justify-center bg-black/50", children: u("div", { className: "w-full max-w-md rounded-lg p-6 shadow-xl bg-background", children: step === 'initial' ? (u(preact.Fragment, { children: [u("h2", { className: "text-lg font-semibold text-gray-900 dark:text-white", children: t('deleteCalendar', { calendarName }) }), u("p", { className: "mt-3 text-sm text-gray-600 dark:text-gray-300", children: t('deleteCalendarMessage', { calendarName }) }), u("div", { className: "mt-6 flex justify-between items-center", children: [u("div", { className: "relative", children: [u("button", { type: "button", onClick: () => setShowMergeDropdown(!showMergeDropdown), className: "flex items-center gap-1 rounded-md border border-gray-300 px-4 py-2 text-xs font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:text-gray-200 dark:hover:bg-slate-700", children: t('merge') }), showMergeDropdown && (u("div", { className: "absolute left-0 top-full mt-1 min-w-full w-max rounded-md border border-gray-200 bg-background shadow-lg dark:border-slate-700 z-10 max-h-60 overflow-y-auto", children: calendars
191
+ return core.createPortal(u("div", { className: 'fixed inset-0 z-[9999] flex items-center justify-center bg-black/50', children: u("div", { className: 'w-full max-w-md rounded-lg bg-background p-6 shadow-xl', children: step === 'initial' ? (u(preact.Fragment, { children: [u("h2", { className: 'text-lg font-semibold text-gray-900 dark:text-white', children: t('deleteCalendar', { calendarName }) }), u("p", { className: 'mt-3 text-sm text-gray-600 dark:text-gray-300', children: t('deleteCalendarMessage', { calendarName }) }), u("div", { className: 'mt-6 flex items-center justify-between', children: [u("div", { className: 'relative', children: [u("button", { type: 'button', onClick: () => setShowMergeDropdown(!showMergeDropdown), className: 'flex items-center gap-1 rounded-md border border-gray-300 px-4 py-2 text-xs font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:text-gray-200 dark:hover:bg-slate-700', children: t('merge') }), showMergeDropdown && (u("div", { className: 'absolute top-full left-0 z-10 mt-1 max-h-60 w-max min-w-full overflow-y-auto rounded-md border border-gray-200 bg-background shadow-lg dark:border-slate-700', children: calendars
241
192
  .filter(c => c.id !== calendarId)
242
- .map(calendar => (u("div", { className: "flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-slate-700 cursor-pointer", onClick: () => {
193
+ .map(calendar => (u("div", { className: 'flex cursor-pointer items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-slate-700', onClick: () => {
243
194
  onMergeSelect(calendar.id);
244
195
  setShowMergeDropdown(false);
245
- }, children: [u("div", { className: "mr-2 h-3 w-3 rounded-sm shrink-0", style: {
196
+ }, children: [u("div", { className: 'mr-2 h-3 w-3 shrink-0 rounded-sm', style: {
246
197
  backgroundColor: calendar.colors.lineColor,
247
- } }), u("span", { className: "whitespace-nowrap", children: calendar.name || calendar.id })] }, calendar.id))) }))] }), u("div", { className: "flex gap-3", children: [u("button", { type: "button", onClick: onCancel, className: core.cancelButton, children: t('cancel') }), u("button", { type: "button", onClick: () => onStepChange('confirm_delete'), className: "rounded-md bg-destructive px-4 py-2 text-xs font-medium text-destructive-foreground hover:bg-destructive/90", children: t('delete') })] })] })] })) : (u(preact.Fragment, { children: [u("h2", { className: "text-lg font-semibold text-gray-900 dark:text-white", children: t('confirmDeleteTitle', { calendarName }) }), u("p", { className: "mt-3 text-sm text-gray-600 dark:text-gray-300", children: t('confirmDeleteMessage') }), u("div", { className: "mt-6 flex justify-end gap-3", children: [u("button", { type: "button", onClick: onCancel, className: "rounded-md bg-background border border-border px-3 py-2 text-xs font-medium text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-slate-700", children: t('cancel') }), u("button", { type: "button", onClick: onConfirmDelete, className: "rounded-md bg-destructive px-3 py-2 text-xs font-medium text-destructive-foreground hover:bg-destructive/90", children: t('delete') })] })] })) }) }), document.body);
198
+ } }), u("span", { className: 'whitespace-nowrap', children: calendar.name || calendar.id })] }, calendar.id))) }))] }), u("div", { className: 'flex gap-3', children: [u("button", { type: 'button', onClick: onCancel, className: core.cancelButton, children: t('cancel') }), u("button", { type: 'button', onClick: () => onStepChange('confirm_delete'), className: 'rounded-md bg-destructive px-4 py-2 text-xs font-medium text-destructive-foreground hover:bg-destructive/90', children: t('delete') })] })] })] })) : (u(preact.Fragment, { children: [u("h2", { className: 'text-lg font-semibold text-gray-900 dark:text-white', children: t('confirmDeleteTitle', { calendarName }) }), u("p", { className: 'mt-3 text-sm text-gray-600 dark:text-gray-300', children: t('confirmDeleteMessage') }), u("div", { className: 'mt-6 flex justify-end gap-3', children: [u("button", { type: 'button', onClick: onCancel, className: 'rounded-md border border-border bg-background px-3 py-2 text-xs font-medium text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-slate-700', children: t('cancel') }), u("button", { type: 'button', onClick: onConfirmDelete, className: 'rounded-md bg-destructive px-3 py-2 text-xs font-medium text-destructive-foreground hover:bg-destructive/90', children: t('delete') })] })] })) }) }), document.body);
248
199
  };
249
200
 
250
201
  const NEW_CALENDAR_ID = 'new-calendar';
@@ -290,25 +241,78 @@ const ImportCalendarDialog = ({ calendars, filename, onConfirm, onCancel, }) =>
290
241
  const rect = (_a = triggerRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
291
242
  if (!rect)
292
243
  return null;
293
- return core.createPortal(u("div", { ref: dropdownRef, className: `fixed z-110 mt-1 max-h-60 overflow-y-auto rounded-md bg-white shadow-lg border border-gray-200 dark:border-slate-700 dark:bg-slate-800 transition-all duration-200 origin-top ${isOpen ? 'opacity-100 scale-100' : 'opacity-0 scale-95'}`, style: {
244
+ return core.createPortal(u("div", { ref: dropdownRef, className: `fixed z-110 mt-1 max-h-60 origin-top overflow-y-auto rounded-md border border-gray-200 bg-white shadow-lg transition-all duration-200 dark:border-slate-700 dark:bg-slate-800 ${isOpen ? 'scale-100 opacity-100' : 'scale-95 opacity-0'}`, style: {
294
245
  top: rect.bottom,
295
246
  left: rect.left,
296
247
  width: rect.width,
297
- }, children: u("div", { className: "py-1", children: [calendars.map(calendar => (u("div", { className: `flex items-center px-3 py-2 cursor-pointer hover:bg-gray-100 dark:hover:bg-slate-700 ${selectedCalendarId === calendar.id ? 'bg-primary/10' : ''}`, onClick: () => handleSelect(calendar.id), children: [u("div", { className: "mr-3 h-3 w-3 shrink-0 rounded-sm", style: { backgroundColor: calendar.colors.lineColor } }), u("span", { className: `flex-1 text-sm truncate ${selectedCalendarId === calendar.id ? 'font-medium text-primary' : 'text-gray-700 dark:text-gray-200'}`, children: calendar.name || calendar.id }), selectedCalendarId === calendar.id && (u(core.Check, { className: "ml-2 w-4 h-4 text-primary shrink-0" }))] }, calendar.id))), u("div", { className: "border-t border-gray-100 dark:border-slate-700 my-1" }), u("div", { className: `flex items-center px-3 py-2 cursor-pointer hover:bg-gray-100 dark:hover:bg-slate-700 ${isNewSelected ? 'bg-primary/10' : ''}`, onClick: () => handleSelect(NEW_CALENDAR_ID), children: [u("span", { className: `flex-1 text-sm truncate ${isNewSelected ? 'font-medium text-primary' : 'text-gray-700 dark:text-gray-200 pl-6'}`, children: [t('newCalendar') || 'New Calendar', ": ", filename] }), isNewSelected && (u(core.Check, { className: "ml-2 w-4 h-4 text-primary shrink-0" }))] })] }) }), document.body);
248
+ }, children: u("div", { className: 'py-1', children: [calendars.map(calendar => (u("div", { className: `flex cursor-pointer items-center px-3 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 ${selectedCalendarId === calendar.id ? 'bg-primary/10' : ''}`, onClick: () => handleSelect(calendar.id), children: [u("div", { className: 'mr-3 h-3 w-3 shrink-0 rounded-sm', style: { backgroundColor: calendar.colors.lineColor } }), u("span", { className: `flex-1 truncate text-sm ${selectedCalendarId === calendar.id ? 'font-medium text-primary' : 'text-gray-700 dark:text-gray-200'}`, children: calendar.name || calendar.id }), selectedCalendarId === calendar.id && (u(core.Check, { className: 'ml-2 h-4 w-4 shrink-0 text-primary' }))] }, calendar.id))), u("div", { className: 'my-1 border-t border-gray-100 dark:border-slate-700' }), u("div", { className: `flex cursor-pointer items-center px-3 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 ${isNewSelected ? 'bg-primary/10' : ''}`, onClick: () => handleSelect(NEW_CALENDAR_ID), children: [u("span", { className: `flex-1 truncate text-sm ${isNewSelected ? 'font-medium text-primary' : 'pl-6 text-gray-700 dark:text-gray-200'}`, children: [t('newCalendar') || 'New Calendar', ": ", filename] }), isNewSelected && (u(core.Check, { className: 'ml-2 h-4 w-4 shrink-0 text-primary' }))] })] }) }), document.body);
298
249
  };
299
- return (u("div", { className: "fixed inset-0 z-100 flex items-center justify-center bg-black/50", children: u("div", { className: "w-full max-w-md rounded-lg bg-white p-6 shadow-xl dark:bg-slate-900", children: [u("h2", { className: "mb-4 text-lg font-semibold text-gray-900 dark:text-white", children: t('addSchedule') || 'Add Schedule' }), u("p", { className: "mb-4 text-sm text-gray-600 dark:text-gray-300", children: t('importCalendarMessage') ||
300
- 'This calendar contains new events. Please select a target calendar.' }), u("div", { className: "relative", children: [u("button", { ref: triggerRef, type: "button", className: "flex items-center w-full border border-gray-300 dark:border-gray-600 rounded-md px-3 py-2 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors shadow-sm", onClick: () => setIsOpen(!isOpen), children: [!isNewSelected && selectedCalendar && (u("div", { className: "mr-3 h-3 w-3 shrink-0 rounded-sm", style: { backgroundColor: selectedCalendar.colors.lineColor } })), u("span", { className: `text-sm font-medium text-gray-700 dark:text-gray-200 flex-1 text-left truncate ${isNewSelected ? 'pl-0' : ''}`, children: isNewSelected
250
+ return (u("div", { className: 'fixed inset-0 z-100 flex items-center justify-center bg-black/50', children: u("div", { className: 'w-full max-w-md rounded-lg bg-white p-6 shadow-xl dark:bg-slate-900', children: [u("h2", { className: 'mb-4 text-lg font-semibold text-gray-900 dark:text-white', children: t('addSchedule') || 'Add Schedule' }), u("p", { className: 'mb-4 text-sm text-gray-600 dark:text-gray-300', children: t('importCalendarMessage') ||
251
+ 'This calendar contains new events. Please select a target calendar.' }), u("div", { className: 'relative', children: [u("button", { ref: triggerRef, type: 'button', className: 'flex w-full items-center rounded-md border border-gray-300 px-3 py-2 shadow-sm transition-colors hover:bg-gray-50 dark:border-gray-600 dark:hover:bg-gray-800', onClick: () => setIsOpen(!isOpen), children: [!isNewSelected && selectedCalendar && (u("div", { className: 'mr-3 h-3 w-3 shrink-0 rounded-sm', style: { backgroundColor: selectedCalendar.colors.lineColor } })), u("span", { className: `flex-1 truncate text-left text-sm font-medium text-gray-700 dark:text-gray-200 ${isNewSelected ? 'pl-0' : ''}`, children: isNewSelected
301
252
  ? `${t('newCalendar')}: ${filename}`
302
- : (selectedCalendar === null || selectedCalendar === void 0 ? void 0 : selectedCalendar.name) || (selectedCalendar === null || selectedCalendar === void 0 ? void 0 : selectedCalendar.id) }), u(core.ChevronsUpDown, { className: "w-4 h-4 text-gray-400 shrink-0 ml-2" })] }), renderDropdown()] }), u("div", { className: "mt-8 flex justify-end gap-3", children: [u("button", { type: "button", onClick: onCancel, className: core.cancelButton, children: t('cancel') || 'Cancel' }), u("button", { type: "button", onClick: () => onConfirm(selectedCalendarId), className: "rounded-md bg-primary px-6 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors shadow-sm", children: t('ok') || 'OK' })] })] }) }));
253
+ : (selectedCalendar === null || selectedCalendar === void 0 ? void 0 : selectedCalendar.name) || (selectedCalendar === null || selectedCalendar === void 0 ? void 0 : selectedCalendar.id) }), u(core.ChevronsUpDown, { className: 'ml-2 h-4 w-4 shrink-0 text-gray-400' })] }), renderDropdown()] }), u("div", { className: 'mt-8 flex justify-end gap-3', children: [u("button", { type: 'button', onClick: onCancel, className: core.cancelButton, children: t('cancel') || 'Cancel' }), u("button", { type: 'button', onClick: () => onConfirm(selectedCalendarId), className: 'rounded-md bg-primary px-6 py-2 text-sm font-medium text-primary-foreground shadow-sm transition-colors hover:bg-primary/90', children: t('ok') || 'OK' })] })] }) }));
254
+ };
255
+
256
+ const MergeCalendarDialog = ({ sourceName, targetName, onConfirm, onCancel, }) => {
257
+ const { t } = core.useLocale();
258
+ return (u("div", { className: 'fixed inset-0 z-100 flex items-center justify-center bg-black/50', children: u("div", { className: 'w-full max-w-md rounded-lg bg-background p-6 shadow-xl', children: [u("h2", { className: 'text-lg font-semibold text-gray-900 dark:text-white', children: t('mergeConfirmTitle', { sourceName, targetName }) }), u("p", { className: 'mt-3 text-sm text-gray-600 dark:text-gray-300', children: t('mergeConfirmMessage', { sourceName, targetName }) }), u("div", { className: 'mt-6 flex justify-end gap-3', children: [u("button", { type: 'button', onClick: onCancel, className: core.cancelButton, children: t('cancel') }), u("button", { type: 'button', onClick: onConfirm, className: 'rounded-md bg-destructive px-3 py-2 text-xs font-medium text-destructive-foreground hover:bg-destructive/90', children: t('merge') })] })] }) }));
303
259
  };
304
260
 
305
- const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCollapsed, setCollapsed, renderCalendarContextMenu, editingCalendarId: propEditingCalendarId, setEditingCalendarId: propSetEditingCalendarId, onCreateCalendar, colorPickerMode = 'default', }) => {
261
+ const stopPropagation = (e) => e.stopPropagation();
262
+ const MergeMenuItem = ({ calendars, currentCalendarId, onMergeSelect, }) => {
263
+ const { t } = core.useLocale();
264
+ const [isHovered, setIsHovered] = hooks.useState(false);
265
+ const itemRef = hooks.useRef(null);
266
+ const submenuRef = hooks.useRef(null);
267
+ const [position, setPosition] = hooks.useState({ x: 0, y: 0 });
268
+ const timeoutRef = hooks.useRef();
269
+ const handleMouseEnter = () => {
270
+ if (timeoutRef.current)
271
+ clearTimeout(timeoutRef.current);
272
+ if (itemRef.current) {
273
+ const rect = itemRef.current.getBoundingClientRect();
274
+ setPosition({ x: rect.right, y: rect.top });
275
+ }
276
+ setIsHovered(true);
277
+ };
278
+ const handleMouseLeave = () => {
279
+ timeoutRef.current = setTimeout(() => {
280
+ setIsHovered(false);
281
+ }, 100);
282
+ };
283
+ hooks.useEffect(() => {
284
+ const el = submenuRef.current;
285
+ if (el) {
286
+ el.addEventListener('mousedown', stopPropagation);
287
+ return () => {
288
+ el.removeEventListener('mousedown', stopPropagation);
289
+ };
290
+ }
291
+ }, [isHovered]);
292
+ const availableCalendars = calendars.filter(c => c.id !== currentCalendarId);
293
+ if (availableCalendars.length === 0)
294
+ return null;
295
+ return (u(preact.Fragment, { children: [u("div", { ref: itemRef, className: 'relative flex cursor-default items-center justify-between rounded-sm px-3 py-0.5 text-[12px] transition-colors outline-none select-none hover:bg-primary hover:text-white dark:text-slate-200 dark:hover:bg-primary dark:hover:text-white', onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [u("span", { children: t('merge') }), u(core.ChevronRight, { className: 'h-4 w-4' })] }), isHovered &&
296
+ core.createPortal(u("div", { ref: submenuRef, "data-submenu-content": 'true', className: 'animate-in fade-in-0 zoom-in-95 fixed z-60 min-w-48 overflow-hidden rounded-md border border-slate-200 bg-white p-1 shadow-md duration-100 dark:border-slate-800 dark:bg-slate-950', style: { top: position.y, left: position.x }, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onMouseDown: e => e.stopPropagation(), children: availableCalendars.map(calendar => (u("div", { className: 'flex cursor-pointer items-center rounded-sm px-3 py-1 text-[12px] text-slate-900 transition-colors hover:bg-primary hover:text-white dark:text-slate-50 dark:hover:bg-primary dark:hover:text-white', onClick: e => {
297
+ e.stopPropagation();
298
+ onMergeSelect(calendar.id);
299
+ }, children: [u("div", { className: 'mr-2 h-3 w-3 shrink-0 rounded-sm', style: { backgroundColor: calendar.colors.lineColor } }), u("span", { className: 'truncate', children: calendar.name || calendar.id })] }, calendar.id))) }), document.body)] }));
300
+ };
301
+
302
+ const SidebarHeader = ({ isCollapsed, onCollapseToggle, }) => {
303
+ const { t } = core.useLocale();
304
+ return (u("div", { className: core.sidebarHeader, children: [u("button", { type: 'button', "aria-label": isCollapsed ? t('expandSidebar') : t('collapseSidebar'), className: core.sidebarHeaderToggle, onClick: onCollapseToggle, children: isCollapsed ? (u(core.PanelRightClose, { className: 'h-4 w-4 text-gray-500 dark:text-gray-400' })) : (u(core.PanelRightOpen, { className: 'h-4 w-4 text-gray-500 dark:text-gray-400' })) }), !isCollapsed && (u("div", { className: 'ml-3 flex flex-1 items-center justify-between', children: u("span", { className: core.sidebarHeaderTitle, children: t('calendars') }) }))] }));
305
+ };
306
+
307
+ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCollapsed, setCollapsed, renderCalendarContextMenu, editingCalendarId: propEditingCalendarId, setEditingCalendarId: propSetEditingCalendarId, onCreateCalendar, }) => {
306
308
  var _a, _b, _c, _d;
307
309
  const { t } = core.useLocale();
310
+ // Detect if custom color picker slot is provided
311
+ const hasCustomPicker = app.state.overrides.includes('colorPicker');
308
312
  const [localEditingCalendarId, setLocalEditingCalendarId] = hooks.useState(null);
309
- const editingCalendarId = propEditingCalendarId !== undefined
310
- ? propEditingCalendarId
311
- : localEditingCalendarId;
313
+ const editingCalendarId = propEditingCalendarId === undefined
314
+ ? localEditingCalendarId
315
+ : propEditingCalendarId;
312
316
  const setEditingCalendarId = propSetEditingCalendarId || setLocalEditingCalendarId;
313
317
  // File input ref for import
314
318
  const fileInputRef = hooks.useRef(null);
@@ -445,7 +449,7 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
445
449
  }, [handleCloseSidebarContextMenu]);
446
450
  const handleFileChange = hooks.useCallback((e) => __awaiter(void 0, void 0, void 0, function* () {
447
451
  var _a;
448
- const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
452
+ const file = (_a = e.currentTarget.files) === null || _a === void 0 ? void 0 : _a[0];
449
453
  if (!file)
450
454
  return;
451
455
  const result = yield core.importICSFile(file);
@@ -524,42 +528,53 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
524
528
  const readOnlyConfig = app.getReadOnlyConfig();
525
529
  const isEditable = !app.state.readOnly;
526
530
  const isDraggable = readOnlyConfig.draggable !== false;
527
- return (u("div", { className: core.sidebarContainer, onContextMenu: isEditable ? handleSidebarContextMenu : undefined, children: [u(SidebarHeader, { isCollapsed: isCollapsed, onCollapseToggle: () => setCollapsed(!isCollapsed) }), !isCollapsed ? (u(preact.Fragment, { children: [u(CalendarList, { calendars: calendars, onToggleVisibility: toggleCalendarVisibility, onReorder: isDraggable ? app.reorderCalendars : () => { }, onRename: isEditable
528
- ? (id, newName) => app.updateCalendar(id, { name: newName })
529
- : () => { }, onContextMenu: isEditable ? handleContextMenu : () => { }, editingId: editingCalendarId, setEditingId: setEditingCalendarId, activeContextMenuCalendarId: contextMenu === null || contextMenu === void 0 ? void 0 : contextMenu.calendarId, isDraggable: isDraggable, isEditable: isEditable }), u("div", { className: "border-t border-gray-200 dark:border-slate-800", children: u(core.MiniCalendar, { visibleMonth: app.getVisibleMonth(), currentDate: app.getCurrentDate(), showHeader: true, onMonthChange: handleMonthChange, onDateSelect: date => app.setCurrentDate(date) }) })] })) : (u(CalendarList, { calendars: calendars, onToggleVisibility: toggleCalendarVisibility, onReorder: isDraggable ? app.reorderCalendars : () => { }, onRename: isEditable
531
+ return (u("div", { className: core.sidebarContainer, onContextMenu: isEditable ? handleSidebarContextMenu : undefined, children: [u(SidebarHeader, { isCollapsed: isCollapsed, onCollapseToggle: () => setCollapsed(!isCollapsed) }), isCollapsed ? (u(CalendarList, { calendars: calendars, onToggleVisibility: toggleCalendarVisibility, onReorder: isDraggable
532
+ ? app.reorderCalendars
533
+ : () => {
534
+ /* noop */
535
+ }, onRename: isEditable
530
536
  ? (id, newName) => app.updateCalendar(id, { name: newName })
531
- : () => { }, onContextMenu: isEditable ? handleContextMenu : () => { }, editingId: editingCalendarId, setEditingId: setEditingCalendarId, activeContextMenuCalendarId: contextMenu === null || contextMenu === void 0 ? void 0 : contextMenu.calendarId, isDraggable: isDraggable, isEditable: isEditable })), contextMenu && (u(core.ContextMenu, { ref: contextMenuRef, x: contextMenu.x, y: contextMenu.y, onClose: handleCloseContextMenu, className: "w-64 p-2", children: u(core.ContentSlot, { generatorName: "calendarContextMenu", generatorArgs: {
537
+ : () => {
538
+ /* noop */
539
+ }, onContextMenu: isEditable
540
+ ? handleContextMenu
541
+ : () => {
542
+ /* noop */
543
+ }, editingId: editingCalendarId, setEditingId: setEditingCalendarId, activeContextMenuCalendarId: contextMenu === null || contextMenu === void 0 ? void 0 : contextMenu.calendarId, isDraggable: isDraggable, isEditable: isEditable })) : (u(preact.Fragment, { children: [u(CalendarList, { calendars: calendars, onToggleVisibility: toggleCalendarVisibility, onReorder: isDraggable
544
+ ? app.reorderCalendars
545
+ : () => {
546
+ /* noop */
547
+ }, onRename: isEditable
548
+ ? (id, newName) => app.updateCalendar(id, { name: newName })
549
+ : () => {
550
+ /* noop */
551
+ }, onContextMenu: isEditable
552
+ ? handleContextMenu
553
+ : () => {
554
+ /* noop */
555
+ }, editingId: editingCalendarId, setEditingId: setEditingCalendarId, activeContextMenuCalendarId: contextMenu === null || contextMenu === void 0 ? void 0 : contextMenu.calendarId, isDraggable: isDraggable, isEditable: isEditable }), u("div", { className: 'border-t border-gray-200 dark:border-slate-800', children: u(core.MiniCalendar, { visibleMonth: app.getVisibleMonth(), currentDate: app.getCurrentDate(), showHeader: true, onMonthChange: handleMonthChange, onDateSelect: date => app.setCurrentDate(date) }) })] })), contextMenu && (u(core.ContextMenu, { ref: contextMenuRef, x: contextMenu.x, y: contextMenu.y, onClose: handleCloseContextMenu, className: 'w-64 p-2', children: u(core.ContentSlot, { generatorName: 'calendarContextMenu', generatorArgs: {
532
556
  calendar: calendars.find(c => c.id === contextMenu.calendarId),
533
557
  onClose: handleCloseContextMenu,
534
558
  }, defaultContent: renderCalendarContextMenu ? (renderCalendarContextMenu(calendars.find(c => c.id === contextMenu.calendarId), handleCloseContextMenu)) : (u(preact.Fragment, { children: [u(core.ContextMenuLabel, { children: t('calendarOptions') }), u(MergeMenuItem, { calendars: calendars, currentCalendarId: contextMenu.calendarId, onMergeSelect: handleMergeSelect }), u(core.ContextMenuItem, { onClick: handleDeleteCalendar, children: t('delete') }), u(core.ContextMenuItem, { onClick: handleExportCalendar, children: t('exportCalendar') || 'Export Calendar' }), u(core.ContextMenuSeparator, {}), u(core.ContextMenuColorPicker, { selectedColor: (_d = calendars.find(c => c.id === contextMenu.calendarId)) === null || _d === void 0 ? void 0 : _d.colors.lineColor, onSelect: handleColorSelect, onCustomColor: handleCustomColor })] })) }) })), sidebarContextMenu &&
535
- core.createPortal(u(core.ContextMenu, { x: sidebarContextMenu.x, y: sidebarContextMenu.y, onClose: handleCloseSidebarContextMenu, className: "w-max p-2", children: [u(core.ContextMenuItem, { onClick: () => {
559
+ core.createPortal(u(core.ContextMenu, { x: sidebarContextMenu.x, y: sidebarContextMenu.y, onClose: handleCloseSidebarContextMenu, className: 'w-max p-2', children: [u(core.ContextMenuItem, { onClick: () => {
536
560
  onCreateCalendar === null || onCreateCalendar === void 0 ? void 0 : onCreateCalendar();
537
561
  handleCloseSidebarContextMenu();
538
562
  }, children: t('newCalendar') || 'New Calendar' }), u(core.ContextMenuItem, { onClick: handleImportClick, children: t('importCalendar') || 'Import Calendar' }), u(core.ContextMenuItem, { onClick: () => {
539
563
  app.triggerRender();
540
564
  handleCloseSidebarContextMenu();
541
- }, children: t('refreshAll') || 'Refresh All' })] }), document.body), u("input", { ref: fileInputRef, type: "file", accept: ".ics", style: { display: 'none' }, onChange: handleFileChange }), importState &&
565
+ }, children: t('refreshAll') || 'Refresh All' })] }), document.body), u("input", { ref: fileInputRef, type: 'file', accept: '.ics', style: { display: 'none' }, onChange: handleFileChange }), importState &&
542
566
  core.createPortal(u(ImportCalendarDialog, { calendars: calendars, filename: importState.filename, onConfirm: handleImportConfirm, onCancel: () => setImportState(null) }), document.body), mergeState &&
543
567
  core.createPortal(u(MergeCalendarDialog, { sourceName: sourceCalendarName, targetName: targetCalendarName, onConfirm: handleMergeConfirm, onCancel: () => setMergeState(null) }), document.body), deleteState &&
544
568
  core.createPortal(u(DeleteCalendarDialog, { calendarId: deleteState.calendarId, calendarName: deleteCalendarName, calendars: calendars, step: deleteState.step, onStepChange: step => setDeleteState(prev => (prev ? Object.assign(Object.assign({}, prev), { step }) : null)), onConfirmDelete: handleConfirmDelete, onCancel: () => setDeleteState(null), onMergeSelect: handleDeleteMergeSelect }), document.body), customColorPicker &&
545
- core.createPortal(u("div", { className: "fixed inset-0 z-50", onMouseDown: () => {
569
+ core.createPortal(u("div", { className: 'fixed inset-0 z-50', onMouseDown: () => {
546
570
  app.updateCalendar(customColorPicker.calendarId, {});
547
571
  setCustomColorPicker(null);
548
- }, children: u("div", { className: "absolute flex items-center justify-center", style: {
572
+ }, children: u("div", { className: 'absolute', style: {
549
573
  top: customColorPicker.y,
550
574
  left: customColorPicker.x,
551
- transform: 'translate(280%, -50%)',
552
- }, onMouseDown: e => e.stopPropagation(), children: colorPickerMode === 'custom' ? (u(core.BlossomColorPicker, { defaultValue: customColorPicker.initialColor, coreSize: 28, petalSize: 28, initialExpanded: true, adaptivePositioning: true, openOnHover: false, onChange: color => {
553
- const { colors, darkColors } = core.getCalendarColorsForHex(color.hex);
554
- app.updateCalendar(customColorPicker.calendarId, {
555
- colors,
556
- darkColors,
557
- }, true);
558
- }, onCollapse: () => {
559
- app.updateCalendar(customColorPicker.calendarId, {});
560
- setCustomColorPicker(null);
561
- } })) : (u(core.ContentSlot, { generatorName: "colorPicker", generatorArgs: {
562
- variant: 'sketch', // TODO: change name
575
+ zIndex: 10002,
576
+ transform: 'translate(40px, -50%)', // Move it to the right of the checkbox/dot
577
+ }, onMouseDown: e => e.stopPropagation(), children: hasCustomPicker ? (u(core.ContentSlot, { generatorName: 'colorPicker', generatorArgs: {
563
578
  color: customColorPicker.currentColor,
564
579
  onChange: (color) => {
565
580
  setCustomColorPicker(prev => prev ? Object.assign(Object.assign({}, prev), { currentColor: color.hex }) : null);
@@ -576,17 +591,26 @@ const DefaultCalendarSidebar = ({ app, calendars, toggleCalendarVisibility, isCo
576
591
  darkColors,
577
592
  });
578
593
  },
579
- }, defaultContent: u(core.DefaultColorPicker, { color: customColorPicker.currentColor, onChange: (color, isPending) => {
580
- setCustomColorPicker(prev => prev ? Object.assign(Object.assign({}, prev), { currentColor: color.hex }) : null);
581
- const { colors, darkColors } = core.getCalendarColorsForHex(color.hex);
582
- app.updateCalendar(customColorPicker.calendarId, {
583
- colors,
584
- darkColors,
585
- }, isPending);
586
- }, onClose: () => {
587
- app.updateCalendar(customColorPicker.calendarId, {});
588
- setCustomColorPicker(null);
589
- } }) })) }) }), document.body)] }));
594
+ }, defaultContent: u("div", { className: 'rounded-lg border border-gray-200 bg-white p-3 shadow-xl dark:border-gray-700 dark:bg-slate-900', children: u(core.DefaultColorPicker, { color: customColorPicker.currentColor, onChange: (color, isPending) => {
595
+ setCustomColorPicker(prev => prev ? Object.assign(Object.assign({}, prev), { currentColor: color.hex }) : null);
596
+ const { colors, darkColors } = core.getCalendarColorsForHex(color.hex);
597
+ app.updateCalendar(customColorPicker.calendarId, {
598
+ colors,
599
+ darkColors,
600
+ }, isPending);
601
+ }, onClose: () => {
602
+ app.updateCalendar(customColorPicker.calendarId, {});
603
+ setCustomColorPicker(null);
604
+ } }) }) })) : (u(core.BlossomColorPicker, { defaultValue: customColorPicker.initialColor, coreSize: 28, petalSize: 28, initialExpanded: true, adaptivePositioning: true, openOnHover: false, onChange: color => {
605
+ const { colors, darkColors } = core.getCalendarColorsForHex(color.hex);
606
+ app.updateCalendar(customColorPicker.calendarId, {
607
+ colors,
608
+ darkColors,
609
+ }, true);
610
+ }, onCollapse: () => {
611
+ app.updateCalendar(customColorPicker.calendarId, {});
612
+ setCustomColorPicker(null);
613
+ } })) }) }), document.body)] }));
590
614
  };
591
615
 
592
616
  const DEFAULT_SIDEBAR_WIDTH = '240px';
@@ -615,11 +639,9 @@ function createSidebarPlugin(config = {}) {
615
639
  const refreshSidebar = hooks.useCallback(() => {
616
640
  setSidebarVersion(prev => prev + 1);
617
641
  }, []);
618
- hooks.useEffect(() => {
619
- return app.subscribe(() => {
620
- refreshSidebar();
621
- });
622
- }, [app, refreshSidebar]);
642
+ hooks.useEffect(() => app.subscribe(() => {
643
+ refreshSidebar();
644
+ }), [app, refreshSidebar]);
623
645
  const calendars = hooks.useMemo(() => app.getCalendars(), [app, sidebarVersion]);
624
646
  const handleToggleCalendarVisibility = hooks.useCallback((calendarId, visible) => {
625
647
  app.setCalendarVisibility(calendarId, visible);
@@ -663,7 +685,6 @@ function createSidebarPlugin(config = {}) {
663
685
  editingCalendarId,
664
686
  setEditingCalendarId,
665
687
  onCreateCalendar: handleCreateCalendar,
666
- colorPickerMode: config.colorPickerMode,
667
688
  }), [
668
689
  app,
669
690
  calendars,
@@ -675,14 +696,13 @@ function createSidebarPlugin(config = {}) {
675
696
  config,
676
697
  ]);
677
698
  const renderContent = () => {
678
- var _a;
679
699
  if (config.render) {
680
700
  return preact.h(core.ContentSlot, {
681
701
  generatorName: 'sidebar',
682
702
  generatorArgs: sidebarProps,
683
703
  });
684
704
  }
685
- return preact.h(DefaultCalendarSidebar, Object.assign(Object.assign({}, sidebarProps), { colorPickerMode: (_a = config.colorPickerMode) !== null && _a !== void 0 ? _a : sidebarProps.colorPickerMode }));
705
+ return preact.h(DefaultCalendarSidebar, Object.assign({}, sidebarProps));
686
706
  };
687
707
  const renderExtraContent = () => {
688
708
  if (!showCreateDialog)
@@ -696,7 +716,7 @@ function createSidebarPlugin(config = {}) {
696
716
  const generatorArgs = {
697
717
  onClose,
698
718
  onCreate,
699
- colorPickerMode: config.colorPickerMode,
719
+ app,
700
720
  };
701
721
  return preact.h(core.ContentSlot, {
702
722
  generatorName: 'createCalendarDialog',
@@ -704,7 +724,7 @@ function createSidebarPlugin(config = {}) {
704
724
  defaultContent: preact.h(core.CreateCalendarDialog, {
705
725
  onClose,
706
726
  onCreate,
707
- colorPickerMode: config.colorPickerMode,
727
+ app,
708
728
  }),
709
729
  });
710
730
  };
@@ -1,3 +1,4 @@
1
+ import { JSX } from 'preact';
1
2
  import type { CalendarSidebarRenderProps } from './plugin';
2
- declare const DefaultCalendarSidebar: ({ app, calendars, toggleCalendarVisibility, isCollapsed, setCollapsed, renderCalendarContextMenu, editingCalendarId: propEditingCalendarId, setEditingCalendarId: propSetEditingCalendarId, onCreateCalendar, colorPickerMode, }: CalendarSidebarRenderProps) => import("preact").JSX.Element;
3
+ declare const DefaultCalendarSidebar: ({ app, calendars, toggleCalendarVisibility, isCollapsed, setCollapsed, renderCalendarContextMenu, editingCalendarId: propEditingCalendarId, setEditingCalendarId: propSetEditingCalendarId, onCreateCalendar, }: CalendarSidebarRenderProps) => JSX.Element;
3
4
  export default DefaultCalendarSidebar;
@@ -1,15 +1,16 @@
1
1
  import { CalendarType } from '@dayflow/core';
2
+ import { JSX } from 'preact';
2
3
  interface CalendarListProps {
3
4
  calendars: CalendarType[];
4
5
  onToggleVisibility: (id: string, visible: boolean) => void;
5
6
  onReorder: (fromIndex: number, toIndex: number) => void;
6
7
  onRename: (id: string, newName: string) => void;
7
- onContextMenu: (e: any, id: string) => void;
8
+ onContextMenu: (e: JSX.TargetedMouseEvent<HTMLElement>, id: string) => void;
8
9
  editingId: string | null;
9
10
  setEditingId: (id: string | null) => void;
10
11
  activeContextMenuCalendarId?: string | null;
11
12
  isDraggable?: boolean;
12
13
  isEditable?: boolean;
13
14
  }
14
- export declare const CalendarList: ({ calendars, onToggleVisibility, onReorder, onRename, onContextMenu, editingId, setEditingId, activeContextMenuCalendarId, isDraggable, isEditable, }: CalendarListProps) => import("preact").JSX.Element;
15
+ export declare const CalendarList: ({ calendars, onToggleVisibility, onReorder, onRename, onContextMenu, editingId, setEditingId, activeContextMenuCalendarId, isDraggable, isEditable, }: CalendarListProps) => JSX.Element;
15
16
  export {};
@@ -12,14 +12,12 @@ export interface CalendarSidebarRenderProps {
12
12
  editingCalendarId?: string | null;
13
13
  setEditingCalendarId?: (id: string | null) => void;
14
14
  onCreateCalendar?: () => void;
15
- colorPickerMode?: 'default' | 'custom';
16
15
  }
17
16
  export interface SidebarPluginConfig {
18
17
  width?: number | string;
19
18
  miniWidth?: string;
20
19
  initialCollapsed?: boolean;
21
20
  createCalendarMode?: 'inline' | 'modal';
22
- colorPickerMode?: 'default' | 'custom';
23
21
  render?: (props: CalendarSidebarRenderProps) => TNode;
24
22
  renderCalendarContextMenu?: (calendar: CalendarType, onClose: () => void) => TNode;
25
23
  renderCreateCalendarDialog?: (props: CreateCalendarDialogProps) => TNode;
package/package.json CHANGED
@@ -1,8 +1,21 @@
1
1
  {
2
2
  "name": "@dayflow/plugin-sidebar",
3
- "version": "1.0.2",
4
- "type": "module",
3
+ "version": "1.1.1",
5
4
  "description": "Sidebar plugin for DayFlow calendar",
5
+ "keywords": [
6
+ "calendar",
7
+ "dayflow",
8
+ "plugin",
9
+ "sidebar"
10
+ ],
11
+ "license": "MIT",
12
+ "author": "Jayce Li",
13
+ "files": [
14
+ "dist",
15
+ "README.md",
16
+ "LICENSE"
17
+ ],
18
+ "type": "module",
6
19
  "main": "dist/index.js",
7
20
  "module": "dist/index.esm.js",
8
21
  "types": "dist/index.d.ts",
@@ -13,36 +26,25 @@
13
26
  "require": "./dist/index.js"
14
27
  }
15
28
  },
16
- "files": [
17
- "dist",
18
- "README.md",
19
- "LICENSE"
20
- ],
21
- "keywords": [
22
- "calendar",
23
- "sidebar",
24
- "dayflow",
25
- "plugin"
26
- ],
27
- "author": "Jayce Li",
28
- "license": "MIT",
29
- "peerDependencies": {
30
- "@dayflow/core": "3.1.2"
31
- },
32
29
  "devDependencies": {
33
30
  "@dayflow/blossom-color-picker": "^2.0.1",
34
31
  "@rollup/plugin-commonjs": "^28.0.2",
35
32
  "@rollup/plugin-node-resolve": "^16.0.0",
36
33
  "@rollup/plugin-typescript": "^12.1.2",
34
+ "preact": "^10.28.3",
35
+ "rimraf": "^6.1.2",
37
36
  "rollup": "^4.29.1",
38
37
  "rollup-plugin-dts": "^6.3.0",
39
- "preact": "^10.25.4",
40
38
  "temporal-polyfill": "^0.3.0",
41
- "typescript": "^5.7.2",
42
- "@dayflow/core": "3.1.2"
39
+ "typescript": "^5.9.3",
40
+ "@dayflow/core": "3.2.1"
41
+ },
42
+ "peerDependencies": {
43
+ "@dayflow/core": "3.2.1"
43
44
  },
44
45
  "scripts": {
45
- "build": "tsc -p tsconfig.build.json && rollup -c",
46
+ "build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && rollup -c",
47
+ "clean": "rimraf dist node_modules",
46
48
  "typecheck": "tsc --noEmit"
47
49
  }
48
50
  }