@djangocfg/ui-tools 2.1.129 → 2.1.131

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 (38) hide show
  1. package/README.md +57 -1
  2. package/dist/CronScheduler.client-5UEBG4EY.mjs +67 -0
  3. package/dist/CronScheduler.client-5UEBG4EY.mjs.map +1 -0
  4. package/dist/CronScheduler.client-ZDNFXYWJ.cjs +72 -0
  5. package/dist/CronScheduler.client-ZDNFXYWJ.cjs.map +1 -0
  6. package/dist/chunk-JFGLA6DT.cjs +1013 -0
  7. package/dist/chunk-JFGLA6DT.cjs.map +1 -0
  8. package/dist/chunk-MQDWUBVX.mjs +993 -0
  9. package/dist/chunk-MQDWUBVX.mjs.map +1 -0
  10. package/dist/index.cjs +109 -0
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +280 -1
  13. package/dist/index.d.ts +280 -1
  14. package/dist/index.mjs +32 -1
  15. package/dist/index.mjs.map +1 -1
  16. package/package.json +6 -6
  17. package/src/index.ts +5 -0
  18. package/src/tools/CronScheduler/CronScheduler.client.tsx +140 -0
  19. package/src/tools/CronScheduler/CronScheduler.story.tsx +220 -0
  20. package/src/tools/CronScheduler/components/CronCheatsheet.tsx +101 -0
  21. package/src/tools/CronScheduler/components/CustomInput.tsx +67 -0
  22. package/src/tools/CronScheduler/components/DayChips.tsx +130 -0
  23. package/src/tools/CronScheduler/components/MonthDayGrid.tsx +143 -0
  24. package/src/tools/CronScheduler/components/SchedulePreview.tsx +103 -0
  25. package/src/tools/CronScheduler/components/ScheduleTypeSelector.tsx +57 -0
  26. package/src/tools/CronScheduler/components/TimeSelector.tsx +132 -0
  27. package/src/tools/CronScheduler/components/index.ts +24 -0
  28. package/src/tools/CronScheduler/context/CronSchedulerContext.tsx +237 -0
  29. package/src/tools/CronScheduler/context/hooks.ts +86 -0
  30. package/src/tools/CronScheduler/context/index.ts +18 -0
  31. package/src/tools/CronScheduler/index.tsx +91 -0
  32. package/src/tools/CronScheduler/lazy.tsx +67 -0
  33. package/src/tools/CronScheduler/types/index.ts +112 -0
  34. package/src/tools/CronScheduler/utils/cron-builder.ts +100 -0
  35. package/src/tools/CronScheduler/utils/cron-humanize.ts +218 -0
  36. package/src/tools/CronScheduler/utils/cron-parser.ts +188 -0
  37. package/src/tools/CronScheduler/utils/index.ts +12 -0
  38. package/src/tools/index.ts +36 -0
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Cron Parser
3
+ *
4
+ * Parses Unix 5-field cron expression into CronSchedulerState
5
+ * Format: minute hour day-of-month month day-of-week
6
+ */
7
+
8
+ import type { CronSchedulerState, ScheduleType, WeekDay, MonthDay } from '../types';
9
+
10
+ /**
11
+ * Parses Unix 5-field cron expression into state
12
+ *
13
+ * @param cron - Cron expression to parse
14
+ * @returns Parsed state or null if invalid
15
+ *
16
+ * @example
17
+ * parseCron('0 9 * * *')
18
+ * // { type: 'daily', hour: 9, minute: 0, ... }
19
+ *
20
+ * parseCron('30 14 * * 1,3,5')
21
+ * // { type: 'weekly', hour: 14, minute: 30, weekDays: [1, 3, 5], ... }
22
+ */
23
+ export function parseCron(cron: string): CronSchedulerState | null {
24
+ if (!cron || typeof cron !== 'string') return null;
25
+
26
+ const parts = cron.trim().split(/\s+/);
27
+
28
+ // Unix cron has exactly 5 fields
29
+ if (parts.length !== 5) return null;
30
+
31
+ const [minutePart, hourPart, dayOfMonthPart, monthPart, dayOfWeekPart] = parts;
32
+
33
+ // Parse minute (0-59 or *)
34
+ const minute = parseField(minutePart, 0, 59);
35
+ if (minute === null && minutePart !== '*') return null;
36
+
37
+ // Parse hour (0-23 or *)
38
+ const hour = parseField(hourPart, 0, 23);
39
+ if (hour === null && hourPart !== '*') return null;
40
+
41
+ // Determine schedule type based on field patterns
42
+ const result = detectScheduleType(
43
+ minutePart,
44
+ hourPart,
45
+ dayOfMonthPart,
46
+ monthPart,
47
+ dayOfWeekPart
48
+ );
49
+
50
+ return {
51
+ type: result.type,
52
+ hour: hour ?? 0,
53
+ minute: minute ?? 0,
54
+ weekDays: result.weekDays,
55
+ monthDays: result.monthDays,
56
+ customCron: cron,
57
+ isValid: true,
58
+ };
59
+ }
60
+
61
+ /**
62
+ * Detects schedule type from cron fields
63
+ */
64
+ function detectScheduleType(
65
+ _minutePart: string,
66
+ _hourPart: string,
67
+ dayOfMonthPart: string,
68
+ monthPart: string,
69
+ dayOfWeekPart: string
70
+ ): {
71
+ type: ScheduleType;
72
+ weekDays: WeekDay[];
73
+ monthDays: MonthDay[];
74
+ } {
75
+ // Default values
76
+ let type: ScheduleType = 'custom';
77
+ let weekDays: WeekDay[] = [1, 2, 3, 4, 5]; // Mon-Fri
78
+ let monthDays: MonthDay[] = [1];
79
+
80
+ // Daily: M H * * *
81
+ if (dayOfMonthPart === '*' && monthPart === '*' && dayOfWeekPart === '*') {
82
+ type = 'daily';
83
+ }
84
+ // Weekly: M H * * 1,2,3 (or ranges like 1-5)
85
+ else if (dayOfMonthPart === '*' && monthPart === '*' && dayOfWeekPart !== '*') {
86
+ type = 'weekly';
87
+ weekDays = parseWeekDays(dayOfWeekPart);
88
+ }
89
+ // Monthly: M H 1,15 * * (day-of-month specified)
90
+ else if (dayOfMonthPart !== '*' && monthPart === '*' && dayOfWeekPart === '*') {
91
+ type = 'monthly';
92
+ monthDays = parseMonthDays(dayOfMonthPart);
93
+ }
94
+ // Everything else is custom
95
+
96
+ return { type, weekDays, monthDays };
97
+ }
98
+
99
+ /**
100
+ * Parses a single numeric field
101
+ */
102
+ function parseField(part: string, min: number, max: number): number | null {
103
+ // Handle simple number
104
+ if (/^\d+$/.test(part)) {
105
+ const num = parseInt(part, 10);
106
+ if (num >= min && num <= max) return num;
107
+ }
108
+ return null;
109
+ }
110
+
111
+ /**
112
+ * Parses week days from cron field
113
+ * Supports: 1,2,3 or 1-5 or MON,WED,FRI
114
+ */
115
+ function parseWeekDays(part: string): WeekDay[] {
116
+ const result: WeekDay[] = [];
117
+
118
+ // Handle ranges like 1-5
119
+ if (part.includes('-')) {
120
+ const [start, end] = part.split('-').map(s => parseInt(s, 10));
121
+ if (!isNaN(start) && !isNaN(end)) {
122
+ for (let i = start; i <= end && i <= 6; i++) {
123
+ if (i >= 0) result.push(i as WeekDay);
124
+ }
125
+ }
126
+ return result.length > 0 ? result : [1, 2, 3, 4, 5];
127
+ }
128
+
129
+ // Handle comma-separated list
130
+ for (const segment of part.split(',')) {
131
+ const num = parseInt(segment.trim(), 10);
132
+ if (!isNaN(num) && num >= 0 && num <= 6) {
133
+ result.push(num as WeekDay);
134
+ }
135
+ }
136
+
137
+ return result.length > 0 ? result : [1, 2, 3, 4, 5];
138
+ }
139
+
140
+ /**
141
+ * Parses month days from cron field
142
+ * Supports: 1,15 or 1-15
143
+ */
144
+ function parseMonthDays(part: string): MonthDay[] {
145
+ const result: MonthDay[] = [];
146
+
147
+ // Handle ranges like 1-15
148
+ if (part.includes('-')) {
149
+ const [start, end] = part.split('-').map(s => parseInt(s, 10));
150
+ if (!isNaN(start) && !isNaN(end)) {
151
+ for (let i = start; i <= end && i <= 31; i++) {
152
+ if (i >= 1) result.push(i as MonthDay);
153
+ }
154
+ }
155
+ return result.length > 0 ? result : [1];
156
+ }
157
+
158
+ // Handle comma-separated list
159
+ for (const segment of part.split(',')) {
160
+ const num = parseInt(segment.trim(), 10);
161
+ if (!isNaN(num) && num >= 1 && num <= 31) {
162
+ result.push(num as MonthDay);
163
+ }
164
+ }
165
+
166
+ return result.length > 0 ? result : [1];
167
+ }
168
+
169
+ /**
170
+ * Validates cron expression syntax
171
+ */
172
+ export function isValidCron(cron: string): boolean {
173
+ if (!cron || typeof cron !== 'string') return false;
174
+
175
+ const parts = cron.trim().split(/\s+/);
176
+ if (parts.length !== 5) return false;
177
+
178
+ // Basic validation for each field
179
+ const patterns = [
180
+ /^(\*|\d{1,2}|\d{1,2}-\d{1,2}|\d{1,2}(,\d{1,2})*|\*\/\d{1,2})$/, // minute
181
+ /^(\*|\d{1,2}|\d{1,2}-\d{1,2}|\d{1,2}(,\d{1,2})*|\*\/\d{1,2})$/, // hour
182
+ /^(\*|\d{1,2}|\d{1,2}-\d{1,2}|\d{1,2}(,\d{1,2})*|\*\/\d{1,2})$/, // day of month
183
+ /^(\*|\d{1,2}|\d{1,2}-\d{1,2}|\d{1,2}(,\d{1,2})*|\*\/\d{1,2})$/, // month
184
+ /^(\*|\d{1}|\d{1}-\d{1}|\d{1}(,\d{1})*|\*\/\d{1,2})$/, // day of week
185
+ ];
186
+
187
+ return parts.every((part, i) => patterns[i].test(part));
188
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Cron Utilities
3
+ */
4
+
5
+ export { buildCron, buildDefaultCron } from './cron-builder';
6
+ export { parseCron, isValidCron } from './cron-parser';
7
+ export {
8
+ humanizeCron,
9
+ formatTime12h,
10
+ getWeekdayName,
11
+ getWeekdayShort,
12
+ } from './cron-humanize';
@@ -11,6 +11,7 @@
11
11
  * - VideoPlayer: ~150KB (Professional video player with Vidstack)
12
12
  * - AudioPlayer: ~200KB (Audio player with WaveSurfer.js)
13
13
  * - ImageViewer: ~50KB (Image viewer with zoom/pan/rotate)
14
+ * - CronScheduler: ~15KB (Cron expression builder)
14
15
  *
15
16
  * Works in any React environment: Next.js, Vite, Wails, CRA
16
17
  */
@@ -161,6 +162,41 @@ export type {
161
162
  export { ImageViewer } from './ImageViewer';
162
163
  export type { ImageViewerProps, ImageFile } from './ImageViewer';
163
164
 
165
+ // Export CronScheduler (~15KB)
166
+ export {
167
+ CronScheduler,
168
+ // Context & Hooks
169
+ CronSchedulerProvider,
170
+ useCronSchedulerContext,
171
+ useCronType,
172
+ useCronTime,
173
+ useCronWeekDays,
174
+ useCronMonthDays,
175
+ useCronCustom,
176
+ useCronPreview,
177
+ useCronScheduler,
178
+ // Utilities
179
+ buildCron,
180
+ parseCron,
181
+ isValidCron,
182
+ humanizeCron,
183
+ // Components
184
+ ScheduleTypeSelector,
185
+ TimeSelector,
186
+ DayChips,
187
+ MonthDayGrid,
188
+ CustomInput,
189
+ SchedulePreview,
190
+ } from './CronScheduler';
191
+ export type {
192
+ CronSchedulerProps,
193
+ ScheduleType,
194
+ WeekDay,
195
+ MonthDay,
196
+ CronSchedulerState,
197
+ CronSchedulerContextValue,
198
+ } from './CronScheduler';
199
+
164
200
  // Export Media Cache Store
165
201
  export {
166
202
  useMediaCacheStore,