@djangocfg/ui-tools 2.1.411 → 2.1.412

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/package.json +6 -6
  2. package/src/tools/Chat/composer/AttachContext.tsx +22 -0
  3. package/src/tools/Chat/composer/Composer.tsx +108 -6
  4. package/src/tools/Chat/composer/ComposerMenuButton.tsx +39 -2
  5. package/src/tools/Chat/composer/fileToAttachment.ts +53 -0
  6. package/src/tools/Chat/composer/index.ts +16 -1
  7. package/src/tools/Chat/composer/types.ts +71 -0
  8. package/src/tools/Chat/composer/useComposerAttach.tsx +218 -0
  9. package/src/tools/Chat/hooks/useChat.ts +32 -0
  10. package/src/tools/Chat/hooks/useChatComposer.ts +13 -0
  11. package/src/tools/Chat/messages/MessageBubble.tsx +1 -1
  12. package/src/tools/Chat/public.ts +1 -0
  13. package/src/tools/Chat/types/events.ts +50 -0
  14. package/src/tools/Chat/types/index.ts +1 -1
  15. package/src/tools/Chat/types/message.ts +5 -0
  16. package/src/tools/CronScheduler/CronScheduler.client.tsx +42 -15
  17. package/src/tools/CronScheduler/components/CustomInput.tsx +26 -7
  18. package/src/tools/CronScheduler/components/DayChips.tsx +20 -7
  19. package/src/tools/CronScheduler/components/MonthDayGrid.tsx +35 -10
  20. package/src/tools/CronScheduler/components/SchedulePreview.tsx +8 -5
  21. package/src/tools/CronScheduler/components/ScheduleTypeSelector.tsx +12 -3
  22. package/src/tools/CronScheduler/components/TimeSelector.tsx +36 -13
  23. package/src/tools/CronScheduler/context/CronSchedulerContext.tsx +4 -0
  24. package/src/tools/CronScheduler/context/hooks.ts +8 -0
  25. package/src/tools/CronScheduler/context/index.ts +1 -0
  26. package/src/tools/CronScheduler/index.tsx +2 -0
  27. package/src/tools/CronScheduler/lazy.tsx +1 -0
  28. package/src/tools/CronScheduler/types/index.ts +18 -1
  29. package/src/tools/Map/lazy.tsx +11 -4
  30. package/src/tools/Uploader/hooks/useClipboardPaste.ts +3 -1
  31. package/src/tools/index.ts +2 -0
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  import { cn } from '@djangocfg/ui-core/lib';
11
- import { useCronWeekDays } from '../context/hooks';
11
+ import { useCronWeekDays, useCronSize } from '../context/hooks';
12
12
  import type { WeekDay } from '../types';
13
13
 
