@galaxy-io/dls 2.1.0 → 2.2.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/dist/drawer/Drawer.d.ts +10 -1
- package/dist/drawer/Drawer.js +42 -55
- package/dist/inputs/CronInput.d.ts +59 -25
- package/dist/inputs/CronInput.js +509 -217
- package/dist/modal/Modal.d.ts +10 -1
- package/dist/modal/Modal.js +21 -34
- package/dist/navigation/CommandPalette.js +8 -8
- package/dist/overlay/internal/OverlayScaleFade.d.ts +16 -0
- package/dist/overlay/internal/OverlayScaleFade.js +60 -0
- package/dist/overlay/internal/OverlayTitleRow.d.ts +23 -0
- package/dist/overlay/internal/OverlayTitleRow.js +90 -0
- package/dist/overlay/internal/contentFirstExit.d.ts +25 -0
- package/dist/overlay/internal/contentFirstExit.js +34 -0
- package/dist/overlays/Popover.js +7 -6
- package/dist/styles.css +1 -1
- package/dist/toast/ToastViewport.js +1 -1
- package/package.json +1 -1
package/dist/inputs/CronInput.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import VisuallyHidden from "../a11y/VisuallyHidden.js";
|
|
2
|
+
import { FontFamily, Orientation } from "../theme/enums.js";
|
|
2
3
|
import Text, { TextSize, TextVariant } from "../text/Text.js";
|
|
3
4
|
import { useControlledState } from "../hooks/useControlledState.js";
|
|
5
|
+
import { useControlledOpenState } from "../hooks/useControlledOpenState.js";
|
|
4
6
|
import Flex, { AlignItems } from "../layout/Flex.js";
|
|
7
|
+
import Box from "../layout/Box.js";
|
|
8
|
+
import Divider from "../layout/Divider.js";
|
|
9
|
+
import Popover, { PopoverRole, PopoverTrigger, PopoverVariant } from "../overlays/Popover.js";
|
|
10
|
+
import Icon, { IconVariant } from "../icons/Icon.js";
|
|
5
11
|
import Button, { ButtonSize, ButtonVariant } from "../buttons/Button.js";
|
|
6
12
|
import ButtonGroup from "../buttons/ButtonGroup.js";
|
|
7
13
|
import { useDevWarning } from "./internal/devWarn.js";
|
|
@@ -9,7 +15,10 @@ import { FieldContext } from "../hooks/useField.js";
|
|
|
9
15
|
import { useFieldWiring } from "./internal/fieldWiring.js";
|
|
10
16
|
import Field, { FieldSize } from "./Field.js";
|
|
11
17
|
import { rootStyle, useOwnField } from "./internal/ownField.js";
|
|
18
|
+
import { BareFieldContext, useIsBareField } from "./internal/bareField.js";
|
|
19
|
+
import "./internal/innerButton.js";
|
|
12
20
|
import { InputSize, InputVariant } from "./Input.js";
|
|
21
|
+
import { useDedupedOpen, useRestoreFocusAfterOutsidePress, useRetriedFocus } from "./internal/useComboboxPopover.js";
|
|
13
22
|
import TextInput from "./TextInput.js";
|
|
14
23
|
import SelectInput, { SelectInputSize, SelectInputVariant } from "./SelectInput.js";
|
|
15
24
|
import ToggleInput, { ToggleInputSize, ToggleInputVariant } from "./ToggleInput.js";
|
|
@@ -18,35 +27,45 @@ import { styled } from "@linaria/react";
|
|
|
18
27
|
import { forwardRef, useMemo, useRef, useState } from "react";
|
|
19
28
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
20
29
|
import { cx } from "@linaria/core";
|
|
30
|
+
import { useMergeRefs } from "@floating-ui/react";
|
|
31
|
+
import { ClockIcon, XIcon } from "@phosphor-icons/react";
|
|
21
32
|
import cronstrue from "cronstrue";
|
|
22
33
|
//#region src/inputs/CronInput.tsx
|
|
23
34
|
/**
|
|
24
35
|
* The form control for a recurring schedule written as a five-field cron expression
|
|
25
|
-
* (`minute hour day-of-month month day-of-week`).
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* sentence from `cronstrue` reads the schedule back ("Runs at 09:00, Monday through
|
|
36
|
+
* (`minute hour day-of-month month day-of-week`). A field shows the expression (or a placeholder)
|
|
37
|
+
* and opens a schedule panel below it: the presets ("Every 15 minutes", "Weekdays at 09:00"), a
|
|
38
|
+
* builder (a frequency, Hourly / Daily / Weekly / Monthly / Custom, and the fields that frequency
|
|
39
|
+
* needs: the minute, the time, the weekdays, the day of the month), the expression itself as text,
|
|
40
|
+
* and a sentence from `cronstrue` that reads the schedule back ("Runs at 09:00, Monday through
|
|
41
|
+
* Friday."). Expressions the builder cannot represent show as Custom and are edited as text.
|
|
30
42
|
*
|
|
31
|
-
* The
|
|
32
|
-
*
|
|
33
|
-
*
|
|
43
|
+
* The field is a select-only combobox with a dialog popup (`Popover` `MANUAL`, `DIALOG`), like
|
|
44
|
+
* DateInput; CronInput moves focus to the expression field on open, so a schedule can be typed
|
|
45
|
+
* straight away. The value is the expression string; an empty string shows the placeholder.
|
|
46
|
+
*
|
|
47
|
+
* CronInput never validates (the app passes `error`; the sentence only says when it cannot read an
|
|
48
|
+
* expression), holds no time zone, and does not support seconds or year fields. Sources: rafa's
|
|
49
|
+
* CronInput and Filament's schedule fields.
|
|
50
|
+
*
|
|
51
|
+
* SSR: closed by default, so the server renders the field only. Nothing here touches `window` or
|
|
52
|
+
* `document` at module scope.
|
|
34
53
|
*/
|
|
35
|
-
/** Canonical rungs; CronInput supports all five
|
|
54
|
+
/** Canonical rungs; CronInput supports all five (the Input rung table). */
|
|
36
55
|
var CronInputSize = /* @__PURE__ */ function(CronInputSize) {
|
|
37
|
-
/** 20px
|
|
56
|
+
/** 20px field, caption text, 12px icon. */
|
|
38
57
|
CronInputSize["X_SMALL"] = "X_SMALL";
|
|
39
|
-
/** 24px
|
|
58
|
+
/** 24px field, body_sm text, 12px icon. */
|
|
40
59
|
CronInputSize["SMALL"] = "SMALL";
|
|
41
|
-
/** 32px
|
|
60
|
+
/** 32px field, body_md text, 14px icon. The default. */
|
|
42
61
|
CronInputSize["MEDIUM"] = "MEDIUM";
|
|
43
|
-
/** 36px
|
|
62
|
+
/** 36px field, body_lg text, 14px icon. */
|
|
44
63
|
CronInputSize["LARGE"] = "LARGE";
|
|
45
|
-
/** 40px
|
|
64
|
+
/** 40px field, body_lg text, 16px icon. */
|
|
46
65
|
CronInputSize["X_LARGE"] = "X_LARGE";
|
|
47
66
|
return CronInputSize;
|
|
48
67
|
}({});
|
|
49
|
-
/** Resting fill of the
|
|
68
|
+
/** Resting fill of the field (Constitution V-A surface set). */
|
|
50
69
|
var CronInputVariant = /* @__PURE__ */ function(CronInputVariant) {
|
|
51
70
|
/** `background.base` fill. */
|
|
52
71
|
CronInputVariant["BASE"] = "BASE";
|
|
@@ -60,8 +79,43 @@ var CronInputVariant = /* @__PURE__ */ function(CronInputVariant) {
|
|
|
60
79
|
}({});
|
|
61
80
|
/** The uncontrolled default: daily at 00:00. */
|
|
62
81
|
var CRON_INPUT_DEFAULT_VALUE = "0 0 * * *";
|
|
63
|
-
/**
|
|
64
|
-
|
|
82
|
+
/** The presets shown when the app passes none. */
|
|
83
|
+
var CRON_INPUT_DEFAULT_PRESETS = [
|
|
84
|
+
{
|
|
85
|
+
label: "Every 5 minutes",
|
|
86
|
+
value: "*/5 * * * *"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
label: "Every 15 minutes",
|
|
90
|
+
value: "*/15 * * * *"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
label: "Hourly",
|
|
94
|
+
value: "0 * * * *"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
label: "Daily at midnight",
|
|
98
|
+
value: "0 0 * * *"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
label: "Weekdays at 09:00",
|
|
102
|
+
value: "0 9 * * 1-5"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
label: "Weekly on Monday",
|
|
106
|
+
value: "0 0 * * 1"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
label: "Monthly on the 1st",
|
|
110
|
+
value: "0 0 1 * *"
|
|
111
|
+
}
|
|
112
|
+
];
|
|
113
|
+
/** Field width without `fillWidth` (DateInput's single width). */
|
|
114
|
+
/** The presets column's narrowest width. */
|
|
115
|
+
/** Width of the two-digit selects (minute, hour, day of month), px for `Box width` (DateInput's time selects). */
|
|
116
|
+
var CRON_INPUT_SELECT_WIDTH = 64;
|
|
117
|
+
/** Frames to wait for the panel's portal before giving up on moving focus into it. */
|
|
118
|
+
var CRON_INPUT_FOCUS_RETRY_FRAMES = 10;
|
|
65
119
|
/** The neutral hint shown when `cronstrue` cannot read the expression. */
|
|
66
120
|
var CRON_INPUT_HINT = "Enter five fields: minute, hour, day of month, month, day of week.";
|
|
67
121
|
/** Each builder row's label; the label column is as wide as the longest, whichever rows show. */
|
|
@@ -246,7 +300,11 @@ function builderToValue(frequency, parts) {
|
|
|
246
300
|
case "MONTHLY": return `${minute} ${hour} ${dayOfMonth} * *`;
|
|
247
301
|
}
|
|
248
302
|
}
|
|
249
|
-
/**
|
|
303
|
+
/** An expression with its fields single-spaced, for comparing against a preset. */
|
|
304
|
+
function normalize(expression) {
|
|
305
|
+
return expression.trim().split(/\s+/).join(" ");
|
|
306
|
+
}
|
|
307
|
+
/** The sentence for an expression, or `null` when `cronstrue` cannot read it. */
|
|
250
308
|
function describe(expression) {
|
|
251
309
|
if (expression.split(/\s+/).length !== 5) return null;
|
|
252
310
|
try {
|
|
@@ -262,34 +320,32 @@ function describe(expression) {
|
|
|
262
320
|
return null;
|
|
263
321
|
}
|
|
264
322
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
["
|
|
268
|
-
["
|
|
269
|
-
["
|
|
270
|
-
["
|
|
271
|
-
|
|
272
|
-
var CRON_INPUT_SIZE_TO_SELECT_INPUT_SIZE_MAP = {
|
|
273
|
-
["X_SMALL"]: SelectInputSize.X_SMALL,
|
|
274
|
-
["SMALL"]: SelectInputSize.SMALL,
|
|
275
|
-
["MEDIUM"]: SelectInputSize.MEDIUM,
|
|
276
|
-
["LARGE"]: SelectInputSize.LARGE,
|
|
277
|
-
["X_LARGE"]: SelectInputSize.X_LARGE
|
|
278
|
-
};
|
|
279
|
-
var CRON_INPUT_SIZE_TO_INPUT_SIZE_MAP = {
|
|
280
|
-
["X_SMALL"]: InputSize.X_SMALL,
|
|
281
|
-
["SMALL"]: InputSize.SMALL,
|
|
282
|
-
["MEDIUM"]: InputSize.MEDIUM,
|
|
283
|
-
["LARGE"]: InputSize.LARGE,
|
|
284
|
-
["X_LARGE"]: InputSize.X_LARGE
|
|
323
|
+
/** Field icon px per rung: one step below the rung's III-A.4 icon (DateInput's). */
|
|
324
|
+
var CRON_INPUT_SIZE_TO_ICON_PX_MAP = {
|
|
325
|
+
["X_SMALL"]: 12,
|
|
326
|
+
["SMALL"]: 12,
|
|
327
|
+
["MEDIUM"]: 14,
|
|
328
|
+
["LARGE"]: 14,
|
|
329
|
+
["X_LARGE"]: 16
|
|
285
330
|
};
|
|
331
|
+
/** The clear button's rung: 20px up to MEDIUM, 24px for LARGE and X_LARGE (Input's). */
|
|
286
332
|
var CRON_INPUT_SIZE_TO_BUTTON_SIZE_MAP = {
|
|
287
333
|
["X_SMALL"]: ButtonSize.X_SMALL,
|
|
288
|
-
["SMALL"]: ButtonSize.
|
|
289
|
-
["MEDIUM"]: ButtonSize.
|
|
290
|
-
["LARGE"]: ButtonSize.
|
|
291
|
-
["X_LARGE"]: ButtonSize.
|
|
334
|
+
["SMALL"]: ButtonSize.X_SMALL,
|
|
335
|
+
["MEDIUM"]: ButtonSize.X_SMALL,
|
|
336
|
+
["LARGE"]: ButtonSize.SMALL,
|
|
337
|
+
["X_LARGE"]: ButtonSize.SMALL
|
|
292
338
|
};
|
|
339
|
+
/** The clear button's px per rung, for the reserved padding (16 on X_SMALL: `X_SMALL_INNER_BUTTON_CSS`). */
|
|
340
|
+
/** Field text step per rung (the canonical control text). */
|
|
341
|
+
var CRON_INPUT_SIZE_TO_TEXT_SIZE_MAP = {
|
|
342
|
+
["X_SMALL"]: TextSize.CAPTION,
|
|
343
|
+
["SMALL"]: TextSize.BODY_SM,
|
|
344
|
+
["MEDIUM"]: TextSize.BODY_MD,
|
|
345
|
+
["LARGE"]: TextSize.BODY_LG,
|
|
346
|
+
["X_LARGE"]: TextSize.BODY_LG
|
|
347
|
+
};
|
|
348
|
+
/** The `Field` a CronInput renders for its own `label` / `error` uses the same rung. */
|
|
293
349
|
var CRON_INPUT_SIZE_TO_FIELD_SIZE_MAP = {
|
|
294
350
|
["X_SMALL"]: FieldSize.X_SMALL,
|
|
295
351
|
["SMALL"]: FieldSize.SMALL,
|
|
@@ -297,53 +353,161 @@ var CRON_INPUT_SIZE_TO_FIELD_SIZE_MAP = {
|
|
|
297
353
|
["LARGE"]: FieldSize.LARGE,
|
|
298
354
|
["X_LARGE"]: FieldSize.X_LARGE
|
|
299
355
|
};
|
|
300
|
-
/**
|
|
301
|
-
var
|
|
302
|
-
["
|
|
303
|
-
["
|
|
304
|
-
["
|
|
305
|
-
["
|
|
306
|
-
["X_LARGE"]: TextSize.BODY_LG
|
|
356
|
+
/** Panel fill: SelectInput's map. A ghost field (`isGhost`) gets a readable `BASE` panel instead. */
|
|
357
|
+
var CRON_INPUT_VARIANT_TO_POPOVER_VARIANT_MAP = {
|
|
358
|
+
["BASE"]: PopoverVariant.PRIMARY,
|
|
359
|
+
["PRIMARY"]: PopoverVariant.PRIMARY,
|
|
360
|
+
["SECONDARY"]: PopoverVariant.SECONDARY,
|
|
361
|
+
["TERTIARY"]: PopoverVariant.TERTIARY
|
|
307
362
|
};
|
|
308
|
-
/**
|
|
309
|
-
var
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
363
|
+
/** Holds the field box, the trailing parts and the hidden summary. */
|
|
364
|
+
var Wrapper = /*#__PURE__*/ styled("div")({
|
|
365
|
+
name: "Wrapper",
|
|
366
|
+
class: "gx-CronInput-Wrapper-wmu78vg",
|
|
367
|
+
propsAsIs: false
|
|
368
|
+
});
|
|
369
|
+
/** Without `fillWidth`: 240px. */
|
|
370
|
+
var WIDTH_CSS = "gx-CronInput-WIDTH_CSS-wvetpyb";
|
|
371
|
+
/**
|
|
372
|
+
* The combobox (focused element and Popover's reference). No outline; focus is `FOCUS_CSS`.
|
|
373
|
+
* Declared before the frame maps.
|
|
374
|
+
*/
|
|
375
|
+
var Control = /*#__PURE__*/ styled("div")({
|
|
376
|
+
name: "Control",
|
|
377
|
+
class: "gx-CronInput-Control-cwvebjn",
|
|
378
|
+
propsAsIs: false
|
|
379
|
+
});
|
|
380
|
+
/** Rest look per variant: fill and hairline color. */
|
|
381
|
+
var CRON_INPUT_VARIANT_TO_CSS_MAP = {
|
|
382
|
+
["BASE"]: "gx-CronInput-BASE-bendsmc",
|
|
383
|
+
["PRIMARY"]: "gx-CronInput-PRIMARY-p1iubrvv",
|
|
384
|
+
["SECONDARY"]: "gx-CronInput-SECONDARY-s1i5sgim",
|
|
385
|
+
["TERTIARY"]: "gx-CronInput-TERTIARY-t1xjp6qf"
|
|
315
386
|
};
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
["
|
|
387
|
+
/** `isGhost`: no fill and no hairline at rest. Declared after the variant map, which it replaces. */
|
|
388
|
+
var GHOST_CSS = "gx-CronInput-GHOST_CSS-g73e2ix";
|
|
389
|
+
/** Hover on an editable field: `border.hovered` (stronger than `border.primary`, Constitution III.6). */
|
|
390
|
+
var CRON_INPUT_VARIANT_TO_HOVER_CSS_MAP = {
|
|
391
|
+
["BASE"]: "gx-CronInput-BASE-b1tyf0oc",
|
|
392
|
+
["PRIMARY"]: "gx-CronInput-PRIMARY-ppl1i3v",
|
|
393
|
+
["SECONDARY"]: "gx-CronInput-SECONDARY-s1r1kpa2",
|
|
394
|
+
["TERTIARY"]: "gx-CronInput-TERTIARY-tr1ns5a"
|
|
321
395
|
};
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
396
|
+
/** Hover on an editable ghost field: the frame appears, `border.hovered` with no fill. */
|
|
397
|
+
var GHOST_HOVER_CSS = "gx-CronInput-GHOST_HOVER_CSS-g1279sor";
|
|
398
|
+
/**
|
|
399
|
+
* Height, start inset, gap and the end inset that reserves the icon zone (rung padding + icon +
|
|
400
|
+
* gap) per rung (SelectInput's table). The start inset subtracts the 0.5px hairline so the value
|
|
401
|
+
* starts on a whole pixel.
|
|
402
|
+
*/
|
|
403
|
+
var CRON_INPUT_SIZE_TO_CSS_MAP = {
|
|
404
|
+
["X_SMALL"]: "gx-CronInput-X_SMALL-x21adkg",
|
|
405
|
+
["SMALL"]: "gx-CronInput-SMALL-snda18n",
|
|
406
|
+
["MEDIUM"]: "gx-CronInput-MEDIUM-m1wqniqa",
|
|
407
|
+
["LARGE"]: "gx-CronInput-LARGE-l144xlp2",
|
|
408
|
+
["X_LARGE"]: "gx-CronInput-X_LARGE-xynnhma"
|
|
327
409
|
};
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
["
|
|
331
|
-
["
|
|
332
|
-
["
|
|
410
|
+
/** With `isClearable`: the end inset also reserves the clear button and a gap. */
|
|
411
|
+
var CRON_INPUT_SIZE_TO_CLEARABLE_CSS_MAP = {
|
|
412
|
+
["X_SMALL"]: "gx-CronInput-X_SMALL-x11zmzgg",
|
|
413
|
+
["SMALL"]: "gx-CronInput-SMALL-sgvaglw",
|
|
414
|
+
["MEDIUM"]: "gx-CronInput-MEDIUM-mv01uf1",
|
|
415
|
+
["LARGE"]: "gx-CronInput-LARGE-lkzx5g9",
|
|
416
|
+
["X_LARGE"]: "gx-CronInput-X_LARGE-xvvvzs"
|
|
333
417
|
};
|
|
334
|
-
/**
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
418
|
+
/**
|
|
419
|
+
* Focus, from the mouse or the keyboard: `FIELD_FOCUS`, `border.focused` at 1px inside the frame. `:focus:hover`
|
|
420
|
+
* beats the hover map, so a ghost field keeps it. Not applied while disabled (the disabled
|
|
421
|
+
* combobox is a `tabIndex={-1}` div, which a click can still focus).
|
|
422
|
+
*/
|
|
423
|
+
var FOCUS_CSS = "gx-CronInput-FOCUS_CSS-f1067muk";
|
|
424
|
+
/** Open: `border.focused`. */
|
|
425
|
+
var OPEN_CSS = "gx-CronInput-OPEN_CSS-o54xey5";
|
|
426
|
+
/** Error border at rest, on hover, with focus and while open. */
|
|
427
|
+
var ERROR_CSS = "gx-CronInput-ERROR_CSS-e1hmaicf";
|
|
428
|
+
/** Disabled keeps the resting hairline; the text, the icon and the cursor say disabled. */
|
|
429
|
+
var DISABLED_CSS = "gx-CronInput-DISABLED_CSS-d66p23w";
|
|
430
|
+
/** Read-only: no pointer affordance. */
|
|
431
|
+
var READ_ONLY_CSS = "gx-CronInput-READ_ONLY_CSS-r1vuh2ii";
|
|
432
|
+
/** Stretch to the parent's width (wrapper, and the `Field` wrapper when there is one). */
|
|
433
|
+
var FILL_WIDTH_CSS = "gx-CronInput-FILL_WIDTH_CSS-fpavuga";
|
|
434
|
+
/** The expression (or placeholder): takes the row, truncates. */
|
|
435
|
+
var ValueDisplay = /*#__PURE__*/ styled("span")({
|
|
436
|
+
name: "ValueDisplay",
|
|
437
|
+
class: "gx-CronInput-ValueDisplay-v18d3ls7",
|
|
338
438
|
propsAsIs: false
|
|
339
439
|
});
|
|
440
|
+
/** The clock icon and the clear button, laid over the field's end. */
|
|
441
|
+
var Trailing = /*#__PURE__*/ styled("span")({
|
|
442
|
+
name: "Trailing",
|
|
443
|
+
class: "gx-CronInput-Trailing-t5fn29j",
|
|
444
|
+
propsAsIs: false
|
|
445
|
+
});
|
|
446
|
+
/** Trailing inset (the rung padding) and gap per rung. */
|
|
447
|
+
var CRON_INPUT_SIZE_TO_TRAILING_CSS_MAP = {
|
|
448
|
+
["X_SMALL"]: "gx-CronInput-X_SMALL-x1f2acxv",
|
|
449
|
+
["SMALL"]: "gx-CronInput-SMALL-srskmwt",
|
|
450
|
+
["MEDIUM"]: "gx-CronInput-MEDIUM-m1p8cnb2",
|
|
451
|
+
["LARGE"]: "gx-CronInput-LARGE-lnz42gb",
|
|
452
|
+
["X_LARGE"]: "gx-CronInput-X_LARGE-x14lh8y9"
|
|
453
|
+
};
|
|
454
|
+
/** Wraps the clear button: the only part of `Trailing` that takes the pointer. */
|
|
455
|
+
var ClearSlot = /*#__PURE__*/ styled("span")({
|
|
456
|
+
name: "ClearSlot",
|
|
457
|
+
class: "gx-CronInput-ClearSlot-cnjxgnh",
|
|
458
|
+
propsAsIs: false
|
|
459
|
+
});
|
|
460
|
+
/** Hidden clear button: keeps its width, leaves the tab order and the accessibility tree. */
|
|
461
|
+
var CLEAR_HIDDEN_CSS = "gx-CronInput-CLEAR_HIDDEN_CSS-c1d4mcpq";
|
|
462
|
+
/** The panel content: the main row, then the summary footer. */
|
|
463
|
+
var PanelBody = /*#__PURE__*/ styled("div")({
|
|
464
|
+
name: "PanelBody",
|
|
465
|
+
class: "gx-CronInput-PanelBody-p11btr9k",
|
|
466
|
+
propsAsIs: false
|
|
467
|
+
});
|
|
468
|
+
/** The main row: presets, then the builder, 12px in and 12px apart. */
|
|
469
|
+
var PanelMain = /*#__PURE__*/ styled("div")({
|
|
470
|
+
name: "PanelMain",
|
|
471
|
+
class: "gx-CronInput-PanelMain-p1az6570",
|
|
472
|
+
propsAsIs: false
|
|
473
|
+
});
|
|
474
|
+
/**
|
|
475
|
+
* The summary footer: the schedule read back, set apart from the controls that make it. A hairline
|
|
476
|
+
* above and a faint foreground tint, so it reads as the panel's output on every panel fill. It
|
|
477
|
+
* wraps to the panel's width and never widens it.
|
|
478
|
+
*/
|
|
479
|
+
var Summary = /*#__PURE__*/ styled("div")({
|
|
480
|
+
name: "Summary",
|
|
481
|
+
class: "gx-CronInput-Summary-s1phzlk6",
|
|
482
|
+
propsAsIs: false
|
|
483
|
+
});
|
|
484
|
+
/** Centers the 12px icon on the summary's first 16px line. */
|
|
485
|
+
var SummaryIcon = /*#__PURE__*/ styled("span")({
|
|
486
|
+
name: "SummaryIcon",
|
|
487
|
+
class: "gx-CronInput-SummaryIcon-su1hduy",
|
|
488
|
+
propsAsIs: false
|
|
489
|
+
});
|
|
490
|
+
/** The presets column. */
|
|
491
|
+
var PresetList = /*#__PURE__*/ styled("div")({
|
|
492
|
+
name: "PresetList",
|
|
493
|
+
class: "gx-CronInput-PresetList-pryjels",
|
|
494
|
+
propsAsIs: false
|
|
495
|
+
});
|
|
496
|
+
/** One preset. Declared before its state classes. */
|
|
497
|
+
var PresetButton = /*#__PURE__*/ styled("button")({
|
|
498
|
+
name: "PresetButton",
|
|
499
|
+
class: "gx-CronInput-PresetButton-pm47nq4",
|
|
500
|
+
propsAsIs: false
|
|
501
|
+
});
|
|
502
|
+
/** The preset whose value is the current expression. */
|
|
503
|
+
var SELECTED_PRESET_CSS = "gx-CronInput-SELECTED_PRESET_CSS-safotm8";
|
|
340
504
|
/**
|
|
341
505
|
* Row labels in the first column, controls in the second. Controls keep their own width
|
|
342
|
-
* (`justify-items: start`), so the
|
|
506
|
+
* (`justify-items: start`), so the weekday row never stretches the frequency toggle.
|
|
343
507
|
*/
|
|
344
508
|
var Rows = /*#__PURE__*/ styled("div")({
|
|
345
509
|
name: "Rows",
|
|
346
|
-
class: "gx-CronInput-Rows-
|
|
510
|
+
class: "gx-CronInput-Rows-r1d29pk4",
|
|
347
511
|
propsAsIs: false
|
|
348
512
|
});
|
|
349
513
|
/**
|
|
@@ -352,50 +516,59 @@ var Rows = /*#__PURE__*/ styled("div")({
|
|
|
352
516
|
*/
|
|
353
517
|
var LabelStack = /*#__PURE__*/ styled("span")({
|
|
354
518
|
name: "LabelStack",
|
|
355
|
-
class: "gx-CronInput-LabelStack-
|
|
519
|
+
class: "gx-CronInput-LabelStack-l1tt5fyf",
|
|
356
520
|
propsAsIs: false
|
|
357
521
|
});
|
|
358
522
|
/** A row label that only sizes the label column: not painted, not announced. */
|
|
359
|
-
var LABEL_SIZER_CSS = "gx-CronInput-LABEL_SIZER_CSS-
|
|
360
|
-
/**
|
|
361
|
-
var
|
|
362
|
-
name: "
|
|
363
|
-
class: "gx-CronInput-
|
|
523
|
+
var LABEL_SIZER_CSS = "gx-CronInput-LABEL_SIZER_CSS-l10uqwad";
|
|
524
|
+
/** A full-width part of the rows grid (the divider above the expression). */
|
|
525
|
+
var RowSpan = /*#__PURE__*/ styled("div")({
|
|
526
|
+
name: "RowSpan",
|
|
527
|
+
class: "gx-CronInput-RowSpan-r1231567",
|
|
364
528
|
propsAsIs: false
|
|
365
529
|
});
|
|
366
|
-
/**
|
|
367
|
-
var ExpressionSlot = /*#__PURE__*/ styled("
|
|
530
|
+
/** Stretches the expression field across the control column. */
|
|
531
|
+
var ExpressionSlot = /*#__PURE__*/ styled("div")({
|
|
368
532
|
name: "ExpressionSlot",
|
|
369
|
-
class: "gx-CronInput-ExpressionSlot-
|
|
533
|
+
class: "gx-CronInput-ExpressionSlot-e13n44nx",
|
|
370
534
|
propsAsIs: false
|
|
371
535
|
});
|
|
372
|
-
/**
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
/** With `fillWidth`, the Custom field fills its cell. */
|
|
377
|
-
var EXPRESSION_FILL_CSS = "gx-CronInput-EXPRESSION_FILL_CSS-e1tyf0oc";
|
|
378
|
-
/** The builder and its preview, wired to the nearest Field (the CronInput's own or the app's). */
|
|
379
|
-
function CronGroup({ cronProps, forwardedRef, isRoot }) {
|
|
380
|
-
const { value, defaultValue = CRON_INPUT_DEFAULT_VALUE, onChange, size = "MEDIUM", variant = "PRIMARY", isGhost = false, label: _label, error, isError = false, isDisabled = false, isReadOnly = false, isRequired = false, fillWidth = false, ariaLabel, id, "aria-describedby": ariaDescribedBy, className, style, ...rest } = cronProps;
|
|
536
|
+
/** The field, the trailing parts and the schedule panel, wired to the nearest Field. */
|
|
537
|
+
function CronInputFrame({ cronProps, forwardedRef, isRoot }) {
|
|
538
|
+
const { value, defaultValue = CRON_INPUT_DEFAULT_VALUE, onChange, presets = CRON_INPUT_DEFAULT_PRESETS, size = "MEDIUM", variant = "PRIMARY", isGhost = false, label: _label, placeholder = "Select schedule…", error, isError = false, isClearable = false, isDisabled = false, isReadOnly = false, isRequired = false, fillWidth = false, ariaLabel, isOpen, defaultIsOpen = false, onOpenChange, id, "aria-describedby": ariaDescribedBy, className, style, ...rest } = cronProps;
|
|
539
|
+
const isBare = useIsBareField();
|
|
381
540
|
const { field, controlId, describedBy, isInvalid, isRequired: isRequiredState, hasName } = useFieldWiring({
|
|
382
541
|
id,
|
|
383
542
|
ariaLabel,
|
|
384
543
|
ariaLabelAttribute: rest["aria-label"],
|
|
385
544
|
ariaLabelledBy: rest["aria-labelledby"],
|
|
386
545
|
ariaDescribedBy,
|
|
387
|
-
describedByIds: (
|
|
546
|
+
describedByIds: (fieldId) => [`${fieldId}-summary`],
|
|
388
547
|
error,
|
|
389
548
|
isError,
|
|
390
549
|
isRequired
|
|
391
550
|
});
|
|
392
|
-
const
|
|
551
|
+
const panelId = `${controlId}-schedule`;
|
|
552
|
+
const summaryId = `${controlId}-summary`;
|
|
553
|
+
const expressionId = `${controlId}-expression-input`;
|
|
393
554
|
const rowLabelId = (row) => `${controlId}-${row}`;
|
|
555
|
+
const controlRef = useRef(null);
|
|
556
|
+
const mergedRef = useMergeRefs([controlRef, forwardedRef]);
|
|
557
|
+
const panelRef = useRef(null);
|
|
558
|
+
const wrapperRef = useRef(null);
|
|
559
|
+
const isEditable = !isDisabled && !isReadOnly;
|
|
394
560
|
const [expression, setExpression] = useControlledState({
|
|
395
561
|
value,
|
|
396
562
|
defaultValue,
|
|
397
563
|
onChange
|
|
398
564
|
});
|
|
565
|
+
const { isOpen: isOpenState, setOpen: setOpenState } = useControlledOpenState({
|
|
566
|
+
isOpen,
|
|
567
|
+
defaultIsOpen,
|
|
568
|
+
onOpenChange
|
|
569
|
+
});
|
|
570
|
+
const isShown = isOpenState && isEditable;
|
|
571
|
+
const { setOpen, isShownRef } = useDedupedOpen(isShown, setOpenState);
|
|
399
572
|
const lastEmittedRef = useRef(null);
|
|
400
573
|
const [builder, setBuilder] = useState(() => valueToBuilder(expression));
|
|
401
574
|
const [lastSeen, setLastSeen] = useState(expression);
|
|
@@ -403,12 +576,31 @@ function CronGroup({ cronProps, forwardedRef, isRoot }) {
|
|
|
403
576
|
setLastSeen(expression);
|
|
404
577
|
if (expression !== lastEmittedRef.current) setBuilder((previous) => valueToBuilder(expression, previous.parts));
|
|
405
578
|
}
|
|
579
|
+
/** Writes an expression the builder made. */
|
|
406
580
|
const emit = (next) => {
|
|
407
581
|
if (next === expression) return;
|
|
408
582
|
lastEmittedRef.current = next;
|
|
409
583
|
setExpression(next);
|
|
410
584
|
};
|
|
411
|
-
|
|
585
|
+
/** Writes an expression from outside the builder (typed, a preset, cleared). */
|
|
586
|
+
const commit = (next) => {
|
|
587
|
+
lastEmittedRef.current = null;
|
|
588
|
+
setExpression(next);
|
|
589
|
+
};
|
|
590
|
+
const shouldFocusExpressionRef = useRef(false);
|
|
591
|
+
const [lastShown, setLastShown] = useState(isShown);
|
|
592
|
+
if (lastShown !== isShown) {
|
|
593
|
+
setLastShown(isShown);
|
|
594
|
+
if (isShown) shouldFocusExpressionRef.current = true;
|
|
595
|
+
}
|
|
596
|
+
useRetriedFocus(shouldFocusExpressionRef, isShown, () => controlRef.current?.ownerDocument.getElementById(expressionId) ?? null, CRON_INPUT_FOCUS_RETRY_FRAMES);
|
|
597
|
+
const close = () => setOpen(false);
|
|
598
|
+
useRestoreFocusAfterOutsidePress({
|
|
599
|
+
isShown,
|
|
600
|
+
focusRef: controlRef,
|
|
601
|
+
insideRefs: [wrapperRef, panelRef],
|
|
602
|
+
focusScopeRefs: [panelRef]
|
|
603
|
+
});
|
|
412
604
|
const { frequency, parts } = builder;
|
|
413
605
|
/** Applies new parts in the current builder frequency and writes the expression. */
|
|
414
606
|
const updateParts = (next) => {
|
|
@@ -437,46 +629,65 @@ function CronGroup({ cronProps, forwardedRef, isRoot }) {
|
|
|
437
629
|
if (isOn && parts.weekdays.length === 1) return;
|
|
438
630
|
updateParts({ weekdays: isOn ? parts.weekdays.filter((selected) => selected !== day) : [...parts.weekdays, day].sort((a, b) => a - b) });
|
|
439
631
|
};
|
|
632
|
+
/** The field's keys: Enter, Space, ArrowDown and Alt+ArrowDown open the panel. */
|
|
633
|
+
const handleControlKeyDown = (event) => {
|
|
634
|
+
if (event.defaultPrevented || !isEditable || isShown) return;
|
|
635
|
+
if (event.key === "Enter" || event.key === " " || event.key === "ArrowDown") {
|
|
636
|
+
event.preventDefault();
|
|
637
|
+
setOpen(true);
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
const handleControlClick = () => {
|
|
641
|
+
if (!isEditable) return;
|
|
642
|
+
setOpen(!isShown);
|
|
643
|
+
};
|
|
644
|
+
/** Focus leaving both the field and the panel for another element closes the panel. */
|
|
645
|
+
const handleFocusOut = (event) => {
|
|
646
|
+
if (!isShownRef.current) return;
|
|
647
|
+
const next = event.relatedTarget;
|
|
648
|
+
if (next === null) return;
|
|
649
|
+
if (panelRef.current?.contains(next) || controlRef.current?.contains(next)) return;
|
|
650
|
+
close();
|
|
651
|
+
};
|
|
652
|
+
const clear = () => {
|
|
653
|
+
commit("");
|
|
654
|
+
if (isShown) close();
|
|
655
|
+
controlRef.current?.focus();
|
|
656
|
+
};
|
|
440
657
|
const trimmed = expression.trim();
|
|
441
658
|
const sentence = useMemo(() => describe(trimmed), [trimmed]);
|
|
442
|
-
|
|
659
|
+
const hasValue = trimmed !== "";
|
|
660
|
+
useDevWarning(!hasName, "[@galaxy-io/dls] CronInput has no accessible name. Pass `label`, wrap it in a labelled `Field`, or set `ariaLabel`. `placeholder` is not a name.");
|
|
443
661
|
const textSize = CRON_INPUT_SIZE_TO_TEXT_SIZE_MAP[size];
|
|
444
|
-
const
|
|
445
|
-
const selectSize = CRON_INPUT_SIZE_TO_SELECT_INPUT_SIZE_MAP[size];
|
|
446
|
-
const selectVariant = CRON_INPUT_VARIANT_TO_SELECT_INPUT_VARIANT_MAP[variant];
|
|
447
|
-
const controlState = {
|
|
448
|
-
isDisabled,
|
|
449
|
-
isReadOnly,
|
|
450
|
-
isError: isInvalid,
|
|
451
|
-
isRequired: isRequiredState
|
|
452
|
-
};
|
|
662
|
+
const isClearHidden = !hasValue || !isEditable;
|
|
453
663
|
const rowLabel = (row) => /* @__PURE__ */ jsx(Text, {
|
|
454
664
|
as: "span",
|
|
455
665
|
id: rowLabelId(row),
|
|
456
|
-
size:
|
|
457
|
-
variant:
|
|
666
|
+
size: TextSize.BODY_SM,
|
|
667
|
+
variant: TextVariant.SECONDARY,
|
|
458
668
|
children: ROW_LABELS[row]
|
|
459
669
|
});
|
|
460
670
|
/** A two-digit select named by its row label (plus its own name inside a time row). */
|
|
461
671
|
const numberSelect = (row, part, options, ownName) => {
|
|
462
672
|
const selectId = `${rowLabelId(row)}-${part}`;
|
|
463
|
-
return /* @__PURE__ */ jsx(
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
"aria-labelledby":
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
673
|
+
return /* @__PURE__ */ jsx(Box, {
|
|
674
|
+
width: CRON_INPUT_SELECT_WIDTH,
|
|
675
|
+
children: /* @__PURE__ */ jsx(SelectInput, {
|
|
676
|
+
id: selectId,
|
|
677
|
+
...ownName === void 0 ? { "aria-labelledby": rowLabelId(row) } : {
|
|
678
|
+
ariaLabel: ownName,
|
|
679
|
+
"aria-labelledby": `${rowLabelId(row)} ${selectId}`
|
|
680
|
+
},
|
|
681
|
+
options,
|
|
682
|
+
value: String(parts[part]),
|
|
683
|
+
onChange: (next) => {
|
|
684
|
+
if (next !== null) updateParts({ [part]: Number(next) });
|
|
685
|
+
},
|
|
686
|
+
size: SelectInputSize.SMALL,
|
|
687
|
+
variant: SelectInputVariant.SECONDARY,
|
|
688
|
+
fillWidth: true
|
|
689
|
+
})
|
|
690
|
+
});
|
|
480
691
|
};
|
|
481
692
|
const timeRow = /* @__PURE__ */ jsxs(Fragment$1, { children: [rowLabel("time"), /* @__PURE__ */ jsxs(Flex, {
|
|
482
693
|
alignItems: AlignItems.CENTER,
|
|
@@ -485,7 +696,7 @@ function CronGroup({ cronProps, forwardedRef, isRoot }) {
|
|
|
485
696
|
numberSelect("time", "hour", HOUR_OPTIONS, "Hour"),
|
|
486
697
|
/* @__PURE__ */ jsx(Text, {
|
|
487
698
|
as: "span",
|
|
488
|
-
size:
|
|
699
|
+
size: TextSize.BODY_SM,
|
|
489
700
|
variant: TextVariant.TERTIARY,
|
|
490
701
|
"aria-hidden": true,
|
|
491
702
|
children: ":"
|
|
@@ -493,98 +704,179 @@ function CronGroup({ cronProps, forwardedRef, isRoot }) {
|
|
|
493
704
|
numberSelect("time", "minute", MINUTE_OPTIONS, "Minute")
|
|
494
705
|
]
|
|
495
706
|
})] });
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
707
|
+
const hasPresets = presets.length > 0;
|
|
708
|
+
const normalized = normalize(expression);
|
|
709
|
+
const body = /* @__PURE__ */ jsx(FieldContext.Provider, {
|
|
710
|
+
value: null,
|
|
711
|
+
children: /* @__PURE__ */ jsxs(PanelBody, {
|
|
712
|
+
onBlur: handleFocusOut,
|
|
713
|
+
children: [/* @__PURE__ */ jsxs(PanelMain, { children: [hasPresets && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(PresetList, {
|
|
714
|
+
role: "group",
|
|
715
|
+
"aria-label": "Presets",
|
|
716
|
+
children: presets.map((preset) => {
|
|
717
|
+
const isPresetSelected = normalize(preset.value) === normalized;
|
|
718
|
+
return /* @__PURE__ */ jsx(PresetButton, {
|
|
719
|
+
type: "button",
|
|
720
|
+
"aria-pressed": isPresetSelected,
|
|
721
|
+
onClick: () => {
|
|
722
|
+
commit(preset.value);
|
|
723
|
+
close();
|
|
724
|
+
},
|
|
725
|
+
className: cx(isPresetSelected && SELECTED_PRESET_CSS),
|
|
726
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
727
|
+
as: "span",
|
|
728
|
+
size: TextSize.BODY_SM,
|
|
729
|
+
variant: isPresetSelected ? TextVariant.PRIMARY : TextVariant.SECONDARY,
|
|
730
|
+
children: preset.label
|
|
731
|
+
})
|
|
732
|
+
}, preset.label);
|
|
733
|
+
})
|
|
734
|
+
}), /* @__PURE__ */ jsx(Divider, { orientation: Orientation.VERTICAL })] }), /* @__PURE__ */ jsxs(Rows, { children: [
|
|
735
|
+
/* @__PURE__ */ jsxs(LabelStack, { children: [rowLabel("frequency"), Object.entries(ROW_LABELS).map(([row, text]) => row === "frequency" ? null : /* @__PURE__ */ jsx(Text, {
|
|
736
|
+
as: "span",
|
|
737
|
+
size: TextSize.BODY_SM,
|
|
738
|
+
className: LABEL_SIZER_CSS,
|
|
739
|
+
"aria-hidden": true,
|
|
740
|
+
children: text
|
|
741
|
+
}, row))] }),
|
|
742
|
+
/* @__PURE__ */ jsx(ToggleInput, {
|
|
743
|
+
options: FREQUENCY_OPTIONS,
|
|
744
|
+
value: frequency,
|
|
745
|
+
onChange: changeFrequency,
|
|
746
|
+
size: ToggleInputSize.SMALL,
|
|
747
|
+
variant: ToggleInputVariant.SECONDARY,
|
|
748
|
+
"aria-labelledby": rowLabelId("frequency")
|
|
749
|
+
}),
|
|
750
|
+
frequency === "HOURLY" && /* @__PURE__ */ jsxs(Fragment$1, { children: [rowLabel("minute"), numberSelect("minute", "minute", MINUTE_OPTIONS)] }),
|
|
751
|
+
frequency === "DAILY" && timeRow,
|
|
752
|
+
frequency === "WEEKLY" && /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
753
|
+
rowLabel("weekdays"),
|
|
754
|
+
/* @__PURE__ */ jsx(ButtonGroup, {
|
|
755
|
+
isAttached: true,
|
|
756
|
+
"aria-labelledby": rowLabelId("weekdays"),
|
|
757
|
+
children: WEEKDAYS.map(({ day, label, name }) => /* @__PURE__ */ jsx(Button, {
|
|
758
|
+
variant: ButtonVariant.SECONDARY,
|
|
759
|
+
size: ButtonSize.SMALL,
|
|
760
|
+
label,
|
|
761
|
+
ariaLabel: name,
|
|
762
|
+
isActive: parts.weekdays.includes(day),
|
|
763
|
+
onClick: () => toggleWeekday(day)
|
|
764
|
+
}, day))
|
|
765
|
+
}),
|
|
766
|
+
timeRow
|
|
767
|
+
] }),
|
|
768
|
+
frequency === "MONTHLY" && /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
769
|
+
rowLabel("day"),
|
|
770
|
+
numberSelect("day", "dayOfMonth", DAY_OF_MONTH_OPTIONS),
|
|
771
|
+
timeRow
|
|
772
|
+
] }),
|
|
773
|
+
/* @__PURE__ */ jsx(RowSpan, { children: /* @__PURE__ */ jsx(Divider, {}) }),
|
|
774
|
+
rowLabel("expression"),
|
|
775
|
+
/* @__PURE__ */ jsx(ExpressionSlot, { children: /* @__PURE__ */ jsx(TextInput, {
|
|
776
|
+
id: expressionId,
|
|
777
|
+
"aria-labelledby": rowLabelId("expression"),
|
|
778
|
+
"aria-describedby": `${panelId}-sentence`,
|
|
779
|
+
family: FontFamily.MONO,
|
|
780
|
+
placeholder: "*/15 * * * *",
|
|
781
|
+
spellCheck: false,
|
|
782
|
+
value: expression,
|
|
783
|
+
onChange: (next) => {
|
|
784
|
+
if (isEditable) commit(next);
|
|
785
|
+
},
|
|
786
|
+
onEnter: close,
|
|
787
|
+
size: InputSize.SMALL,
|
|
788
|
+
variant: InputVariant.SECONDARY,
|
|
789
|
+
isError: isInvalid,
|
|
790
|
+
fillWidth: true
|
|
791
|
+
}) })
|
|
792
|
+
] })] }), /* @__PURE__ */ jsxs(Summary, { children: [/* @__PURE__ */ jsx(SummaryIcon, { children: /* @__PURE__ */ jsx(Icon, {
|
|
793
|
+
component: ClockIcon,
|
|
794
|
+
size: 12,
|
|
795
|
+
variant: sentence === null ? IconVariant.TERTIARY : IconVariant.SECONDARY,
|
|
796
|
+
"aria-hidden": true
|
|
797
|
+
}) }), /* @__PURE__ */ jsx(Text, {
|
|
798
|
+
as: "p",
|
|
799
|
+
id: `${panelId}-sentence`,
|
|
800
|
+
size: TextSize.BODY_SM,
|
|
801
|
+
variant: sentence === null ? TextVariant.TERTIARY : TextVariant.PRIMARY,
|
|
802
|
+
children: sentence ?? CRON_INPUT_HINT
|
|
803
|
+
})] })]
|
|
804
|
+
})
|
|
805
|
+
});
|
|
806
|
+
const labelId = field?.labelId;
|
|
807
|
+
return /* @__PURE__ */ jsxs(Wrapper, {
|
|
808
|
+
ref: wrapperRef,
|
|
809
|
+
className: cx(WIDTH_CSS, fillWidth && FILL_WIDTH_CSS, isRoot ? className : void 0),
|
|
505
810
|
...rootStyle(isRoot, style),
|
|
506
|
-
children: [
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
811
|
+
children: [
|
|
812
|
+
/* @__PURE__ */ jsx(Popover, {
|
|
813
|
+
ref: panelRef,
|
|
814
|
+
trigger: PopoverTrigger.MANUAL,
|
|
815
|
+
role: PopoverRole.DIALOG,
|
|
816
|
+
variant: isGhost ? PopoverVariant.BASE : CRON_INPUT_VARIANT_TO_POPOVER_VARIANT_MAP[variant],
|
|
817
|
+
isOpen: isShown,
|
|
818
|
+
onOpenChange: setOpen,
|
|
819
|
+
isDisabled: !isEditable,
|
|
820
|
+
id: panelId,
|
|
821
|
+
ariaLabel: "Choose schedule",
|
|
822
|
+
body: /* @__PURE__ */ jsx(BareFieldContext.Provider, {
|
|
823
|
+
value: false,
|
|
824
|
+
children: body
|
|
825
|
+
}),
|
|
826
|
+
children: /* @__PURE__ */ jsx(Control, {
|
|
827
|
+
ref: mergedRef,
|
|
828
|
+
id: controlId,
|
|
829
|
+
role: "combobox",
|
|
830
|
+
tabIndex: isDisabled ? -1 : 0,
|
|
831
|
+
"aria-labelledby": labelId,
|
|
832
|
+
"aria-label": ariaLabel,
|
|
833
|
+
"aria-describedby": describedBy,
|
|
834
|
+
"aria-invalid": isInvalid ? true : void 0,
|
|
835
|
+
"aria-required": isRequiredState ? true : void 0,
|
|
836
|
+
"aria-readonly": isReadOnly ? true : void 0,
|
|
837
|
+
"aria-disabled": isDisabled ? true : void 0,
|
|
838
|
+
onKeyDown: handleControlKeyDown,
|
|
839
|
+
onClick: handleControlClick,
|
|
840
|
+
onBlur: handleFocusOut,
|
|
841
|
+
...rest,
|
|
842
|
+
className: cx(isGhost ? GHOST_CSS : CRON_INPUT_VARIANT_TO_CSS_MAP[variant], CRON_INPUT_SIZE_TO_CSS_MAP[size], isClearable && CRON_INPUT_SIZE_TO_CLEARABLE_CSS_MAP[size], isEditable && !isInvalid && (isGhost ? GHOST_HOVER_CSS : CRON_INPUT_VARIANT_TO_HOVER_CSS_MAP[variant]), !isDisabled && FOCUS_CSS, isShown && OPEN_CSS, isInvalid && !isDisabled && ERROR_CSS, isDisabled && DISABLED_CSS, isReadOnly && READ_ONLY_CSS, isBare && "gx-bareField-BARE_FIELD_CSS-b1memido"),
|
|
843
|
+
children: /* @__PURE__ */ jsx(ValueDisplay, { children: /* @__PURE__ */ jsx(Text, {
|
|
512
844
|
as: "span",
|
|
513
845
|
size: textSize,
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
isDisabled,
|
|
544
|
-
fillWidth,
|
|
545
|
-
...isReadOnly ? { "aria-disabled": true } : {},
|
|
546
|
-
onClick: () => toggleWeekday(day)
|
|
547
|
-
}, day))
|
|
548
|
-
}),
|
|
549
|
-
timeRow
|
|
550
|
-
] }),
|
|
551
|
-
frequency === "MONTHLY" && /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
552
|
-
rowLabel("day"),
|
|
553
|
-
numberSelect("day", "dayOfMonth", DAY_OF_MONTH_OPTIONS),
|
|
554
|
-
timeRow
|
|
555
|
-
] }),
|
|
556
|
-
frequency === "CUSTOM" && /* @__PURE__ */ jsxs(Fragment$1, { children: [rowLabel("expression"), /* @__PURE__ */ jsx(ExpressionSlot, {
|
|
557
|
-
className: cx(fillWidth && EXPRESSION_FILL_CSS),
|
|
558
|
-
children: /* @__PURE__ */ jsx(TextInput, {
|
|
559
|
-
"aria-labelledby": rowLabelId("expression"),
|
|
560
|
-
family: FontFamily.MONO,
|
|
561
|
-
placeholder: "*/15 * * * *",
|
|
562
|
-
spellCheck: false,
|
|
563
|
-
value: expression,
|
|
564
|
-
onChange: (next) => {
|
|
565
|
-
if (!isEditable) return;
|
|
566
|
-
lastEmittedRef.current = next;
|
|
567
|
-
setExpression(next);
|
|
568
|
-
},
|
|
569
|
-
size: CRON_INPUT_SIZE_TO_INPUT_SIZE_MAP[size],
|
|
570
|
-
variant: CRON_INPUT_VARIANT_TO_INPUT_VARIANT_MAP[variant],
|
|
571
|
-
isGhost,
|
|
572
|
-
fillWidth: true,
|
|
573
|
-
...controlState
|
|
574
|
-
})
|
|
575
|
-
})] })
|
|
576
|
-
]
|
|
846
|
+
...hasValue ? { family: FontFamily.MONO } : {},
|
|
847
|
+
variant: isDisabled ? TextVariant.DISABLED : hasValue ? TextVariant.PRIMARY : TextVariant.TERTIARY,
|
|
848
|
+
lineClamp: 1,
|
|
849
|
+
children: hasValue ? trimmed : placeholder
|
|
850
|
+
}) })
|
|
851
|
+
})
|
|
852
|
+
}),
|
|
853
|
+
/* @__PURE__ */ jsx(VisuallyHidden, {
|
|
854
|
+
id: summaryId,
|
|
855
|
+
children: hasValue ? sentence ?? "" : ""
|
|
856
|
+
}),
|
|
857
|
+
/* @__PURE__ */ jsxs(Trailing, {
|
|
858
|
+
className: CRON_INPUT_SIZE_TO_TRAILING_CSS_MAP[size],
|
|
859
|
+
children: [isClearable && /* @__PURE__ */ jsx(ClearSlot, {
|
|
860
|
+
className: cx(isClearHidden && CLEAR_HIDDEN_CSS),
|
|
861
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
862
|
+
variant: ButtonVariant.TERTIARY,
|
|
863
|
+
size: CRON_INPUT_SIZE_TO_BUTTON_SIZE_MAP[size],
|
|
864
|
+
icon: XIcon,
|
|
865
|
+
ariaLabel: "Clear",
|
|
866
|
+
onClick: clear,
|
|
867
|
+
className: cx(size === "X_SMALL" && "gx-innerButton-X_SMALL_INNER_BUTTON_CSS-x1ep0pcd")
|
|
868
|
+
})
|
|
869
|
+
}), /* @__PURE__ */ jsx(Icon, {
|
|
870
|
+
component: ClockIcon,
|
|
871
|
+
size: CRON_INPUT_SIZE_TO_ICON_PX_MAP[size],
|
|
872
|
+
variant: isDisabled ? IconVariant.DISABLED : IconVariant.SECONDARY,
|
|
873
|
+
"aria-hidden": true
|
|
874
|
+
})]
|
|
577
875
|
})
|
|
578
|
-
|
|
579
|
-
as: "p",
|
|
580
|
-
id: previewId,
|
|
581
|
-
size: helpSize,
|
|
582
|
-
variant: isDisabled ? TextVariant.DISABLED : sentence === null ? TextVariant.TERTIARY : TextVariant.SECONDARY,
|
|
583
|
-
children: sentence ?? CRON_INPUT_HINT
|
|
584
|
-
})]
|
|
876
|
+
]
|
|
585
877
|
});
|
|
586
878
|
}
|
|
587
|
-
/** A five-field cron expression
|
|
879
|
+
/** A five-field cron expression in a field that opens presets and a schedule builder. */
|
|
588
880
|
var CronInput = forwardRef(function CronInput(props, ref) {
|
|
589
881
|
const { label, error, isRequired = false, size = "MEDIUM", fillWidth = false } = props;
|
|
590
882
|
const { id, className, style } = props;
|
|
@@ -601,13 +893,13 @@ var CronInput = forwardRef(function CronInput(props, ref) {
|
|
|
601
893
|
});
|
|
602
894
|
if (ownField !== null) return /* @__PURE__ */ jsx(Field, {
|
|
603
895
|
...ownField,
|
|
604
|
-
children: /* @__PURE__ */ jsx(
|
|
896
|
+
children: /* @__PURE__ */ jsx(CronInputFrame, {
|
|
605
897
|
cronProps: props,
|
|
606
898
|
forwardedRef: ref,
|
|
607
899
|
isRoot: false
|
|
608
900
|
})
|
|
609
901
|
});
|
|
610
|
-
return /* @__PURE__ */ jsx(
|
|
902
|
+
return /* @__PURE__ */ jsx(CronInputFrame, {
|
|
611
903
|
cronProps: props,
|
|
612
904
|
forwardedRef: ref,
|
|
613
905
|
isRoot: true
|