@dowel-ui/react 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/README.md +9 -5
  2. package/dist/components/ai-extraction-review/ai-extraction-review.d.ts +52 -0
  3. package/dist/components/ai-extraction-review/ai-extraction-review.d.ts.map +1 -0
  4. package/dist/components/ai-extraction-review/ai-extraction-review.js +249 -0
  5. package/dist/components/ai-extraction-review/ai-extraction-review.js.map +1 -0
  6. package/dist/components/ai-extraction-review/extraction-model.d.ts +94 -0
  7. package/dist/components/ai-extraction-review/extraction-model.d.ts.map +1 -0
  8. package/dist/components/ai-extraction-review/extraction-model.js +91 -0
  9. package/dist/components/ai-extraction-review/extraction-model.js.map +1 -0
  10. package/dist/components/ai-extraction-review/index.d.ts +3 -0
  11. package/dist/components/ai-extraction-review/index.js +3 -0
  12. package/dist/components/ai-extraction-review/meta.js +17 -0
  13. package/dist/components/ai-extraction-review/meta.js.map +1 -0
  14. package/dist/components/ai-suggested-value/ai-suggested-value.d.ts +72 -0
  15. package/dist/components/ai-suggested-value/ai-suggested-value.d.ts.map +1 -0
  16. package/dist/components/ai-suggested-value/ai-suggested-value.js +126 -0
  17. package/dist/components/ai-suggested-value/ai-suggested-value.js.map +1 -0
  18. package/dist/components/ai-suggested-value/index.d.ts +2 -0
  19. package/dist/components/ai-suggested-value/index.js +2 -0
  20. package/dist/components/ai-suggested-value/meta.js +17 -0
  21. package/dist/components/ai-suggested-value/meta.js.map +1 -0
  22. package/dist/components/alert/alert.d.ts +1 -1
  23. package/dist/components/avatar/avatar.d.ts +1 -1
  24. package/dist/components/badge/badge.d.ts +1 -1
  25. package/dist/components/button/button.d.ts +1 -1
  26. package/dist/components/confirm-typed/confirm-typed.d.ts +47 -0
  27. package/dist/components/confirm-typed/confirm-typed.d.ts.map +1 -0
  28. package/dist/components/confirm-typed/confirm-typed.js +106 -0
  29. package/dist/components/confirm-typed/confirm-typed.js.map +1 -0
  30. package/dist/components/confirm-typed/index.d.ts +2 -0
  31. package/dist/components/confirm-typed/index.js +2 -0
  32. package/dist/components/confirm-typed/meta.js +17 -0
  33. package/dist/components/confirm-typed/meta.js.map +1 -0
  34. package/dist/components/cron-editor/cron-editor.d.ts +36 -0
  35. package/dist/components/cron-editor/cron-editor.d.ts.map +1 -0
  36. package/dist/components/cron-editor/cron-editor.js +493 -0
  37. package/dist/components/cron-editor/cron-editor.js.map +1 -0
  38. package/dist/components/cron-editor/cron-expression.d.ts +82 -0
  39. package/dist/components/cron-editor/cron-expression.d.ts.map +1 -0
  40. package/dist/components/cron-editor/cron-expression.js +352 -0
  41. package/dist/components/cron-editor/cron-expression.js.map +1 -0
  42. package/dist/components/cron-editor/index.d.ts +3 -0
  43. package/dist/components/cron-editor/index.js +3 -0
  44. package/dist/components/cron-editor/meta.js +17 -0
  45. package/dist/components/cron-editor/meta.js.map +1 -0
  46. package/dist/components/dns-record/dns-record.d.ts +61 -0
  47. package/dist/components/dns-record/dns-record.d.ts.map +1 -0
  48. package/dist/components/dns-record/dns-record.js +227 -0
  49. package/dist/components/dns-record/dns-record.js.map +1 -0
  50. package/dist/components/dns-record/index.d.ts +2 -0
  51. package/dist/components/dns-record/index.js +2 -0
  52. package/dist/components/dns-record/meta.js +17 -0
  53. package/dist/components/dns-record/meta.js.map +1 -0
  54. package/dist/components/permission-matrix/index.d.ts +3 -0
  55. package/dist/components/permission-matrix/index.js +3 -0
  56. package/dist/components/permission-matrix/meta.js +17 -0
  57. package/dist/components/permission-matrix/meta.js.map +1 -0
  58. package/dist/components/permission-matrix/permission-matrix.d.ts +46 -0
  59. package/dist/components/permission-matrix/permission-matrix.d.ts.map +1 -0
  60. package/dist/components/permission-matrix/permission-matrix.js +199 -0
  61. package/dist/components/permission-matrix/permission-matrix.js.map +1 -0
  62. package/dist/components/permission-matrix/permission-model.d.ts +53 -0
  63. package/dist/components/permission-matrix/permission-model.d.ts.map +1 -0
  64. package/dist/components/permission-matrix/permission-model.js +64 -0
  65. package/dist/components/permission-matrix/permission-model.js.map +1 -0
  66. package/dist/components/progress/progress.d.ts +1 -1
  67. package/dist/components/secret-field/index.d.ts +2 -0
  68. package/dist/components/secret-field/index.js +2 -0
  69. package/dist/components/secret-field/meta.js +17 -0
  70. package/dist/components/secret-field/meta.js.map +1 -0
  71. package/dist/components/secret-field/secret-field.d.ts +58 -0
  72. package/dist/components/secret-field/secret-field.d.ts.map +1 -0
  73. package/dist/components/secret-field/secret-field.js +168 -0
  74. package/dist/components/secret-field/secret-field.js.map +1 -0
  75. package/dist/components/session-expiry/index.d.ts +2 -0
  76. package/dist/components/session-expiry/index.js +2 -0
  77. package/dist/components/session-expiry/meta.js +17 -0
  78. package/dist/components/session-expiry/meta.js.map +1 -0
  79. package/dist/components/session-expiry/session-expiry.d.ts +64 -0
  80. package/dist/components/session-expiry/session-expiry.d.ts.map +1 -0
  81. package/dist/components/session-expiry/session-expiry.js +185 -0
  82. package/dist/components/session-expiry/session-expiry.js.map +1 -0
  83. package/dist/components/shortcut-recorder/index.d.ts +3 -0
  84. package/dist/components/shortcut-recorder/index.js +3 -0
  85. package/dist/components/shortcut-recorder/meta.js +17 -0
  86. package/dist/components/shortcut-recorder/meta.js.map +1 -0
  87. package/dist/components/shortcut-recorder/shortcut-model.d.ts +67 -0
  88. package/dist/components/shortcut-recorder/shortcut-model.d.ts.map +1 -0
  89. package/dist/components/shortcut-recorder/shortcut-model.js +168 -0
  90. package/dist/components/shortcut-recorder/shortcut-model.js.map +1 -0
  91. package/dist/components/shortcut-recorder/shortcut-recorder.d.ts +47 -0
  92. package/dist/components/shortcut-recorder/shortcut-recorder.d.ts.map +1 -0
  93. package/dist/components/shortcut-recorder/shortcut-recorder.js +212 -0
  94. package/dist/components/shortcut-recorder/shortcut-recorder.js.map +1 -0
  95. package/dist/components/spinner/spinner.d.ts +1 -1
  96. package/dist/components/sync-status/index.d.ts +2 -0
  97. package/dist/components/sync-status/index.js +2 -0
  98. package/dist/components/sync-status/meta.js +17 -0
  99. package/dist/components/sync-status/meta.js.map +1 -0
  100. package/dist/components/sync-status/sync-status.d.ts +65 -0
  101. package/dist/components/sync-status/sync-status.d.ts.map +1 -0
  102. package/dist/components/sync-status/sync-status.js +103 -0
  103. package/dist/components/sync-status/sync-status.js.map +1 -0
  104. package/dist/components/toast/toast.d.ts +1 -1
  105. package/dist/index.d.ts +25 -1
  106. package/dist/index.js +16 -2
  107. package/dist/registry/components.d.ts.map +1 -1
  108. package/dist/registry/components.js +73 -53
  109. package/dist/registry/components.js.map +1 -1
  110. package/package.json +4 -4
  111. package/src/components/ai-extraction-review/ai-extraction-review.tsx +492 -0
  112. package/src/components/ai-extraction-review/extraction-model.ts +159 -0
  113. package/src/components/ai-extraction-review/index.ts +13 -0
  114. package/src/components/ai-extraction-review/meta.ts +24 -0
  115. package/src/components/ai-suggested-value/ai-suggested-value.tsx +295 -0
  116. package/src/components/ai-suggested-value/index.ts +6 -0
  117. package/src/components/ai-suggested-value/meta.ts +24 -0
  118. package/src/components/confirm-typed/confirm-typed.tsx +191 -0
  119. package/src/components/confirm-typed/index.ts +1 -0
  120. package/src/components/confirm-typed/meta.ts +22 -0
  121. package/src/components/cron-editor/cron-editor.tsx +676 -0
  122. package/src/components/cron-editor/cron-expression.ts +552 -0
  123. package/src/components/cron-editor/index.ts +23 -0
  124. package/src/components/cron-editor/meta.ts +23 -0
  125. package/src/components/dns-record/dns-record.tsx +315 -0
  126. package/src/components/dns-record/index.ts +7 -0
  127. package/src/components/dns-record/meta.ts +21 -0
  128. package/src/components/permission-matrix/index.ts +14 -0
  129. package/src/components/permission-matrix/meta.ts +23 -0
  130. package/src/components/permission-matrix/permission-matrix.tsx +368 -0
  131. package/src/components/permission-matrix/permission-model.ts +120 -0
  132. package/src/components/secret-field/index.ts +6 -0
  133. package/src/components/secret-field/meta.ts +21 -0
  134. package/src/components/secret-field/secret-field.tsx +284 -0
  135. package/src/components/session-expiry/index.ts +9 -0
  136. package/src/components/session-expiry/meta.ts +23 -0
  137. package/src/components/session-expiry/session-expiry.tsx +321 -0
  138. package/src/components/shortcut-recorder/index.ts +19 -0
  139. package/src/components/shortcut-recorder/meta.ts +22 -0
  140. package/src/components/shortcut-recorder/shortcut-model.ts +204 -0
  141. package/src/components/shortcut-recorder/shortcut-recorder.tsx +336 -0
  142. package/src/components/sync-status/index.ts +9 -0
  143. package/src/components/sync-status/meta.ts +21 -0
  144. package/src/components/sync-status/sync-status.tsx +217 -0
  145. package/src/index.ts +10 -0
  146. package/src/registry/components.ts +20 -0
