@galaxy-io/dls 2.1.0 → 2.2.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.
@@ -1,3 +1,4 @@
1
+ import { type Icon as PhosphorIcon } from "@phosphor-icons/react";
1
2
  import { type AriaAttributes, type CSSProperties, type ReactNode } from "react";
2
3
  import { Side } from "../theme/enums.js";
3
4
  /**
@@ -67,8 +68,12 @@ interface DrawerBaseProps extends AriaAttributes {
67
68
  }
68
69
  /** A title row names the drawer. */
69
70
  interface DrawerTitledProps {
70
- /** The title row. A string renders as an `h2` `Text` and names the drawer; a node renders as it is. Required unless `ariaLabel` is set. */
71
+ /** The title row. A string renders as an `h2` `Text` and names the drawer; a node renders as it is, in a first line one control tall. Required unless `ariaLabel` is set. */
71
72
  header: ReactNode;
73
+ /** A secondary line under the title (the connector, the run's pipeline). Describes the drawer. */
74
+ subheader?: string | undefined;
75
+ /** A leading icon before the title. Pass the component, not an element. */
76
+ icon?: PhosphorIcon | undefined;
72
77
  /** Accessible name. Required by type when there is no `header`. */
73
78
  ariaLabel?: string;
74
79
  }
@@ -76,6 +81,10 @@ interface DrawerTitledProps {
76
81
  interface DrawerUntitledProps {
77
82
  /** The title row. A string renders as an `h2` `Text` and names the drawer; a node renders as it is. Required unless `ariaLabel` is set. */
78
83
  header?: undefined;
84
+ /** A secondary line under the title. Needs `header`. */
85
+ subheader?: undefined;
86
+ /** A leading icon before the title. Needs `header`. */
87
+ icon?: undefined;
79
88
  /** Accessible name. Required by type when there is no `header`. */
80
89
  ariaLabel: string;
81
90
  }
@@ -1,15 +1,17 @@
1
1
  import FocusScope, { FocusScopeAutoFocus } from "../a11y/FocusScope.js";
2
2
  import { Orientation, Side } from "../theme/enums.js";
3
- import Text, { TextSize, TextWeight } from "../text/Text.js";
3
+ import Text from "../text/Text.js";
4
4
  import { DURATION, SPACE } from "../theme/tokens/scales.js";
5
5
  import { useControlledOpenState } from "../hooks/useControlledOpenState.js";
6
6
  import Portal from "../layout/Portal.js";
7
7
  import { OverlayLayer, useOverlay } from "../overlay/useOverlay.js";
8
8
  import { usePrefersReducedMotion } from "../hooks/usePrefersReducedMotion.js";
9
+ import { OVERLAY_CONTENT_SHOWN, withContentFirstExit } from "../overlay/internal/contentFirstExit.js";
9
10
  import { OverlayNode } from "../overlay/OverlayProvider.js";
10
11
  import Button, { ButtonSize, ButtonVariant } from "../buttons/Button.js";
11
12
  import { isDevelopment, useDevWarning } from "../inputs/internal/devWarn.js";
12
13
  import ResizeHandle from "../layout/ResizeHandle.js";
14
+ import OverlayTitleRow from "../overlay/internal/OverlayTitleRow.js";
13
15
  import Fade from "../transform/Fade.js";
14
16
  /* empty css */
15
17
  import { styled } from "@linaria/react";
@@ -131,7 +133,8 @@ var DRAWER_OPEN = {
131
133
  opacity: 1,
132
134
  x: 0,
133
135
  y: 0,
134
- pointerEvents: "auto"
136
+ pointerEvents: "auto",
137
+ ...OVERLAY_CONTENT_SHOWN
135
138
  };
136
139
  /**
137
140
  * Scroll lock: while any drawer backdrop is mounted (open or exiting) the page does not scroll.
@@ -176,44 +179,21 @@ var DRAWER_PUSH_PANEL_SIDE_TO_CSS_MAP = {
176
179
  [Side.TOP]: "gx-Drawer-Side_TOP-s1smajqi",
177
180
  [Side.BOTTOM]: "gx-Drawer-Side_BOTTOM-s3tnyde"
178
181
  };
179
- var Header = /*#__PURE__*/ styled("div")({
180
- name: "Header",
181
- class: "gx-Drawer-Header-h45j7yl",
182
- propsAsIs: false
183
- });
184
- /** While the close button shows: a long title never runs under it. */
185
- var HAS_CLOSE_CSS = "gx-Drawer-HAS_CLOSE_CSS-hov58xm";
186
- /** With `actions`, the close button joins them: the same 4px apart, one group at the row's end. */
187
- var HAS_CLOSE_WITH_ACTIONS_CSS = "gx-Drawer-HAS_CLOSE_WITH_ACTIONS_CSS-hckczr5";
188
- /** A node `header`: takes the row and may shrink. */
189
- var HeaderNode = /*#__PURE__*/ styled("div")({
190
- name: "HeaderNode",
191
- class: "gx-Drawer-HeaderNode-h1v64nx4",
192
- propsAsIs: false
193
- });
194
- /** A string `header` takes the row too, so `actions` sit at its end. */
195
- var HEADER_TITLE_CSS = "gx-Drawer-HEADER_TITLE_CSS-ht6k1c3";
196
- /** `actions`: at the end of the title row, 4px apart and 4px before the close button. */
197
- var HeaderActions = /*#__PURE__*/ styled("div")({
198
- name: "HeaderActions",
199
- class: "gx-Drawer-HeaderActions-h15lcrsa",
200
- propsAsIs: false
201
- });
202
182
  /** More header controls than this crowd the title: the rest belong in the ⋯ menu. */
203
183
  var DRAWER_MAX_HEADER_ACTIONS = 3;
204
184
  var Body = /*#__PURE__*/ styled("div")({
205
185
  name: "Body",
206
- class: "gx-Drawer-Body-b1ob4oh8",
186
+ class: "gx-Drawer-Body-b45j7yl",
207
187
  propsAsIs: false
208
188
  });
209
189
  var Footer = /*#__PURE__*/ styled("div")({
210
190
  name: "Footer",
211
- class: "gx-Drawer-Footer-f14nwavk",
191
+ class: "gx-Drawer-Footer-fov58xm",
212
192
  propsAsIs: false
213
193
  });
214
194
  var CloseSlot = /*#__PURE__*/ styled("span")({
215
195
  name: "CloseSlot",
216
- class: "gx-Drawer-CloseSlot-c1ifjfam",
196
+ class: "gx-Drawer-CloseSlot-cckczr5",
217
197
  propsAsIs: false
218
198
  });
219
199
  /**
@@ -222,21 +202,23 @@ var CloseSlot = /*#__PURE__*/ styled("span")({
222
202
  * the stylesheet.
223
203
  */
224
204
  var DRAWER_SIDE_TO_HANDLE_CSS_MAP = {
225
- [Side.RIGHT]: "gx-Drawer-Side_RIGHT-sv6fh8e",
226
- [Side.LEFT]: "gx-Drawer-Side_LEFT-s1c8bwjq",
227
- [Side.TOP]: "gx-Drawer-Side_TOP-s1vq4aq7",
228
- [Side.BOTTOM]: "gx-Drawer-Side_BOTTOM-svqv727"
205
+ [Side.RIGHT]: "gx-Drawer-Side_RIGHT-s1v64nx4",
206
+ [Side.LEFT]: "gx-Drawer-Side_LEFT-st6k1c3",
207
+ [Side.TOP]: "gx-Drawer-Side_TOP-s15lcrsa",
208
+ [Side.BOTTOM]: "gx-Drawer-Side_BOTTOM-s1ob4oh8"
229
209
  };
230
210
  /** The viewport length on the side's axis, less the 48px strip. */
231
211
  function readMaxSize(side) {
232
212
  return (DRAWER_SIDE_TO_IS_HORIZONTAL_MAP[side] ? window.innerWidth : window.innerHeight) - DRAWER_VIEWPORT_GAP_PX;
233
213
  }
234
214
  /** A panel that slides in from an edge: title row, scrolling body, actions row. */
235
- var Drawer = forwardRef(function Drawer({ children, header, footer, actions, side = Side.RIGHT, size = "MEDIUM", isResizable = false, isModal = true, isDismissable = true, isOpen: isOpenProp, defaultIsOpen = false, onOpenChange, ariaLabel, id, className, style, ...rest }, ref) {
215
+ var Drawer = forwardRef(function Drawer({ children, header, subheader, icon, footer, actions, side = Side.RIGHT, size = "MEDIUM", isResizable = false, isModal = true, isDismissable = true, isOpen: isOpenProp, defaultIsOpen = false, onOpenChange, ariaLabel, id, className, style, ...rest }, ref) {
236
216
  const generatedId = useId();
237
217
  const titleId = useId();
218
+ const subheaderId = useId();
238
219
  const panelId = id ?? generatedId;
239
- const transition = usePrefersReducedMotion() ? DRAWER_REDUCED_TRANSITION : DRAWER_TRANSITION;
220
+ const prefersReducedMotion = usePrefersReducedMotion();
221
+ const transition = prefersReducedMotion ? DRAWER_REDUCED_TRANSITION : DRAWER_TRANSITION;
240
222
  const { isOpen, setOpen } = useControlledOpenState({
241
223
  isOpen: isOpenProp,
242
224
  defaultIsOpen,
@@ -288,24 +270,18 @@ var Drawer = forwardRef(function Drawer({ children, header, footer, actions, sid
288
270
  }, [isOpen, actions]);
289
271
  useDevWarning(actionCount > DRAWER_MAX_HEADER_ACTIONS, "[@galaxy-io/dls] Drawer has more than three header `actions`. Keep one or two icon buttons and a ⋯ Menu, and move the rest into the menu.");
290
272
  const labelling = ariaLabel !== void 0 ? { "aria-label": ariaLabel } : rest["aria-labelledby"] !== void 0 || header === void 0 ? {} : { "aria-labelledby": titleId };
273
+ const describing = subheader !== void 0 && header !== void 0 && rest["aria-describedby"] === void 0 ? { "aria-describedby": subheaderId } : {};
291
274
  const sizeStyle = { "--gx-drawer-size": `${currentSize}px` };
292
275
  const regions = /* @__PURE__ */ jsxs(Fragment$1, { children: [
293
- hasHeaderRow && /* @__PURE__ */ jsxs(Header, {
294
- className: cx(isDismissable && (actions === void 0 ? HAS_CLOSE_CSS : HAS_CLOSE_WITH_ACTIONS_CSS)),
295
- children: [typeof header === "string" ? /* @__PURE__ */ jsx(Text, {
296
- as: "h2",
297
- size: TextSize.BODY_LG,
298
- weight: TextWeight.MEDIUM,
299
- id: titleId,
300
- className: HEADER_TITLE_CSS,
301
- children: header
302
- }) : header !== void 0 ? /* @__PURE__ */ jsx(HeaderNode, {
303
- id: titleId,
304
- children: header
305
- }) : /* @__PURE__ */ jsx(HeaderNode, {}), actions !== void 0 && /* @__PURE__ */ jsx(HeaderActions, {
306
- ref: actionsRef,
307
- children: actions
308
- })]
276
+ hasHeaderRow && /* @__PURE__ */ jsx(OverlayTitleRow, {
277
+ header,
278
+ subheader,
279
+ icon,
280
+ actions,
281
+ actionsRef,
282
+ titleId,
283
+ subheaderId,
284
+ hasClose: isDismissable
309
285
  }),
310
286
  /* @__PURE__ */ jsx(Body, { children: typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsx(Text, { children }) : children }),
311
287
  footer !== void 0 && /* @__PURE__ */ jsx(Footer, { children: footer }),
@@ -331,9 +307,15 @@ var Drawer = forwardRef(function Drawer({ children, header, footer, actions, sid
331
307
  if (!isModal) return /* @__PURE__ */ jsx(AnimatePresence, {
332
308
  initial: false,
333
309
  children: isOpen && /* @__PURE__ */ jsx(motion.div, {
334
- initial: DRAWER_SIDE_TO_PUSH_COLLAPSED_MAP[side],
335
- animate: DRAWER_SIDE_TO_PUSH_OPEN_MAP[side],
336
- exit: DRAWER_SIDE_TO_PUSH_COLLAPSED_MAP[side],
310
+ initial: {
311
+ ...DRAWER_SIDE_TO_PUSH_COLLAPSED_MAP[side],
312
+ ...OVERLAY_CONTENT_SHOWN
313
+ },
314
+ animate: {
315
+ ...DRAWER_SIDE_TO_PUSH_OPEN_MAP[side],
316
+ ...OVERLAY_CONTENT_SHOWN
317
+ },
318
+ exit: withContentFirstExit(DRAWER_SIDE_TO_PUSH_COLLAPSED_MAP[side], prefersReducedMotion),
337
319
  transition,
338
320
  className: cx(PUSH_ROOT_CSS, DRAWER_PUSH_SIDE_TO_CSS_MAP[side]),
339
321
  children: /* @__PURE__ */ jsx(FocusScope, {
@@ -343,6 +325,7 @@ var Drawer = forwardRef(function Drawer({ children, header, footer, actions, sid
343
325
  children: /* @__PURE__ */ jsx(Panel, {
344
326
  ...rest,
345
327
  ...labelling,
328
+ ...describing,
346
329
  ref,
347
330
  id: panelId,
348
331
  role: "region",
@@ -381,9 +364,12 @@ var Drawer = forwardRef(function Drawer({ children, header, footer, actions, sid
381
364
  }), /* @__PURE__ */ jsx(AnimatePresence, {
382
365
  initial: shouldAnimateOnMount,
383
366
  children: isOpen && /* @__PURE__ */ jsx(motion.div, {
384
- initial: closed,
367
+ initial: {
368
+ ...closed,
369
+ ...OVERLAY_CONTENT_SHOWN
370
+ },
385
371
  animate: DRAWER_OPEN,
386
- exit: closed,
372
+ exit: withContentFirstExit(closed, prefersReducedMotion),
387
373
  transition,
388
374
  className: cx(FRAME_CSS, DRAWER_SIDE_TO_CSS_MAP[side]),
389
375
  style: frameStyle,
@@ -393,6 +379,7 @@ var Drawer = forwardRef(function Drawer({ children, header, footer, actions, sid
393
379
  children: /* @__PURE__ */ jsx(Panel, {
394
380
  ...rest,
395
381
  ...labelling,
382
+ ...describing,
396
383
  ref,
397
384
  id: panelId,
398
385
  role: "dialog",
@@ -1,18 +1,18 @@
1
1
  import { type AriaAttributes, type CSSProperties } from "react";
2
- /** Canonical rungs; CronInput supports all five and passes the rung to every control it renders. */
2
+ /** Canonical rungs; CronInput supports all five (the Input rung table). */
3
3
  export declare enum CronInputSize {
4
- /** 20px controls, caption text. */
4
+ /** 20px field, caption text, 12px icon. */
5
5
  X_SMALL = "X_SMALL",
6
- /** 24px controls, body_sm text. */
6
+ /** 24px field, body_sm text, 12px icon. */
7
7
  SMALL = "SMALL",
8
- /** 32px controls, body_md text. The default. */
8
+ /** 32px field, body_md text, 14px icon. The default. */
9
9
  MEDIUM = "MEDIUM",
10
- /** 36px controls, body_lg text. */
10
+ /** 36px field, body_lg text, 14px icon. */
11
11
  LARGE = "LARGE",
12
- /** 40px controls, body_lg text. */
12
+ /** 40px field, body_lg text, 16px icon. */
13
13
  X_LARGE = "X_LARGE"
14
14
  }
15
- /** Resting fill of the builder's controls (Constitution V-A surface set). */
15
+ /** Resting fill of the field (Constitution V-A surface set). */
16
16
  export declare enum CronInputVariant {
17
17
  /** `background.base` fill. */
18
18
  BASE = "BASE",
@@ -23,72 +23,106 @@ export declare enum CronInputVariant {
23
23
  /** `background.tertiary` fill. */
24
24
  TERTIARY = "TERTIARY"
25
25
  }
26
+ /** One named schedule in the presets column. */
27
+ export interface CronInputPreset {
28
+ /** Text of the preset row ("Weekdays at 09:00"). */
29
+ label: string;
30
+ /** The five-field expression the preset sets. */
31
+ value: string;
32
+ }
26
33
  export interface CronInputProps extends AriaAttributes {
27
- /** Controlled five-field cron expression. Pass it with `onChange`. */
34
+ /** Controlled five-field cron expression. An empty string shows the placeholder. Pass it with `onChange`. */
28
35
  value?: string;
29
36
  /**
30
37
  * Initial expression while uncontrolled (daily at 00:00).
31
38
  * @default 0 0 * * *
32
39
  */
33
40
  defaultValue?: string;
34
- /** Called with the new expression on every builder change and every keystroke in the Custom field. */
41
+ /** Called with the new expression on every builder change, every keystroke in the expression field, a preset, and with `""` when the clear button is pressed. */
35
42
  onChange?: (value: string) => void;
36
43
  /**
37
- * Rung of every control in the builder: 20 / 24 / 32 / 36 / 40px.
44
+ * Named schedules shown in a column beside the builder. Choosing one sets the value and closes the panel. Pass `[]` to hide the column.
45
+ * @default Every 5 minutes, Every 15 minutes, Hourly, Daily at midnight, Weekdays at 09:00, Weekly on Monday, Monthly on the 1st
46
+ */
47
+ presets?: CronInputPreset[];
48
+ /**
49
+ * Control rung: 20 / 24 / 32 / 36 / 40px tall. The schedule panel is the same size at every rung.
38
50
  * @default CronInputSize.MEDIUM
39
51
  */
40
52
  size?: CronInputSize;
41
53
  /**
42
- * Resting fill of the builder's controls, from the surface set. Ignored with `isGhost`.
54
+ * Resting fill of the field, from the surface set. Ignored with `isGhost`.
43
55
  * @default CronInputVariant.PRIMARY
44
56
  */
45
57
  variant?: CronInputVariant;
46
58
  /**
47
- * Ghost controls (1.x `TRANSPARENT`): the selects and the Custom field show no fill and no hairline
48
- * until hover or focus, and the frequency toggle's track has no fill and no hairline.
59
+ * Ghost field: no fill and no hairline at rest; the frame appears on hover, focus and open (1.x
60
+ * `TRANSPARENT`). For schedules set into a toolbar or a table cell. The panel is `PopoverVariant.BASE`.
49
61
  * @default false
50
62
  */
51
63
  isGhost?: boolean;
52
- /** Label above the builder, rendered through `Field`. For a description or a horizontal layout, wrap the input in `Field` instead. */
64
+ /** Label above the field, rendered through `Field`. For a description or a horizontal layout, wrap the input in `Field` instead. */
53
65
  label?: string;
54
- /** Message from the app, shown under the builder through `Field`. Also marks the builder's controls invalid. */
66
+ /**
67
+ * Shown in the field while the expression is empty. Never the label.
68
+ * @default Select schedule…
69
+ */
70
+ placeholder?: string;
71
+ /** Message from the app, shown under the field through `Field`. Also turns the border red and sets `aria-invalid`. */
55
72
  error?: string;
56
73
  /**
57
- * Error borders and `aria-invalid` on the controls without a message. `error` implies it.
74
+ * Error border and `aria-invalid` without a message. `error` implies it.
58
75
  * @default false
59
76
  */
60
77
  isError?: boolean;
61
78
  /**
62
- * Every control is disabled.
79
+ * Shows a clear button while there is an expression and the field is editable. It calls `onChange("")`.
80
+ * @default false
81
+ */
82
+ isClearable?: boolean;
83
+ /**
84
+ * Not focusable, never opens. Shows the disabled look.
63
85
  * @default false
64
86
  */
65
87
  isDisabled?: boolean;
66
88
  /**
67
- * Every control is focusable and announced but cannot change the schedule.
89
+ * Focusable and announced, shows the expression, but never opens and has no clear button.
68
90
  * @default false
69
91
  */
70
92
  isReadOnly?: boolean;
71
93
  /**
72
- * Required marker on the `label` (via `Field`) and `aria-required` on the controls. No validation.
94
+ * Required marker on the `label` (via `Field`) and `aria-required`. No validation.
73
95
  * @default false
74
96
  */
75
97
  isRequired?: boolean;
76
98
  /**
77
- * Stretch to the parent's width; the control column fills the rest of each row.
99
+ * Stretch to the parent's width. Without it, the field is 240px wide.
78
100
  * @default false
79
101
  */
80
102
  fillWidth?: boolean;
81
- /** Accessible name of the group when there is no visible label (no `label` and no wrapping `Field`). */
103
+ /** Accessible name when there is no visible label (no `label` and no wrapping `Field`). */
82
104
  ariaLabel?: string;
83
- /** DOM id of the group element. A wrapping `Field`'s id wins. */
105
+ /** Controlled open state of the schedule panel. When set, CronInput calls `onOpenChange` and lets the caller decide. */
106
+ isOpen?: boolean;
107
+ /**
108
+ * Initial open state while uncontrolled.
109
+ * @default false
110
+ */
111
+ defaultIsOpen?: boolean;
112
+ /** Called with the requested state on click, the keyboard, a preset, Enter in the expression field, Escape, an outside press and focus leaving the panel. */
113
+ onOpenChange?: (isOpen: boolean) => void;
114
+ /**
115
+ * DOM id of the combobox element. A wrapping `Field`'s id wins.
116
+ * @default useId()
117
+ */
84
118
  id?: string;
85
- /** Any `data-*` attribute, forwarded to the group element. */
119
+ /** Any `data-*` attribute, forwarded to the combobox element. */
86
120
  [dataAttribute: `data-${string}`]: string | number | boolean | undefined;
87
- /** Extra class on the root: the `Field` wrapper when CronInput renders one, otherwise the group. */
121
+ /** Extra class on the root: the `Field` wrapper when CronInput renders one, otherwise the field wrapper. */
88
122
  className?: string;
89
123
  /** Inline style on the root; only for setting CSS custom properties. */
90
124
  style?: CSSProperties;
91
125
  }
92
- /** A five-field cron expression, edited through a frequency builder with a plain-English preview. */
126
+ /** A five-field cron expression in a field that opens presets and a schedule builder. */
93
127
  declare const CronInput: import("react").ForwardRefExoticComponent<CronInputProps & import("react").RefAttributes<HTMLDivElement>>;
94
128
  export default CronInput;