14
14
  const DAYS: { value: WeekDay; label: string; full: string }[] = [
@@ -33,6 +33,7 @@ export function DayChips({
33
33
  className,
34
34
  }: DayChipsProps) {
35
35
  const { weekDays, toggleWeekDay, setWeekDays } = useCronWeekDays();
36
+ const isSm = useCronSize() === 'sm';
36
37
 
37
38
  // Ensure weekDays is always an array
38
39
  const safeWeekDays = Array.isArray(weekDays) ? weekDays : [];
@@ -54,7 +55,10 @@ export function DayChips({
54
55
  isWeekendDay,
55
56
  className: cn(
56
57
  'flex flex-col items-center justify-center',
57
- 'py-2.5 rounded-lg text-xs font-medium',
58
+ 'font-medium',
59
+ isSm
60
+ ? 'h-6 rounded-md text-[11px] leading-none'
61
+ : 'py-2.5 rounded-lg text-xs',
58
62
  'transition-all duration-150',
59
63
  'focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/50',
60
64
  'active:scale-[0.97]',
@@ -76,9 +80,13 @@ export function DayChips({
76
80
  ];
77
81
 
78
82
  return (
79
- <div className={cn('space-y-3', className)}>
83
+ <div className={cn(isSm ? 'space-y-1.5' : 'space-y-3', className)}>
80
84
  {/* Day Grid - full width */}
81
- <div className="grid grid-cols-7 gap-1" role="group" aria-label="Days of week">
85
+ <div
86
+ className={cn('grid grid-cols-7', isSm ? 'gap-1' : 'gap-1')}
87
+ role="group"
88
+ aria-label="Days of week"
89
+ >
82
90
  {dayButtons.map((day) => (
83
91
  <button
84
92
  key={day.value}
@@ -96,7 +104,7 @@ export function DayChips({
96
104
 
97
105
  {/* Quick Presets */}
98
106
  {showPresets && (
99
- <div className="flex gap-2">
107
+ <div className={cn('flex', isSm ? 'gap-1' : 'gap-2')}>
100
108
  {presets.map((preset) => (
101
109
  <PresetButton
102
110
  key={preset.label}
@@ -104,6 +112,7 @@ export function DayChips({
104
112
  isActive={preset.isActive}
105
113
  onClick={() => setWeekDays(preset.days)}
106
114
  disabled={disabled}
115
+ compact={isSm}
107
116
  />
108
117
  ))}
109
118
  </div>
@@ -117,16 +126,20 @@ interface PresetButtonProps {
117
126
  isActive: boolean;
118
127
  onClick: () => void;
119
128
  disabled?: boolean;
129
+ compact?: boolean;
120
130
  }
121
131
 
122
- function PresetButton({ label, isActive, onClick, disabled }: PresetButtonProps) {
132
+ function PresetButton({ label, isActive, onClick, disabled, compact }: PresetButtonProps) {
123
133
  return (
124
134
  <button
125
135
  type="button"
126
136
  disabled={disabled}
127
137
  onClick={onClick}
128
138
  className={cn(
129
- 'flex-1 px-3 py-1.5 rounded-md text-xs font-medium',
139
+ 'flex-1 rounded-md font-medium',
140
+ compact
141
+ ? 'h-6 px-1.5 text-[11px] leading-none'
142
+ : 'px-3 py-1.5 text-xs',
130
143
  'transition-colors duration-150',
131
144
  'focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/50',
132
145
  isActive
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  import { cn } from '@djangocfg/ui-core/lib';
11
- import { useCronMonthDays } from '../context/hooks';
11
+ import { useCronMonthDays, useCronSize } from '../context/hooks';
12
12
  import type { MonthDay } from '../types';
13
13
 
14
14
  // Generate days 1-31
@@ -29,6 +29,7 @@ export function MonthDayGrid({
29
29
  className,
30
30
  }: MonthDayGridProps) {
31
31
  const { monthDays, toggleMonthDay, setMonthDays } = useCronMonthDays();
32
+ const isSm = useCronSize() === 'sm';
32
33
 
33
34
  // Ensure monthDays is always an array
34
35
  const safeMonthDays = Array.isArray(monthDays) ? monthDays : [];
@@ -61,8 +62,11 @@ export function MonthDayGrid({
61
62
  day: day as MonthDay,
62
63
  isSelected,
63
64
  className: cn(
64
- 'aspect-square flex items-center justify-center',
65
- 'rounded-lg text-sm font-medium',
65
+ 'flex items-center justify-center',
66
+ 'font-medium',
67
+ isSm
68
+ ? 'h-7 rounded-[5px] text-[10px] leading-none'
69
+ : 'aspect-square rounded-lg text-sm',
66
70
  'transition-all duration-150',
67
71
  'focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/50',
68
72
  'active:scale-[0.95]',
@@ -82,10 +86,10 @@ export function MonthDayGrid({
82
86
  const selectionCount = safeMonthDays.length;
83
87
 
84
88
  return (
85
- <div className={cn('space-y-3', className)}>
89
+ <div className={cn(isSm ? 'space-y-1.5' : 'space-y-3', className)}>
86
90
  {/* Quick Presets */}
87
91
  {showPresets && (
88
- <div className="flex gap-2">
92
+ <div className={cn('flex', isSm ? 'gap-1' : 'gap-2')}>
89
93
  {presets.map((preset) => (
90
94
  <PresetButton
91
95
  key={preset.label}
@@ -93,16 +97,27 @@ export function MonthDayGrid({
93
97
  isActive={preset.isActive}
94
98
  onClick={() => setMonthDays(preset.days)}
95
99
  disabled={disabled}
100
+ compact={isSm}
96
101
  />
97
102
  ))}
98
103
  </div>
99
104
  )}
100
105
 
101
106
  {/* Calendar Grid - full width */}
102
- <div className="grid grid-cols-7 gap-1" role="group" aria-label="Days of month">
107
+ <div
108
+ className={cn('grid grid-cols-7', isSm ? 'gap-0.5' : 'gap-1')}
109
+ role="group"
110
+ aria-label="Days of month"
111
+ >
103
112
  {gridCells.map((cell) => {
104
113
  if (cell.type === 'empty') {
105
- return <div key={cell.key} aria-hidden="true" className="aspect-square" />;
114
+ return (
115
+ <div
116
+ key={cell.key}
117
+ aria-hidden="true"
118
+ className={isSm ? 'h-7' : 'aspect-square'}
119
+ />
120
+ );
106
121
  }
107
122
 
108
123
  return (
@@ -123,7 +138,13 @@ export function MonthDayGrid({
123
138
 
124
139
  {/* Selection hint */}
125
140
  {selectionCount > 1 && (
126
- <p aria-live="polite" className="text-xs text-muted-foreground text-center">
141
+ <p
142
+ aria-live="polite"
143
+ className={cn(
144
+ 'text-muted-foreground text-center',
145
+ isSm ? 'text-[10px]' : 'text-xs'
146
+ )}
147
+ >
127
148
  {selectionCount} days selected
128
149
  </p>
129
150
  )}
@@ -136,16 +157,20 @@ interface PresetButtonProps {
136
157
  isActive: boolean;
137
158
  onClick: () => void;
138
159
  disabled?: boolean;
160
+ compact?: boolean;
139
161
  }
140
162
 
141
- function PresetButton({ label, isActive, onClick, disabled }: PresetButtonProps) {
163
+ function PresetButton({ label, isActive, onClick, disabled, compact }: PresetButtonProps) {
142
164
  return (
143
165
  <button
144
166
  type="button"
145
167
  disabled={disabled}
146
168
  onClick={onClick}
147
169
  className={cn(
148
- 'flex-1 px-3 py-1.5 rounded-md text-xs font-medium',
170
+ 'flex-1 rounded-md font-medium',
171
+ compact
172
+ ? 'h-6 px-1.5 text-[11px] leading-none'
173
+ : 'px-3 py-1.5 text-xs',
149
174
  'transition-colors duration-150',
150
175
  'focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/50',
151
176
  isActive
@@ -10,7 +10,7 @@
10
10
  import { useState, useCallback, useMemo } from 'react';
11
11
  import { Calendar, Copy, Check, ArrowRight } from 'lucide-react';
12
12
  import { cn } from '@djangocfg/ui-core/lib';
13
- import { useCronPreview } from '../context/hooks';
13
+ import { useCronPreview, useCronSize } from '../context/hooks';
14
14
  import { CronCheatsheet } from './CronCheatsheet';
15
15
 
16
16
  export interface SchedulePreviewProps {
@@ -31,6 +31,7 @@ export function SchedulePreview({
31
31
  className,
32
32
  }: SchedulePreviewProps) {
33
33
  const { cronExpression, humanDescription, isValid, initialValue } = useCronPreview();
34
+ const isSm = useCronSize() === 'sm';
34
35
 
35
36
  // Check if value has changed from initial
36
37
  const hasChanged = useMemo(
@@ -54,7 +55,8 @@ export function SchedulePreview({
54
55
  role="status"
55
56
  aria-live="polite"
56
57
  className={cn(
57
- 'px-3 py-2.5 rounded-lg border',
58
+ 'rounded-lg border',
59
+ isSm ? 'px-2 py-1.5' : 'px-3 py-2.5',
58
60
  'bg-muted/30 border-border/50',
59
61
  !isValid && 'border-destructive/30 bg-destructive/5',
60
62
  className
@@ -62,17 +64,18 @@ export function SchedulePreview({
62
64
  >
63
65
  {/* Human description */}
64
66
  <div className="flex items-center justify-between gap-2">
65
- <div className="flex items-center gap-2 min-w-0">
67
+ <div className={cn('flex items-center min-w-0', isSm ? 'gap-1.5' : 'gap-2')}>
66
68
  <Calendar
67
69
  aria-hidden="true"
68
70
  className={cn(
69
- 'h-4 w-4 shrink-0',
71
+ 'shrink-0',
72
+ isSm ? 'h-3.5 w-3.5' : 'h-4 w-4',
70
73
  isValid ? 'text-primary' : 'text-destructive'
71
74
  )}
72
75
  />
73
76
  <span
74
77
  className={cn(
75
- 'text-sm',
78
+ isSm ? 'text-xs' : 'text-sm',
76
79
  isValid ? 'text-foreground' : 'text-destructive'
77
80
  )}
78
81
  >
@@ -9,7 +9,7 @@
9
9
 
10
10
  import { Tabs, TabsList, TabsTrigger } from '@djangocfg/ui-core/components';
11
11
  import { cn } from '@djangocfg/ui-core/lib';
12
- import { useCronType } from '../context/hooks';
12
+ import { useCronType, useCronSize } from '../context/hooks';
13
13
  import type { ScheduleType } from '../types';
14
14
 
15
15
  const SCHEDULE_TYPES: { value: ScheduleType; label: string }[] = [
@@ -29,9 +29,13 @@ export function ScheduleTypeSelector({
29
29
  className,
30
30
  }: ScheduleTypeSelectorProps) {
31
31
  const { type, setType } = useCronType();
32
+ const isSm = useCronSize() === 'sm';
32
33
 
33
34
  const triggerClassName = cn(
34
- 'text-xs font-medium px-2 py-1.5',
35
+ 'font-medium',
36
+ isSm
37
+ ? 'text-[11px] leading-none px-1 py-0.5 h-6 rounded-[5px]'
38
+ : 'text-xs px-2 py-1.5',
35
39
  'data-[state=active]:shadow-sm',
36
40
  'transition-all duration-150'
37
41
  );
@@ -49,7 +53,12 @@ export function ScheduleTypeSelector({
49
53
  onValueChange={(v) => setType(v as ScheduleType)}
50
54
  className={cn('w-full', className)}
51
55
  >
52
- <TabsList className="grid w-full grid-cols-4 h-9 p-0.5">
56
+ <TabsList
57
+ className={cn(
58
+ 'grid w-full grid-cols-4',
59
+ isSm ? 'h-7 p-0.5 gap-0.5' : 'h-9 p-0.5'
60
+ )}
61
+ >
53
62
  {triggers.map((trigger) => (
54
63
  <TabsTrigger
55
64
  key={trigger.value}
@@ -15,7 +15,7 @@ import {
15
15
  } from '@djangocfg/ui-core/components';
16
16
  import { cn } from '@djangocfg/ui-core/lib';
17
17
  import { Clock } from 'lucide-react';
18
- import { useCronTime } from '../context/hooks';
18
+ import { useCronTime, useCronSize } from '../context/hooks';
19
19
 
20
20
  const HOURS = Array.from({ length: 24 }, (_, i) => i);
21
21
  const MINUTES = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55];
@@ -32,6 +32,7 @@ export function TimeSelector({
32
32
  className,
33
33
  }: TimeSelectorProps) {
34
34
  const { hour, minute, setTime } = useCronTime();
35
+ const isSm = useCronSize() === 'sm';
35
36
 
36
37
  const is24h = format === '24h';
37
38
  const displayHour = is24h ? hour : (hour % 12) || 12;
@@ -60,28 +61,50 @@ export function TimeSelector({
60
61
 
61
62
  const hours = is24h ? HOURS : Array.from({ length: 12 }, (_, i) => i + 1);
62
63
 
64
+ // Compact-aware class fragments
65
+ const triggerClassName = cn(
66
+ isSm ? 'w-[58px] h-7 px-2 text-xs' : 'w-[70px] h-9'
67
+ );
68
+ const itemClassName = isSm ? 'text-xs' : undefined;
69
+
63
70
  return (
64
- <div className={cn('flex items-center gap-3', className)}>
65
- <div className="flex items-center gap-2 text-muted-foreground">
66
- <Clock aria-hidden="true" className="h-4 w-4" />
67
- <span className="text-sm">Run at</span>
71
+ <div
72
+ className={cn(
73
+ 'flex items-center',
74
+ isSm ? 'gap-2' : 'gap-3',
75
+ className
76
+ )}
77
+ >
78
+ <div
79
+ className={cn(
80
+ 'flex items-center text-muted-foreground',
81
+ isSm ? 'gap-1.5' : 'gap-2'
82
+ )}
83
+ >
84
+ <Clock
85
+ aria-hidden="true"
86
+ className={isSm ? 'h-3.5 w-3.5' : 'h-4 w-4'}
87
+ />
88
+ <span className={isSm ? 'text-xs' : 'text-sm'}>Run at</span>
68
89
  </div>
69
90
 
70
- <div className="flex items-center gap-1.5 flex-1">
91
+ <div
92
+ className={cn('flex items-center flex-1', isSm ? 'gap-1' : 'gap-1.5')}
93
+ >
71
94
  {/* Hour */}
72
95
  <Select
73
96
  value={displayHour.toString()}
74
97
  onValueChange={handleHourChange}
75
98
  disabled={disabled}
76
99
  >
77
- <SelectTrigger className="w-[70px] h-9">
100
+ <SelectTrigger className={triggerClassName}>
78
101
  <SelectValue>
79
102
  {displayHour.toString().padStart(2, '0')}
80
103
  </SelectValue>
81
104
  </SelectTrigger>
82
105
  <SelectContent className="max-h-48">
83
106
  {hours.map((h) => (
84
- <SelectItem key={h} value={h.toString()}>
107
+ <SelectItem key={h} value={h.toString()} className={itemClassName}>
85
108
  {h.toString().padStart(2, '0')}
86
109
  </SelectItem>
87
110
  ))}
@@ -96,14 +119,14 @@ export function TimeSelector({
96
119
  onValueChange={handleMinuteChange}
97
120
  disabled={disabled}
98
121
  >
99
- <SelectTrigger className="w-[70px] h-9">
122
+ <SelectTrigger className={triggerClassName}>
100
123
  <SelectValue>
101
124
  {minute.toString().padStart(2, '0')}
102
125
  </SelectValue>
103
126
  </SelectTrigger>
104
127
  <SelectContent className="max-h-48">
105
128
  {MINUTES.map((m) => (
106
- <SelectItem key={m} value={m.toString()}>
129
+ <SelectItem key={m} value={m.toString()} className={itemClassName}>
107
130
  {m.toString().padStart(2, '0')}
108
131
  </SelectItem>
109
132
  ))}
@@ -117,12 +140,12 @@ export function TimeSelector({
117
140
  onValueChange={handlePeriodChange}
118
141
  disabled={disabled}
119
142
  >
120
- <SelectTrigger className="w-[70px] h-9">
143
+ <SelectTrigger className={triggerClassName}>
121
144
  <SelectValue />
122
145
  </SelectTrigger>
123
146
  <SelectContent>
124
- <SelectItem value="AM">AM</SelectItem>
125
- <SelectItem value="PM">PM</SelectItem>
147
+ <SelectItem value="AM" className={itemClassName}>AM</SelectItem>
148
+ <SelectItem value="PM" className={itemClassName}>PM</SelectItem>
126
149
  </SelectContent>
127
150
  </Select>
128
151
  )}
@@ -57,6 +57,7 @@ export function CronSchedulerProvider({
57
57
  value,
58
58
  onChange,
59
59
  defaultType = 'daily',
60
+ size = 'default',
60
61
  }: CronSchedulerProviderProps) {
61
62
  // Track if this is initial mount to avoid calling onChange on mount
62
63
  const isInitialMount = useRef(true);
@@ -203,6 +204,8 @@ export function CronSchedulerProvider({
203
204
  () => ({
204
205
  // State
205
206
  ...state,
207
+ // Config
208
+ size,
206
209
  // Computed
207
210
  cronExpression,
208
211
  humanDescription,
@@ -219,6 +222,7 @@ export function CronSchedulerProvider({
219
222
  }),
220
223
  [
221
224
  state,
225
+ size,
222
226
  cronExpression,
223
227
  humanDescription,
224
228
  initialValue,
@@ -78,6 +78,14 @@ export function useCronPreview() {
78
78
  );
79
79
  }
80
80
 
81
+ /**
82
+ * Hook for the configured visual density (`default` | `sm`).
83
+ * Returns a stable value — never causes re-renders by itself.
84
+ */
85
+ export function useCronSize() {
86
+ return useCronSchedulerContext().size;
87
+ }
88
+
81
89
  /**
82
90
  * Full context access
83
91
  * Use sparingly - causes re-render on any state change
@@ -14,5 +14,6 @@ export {
14
14
  useCronMonthDays,
15
15
  useCronCustom,
16
16
  useCronPreview,
17
+ useCronSize,
17
18
  useCronScheduler,
18
19
  } from './hooks';
@@ -50,6 +50,7 @@ function CronSchedulerFallback() {
50
50
  // Re-export types
51
51
  export type {
52
52
  CronSchedulerProps,
53
+ CronSchedulerSize,
53
54
  ScheduleType,
54
55
  WeekDay,
55
56
  MonthDay,
@@ -67,6 +68,7 @@ export {
67
68
  useCronMonthDays,
68
69
  useCronCustom,
69
70
  useCronPreview,
71
+ useCronSize,
70
72
  useCronScheduler,
71
73
  } from './context';
72
74
 
@@ -21,6 +21,7 @@ import type { CronSchedulerProps } from './types';
21
21
  // Re-export types
22
22
  export type {
23
23
  CronSchedulerProps,
24
+ CronSchedulerSize,
24
25
  ScheduleType,
25
26
  WeekDay,
26
27
  MonthDay,
@@ -10,6 +10,13 @@
10
10
 
11
11
  export type ScheduleType = 'daily' | 'weekly' | 'monthly' | 'custom';
12
12
 
13
+ /**
14
+ * Visual density of the scheduler fields.
15
+ * - `default` — full-size fields (unchanged).
16
+ * - `sm` — compact fields for narrow side panels / modals (~360-420px).
17
+ */
18
+ export type CronSchedulerSize = 'default' | 'sm';
19
+
13
20
  /** Day of week: 0 = Sunday, 1 = Monday, ..., 6 = Saturday */
14
21
  export type WeekDay = 0 | 1 | 2 | 3 | 4 | 5 | 6;
15
22
 
@@ -79,7 +86,10 @@ export interface CronSchedulerActions {
79
86
  export interface CronSchedulerContextValue
80
87
  extends CronSchedulerState,
81
88
  CronSchedulerComputed,
82
- CronSchedulerActions {}
89
+ CronSchedulerActions {
90
+ /** Visual density of the fields (`default` | `sm`) */
91
+ size: CronSchedulerSize;
92
+ }
83
93
 
84
94
  // ============================================================================
85
95
  // Component Props
@@ -107,6 +117,11 @@ export interface CronSchedulerProps {
107
117
  inline?: boolean;
108
118
  /** Trigger text shown when no schedule is set (compact mode only) */
109
119
  placeholder?: string;
120
+ /**
121
+ * Visual density of the fields. `sm` renders smaller, tighter fields
122
+ * suited for narrow side panels / modals. Default: `default`.
123
+ */
124
+ size?: CronSchedulerSize;
110
125
  /** Additional CSS classes */
111
126
  className?: string;
112
127
  }
@@ -116,4 +131,6 @@ export interface CronSchedulerProviderProps {
116
131
  value?: string;
117
132
  onChange?: (cron: string) => void;
118
133
  defaultType?: ScheduleType;
134
+ /** Visual density propagated to all field components. Default: `default`. */
135
+ size?: CronSchedulerSize;
119
136
  }
@@ -12,6 +12,7 @@
12
12
 
13
13
  import * as React from 'react';
14
14
  import { createLazyComponent, MapLoadingFallback } from '../../components';
15
+ import type { MapContainerProps } from './components';
15
16
 
16
17
  // ============================================================================
17
18
  // Lazy Components
@@ -22,8 +23,11 @@ import { createLazyComponent, MapLoadingFallback } from '../../components';
22
23
  *
23
24
  * Automatically shows loading state while MapLibre GL loads (~800KB)
24
25
  */
25
- export const LazyMapContainer = createLazyComponent(
26
- () => import('./components/MapContainer').then((mod) => ({ default: mod.MapContainer })),
26
+ export const LazyMapContainer = createLazyComponent<MapContainerProps>(
27
+ () =>
28
+ import('./components/MapContainer').then((mod) => ({
29
+ default: mod.MapContainer,
30
+ })),
27
31
  {
28
32
  displayName: 'LazyMapContainer',
29
33
  fallback: <MapLoadingFallback minHeight={400} />,
@@ -33,8 +37,11 @@ export const LazyMapContainer = createLazyComponent(
33
37
  /**
34
38
  * LazyMapView - Lazy-loaded map view (alias for MapContainer)
35
39
  */
36
- export const LazyMapView = createLazyComponent(
37
- () => import('./components/MapContainer').then((mod) => ({ default: mod.MapView })),
40
+ export const LazyMapView = createLazyComponent<Omit<MapContainerProps, 'initialViewport'>>(
41
+ () =>
42
+ import('./components/MapContainer').then((mod) => ({
43
+ default: mod.MapView,
44
+ })),
38
45
  {
39
46
  displayName: 'LazyMapView',
40
47
  fallback: <MapLoadingFallback minHeight={400} />,
@@ -87,7 +87,9 @@ async function resolveClipboardFiles(
87
87
  }
88
88
  return [file];
89
89
  } catch (err) {
90
- logger.warn('Failed to fetch pasted URL', err);
90
+ logger.warn('Failed to fetch pasted URL', {
91
+ error: err instanceof Error ? err.message : String(err),
92
+ });
91
93
  return [];
92
94
  }
93
95
  }
@@ -112,6 +112,7 @@ export {
112
112
  useCronMonthDays,
113
113
  useCronCustom,
114
114
  useCronPreview,
115
+ useCronSize,
115
116
  useCronScheduler,
116
117
  // Utilities
117
118
  buildCron,
@@ -128,6 +129,7 @@ export {
128
129
  } from './CronScheduler';
129
130
  export type {
130
131
  CronSchedulerProps,
132
+ CronSchedulerSize,
131
133
  ScheduleType,
132
134
  WeekDay,
133
135
  MonthDay,