@@ -0,0 +1,352 @@
1
+ //#region src/components/cron-editor/cron-expression.ts
2
+ var CronExpressionError = class extends Error {
3
+ field;
4
+ constructor(message, field) {
5
+ super(message);
6
+ this.field = field;
7
+ this.name = "CronExpressionError";
8
+ }
9
+ };
10
+ const FIELDS = [
11
+ "minute",
12
+ "hour",
13
+ "dayOfMonth",
14
+ "month",
15
+ "dayOfWeek"
16
+ ];
17
+ const RANGES = {
18
+ minute: {
19
+ min: 0,
20
+ max: 59,
21
+ label: "Minute"
22
+ },
23
+ hour: {
24
+ min: 0,
25
+ max: 23,
26
+ label: "Hour"
27
+ },
28
+ dayOfMonth: {
29
+ min: 1,
30
+ max: 31,
31
+ label: "Day of month"
32
+ },
33
+ month: {
34
+ min: 1,
35
+ max: 12,
36
+ label: "Month"
37
+ },
38
+ dayOfWeek: {
39
+ min: 0,
40
+ max: 7,
41
+ label: "Day of week"
42
+ }
43
+ };
44
+ const MONTH_NAMES = [
45
+ "JAN",
46
+ "FEB",
47
+ "MAR",
48
+ "APR",
49
+ "MAY",
50
+ "JUN",
51
+ "JUL",
52
+ "AUG",
53
+ "SEP",
54
+ "OCT",
55
+ "NOV",
56
+ "DEC"
57
+ ];
58
+ const DAY_NAMES = [
59
+ "SUN",
60
+ "MON",
61
+ "TUE",
62
+ "WED",
63
+ "THU",
64
+ "FRI",
65
+ "SAT"
66
+ ];
67
+ const CRON_SHORTCUTS = {
68
+ "@yearly": "0 0 1 1 *",
69
+ "@annually": "0 0 1 1 *",
70
+ "@monthly": "0 0 1 * *",
71
+ "@weekly": "0 0 * * 0",
72
+ "@daily": "0 0 * * *",
73
+ "@midnight": "0 0 * * *",
74
+ "@hourly": "0 * * * *"
75
+ };
76
+ function nameToNumber(token, field) {
77
+ const upper = token.toUpperCase();
78
+ if (field === "month") {
79
+ const index = MONTH_NAMES.indexOf(upper);
80
+ return index === -1 ? null : index + 1;
81
+ }
82
+ if (field === "dayOfWeek") {
83
+ const index = DAY_NAMES.indexOf(upper);
84
+ return index === -1 ? null : index;
85
+ }
86
+ return null;
87
+ }
88
+ function parseNumber(token, field) {
89
+ const { min, max, label } = RANGES[field];
90
+ const value = nameToNumber(token, field) ?? (/^\d+$/.test(token) ? Number(token) : NaN);
91
+ if (Number.isNaN(value)) throw new CronExpressionError(`${label}: "${token}" is not a number${field === "month" || field === "dayOfWeek" ? " or a name" : ""}.`, field);
92
+ if (value < min || value > max) throw new CronExpressionError(`${label} must be ${String(min)}–${String(max)}, not ${String(value)}.`, field);
93
+ return value;
94
+ }
95
+ /** One field's set of values, in order and without duplicates. */
96
+ function parseField(text, field) {
97
+ const { min, max, label } = RANGES[field];
98
+ const top = field === "dayOfWeek" ? 6 : max;
99
+ const values = /* @__PURE__ */ new Set();
100
+ let restricted = false;
101
+ for (const part of text.split(",")) {
102
+ if (part === "") throw new CronExpressionError(`${label}: empty item in "${text}".`, field);
103
+ const [rangeText, stepText, ...extra] = part.split("/");
104
+ if (extra.length > 0 || stepText === "") throw new CronExpressionError(`${label}: "${part}" has a malformed step.`, field);
105
+ const step = stepText === void 0 ? 1 : Number(stepText);
106
+ if (stepText !== void 0 && (!/^\d+$/.test(stepText) || step < 1)) throw new CronExpressionError(`${label}: step must be a whole number of 1 or more, not "${stepText}".`, field);
107
+ let start;
108
+ let end;
109
+ if (rangeText === "*") {
110
+ start = min;
111
+ end = top;
112
+ if (stepText !== void 0) restricted = true;
113
+ } else if (rangeText === void 0) throw new CronExpressionError(`${label}: "${part}" is empty.`, field);
114
+ else {
115
+ restricted = true;
116
+ const [startText, endText, ...more] = rangeText.split("-");
117
+ if (more.length > 0 || startText === void 0 || startText === "") throw new CronExpressionError(`${label}: "${rangeText}" is not a range.`, field);
118
+ start = parseNumber(startText, field);
119
+ if (endText === void 0) end = stepText === void 0 ? start : top;
120
+ else {
121
+ if (endText === "") throw new CronExpressionError(`${label}: "${rangeText}" is missing its end.`, field);
122
+ end = parseNumber(endText, field);
123
+ if (end < start) throw new CronExpressionError(`${label}: ${String(start)}-${String(end)} runs backwards.`, field);
124
+ }
125
+ }
126
+ for (let value = start; value <= end; value += step) values.add(field === "dayOfWeek" && value === 7 ? 0 : value);
127
+ }
128
+ return {
129
+ values: [...values].sort((a, b) => a - b),
130
+ restricted
131
+ };
132
+ }
133
+ function parseCron(expression) {
134
+ const trimmed = expression.trim();
135
+ if (trimmed === "") throw new CronExpressionError("Enter a schedule.");
136
+ const expanded = trimmed.startsWith("@") ? CRON_SHORTCUTS[trimmed.toLowerCase()] : trimmed;
137
+ if (expanded === void 0) throw new CronExpressionError(`"${trimmed}" is not a shortcut. Try @hourly, @daily, @weekly, @monthly or @yearly.`);
138
+ const parts = expanded.split(/\s+/);
139
+ if (parts.length !== 5) throw new CronExpressionError(`Expected 5 fields — minute, hour, day of month, month, day of week — not ${String(parts.length)}.`);
140
+ const fields = FIELDS.map((field, index) => parseField(parts[index] ?? "", field));
141
+ const at = (index) => fields[index] ?? {
142
+ values: [],
143
+ restricted: false
144
+ };
145
+ const [minute, hour, dayOfMonth, month, dayOfWeek] = [
146
+ at(0),
147
+ at(1),
148
+ at(2),
149
+ at(3),
150
+ at(4)
151
+ ];
152
+ return {
153
+ minutes: minute.values,
154
+ hours: hour.values,
155
+ daysOfMonth: dayOfMonth.values,
156
+ months: month.values,
157
+ daysOfWeek: dayOfWeek.values,
158
+ dayOfMonthRestricted: dayOfMonth.restricted,
159
+ dayOfWeekRestricted: dayOfWeek.restricted,
160
+ expression: parts.join(" ")
161
+ };
162
+ }
163
+ function isValidCron(expression) {
164
+ try {
165
+ parseCron(expression);
166
+ return true;
167
+ } catch {
168
+ return false;
169
+ }
170
+ }
171
+ /** "1, 2 and 3", or "1 to 5" when the values are consecutive. */
172
+ function listOf(items, consecutive) {
173
+ if (items.length === 1) return items[0] ?? "";
174
+ if (consecutive && items.length > 2) return `${items[0] ?? ""} to ${items[items.length - 1] ?? ""}`;
175
+ return `${items.slice(0, -1).join(", ")} and ${items[items.length - 1] ?? ""}`;
176
+ }
177
+ function isConsecutive(values) {
178
+ return values.every((value, index) => index === 0 || value === (values[index - 1] ?? 0) + 1);
179
+ }
180
+ /** The step a field was written with, when it was written as a star over a number. */
181
+ function stepOf(text) {
182
+ const match = /^\*\/(\d+)$/.exec(text);
183
+ return match ? Number(match[1]) : null;
184
+ }
185
+ function ordinal(n) {
186
+ const rem10 = n % 10;
187
+ const rem100 = n % 100;
188
+ return `${String(n)}${rem10 === 1 && rem100 !== 11 ? "st" : rem10 === 2 && rem100 !== 12 ? "nd" : rem10 === 3 && rem100 !== 13 ? "rd" : "th"}`;
189
+ }
190
+ function formatTime(hour, minute, locale) {
191
+ return new Intl.DateTimeFormat(locale, {
192
+ hour: "2-digit",
193
+ minute: "2-digit",
194
+ timeZone: "UTC"
195
+ }).format(Date.UTC(2026, 0, 1, hour, minute));
196
+ }
197
+ function dayName(index, locale) {
198
+ return new Intl.DateTimeFormat(locale, { weekday: "long" }).format(new Date(2026, 0, 4 + index));
199
+ }
200
+ function monthName(index, locale) {
201
+ return new Intl.DateTimeFormat(locale, { month: "long" }).format(new Date(2026, index - 1, 1));
202
+ }
203
+ /**
204
+ * The schedule in a sentence.
205
+ *
206
+ * Every product that has this control renders "Every Monday at 09:00" beside
207
+ * the expression, because `0 9 * * 1` is not something most people can read.
208
+ * Throws for an invalid expression; the editor turns that into the field's
209
+ * error text.
210
+ */
211
+ function describeCron(expression, options = {}) {
212
+ const { locale } = options;
213
+ const schedule = parseCron(expression);
214
+ const [minuteText = "", hourText = "", dayText = "", monthText = ""] = schedule.expression.split(" ");
215
+ const every = (label, n) => n === 1 ? `every ${label}` : `every ${ordinal(n)} ${label}`;
216
+ let time;
217
+ const minuteStep = stepOf(minuteText);
218
+ const hourStep = stepOf(hourText);
219
+ const allMinutes = minuteText === "*";
220
+ const allHours = hourText === "*";
221
+ if (allMinutes && allHours) time = "Every minute";
222
+ else if (minuteStep !== null && allHours) time = `Every ${minuteStep === 1 ? "minute" : `${String(minuteStep)} minutes`}`;
223
+ else if (allMinutes) time = `Every minute of ${listOf(schedule.hours.map((h) => formatTime(h, 0, locale)), isConsecutive(schedule.hours))}`;
224
+ else if (allHours || hourStep !== null) {
225
+ const hours = hourStep !== null && hourStep > 1 ? every("hour", hourStep) : "every hour";
226
+ if (minuteStep !== null) time = `Every ${String(minuteStep)} minutes of ${hours}`;
227
+ else time = `At minute ${listOf(schedule.minutes.map(String), isConsecutive(schedule.minutes))} past ${hours}`;
228
+ } else if (minuteStep !== null) time = `Every ${String(minuteStep)} minutes during ${listOf(schedule.hours.map((h) => formatTime(h, 0, locale)), isConsecutive(schedule.hours))}`;
229
+ else if (schedule.minutes.length === 1) {
230
+ const minute = schedule.minutes[0] ?? 0;
231
+ time = `At ${listOf(schedule.hours.map((h) => formatTime(h, minute, locale)), false)}`;
232
+ } else time = `At minute ${listOf(schedule.minutes.map(String), isConsecutive(schedule.minutes))} past ${listOf(schedule.hours.map((h) => formatTime(h, 0, locale)), isConsecutive(schedule.hours))}`;
233
+ const dayPhrases = [];
234
+ if (schedule.dayOfMonthRestricted) {
235
+ const step = stepOf(dayText);
236
+ dayPhrases.push(step !== null ? `${every("day", step)} of the month` : `on day ${listOf(schedule.daysOfMonth.map(String), isConsecutive(schedule.daysOfMonth))} of the month`);
237
+ }
238
+ if (schedule.dayOfWeekRestricted) dayPhrases.push(`on ${listOf(schedule.daysOfWeek.map((d) => dayName(d, locale)), isConsecutive(schedule.daysOfWeek))}`);
239
+ let days = dayPhrases.join(", or ");
240
+ if (!days && !allMinutes && !allHours && minuteStep === null && hourStep === null) days = "every day";
241
+ if (schedule.months.length < 12) {
242
+ const step = stepOf(monthText);
243
+ const months = step !== null ? every("month", step) : listOf(schedule.months.map((m) => monthName(m, locale)), isConsecutive(schedule.months));
244
+ days = `${days ? `${days} ` : ""}in ${months}`;
245
+ }
246
+ return days ? `${time} ${days}` : time;
247
+ }
248
+ const formatters = /* @__PURE__ */ new Map();
249
+ function formatterFor(timeZone) {
250
+ const key = timeZone ?? "";
251
+ let formatter = formatters.get(key);
252
+ if (!formatter) {
253
+ formatter = new Intl.DateTimeFormat("en-US", {
254
+ timeZone,
255
+ hourCycle: "h23",
256
+ year: "numeric",
257
+ month: "numeric",
258
+ day: "numeric",
259
+ hour: "numeric",
260
+ minute: "numeric",
261
+ weekday: "short"
262
+ });
263
+ formatters.set(key, formatter);
264
+ }
265
+ return formatter;
266
+ }
267
+ function wallClockOf(instant, timeZone) {
268
+ const parts = {};
269
+ for (const part of formatterFor(timeZone).formatToParts(new Date(instant))) parts[part.type] = part.value;
270
+ return {
271
+ year: Number(parts.year),
272
+ month: Number(parts.month),
273
+ day: Number(parts.day),
274
+ hour: Number(parts.hour) % 24,
275
+ minute: Number(parts.minute),
276
+ weekday: DAY_NAMES.indexOf((parts.weekday ?? "").slice(0, 3).toUpperCase())
277
+ };
278
+ }
279
+ function offsetAt(instant, timeZone) {
280
+ const wall = wallClockOf(instant, timeZone);
281
+ return Date.UTC(wall.year, wall.month - 1, wall.day, wall.hour, wall.minute) - Math.floor(instant / 6e4) * 6e4;
282
+ }
283
+ /**
284
+ * The instant a wall-clock time names in a zone, or null when it names none —
285
+ * the hour the clocks skip in spring. An ambiguous time, in the hour that
286
+ * repeats in autumn, resolves to its first occurrence.
287
+ */
288
+ function zonedTimeToInstant(year, month, day, hour, minute, timeZone) {
289
+ const guess = Date.UTC(year, month - 1, day, hour, minute);
290
+ const candidates = /* @__PURE__ */ new Set();
291
+ const oneDay = 864e5;
292
+ for (const seed of [
293
+ guess,
294
+ guess - oneDay,
295
+ guess + oneDay
296
+ ]) {
297
+ let instant = seed;
298
+ for (let pass = 0; pass < 2; pass += 1) {
299
+ instant = guess - offsetAt(instant, timeZone);
300
+ candidates.add(instant);
301
+ }
302
+ }
303
+ for (const candidate of [...candidates].sort((a, b) => a - b)) {
304
+ const wall = wallClockOf(candidate, timeZone);
305
+ if (wall.year === year && wall.month === month && wall.day === day && wall.hour === hour && wall.minute === minute) return candidate;
306
+ }
307
+ return null;
308
+ }
309
+ /** Roughly five years of days: enough to find the 29th of February, and to give up on the 30th. */
310
+ const MAX_DAYS = 1830;
311
+ /**
312
+ * The next `count` instants the schedule fires, in order.
313
+ *
314
+ * Fewer than `count` are returned when the schedule cannot produce them —
315
+ * `0 0 30 2 *` never runs, and saying so beats a spinner.
316
+ */
317
+ function nextRuns(expression, options) {
318
+ const { from, count = 5, timeZone } = options;
319
+ const schedule = parseCron(expression);
320
+ const runs = [];
321
+ const start = Math.floor(from.getTime() / 6e4) * 6e4 + 6e4;
322
+ const months = new Set(schedule.months);
323
+ const daysOfMonth = new Set(schedule.daysOfMonth);
324
+ const daysOfWeek = new Set(schedule.daysOfWeek);
325
+ const dayMatches = (wall) => {
326
+ if (!months.has(wall.month)) return false;
327
+ const domMatch = daysOfMonth.has(wall.day);
328
+ const dowMatch = daysOfWeek.has(wall.weekday);
329
+ if (schedule.dayOfMonthRestricted && schedule.dayOfWeekRestricted) return domMatch || dowMatch;
330
+ if (schedule.dayOfMonthRestricted) return domMatch;
331
+ if (schedule.dayOfWeekRestricted) return dowMatch;
332
+ return true;
333
+ };
334
+ const first = wallClockOf(start, timeZone);
335
+ let noon = zonedTimeToInstant(first.year, first.month, first.day, 12, 0, timeZone);
336
+ if (noon === null) return runs;
337
+ for (let i = 0; i < MAX_DAYS && runs.length < count; i += 1, noon += 864e5) {
338
+ const wall = wallClockOf(noon, timeZone);
339
+ if (!dayMatches(wall)) continue;
340
+ for (const hour of schedule.hours) for (const minute of schedule.minutes) {
341
+ const instant = zonedTimeToInstant(wall.year, wall.month, wall.day, hour, minute, timeZone);
342
+ if (instant === null || instant < start) continue;
343
+ runs.push(new Date(instant));
344
+ if (runs.length >= count) return runs;
345
+ }
346
+ }
347
+ return runs;
348
+ }
349
+ //#endregion
350
+ export { CRON_SHORTCUTS, CronExpressionError, describeCron, isValidCron, nextRuns, parseCron, zonedTimeToInstant };
351
+
352
+ //# sourceMappingURL=cron-expression.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron-expression.js","names":[],"sources":["../../../src/components/cron-editor/cron-expression.ts"],"sourcesContent":["/**\n * The five-field cron expression, as a value: parsed, described in words, and\n * projected onto a calendar in a named time zone.\n *\n * The dialect is the POSIX one — minute, hour, day of month, month, day of\n * week — which is what crontab, GitHub Actions, Vercel, Kubernetes and Airflow\n * all read. Not the Quartz one: no seconds field and no `L`, `W` or `#`,\n * because the products people schedule from a form do not accept them, and an\n * expression this editor produces has to run where it is pasted. The `@daily`\n * family of shortcuts is accepted, since crontab accepts it.\n *\n * Everything here is pure and takes its clock as an argument, so the\n * description, the run times and the two things every reimplementation gets\n * wrong — day-of-month OR day-of-week, and a wall-clock time that does not\n * exist on the day the clocks go forward — are tested without rendering\n * anything, and an application can compute the next run on the server from\n * the same expression the editor produced.\n */\n\nexport type CronField = \"minute\" | \"hour\" | \"dayOfMonth\" | \"month\" | \"dayOfWeek\";\n\nexport class CronExpressionError extends Error {\n constructor(\n message: string,\n /** Which of the five fields is wrong, when one is. */\n public readonly field?: CronField,\n ) {\n super(message);\n this.name = \"CronExpressionError\";\n }\n}\n\nexport interface CronSchedule {\n minutes: number[];\n hours: number[];\n daysOfMonth: number[];\n months: number[];\n /** 0 to 6, Sunday first. `7` in the source is folded into 0. */\n daysOfWeek: number[];\n /**\n * Whether each day field was written as something other than `*`. Cron's\n * rule, which every reimplementation gets wrong at least once: when both are\n * restricted a day matches if EITHER does, not both.\n */\n dayOfMonthRestricted: boolean;\n dayOfWeekRestricted: boolean;\n /** The expression with any shortcut expanded. */\n expression: string;\n}\n\nconst FIELDS: readonly CronField[] = [\"minute\", \"hour\", \"dayOfMonth\", \"month\", \"dayOfWeek\"];\n\nconst RANGES: Record<CronField, { min: number; max: number; label: string }> = {\n minute: { min: 0, max: 59, label: \"Minute\" },\n hour: { min: 0, max: 23, label: \"Hour\" },\n dayOfMonth: { min: 1, max: 31, label: \"Day of month\" },\n month: { min: 1, max: 12, label: \"Month\" },\n dayOfWeek: { min: 0, max: 7, label: \"Day of week\" },\n};\n\nconst MONTH_NAMES = [\n \"JAN\",\n \"FEB\",\n \"MAR\",\n \"APR\",\n \"MAY\",\n \"JUN\",\n \"JUL\",\n \"AUG\",\n \"SEP\",\n \"OCT\",\n \"NOV\",\n \"DEC\",\n];\nconst DAY_NAMES = [\"SUN\", \"MON\", \"TUE\", \"WED\", \"THU\", \"FRI\", \"SAT\"];\n\nexport const CRON_SHORTCUTS: Record<string, string> = {\n \"@yearly\": \"0 0 1 1 *\",\n \"@annually\": \"0 0 1 1 *\",\n \"@monthly\": \"0 0 1 * *\",\n \"@weekly\": \"0 0 * * 0\",\n \"@daily\": \"0 0 * * *\",\n \"@midnight\": \"0 0 * * *\",\n \"@hourly\": \"0 * * * *\",\n};\n\nfunction nameToNumber(token: string, field: CronField): number | null {\n const upper = token.toUpperCase();\n if (field === \"month\") {\n const index = MONTH_NAMES.indexOf(upper);\n return index === -1 ? null : index + 1;\n }\n if (field === \"dayOfWeek\") {\n const index = DAY_NAMES.indexOf(upper);\n return index === -1 ? null : index;\n }\n return null;\n}\n\nfunction parseNumber(token: string, field: CronField): number {\n const { min, max, label } = RANGES[field];\n const named = nameToNumber(token, field);\n const value = named ?? (/^\\d+$/.test(token) ? Number(token) : Number.NaN);\n if (Number.isNaN(value)) {\n throw new CronExpressionError(\n `${label}: \"${token}\" is not a number${field === \"month\" || field === \"dayOfWeek\" ? \" or a name\" : \"\"}.`,\n field,\n );\n }\n if (value < min || value > max) {\n throw new CronExpressionError(\n `${label} must be ${String(min)}–${String(max)}, not ${String(value)}.`,\n field,\n );\n }\n return value;\n}\n\n/** One field's set of values, in order and without duplicates. */\nfunction parseField(text: string, field: CronField): { values: number[]; restricted: boolean } {\n const { min, max, label } = RANGES[field];\n // Day of week runs 0–7 in the source and 0–6 in the result.\n const top = field === \"dayOfWeek\" ? 6 : max;\n const values = new Set<number>();\n let restricted = false;\n\n for (const part of text.split(\",\")) {\n if (part === \"\") throw new CronExpressionError(`${label}: empty item in \"${text}\".`, field);\n\n const [rangeText, stepText, ...extra] = part.split(\"/\");\n if (extra.length > 0 || stepText === \"\") {\n throw new CronExpressionError(`${label}: \"${part}\" has a malformed step.`, field);\n }\n const step = stepText === undefined ? 1 : Number(stepText);\n if (stepText !== undefined && (!/^\\d+$/.test(stepText) || step < 1)) {\n throw new CronExpressionError(\n `${label}: step must be a whole number of 1 or more, not \"${stepText}\".`,\n field,\n );\n }\n\n let start: number;\n let end: number;\n if (rangeText === \"*\") {\n start = min;\n end = top;\n if (stepText !== undefined) restricted = true;\n } else if (rangeText === undefined) {\n throw new CronExpressionError(`${label}: \"${part}\" is empty.`, field);\n } else {\n restricted = true;\n const [startText, endText, ...more] = rangeText.split(\"-\");\n if (more.length > 0 || startText === undefined || startText === \"\") {\n throw new CronExpressionError(`${label}: \"${rangeText}\" is not a range.`, field);\n }\n start = parseNumber(startText, field);\n if (endText === undefined) {\n // A bare number with a step, `5/10`, means \"from 5 onwards\" in Vixie cron.\n end = stepText === undefined ? start : top;\n } else {\n if (endText === \"\")\n throw new CronExpressionError(`${label}: \"${rangeText}\" is missing its end.`, field);\n end = parseNumber(endText, field);\n if (end < start) {\n throw new CronExpressionError(\n `${label}: ${String(start)}-${String(end)} runs backwards.`,\n field,\n );\n }\n }\n }\n\n for (let value = start; value <= end; value += step) {\n values.add(field === \"dayOfWeek\" && value === 7 ? 0 : value);\n }\n }\n\n return { values: [...values].sort((a, b) => a - b), restricted };\n}\n\nexport function parseCron(expression: string): CronSchedule {\n const trimmed = expression.trim();\n if (trimmed === \"\") throw new CronExpressionError(\"Enter a schedule.\");\n\n const expanded = trimmed.startsWith(\"@\") ? CRON_SHORTCUTS[trimmed.toLowerCase()] : trimmed;\n if (expanded === undefined) {\n throw new CronExpressionError(\n `\"${trimmed}\" is not a shortcut. Try @hourly, @daily, @weekly, @monthly or @yearly.`,\n );\n }\n\n const parts = expanded.split(/\\s+/);\n if (parts.length !== 5) {\n throw new CronExpressionError(\n `Expected 5 fields — minute, hour, day of month, month, day of week — not ${String(parts.length)}.`,\n );\n }\n\n const fields = FIELDS.map((field, index) => parseField(parts[index] ?? \"\", field));\n const at = (index: number) => fields[index] ?? { values: [], restricted: false };\n const [minute, hour, dayOfMonth, month, dayOfWeek] = [at(0), at(1), at(2), at(3), at(4)];\n\n return {\n minutes: minute.values,\n hours: hour.values,\n daysOfMonth: dayOfMonth.values,\n months: month.values,\n daysOfWeek: dayOfWeek.values,\n dayOfMonthRestricted: dayOfMonth.restricted,\n dayOfWeekRestricted: dayOfWeek.restricted,\n expression: parts.join(\" \"),\n };\n}\n\nexport function isValidCron(expression: string): boolean {\n try {\n parseCron(expression);\n return true;\n } catch {\n return false;\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* Describing */\n/* ------------------------------------------------------------------ */\n\nexport interface DescribeOptions {\n locale?: string;\n}\n\n/** \"1, 2 and 3\", or \"1 to 5\" when the values are consecutive. */\nfunction listOf(items: string[], consecutive: boolean): string {\n if (items.length === 1) return items[0] ?? \"\";\n if (consecutive && items.length > 2)\n return `${items[0] ?? \"\"} to ${items[items.length - 1] ?? \"\"}`;\n return `${items.slice(0, -1).join(\", \")} and ${items[items.length - 1] ?? \"\"}`;\n}\n\nfunction isConsecutive(values: number[]): boolean {\n return values.every((value, index) => index === 0 || value === (values[index - 1] ?? 0) + 1);\n}\n\n/** The step a field was written with, when it was written as a star over a number. */\nfunction stepOf(text: string): number | null {\n const match = /^\\*\\/(\\d+)$/.exec(text);\n return match ? Number(match[1]) : null;\n}\n\nfunction ordinal(n: number): string {\n const rem10 = n % 10;\n const rem100 = n % 100;\n const suffix =\n rem10 === 1 && rem100 !== 11\n ? \"st\"\n : rem10 === 2 && rem100 !== 12\n ? \"nd\"\n : rem10 === 3 && rem100 !== 13\n ? \"rd\"\n : \"th\";\n return `${String(n)}${suffix}`;\n}\n\nfunction formatTime(hour: number, minute: number, locale?: string): string {\n // Formatted in UTC from a UTC instant, so the runtime zone cannot shift it.\n return new Intl.DateTimeFormat(locale, {\n hour: \"2-digit\",\n minute: \"2-digit\",\n timeZone: \"UTC\",\n }).format(Date.UTC(2026, 0, 1, hour, minute));\n}\n\nfunction dayName(index: number, locale?: string): string {\n // 4 January 2026 is a Sunday.\n return new Intl.DateTimeFormat(locale, { weekday: \"long\" }).format(\n new Date(2026, 0, 4 + index),\n );\n}\n\nfunction monthName(index: number, locale?: string): string {\n return new Intl.DateTimeFormat(locale, { month: \"long\" }).format(\n new Date(2026, index - 1, 1),\n );\n}\n\n/**\n * The schedule in a sentence.\n *\n * Every product that has this control renders \"Every Monday at 09:00\" beside\n * the expression, because `0 9 * * 1` is not something most people can read.\n * Throws for an invalid expression; the editor turns that into the field's\n * error text.\n */\nexport function describeCron(expression: string, options: DescribeOptions = {}): string {\n const { locale } = options;\n const schedule = parseCron(expression);\n const [minuteText = \"\", hourText = \"\", dayText = \"\", monthText = \"\"] =\n schedule.expression.split(\" \");\n\n const every = (label: string, n: number) =>\n n === 1 ? `every ${label}` : `every ${ordinal(n)} ${label}`;\n\n // Time of day.\n let time: string;\n const minuteStep = stepOf(minuteText);\n const hourStep = stepOf(hourText);\n const allMinutes = minuteText === \"*\";\n const allHours = hourText === \"*\";\n\n if (allMinutes && allHours) {\n time = \"Every minute\";\n } else if (minuteStep !== null && allHours) {\n time = `Every ${minuteStep === 1 ? \"minute\" : `${String(minuteStep)} minutes`}`;\n } else if (allMinutes) {\n time = `Every minute of ${listOf(\n schedule.hours.map((h) => formatTime(h, 0, locale)),\n isConsecutive(schedule.hours),\n )}`;\n } else if (allHours || hourStep !== null) {\n const hours = hourStep !== null && hourStep > 1 ? every(\"hour\", hourStep) : \"every hour\";\n if (minuteStep !== null) {\n time = `Every ${String(minuteStep)} minutes of ${hours}`;\n } else {\n time = `At minute ${listOf(schedule.minutes.map(String), isConsecutive(schedule.minutes))} past ${hours}`;\n }\n } else if (minuteStep !== null) {\n time = `Every ${String(minuteStep)} minutes during ${listOf(\n schedule.hours.map((h) => formatTime(h, 0, locale)),\n isConsecutive(schedule.hours),\n )}`;\n } else if (schedule.minutes.length === 1) {\n const minute = schedule.minutes[0] ?? 0;\n time = `At ${listOf(\n schedule.hours.map((h) => formatTime(h, minute, locale)),\n false,\n )}`;\n } else {\n time = `At minute ${listOf(schedule.minutes.map(String), isConsecutive(schedule.minutes))} past ${listOf(\n schedule.hours.map((h) => formatTime(h, 0, locale)),\n isConsecutive(schedule.hours),\n )}`;\n }\n\n // Days. When both day fields are restricted a day matches if either does —\n // said with \"or\", because \"and\" is what readers assume and it is wrong.\n const dayPhrases: string[] = [];\n if (schedule.dayOfMonthRestricted) {\n const step = stepOf(dayText);\n dayPhrases.push(\n step !== null\n ? `${every(\"day\", step)} of the month`\n : `on day ${listOf(schedule.daysOfMonth.map(String), isConsecutive(schedule.daysOfMonth))} of the month`,\n );\n }\n if (schedule.dayOfWeekRestricted) {\n dayPhrases.push(\n `on ${listOf(\n schedule.daysOfWeek.map((d) => dayName(d, locale)),\n isConsecutive(schedule.daysOfWeek),\n )}`,\n );\n }\n let days = dayPhrases.join(\", or \");\n\n // A fixed time of day with no day named is every day. \"Every 15 minutes\"\n // already says how often, and \"every day\" after it would be noise.\n const fixedTime = !allMinutes && !allHours && minuteStep === null && hourStep === null;\n if (!days && fixedTime) days = \"every day\";\n\n if (schedule.months.length < 12) {\n const step = stepOf(monthText);\n const months =\n step !== null\n ? every(\"month\", step)\n : listOf(\n schedule.months.map((m) => monthName(m, locale)),\n isConsecutive(schedule.months),\n );\n days = `${days ? `${days} ` : \"\"}in ${months}`;\n }\n\n return days ? `${time} ${days}` : time;\n}\n\n/* ------------------------------------------------------------------ */\n/* Next runs */\n/* ------------------------------------------------------------------ */\n\nexport interface NextRunsOptions {\n /** Runs strictly after this instant. */\n from: Date;\n count?: number;\n /** IANA zone the expression's wall-clock times are in. Defaults to the runtime zone. */\n timeZone?: string;\n}\n\ninterface WallClock {\n year: number;\n month: number;\n day: number;\n hour: number;\n minute: number;\n /** 0 = Sunday. */\n weekday: number;\n}\n\nconst formatters = new Map<string, Intl.DateTimeFormat>();\n\nfunction formatterFor(timeZone: string | undefined): Intl.DateTimeFormat {\n const key = timeZone ?? \"\";\n let formatter = formatters.get(key);\n if (!formatter) {\n formatter = new Intl.DateTimeFormat(\"en-US\", {\n timeZone,\n hourCycle: \"h23\",\n year: \"numeric\",\n month: \"numeric\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"numeric\",\n weekday: \"short\",\n });\n formatters.set(key, formatter);\n }\n return formatter;\n}\n\nfunction wallClockOf(instant: number, timeZone: string | undefined): WallClock {\n const parts: Record<string, string> = {};\n for (const part of formatterFor(timeZone).formatToParts(new Date(instant))) {\n parts[part.type] = part.value;\n }\n return {\n year: Number(parts.year),\n month: Number(parts.month),\n day: Number(parts.day),\n hour: Number(parts.hour) % 24,\n minute: Number(parts.minute),\n weekday: DAY_NAMES.indexOf((parts.weekday ?? \"\").slice(0, 3).toUpperCase()),\n };\n}\n\nfunction offsetAt(instant: number, timeZone: string | undefined): number {\n const wall = wallClockOf(instant, timeZone);\n return (\n Date.UTC(wall.year, wall.month - 1, wall.day, wall.hour, wall.minute) -\n Math.floor(instant / 60_000) * 60_000\n );\n}\n\n/**\n * The instant a wall-clock time names in a zone, or null when it names none —\n * the hour the clocks skip in spring. An ambiguous time, in the hour that\n * repeats in autumn, resolves to its first occurrence.\n */\nexport function zonedTimeToInstant(\n year: number,\n month: number,\n day: number,\n hour: number,\n minute: number,\n timeZone: string | undefined,\n): number | null {\n const guess = Date.UTC(year, month - 1, day, hour, minute);\n // Each pass corrects the guess by the offset in force at the previous\n // answer; across a DST change the two answers are the two candidates.\n const candidates = new Set<number>();\n // Seeded from a day either side as well, so the offset that stopped\n // applying an hour ago — the one that makes an autumn time ambiguous — is\n // still tried.\n const oneDay = 24 * 60 * 60_000;\n for (const seed of [guess, guess - oneDay, guess + oneDay]) {\n let instant = seed;\n for (let pass = 0; pass < 2; pass += 1) {\n instant = guess - offsetAt(instant, timeZone);\n candidates.add(instant);\n }\n }\n for (const candidate of [...candidates].sort((a, b) => a - b)) {\n const wall = wallClockOf(candidate, timeZone);\n if (\n wall.year === year &&\n wall.month === month &&\n wall.day === day &&\n wall.hour === hour &&\n wall.minute === minute\n ) {\n return candidate;\n }\n }\n return null;\n}\n\n/** Roughly five years of days: enough to find the 29th of February, and to give up on the 30th. */\nconst MAX_DAYS = 366 * 5;\n\n/**\n * The next `count` instants the schedule fires, in order.\n *\n * Fewer than `count` are returned when the schedule cannot produce them —\n * `0 0 30 2 *` never runs, and saying so beats a spinner.\n */\nexport function nextRuns(expression: string, options: NextRunsOptions): Date[] {\n const { from, count = 5, timeZone } = options;\n const schedule = parseCron(expression);\n const runs: Date[] = [];\n\n const start = Math.floor(from.getTime() / 60_000) * 60_000 + 60_000;\n const months = new Set(schedule.months);\n const daysOfMonth = new Set(schedule.daysOfMonth);\n const daysOfWeek = new Set(schedule.daysOfWeek);\n\n const dayMatches = (wall: WallClock): boolean => {\n if (!months.has(wall.month)) return false;\n const domMatch = daysOfMonth.has(wall.day);\n const dowMatch = daysOfWeek.has(wall.weekday);\n if (schedule.dayOfMonthRestricted && schedule.dayOfWeekRestricted)\n return domMatch || dowMatch;\n if (schedule.dayOfMonthRestricted) return domMatch;\n if (schedule.dayOfWeekRestricted) return dowMatch;\n return true;\n };\n\n // Walk day by day from noon, which no DST change touches, so that stepping\n // 24 hours always lands in the next calendar day.\n const first = wallClockOf(start, timeZone);\n let noon = zonedTimeToInstant(first.year, first.month, first.day, 12, 0, timeZone);\n if (noon === null) return runs;\n\n for (let i = 0; i < MAX_DAYS && runs.length < count; i += 1, noon += 24 * 60 * 60_000) {\n const wall = wallClockOf(noon, timeZone);\n if (!dayMatches(wall)) continue;\n\n for (const hour of schedule.hours) {\n for (const minute of schedule.minutes) {\n const instant = zonedTimeToInstant(\n wall.year,\n wall.month,\n wall.day,\n hour,\n minute,\n timeZone,\n );\n if (instant === null || instant < start) continue;\n runs.push(new Date(instant));\n if (runs.length >= count) return runs;\n }\n }\n }\n\n return runs;\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Cron, CronBuilder, CronBuilderProps, CronExpression, CronExpressionProps, CronNextRuns, CronNextRunsProps, CronProps } from "./cron-editor.js";
2
+ import { CRON_SHORTCUTS, CronExpressionError, CronField, CronSchedule, DescribeOptions, NextRunsOptions, describeCron, isValidCron, nextRuns, parseCron, zonedTimeToInstant } from "./cron-expression.js";
3
+ export { CRON_SHORTCUTS, Cron, CronBuilder, type CronBuilderProps, CronExpression, CronExpressionError, type CronExpressionProps, type CronField, CronNextRuns, type CronNextRunsProps, type CronProps, type CronSchedule, type DescribeOptions, type NextRunsOptions, describeCron, isValidCron, nextRuns, parseCron, zonedTimeToInstant };
@@ -0,0 +1,3 @@
1
+ import { CRON_SHORTCUTS, CronExpressionError, describeCron, isValidCron, nextRuns, parseCron, zonedTimeToInstant } from "./cron-expression.js";
2
+ import { Cron, CronBuilder, CronExpression, CronNextRuns } from "./cron-editor.js";
3
+ export { CRON_SHORTCUTS, Cron, CronBuilder, CronExpression, CronExpressionError, CronNextRuns, describeCron, isValidCron, nextRuns, parseCron, zonedTimeToInstant };
@@ -0,0 +1,17 @@
1
+ import { defineMeta } from "../../registry/schema.js";
2
+ //#region src/components/cron-editor/meta.ts
3
+ const meta = defineMeta({
4
+ name: "cron-editor",
5
+ title: "Cron Editor",
6
+ description: "A schedule as a cron expression, with a plain-language reading and the next runs.",
7
+ category: "form",
8
+ status: "stable",
9
+ dependencies: [],
10
+ registryDependencies: ["input", "select"],
11
+ files: ["cron-expression.ts", "cron-editor.tsx"],
12
+ a11y: "The expression field is described by one element that holds either the plain-language reading or the reason the expression is invalid, so a reader hears the error replace the reading rather than both at once; an invalid expression is never applied. The builder's day buttons are a named group of aria-pressed toggles with the full day name as the accessible name, and the last selected day cannot be removed silently — the group says why. Days 29 to 31 say in text that shorter months skip them. Next runs are a list of time elements with machine-readable datetimes, headed by the zone they are in, because a time with no zone is the classic scheduling mistake. Nothing clock-dependent renders until the clock is known, so server and client cannot disagree."
13
+ });
14
+ //#endregion
15
+ export { meta };
16
+
17
+ //# sourceMappingURL=meta.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta.js","names":[],"sources":["../../../src/components/cron-editor/meta.ts"],"sourcesContent":["import { defineMeta } from \"@/registry/schema\";\n\nexport const meta = defineMeta({\n name: \"cron-editor\",\n title: \"Cron Editor\",\n description:\n \"A schedule as a cron expression, with a plain-language reading and the next runs.\",\n category: \"form\",\n status: \"stable\",\n dependencies: [],\n registryDependencies: [\"input\", \"select\"],\n files: [\"cron-expression.ts\", \"cron-editor.tsx\"],\n a11y:\n \"The expression field is described by one element that holds either the plain-language \" +\n \"reading or the reason the expression is invalid, so a reader hears the error replace the \" +\n \"reading rather than both at once; an invalid expression is never applied. The builder's \" +\n \"day buttons are a named group of aria-pressed toggles with the full day name as the \" +\n \"accessible name, and the last selected day cannot be removed silently — the group says why. \" +\n \"Days 29 to 31 say in text that shorter months skip them. Next runs are a list of time \" +\n \"elements with machine-readable datetimes, headed by the zone they are in, because a time \" +\n \"with no zone is the classic scheduling mistake. Nothing clock-dependent renders until the \" +\n \"clock is known, so server and client cannot disagree.\",\n});\n"],"mappings":";;AAEA,MAAa,OAAO,WAAW;CAC7B,MAAM;CACN,OAAO;CACP,aACE;CACF,UAAU;CACV,QAAQ;CACR,cAAc,CAAC;CACf,sBAAsB,CAAC,SAAS,QAAQ;CACxC,OAAO,CAAC,sBAAsB,iBAAiB;CAC/C,MACE;AASJ,CAAC"}
@@ -0,0 +1,61 @@
1
+ import { ComponentPropsWithRef, ReactNode } from "react";
2
+ //#region src/components/dns-record/dns-record.d.ts
3
+ /**
4
+ * "Add this record at your DNS provider."
5
+ *
6
+ * Vercel, Resend, Cloudflare, Postmark, Google Workspace and every product
7
+ * that verifies a domain or routes its mail draws this card by hand, and
8
+ * they all learn the same three things the hard way.
9
+ *
10
+ * The parts are copied separately. A provider's form has a Name field, a
11
+ * Type field and a Value field, so one button that copies the whole line
12
+ * copies something nobody can paste anywhere.
13
+ *
14
+ * The Name field is a trap. Some providers want the host relative to the
15
+ * zone, `_dmarc`; some want the full name, `_dmarc.acme.com`; and some take
16
+ * the relative form and append the zone themselves, so a full name pasted
17
+ * in becomes `_dmarc.acme.com.acme.com` and the check fails for a reason
18
+ * nobody can see. So the host is shown both ways, with the sentence that
19
+ * explains which to use.
20
+ *
21
+ * A failed check says what was found. "Not verified" sends people back to
22
+ * their provider to stare at a record that is correct and has not
23
+ * propagated yet; "found v=spf1 -all, expected v=spf1 include:…" sends them
24
+ * to the typo. And nothing found at all is said as nothing found, with how
25
+ * long that can take, because it is not the same as wrong.
26
+ */
27
+ type DnsRecordStatus = "pending" | "checking" | "verified" | "failed";
28
+ interface DnsHostForms {
29
+ /** Relative to the zone: `_dmarc`, or `@` for the zone itself. */
30
+ relative: string;
31
+ /** Fully qualified: `_dmarc.acme.com`. */
32
+ full: string;
33
+ }
34
+ /**
35
+ * The host both ways a provider might want it. Accepts either form and a
36
+ * trailing dot, so the record can be declared however the backend has it.
37
+ */
38
+ declare function dnsHostForms(name: string, zone: string): DnsHostForms;
39
+ interface DnsRecordProps extends Omit<ComponentPropsWithRef<"section">, "children"> {
40
+ type: string;
41
+ /** The host, relative or fully qualified. */
42
+ name: string;
43
+ value: string;
44
+ /** The zone the record belongs to. Enables the host to be shown both ways. */
45
+ zone?: string;
46
+ ttl?: number | string;
47
+ priority?: number;
48
+ /** What the record is for, in the reader's language: "Proves you own acme.com". */
49
+ purpose?: string;
50
+ status?: DnsRecordStatus;
51
+ /** What the check found instead, when it failed. The useful part. */
52
+ found?: string[];
53
+ checkedAt?: Date;
54
+ locale?: string;
55
+ onCheck?: () => void;
56
+ children?: ReactNode;
57
+ }
58
+ declare function DnsRecord({ className, type, name, value, zone, ttl, priority, purpose, status, found, checkedAt, locale, onCheck, children, ...props }: DnsRecordProps): import("react").JSX.Element;
59
+ //#endregion
60
+ export { DnsHostForms, DnsRecord, DnsRecordProps, DnsRecordStatus, dnsHostForms };
61
+ //# sourceMappingURL=dns-record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dns-record.d.ts","names":[],"sources":["../../../src/components/dns-record/dns-record.tsx"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;KAyCY;UAEK;;EAEf;;EAEA;;;;;;iBAOc,aAAa,cAAc,eAAe;UAYzC,uBAAuB,KAAK;EAC3C;;EAEA;EACA;;EAEA;EACA;EACA;;EAEA;EACA,SAAS;;EAET;EACA,YAAY;EACZ;EACA;EACA,WAAW;;iBAKG,YACd,WACA,MACA,MACA,OACA,MACA,KACA,UACA,SACA,QACA,OACA,WACA,QACA,SACA,aACG,SACF,iCAAc,IAAA"}