@praxisui/cron-builder 0.0.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/LICENSE ADDED
@@ -0,0 +1,6 @@
1
+ This package is licensed under the Apache License, Version 2.0.
2
+
3
+ For the full license text, see the repository root LICENSE file:
4
+ ../../LICENSE
5
+
6
+ Apache License 2.0: https://www.apache.org/licenses/LICENSE-2.0
package/README.md ADDED
@@ -0,0 +1,121 @@
1
+ # @praxis/cron-builder
2
+
3
+ Angular cron expression builder component with validation, humanized description and preview of next occurrences. Ships as a standalone component.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm i @praxis/cron-builder
9
+ ```
10
+
11
+ Peer dependencies (Angular v20):
12
+ - `@angular/core` `^20.1.0`
13
+ - `@angular/common` `^20.1.0`
14
+ - `@angular/forms` `^20.1.0`
15
+ - `@angular/cdk` `^20.1.0`
16
+ - `@angular/material` `^20.1.0`
17
+ - `@praxis/core` `^0.0.1`
18
+
19
+ Runtime dependencies (installed automatically):
20
+ - `cron-parser`, `cronstrue`, `cron-validator`, `luxon`
21
+
22
+ ## Quick Start
23
+
24
+ Import the standalone component and use it in your template.
25
+
26
+ ```ts
27
+ // Any standalone component or NgModule-enabled component
28
+ import { Component } from '@angular/core';
29
+ import { PdxCronBuilderComponent } from '@praxis/cron-builder';
30
+
31
+ @Component({
32
+ selector: 'app-schedule-form',
33
+ standalone: true,
34
+ imports: [PdxCronBuilderComponent],
35
+ template: `
36
+ <pdx-cron-builder
37
+ [metadata]="metadata"
38
+ (ngModelChange)="onCronChange($event)"
39
+ ></pdx-cron-builder>
40
+ `,
41
+ })
42
+ export class ScheduleFormComponent {
43
+ metadata = {
44
+ mode: 'both',
45
+ timezone: 'UTC',
46
+ presets: [
47
+ { label: 'Every 5 minutes', cron: '*/5 * * * *' },
48
+ { label: 'Daily at midnight', cron: '0 0 * * *' },
49
+ ],
50
+ previewOccurrences: 5,
51
+ } satisfies CronBuilderMetadata;
52
+
53
+ onCronChange(cron: string) {
54
+ console.log('Selected CRON:', cron);
55
+ }
56
+ }
57
+ ```
58
+
59
+ Template-only example:
60
+
61
+ ```html
62
+ <pdx-cron-builder [metadata]="{ mode: 'advanced', timezone: 'UTC', previewOccurrences: 3 }"></pdx-cron-builder>
63
+ ```
64
+
65
+ ## API (Quick Reference)
66
+
67
+ Exports:
68
+ - `PdxCronBuilderComponent`
69
+ - Types: `CronBuilderMetadata`, `SimpleCronFormValue`, `AdvancedCronFormValue`, `CronPresetType`
70
+
71
+ Inputs/Outputs:
72
+ - `metadata: CronBuilderMetadata` – configure fields, timezone, locale, presets, preview.
73
+ - Implements `ControlValueAccessor` – bind with `[(ngModel)]` or reactive forms.
74
+
75
+ `CronBuilderMetadata` (key fields):
76
+ - `mode?: 'simple' | 'advanced' | 'both'` – enabled UI tabs.
77
+ - `fields?: { seconds?: boolean; ... }` – show seconds field.
78
+ - `timezone?: string` – IANA tz used for preview (e.g. `UTC`, `America/Sao_Paulo`).
79
+ - `locale?: string` – locale used by humanized text.
80
+ - `presets?: Array<{ label: string; cron: string }>` – quick-pick presets.
81
+ - `previewOccurrences?: number` – number of preview dates to show.
82
+ - `validators?: { invalidCronMessage?: string }` – customize error messages.
83
+
84
+ ## CommonJS/ESM Notes
85
+
86
+ This component dynamically imports `cron-parser`, `cronstrue` and `cron-validator`. Some versions of these, or their transitive deps (e.g. `luxon`), may emit CommonJS warnings in Angular builds.
87
+
88
+ If you want to suppress warnings in your app build, add them to `allowedCommonJsDependencies`:
89
+
90
+ ```json
91
+ // angular.json
92
+ {
93
+ "projects": {
94
+ "your-app": {
95
+ "architect": {
96
+ "build": {
97
+ "options": {
98
+ "allowedCommonJsDependencies": [
99
+ "cron-parser",
100
+ "cronstrue",
101
+ "cron-validator",
102
+ "luxon"
103
+ ]
104
+ }
105
+ }
106
+ }
107
+ }
108
+ }
109
+ }
110
+ ```
111
+
112
+ Note: Depending on your Angular CLI version, the warning behavior can vary. The above option is supported in current CLI releases when using the application builder.
113
+
114
+ ## Compatibility
115
+
116
+ - Angular: v20.x
117
+ - Module format: ESM2022, partial Ivy metadata
118
+
119
+ ## License
120
+
121
+ Apache-2.0 – see `LICENSE` packaged with this library or the repository root.
@@ -0,0 +1,451 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, forwardRef, Input, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import * as i1 from '@angular/forms';
4
+ import { NonNullableFormBuilder, FormControl, ReactiveFormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
5
+ import * as i11 from '@angular/common';
6
+ import { CommonModule } from '@angular/common';
7
+ import * as i2 from '@angular/material/tabs';
8
+ import { MatTabsModule } from '@angular/material/tabs';
9
+ import { MatRadioModule } from '@angular/material/radio';
10
+ import * as i3 from '@angular/material/select';
11
+ import { MatSelectModule } from '@angular/material/select';
12
+ import * as i4 from '@angular/material/input';
13
+ import { MatInputModule } from '@angular/material/input';
14
+ import { MatFormFieldModule } from '@angular/material/form-field';
15
+ import * as i5 from '@angular/material/list';
16
+ import { MatListModule } from '@angular/material/list';
17
+ import * as i6 from '@angular/material/button';
18
+ import { MatButtonModule } from '@angular/material/button';
19
+ import * as i7 from '@angular/material/icon';
20
+ import { MatIconModule } from '@angular/material/icon';
21
+ import * as i8 from '@angular/material/tooltip';
22
+ import { MatTooltipModule } from '@angular/material/tooltip';
23
+ import * as i9 from '@angular/material/slider';
24
+ import { MatSliderModule } from '@angular/material/slider';
25
+ import * as i10 from '@angular/material/chips';
26
+ import { MatChipsModule } from '@angular/material/chips';
27
+ import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
28
+ import { Clipboard } from '@angular/cdk/clipboard';
29
+ import { PraxisIconDirective } from '@praxisui/core';
30
+ import { Subject } from 'rxjs';
31
+ import { takeUntil } from 'rxjs/operators';
32
+
33
+ // Lazy module singletons
34
+ let _cronValidator;
35
+ let _cronstrue;
36
+ let _cronParser;
37
+ class PdxCronBuilderComponent {
38
+ // Tipos auxiliares para Typed Forms
39
+ fb = inject(NonNullableFormBuilder);
40
+ clipboard = inject(Clipboard);
41
+ snackBar = inject(MatSnackBar);
42
+ metadata = {
43
+ mode: 'both',
44
+ fields: {
45
+ seconds: false,
46
+ minutes: true,
47
+ hours: true,
48
+ dom: true,
49
+ month: true,
50
+ dow: true,
51
+ },
52
+ presets: [
53
+ { label: 'Every minute (* * * * *)', cron: '* * * * *' },
54
+ { label: 'Every 5 minutes (*/5 * * * *)', cron: '*/5 * * * *' },
55
+ { label: 'Daily at midnight (0 0 * * *)', cron: '0 0 * * *' },
56
+ { label: 'Weekly on Sunday at midnight (0 0 * * 0)', cron: '0 0 * * 0' },
57
+ ],
58
+ previewOccurrences: 5,
59
+ };
60
+ value = null;
61
+ isDisabled = false;
62
+ activeTab = 'simple';
63
+ selectedTabIndex = 0;
64
+ form;
65
+ simpleForm;
66
+ timezoneControl = new FormControl('UTC', { nonNullable: true });
67
+ destroy$ = new Subject();
68
+ humanized = '';
69
+ preview = [];
70
+ error = null;
71
+ // Opções expostas ao template para controle de fluxo moderno
72
+ weekdayLabels = ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'];
73
+ weeklyDayOptions = [0, 1, 2, 3, 4, 5, 6];
74
+ nthOrderOptions = [1, 2, 3, 4, 5];
75
+ nthDayOptions = [1, 2, 3, 4, 5, 6, 0];
76
+ timezoneOptions = ['UTC', 'America/Sao_Paulo', 'Europe/London', 'America/New_York'];
77
+ constructor() {
78
+ this.form = this.fb.group({
79
+ seconds: this.fb.control('*'),
80
+ minutes: this.fb.control('*'),
81
+ hours: this.fb.control('*'),
82
+ dayOfMonth: this.fb.control('*'),
83
+ month: this.fb.control('*'),
84
+ dayOfWeek: this.fb.control('*'),
85
+ });
86
+ this.simpleForm = this.fb.group({
87
+ type: this.fb.control('everyNMinutes'),
88
+ everyN: this.fb.control(5),
89
+ dailyTime: this.fb.control('00:00'),
90
+ weeklyDays: this.fb.control([]),
91
+ weeklyTime: this.fb.control('00:00'),
92
+ monthlyDay: this.fb.control(1),
93
+ monthlyTime: this.fb.control('00:00'),
94
+ nth: this.fb.control(1),
95
+ nthDay: this.fb.control(1),
96
+ nthTime: this.fb.control('00:00'),
97
+ });
98
+ }
99
+ // Acesso facilitado aos controles no template
100
+ get simpleControls() {
101
+ return this.simpleForm.controls;
102
+ }
103
+ ngOnInit() {
104
+ if (this.metadata.mode === 'simple') {
105
+ this.activeTab = 'simple';
106
+ this.selectedTabIndex = 0;
107
+ }
108
+ else if (this.metadata.mode === 'advanced') {
109
+ this.activeTab = 'advanced';
110
+ this.selectedTabIndex = 1;
111
+ }
112
+ this.form.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((value) => {
113
+ const cron = this.constructCronString(value);
114
+ this.updateValue(cron);
115
+ });
116
+ this.simpleForm.valueChanges
117
+ .pipe(takeUntil(this.destroy$))
118
+ .subscribe((value) => {
119
+ const cron = this.buildCronFromSimple(value);
120
+ this.updateValue(cron);
121
+ });
122
+ this.timezoneControl.setValue(this.metadata.timezone || 'UTC', {
123
+ emitEvent: false,
124
+ });
125
+ this.timezoneControl.valueChanges
126
+ .pipe(takeUntil(this.destroy$))
127
+ .subscribe((tz) => {
128
+ this.metadata.timezone = tz || 'UTC';
129
+ if (typeof this.value === 'string') {
130
+ this.generatePreview(this.value);
131
+ }
132
+ });
133
+ }
134
+ onChange = () => { };
135
+ onTouched = () => { };
136
+ writeValue(value) {
137
+ if (typeof value === 'string') {
138
+ this.updateValue(value, false);
139
+ this.parseCronString(value);
140
+ this.syncSimpleForm(value);
141
+ }
142
+ }
143
+ registerOnChange(fn) {
144
+ this.onChange = fn;
145
+ }
146
+ registerOnTouched(fn) {
147
+ this.onTouched = fn;
148
+ }
149
+ setDisabledState(isDisabled) {
150
+ this.isDisabled = isDisabled;
151
+ if (isDisabled) {
152
+ this.form.disable();
153
+ this.simpleForm.disable();
154
+ this.timezoneControl.disable();
155
+ }
156
+ else {
157
+ this.form.enable();
158
+ this.simpleForm.enable();
159
+ this.timezoneControl.enable();
160
+ }
161
+ }
162
+ onTabChange(event) {
163
+ this.selectedTabIndex = event.index;
164
+ this.activeTab = event.index === 0 ? 'simple' : 'advanced';
165
+ this.onTouched();
166
+ }
167
+ setPreset(cron) {
168
+ this.updateValue(cron);
169
+ this.parseCronString(cron);
170
+ this.syncSimpleForm(cron);
171
+ }
172
+ updateValue(cron, emitEvent = true) {
173
+ this.value = cron;
174
+ if (emitEvent) {
175
+ this.onChange(cron);
176
+ }
177
+ this.validate(cron);
178
+ this.humanize(cron);
179
+ this.generatePreview(cron);
180
+ }
181
+ copyCron() {
182
+ if (typeof this.value === 'string') {
183
+ this.clipboard.copy(this.value);
184
+ this.snackBar.open('CRON expression copied', undefined, {
185
+ duration: 2000,
186
+ });
187
+ }
188
+ }
189
+ copyHumanized() {
190
+ if (this.humanized) {
191
+ this.clipboard.copy(this.humanized);
192
+ this.snackBar.open('Description copied', undefined, { duration: 2000 });
193
+ }
194
+ }
195
+ importCron() {
196
+ const cron = prompt('Enter CRON expression');
197
+ if (cron) {
198
+ this.updateValue(cron);
199
+ this.parseCronString(cron);
200
+ this.syncSimpleForm(cron);
201
+ }
202
+ }
203
+ validate(cron) {
204
+ (async () => {
205
+ try {
206
+ _cronValidator = _cronValidator || (await import('cron-validator'));
207
+ const ok = await _cronValidator.isValidCron?.(cron, { alias: true, allowBlankDay: true });
208
+ this.error = ok
209
+ ? null
210
+ : this.metadata.validators?.invalidCronMessage || 'Invalid CRON expression';
211
+ }
212
+ catch {
213
+ // On import/validation failure, do a minimal sanity check and do not block UX
214
+ this.error = /\S+ \S+ \S+ \S+ \S+/.test(cron) ? null : 'Invalid CRON expression';
215
+ }
216
+ })();
217
+ }
218
+ humanize(cron) {
219
+ if (this.error) {
220
+ this.humanized = '';
221
+ return;
222
+ }
223
+ (async () => {
224
+ try {
225
+ _cronstrue = _cronstrue || (await import('cronstrue'));
226
+ this.humanized = _cronstrue.toString?.(cron, { locale: this.metadata.locale }) || '';
227
+ }
228
+ catch {
229
+ this.humanized = '';
230
+ }
231
+ })();
232
+ }
233
+ generatePreview(cron) {
234
+ if (this.error || !this.metadata.previewOccurrences) {
235
+ this.preview = [];
236
+ return;
237
+ }
238
+ (async () => {
239
+ try {
240
+ _cronParser = _cronParser || (await import('cron-parser'));
241
+ const parse = _cronParser.parse || _cronParser.default?.parse;
242
+ const interval = parse?.(cron, {
243
+ currentDate: this.metadata.previewFrom ?? new Date(),
244
+ tz: this.metadata.timezone,
245
+ });
246
+ const next = [];
247
+ for (let i = 0; i < (this.metadata.previewOccurrences ?? 5); i++) {
248
+ next.push(interval.next().toDate());
249
+ }
250
+ this.preview = next;
251
+ }
252
+ catch {
253
+ this.preview = [];
254
+ }
255
+ })();
256
+ }
257
+ parseCronString(cron) {
258
+ const parts = cron.trim().split(/\s+/);
259
+ if (parts.length < 5)
260
+ return;
261
+ let seconds = '*';
262
+ let minutes;
263
+ let hours;
264
+ let dayOfMonth;
265
+ let month;
266
+ let dayOfWeek;
267
+ if (parts.length === 6) {
268
+ [seconds, minutes, hours, dayOfMonth, month, dayOfWeek] = parts;
269
+ }
270
+ else {
271
+ [minutes, hours, dayOfMonth, month, dayOfWeek] = parts;
272
+ }
273
+ this.form.patchValue({
274
+ seconds: this.metadata.fields?.seconds ? seconds : '*',
275
+ minutes: minutes || '*',
276
+ hours: hours || '*',
277
+ dayOfMonth: dayOfMonth || '*',
278
+ month: month || '*',
279
+ dayOfWeek: dayOfWeek || '*',
280
+ }, { emitEvent: false });
281
+ }
282
+ syncSimpleForm(cron) {
283
+ const parts = cron.trim().split(/\s+/);
284
+ if (parts.length < 5)
285
+ return;
286
+ if (parts.length === 6) {
287
+ parts.shift();
288
+ }
289
+ const [minutes, hours, dom, month, dow] = parts;
290
+ if (minutes.startsWith('*/') &&
291
+ hours === '*' &&
292
+ dom === '*' &&
293
+ month === '*' &&
294
+ dow === '*') {
295
+ this.simpleForm.patchValue({ type: 'everyNMinutes', everyN: parseInt(minutes.slice(2), 10) }, { emitEvent: false });
296
+ }
297
+ else if (dom === '*' && month === '*' && dow === '*') {
298
+ this.simpleForm.patchValue({ type: 'dailyAt', dailyTime: this.toTime(hours, minutes) }, { emitEvent: false });
299
+ }
300
+ else if (dom === '*' && month === '*') {
301
+ this.simpleForm.patchValue({
302
+ type: 'weekly',
303
+ weeklyTime: this.toTime(hours, minutes),
304
+ weeklyDays: dow.split(',').map((d) => +d),
305
+ }, { emitEvent: false });
306
+ }
307
+ else if (month === '*' && dow === '*') {
308
+ this.simpleForm.patchValue({
309
+ type: 'monthlyDay',
310
+ monthlyTime: this.toTime(hours, minutes),
311
+ monthlyDay: +dom,
312
+ }, { emitEvent: false });
313
+ }
314
+ else if (dom === '?' && dow.includes('#')) {
315
+ const [day, nth] = dow.split('#');
316
+ this.simpleForm.patchValue({
317
+ type: 'monthlyNthWeekday',
318
+ nth: +nth,
319
+ nthDay: +day,
320
+ nthTime: this.toTime(hours, minutes),
321
+ }, { emitEvent: false });
322
+ }
323
+ }
324
+ buildCronFromSimple(v) {
325
+ let cron;
326
+ switch (v.type) {
327
+ case 'everyNMinutes':
328
+ cron = `*/${v.everyN || 1} * * * *`;
329
+ break;
330
+ case 'dailyAt': {
331
+ const [h, m] = this.parseTime(v.dailyTime);
332
+ cron = `${m} ${h} * * *`;
333
+ break;
334
+ }
335
+ case 'weekly': {
336
+ const [h, m] = this.parseTime(v.weeklyTime);
337
+ const days = (v.weeklyDays || []).sort().join(',') || '*';
338
+ cron = `${m} ${h} * * ${days}`;
339
+ break;
340
+ }
341
+ case 'monthlyDay': {
342
+ const [h, m] = this.parseTime(v.monthlyTime);
343
+ cron = `${m} ${h} ${v.monthlyDay || 1} * *`;
344
+ break;
345
+ }
346
+ case 'monthlyNthWeekday': {
347
+ const [h, m] = this.parseTime(v.nthTime);
348
+ cron = `${m} ${h} ? * ${v.nthDay || 1}#${v.nth || 1}`;
349
+ break;
350
+ }
351
+ default:
352
+ cron = '* * * * *';
353
+ }
354
+ return this.metadata.fields?.seconds ? `0 ${cron}` : cron;
355
+ }
356
+ parseTime(time) {
357
+ if (!time) {
358
+ return [0, 0];
359
+ }
360
+ const [h, m] = time.split(':').map((v) => parseInt(v, 10));
361
+ return [h || 0, m || 0];
362
+ }
363
+ toTime(h, m) {
364
+ return `${this.pad(parseInt(h, 10))}:${this.pad(parseInt(m, 10))}`;
365
+ }
366
+ pad(v) {
367
+ return v.toString().padStart(2, '0');
368
+ }
369
+ constructCronString(value) {
370
+ const { seconds, minutes, hours, dayOfMonth, month, dayOfWeek } = value;
371
+ if (this.metadata.fields?.seconds) {
372
+ return `${seconds || '*'} ${minutes || '*'} ${hours || '*'} ${dayOfMonth || '*'} ${month || '*'} ${dayOfWeek || '*'}`;
373
+ }
374
+ return `${minutes || '*'} ${hours || '*'} ${dayOfMonth || '*'} ${month || '*'} ${dayOfWeek || '*'}`;
375
+ }
376
+ ngOnDestroy() {
377
+ this.destroy$.next();
378
+ this.destroy$.complete();
379
+ }
380
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PdxCronBuilderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
381
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.4", type: PdxCronBuilderComponent, isStandalone: true, selector: "pdx-cron-builder", inputs: { metadata: "metadata" }, providers: [
382
+ {
383
+ provide: NG_VALUE_ACCESSOR,
384
+ useExisting: forwardRef(() => PdxCronBuilderComponent),
385
+ multi: true,
386
+ },
387
+ ], ngImport: i0, template: "<div class=\"cron-builder-container\" (focusout)=\"onTouched()\">\n @if (metadata.mode === 'both') {\n <mat-tab-group\n [selectedIndex]=\"selectedTabIndex\"\n (selectedTabChange)=\"onTabChange($event)\"\n >\n <mat-tab label=\"Simple\"></mat-tab>\n <mat-tab label=\"Advanced\"></mat-tab>\n </mat-tab-group>\n }\n\n @if (value) {\n <div class=\"cron-expression\">\n <mat-form-field appearance=\"outline\" class=\"cron-expression-field\">\n <mat-label>CRON Expression</mat-label>\n <input matInput [value]=\"value\" readonly />\n <button\n mat-icon-button\n matSuffix\n (click)=\"copyCron()\"\n [matTooltip]=\"'Copy to clipboard'\"\n aria-label=\"Copy CRON expression\"\n >\n <mat-icon [praxisIcon]=\"'content_copy'\"></mat-icon>\n </button>\n </mat-form-field>\n <button mat-button (click)=\"importCron()\">Import CRON</button>\n </div>\n }\n\n @switch (activeTab) {\n @case ('simple') {\n <div [formGroup]=\"simpleForm\" class=\"simple-mode\">\n <mat-form-field appearance=\"outline\" class=\"preset-select\">\n <mat-label>Preset</mat-label>\n <mat-select formControlName=\"type\">\n <mat-option value=\"everyNMinutes\">A cada X min</mat-option>\n <mat-option value=\"dailyAt\">Diariamente \u00E0s</mat-option>\n <mat-option value=\"weekly\">Semanal (dias marcados) \u00E0s</mat-option>\n <mat-option value=\"monthlyDay\">Mensal (dia N) \u00E0s</mat-option>\n <mat-option value=\"monthlyNthWeekday\">\n Mensal (N-\u00E9sima 2\u00AA-feira) \u00E0s\n </mat-option>\n </mat-select>\n </mat-form-field>\n\n @switch (simpleControls.type.value) {\n @case ('everyNMinutes') {\n <div class=\"preset-body\">\n <mat-slider\n formControlName=\"everyN\"\n min=\"1\"\n max=\"60\"\n step=\"1\"\n thumbLabel\n ></mat-slider>\n <div class=\"cron-hint\">\n A cada {{ simpleControls.everyN.value }} minutos\n </div>\n </div>\n }\n\n @case ('dailyAt') {\n <div class=\"preset-body\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Hora</mat-label>\n <input matInput type=\"time\" formControlName=\"dailyTime\" />\n </mat-form-field>\n <div class=\"cron-hint\">\n Diariamente \u00E0s {{ simpleControls.dailyTime.value }}\n </div>\n </div>\n }\n\n @case ('weekly') {\n <div class=\"preset-body\">\n <mat-chip-listbox formControlName=\"weeklyDays\" multiple>\n @for (day of weeklyDayOptions; track day) {\n <mat-chip-option [value]=\"day\">\n {{ weekdayLabels[day] }}\n </mat-chip-option>\n }\n </mat-chip-listbox>\n <mat-form-field appearance=\"outline\">\n <mat-label>Hora</mat-label>\n <input matInput type=\"time\" formControlName=\"weeklyTime\" />\n </mat-form-field>\n <div class=\"cron-hint\">\n Semanalmente \u00E0s {{ simpleControls.weeklyTime.value }}\n </div>\n </div>\n }\n\n @case ('monthlyDay') {\n <div class=\"preset-body\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Dia</mat-label>\n <input\n matInput\n type=\"number\"\n formControlName=\"monthlyDay\"\n min=\"1\"\n max=\"31\"\n />\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Hora</mat-label>\n <input matInput type=\"time\" formControlName=\"monthlyTime\" />\n </mat-form-field>\n <div class=\"cron-hint\">\n Dia {{ simpleControls.monthlyDay.value }} \u00E0s\n {{ simpleControls.monthlyTime.value }}\n </div>\n </div>\n }\n\n @case ('monthlyNthWeekday') {\n <div class=\"preset-body\">\n <mat-form-field appearance=\"outline\">\n <mat-label>N-\u00E9sima</mat-label>\n <mat-select formControlName=\"nth\">\n @for (nth of nthOrderOptions; track nth) {\n <mat-option [value]=\"nth\">{{ nth }}\u00AA</mat-option>\n }\n </mat-select>\n </mat-form-field>\n <mat-chip-listbox formControlName=\"nthDay\">\n @for (day of nthDayOptions; track day) {\n <mat-chip-option [value]=\"day\">\n {{ weekdayLabels[day] }}\n </mat-chip-option>\n }\n </mat-chip-listbox>\n <mat-form-field appearance=\"outline\">\n <mat-label>Hora</mat-label>\n <input matInput type=\"time\" formControlName=\"nthTime\" />\n </mat-form-field>\n <div class=\"cron-hint\">\n {{ simpleControls.nth.value }}\u00AA\n {{ weekdayLabels[simpleControls.nthDay.value] }}\n \u00E0s\n {{ simpleControls.nthTime.value }}\n </div>\n </div>\n }\n }\n </div>\n }\n\n @case ('advanced') {\n <div [formGroup]=\"form\">\n <div class=\"cron-fields\">\n @if (metadata.fields?.minutes) {\n <mat-form-field>\n <mat-label>Minutes</mat-label>\n <input matInput formControlName=\"minutes\" />\n </mat-form-field>\n }\n @if (metadata.fields?.hours) {\n <mat-form-field>\n <mat-label>Hours</mat-label>\n <input matInput formControlName=\"hours\" />\n </mat-form-field>\n }\n @if (metadata.fields?.dom) {\n <mat-form-field>\n <mat-label>Day of Month</mat-label>\n <input matInput formControlName=\"dayOfMonth\" />\n </mat-form-field>\n }\n @if (metadata.fields?.month) {\n <mat-form-field>\n <mat-label>Month</mat-label>\n <input matInput formControlName=\"month\" />\n </mat-form-field>\n }\n @if (metadata.fields?.dow) {\n <mat-form-field>\n <mat-label>Day of Week</mat-label>\n <input matInput formControlName=\"dayOfWeek\" />\n </mat-form-field>\n }\n @if (metadata.fields?.seconds) {\n <mat-form-field>\n <mat-label>Seconds</mat-label>\n <input matInput formControlName=\"seconds\" />\n </mat-form-field>\n }\n </div>\n </div>\n }\n }\n\n <div class=\"cron-feedback\">\n <mat-form-field appearance=\"outline\" class=\"timezone-field\">\n <mat-label>Timezone</mat-label>\n <mat-select [formControl]=\"timezoneControl\">\n @for (tz of timezoneOptions; track tz) {\n <mat-option [value]=\"tz\">\n {{ tz }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n @if (humanized) {\n <div class=\"humanized-description\" aria-live=\"polite\">\n {{ humanized }}\n <button\n mat-icon-button\n class=\"copy-humanized\"\n (click)=\"copyHumanized()\"\n [matTooltip]=\"'Copy description'\"\n aria-label=\"Copy description\"\n >\n <mat-icon [praxisIcon]=\"'content_copy'\"></mat-icon>\n </button>\n </div>\n }\n\n @if (error) {\n <div class=\"cron-error\">{{ error }}</div>\n }\n\n @if (preview.length > 0) {\n <div class=\"preview-section\">\n <h4>Next Occurrences:</h4>\n <mat-list>\n @for (date of preview; track $index) {\n <mat-list-item>\n {{\n date\n | date\n : \"full\"\n : timezoneControl.value\n : metadata.locale || \"pt-BR\"\n }}\n </mat-list-item>\n }\n </mat-list>\n </div>\n }\n </div>\n\n @if (metadata.hint) {\n <div class=\"cron-hint\">{{ metadata.hint }}</div>\n }\n</div>\n", styles: [":host{display:block}.cron-expression-field{width:100%}.cron-expression{margin-bottom:1rem}.simple-mode{display:flex;flex-direction:column;gap:1rem}.preset-body{display:flex;flex-direction:column;gap:.5rem}.cron-feedback{margin-top:1rem;display:flex;flex-direction:column;gap:.5rem}.humanized-description{display:flex;align-items:center;gap:.5rem}.timezone-field{width:250px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i2.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i2.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: MatRadioModule }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "component", type: i3.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i3.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatListModule }, { kind: "component", type: i5.MatList, selector: "mat-list", exportAs: ["matList"] }, { kind: "component", type: i5.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i6.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i6.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatSliderModule }, { kind: "component", type: i9.MatSlider, selector: "mat-slider", inputs: ["disabled", "discrete", "showTickMarks", "min", "color", "disableRipple", "max", "step", "displayWith"], exportAs: ["matSlider"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i10.MatChipListbox, selector: "mat-chip-listbox", inputs: ["multiple", "aria-orientation", "selectable", "compareWith", "required", "hideSingleSelectionIndicator", "value"], outputs: ["change"] }, { kind: "component", type: i10.MatChipOption, selector: "mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]", inputs: ["selectable", "selected"], outputs: ["selectionChange"] }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "pipe", type: i11.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
388
+ }
389
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PdxCronBuilderComponent, decorators: [{
390
+ type: Component,
391
+ args: [{ selector: 'pdx-cron-builder', standalone: true, imports: [
392
+ CommonModule,
393
+ ReactiveFormsModule,
394
+ MatTabsModule,
395
+ MatRadioModule,
396
+ MatSelectModule,
397
+ MatInputModule,
398
+ MatFormFieldModule,
399
+ MatListModule,
400
+ MatButtonModule,
401
+ MatIconModule,
402
+ MatTooltipModule,
403
+ MatSliderModule,
404
+ MatChipsModule,
405
+ MatSnackBarModule,
406
+ PraxisIconDirective,
407
+ ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
408
+ {
409
+ provide: NG_VALUE_ACCESSOR,
410
+ useExisting: forwardRef(() => PdxCronBuilderComponent),
411
+ multi: true,
412
+ },
413
+ ], template: "<div class=\"cron-builder-container\" (focusout)=\"onTouched()\">\n @if (metadata.mode === 'both') {\n <mat-tab-group\n [selectedIndex]=\"selectedTabIndex\"\n (selectedTabChange)=\"onTabChange($event)\"\n >\n <mat-tab label=\"Simple\"></mat-tab>\n <mat-tab label=\"Advanced\"></mat-tab>\n </mat-tab-group>\n }\n\n @if (value) {\n <div class=\"cron-expression\">\n <mat-form-field appearance=\"outline\" class=\"cron-expression-field\">\n <mat-label>CRON Expression</mat-label>\n <input matInput [value]=\"value\" readonly />\n <button\n mat-icon-button\n matSuffix\n (click)=\"copyCron()\"\n [matTooltip]=\"'Copy to clipboard'\"\n aria-label=\"Copy CRON expression\"\n >\n <mat-icon [praxisIcon]=\"'content_copy'\"></mat-icon>\n </button>\n </mat-form-field>\n <button mat-button (click)=\"importCron()\">Import CRON</button>\n </div>\n }\n\n @switch (activeTab) {\n @case ('simple') {\n <div [formGroup]=\"simpleForm\" class=\"simple-mode\">\n <mat-form-field appearance=\"outline\" class=\"preset-select\">\n <mat-label>Preset</mat-label>\n <mat-select formControlName=\"type\">\n <mat-option value=\"everyNMinutes\">A cada X min</mat-option>\n <mat-option value=\"dailyAt\">Diariamente \u00E0s</mat-option>\n <mat-option value=\"weekly\">Semanal (dias marcados) \u00E0s</mat-option>\n <mat-option value=\"monthlyDay\">Mensal (dia N) \u00E0s</mat-option>\n <mat-option value=\"monthlyNthWeekday\">\n Mensal (N-\u00E9sima 2\u00AA-feira) \u00E0s\n </mat-option>\n </mat-select>\n </mat-form-field>\n\n @switch (simpleControls.type.value) {\n @case ('everyNMinutes') {\n <div class=\"preset-body\">\n <mat-slider\n formControlName=\"everyN\"\n min=\"1\"\n max=\"60\"\n step=\"1\"\n thumbLabel\n ></mat-slider>\n <div class=\"cron-hint\">\n A cada {{ simpleControls.everyN.value }} minutos\n </div>\n </div>\n }\n\n @case ('dailyAt') {\n <div class=\"preset-body\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Hora</mat-label>\n <input matInput type=\"time\" formControlName=\"dailyTime\" />\n </mat-form-field>\n <div class=\"cron-hint\">\n Diariamente \u00E0s {{ simpleControls.dailyTime.value }}\n </div>\n </div>\n }\n\n @case ('weekly') {\n <div class=\"preset-body\">\n <mat-chip-listbox formControlName=\"weeklyDays\" multiple>\n @for (day of weeklyDayOptions; track day) {\n <mat-chip-option [value]=\"day\">\n {{ weekdayLabels[day] }}\n </mat-chip-option>\n }\n </mat-chip-listbox>\n <mat-form-field appearance=\"outline\">\n <mat-label>Hora</mat-label>\n <input matInput type=\"time\" formControlName=\"weeklyTime\" />\n </mat-form-field>\n <div class=\"cron-hint\">\n Semanalmente \u00E0s {{ simpleControls.weeklyTime.value }}\n </div>\n </div>\n }\n\n @case ('monthlyDay') {\n <div class=\"preset-body\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Dia</mat-label>\n <input\n matInput\n type=\"number\"\n formControlName=\"monthlyDay\"\n min=\"1\"\n max=\"31\"\n />\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Hora</mat-label>\n <input matInput type=\"time\" formControlName=\"monthlyTime\" />\n </mat-form-field>\n <div class=\"cron-hint\">\n Dia {{ simpleControls.monthlyDay.value }} \u00E0s\n {{ simpleControls.monthlyTime.value }}\n </div>\n </div>\n }\n\n @case ('monthlyNthWeekday') {\n <div class=\"preset-body\">\n <mat-form-field appearance=\"outline\">\n <mat-label>N-\u00E9sima</mat-label>\n <mat-select formControlName=\"nth\">\n @for (nth of nthOrderOptions; track nth) {\n <mat-option [value]=\"nth\">{{ nth }}\u00AA</mat-option>\n }\n </mat-select>\n </mat-form-field>\n <mat-chip-listbox formControlName=\"nthDay\">\n @for (day of nthDayOptions; track day) {\n <mat-chip-option [value]=\"day\">\n {{ weekdayLabels[day] }}\n </mat-chip-option>\n }\n </mat-chip-listbox>\n <mat-form-field appearance=\"outline\">\n <mat-label>Hora</mat-label>\n <input matInput type=\"time\" formControlName=\"nthTime\" />\n </mat-form-field>\n <div class=\"cron-hint\">\n {{ simpleControls.nth.value }}\u00AA\n {{ weekdayLabels[simpleControls.nthDay.value] }}\n \u00E0s\n {{ simpleControls.nthTime.value }}\n </div>\n </div>\n }\n }\n </div>\n }\n\n @case ('advanced') {\n <div [formGroup]=\"form\">\n <div class=\"cron-fields\">\n @if (metadata.fields?.minutes) {\n <mat-form-field>\n <mat-label>Minutes</mat-label>\n <input matInput formControlName=\"minutes\" />\n </mat-form-field>\n }\n @if (metadata.fields?.hours) {\n <mat-form-field>\n <mat-label>Hours</mat-label>\n <input matInput formControlName=\"hours\" />\n </mat-form-field>\n }\n @if (metadata.fields?.dom) {\n <mat-form-field>\n <mat-label>Day of Month</mat-label>\n <input matInput formControlName=\"dayOfMonth\" />\n </mat-form-field>\n }\n @if (metadata.fields?.month) {\n <mat-form-field>\n <mat-label>Month</mat-label>\n <input matInput formControlName=\"month\" />\n </mat-form-field>\n }\n @if (metadata.fields?.dow) {\n <mat-form-field>\n <mat-label>Day of Week</mat-label>\n <input matInput formControlName=\"dayOfWeek\" />\n </mat-form-field>\n }\n @if (metadata.fields?.seconds) {\n <mat-form-field>\n <mat-label>Seconds</mat-label>\n <input matInput formControlName=\"seconds\" />\n </mat-form-field>\n }\n </div>\n </div>\n }\n }\n\n <div class=\"cron-feedback\">\n <mat-form-field appearance=\"outline\" class=\"timezone-field\">\n <mat-label>Timezone</mat-label>\n <mat-select [formControl]=\"timezoneControl\">\n @for (tz of timezoneOptions; track tz) {\n <mat-option [value]=\"tz\">\n {{ tz }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n @if (humanized) {\n <div class=\"humanized-description\" aria-live=\"polite\">\n {{ humanized }}\n <button\n mat-icon-button\n class=\"copy-humanized\"\n (click)=\"copyHumanized()\"\n [matTooltip]=\"'Copy description'\"\n aria-label=\"Copy description\"\n >\n <mat-icon [praxisIcon]=\"'content_copy'\"></mat-icon>\n </button>\n </div>\n }\n\n @if (error) {\n <div class=\"cron-error\">{{ error }}</div>\n }\n\n @if (preview.length > 0) {\n <div class=\"preview-section\">\n <h4>Next Occurrences:</h4>\n <mat-list>\n @for (date of preview; track $index) {\n <mat-list-item>\n {{\n date\n | date\n : \"full\"\n : timezoneControl.value\n : metadata.locale || \"pt-BR\"\n }}\n </mat-list-item>\n }\n </mat-list>\n </div>\n }\n </div>\n\n @if (metadata.hint) {\n <div class=\"cron-hint\">{{ metadata.hint }}</div>\n }\n</div>\n", styles: [":host{display:block}.cron-expression-field{width:100%}.cron-expression{margin-bottom:1rem}.simple-mode{display:flex;flex-direction:column;gap:1rem}.preset-body{display:flex;flex-direction:column;gap:.5rem}.cron-feedback{margin-top:1rem;display:flex;flex-direction:column;gap:.5rem}.humanized-description{display:flex;align-items:center;gap:.5rem}.timezone-field{width:250px}\n"] }]
414
+ }], ctorParameters: () => [], propDecorators: { metadata: [{
415
+ type: Input
416
+ }] } });
417
+
418
+ // Keep this metadata object self-contained to avoid build-time dependency on @praxisui/core types.
419
+ const PDX_CRON_BUILDER_COMPONENT_METADATA = {
420
+ id: 'pdx-cron-builder',
421
+ selector: 'pdx-cron-builder',
422
+ component: PdxCronBuilderComponent,
423
+ friendlyName: 'Cron (builder)',
424
+ description: 'Editor visual para expressões CRON com validação e presets.',
425
+ icon: 'schedule',
426
+ inputs: [
427
+ { name: 'label', type: 'string', description: 'Rótulo do campo' },
428
+ { name: 'hint', type: 'string', description: 'Texto auxiliar' },
429
+ { name: 'presets', type: 'Array<{ label: string; cron: string }>', description: 'Lista de presets disponíveis' },
430
+ { name: 'enableSeconds', type: 'boolean', description: 'Habilita segundo campo (6 partes)', default: false },
431
+ { name: 'metadata', type: 'any', description: 'Metadados compatíveis com formulários Praxis' },
432
+ ],
433
+ outputs: [
434
+ { name: 'valueChange', type: 'string', description: 'Emite quando a expressão cron muda' },
435
+ ],
436
+ tags: ['widget', 'field', 'cron', 'schedule'],
437
+ lib: '@praxisui/cron-builder',
438
+ };
439
+
440
+ /*
441
+ * Public API Surface of praxis-cron-builder
442
+ */
443
+ // Note: runtime cron libraries are loaded dynamically inside the component to
444
+ // avoid build-time type resolution issues with ng-packagr.
445
+
446
+ /**
447
+ * Generated bundle index. Do not edit.
448
+ */
449
+
450
+ export { PDX_CRON_BUILDER_COMPONENT_METADATA, PdxCronBuilderComponent };
451
+ //# sourceMappingURL=praxisui-cron-builder.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"praxisui-cron-builder.mjs","sources":["../../../projects/praxis-cron-builder/src/lib/pdx-cron-builder.component.ts","../../../projects/praxis-cron-builder/src/lib/pdx-cron-builder.component.html","../../../projects/praxis-cron-builder/src/lib/pdx-cron-builder.metadata.ts","../../../projects/praxis-cron-builder/src/public-api.ts","../../../projects/praxis-cron-builder/src/praxisui-cron-builder.ts"],"sourcesContent":["import { Component, Input, forwardRef, OnInit, OnDestroy, ChangeDetectionStrategy, inject } from '@angular/core';\nimport {\r\n ControlValueAccessor,\r\n NG_VALUE_ACCESSOR,\r\n NonNullableFormBuilder,\n FormGroup,\n FormControl,\n ReactiveFormsModule,\n} from '@angular/forms';\nimport { CommonModule } from '@angular/common';\r\nimport { MatTabsModule, MatTabChangeEvent } from '@angular/material/tabs';\r\nimport { MatRadioModule } from '@angular/material/radio';\r\nimport { MatSelectModule } from '@angular/material/select';\r\nimport { MatInputModule } from '@angular/material/input';\r\nimport { MatFormFieldModule } from '@angular/material/form-field';\r\nimport { MatListModule } from '@angular/material/list';\r\nimport { MatButtonModule } from '@angular/material/button';\r\nimport { MatIconModule } from '@angular/material/icon';\r\nimport { MatTooltipModule } from '@angular/material/tooltip';\r\nimport { MatSliderModule } from '@angular/material/slider';\r\nimport { MatChipsModule } from '@angular/material/chips';\r\nimport { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';\r\nimport { Clipboard } from '@angular/cdk/clipboard';\nimport { PraxisIconDirective } from '@praxisui/core';\n// Avoid static imports of heavy node-targeted cron libraries to prevent ng-packagr TS issues.\n// Use dynamic imports inside methods instead.\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n// Lazy module singletons\nlet _cronValidator: any | undefined;\nlet _cronstrue: any | undefined;\nlet _cronParser: any | undefined;\n\r\n// ... (keep existing interfaces)\r\nexport interface Recurrence {\r\n // Define recurrence properties here later\r\n}\r\n\r\nexport interface CronBuilderMetadata {\n mode?: 'simple' | 'advanced' | 'both';\r\n fields?: {\r\n seconds?: boolean;\r\n minutes?: boolean;\r\n hours?: boolean;\r\n dom?: boolean;\r\n month?: boolean;\r\n dow?: boolean;\r\n };\r\n timezone?: string;\r\n locale?: string;\r\n presets?: Array<{ label: string; cron: string }>;\r\n previewOccurrences?: number;\r\n previewFrom?: Date;\r\n validators?: {\r\n requiredMessage?: string;\r\n invalidCronMessage?: string;\r\n };\r\n validationTrigger?: 'change' | 'blur';\r\n validationDebounce?: number;\r\n errorPosition?: 'tooltip' | 'inline';\r\n showInlineErrors?: boolean;\r\n hint?: string;\r\n}\n\nexport type CronPresetType =\n | 'everyNMinutes'\n | 'dailyAt'\n | 'weekly'\n | 'monthlyDay'\n | 'monthlyNthWeekday';\n\nexport interface SimpleCronFormValue {\n type: CronPresetType;\n everyN: number;\n dailyTime: string;\n weeklyDays: number[];\n weeklyTime: string;\n monthlyDay: number;\n monthlyTime: string;\n nth: number;\n nthDay: number;\n nthTime: string;\n}\n\nexport interface AdvancedCronFormValue {\n seconds?: string;\n minutes: string;\n hours: string;\n dayOfMonth: string;\n month: string;\n dayOfWeek: string;\n}\n\n@Component({\n selector: 'pdx-cron-builder',\n standalone: true,\n imports: [\n CommonModule,\n ReactiveFormsModule,\n MatTabsModule,\n MatRadioModule,\n MatSelectModule,\n MatInputModule,\n MatFormFieldModule,\n MatListModule,\n MatButtonModule,\n MatIconModule,\n MatTooltipModule,\n MatSliderModule,\n MatChipsModule,\n MatSnackBarModule,\n PraxisIconDirective,\n ],\n templateUrl: './pdx-cron-builder.component.html',\n styleUrls: ['./pdx-cron-builder.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => PdxCronBuilderComponent),\n multi: true,\n },\n ],\n})\n\nexport class PdxCronBuilderComponent\n implements ControlValueAccessor, OnInit, OnDestroy\n{\n // Tipos auxiliares para Typed Forms\n private readonly fb = inject(NonNullableFormBuilder);\n private readonly clipboard = inject(Clipboard);\n private readonly snackBar = inject(MatSnackBar);\n\n @Input() metadata: CronBuilderMetadata = {\n mode: 'both',\n fields: {\n seconds: false,\n minutes: true,\n hours: true,\r\n dom: true,\r\n month: true,\r\n dow: true,\r\n },\r\n presets: [\r\n { label: 'Every minute (* * * * *)', cron: '* * * * *' },\r\n { label: 'Every 5 minutes (*/5 * * * *)', cron: '*/5 * * * *' },\r\n { label: 'Daily at midnight (0 0 * * *)', cron: '0 0 * * *' },\r\n { label: 'Weekly on Sunday at midnight (0 0 * * 0)', cron: '0 0 * * 0' },\r\n ],\r\n previewOccurrences: 5,\r\n };\r\n\r\n value: string | Recurrence | null = null;\r\n isDisabled = false;\r\n activeTab: 'simple' | 'advanced' = 'simple';\n selectedTabIndex = 0;\n\n readonly form: FormGroup;\n readonly simpleForm: FormGroup;\n readonly timezoneControl = new FormControl<string>('UTC', { nonNullable: true });\n private readonly destroy$ = new Subject<void>();\n\n humanized = '';\n preview: Date[] = [];\n error: string | null = null;\n\n // Opções expostas ao template para controle de fluxo moderno\n readonly weekdayLabels = ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'] as const;\n readonly weeklyDayOptions = [0, 1, 2, 3, 4, 5, 6] as const;\n readonly nthOrderOptions = [1, 2, 3, 4, 5] as const;\n readonly nthDayOptions = [1, 2, 3, 4, 5, 6, 0] as const;\n readonly timezoneOptions = ['UTC', 'America/Sao_Paulo', 'Europe/London', 'America/New_York'] as const;\n\n constructor() {\n this.form = this.fb.group({\n seconds: this.fb.control('*'),\n minutes: this.fb.control('*'),\n hours: this.fb.control('*'),\n dayOfMonth: this.fb.control('*'),\n month: this.fb.control('*'),\n dayOfWeek: this.fb.control('*'),\n });\n\n this.simpleForm = this.fb.group({\n type: this.fb.control<'everyNMinutes' | 'dailyAt' | 'weekly' | 'monthlyDay' | 'monthlyNthWeekday'>('everyNMinutes'),\n everyN: this.fb.control(5),\n dailyTime: this.fb.control('00:00'),\n weeklyDays: this.fb.control<number[]>([]),\n weeklyTime: this.fb.control('00:00'),\n monthlyDay: this.fb.control(1),\n monthlyTime: this.fb.control('00:00'),\n nth: this.fb.control(1),\n nthDay: this.fb.control(1),\n nthTime: this.fb.control('00:00'),\n });\n }\n\n // Acesso facilitado aos controles no template\n get simpleControls() {\n return (this.simpleForm as any).controls as Record<string, FormControl>;\n }\n\r\n ngOnInit(): void {\r\n if (this.metadata.mode === 'simple') {\r\n this.activeTab = 'simple';\r\n this.selectedTabIndex = 0;\r\n } else if (this.metadata.mode === 'advanced') {\r\n this.activeTab = 'advanced';\r\n this.selectedTabIndex = 1;\r\n }\r\n\r\n this.form.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((value: AdvancedCronFormValue) => {\n const cron = this.constructCronString(value as AdvancedCronFormValue);\n this.updateValue(cron);\n });\n\n this.simpleForm.valueChanges\n .pipe(takeUntil(this.destroy$))\n .subscribe((value: SimpleCronFormValue) => {\n const cron = this.buildCronFromSimple(value as SimpleCronFormValue);\n this.updateValue(cron);\n });\n\r\n this.timezoneControl.setValue(this.metadata.timezone || 'UTC', {\r\n emitEvent: false,\r\n });\r\n this.timezoneControl.valueChanges\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe((tz) => {\r\n this.metadata.timezone = tz || 'UTC';\r\n if (typeof this.value === 'string') {\r\n this.generatePreview(this.value);\r\n }\r\n });\r\n }\r\n\r\n onChange: (value: any) => void = () => {};\r\n onTouched: () => void = () => {};\r\n\r\n writeValue(value: string | Recurrence | null): void {\r\n if (typeof value === 'string') {\r\n this.updateValue(value, false);\r\n this.parseCronString(value);\r\n this.syncSimpleForm(value);\r\n }\r\n }\r\n\r\n registerOnChange(fn: any): void {\r\n this.onChange = fn;\r\n }\r\n\r\n registerOnTouched(fn: any): void {\r\n this.onTouched = fn;\r\n }\r\n\r\n setDisabledState?(isDisabled: boolean): void {\r\n this.isDisabled = isDisabled;\r\n if (isDisabled) {\r\n this.form.disable();\r\n this.simpleForm.disable();\r\n this.timezoneControl.disable();\r\n } else {\r\n this.form.enable();\r\n this.simpleForm.enable();\r\n this.timezoneControl.enable();\r\n }\r\n }\r\n\r\n onTabChange(event: MatTabChangeEvent): void {\r\n this.selectedTabIndex = event.index;\r\n this.activeTab = event.index === 0 ? 'simple' : 'advanced';\r\n this.onTouched();\r\n }\r\n\r\n setPreset(cron: string): void {\r\n this.updateValue(cron);\r\n this.parseCronString(cron);\r\n this.syncSimpleForm(cron);\r\n }\r\n\r\n updateValue(cron: string, emitEvent = true): void {\r\n this.value = cron;\r\n if (emitEvent) {\r\n this.onChange(cron);\r\n }\r\n this.validate(cron);\r\n this.humanize(cron);\r\n this.generatePreview(cron);\r\n }\r\n\r\n copyCron(): void {\r\n if (typeof this.value === 'string') {\r\n this.clipboard.copy(this.value);\r\n this.snackBar.open('CRON expression copied', undefined, {\r\n duration: 2000,\r\n });\r\n }\r\n }\r\n\r\n copyHumanized(): void {\r\n if (this.humanized) {\r\n this.clipboard.copy(this.humanized);\r\n this.snackBar.open('Description copied', undefined, { duration: 2000 });\r\n }\r\n }\r\n\r\n importCron(): void {\r\n const cron = prompt('Enter CRON expression');\r\n if (cron) {\r\n this.updateValue(cron);\r\n this.parseCronString(cron);\r\n this.syncSimpleForm(cron);\r\n }\r\n }\r\n\r\n private validate(cron: string): void {\n (async () => {\n try {\n _cronValidator = _cronValidator || (await import('cron-validator'));\n const ok = await _cronValidator.isValidCron?.(cron, { alias: true, allowBlankDay: true });\n this.error = ok\n ? null\n : this.metadata.validators?.invalidCronMessage || 'Invalid CRON expression';\n } catch {\n // On import/validation failure, do a minimal sanity check and do not block UX\n this.error = /\\S+ \\S+ \\S+ \\S+ \\S+/.test(cron) ? null : 'Invalid CRON expression';\n }\n })();\n }\n\r\n private humanize(cron: string): void {\n if (this.error) {\n this.humanized = '';\n return;\n }\n (async () => {\n try {\n _cronstrue = _cronstrue || (await import('cronstrue'));\n this.humanized = _cronstrue.toString?.(cron, { locale: this.metadata.locale }) || '';\n } catch {\n this.humanized = '';\n }\n })();\n }\n\r\n private generatePreview(cron: string): void {\n if (this.error || !this.metadata.previewOccurrences) {\n this.preview = [];\n return;\n }\n (async () => {\n try {\n _cronParser = _cronParser || (await import('cron-parser'));\n const parse = _cronParser.parse || _cronParser.default?.parse;\n const interval = parse?.(cron, {\n currentDate: this.metadata.previewFrom ?? new Date(),\n tz: this.metadata.timezone,\n } as any);\n const next: Date[] = [];\n for (let i = 0; i < (this.metadata.previewOccurrences ?? 5); i++) {\n next.push(interval.next().toDate());\n }\n this.preview = next;\n } catch {\n this.preview = [];\n }\n })();\n }\n\r\n private parseCronString(cron: string): void {\r\n const parts = cron.trim().split(/\\s+/);\r\n if (parts.length < 5) return;\r\n\r\n let seconds = '*';\r\n let minutes: string;\r\n let hours: string;\r\n let dayOfMonth: string;\r\n let month: string;\r\n let dayOfWeek: string;\r\n\r\n if (parts.length === 6) {\r\n [seconds, minutes, hours, dayOfMonth, month, dayOfWeek] = parts;\r\n } else {\r\n [minutes, hours, dayOfMonth, month, dayOfWeek] = parts;\r\n }\r\n\r\n this.form.patchValue(\r\n {\r\n seconds: this.metadata.fields?.seconds ? seconds : '*',\r\n minutes: minutes || '*',\r\n hours: hours || '*',\r\n dayOfMonth: dayOfMonth || '*',\r\n month: month || '*',\r\n dayOfWeek: dayOfWeek || '*',\r\n },\r\n { emitEvent: false },\r\n );\r\n }\r\n\r\n private syncSimpleForm(cron: string): void {\r\n const parts = cron.trim().split(/\\s+/);\r\n if (parts.length < 5) return;\r\n if (parts.length === 6) {\r\n parts.shift();\r\n }\r\n const [minutes, hours, dom, month, dow] = parts;\r\n\r\n if (\r\n minutes.startsWith('*/') &&\r\n hours === '*' &&\r\n dom === '*' &&\r\n month === '*' &&\r\n dow === '*'\r\n ) {\r\n this.simpleForm.patchValue(\r\n { type: 'everyNMinutes', everyN: parseInt(minutes.slice(2), 10) },\r\n { emitEvent: false },\r\n );\r\n } else if (dom === '*' && month === '*' && dow === '*') {\r\n this.simpleForm.patchValue(\r\n { type: 'dailyAt', dailyTime: this.toTime(hours, minutes) },\r\n { emitEvent: false },\r\n );\r\n } else if (dom === '*' && month === '*') {\r\n this.simpleForm.patchValue(\r\n {\r\n type: 'weekly',\r\n weeklyTime: this.toTime(hours, minutes),\r\n weeklyDays: dow.split(',').map((d) => +d),\r\n },\r\n { emitEvent: false },\r\n );\r\n } else if (month === '*' && dow === '*') {\r\n this.simpleForm.patchValue(\r\n {\r\n type: 'monthlyDay',\r\n monthlyTime: this.toTime(hours, minutes),\r\n monthlyDay: +dom,\r\n },\r\n { emitEvent: false },\r\n );\r\n } else if (dom === '?' && dow.includes('#')) {\r\n const [day, nth] = dow.split('#');\r\n this.simpleForm.patchValue(\r\n {\r\n type: 'monthlyNthWeekday',\r\n nth: +nth,\r\n nthDay: +day,\r\n nthTime: this.toTime(hours, minutes),\r\n },\r\n { emitEvent: false },\r\n );\r\n }\r\n }\r\n\r\n private buildCronFromSimple(v: SimpleCronFormValue): string {\n let cron: string;\r\n switch (v.type) {\r\n case 'everyNMinutes':\r\n cron = `*/${v.everyN || 1} * * * *`;\r\n break;\r\n case 'dailyAt': {\r\n const [h, m] = this.parseTime(v.dailyTime);\r\n cron = `${m} ${h} * * *`;\r\n break;\r\n }\r\n case 'weekly': {\r\n const [h, m] = this.parseTime(v.weeklyTime);\r\n const days = (v.weeklyDays || []).sort().join(',') || '*';\r\n cron = `${m} ${h} * * ${days}`;\r\n break;\r\n }\r\n case 'monthlyDay': {\r\n const [h, m] = this.parseTime(v.monthlyTime);\r\n cron = `${m} ${h} ${v.monthlyDay || 1} * *`;\r\n break;\r\n }\r\n case 'monthlyNthWeekday': {\r\n const [h, m] = this.parseTime(v.nthTime);\r\n cron = `${m} ${h} ? * ${v.nthDay || 1}#${v.nth || 1}`;\r\n break;\r\n }\r\n default:\r\n cron = '* * * * *';\r\n }\r\n return this.metadata.fields?.seconds ? `0 ${cron}` : cron;\r\n }\r\n\r\n private parseTime(time: string): [number, number] {\r\n if (!time) {\r\n return [0, 0];\r\n }\r\n const [h, m] = time.split(':').map((v) => parseInt(v, 10));\r\n return [h || 0, m || 0];\r\n }\r\n\r\n private toTime(h: string, m: string): string {\r\n return `${this.pad(parseInt(h, 10))}:${this.pad(parseInt(m, 10))}`;\r\n }\r\n\r\n private pad(v: number): string {\r\n return v.toString().padStart(2, '0');\r\n }\r\n\r\n private constructCronString(value: AdvancedCronFormValue): string {\n const { seconds, minutes, hours, dayOfMonth, month, dayOfWeek } = value;\r\n if (this.metadata.fields?.seconds) {\r\n return `${seconds || '*'} ${minutes || '*'} ${hours || '*'} ${dayOfMonth || '*'} ${month || '*'} ${dayOfWeek || '*'}`;\r\n }\r\n return `${minutes || '*'} ${hours || '*'} ${dayOfMonth || '*'} ${month || '*'} ${dayOfWeek || '*'}`;\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.destroy$.next();\r\n this.destroy$.complete();\r\n }\r\n}\r\n","<div class=\"cron-builder-container\" (focusout)=\"onTouched()\">\n @if (metadata.mode === 'both') {\n <mat-tab-group\n [selectedIndex]=\"selectedTabIndex\"\n (selectedTabChange)=\"onTabChange($event)\"\n >\n <mat-tab label=\"Simple\"></mat-tab>\n <mat-tab label=\"Advanced\"></mat-tab>\n </mat-tab-group>\n }\n\n @if (value) {\n <div class=\"cron-expression\">\n <mat-form-field appearance=\"outline\" class=\"cron-expression-field\">\n <mat-label>CRON Expression</mat-label>\n <input matInput [value]=\"value\" readonly />\n <button\n mat-icon-button\n matSuffix\n (click)=\"copyCron()\"\n [matTooltip]=\"'Copy to clipboard'\"\n aria-label=\"Copy CRON expression\"\n >\n <mat-icon [praxisIcon]=\"'content_copy'\"></mat-icon>\n </button>\n </mat-form-field>\n <button mat-button (click)=\"importCron()\">Import CRON</button>\n </div>\n }\n\n @switch (activeTab) {\n @case ('simple') {\n <div [formGroup]=\"simpleForm\" class=\"simple-mode\">\n <mat-form-field appearance=\"outline\" class=\"preset-select\">\n <mat-label>Preset</mat-label>\n <mat-select formControlName=\"type\">\n <mat-option value=\"everyNMinutes\">A cada X min</mat-option>\n <mat-option value=\"dailyAt\">Diariamente às</mat-option>\n <mat-option value=\"weekly\">Semanal (dias marcados) às</mat-option>\n <mat-option value=\"monthlyDay\">Mensal (dia N) às</mat-option>\n <mat-option value=\"monthlyNthWeekday\">\n Mensal (N-ésima 2ª-feira) às\n </mat-option>\n </mat-select>\n </mat-form-field>\n\n @switch (simpleControls.type.value) {\n @case ('everyNMinutes') {\n <div class=\"preset-body\">\n <mat-slider\n formControlName=\"everyN\"\n min=\"1\"\n max=\"60\"\n step=\"1\"\n thumbLabel\n ></mat-slider>\n <div class=\"cron-hint\">\n A cada {{ simpleControls.everyN.value }} minutos\n </div>\n </div>\n }\n\n @case ('dailyAt') {\n <div class=\"preset-body\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Hora</mat-label>\n <input matInput type=\"time\" formControlName=\"dailyTime\" />\n </mat-form-field>\n <div class=\"cron-hint\">\n Diariamente às {{ simpleControls.dailyTime.value }}\n </div>\n </div>\n }\n\n @case ('weekly') {\n <div class=\"preset-body\">\n <mat-chip-listbox formControlName=\"weeklyDays\" multiple>\n @for (day of weeklyDayOptions; track day) {\n <mat-chip-option [value]=\"day\">\n {{ weekdayLabels[day] }}\n </mat-chip-option>\n }\n </mat-chip-listbox>\n <mat-form-field appearance=\"outline\">\n <mat-label>Hora</mat-label>\n <input matInput type=\"time\" formControlName=\"weeklyTime\" />\n </mat-form-field>\n <div class=\"cron-hint\">\n Semanalmente às {{ simpleControls.weeklyTime.value }}\n </div>\n </div>\n }\n\n @case ('monthlyDay') {\n <div class=\"preset-body\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Dia</mat-label>\n <input\n matInput\n type=\"number\"\n formControlName=\"monthlyDay\"\n min=\"1\"\n max=\"31\"\n />\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Hora</mat-label>\n <input matInput type=\"time\" formControlName=\"monthlyTime\" />\n </mat-form-field>\n <div class=\"cron-hint\">\n Dia {{ simpleControls.monthlyDay.value }} às\n {{ simpleControls.monthlyTime.value }}\n </div>\n </div>\n }\n\n @case ('monthlyNthWeekday') {\n <div class=\"preset-body\">\n <mat-form-field appearance=\"outline\">\n <mat-label>N-ésima</mat-label>\n <mat-select formControlName=\"nth\">\n @for (nth of nthOrderOptions; track nth) {\n <mat-option [value]=\"nth\">{{ nth }}ª</mat-option>\n }\n </mat-select>\n </mat-form-field>\n <mat-chip-listbox formControlName=\"nthDay\">\n @for (day of nthDayOptions; track day) {\n <mat-chip-option [value]=\"day\">\n {{ weekdayLabels[day] }}\n </mat-chip-option>\n }\n </mat-chip-listbox>\n <mat-form-field appearance=\"outline\">\n <mat-label>Hora</mat-label>\n <input matInput type=\"time\" formControlName=\"nthTime\" />\n </mat-form-field>\n <div class=\"cron-hint\">\n {{ simpleControls.nth.value }}ª\n {{ weekdayLabels[simpleControls.nthDay.value] }}\n às\n {{ simpleControls.nthTime.value }}\n </div>\n </div>\n }\n }\n </div>\n }\n\n @case ('advanced') {\n <div [formGroup]=\"form\">\n <div class=\"cron-fields\">\n @if (metadata.fields?.minutes) {\n <mat-form-field>\n <mat-label>Minutes</mat-label>\n <input matInput formControlName=\"minutes\" />\n </mat-form-field>\n }\n @if (metadata.fields?.hours) {\n <mat-form-field>\n <mat-label>Hours</mat-label>\n <input matInput formControlName=\"hours\" />\n </mat-form-field>\n }\n @if (metadata.fields?.dom) {\n <mat-form-field>\n <mat-label>Day of Month</mat-label>\n <input matInput formControlName=\"dayOfMonth\" />\n </mat-form-field>\n }\n @if (metadata.fields?.month) {\n <mat-form-field>\n <mat-label>Month</mat-label>\n <input matInput formControlName=\"month\" />\n </mat-form-field>\n }\n @if (metadata.fields?.dow) {\n <mat-form-field>\n <mat-label>Day of Week</mat-label>\n <input matInput formControlName=\"dayOfWeek\" />\n </mat-form-field>\n }\n @if (metadata.fields?.seconds) {\n <mat-form-field>\n <mat-label>Seconds</mat-label>\n <input matInput formControlName=\"seconds\" />\n </mat-form-field>\n }\n </div>\n </div>\n }\n }\n\n <div class=\"cron-feedback\">\n <mat-form-field appearance=\"outline\" class=\"timezone-field\">\n <mat-label>Timezone</mat-label>\n <mat-select [formControl]=\"timezoneControl\">\n @for (tz of timezoneOptions; track tz) {\n <mat-option [value]=\"tz\">\n {{ tz }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n @if (humanized) {\n <div class=\"humanized-description\" aria-live=\"polite\">\n {{ humanized }}\n <button\n mat-icon-button\n class=\"copy-humanized\"\n (click)=\"copyHumanized()\"\n [matTooltip]=\"'Copy description'\"\n aria-label=\"Copy description\"\n >\n <mat-icon [praxisIcon]=\"'content_copy'\"></mat-icon>\n </button>\n </div>\n }\n\n @if (error) {\n <div class=\"cron-error\">{{ error }}</div>\n }\n\n @if (preview.length > 0) {\n <div class=\"preview-section\">\n <h4>Next Occurrences:</h4>\n <mat-list>\n @for (date of preview; track $index) {\n <mat-list-item>\n {{\n date\n | date\n : \"full\"\n : timezoneControl.value\n : metadata.locale || \"pt-BR\"\n }}\n </mat-list-item>\n }\n </mat-list>\n </div>\n }\n </div>\n\n @if (metadata.hint) {\n <div class=\"cron-hint\">{{ metadata.hint }}</div>\n }\n</div>\n","import { PdxCronBuilderComponent } from './pdx-cron-builder.component';\n\n// Keep this metadata object self-contained to avoid build-time dependency on @praxisui/core types.\nexport const PDX_CRON_BUILDER_COMPONENT_METADATA: any = {\n id: 'pdx-cron-builder',\n selector: 'pdx-cron-builder',\n component: PdxCronBuilderComponent,\n friendlyName: 'Cron (builder)',\n description: 'Editor visual para expressões CRON com validação e presets.',\n icon: 'schedule',\n inputs: [\n { name: 'label', type: 'string', description: 'Rótulo do campo' },\n { name: 'hint', type: 'string', description: 'Texto auxiliar' },\n { name: 'presets', type: 'Array<{ label: string; cron: string }>', description: 'Lista de presets disponíveis' },\n { name: 'enableSeconds', type: 'boolean', description: 'Habilita segundo campo (6 partes)', default: false },\n { name: 'metadata', type: 'any', description: 'Metadados compatíveis com formulários Praxis' },\n ],\n outputs: [\n { name: 'valueChange', type: 'string', description: 'Emite quando a expressão cron muda' },\n ],\n tags: ['widget', 'field', 'cron', 'schedule'],\n lib: '@praxisui/cron-builder',\n};\n","/*\n * Public API Surface of praxis-cron-builder\n */\n\nexport * from './lib/pdx-cron-builder.component';\nexport * from './lib/pdx-cron-builder.metadata';\n// Note: runtime cron libraries are loaded dynamically inside the component to\n// avoid build-time type resolution issues with ng-packagr.\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA;AACA,IAAI,cAA+B;AACnC,IAAI,UAA2B;AAC/B,IAAI,WAA4B;MA8FnB,uBAAuB,CAAA;;AAIjB,IAAA,EAAE,GAAG,MAAM,CAAC,sBAAsB,CAAC;AACnC,IAAA,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;AAC7B,IAAA,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC;AAEtC,IAAA,QAAQ,GAAwB;AACvC,QAAA,IAAI,EAAE,MAAM;AACZ,QAAA,MAAM,EAAE;AACN,YAAA,OAAO,EAAE,KAAK;AACd,YAAA,OAAO,EAAE,IAAI;AACb,YAAA,KAAK,EAAE,IAAI;AACX,YAAA,GAAG,EAAE,IAAI;AACT,YAAA,KAAK,EAAE,IAAI;AACX,YAAA,GAAG,EAAE,IAAI;AACV,SAAA;AACD,QAAA,OAAO,EAAE;AACP,YAAA,EAAE,KAAK,EAAE,0BAA0B,EAAE,IAAI,EAAE,WAAW,EAAE;AACxD,YAAA,EAAE,KAAK,EAAE,+BAA+B,EAAE,IAAI,EAAE,aAAa,EAAE;AAC/D,YAAA,EAAE,KAAK,EAAE,+BAA+B,EAAE,IAAI,EAAE,WAAW,EAAE;AAC7D,YAAA,EAAE,KAAK,EAAE,0CAA0C,EAAE,IAAI,EAAE,WAAW,EAAE;AACzE,SAAA;AACD,QAAA,kBAAkB,EAAE,CAAC;KACtB;IAED,KAAK,GAA+B,IAAI;IACxC,UAAU,GAAG,KAAK;IAClB,SAAS,GAA0B,QAAQ;IAC3C,gBAAgB,GAAG,CAAC;AAEX,IAAA,IAAI;AACJ,IAAA,UAAU;AACV,IAAA,eAAe,GAAG,IAAI,WAAW,CAAS,KAAK,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;AAC/D,IAAA,QAAQ,GAAG,IAAI,OAAO,EAAQ;IAE/C,SAAS,GAAG,EAAE;IACd,OAAO,GAAW,EAAE;IACpB,KAAK,GAAkB,IAAI;;AAGlB,IAAA,aAAa,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAU;AAC1E,IAAA,gBAAgB,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAU;AACjD,IAAA,eAAe,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAU;AAC1C,IAAA,aAAa,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAU;IAC9C,eAAe,GAAG,CAAC,KAAK,EAAE,mBAAmB,EAAE,eAAe,EAAE,kBAAkB,CAAU;AAErG,IAAA,WAAA,GAAA;QACE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC;YACxB,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;YAC7B,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;YAC7B,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;YAC3B,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;YAChC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;YAC3B,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;AAChC,SAAA,CAAC;QAEF,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC;YAC9B,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAA8E,eAAe,CAAC;YACnH,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;YAC1B,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;YACnC,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAW,EAAE,CAAC;YACzC,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;YACpC,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;YAC9B,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;YACrC,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;YACvB,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;YAC1B,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;AAClC,SAAA,CAAC;;;AAIJ,IAAA,IAAI,cAAc,GAAA;AAChB,QAAA,OAAQ,IAAI,CAAC,UAAkB,CAAC,QAAuC;;IAGzE,QAAQ,GAAA;QACN,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,QAAQ,EAAE;AACnC,YAAA,IAAI,CAAC,SAAS,GAAG,QAAQ;AACzB,YAAA,IAAI,CAAC,gBAAgB,GAAG,CAAC;;aACpB,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,UAAU,EAAE;AAC5C,YAAA,IAAI,CAAC,SAAS,GAAG,UAAU;AAC3B,YAAA,IAAI,CAAC,gBAAgB,GAAG,CAAC;;QAG3B,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,KAA4B,KAAI;YAC/F,MAAM,IAAI,GAAG,IAAI,CAAC,mBAAmB,CAAC,KAA8B,CAAC;AACrE,YAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;AACxB,SAAC,CAAC;QAEF,IAAI,CAAC,UAAU,CAAC;AACb,aAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC;AAC7B,aAAA,SAAS,CAAC,CAAC,KAA0B,KAAI;YACxC,MAAM,IAAI,GAAG,IAAI,CAAC,mBAAmB,CAAC,KAA4B,CAAC;AACnE,YAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;AACxB,SAAC,CAAC;AAEJ,QAAA,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,IAAI,KAAK,EAAE;AAC7D,YAAA,SAAS,EAAE,KAAK;AACjB,SAAA,CAAC;QACF,IAAI,CAAC,eAAe,CAAC;AAClB,aAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC;AAC7B,aAAA,SAAS,CAAC,CAAC,EAAE,KAAI;YAChB,IAAI,CAAC,QAAQ,CAAC,QAAQ,GAAG,EAAE,IAAI,KAAK;AACpC,YAAA,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE;AAClC,gBAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC;;AAEpC,SAAC,CAAC;;AAGN,IAAA,QAAQ,GAAyB,MAAK,GAAG;AACzC,IAAA,SAAS,GAAe,MAAK,GAAG;AAEhC,IAAA,UAAU,CAAC,KAAiC,EAAA;AAC1C,QAAA,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AAC7B,YAAA,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC;AAC9B,YAAA,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC;AAC3B,YAAA,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC;;;AAI9B,IAAA,gBAAgB,CAAC,EAAO,EAAA;AACtB,QAAA,IAAI,CAAC,QAAQ,GAAG,EAAE;;AAGpB,IAAA,iBAAiB,CAAC,EAAO,EAAA;AACvB,QAAA,IAAI,CAAC,SAAS,GAAG,EAAE;;AAGrB,IAAA,gBAAgB,CAAE,UAAmB,EAAA;AACnC,QAAA,IAAI,CAAC,UAAU,GAAG,UAAU;QAC5B,IAAI,UAAU,EAAE;AACd,YAAA,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;AACnB,YAAA,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE;AACzB,YAAA,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE;;aACzB;AACL,YAAA,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;AAClB,YAAA,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE;AACxB,YAAA,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE;;;AAIjC,IAAA,WAAW,CAAC,KAAwB,EAAA;AAClC,QAAA,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC,KAAK;AACnC,QAAA,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,KAAK,KAAK,CAAC,GAAG,QAAQ,GAAG,UAAU;QAC1D,IAAI,CAAC,SAAS,EAAE;;AAGlB,IAAA,SAAS,CAAC,IAAY,EAAA;AACpB,QAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;AACtB,QAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;AAC1B,QAAA,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC;;AAG3B,IAAA,WAAW,CAAC,IAAY,EAAE,SAAS,GAAG,IAAI,EAAA;AACxC,QAAA,IAAI,CAAC,KAAK,GAAG,IAAI;QACjB,IAAI,SAAS,EAAE;AACb,YAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;;AAErB,QAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;AACnB,QAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;AACnB,QAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;;IAG5B,QAAQ,GAAA;AACN,QAAA,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE;YAClC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;YAC/B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,wBAAwB,EAAE,SAAS,EAAE;AACtD,gBAAA,QAAQ,EAAE,IAAI;AACf,aAAA,CAAC;;;IAIN,aAAa,GAAA;AACX,QAAA,IAAI,IAAI,CAAC,SAAS,EAAE;YAClB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;AACnC,YAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,oBAAoB,EAAE,SAAS,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;;IAI3E,UAAU,GAAA;AACR,QAAA,MAAM,IAAI,GAAG,MAAM,CAAC,uBAAuB,CAAC;QAC5C,IAAI,IAAI,EAAE;AACR,YAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;AACtB,YAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;AAC1B,YAAA,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC;;;AAIrB,IAAA,QAAQ,CAAC,IAAY,EAAA;QAC3B,CAAC,YAAW;AACV,YAAA,IAAI;gBACF,cAAc,GAAG,cAAc,KAAK,MAAM,OAAO,gBAAgB,CAAC,CAAC;gBACnE,MAAM,EAAE,GAAG,MAAM,cAAc,CAAC,WAAW,GAAG,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;gBACzF,IAAI,CAAC,KAAK,GAAG;AACX,sBAAE;sBACA,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,kBAAkB,IAAI,yBAAyB;;AAC7E,YAAA,MAAM;;AAEN,gBAAA,IAAI,CAAC,KAAK,GAAG,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,yBAAyB;;SAEnF,GAAG;;AAGE,IAAA,QAAQ,CAAC,IAAY,EAAA;AAC3B,QAAA,IAAI,IAAI,CAAC,KAAK,EAAE;AACd,YAAA,IAAI,CAAC,SAAS,GAAG,EAAE;YACnB;;QAEF,CAAC,YAAW;AACV,YAAA,IAAI;gBACF,UAAU,GAAG,UAAU,KAAK,MAAM,OAAO,WAAW,CAAC,CAAC;gBACtD,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,QAAQ,GAAG,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;;AACpF,YAAA,MAAM;AACN,gBAAA,IAAI,CAAC,SAAS,GAAG,EAAE;;SAEtB,GAAG;;AAGE,IAAA,eAAe,CAAC,IAAY,EAAA;QAClC,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,kBAAkB,EAAE;AACnD,YAAA,IAAI,CAAC,OAAO,GAAG,EAAE;YACjB;;QAEF,CAAC,YAAW;AACV,YAAA,IAAI;gBACF,WAAW,GAAG,WAAW,KAAK,MAAM,OAAO,aAAa,CAAC,CAAC;gBAC1D,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,IAAI,WAAW,CAAC,OAAO,EAAE,KAAK;AAC7D,gBAAA,MAAM,QAAQ,GAAG,KAAK,GAAG,IAAI,EAAE;oBAC7B,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,IAAI,IAAI,IAAI,EAAE;AACpD,oBAAA,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ;AACpB,iBAAA,CAAC;gBACT,MAAM,IAAI,GAAW,EAAE;gBACvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,kBAAkB,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;oBAChE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;;AAErC,gBAAA,IAAI,CAAC,OAAO,GAAG,IAAI;;AACnB,YAAA,MAAM;AACN,gBAAA,IAAI,CAAC,OAAO,GAAG,EAAE;;SAEpB,GAAG;;AAGE,IAAA,eAAe,CAAC,IAAY,EAAA;QAClC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC;AACtC,QAAA,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE;QAEtB,IAAI,OAAO,GAAG,GAAG;AACjB,QAAA,IAAI,OAAe;AACnB,QAAA,IAAI,KAAa;AACjB,QAAA,IAAI,UAAkB;AACtB,QAAA,IAAI,KAAa;AACjB,QAAA,IAAI,SAAiB;AAErB,QAAA,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;AACtB,YAAA,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,CAAC,GAAG,KAAK;;aAC1D;AACL,YAAA,CAAC,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,CAAC,GAAG,KAAK;;AAGxD,QAAA,IAAI,CAAC,IAAI,CAAC,UAAU,CAClB;AACE,YAAA,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,GAAG,GAAG;YACtD,OAAO,EAAE,OAAO,IAAI,GAAG;YACvB,KAAK,EAAE,KAAK,IAAI,GAAG;YACnB,UAAU,EAAE,UAAU,IAAI,GAAG;YAC7B,KAAK,EAAE,KAAK,IAAI,GAAG;YACnB,SAAS,EAAE,SAAS,IAAI,GAAG;AAC5B,SAAA,EACD,EAAE,SAAS,EAAE,KAAK,EAAE,CACrB;;AAGK,IAAA,cAAc,CAAC,IAAY,EAAA;QACjC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC;AACtC,QAAA,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE;AACtB,QAAA,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;YACtB,KAAK,CAAC,KAAK,EAAE;;AAEf,QAAA,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,GAAG,KAAK;AAE/C,QAAA,IACE,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;AACxB,YAAA,KAAK,KAAK,GAAG;AACb,YAAA,GAAG,KAAK,GAAG;AACX,YAAA,KAAK,KAAK,GAAG;YACb,GAAG,KAAK,GAAG,EACX;AACA,YAAA,IAAI,CAAC,UAAU,CAAC,UAAU,CACxB,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EACjE,EAAE,SAAS,EAAE,KAAK,EAAE,CACrB;;AACI,aAAA,IAAI,GAAG,KAAK,GAAG,IAAI,KAAK,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,EAAE;AACtD,YAAA,IAAI,CAAC,UAAU,CAAC,UAAU,CACxB,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,EAC3D,EAAE,SAAS,EAAE,KAAK,EAAE,CACrB;;aACI,IAAI,GAAG,KAAK,GAAG,IAAI,KAAK,KAAK,GAAG,EAAE;AACvC,YAAA,IAAI,CAAC,UAAU,CAAC,UAAU,CACxB;AACE,gBAAA,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC;AACvC,gBAAA,UAAU,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC1C,aAAA,EACD,EAAE,SAAS,EAAE,KAAK,EAAE,CACrB;;aACI,IAAI,KAAK,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,EAAE;AACvC,YAAA,IAAI,CAAC,UAAU,CAAC,UAAU,CACxB;AACE,gBAAA,IAAI,EAAE,YAAY;gBAClB,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC;gBACxC,UAAU,EAAE,CAAC,GAAG;AACjB,aAAA,EACD,EAAE,SAAS,EAAE,KAAK,EAAE,CACrB;;aACI,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;AAC3C,YAAA,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC;AACjC,YAAA,IAAI,CAAC,UAAU,CAAC,UAAU,CACxB;AACE,gBAAA,IAAI,EAAE,mBAAmB;gBACzB,GAAG,EAAE,CAAC,GAAG;gBACT,MAAM,EAAE,CAAC,GAAG;gBACZ,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC;AACrC,aAAA,EACD,EAAE,SAAS,EAAE,KAAK,EAAE,CACrB;;;AAIG,IAAA,mBAAmB,CAAC,CAAsB,EAAA;AAChD,QAAA,IAAI,IAAY;AAChB,QAAA,QAAQ,CAAC,CAAC,IAAI;AACZ,YAAA,KAAK,eAAe;gBAClB,IAAI,GAAG,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,UAAU;gBACnC;YACF,KAAK,SAAS,EAAE;AACd,gBAAA,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1C,gBAAA,IAAI,GAAG,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,CAAC,QAAQ;gBACxB;;YAEF,KAAK,QAAQ,EAAE;AACb,gBAAA,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC;AAC3C,gBAAA,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,UAAU,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG;gBACzD,IAAI,GAAG,GAAG,CAAC,CAAA,CAAA,EAAI,CAAC,CAAA,KAAA,EAAQ,IAAI,EAAE;gBAC9B;;YAEF,KAAK,YAAY,EAAE;AACjB,gBAAA,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC;AAC5C,gBAAA,IAAI,GAAG,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA,EAAI,CAAC,CAAC,UAAU,IAAI,CAAC,CAAA,IAAA,CAAM;gBAC3C;;YAEF,KAAK,mBAAmB,EAAE;AACxB,gBAAA,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;AACxC,gBAAA,IAAI,GAAG,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA,KAAA,EAAQ,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE;gBACrD;;AAEF,YAAA;gBACE,IAAI,GAAG,WAAW;;AAEtB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,KAAK,IAAI,CAAA,CAAE,GAAG,IAAI;;AAGnD,IAAA,SAAS,CAAC,IAAY,EAAA;QAC5B,IAAI,CAAC,IAAI,EAAE;AACT,YAAA,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;;QAEf,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1D,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;;IAGjB,MAAM,CAAC,CAAS,EAAE,CAAS,EAAA;QACjC,OAAO,CAAA,EAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA,CAAE;;AAG5D,IAAA,GAAG,CAAC,CAAS,EAAA;QACnB,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC;;AAG9B,IAAA,mBAAmB,CAAC,KAA4B,EAAA;AACtD,QAAA,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,KAAK;QACvE,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE;YACjC,OAAO,CAAA,EAAG,OAAO,IAAI,GAAG,CAAA,CAAA,EAAI,OAAO,IAAI,GAAG,CAAA,CAAA,EAAI,KAAK,IAAI,GAAG,IAAI,UAAU,IAAI,GAAG,CAAA,CAAA,EAAI,KAAK,IAAI,GAAG,CAAA,CAAA,EAAI,SAAS,IAAI,GAAG,CAAA,CAAE;;QAEvH,OAAO,CAAA,EAAG,OAAO,IAAI,GAAG,IAAI,KAAK,IAAI,GAAG,CAAA,CAAA,EAAI,UAAU,IAAI,GAAG,CAAA,CAAA,EAAI,KAAK,IAAI,GAAG,IAAI,SAAS,IAAI,GAAG,CAAA,CAAE;;IAGrG,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE;AACpB,QAAA,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE;;uGArYf,uBAAuB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAvB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,uBAAuB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,kBAAA,EAAA,MAAA,EAAA,EAAA,QAAA,EAAA,UAAA,EAAA,EAAA,SAAA,EATvB;AACT,YAAA;AACE,gBAAA,OAAO,EAAE,iBAAiB;AAC1B,gBAAA,WAAW,EAAE,UAAU,CAAC,MAAM,uBAAuB,CAAC;AACtD,gBAAA,KAAK,EAAE,IAAI;AACZ,aAAA;AACF,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EC1HH,ktQAwPA,EAAA,MAAA,EAAA,CAAA,0XAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDvJI,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACZ,mBAAmB,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,8MAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,mBAAA,EAAA,QAAA,EAAA,iGAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,2CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,0FAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,YAAA,EAAA,QAAA,EAAA,gHAAA,EAAA,MAAA,EAAA,CAAA,KAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,YAAA,EAAA,QAAA,EAAA,gHAAA,EAAA,MAAA,EAAA,CAAA,KAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,CAAA,aAAA,EAAA,UAAA,EAAA,SAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,QAAA,EAAA,CAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,kBAAA,EAAA,QAAA,EAAA,aAAA,EAAA,MAAA,EAAA,CAAA,WAAA,CAAA,EAAA,OAAA,EAAA,CAAA,UAAA,CAAA,EAAA,QAAA,EAAA,CAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,CAAA,iBAAA,EAAA,UAAA,EAAA,SAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACnB,aAAa,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,QAAA,EAAA,SAAA,EAAA,MAAA,EAAA,CAAA,UAAA,EAAA,OAAA,EAAA,YAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,WAAA,EAAA,IAAA,CAAA,EAAA,QAAA,EAAA,CAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,WAAA,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,oBAAA,EAAA,kBAAA,EAAA,gBAAA,EAAA,eAAA,EAAA,eAAA,EAAA,gBAAA,EAAA,mBAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,iBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,qBAAA,EAAA,aAAA,EAAA,eAAA,EAAA,mBAAA,CAAA,EAAA,QAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACb,cAAc,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACd,eAAe,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,YAAA,EAAA,QAAA,EAAA,gBAAA,EAAA,MAAA,EAAA,CAAA,oBAAA,EAAA,OAAA,EAAA,YAAA,EAAA,YAAA,EAAA,iBAAA,EAAA,WAAA,CAAA,EAAA,QAAA,EAAA,CAAA,cAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,QAAA,EAAA,QAAA,EAAA,WAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,SAAA,EAAA,QAAA,EAAA,+CAAA,EAAA,MAAA,EAAA,CAAA,eAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,SAAA,EAAA,QAAA,EAAA,YAAA,EAAA,MAAA,EAAA,CAAA,kBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,eAAA,EAAA,UAAA,EAAA,8BAAA,EAAA,aAAA,EAAA,UAAA,EAAA,UAAA,EAAA,wBAAA,EAAA,aAAA,EAAA,OAAA,EAAA,YAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,2BAAA,EAAA,gBAAA,EAAA,IAAA,EAAA,YAAA,EAAA,0BAAA,CAAA,EAAA,OAAA,EAAA,CAAA,cAAA,EAAA,QAAA,EAAA,QAAA,EAAA,iBAAA,EAAA,aAAA,CAAA,EAAA,QAAA,EAAA,CAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,SAAA,EAAA,QAAA,EAAA,YAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,IAAA,EAAA,UAAA,CAAA,EAAA,OAAA,EAAA,CAAA,mBAAA,CAAA,EAAA,QAAA,EAAA,CAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACf,cAAc,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,QAAA,EAAA,QAAA,EAAA,yHAAA,EAAA,MAAA,EAAA,CAAA,UAAA,EAAA,IAAA,EAAA,aAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,mBAAA,EAAA,kBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,qBAAA,CAAA,EAAA,QAAA,EAAA,CAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACd,kBAAkB,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAClB,aAAa,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,WAAA,EAAA,QAAA,EAAA,wDAAA,EAAA,MAAA,EAAA,CAAA,WAAA,CAAA,EAAA,QAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACb,eAAe,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,SAAA,EAAA,QAAA,EAAA,iOAAA,EAAA,MAAA,EAAA,CAAA,WAAA,CAAA,EAAA,QAAA,EAAA,CAAA,WAAA,EAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,aAAA,EAAA,QAAA,EAAA,sFAAA,EAAA,QAAA,EAAA,CAAA,WAAA,EAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACf,aAAa,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,UAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,SAAA,EAAA,SAAA,EAAA,UAAA,CAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACb,gBAAgB,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,UAAA,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,EAAA,CAAA,oBAAA,EAAA,4BAAA,EAAA,oBAAA,EAAA,qBAAA,EAAA,qBAAA,EAAA,yBAAA,EAAA,YAAA,EAAA,iBAAA,CAAA,EAAA,QAAA,EAAA,CAAA,YAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAChB,eAAe,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,SAAA,EAAA,QAAA,EAAA,YAAA,EAAA,MAAA,EAAA,CAAA,UAAA,EAAA,UAAA,EAAA,eAAA,EAAA,KAAA,EAAA,OAAA,EAAA,eAAA,EAAA,KAAA,EAAA,MAAA,EAAA,aAAA,CAAA,EAAA,QAAA,EAAA,CAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACf,cAAc,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,GAAA,CAAA,cAAA,EAAA,QAAA,EAAA,kBAAA,EAAA,MAAA,EAAA,CAAA,UAAA,EAAA,kBAAA,EAAA,YAAA,EAAA,aAAA,EAAA,UAAA,EAAA,8BAAA,EAAA,OAAA,CAAA,EAAA,OAAA,EAAA,CAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,GAAA,CAAA,aAAA,EAAA,QAAA,EAAA,oFAAA,EAAA,MAAA,EAAA,CAAA,YAAA,EAAA,UAAA,CAAA,EAAA,OAAA,EAAA,CAAA,iBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACd,iBAAiB,+BACjB,mBAAmB,EAAA,QAAA,EAAA,sBAAA,EAAA,MAAA,EAAA,CAAA,YAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA,GAAA,CAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAcV,uBAAuB,EAAA,UAAA,EAAA,CAAA;kBAhCnC,SAAS;+BACE,kBAAkB,EAAA,UAAA,EAChB,IAAI,EAAA,OAAA,EACP;wBACP,YAAY;wBACZ,mBAAmB;wBACnB,aAAa;wBACb,cAAc;wBACd,eAAe;wBACf,cAAc;wBACd,kBAAkB;wBAClB,aAAa;wBACb,eAAe;wBACf,aAAa;wBACb,gBAAgB;wBAChB,eAAe;wBACf,cAAc;wBACd,iBAAiB;wBACjB,mBAAmB;qBACpB,EAAA,eAAA,EAGgB,uBAAuB,CAAC,MAAM,EAAA,SAAA,EACpC;AACT,wBAAA;AACE,4BAAA,OAAO,EAAE,iBAAiB;AAC1B,4BAAA,WAAW,EAAE,UAAU,CAAC,6BAA6B,CAAC;AACtD,4BAAA,KAAK,EAAE,IAAI;AACZ,yBAAA;AACF,qBAAA,EAAA,QAAA,EAAA,ktQAAA,EAAA,MAAA,EAAA,CAAA,0XAAA,CAAA,EAAA;wDAWQ,QAAQ,EAAA,CAAA;sBAAhB;;;AEnIH;AACO,MAAM,mCAAmC,GAAQ;AACtD,IAAA,EAAE,EAAE,kBAAkB;AACtB,IAAA,QAAQ,EAAE,kBAAkB;AAC5B,IAAA,SAAS,EAAE,uBAAuB;AAClC,IAAA,YAAY,EAAE,gBAAgB;AAC9B,IAAA,WAAW,EAAE,6DAA6D;AAC1E,IAAA,IAAI,EAAE,UAAU;AAChB,IAAA,MAAM,EAAE;QACN,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,iBAAiB,EAAE;QACjE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,gBAAgB,EAAE;QAC/D,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,wCAAwC,EAAE,WAAW,EAAE,8BAA8B,EAAE;AAChH,QAAA,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,mCAAmC,EAAE,OAAO,EAAE,KAAK,EAAE;QAC5G,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,8CAA8C,EAAE;AAC/F,KAAA;AACD,IAAA,OAAO,EAAE;QACP,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oCAAoC,EAAE;AAC3F,KAAA;IACD,IAAI,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC;AAC7C,IAAA,GAAG,EAAE,wBAAwB;;;ACrB/B;;AAEG;AAIH;AACA;;ACPA;;AAEG;;;;"}
package/index.d.ts ADDED
@@ -0,0 +1,111 @@
1
+ import * as i0 from '@angular/core';
2
+ import { OnInit, OnDestroy } from '@angular/core';
3
+ import { ControlValueAccessor, FormGroup, FormControl } from '@angular/forms';
4
+ import { MatTabChangeEvent } from '@angular/material/tabs';
5
+
6
+ interface Recurrence {
7
+ }
8
+ interface CronBuilderMetadata {
9
+ mode?: 'simple' | 'advanced' | 'both';
10
+ fields?: {
11
+ seconds?: boolean;
12
+ minutes?: boolean;
13
+ hours?: boolean;
14
+ dom?: boolean;
15
+ month?: boolean;
16
+ dow?: boolean;
17
+ };
18
+ timezone?: string;
19
+ locale?: string;
20
+ presets?: Array<{
21
+ label: string;
22
+ cron: string;
23
+ }>;
24
+ previewOccurrences?: number;
25
+ previewFrom?: Date;
26
+ validators?: {
27
+ requiredMessage?: string;
28
+ invalidCronMessage?: string;
29
+ };
30
+ validationTrigger?: 'change' | 'blur';
31
+ validationDebounce?: number;
32
+ errorPosition?: 'tooltip' | 'inline';
33
+ showInlineErrors?: boolean;
34
+ hint?: string;
35
+ }
36
+ type CronPresetType = 'everyNMinutes' | 'dailyAt' | 'weekly' | 'monthlyDay' | 'monthlyNthWeekday';
37
+ interface SimpleCronFormValue {
38
+ type: CronPresetType;
39
+ everyN: number;
40
+ dailyTime: string;
41
+ weeklyDays: number[];
42
+ weeklyTime: string;
43
+ monthlyDay: number;
44
+ monthlyTime: string;
45
+ nth: number;
46
+ nthDay: number;
47
+ nthTime: string;
48
+ }
49
+ interface AdvancedCronFormValue {
50
+ seconds?: string;
51
+ minutes: string;
52
+ hours: string;
53
+ dayOfMonth: string;
54
+ month: string;
55
+ dayOfWeek: string;
56
+ }
57
+ declare class PdxCronBuilderComponent implements ControlValueAccessor, OnInit, OnDestroy {
58
+ private readonly fb;
59
+ private readonly clipboard;
60
+ private readonly snackBar;
61
+ metadata: CronBuilderMetadata;
62
+ value: string | Recurrence | null;
63
+ isDisabled: boolean;
64
+ activeTab: 'simple' | 'advanced';
65
+ selectedTabIndex: number;
66
+ readonly form: FormGroup;
67
+ readonly simpleForm: FormGroup;
68
+ readonly timezoneControl: FormControl<string>;
69
+ private readonly destroy$;
70
+ humanized: string;
71
+ preview: Date[];
72
+ error: string | null;
73
+ readonly weekdayLabels: readonly ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb"];
74
+ readonly weeklyDayOptions: readonly [0, 1, 2, 3, 4, 5, 6];
75
+ readonly nthOrderOptions: readonly [1, 2, 3, 4, 5];
76
+ readonly nthDayOptions: readonly [1, 2, 3, 4, 5, 6, 0];
77
+ readonly timezoneOptions: readonly ["UTC", "America/Sao_Paulo", "Europe/London", "America/New_York"];
78
+ constructor();
79
+ get simpleControls(): Record<string, FormControl>;
80
+ ngOnInit(): void;
81
+ onChange: (value: any) => void;
82
+ onTouched: () => void;
83
+ writeValue(value: string | Recurrence | null): void;
84
+ registerOnChange(fn: any): void;
85
+ registerOnTouched(fn: any): void;
86
+ setDisabledState?(isDisabled: boolean): void;
87
+ onTabChange(event: MatTabChangeEvent): void;
88
+ setPreset(cron: string): void;
89
+ updateValue(cron: string, emitEvent?: boolean): void;
90
+ copyCron(): void;
91
+ copyHumanized(): void;
92
+ importCron(): void;
93
+ private validate;
94
+ private humanize;
95
+ private generatePreview;
96
+ private parseCronString;
97
+ private syncSimpleForm;
98
+ private buildCronFromSimple;
99
+ private parseTime;
100
+ private toTime;
101
+ private pad;
102
+ private constructCronString;
103
+ ngOnDestroy(): void;
104
+ static ɵfac: i0.ɵɵFactoryDeclaration<PdxCronBuilderComponent, never>;
105
+ static ɵcmp: i0.ɵɵComponentDeclaration<PdxCronBuilderComponent, "pdx-cron-builder", never, { "metadata": { "alias": "metadata"; "required": false; }; }, {}, never, never, true, never>;
106
+ }
107
+
108
+ declare const PDX_CRON_BUILDER_COMPONENT_METADATA: any;
109
+
110
+ export { PDX_CRON_BUILDER_COMPONENT_METADATA, PdxCronBuilderComponent };
111
+ export type { AdvancedCronFormValue, CronBuilderMetadata, CronPresetType, Recurrence, SimpleCronFormValue };
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@praxisui/cron-builder",
3
+ "version": "0.0.1",
4
+ "peerDependencies": {
5
+ "@angular/common": "^20.1.0",
6
+ "@angular/core": "^20.1.0",
7
+ "@angular/forms": "^20.1.0",
8
+ "@angular/cdk": "^20.1.0",
9
+ "@angular/material": "^20.1.0",
10
+ "@praxisui/core": "^0.0.1"
11
+ },
12
+ "dependencies": {
13
+ "tslib": "^2.3.0",
14
+ "luxon": "^3.7.1",
15
+ "cron-parser": "^5.3.0",
16
+ "cronstrue": "^3.2.0",
17
+ "cron-validator": "^1.4.0"
18
+ },
19
+ "license": "Apache-2.0",
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/codexrodrigues/praxis"
26
+ },
27
+ "homepage": "https://github.com/codexrodrigues/praxis#readme",
28
+ "bugs": {
29
+ "url": "https://github.com/codexrodrigues/praxis/issues"
30
+ },
31
+ "sideEffects": false,
32
+ "module": "fesm2022/praxisui-cron-builder.mjs",
33
+ "typings": "index.d.ts",
34
+ "exports": {
35
+ "./package.json": {
36
+ "default": "./package.json"
37
+ },
38
+ ".": {
39
+ "types": "./index.d.ts",
40
+ "default": "./fesm2022/praxisui-cron-builder.mjs"
41
+ }
42
+ }
43
+ }