@lostgradient/cinder 0.9.0 → 0.12.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.
- package/CHANGELOG.md +26 -0
- package/components.json +82 -4
- package/dist/components/access-gate/index.js +381 -239
- package/dist/components/chat/builders.d.ts +17 -8
- package/dist/components/chat/conversation-model.d.ts +1 -1
- package/dist/components/chat/index.d.ts +1 -1
- package/dist/components/chat/index.js +300 -17
- package/dist/components/chat/utilities/conversation.d.ts +6 -6
- package/dist/components/chat-conversation-header/index.js +19 -6
- package/dist/components/chat-conversation-list/index.js +19 -6
- package/dist/components/code-block/code-block.css +15 -9
- package/dist/components/code-block/code-block.variables.js +8 -2
- package/dist/components/confirm-dialog/confirm-dialog.css +2 -0
- package/dist/components/confirm-dialog/confirm-dialog.schema.js +10 -1
- package/dist/components/confirm-dialog/confirm-dialog.types.d.ts +7 -0
- package/dist/components/confirm-dialog/index.js +478 -106
- package/dist/components/connection-indicator/connection-indicator.css +136 -0
- package/dist/components/connection-indicator/connection-indicator.css.d.ts +1 -0
- package/dist/components/connection-indicator/connection-indicator.schema.d.ts +3 -0
- package/dist/components/connection-indicator/connection-indicator.schema.js +89 -0
- package/dist/components/connection-indicator/connection-indicator.svelte.d.ts +21 -0
- package/dist/components/connection-indicator/connection-indicator.types.d.ts +46 -0
- package/dist/components/connection-indicator/connection-indicator.variables.d.ts +2 -0
- package/dist/components/connection-indicator/connection-indicator.variables.js +61 -0
- package/dist/components/connection-indicator/index.d.ts +5 -0
- package/dist/components/connection-indicator/index.js +409 -0
- package/dist/components/container/container.schema.js +4 -4
- package/dist/components/faceted-filter-bar/faceted-filter-bar.schema.js +5 -1
- package/dist/components/faceted-filter-bar/faceted-filter-bar.types.d.ts +2 -0
- package/dist/components/faceted-filter-bar/index.js +40 -31
- package/dist/components/invocation-rule-builder/index.d.ts +1 -1
- package/dist/components/invocation-rule-builder/index.js +305 -150
- package/dist/components/invocation-rule-builder/invocation-rule-builder.css +28 -0
- package/dist/components/invocation-rule-builder/invocation-rule-builder.schema.js +89 -5
- package/dist/components/invocation-rule-builder/invocation-rule-builder.svelte.d.ts +2 -1
- package/dist/components/invocation-rule-builder/invocation-rule-builder.types.d.ts +114 -16
- package/dist/components/navigation-bar/index.js +11 -17
- package/dist/components/run-step-timeline/index.d.ts +1 -1
- package/dist/components/run-step-timeline/index.js +1052 -560
- package/dist/components/run-step-timeline/run-step-branch-disclosure.svelte.d.ts +17 -0
- package/dist/components/run-step-timeline/run-step-timeline.css +124 -0
- package/dist/components/run-step-timeline/run-step-timeline.schema.js +873 -350
- package/dist/components/run-step-timeline/run-step-timeline.svelte.d.ts +1 -15
- package/dist/components/run-step-timeline/run-step-timeline.types.d.ts +182 -5
- package/dist/components/run-step-timeline/run-step-timeline.utilities.d.ts +60 -0
- package/dist/components/schedule-builder/index.d.ts +5 -0
- package/dist/components/schedule-builder/index.js +3176 -0
- package/dist/components/schedule-builder/schedule-builder.css +121 -0
- package/dist/components/schedule-builder/schedule-builder.css.d.ts +1 -0
- package/dist/components/schedule-builder/schedule-builder.schema.d.ts +3 -0
- package/dist/components/schedule-builder/schedule-builder.schema.js +141 -0
- package/dist/components/schedule-builder/schedule-builder.svelte.d.ts +22 -0
- package/dist/components/schedule-builder/schedule-builder.types.d.ts +130 -0
- package/dist/components/schedule-builder/schedule-builder.utilities.d.ts +78 -0
- package/dist/components/schedule-builder/schedule-builder.variables.d.ts +2 -0
- package/dist/components/schedule-builder/schedule-builder.variables.js +61 -0
- package/dist/components/tag-input/index.js +22 -4
- package/dist/components/tag-input/tag-input.schema.js +5 -1
- package/dist/components/tag-input/tag-input.types.d.ts +4 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +23069 -20833
- package/dist/server/components/access-gate/index.js +2 -1
- package/dist/server/components/chat/index.js +4 -4
- package/dist/server/components/chat-conversation-header/index.js +5 -5
- package/dist/server/components/chat-conversation-list/index.js +3 -3
- package/dist/server/components/color-field/index.js +2 -2
- package/dist/server/components/confirm-dialog/index.js +7 -2
- package/dist/server/components/connection-indicator/index.js +16 -0
- package/dist/server/components/data-table/index.js +3 -3
- package/dist/server/components/diff-viewer/index.js +4 -3
- package/dist/server/components/faceted-filter-bar/index.js +1 -1
- package/dist/server/components/invocation-rule-builder/index.js +1 -1
- package/dist/server/components/json-schema-editor/index.js +4 -3
- package/dist/server/components/navigation-bar/index.js +1 -1
- package/dist/server/components/review-editor/index.js +4 -3
- package/dist/server/components/run-step-timeline/index.js +1 -1
- package/dist/server/components/schedule-builder/index.js +30 -0
- package/dist/server/components/side-navigation/index.js +2 -2
- package/dist/server/components/table/index.js +3 -3
- package/dist/server/components/tag-input/index.js +1 -1
- package/dist/server/components/time-field/index.js +5 -3
- package/dist/server/index.js +105 -92
- package/dist/server/index.server-0sx92swg.js +9 -0
- package/dist/server/{index.server-mzzb7dnm.js → index.server-2bbwajb2.js} +1 -1
- package/dist/server/{index.server-q7w4jw89.js → index.server-2s5h1d05.js} +2 -2
- package/dist/server/{index.server-dg83ke3k.js → index.server-2zdbz3rj.js} +1 -1
- package/dist/server/{index.server-0jhra85x.js → index.server-3w72dxz7.js} +4 -4
- package/dist/server/{index.server-5tf22d6e.js → index.server-4wx0qven.js} +3 -3
- package/dist/server/{index.server-qh9qzd5t.js → index.server-4x4hgvqe.js} +283 -13
- package/dist/server/{index.server-c6pe4kaf.js → index.server-5gzyqv78.js} +1 -1
- package/dist/server/{index.server-mqt1ngqw.js → index.server-6hnfzc7f.js} +19 -6
- package/dist/server/{index.server-894t97kv.js → index.server-7yvpb6z7.js} +4 -4
- package/dist/server/index.server-be9bpqeh.js +93 -0
- package/dist/server/{index.server-f3z7tpxr.js → index.server-c42b462p.js} +2 -4
- package/dist/server/{index.server-7vyzen5x.js → index.server-c5qv3p61.js} +171 -63
- package/dist/server/index.server-cch0eed5.js +144 -0
- package/dist/server/{index.server-btgb3d56.js → index.server-d5a5ccz7.js} +18 -12
- package/dist/server/index.server-g5jgq3jp.js +793 -0
- package/dist/server/index.server-gmh5ar16.js +2 -0
- package/dist/server/{index.server-0atyznp7.js → index.server-h89zk5ev.js} +7 -7
- package/dist/server/{index.server-jxg42jpz.js → index.server-jdcq5zza.js} +7 -7
- package/dist/server/{index.server-2dga5yzr.js → index.server-jfrssta6.js} +1 -1
- package/dist/server/{index.server-fy068yne.js → index.server-jj76374p.js} +1 -1
- package/dist/server/{index.server-39ne5cd1.js → index.server-pxq277t5.js} +32 -1
- package/dist/server/index.server-qbkxz7r2.js +750 -0
- package/dist/server/{index.server-marjz8ps.js → index.server-tcay903b.js} +3 -2
- package/dist/server/{index.server-yz4k36cw.js → index.server-z7hxtqs1.js} +1 -1
- package/package.json +87 -97
- package/src/components/chat/builders.ts +445 -14
- package/src/components/chat/conversation-model.ts +1 -0
- package/src/components/chat/index.ts +1 -0
- package/src/components/chat/utilities/conversation.ts +33 -15
- package/src/components/code-block/code-block.css +15 -9
- package/src/components/code-block/code-block.variables.json +7 -1
- package/src/components/code-block/code-block.variables.ts +7 -1
- package/src/components/confirm-dialog/confirm-dialog.css +2 -0
- package/src/components/confirm-dialog/confirm-dialog.schema.json +8 -0
- package/src/components/confirm-dialog/confirm-dialog.schema.ts +10 -0
- package/src/components/confirm-dialog/confirm-dialog.svelte +31 -3
- package/src/components/confirm-dialog/confirm-dialog.types.ts +7 -0
- package/src/components/connection-indicator/connection-indicator.css +136 -0
- package/src/components/connection-indicator/connection-indicator.examples.json +31 -0
- package/src/components/connection-indicator/connection-indicator.schema.json +29 -0
- package/src/components/connection-indicator/connection-indicator.schema.ts +36 -0
- package/src/components/connection-indicator/connection-indicator.svelte +63 -0
- package/src/components/connection-indicator/connection-indicator.types.ts +58 -0
- package/src/components/connection-indicator/connection-indicator.variables.json +1 -0
- package/src/components/connection-indicator/connection-indicator.variables.ts +3 -0
- package/src/components/connection-indicator/index.ts +10 -0
- package/src/components/container/container.schema.json +3 -3
- package/src/components/container/container.schema.ts +3 -3
- package/src/components/faceted-filter-bar/faceted-filter-bar.schema.json +4 -0
- package/src/components/faceted-filter-bar/faceted-filter-bar.schema.ts +4 -0
- package/src/components/faceted-filter-bar/faceted-filter-bar.svelte +13 -11
- package/src/components/faceted-filter-bar/faceted-filter-bar.types.ts +2 -0
- package/src/components/invocation-rule-builder/index.ts +4 -0
- package/src/components/invocation-rule-builder/invocation-rule-builder.css +28 -0
- package/src/components/invocation-rule-builder/invocation-rule-builder.examples.json +6 -0
- package/src/components/invocation-rule-builder/invocation-rule-builder.schema.json +76 -3
- package/src/components/invocation-rule-builder/invocation-rule-builder.schema.ts +83 -3
- package/src/components/invocation-rule-builder/invocation-rule-builder.svelte +326 -113
- package/src/components/invocation-rule-builder/invocation-rule-builder.types.ts +157 -43
- package/src/components/navigation-bar/navigation-bar.svelte +2 -2
- package/src/components/run-step-timeline/index.ts +8 -0
- package/src/components/run-step-timeline/run-step-branch-disclosure.svelte +16 -0
- package/src/components/run-step-timeline/run-step-timeline.css +124 -0
- package/src/components/run-step-timeline/run-step-timeline.examples.json +18 -0
- package/src/components/run-step-timeline/run-step-timeline.schema.json +872 -349
- package/src/components/run-step-timeline/run-step-timeline.schema.ts +931 -349
- package/src/components/run-step-timeline/run-step-timeline.svelte +388 -269
- package/src/components/run-step-timeline/run-step-timeline.types.ts +192 -5
- package/src/components/run-step-timeline/run-step-timeline.utilities.ts +310 -0
- package/src/components/schedule-builder/index.ts +14 -0
- package/src/components/schedule-builder/schedule-builder.css +121 -0
- package/src/components/schedule-builder/schedule-builder.examples.json +31 -0
- package/src/components/schedule-builder/schedule-builder.schema.json +78 -0
- package/src/components/schedule-builder/schedule-builder.schema.ts +86 -0
- package/src/components/schedule-builder/schedule-builder.svelte +629 -0
- package/src/components/schedule-builder/schedule-builder.types.ts +137 -0
- package/src/components/schedule-builder/schedule-builder.utilities.ts +344 -0
- package/src/components/schedule-builder/schedule-builder.variables.json +1 -0
- package/src/components/schedule-builder/schedule-builder.variables.ts +3 -0
- package/src/components/tag-input/tag-input.schema.json +4 -0
- package/src/components/tag-input/tag-input.schema.ts +4 -0
- package/src/components/tag-input/tag-input.svelte +20 -3
- package/src/components/tag-input/tag-input.types.ts +4 -0
- package/src/index.ts +23 -0
- package/src/styles/components.css +2 -0
- package/dist/server/index.server-qk1h0n02.js +0 -393
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The unit for an interval recurrence.
|
|
6
|
+
*/
|
|
7
|
+
export type ScheduleIntervalUnit = 'minutes' | 'hours' | 'days' | 'weeks';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The emitted, lossless recurrence value. There are only ever TWO value
|
|
11
|
+
* variants — `cron` and `interval` — even though the UI offers a third
|
|
12
|
+
* "presets" authoring mode. Presets are sugar that lower to one of these two
|
|
13
|
+
* (e.g. "every 15 minutes" → `interval`; "daily at 09:00" → `cron`); there is
|
|
14
|
+
* no `mode: 'preset'` in the value a consumer receives.
|
|
15
|
+
*/
|
|
16
|
+
export type ScheduleValue =
|
|
17
|
+
| {
|
|
18
|
+
/** Discriminator: a 5-field cron recurrence. */
|
|
19
|
+
mode: 'cron';
|
|
20
|
+
/** The 5-field cron expression, space-separated (minute hour day-of-month month day-of-week). */
|
|
21
|
+
expression: string;
|
|
22
|
+
}
|
|
23
|
+
| {
|
|
24
|
+
/** Discriminator: a fixed-interval recurrence. */
|
|
25
|
+
mode: 'interval';
|
|
26
|
+
/** How many `unit`s between fires. A positive integer. */
|
|
27
|
+
every: number;
|
|
28
|
+
/** The interval unit. */
|
|
29
|
+
unit: ScheduleIntervalUnit;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The authoring mode surfaced in the UI's SegmentedControl. Distinct from
|
|
34
|
+
* {@link ScheduleValue}'s `mode` discriminator: `presets` is an authoring
|
|
35
|
+
* convenience that emits a `cron` or `interval` value.
|
|
36
|
+
*/
|
|
37
|
+
export type ScheduleAuthoringMode = 'presets' | 'cron' | 'interval';
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* A single computed upcoming fire, as returned by the injected
|
|
41
|
+
* {@link ScheduleBuilderProps.computeNextFires} callback. The component never
|
|
42
|
+
* computes or formats times itself (it ships no date/cron dependency): the
|
|
43
|
+
* consumer returns already-formatted display strings.
|
|
44
|
+
*/
|
|
45
|
+
export type ScheduleFire = {
|
|
46
|
+
/** Stable identity for the keyed preview list. */
|
|
47
|
+
id: string;
|
|
48
|
+
/** Human-readable label for this fire, e.g. "Mon Jun 1, 09:00". */
|
|
49
|
+
label: string;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Props for the ScheduleBuilder component.
|
|
54
|
+
*
|
|
55
|
+
* ScheduleBuilder is a presentational recurrence-definition control. It owns
|
|
56
|
+
* no scheduling execution, persistence, or date math. It is date-library-free:
|
|
57
|
+
* the "next N fires" preview is produced by the injected `computeNextFires`
|
|
58
|
+
* callback, and degrades gracefully (the preview is hidden) when the callback
|
|
59
|
+
* is absent. Scope is recurrence only — overlap policy, jitter, and backfill
|
|
60
|
+
* belong to the consumer's surrounding form.
|
|
61
|
+
*/
|
|
62
|
+
export type ScheduleBuilderProps = Omit<
|
|
63
|
+
HTMLAttributes<HTMLDivElement>,
|
|
64
|
+
'class' | 'children' | 'onchange'
|
|
65
|
+
> & {
|
|
66
|
+
/**
|
|
67
|
+
* The current recurrence value (controlled). Pass the value returned from
|
|
68
|
+
* `onchange` back in to commit an edit. When omitted, the component starts
|
|
69
|
+
* from a sensible default (`interval`, every 15 minutes).
|
|
70
|
+
*/
|
|
71
|
+
value?: ScheduleValue | undefined;
|
|
72
|
+
/**
|
|
73
|
+
* Called whenever the user edits the recurrence. Receives the next lossless
|
|
74
|
+
* {@link ScheduleValue}. The consumer owns persistence and validation.
|
|
75
|
+
*/
|
|
76
|
+
onchange?: ((value: ScheduleValue) => void) | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* Injected next-fires computation. The component passes the current value and
|
|
79
|
+
* the requested count and renders whatever fires the consumer returns. When
|
|
80
|
+
* omitted, the preview list is hidden (the component ships no date logic).
|
|
81
|
+
*/
|
|
82
|
+
computeNextFires?: ((value: ScheduleValue, count: number) => ScheduleFire[]) | undefined;
|
|
83
|
+
/**
|
|
84
|
+
* How many upcoming fires to request from `computeNextFires`. Defaults to 5.
|
|
85
|
+
*/
|
|
86
|
+
previewCount?: number | undefined;
|
|
87
|
+
/**
|
|
88
|
+
* Timezone label rendered in the always-visible timezone display slot, e.g.
|
|
89
|
+
* "America/New_York" or "UTC". Purely presentational — the component does not
|
|
90
|
+
* interpret it. When omitted, provide the `timezone` snippet instead; if
|
|
91
|
+
* neither is supplied the slot shows a "Not set" placeholder (the slot itself
|
|
92
|
+
* is always rendered).
|
|
93
|
+
*/
|
|
94
|
+
timezoneLabel?: string | undefined;
|
|
95
|
+
/**
|
|
96
|
+
* Custom content for the timezone display slot. Takes precedence over
|
|
97
|
+
* `timezoneLabel` when both are supplied.
|
|
98
|
+
*/
|
|
99
|
+
timezone?: Snippet | undefined;
|
|
100
|
+
/** Accessible label for the whole control. Defaults to "Schedule". */
|
|
101
|
+
label?: string | undefined;
|
|
102
|
+
/** Additional CSS classes applied to the root element. */
|
|
103
|
+
class?: string | undefined;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Schema-facing mirror of {@link ScheduleValue}.
|
|
108
|
+
* @schemaObject
|
|
109
|
+
*/
|
|
110
|
+
export type ScheduleValueSchema =
|
|
111
|
+
| { mode: 'cron'; expression: string }
|
|
112
|
+
| { mode: 'interval'; every: number; unit: ScheduleIntervalUnit };
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Cinder-specific schema surface for ScheduleBuilder.
|
|
116
|
+
*
|
|
117
|
+
* The `onchange`, `computeNextFires`, and `timezone` props are documented but
|
|
118
|
+
* unsupported by JSON Schema because functions and snippets cannot be modeled.
|
|
119
|
+
*/
|
|
120
|
+
export type ScheduleBuilderSchemaProps = {
|
|
121
|
+
/**
|
|
122
|
+
* The current recurrence value (controlled). When omitted, the component
|
|
123
|
+
* starts from a sensible default (`interval`, every 15 minutes).
|
|
124
|
+
* @schemaObject
|
|
125
|
+
*/
|
|
126
|
+
value?: ScheduleValueSchema | undefined;
|
|
127
|
+
/**
|
|
128
|
+
* How many upcoming fires to request from `computeNextFires`. Defaults to 5.
|
|
129
|
+
*/
|
|
130
|
+
previewCount?: number | undefined;
|
|
131
|
+
/** Timezone label rendered in the always-visible timezone display slot. */
|
|
132
|
+
timezoneLabel?: string | undefined;
|
|
133
|
+
/** Accessible label for the whole control. Defaults to "Schedule". */
|
|
134
|
+
label?: string | undefined;
|
|
135
|
+
/** Additional CSS classes applied to the root element. */
|
|
136
|
+
class?: string | undefined;
|
|
137
|
+
};
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import type { ScheduleIntervalUnit, ScheduleValue } from './schedule-builder.types.ts';
|
|
2
|
+
|
|
3
|
+
/** The interval units offered in the interval mode selector, in order. */
|
|
4
|
+
export const INTERVAL_UNITS: readonly ScheduleIntervalUnit[] = [
|
|
5
|
+
'minutes',
|
|
6
|
+
'hours',
|
|
7
|
+
'days',
|
|
8
|
+
'weeks',
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
/** Weekday chips for the weekly preset. `value` matches cron day-of-week (0 = Sunday). */
|
|
12
|
+
export const WEEKDAYS: readonly { value: number; short: string; long: string }[] = [
|
|
13
|
+
{ value: 1, short: 'Mon', long: 'Monday' },
|
|
14
|
+
{ value: 2, short: 'Tue', long: 'Tuesday' },
|
|
15
|
+
{ value: 3, short: 'Wed', long: 'Wednesday' },
|
|
16
|
+
{ value: 4, short: 'Thu', long: 'Thursday' },
|
|
17
|
+
{ value: 5, short: 'Fri', long: 'Friday' },
|
|
18
|
+
{ value: 6, short: 'Sat', long: 'Saturday' },
|
|
19
|
+
{ value: 0, short: 'Sun', long: 'Sunday' },
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
/** The five cron fields, in order, with their valid numeric ranges and hints. */
|
|
23
|
+
export const CRON_FIELDS: readonly {
|
|
24
|
+
name: string;
|
|
25
|
+
min: number;
|
|
26
|
+
max: number;
|
|
27
|
+
hint: string;
|
|
28
|
+
}[] = [
|
|
29
|
+
{ name: 'Minute', min: 0, max: 59, hint: '0–59' },
|
|
30
|
+
{ name: 'Hour', min: 0, max: 23, hint: '0–23' },
|
|
31
|
+
{ name: 'Day of month', min: 1, max: 31, hint: '1–31' },
|
|
32
|
+
{ name: 'Month', min: 1, max: 12, hint: '1–12' },
|
|
33
|
+
{ name: 'Day of week', min: 0, max: 6, hint: '0–6 (Sun–Sat)' },
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
/** The default value used when the consumer passes none. */
|
|
37
|
+
export function defaultScheduleValue(): ScheduleValue {
|
|
38
|
+
return { mode: 'interval', every: 15, unit: 'minutes' };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Singularize an interval unit for "every 1 X" phrasing. */
|
|
42
|
+
function singularUnit(unit: ScheduleIntervalUnit): string {
|
|
43
|
+
return unit.slice(0, -1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Validate a single cron field value against its field range. Accepts a
|
|
48
|
+
* wildcard, a step, a range, a comma list, or a plain number. Returns an error
|
|
49
|
+
* message when invalid, or `undefined` when the field is acceptable.
|
|
50
|
+
*/
|
|
51
|
+
export function validateCronField(rawValue: string, fieldIndex: number): string | undefined {
|
|
52
|
+
const field = CRON_FIELDS[fieldIndex];
|
|
53
|
+
if (!field) return 'Unknown field.';
|
|
54
|
+
const value = rawValue.trim();
|
|
55
|
+
if (value === '') return 'Required.';
|
|
56
|
+
|
|
57
|
+
const inRange = (n: number): boolean => Number.isInteger(n) && n >= field.min && n <= field.max;
|
|
58
|
+
|
|
59
|
+
// Comma-separated list: every part must be valid on its own.
|
|
60
|
+
for (const part of value.split(',')) {
|
|
61
|
+
const token = part.trim();
|
|
62
|
+
if (token === '') return 'Empty list item.';
|
|
63
|
+
|
|
64
|
+
// `*` or `*/step`
|
|
65
|
+
if (token === '*') continue;
|
|
66
|
+
const stepMatch = token.match(/^(\*|\d+-\d+)\/(\d+)$/);
|
|
67
|
+
if (stepMatch) {
|
|
68
|
+
const step = Number(stepMatch[2] ?? '');
|
|
69
|
+
if (!Number.isInteger(step) || step <= 0) return 'Step must be a positive integer.';
|
|
70
|
+
// A step larger than the field's maximum (e.g. `*/100` for minutes) is
|
|
71
|
+
// out of the advertised range and rejected by many cron parsers.
|
|
72
|
+
if (step > field.max) return `Step is larger than ${field.hint}.`;
|
|
73
|
+
const rangeText = stepMatch[1] ?? '*';
|
|
74
|
+
if (rangeText !== '*') {
|
|
75
|
+
const [a, b] = rangeText.split('-').map(Number);
|
|
76
|
+
if (a === undefined || b === undefined || !inRange(a) || !inRange(b)) {
|
|
77
|
+
return `Out of range (${field.hint}).`;
|
|
78
|
+
}
|
|
79
|
+
if (a > b) return 'Range start is after its end.';
|
|
80
|
+
}
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Range `a-b`
|
|
85
|
+
const rangeMatch = token.match(/^(\d+)-(\d+)$/);
|
|
86
|
+
if (rangeMatch) {
|
|
87
|
+
const a = Number(rangeMatch[1]);
|
|
88
|
+
const b = Number(rangeMatch[2]);
|
|
89
|
+
if (!inRange(a) || !inRange(b)) return `Out of range (${field.hint}).`;
|
|
90
|
+
if (a > b) return 'Range start is after its end.';
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Plain number
|
|
95
|
+
if (/^\d+$/.test(token)) {
|
|
96
|
+
if (!inRange(Number(token))) return `Out of range (${field.hint}).`;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return 'Not a valid cron token.';
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Whether all five cron fields are individually valid. */
|
|
107
|
+
export function cronFieldsValid(fields: string[]): boolean {
|
|
108
|
+
return (
|
|
109
|
+
fields.length === 5 &&
|
|
110
|
+
fields.every((value, index) => validateCronField(value, index) === undefined)
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Join five cron fields into a normalized single-space expression. */
|
|
115
|
+
export function joinCron(fields: string[]): string {
|
|
116
|
+
return fields.map((field) => field.trim()).join(' ');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Split a cron expression into exactly five fields, padding with `*` if short. */
|
|
120
|
+
export function splitCron(expression: string): [string, string, string, string, string] {
|
|
121
|
+
const parts = expression.trim().split(/\s+/).filter(Boolean);
|
|
122
|
+
// Preserve any overflow (e.g. a 6-field seconds cron) in the last field rather
|
|
123
|
+
// than silently dropping it — the joined field then fails per-field validation
|
|
124
|
+
// so the out-of-contract expression is surfaced instead of quietly truncated.
|
|
125
|
+
const lastField = parts.length > 5 ? parts.slice(4).join(' ') : parts[4];
|
|
126
|
+
return [parts[0] ?? '*', parts[1] ?? '*', parts[2] ?? '*', parts[3] ?? '*', lastField ?? '*'];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Clamp/parse a `HH:MM` time string into `{ hour, minute }`, defaulting to 00:00. */
|
|
130
|
+
export function parseTime(time: string): { hour: number; minute: number } {
|
|
131
|
+
const match = time.trim().match(/^(\d{1,2}):(\d{2})$/);
|
|
132
|
+
if (!match) return { hour: 0, minute: 0 };
|
|
133
|
+
const hour = Math.min(23, Math.max(0, Number(match[1])));
|
|
134
|
+
const minute = Math.min(59, Math.max(0, Number(match[2])));
|
|
135
|
+
return { hour, minute };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ---------------------------------------------------------------------------
|
|
139
|
+
// Preset lowering — presets are sugar that lower to a cron or interval value.
|
|
140
|
+
// ---------------------------------------------------------------------------
|
|
141
|
+
|
|
142
|
+
/** "every N minutes/hours" → an interval value. */
|
|
143
|
+
export function lowerEveryN(every: number, unit: ScheduleIntervalUnit): ScheduleValue {
|
|
144
|
+
const safeEvery = Number.isInteger(every) && every > 0 ? every : 1;
|
|
145
|
+
return { mode: 'interval', every: safeEvery, unit };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** "daily at HH:MM" → a cron value. */
|
|
149
|
+
export function lowerDailyAt(time: string): ScheduleValue {
|
|
150
|
+
const { hour, minute } = parseTime(time);
|
|
151
|
+
return { mode: 'cron', expression: `${minute} ${hour} * * *` };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** "weekly on [days] at HH:MM" → a cron value. Empty days falls back to every day. */
|
|
155
|
+
export function lowerWeeklyAt(days: number[], time: string): ScheduleValue {
|
|
156
|
+
const { hour, minute } = parseTime(time);
|
|
157
|
+
// Don't use `Array.prototype.toSorted()` — it is ES2023 and the package
|
|
158
|
+
// targets ES2022, so it crashes runtimes that follow the target. Sort a
|
|
159
|
+
// caller-owned copy in place instead of mutating the input.
|
|
160
|
+
const sortedDays = [...days];
|
|
161
|
+
sortedDays.sort((a, b) => a - b);
|
|
162
|
+
const dow = sortedDays.length > 0 ? sortedDays.join(',') : '*';
|
|
163
|
+
return { mode: 'cron', expression: `${minute} ${hour} * * ${dow}` };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** "monthly on day N at HH:MM" → a cron value. */
|
|
167
|
+
export function lowerMonthlyOnDay(day: number, time: string): ScheduleValue {
|
|
168
|
+
const { hour, minute } = parseTime(time);
|
|
169
|
+
const safeDay = Math.min(31, Math.max(1, Math.trunc(day)));
|
|
170
|
+
return { mode: 'cron', expression: `${minute} ${hour} ${safeDay} * *` };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ---------------------------------------------------------------------------
|
|
174
|
+
// Cross-mode conversion — preserve intent losslessly where representable.
|
|
175
|
+
// ---------------------------------------------------------------------------
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Whether a step wildcard of `every` on a field that wraps every `cycleLength`
|
|
179
|
+
* units (60 for minutes, 24 for hours) is a genuinely fixed-gap interval. A
|
|
180
|
+
* step wildcard restarts counting from the field's own zero point each cycle
|
|
181
|
+
* (e.g. the minute field restarts at :00 every hour), so it only behaves like
|
|
182
|
+
* a true "every N units, forever" interval when `every` evenly divides the
|
|
183
|
+
* cycle — otherwise the LAST gap before the restart is shorter than `every`.
|
|
184
|
+
* For example, an every-45-minutes step wildcard fires at :00 and :45 — a
|
|
185
|
+
* 45-then-15-minute gap, not a steady 45 minutes — because 45 does not
|
|
186
|
+
* divide 60.
|
|
187
|
+
*/
|
|
188
|
+
function isEvenDivisorStep(every: number, cycleLength: number): boolean {
|
|
189
|
+
// Must be strictly below the cycle length: a `*/N` where N equals (or exceeds)
|
|
190
|
+
// the cycle is out of the field's range (e.g. `*/60` for minutes, max 59) and
|
|
191
|
+
// is rejected by the cron validator, so it is not a representable step.
|
|
192
|
+
return Number.isInteger(every) && every > 0 && every < cycleLength && cycleLength % every === 0;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Convert any value into cron fields, so switching into cron mode always has
|
|
197
|
+
* something sensible to show. Only `minutes` and `hours` intervals whose
|
|
198
|
+
* `every` evenly divides their field's cycle (60 for minutes, 24 for hours)
|
|
199
|
+
* are losslessly representable as a cron step wildcard — see
|
|
200
|
+
* `isEvenDivisorStep`. A non-dividing minute/hour interval (e.g. every 45
|
|
201
|
+
* minutes or every 5 hours), and `days`/`weeks` intervals (a step wildcard on
|
|
202
|
+
* the day-of-month field resets at the start of every month rather than
|
|
203
|
+
* repeating every N days, and cron has no field for "every N weeks" at all),
|
|
204
|
+
* would silently change the schedule's actual cadence the moment a user
|
|
205
|
+
* merely LOOKED at the Cron tab if lowered to a step wildcard. Seed an honest
|
|
206
|
+
* neutral default (daily at midnight) instead for all of those — see
|
|
207
|
+
* `valueToInterval` below, which mirrors this by only recovering a step that
|
|
208
|
+
* actually divides evenly.
|
|
209
|
+
*/
|
|
210
|
+
export function valueToCronFields(value: ScheduleValue): string[] {
|
|
211
|
+
if (value.mode === 'cron') return splitCron(value.expression);
|
|
212
|
+
switch (value.unit) {
|
|
213
|
+
case 'minutes':
|
|
214
|
+
if (isEvenDivisorStep(value.every, 60)) return [`*/${value.every}`, '*', '*', '*', '*'];
|
|
215
|
+
// A whole-hour minute cadence (60, 120, …) is an hours interval in
|
|
216
|
+
// disguise: lower it through the hour field where representable rather
|
|
217
|
+
// than collapsing to a daily default that would turn hourly into daily.
|
|
218
|
+
if (value.every % 60 === 0) return hoursIntervalFields(value.every / 60);
|
|
219
|
+
return ['0', '0', '*', '*', '*'];
|
|
220
|
+
case 'hours':
|
|
221
|
+
return hoursIntervalFields(value.every);
|
|
222
|
+
case 'days':
|
|
223
|
+
case 'weeks':
|
|
224
|
+
return ['0', '0', '*', '*', '*'];
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Lower an "every N hours" cadence to cron fields. Hourly (`N === 1`) is the
|
|
230
|
+
* plain `0 * * * *`; a larger N that evenly divides 24 becomes an hour step
|
|
231
|
+
* wildcard. Anything that does not divide the day (every 5 hours, or `N >= 24`)
|
|
232
|
+
* has no faithful fixed-gap cron form — a step wildcard would reset at midnight
|
|
233
|
+
* and shift the cadence at the day boundary — so it seeds the neutral daily
|
|
234
|
+
* default instead.
|
|
235
|
+
*/
|
|
236
|
+
function hoursIntervalFields(everyHours: number): string[] {
|
|
237
|
+
if (everyHours === 1) return ['0', '*', '*', '*', '*'];
|
|
238
|
+
if (isEvenDivisorStep(everyHours, 24)) return ['0', `*/${everyHours}`, '*', '*', '*'];
|
|
239
|
+
return ['0', '0', '*', '*', '*'];
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Recover an interval `{ every, unit }` from a value when representable, so
|
|
244
|
+
* switching into interval mode is lossless for simple step patterns. Only a
|
|
245
|
+
* `minutes` or `hours` step that evenly divides its field's cycle (60 or 24
|
|
246
|
+
* — see `isEvenDivisorStep`) is recovered: a non-dividing minute/hour step
|
|
247
|
+
* (e.g. a 45-minute step wildcard) is not a true fixed-gap interval, and a
|
|
248
|
+
* day-of-month step
|
|
249
|
+
* wildcard is deliberately NOT read back as `{ unit: 'days' }` at all —
|
|
250
|
+
* cron's day-of-month step resets every month, so it is not equivalent to
|
|
251
|
+
* "every N days" and `valueToCronFields` never produces one for an interval
|
|
252
|
+
* value. Returns `undefined` when the cron expression is not a pure,
|
|
253
|
+
* evenly-dividing minute/hour interval.
|
|
254
|
+
*/
|
|
255
|
+
export function valueToInterval(
|
|
256
|
+
value: ScheduleValue,
|
|
257
|
+
): { every: number; unit: ScheduleIntervalUnit } | undefined {
|
|
258
|
+
if (value.mode === 'interval') return { every: value.every, unit: value.unit };
|
|
259
|
+
const [minute, hour, dom, month, dow] = splitCron(value.expression);
|
|
260
|
+
if (month !== '*' || dow !== '*') return undefined;
|
|
261
|
+
// Common plain-wildcard forms: `* * * * *` = every minute, `0 * * * *` = hourly.
|
|
262
|
+
if (dom === '*' && hour === '*' && minute === '*') return { every: 1, unit: 'minutes' };
|
|
263
|
+
if (dom === '*' && hour === '*' && minute === '0') return { every: 1, unit: 'hours' };
|
|
264
|
+
const minuteStep = cronFieldStep(minute);
|
|
265
|
+
if (minuteStep && isEvenDivisorStep(minuteStep, 60) && hour === '*' && dom === '*') {
|
|
266
|
+
return { every: minuteStep, unit: 'minutes' };
|
|
267
|
+
}
|
|
268
|
+
const hourStep = cronFieldStep(hour);
|
|
269
|
+
if (hourStep && isEvenDivisorStep(hourStep, 24) && minute === '0' && dom === '*') {
|
|
270
|
+
return { every: hourStep, unit: 'hours' };
|
|
271
|
+
}
|
|
272
|
+
return undefined;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/** Extract the numeric step from a bare wildcard-step cron token, or `undefined`. */
|
|
276
|
+
function cronFieldStep(token: string): number | undefined {
|
|
277
|
+
const match = token.match(/^\*\/(\d+)$/);
|
|
278
|
+
return match ? Number(match[1]) : undefined;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// ---------------------------------------------------------------------------
|
|
282
|
+
// Plain-English summary — no date library required.
|
|
283
|
+
// ---------------------------------------------------------------------------
|
|
284
|
+
|
|
285
|
+
const DOW_NAMES = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
|
286
|
+
|
|
287
|
+
function pad2(n: number): string {
|
|
288
|
+
return n.toString().padStart(2, '0');
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/** Whether a cron token is a single integer within the inclusive `[min, max]` range. */
|
|
292
|
+
function isFixedInRange(token: string, min: number, max: number): boolean {
|
|
293
|
+
if (!/^\d+$/.test(token)) return false;
|
|
294
|
+
const n = Number(token);
|
|
295
|
+
return Number.isInteger(n) && n >= min && n <= max;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/** A concise, human-readable description of a recurrence value. */
|
|
299
|
+
export function describeValue(value: ScheduleValue): string {
|
|
300
|
+
if (value.mode === 'interval') {
|
|
301
|
+
return value.every === 1
|
|
302
|
+
? `Every ${singularUnit(value.unit)}`
|
|
303
|
+
: `Every ${value.every} ${value.unit}`;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const [minute, hour, dom, month, dow] = splitCron(value.expression);
|
|
307
|
+
// A "fixed" field must be a single integer WITHIN its cron range: an
|
|
308
|
+
// out-of-range digit token like `99` is invalid (validateCronField rejects it
|
|
309
|
+
// and preview is disabled), so the always-visible summary must not present
|
|
310
|
+
// `Daily at 99:00` or `Monthly on day 99` as if it were a real cadence.
|
|
311
|
+
const timeIsFixed = isFixedInRange(minute, 0, 59) && isFixedInRange(hour, 0, 23);
|
|
312
|
+
const at = timeIsFixed ? ` at ${pad2(Number(hour))}:${pad2(Number(minute))}` : '';
|
|
313
|
+
|
|
314
|
+
// The "Weekly"/"Monthly" phrasings imply a single fire per day, so they only
|
|
315
|
+
// hold when BOTH minute and hour are fixed. A schedule like `* * * * 1` or
|
|
316
|
+
// `0 * * * 1` fires every minute / every hour on Mondays — calling that
|
|
317
|
+
// "Weekly on Monday" understates the cadence — so those fall through to the
|
|
318
|
+
// raw cron summary below. ("Daily" already requires a fixed time.)
|
|
319
|
+
|
|
320
|
+
// Weekly: fixed day-of-week and a fixed time, wildcards elsewhere.
|
|
321
|
+
if (timeIsFixed && dom === '*' && month === '*' && dow !== '*' && /^[\d,]+$/.test(dow)) {
|
|
322
|
+
const dayNumbers = dow.split(',').map(Number);
|
|
323
|
+
// Day-of-week is declared 0–6 (Sun–Sat) by CRON_FIELDS, and
|
|
324
|
+
// validateCronField already rejects a user-typed 7 for that reason — this
|
|
325
|
+
// component does NOT treat 7 as a Sunday alias (some cron dialects do).
|
|
326
|
+
// An out-of-range day here can only come from a consumer-supplied value
|
|
327
|
+
// that bypassed field validation; fall through to the raw cron fallback
|
|
328
|
+
// below rather than silently wrap it into a misleading weekday via `% 7`.
|
|
329
|
+
const allDaysInRange = dayNumbers.every((day) => Number.isInteger(day) && day >= 0 && day <= 6);
|
|
330
|
+
if (allDaysInRange) {
|
|
331
|
+
const names = dayNumbers.map((day) => DOW_NAMES[day] ?? '').join(', ');
|
|
332
|
+
return `Weekly on ${names}${at}`;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
// Monthly: an in-range fixed day-of-month and a fixed time.
|
|
336
|
+
if (timeIsFixed && isFixedInRange(dom, 1, 31) && month === '*' && dow === '*') {
|
|
337
|
+
return `Monthly on day ${dom}${at}`;
|
|
338
|
+
}
|
|
339
|
+
// Daily: wildcards on day fields, fixed time.
|
|
340
|
+
if (dom === '*' && month === '*' && dow === '*' && timeIsFixed) {
|
|
341
|
+
return `Daily${at}`;
|
|
342
|
+
}
|
|
343
|
+
return `Cron: ${joinCron([minute, hour, dom, month, dow])}`;
|
|
344
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[]
|
|
@@ -28,6 +28,10 @@
|
|
|
28
28
|
"type": "boolean",
|
|
29
29
|
"description": "Allow the same trimmed tag value to appear more than once."
|
|
30
30
|
},
|
|
31
|
+
"commitOnSubmit": {
|
|
32
|
+
"type": "boolean",
|
|
33
|
+
"description": "Commit a non-empty pending draft before the parent form submits."
|
|
34
|
+
},
|
|
31
35
|
"autocapitalize": {
|
|
32
36
|
"enum": ["off", "on", "characters", "none", "sentences", "words", null],
|
|
33
37
|
"description": "Autocapitalization hint forwarded to the visible text input."
|
|
@@ -31,6 +31,10 @@ const schema = {
|
|
|
31
31
|
type: 'boolean',
|
|
32
32
|
description: 'Allow the same trimmed tag value to appear more than once.',
|
|
33
33
|
},
|
|
34
|
+
commitOnSubmit: {
|
|
35
|
+
type: 'boolean',
|
|
36
|
+
description: 'Commit a non-empty pending draft before the parent form submits.',
|
|
37
|
+
},
|
|
34
38
|
autocapitalize: {
|
|
35
39
|
enum: ['off', 'on', 'characters', 'none', 'sentences', 'words', null],
|
|
36
40
|
description: 'Autocapitalization hint forwarded to the visible text input.',
|
|
@@ -3,7 +3,7 @@ export {};
|
|
|
3
3
|
</script>
|
|
4
4
|
|
|
5
5
|
<script lang="ts">
|
|
6
|
-
import { tick, untrack } from 'svelte';
|
|
6
|
+
import { flushSync, tick, untrack } from 'svelte';
|
|
7
7
|
import { devWarn } from '../../utilities/dev-warn.ts';
|
|
8
8
|
import { ariaInvalid, composeDescribedBy, resolveFieldControl, } from '../../_internal/field-control.ts';
|
|
9
9
|
import VisuallyHiddenLiveRegion from '../_visually-hidden-live-region.svelte';
|
|
@@ -11,7 +11,7 @@ import { getFormFieldContext } from '../../_internal/form-field-context.ts';
|
|
|
11
11
|
import { classNames } from '../../utilities/class-names.ts';
|
|
12
12
|
import { handleRovingKeydown, isRovingKey } from '../../utilities/roving-tabindex.ts';
|
|
13
13
|
const generatedId = $props.id();
|
|
14
|
-
let { id, value, defaultValue, delimiter = ',', max, validate, allowDuplicates = false, disabled, readonly = false, name, class: className, oninput: consumerInput, onkeydown: consumerKeyDown, onfocus: consumerFocus, onblur: consumerBlur, 'aria-describedby': consumerDescribedBy, 'aria-label': consumerAriaLabel, 'aria-labelledby': consumerAriaLabelledBy, 'aria-invalid': consumerInvalid, required: _ignoredRequired, onchange, ...rest } = $props();
|
|
14
|
+
let { id, value, defaultValue, delimiter = ',', max, validate, allowDuplicates = false, commitOnSubmit = false, disabled, readonly = false, name, class: className, oninput: consumerInput, onkeydown: consumerKeyDown, onfocus: consumerFocus, onblur: consumerBlur, 'aria-describedby': consumerDescribedBy, 'aria-label': consumerAriaLabel, 'aria-labelledby': consumerAriaLabelledBy, 'aria-invalid': consumerInvalid, required: _ignoredRequired, onchange, ...rest } = $props();
|
|
15
15
|
const initialDefaultTags = untrack(() => [...(defaultValue ?? [])]);
|
|
16
16
|
const context = getFormFieldContext();
|
|
17
17
|
let rootElement = $state(null);
|
|
@@ -92,6 +92,19 @@ $effect(() => {
|
|
|
92
92
|
const form = inputElement.closest('form');
|
|
93
93
|
if (!form)
|
|
94
94
|
return;
|
|
95
|
+
const onSubmit = (event) => {
|
|
96
|
+
if (!commitOnSubmit || field.disabled || resolvedReadonly)
|
|
97
|
+
return;
|
|
98
|
+
if (!draftValue.trim())
|
|
99
|
+
return;
|
|
100
|
+
let committed = false;
|
|
101
|
+
flushSync(() => {
|
|
102
|
+
committed = commitDraft();
|
|
103
|
+
});
|
|
104
|
+
if (!committed) {
|
|
105
|
+
event.preventDefault();
|
|
106
|
+
}
|
|
107
|
+
};
|
|
95
108
|
const onReset = () => {
|
|
96
109
|
draftValue = '';
|
|
97
110
|
inlineError = null;
|
|
@@ -100,8 +113,12 @@ $effect(() => {
|
|
|
100
113
|
uncontrolledTags = [...initialDefaultTags];
|
|
101
114
|
}
|
|
102
115
|
};
|
|
116
|
+
form.addEventListener('submit', onSubmit, true);
|
|
103
117
|
form.addEventListener('reset', onReset);
|
|
104
|
-
return () =>
|
|
118
|
+
return () => {
|
|
119
|
+
form.removeEventListener('submit', onSubmit, true);
|
|
120
|
+
form.removeEventListener('reset', onReset);
|
|
121
|
+
};
|
|
105
122
|
});
|
|
106
123
|
function getChipElements() {
|
|
107
124
|
// The focusable, keyboard-removable element is the remove <button> — the
|
|
@@ -34,6 +34,8 @@ export type TagInputProps = SupportedInputAttributes & {
|
|
|
34
34
|
validate?: (tag: string) => boolean | string;
|
|
35
35
|
/** Allow the same trimmed tag value to appear more than once. */
|
|
36
36
|
allowDuplicates?: boolean;
|
|
37
|
+
/** Commit a non-empty pending draft before the parent form submits. */
|
|
38
|
+
commitOnSubmit?: boolean;
|
|
37
39
|
/** Disable the input and chip removal affordances. */
|
|
38
40
|
disabled?: boolean;
|
|
39
41
|
/** Render the pending-tag input as read-only and make committed tags non-removable. */
|
|
@@ -59,6 +61,8 @@ export interface TagInputSchemaProps {
|
|
|
59
61
|
delimiter?: string | RegExp;
|
|
60
62
|
/** Allow the same trimmed tag value to appear more than once. */
|
|
61
63
|
allowDuplicates?: boolean;
|
|
64
|
+
/** Commit a non-empty pending draft before the parent form submits. */
|
|
65
|
+
commitOnSubmit?: boolean;
|
|
62
66
|
/** Autocomplete hint forwarded to the visible text input. */
|
|
63
67
|
autocomplete?: HTMLInputAttributes['autocomplete'];
|
|
64
68
|
/** Autocapitalization hint forwarded to the visible text input. */
|
package/src/index.ts
CHANGED
|
@@ -257,6 +257,12 @@ export type { CommandPaletteProps } from './components/command-palette/index.ts'
|
|
|
257
257
|
export { default as ConfirmDialog } from './components/confirm-dialog/index.ts';
|
|
258
258
|
export type { ConfirmDialogProps } from './components/confirm-dialog/index.ts';
|
|
259
259
|
|
|
260
|
+
export { default as ConnectionIndicator } from './components/connection-indicator/index.ts';
|
|
261
|
+
export type {
|
|
262
|
+
ConnectionIndicatorProps,
|
|
263
|
+
ConnectionIndicatorStatus,
|
|
264
|
+
} from './components/connection-indicator/index.ts';
|
|
265
|
+
|
|
260
266
|
export { default as Container } from './components/container/index.ts';
|
|
261
267
|
export type {
|
|
262
268
|
ContainerElement,
|
|
@@ -504,10 +510,14 @@ export { default as InvocationRuleBuilder } from './components/invocation-rule-b
|
|
|
504
510
|
export type {
|
|
505
511
|
InvocationRule,
|
|
506
512
|
InvocationRuleAction,
|
|
513
|
+
InvocationRuleBuilderMode,
|
|
507
514
|
InvocationRuleBuilderProps,
|
|
508
515
|
InvocationRuleChange,
|
|
509
516
|
InvocationRuleCondition,
|
|
517
|
+
InvocationRuleConditionsOnlyOperator,
|
|
518
|
+
InvocationRuleFieldType,
|
|
510
519
|
InvocationRuleOption,
|
|
520
|
+
InvocationRuleValueChoice,
|
|
511
521
|
} from './components/invocation-rule-builder/index.ts';
|
|
512
522
|
|
|
513
523
|
export { default as JsonViewer } from './components/json-viewer/index.ts';
|
|
@@ -696,9 +706,13 @@ export type { RatingPrecision, RatingProps } from './components/rating/index.ts'
|
|
|
696
706
|
export { default as RunStepTimeline } from './components/run-step-timeline/index.ts';
|
|
697
707
|
export type {
|
|
698
708
|
RunStep,
|
|
709
|
+
RunStepBranchGroup,
|
|
710
|
+
RunStepBranchLane,
|
|
711
|
+
RunStepBranchLaneOutcome,
|
|
699
712
|
RunStepDetail,
|
|
700
713
|
RunStepLink,
|
|
701
714
|
RunStepStatus,
|
|
715
|
+
RunStepTimelineEntry,
|
|
702
716
|
RunStepTimelineProps,
|
|
703
717
|
} from './components/run-step-timeline/index.ts';
|
|
704
718
|
|
|
@@ -715,6 +729,15 @@ export type {
|
|
|
715
729
|
ResizablePanelsResizeReason,
|
|
716
730
|
} from './components/resizable-panels/index.ts';
|
|
717
731
|
|
|
732
|
+
export { default as ScheduleBuilder } from './components/schedule-builder/index.ts';
|
|
733
|
+
export type {
|
|
734
|
+
ScheduleAuthoringMode,
|
|
735
|
+
ScheduleBuilderProps,
|
|
736
|
+
ScheduleFire,
|
|
737
|
+
ScheduleIntervalUnit,
|
|
738
|
+
ScheduleValue,
|
|
739
|
+
} from './components/schedule-builder/index.ts';
|
|
740
|
+
|
|
718
741
|
export { default as SchemaForm, readSchemaFormData } from './components/schema-form/index.ts';
|
|
719
742
|
export type {
|
|
720
743
|
SchemaFormOutput,
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
@import '../components/command-menu/command-menu.css';
|
|
54
54
|
@import '../components/command-palette/command-palette.css';
|
|
55
55
|
@import '../components/confirm-dialog/confirm-dialog.css';
|
|
56
|
+
@import '../components/connection-indicator/connection-indicator.css';
|
|
56
57
|
@import '../components/container/container.css';
|
|
57
58
|
@import '../components/context-menu/context-menu.css';
|
|
58
59
|
@import '../components/copy-button/copy-button.css';
|
|
@@ -129,6 +130,7 @@
|
|
|
129
130
|
@import '../components/resizable-panels/resizable-panels.css';
|
|
130
131
|
@import '../components/run-step-timeline/run-step-timeline.css';
|
|
131
132
|
@import '../components/review-editor/review-editor.css';
|
|
133
|
+
@import '../components/schedule-builder/schedule-builder.css';
|
|
132
134
|
@import '../components/schema-form/schema-form.css';
|
|
133
135
|
@import '../components/scroll-area/scroll-area.css';
|
|
134
136
|
@import '../components/search-field/search-field.css';
|