@galaxy-io/dls 2.8.1 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/README.md +2 -2
  2. package/dist/beacons/Beacon.d.ts +1 -1
  3. package/dist/beacons/Beacon.js +12 -28
  4. package/dist/brand/GalaxyAlchemyWordmark.d.ts +4 -1
  5. package/dist/brand/GalaxyAlchemyWordmark.js +7 -1
  6. package/dist/brand/GalaxyFilamentWordmark.d.ts +5 -2
  7. package/dist/brand/GalaxyFilamentWordmark.js +9 -2
  8. package/dist/brand/GalaxyLogomark.js +3 -0
  9. package/dist/brand/PoweredBy.d.ts +27 -0
  10. package/dist/brand/PoweredBy.js +96 -0
  11. package/dist/brand/internal/svg/GalaxyAlchemyWordmarkSvg.d.ts +1 -1
  12. package/dist/brand/internal/svg/GalaxyAlchemyWordmarkSvg.js +34 -8
  13. package/dist/brand/internal/svg/GalaxyFilamentWordmarkSvg.d.ts +1 -1
  14. package/dist/brand/internal/svg/GalaxyFilamentWordmarkSvg.js +2 -2
  15. package/dist/charts/Heatmap.js +25 -9
  16. package/dist/charts/Sparkline.d.ts +1 -1
  17. package/dist/charts/Sparkline.js +10 -26
  18. package/dist/charts/chartFormat.d.ts +1 -1
  19. package/dist/charts/chartFormat.js +2 -2
  20. package/dist/charts/heatmapGeometry.d.ts +14 -0
  21. package/dist/charts/heatmapGeometry.js +17 -1
  22. package/dist/chips/Chip.d.ts +2 -2
  23. package/dist/chips/Chip.js +15 -31
  24. package/dist/drawer/Drawer.d.ts +2 -2
  25. package/dist/drawer/Drawer.js +1 -1
  26. package/dist/editor/CodeEditor.d.ts +1 -1
  27. package/dist/editor/CodeEditor.js +2 -1
  28. package/dist/feedback/Alert.d.ts +36 -9
  29. package/dist/feedback/Alert.js +26 -8
  30. package/dist/feedback/ProgressBar.d.ts +4 -1
  31. package/dist/feedback/ProgressBar.js +17 -30
  32. package/dist/feedback/ProgressCircle.d.ts +1 -1
  33. package/dist/feedback/ProgressCircle.js +14 -30
  34. package/dist/hooks/useEndReached.d.ts +40 -0
  35. package/dist/hooks/useEndReached.js +69 -0
  36. package/dist/icons/Icon.d.ts +36 -8
  37. package/dist/icons/Icon.js +14 -7
  38. package/dist/inputs/CronInput.js +114 -78
  39. package/dist/inputs/DateInput.d.ts +1 -1
  40. package/dist/inputs/DateInput.js +10 -10
  41. package/dist/inputs/MultiSelectInput.d.ts +3 -1
  42. package/dist/inputs/MultiSelectInput.js +8 -3
  43. package/dist/inputs/SelectInput.d.ts +8 -1
  44. package/dist/inputs/SelectInput.js +52 -25
  45. package/dist/inputs/internal/selectAll.d.ts +11 -0
  46. package/dist/inputs/internal/selectAll.js +28 -0
  47. package/dist/json/JsonViewer.js +7 -6
  48. package/dist/layout/AppFrame.d.ts +20 -0
  49. package/dist/layout/AppFrame.js +71 -0
  50. package/dist/layout/EmptyLayout.d.ts +53 -0
  51. package/dist/layout/EmptyLayout.js +59 -0
  52. package/dist/layout/ErrorLayout.d.ts +42 -0
  53. package/dist/layout/ErrorLayout.js +60 -0
  54. package/dist/layout/PageLayout.d.ts +26 -0
  55. package/dist/layout/PageLayout.js +116 -0
  56. package/dist/layout/PendingLayout.d.ts +30 -0
  57. package/dist/layout/PendingLayout.js +57 -0
  58. package/dist/layout/internal/errorState.d.ts +14 -0
  59. package/dist/layout/internal/errorState.js +49 -0
  60. package/dist/layout/internal/region.d.ts +10 -0
  61. package/dist/layout/internal/region.js +24 -0
  62. package/dist/lists/DescriptionList.js +1 -0
  63. package/dist/menu/Menu.d.ts +2 -2
  64. package/dist/menu/Menu.js +6 -13
  65. package/dist/modal/Modal.d.ts +2 -2
  66. package/dist/modal/Modal.js +1 -1
  67. package/dist/navigation/CommandPalette.js +4 -11
  68. package/dist/navigation/SidebarNav.d.ts +5 -0
  69. package/dist/navigation/SidebarNav.js +41 -22
  70. package/dist/navigation/Topbar.js +4 -0
  71. package/dist/shapes/Circle.d.ts +1 -1
  72. package/dist/shapes/Circle.js +10 -26
  73. package/dist/shapes/Square.d.ts +1 -1
  74. package/dist/shapes/Square.js +10 -26
  75. package/dist/styles/internal/roleColor.d.ts +3 -0
  76. package/dist/styles/internal/roleColor.js +42 -0
  77. package/dist/styles/mixins.js +1 -1
  78. package/dist/styles.css +1 -1
  79. package/dist/table/InfiniteSpreadsheet.js +6 -6
  80. package/dist/table/InfiniteTable.d.ts +57 -18
  81. package/dist/table/InfiniteTable.js +5 -3
  82. package/dist/table/TableCore.d.ts +11 -2
  83. package/dist/table/TableCore.js +108 -87
  84. package/dist/table/VirtualizedInfiniteTable.d.ts +58 -19
  85. package/dist/table/VirtualizedInfiniteTable.js +9 -6
  86. package/dist/table/useInfiniteScrollSentinel.d.ts +13 -13
  87. package/dist/table/useInfiniteScrollSentinel.js +7 -51
  88. package/dist/table/useTableColumnLayout.d.ts +8 -2
  89. package/dist/table/useTableColumnLayout.js +36 -13
  90. package/dist/theme/tokens/dark.js +1 -1
  91. package/dist/theme/tokens/light.js +4 -3
  92. package/dist/theme/tokens/types.d.ts +7 -7
  93. package/dist/timeline/Timeline.d.ts +1 -1
  94. package/dist/timeline/Timeline.js +6 -24
  95. package/dist/tokens.css +1 -1
  96. package/dist/utils/format.d.ts +35 -10
  97. package/dist/utils/format.js +60 -12
  98. package/dist/utils/search.d.ts +15 -0
  99. package/dist/utils/search.js +24 -0
  100. package/dist/vite/index.d.ts +16 -2
  101. package/dist/vite/index.js +28 -19
  102. package/dist/vite/internal/themeBoot.d.ts +25 -0
  103. package/dist/vite/internal/themeBoot.js +44 -0
  104. package/dist/vite/internal/wywOptions.d.ts +46 -0
  105. package/dist/vite/internal/wywOptions.js +44 -0
  106. package/package.json +34 -1
@@ -1,7 +1,7 @@
1
1
  import type { Icon as PhosphorIcon } from "@phosphor-icons/react";
2
2
  import { type AriaAttributes, type CSSProperties, type ReactNode } from "react";
3
- import type { Hex } from "../theme/tokens/types.js";
4
- /** Color role of the icon (color set, Constitution V-A). Resolves to `color.text.*`. */
3
+ import type { Hex, RoleColor } from "../theme/tokens/types.js";
4
+ /** Color role of the icon (AGENTS.md "Variant": color set). Resolves to `color.text.*`. */
5
5
  export declare enum IconVariant {
6
6
  /** `text.primary`. The default. */
7
7
  PRIMARY = "PRIMARY",
@@ -35,7 +35,8 @@ export declare enum IconWeight {
35
35
  /** Stroke over a 20% fill. */
36
36
  DUOTONE = "DUOTONE"
37
37
  }
38
- export interface IconProps extends AriaAttributes {
38
+ /** Every Icon prop except the color axis (`variant` or `color`). */
39
+ interface IconBaseProps extends AriaAttributes {
39
40
  /** Phosphor icon *component*: pass `PlusIcon`, not `<PlusIcon />`. */
40
41
  component: PhosphorIcon;
41
42
  /**
@@ -48,11 +49,6 @@ export interface IconProps extends AriaAttributes {
48
49
  * @default IconWeight.REGULAR
49
50
  */
50
51
  weight?: IconWeight;
51
- /**
52
- * Color role. `INHERIT` follows the parent's color (used inside Button).
53
- * @default IconVariant.PRIMARY
54
- */
55
- variant?: IconVariant;
56
52
  /** Raw color override that bypasses `variant`. Discouraged: prefer a `variant`. */
57
53
  hex?: Hex;
58
54
  /** Accessible name. Set it when the icon carries meaning on its own; when absent the icon is `aria-hidden`. */
@@ -73,6 +69,38 @@ export interface IconProps extends AriaAttributes {
73
69
  /** Inline style on the `<svg>`; only for setting CSS custom properties. */
74
70
  style?: CSSProperties;
75
71
  }
72
+ /** An icon colored by meaning (`variant`), or the default `PRIMARY`. */
73
+ interface IconVariantProps {
74
+ /**
75
+ * Color role. `INHERIT` follows the parent's color (used inside Button). Not with `color`.
76
+ * @default IconVariant.PRIMARY
77
+ */
78
+ variant?: IconVariant;
79
+ /**
80
+ * Categorical palette family (`"blue"`, `"yellow"`, …) or a status role as a string
81
+ * (`"success"`): the family's `text.<color>`. For a glyph that names a category the page
82
+ * already shows (a run status map, a source type); a status that is meaning takes `variant`.
83
+ * Not with `variant`.
84
+ */
85
+ color?: undefined;
86
+ }
87
+ /** An icon colored by category (`color`). */
88
+ interface IconColorProps {
89
+ /**
90
+ * Color role. `INHERIT` follows the parent's color (used inside Button). Not with `color`.
91
+ * @default IconVariant.PRIMARY
92
+ */
93
+ variant?: undefined;
94
+ /**
95
+ * Categorical palette family (`"blue"`, `"yellow"`, …) or a status role as a string
96
+ * (`"success"`): the family's `text.<color>`. For a glyph that names a category the page
97
+ * already shows (a run status map, a source type); a status that is meaning takes `variant`.
98
+ * Not with `variant`.
99
+ */
100
+ color: RoleColor;
101
+ }
102
+ /** Icon props. An icon with both `variant` and `color` is a type error. */
103
+ export type IconProps = IconBaseProps & (IconVariantProps | IconColorProps);
76
104
  /** Wraps a Phosphor icon so its color, weight and motion come from the DLS. Never render a Phosphor icon bare. */
77
105
  declare const Icon: import("react").ForwardRefExoticComponent<IconProps & import("react").RefAttributes<SVGSVGElement>>;
78
106
  export default Icon;
@@ -1,4 +1,5 @@
1
1
  import LazyTooltip from "../tooltip/internal/LazyTooltip.js";
2
+ import { ROLE_COLOR_TO_CSS_MAP } from "../styles/internal/roleColor.js";
2
3
  /* empty css */
3
4
  import { forwardRef } from "react";
4
5
  import { jsx } from "react/jsx-runtime";
@@ -13,13 +14,17 @@ import { cx } from "@linaria/core";
13
14
  * `<PARENT>_SIZE_TO_ICON_PX_MAP` (`BUTTON_SIZE_TO_ICON_PX_MAP`). Parents that own the color
14
15
  * (`Button`, `Chip`) pass `IconVariant.INHERIT` so the icon follows their `color`.
15
16
  *
17
+ * `color` takes a category (a palette family, or a status name used as data) instead of a
18
+ * meaning: it resolves to `text.<color>` through the shared `--gx-role-*` variables (icons keep
19
+ * `text`, never `mark`), and is exclusive with `variant` by type (the Chip union).
20
+ *
16
21
  * `hex` is set as the `--gx-icon-hex` custom property in `style` and read by a block switched on
17
- * only when the prop is set (the Text pattern).
22
+ * only when the prop is set (the Text pattern). It wins over `variant` and `color`.
18
23
  *
19
24
  * `tooltip` renders through `LazyTooltip`, so an icon without one never loads `Tooltip` (and
20
25
  * floating-ui) into the bundle that draws it.
21
26
  */
22
- /** Color role of the icon (color set, Constitution V-A). Resolves to `color.text.*`. */
27
+ /** Color role of the icon (AGENTS.md "Variant": color set). Resolves to `color.text.*`. */
23
28
  var IconVariant = /* @__PURE__ */ function(IconVariant) {
24
29
  /** `text.primary`. The default. */
25
30
  IconVariant["PRIMARY"] = "PRIMARY";
@@ -76,15 +81,17 @@ var ICON_VARIANT_TO_CSS_MAP = {
76
81
  ["WARNING"]: "gx-Icon-WARNING-w1awu5xi",
77
82
  ["ERROR"]: "gx-Icon-ERROR-e1ucpgem"
78
83
  };
79
- /** Declared after the variant map so `hex` wins over it. */
80
- var HEX_CSS = "gx-Icon-HEX_CSS-h8mope0";
84
+ /** Categorical `color`: the family's `text.<color>`, read from the shared role variables. */
85
+ var COLOR_CSS = "gx-Icon-COLOR_CSS-c8mope0";
86
+ /** Declared after the variant map and `COLOR_CSS` so `hex` wins over both. */
87
+ var HEX_CSS = "gx-Icon-HEX_CSS-h1uiuyxj";
81
88
  /**
82
89
  * One turn every six `duration.base` steps (900ms), linear, forever. The keyframes are global, so
83
90
  * the name is `gx-` prefixed. `REDUCED_MOTION` stops it.
84
91
  */
85
- var SPINNING_CSS = "gx-Icon-SPINNING_CSS-s1uiuyxj";
92
+ var SPINNING_CSS = "gx-Icon-SPINNING_CSS-szci2ir";
86
93
  /** Wraps a Phosphor icon so its color, weight and motion come from the DLS. Never render a Phosphor icon bare. */
87
- var Icon = forwardRef(function Icon({ component: PhosphorComponent, size = 16, weight = "REGULAR", variant = "PRIMARY", hex, ariaLabel, tooltip, isSpinning = false, id, className, style, ...rest }, ref) {
94
+ var Icon = forwardRef(function Icon({ component: PhosphorComponent, size = 16, weight = "REGULAR", variant = "PRIMARY", color, hex, ariaLabel, tooltip, isSpinning = false, id, className, style, ...rest }, ref) {
88
95
  const variables = {};
89
96
  if (hex !== void 0) variables["--gx-icon-hex"] = hex;
90
97
  const hasTooltip = tooltip !== void 0 && tooltip !== null && tooltip !== false && tooltip !== "";
@@ -99,7 +106,7 @@ var Icon = forwardRef(function Icon({ component: PhosphorComponent, size = 16, w
99
106
  size,
100
107
  weight: ICON_WEIGHT_TO_PHOSPHOR_WEIGHT_MAP[weight],
101
108
  color: "currentColor",
102
- className: cx(ROOT_CSS, ICON_VARIANT_TO_CSS_MAP[variant], hex !== void 0 && HEX_CSS, isSpinning && SPINNING_CSS, className),
109
+ className: cx(ROOT_CSS, color === void 0 ? ICON_VARIANT_TO_CSS_MAP[variant] : cx(ROLE_COLOR_TO_CSS_MAP[color], COLOR_CSS), hex !== void 0 && HEX_CSS, isSpinning && SPINNING_CSS, className),
103
110
  style: {
104
111
  ...variables,
105
112
  ...style
@@ -1,5 +1,5 @@
1
1
  import VisuallyHidden from "../a11y/VisuallyHidden.js";
2
- import { FontFamily, Orientation } from "../theme/enums.js";
2
+ import { FontFamily } from "../theme/enums.js";
3
3
  import Text, { TextSize, TextVariant } from "../text/Text.js";
4
4
  import { useControlledState } from "../hooks/useControlledState.js";
5
5
  import { useControlledOpenState } from "../hooks/useControlledOpenState.js";
@@ -20,6 +20,7 @@ import "./internal/innerButton.js";
20
20
  import { InputSize, InputVariant } from "./Input.js";
21
21
  import { useDedupedOpen, useRestoreFocusAfterOutsidePress, useRetriedFocus } from "./internal/useComboboxPopover.js";
22
22
  import TextInput from "./TextInput.js";
23
+ import Widget, { WidgetVariant } from "../widget/Widget.js";
23
24
  import SelectInput, { SelectInputSize, SelectInputVariant } from "./SelectInput.js";
24
25
  import ToggleInput, { ToggleInputSize, ToggleInputVariant } from "./ToggleInput.js";
25
26
  /* empty css */
@@ -40,6 +41,9 @@ import cronstrue from "cronstrue";
40
41
  * and a sentence from `cronstrue` that reads the schedule back ("Runs at 09:00, Monday through
41
42
  * Friday."). Expressions the builder cannot represent show as Custom and are edited as text.
42
43
  *
44
+ * The builder and the expression are two cards split by an "or" divider, centered beside the
45
+ * presets. The builder card holds the tallest frequency's rows, so the panel keeps one height.
46
+ *
43
47
  * The field is a select-only combobox with a dialog popup (`Popover` `MANUAL`, `DIALOG`), like
44
48
  * DateInput; CronInput moves focus to the expression field on open, so a schedule can be typed
45
49
  * straight away. The value is the expression string; an empty string shows the placeholder.
@@ -118,6 +122,8 @@ var CRON_INPUT_SELECT_WIDTH = 64;
118
122
  var CRON_INPUT_FOCUS_RETRY_FRAMES = 10;
119
123
  /** The neutral hint shown when `cronstrue` cannot read the expression. */
120
124
  var CRON_INPUT_HINT = "Enter five fields: minute, hour, day of month, month, day of week.";
125
+ /** The caption on the divider between the builder and the expression. */
126
+ var CRON_INPUT_DIVIDER_LABEL = "or";
121
127
  /** Each builder row's label; the label column is as wide as the longest, whichever rows show. */
122
128
  var ROW_LABELS = {
123
129
  frequency: "Frequency",
@@ -360,6 +366,13 @@ var CRON_INPUT_VARIANT_TO_POPOVER_VARIANT_MAP = {
360
366
  ["SECONDARY"]: PopoverVariant.SECONDARY,
361
367
  ["TERTIARY"]: PopoverVariant.TERTIARY
362
368
  };
369
+ /** The builder's cards take the panel's own fill, so they read as hairline frames on it. */
370
+ var POPOVER_VARIANT_TO_WIDGET_VARIANT_MAP = {
371
+ [PopoverVariant.BASE]: WidgetVariant.BASE,
372
+ [PopoverVariant.PRIMARY]: WidgetVariant.PRIMARY,
373
+ [PopoverVariant.SECONDARY]: WidgetVariant.SECONDARY,
374
+ [PopoverVariant.TERTIARY]: WidgetVariant.TERTIARY
375
+ };
363
376
  /** Holds the field box, the trailing parts and the hidden summary. */
364
377
  var Wrapper = /*#__PURE__*/ styled("div")({
365
378
  name: "Wrapper",
@@ -465,12 +478,21 @@ var PanelBody = /*#__PURE__*/ styled("div")({
465
478
  class: "gx-CronInput-PanelBody-p11btr9k",
466
479
  propsAsIs: false
467
480
  });
468
- /** The main row: presets, then the builder, 12px in and 12px apart. */
481
+ /**
482
+ * The main row: presets, then the builder, 16px in and 16px apart. Both columns center on the
483
+ * row, so the shorter one sits in the middle of the taller.
484
+ */
469
485
  var PanelMain = /*#__PURE__*/ styled("div")({
470
486
  name: "PanelMain",
471
487
  class: "gx-CronInput-PanelMain-p1az6570",
472
488
  propsAsIs: false
473
489
  });
490
+ /** The builder column: the frequency card, the labeled divider and the expression card. */
491
+ var Builder = /*#__PURE__*/ styled("div")({
492
+ name: "Builder",
493
+ class: "gx-CronInput-Builder-b1phzlk6",
494
+ propsAsIs: false
495
+ });
474
496
  /**
475
497
  * The summary footer: the schedule read back, set apart from the controls that make it. A hairline
476
498
  * above and a faint foreground tint, so it reads as the panel's output on every panel fill. It
@@ -478,59 +500,59 @@ var PanelMain = /*#__PURE__*/ styled("div")({
478
500
  */
479
501
  var Summary = /*#__PURE__*/ styled("div")({
480
502
  name: "Summary",
481
- class: "gx-CronInput-Summary-s1phzlk6",
503
+ class: "gx-CronInput-Summary-su1hduy",
482
504
  propsAsIs: false
483
505
  });
484
506
  /** Centers the 12px icon on the summary's first 16px line. */
485
507
  var SummaryIcon = /*#__PURE__*/ styled("span")({
486
508
  name: "SummaryIcon",
487
- class: "gx-CronInput-SummaryIcon-su1hduy",
509
+ class: "gx-CronInput-SummaryIcon-sryjels",
488
510
  propsAsIs: false
489
511
  });
490
512
  /** The presets column. */
491
513
  var PresetList = /*#__PURE__*/ styled("div")({
492
514
  name: "PresetList",
493
- class: "gx-CronInput-PresetList-pryjels",
515
+ class: "gx-CronInput-PresetList-pm47nq4",
494
516
  propsAsIs: false
495
517
  });
496
518
  /** One preset. Declared before its state classes. */
497
519
  var PresetButton = /*#__PURE__*/ styled("button")({
498
520
  name: "PresetButton",
499
- class: "gx-CronInput-PresetButton-pm47nq4",
521
+ class: "gx-CronInput-PresetButton-pafotm8",
500
522
  propsAsIs: false
501
523
  });
502
524
  /** The preset whose value is the current expression. */
503
- var SELECTED_PRESET_CSS = "gx-CronInput-SELECTED_PRESET_CSS-safotm8";
525
+ var SELECTED_PRESET_CSS = "gx-CronInput-SELECTED_PRESET_CSS-s1d29pk4";
504
526
  /**
505
527
  * Row labels in the first column, controls in the second. Controls keep their own width
506
528
  * (`justify-items: start`), so the weekday row never stretches the frequency toggle.
507
529
  */
508
530
  var Rows = /*#__PURE__*/ styled("div")({
509
531
  name: "Rows",
510
- class: "gx-CronInput-Rows-r1d29pk4",
532
+ class: "gx-CronInput-Rows-r1tt5fyf",
511
533
  propsAsIs: false
512
534
  });
513
535
  /**
514
- * The frequency row's label cell: the label and every other row label stacked in one grid area.
515
- * The hidden ones size the label column, so switching frequency never moves the controls.
536
+ * The frequency card's rows hold the tallest frequency (Weekly and Monthly: three 24px rows), so
537
+ * switching frequency never changes the panel's height or moves the presets.
538
+ */
539
+ var FREQUENCY_ROWS_CSS = "gx-CronInput-FREQUENCY_ROWS_CSS-f10uqwad";
540
+ /**
541
+ * A card's first label cell: its label and every other row label stacked in one grid area. The
542
+ * hidden ones size the label column, so both cards' controls start on one line and switching
543
+ * frequency never moves them.
516
544
  */
517
545
  var LabelStack = /*#__PURE__*/ styled("span")({
518
546
  name: "LabelStack",
519
- class: "gx-CronInput-LabelStack-l1tt5fyf",
547
+ class: "gx-CronInput-LabelStack-l1231567",
520
548
  propsAsIs: false
521
549
  });
522
550
  /** A row label that only sizes the label column: not painted, not announced. */
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",
528
- propsAsIs: false
529
- });
551
+ var LABEL_SIZER_CSS = "gx-CronInput-LABEL_SIZER_CSS-l13n44nx";
530
552
  /** Stretches the expression field across the control column. */
531
553
  var ExpressionSlot = /*#__PURE__*/ styled("div")({
532
554
  name: "ExpressionSlot",
533
- class: "gx-CronInput-ExpressionSlot-e13n44nx",
555
+ class: "gx-CronInput-ExpressionSlot-e5dtj40",
534
556
  propsAsIs: false
535
557
  });
536
558
  /** The field, the trailing parts and the schedule panel, wired to the nearest Field. */
@@ -704,13 +726,23 @@ function CronInputFrame({ cronProps, forwardedRef, isRoot }) {
704
726
  numberSelect("time", "minute", MINUTE_OPTIONS, "Minute")
705
727
  ]
706
728
  })] });
729
+ /** A card's first label cell: `row`'s label over hidden sizers for every other row. */
730
+ const labelCell = (visibleRow) => /* @__PURE__ */ jsxs(LabelStack, { children: [rowLabel(visibleRow), Object.entries(ROW_LABELS).map(([row, text]) => row === visibleRow ? null : /* @__PURE__ */ jsx(Text, {
731
+ as: "span",
732
+ size: TextSize.BODY_SM,
733
+ className: LABEL_SIZER_CSS,
734
+ "aria-hidden": true,
735
+ children: text
736
+ }, row))] });
707
737
  const hasPresets = presets.length > 0;
708
738
  const normalized = normalize(expression);
739
+ const panelVariant = isGhost ? PopoverVariant.BASE : CRON_INPUT_VARIANT_TO_POPOVER_VARIANT_MAP[variant];
740
+ const cardVariant = POPOVER_VARIANT_TO_WIDGET_VARIANT_MAP[panelVariant];
709
741
  const body = /* @__PURE__ */ jsx(FieldContext.Provider, {
710
742
  value: null,
711
743
  children: /* @__PURE__ */ jsxs(PanelBody, {
712
744
  onBlur: handleFocusOut,
713
- children: [/* @__PURE__ */ jsxs(PanelMain, { children: [hasPresets && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(PresetList, {
745
+ children: [/* @__PURE__ */ jsxs(PanelMain, { children: [hasPresets && /* @__PURE__ */ jsx(PresetList, {
714
746
  role: "group",
715
747
  "aria-label": "Presets",
716
748
  children: presets.map((preset) => {
@@ -731,64 +763,68 @@ function CronInputFrame({ cronProps, forwardedRef, isRoot }) {
731
763
  })
732
764
  }, preset.label);
733
765
  })
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")
766
+ }), /* @__PURE__ */ jsxs(Builder, { children: [
767
+ /* @__PURE__ */ jsx(Widget, {
768
+ variant: cardVariant,
769
+ children: /* @__PURE__ */ jsxs(Rows, {
770
+ className: FREQUENCY_ROWS_CSS,
771
+ children: [
772
+ labelCell("frequency"),
773
+ /* @__PURE__ */ jsx(ToggleInput, {
774
+ options: FREQUENCY_OPTIONS,
775
+ value: frequency,
776
+ onChange: changeFrequency,
777
+ size: ToggleInputSize.SMALL,
778
+ variant: ToggleInputVariant.SECONDARY,
779
+ "aria-labelledby": rowLabelId("frequency")
780
+ }),
781
+ frequency === "HOURLY" && /* @__PURE__ */ jsxs(Fragment$1, { children: [rowLabel("minute"), numberSelect("minute", "minute", MINUTE_OPTIONS)] }),
782
+ frequency === "DAILY" && timeRow,
783
+ frequency === "WEEKLY" && /* @__PURE__ */ jsxs(Fragment$1, { children: [
784
+ rowLabel("weekdays"),
785
+ /* @__PURE__ */ jsx(ButtonGroup, {
786
+ isAttached: true,
787
+ "aria-labelledby": rowLabelId("weekdays"),
788
+ children: WEEKDAYS.map(({ day, label, name }) => /* @__PURE__ */ jsx(Button, {
789
+ variant: ButtonVariant.SECONDARY,
790
+ size: ButtonSize.SMALL,
791
+ label,
792
+ ariaLabel: name,
793
+ isActive: parts.weekdays.includes(day),
794
+ onClick: () => toggleWeekday(day)
795
+ }, day))
796
+ }),
797
+ timeRow
798
+ ] }),
799
+ frequency === "MONTHLY" && /* @__PURE__ */ jsxs(Fragment$1, { children: [
800
+ rowLabel("day"),
801
+ numberSelect("day", "dayOfMonth", DAY_OF_MONTH_OPTIONS),
802
+ timeRow
803
+ ] })
804
+ ]
805
+ })
749
806
  }),
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
- }) })
807
+ /* @__PURE__ */ jsx(Divider, { label: CRON_INPUT_DIVIDER_LABEL }),
808
+ /* @__PURE__ */ jsx(Widget, {
809
+ variant: cardVariant,
810
+ children: /* @__PURE__ */ jsxs(Rows, { children: [labelCell("expression"), /* @__PURE__ */ jsx(ExpressionSlot, { children: /* @__PURE__ */ jsx(TextInput, {
811
+ id: expressionId,
812
+ "aria-labelledby": rowLabelId("expression"),
813
+ "aria-describedby": `${panelId}-sentence`,
814
+ family: FontFamily.MONO,
815
+ placeholder: "*/15 * * * *",
816
+ spellCheck: false,
817
+ value: expression,
818
+ onChange: (next) => {
819
+ if (isEditable) commit(next);
820
+ },
821
+ onEnter: close,
822
+ size: InputSize.SMALL,
823
+ variant: InputVariant.SECONDARY,
824
+ isError: isInvalid,
825
+ fillWidth: true
826
+ }) })] })
827
+ })
792
828
  ] })] }), /* @__PURE__ */ jsxs(Summary, { children: [/* @__PURE__ */ jsx(SummaryIcon, { children: /* @__PURE__ */ jsx(Icon, {
793
829
  component: ClockIcon,
794
830
  size: 12,
@@ -813,7 +849,7 @@ function CronInputFrame({ cronProps, forwardedRef, isRoot }) {
813
849
  ref: panelRef,
814
850
  trigger: PopoverTrigger.MANUAL,
815
851
  role: PopoverRole.DIALOG,
816
- variant: isGhost ? PopoverVariant.BASE : CRON_INPUT_VARIANT_TO_POPOVER_VARIANT_MAP[variant],
852
+ variant: panelVariant,
817
853
  isOpen: isShown,
818
854
  onOpenChange: setOpen,
819
855
  isDisabled: !isEditable,
@@ -12,7 +12,7 @@ export declare enum DateInputSize {
12
12
  /** 40px field, body_lg text, 16px icon. */
13
13
  X_LARGE = "X_LARGE"
14
14
  }
15
- /** Resting fill of the field (Constitution V-A surface set; 1.x `InputVariant` unchanged). */
15
+ /** Resting fill of the field (AGENTS.md "Variant": surface set; 1.x `InputVariant` unchanged). */
16
16
  export declare enum DateInputVariant {
17
17
  /** `background.base` fill. */
18
18
  BASE = "BASE",
@@ -9,6 +9,7 @@ import Divider from "../layout/Divider.js";
9
9
  import Popover, { PopoverRole, PopoverTrigger, PopoverVariant } from "../overlays/Popover.js";
10
10
  import Icon, { IconVariant } from "../icons/Icon.js";
11
11
  import Button, { ButtonSize, ButtonVariant } from "../buttons/Button.js";
12
+ import { formatDate } from "../utils/format.js";
12
13
  import FlexItem from "../layout/FlexItem.js";
13
14
  import { useDevWarning } from "./internal/devWarn.js";
14
15
  import { FieldContext } from "../hooks/useField.js";
@@ -61,7 +62,7 @@ var DateInputSize = /* @__PURE__ */ function(DateInputSize) {
61
62
  DateInputSize["X_LARGE"] = "X_LARGE";
62
63
  return DateInputSize;
63
64
  }({});
64
- /** Resting fill of the field (Constitution V-A surface set; 1.x `InputVariant` unchanged). */
65
+ /** Resting fill of the field (AGENTS.md "Variant": surface set; 1.x `InputVariant` unchanged). */
65
66
  var DateInputVariant = /* @__PURE__ */ function(DateInputVariant) {
66
67
  /** `background.base` fill. */
67
68
  DateInputVariant["BASE"] = "BASE";
@@ -177,7 +178,7 @@ var DATE_INPUT_VARIANT_TO_CSS_MAP = {
177
178
  };
178
179
  /** `isGhost`: no fill and no hairline at rest. Declared after the variant map, which it replaces. */
179
180
  var GHOST_CSS = "gx-DateInput-GHOST_CSS-g1mgixmn";
180
- /** Hover on an editable field: `border.hovered` (stronger than `border.primary`, Constitution III.6). */
181
+ /** Hover on an editable field: `border.hovered` (stronger than `border.primary`; `tokens.test.ts` holds the order). */
181
182
  var DATE_INPUT_VARIANT_TO_HOVER_CSS_MAP = {
182
183
  ["BASE"]: "gx-DateInput-BASE-bvno65u",
183
184
  ["PRIMARY"]: "gx-DateInput-PRIMARY-p1c49qmz",
@@ -434,18 +435,17 @@ function fullDateLabel(day) {
434
435
  }
435
436
  /** The default field text: "Oct 3, 2026" (or "Oct 3, 2026, 14:30" with time) in the zone. */
436
437
  function defaultFormat(date, hasTime, timeZone) {
437
- const options = {
438
+ const zone = timeZone === void 0 ? {} : { timeZone };
439
+ if (!hasTime) return formatDate(date, zone);
440
+ return new Intl.DateTimeFormat("en-US", {
438
441
  month: "short",
439
442
  day: "numeric",
440
- year: "numeric"
441
- };
442
- if (hasTime) Object.assign(options, {
443
+ year: "numeric",
443
444
  hour: "2-digit",
444
445
  minute: "2-digit",
445
- hourCycle: "h23"
446
- });
447
- if (timeZone !== void 0) options.timeZone = timeZone;
448
- return new Intl.DateTimeFormat("en-US", options).format(date);
446
+ hourCycle: "h23",
447
+ ...zone
448
+ }).format(date);
449
449
  }
450
450
  /** The zone's short name for an instant ("UTC", "EDT", "GMT+2"). */
451
451
  function zoneName(date, timeZone) {
@@ -14,7 +14,7 @@ export declare enum MultiSelectInputSize {
14
14
  /** 40px field, 28px chips, 32px rows. */
15
15
  X_LARGE = "X_LARGE"
16
16
  }
17
- /** Resting fill of the field (Constitution V-A surface set; 1.x `InputVariant` unchanged). */
17
+ /** Resting fill of the field (AGENTS.md "Variant": surface set; 1.x `InputVariant` unchanged). */
18
18
  export declare enum MultiSelectInputVariant {
19
19
  /** `background.base` fill. */
20
20
  BASE = "BASE",
@@ -130,6 +130,8 @@ export interface MultiSelectInputBaseProps<TId extends string = string> extends
130
130
  renderValue?: (options: SelectOption<TId>[]) => ReactNode;
131
131
  /** Options shown in a section above the list, in this order, whatever the search term. */
132
132
  pinnedIds?: TId[];
133
+ /** Adds a first row with this label ("All sources") that selects every enabled option matching the search term, or clears them when all are selected. Checked when all are selected, `aria-checked="mixed"` with a dash when some are. Respects `maxSelected`; it is not an option, so it never appears in `value`. */
134
+ selectAllLabel?: string;
133
135
  /**
134
136
  * Preferred side and alignment of the panel. It flips and shifts to stay in the viewport.
135
137
  * @default Placement.BOTTOM_START
@@ -3,6 +3,7 @@ import VisuallyHidden from "../a11y/VisuallyHidden.js";
3
3
  import { useControlledState } from "../hooks/useControlledState.js";
4
4
  import Chip, { ChipSize } from "../chips/Chip.js";
5
5
  import { SelectInputRoot, SelectInputSize, SelectInputVariant } from "./SelectInput.js";
6
+ import { applySelectAll } from "./internal/selectAll.js";
6
7
  /* empty css */
7
8
  import { styled } from "@linaria/react";
8
9
  import { forwardRef, useEffect, useRef, useState } from "react";
@@ -15,7 +16,9 @@ import { cx } from "@linaria/core";
15
16
  * array of option ids in selection order, choosing a row toggles it and keeps the panel open, and
16
17
  * the field shows the chosen options as chips on one line, with a `+N` chip for those that do not
17
18
  * fit. `maxSelected` caps the choices; `onCreate` (with `isSearchable`) offers a "Create" row for a
18
- * term that matches no option.
19
+ * term that matches no option; `selectAllLabel` adds a tri-state "select all" row above the list
20
+ * that toggles the enabled options matching the term (it is not an option, so nothing of its own
21
+ * ever reaches `value`).
19
22
  *
20
23
  * Search, groups, pinned options, descriptions, disabled reasons, loading, paging,
21
24
  * virtualization, the keyboard model, sizes and fills are SelectInput's. It does not validate (the
@@ -38,7 +41,7 @@ var MultiSelectInputSize = /* @__PURE__ */ function(MultiSelectInputSize) {
38
41
  MultiSelectInputSize["X_LARGE"] = "X_LARGE";
39
42
  return MultiSelectInputSize;
40
43
  }({});
41
- /** Resting fill of the field (Constitution V-A surface set; 1.x `InputVariant` unchanged). */
44
+ /** Resting fill of the field (AGENTS.md "Variant": surface set; 1.x `InputVariant` unchanged). */
42
45
  var MultiSelectInputVariant = /* @__PURE__ */ function(MultiSelectInputVariant) {
43
46
  /** `background.base` fill. */
44
47
  MultiSelectInputVariant["BASE"] = "BASE";
@@ -144,7 +147,7 @@ function ChipRow({ options, size, isDisabled }) {
144
147
  });
145
148
  }
146
149
  /** Choose several values from a list of options; the choices show as chips in the field. */
147
- var MultiSelectInputInner = forwardRef(function MultiSelectInput({ value, defaultValue, onChange, size: sizeProp, variant: variantProp, isGhost, placeholder, isDisabled: isDisabledProp, maxSelected, renderValue, isSearchable, onCreate, className, style, ...rest }, ref) {
150
+ var MultiSelectInputInner = forwardRef(function MultiSelectInput({ value, defaultValue, onChange, size: sizeProp, variant: variantProp, isGhost, placeholder, isDisabled: isDisabledProp, maxSelected, renderValue, isSearchable, onCreate, selectAllLabel, className, style, ...rest }, ref) {
148
151
  const size = sizeProp ?? "MEDIUM";
149
152
  const variant = variantProp ?? "PRIMARY";
150
153
  const isDisabled = isDisabledProp ?? false;
@@ -180,6 +183,8 @@ var MultiSelectInputInner = forwardRef(function MultiSelectInput({ value, defaul
180
183
  getSelectionText: (selected) => selected.map((option) => option.label).join(", "),
181
184
  limitReason: isAtLimit ? `Limit of ${limit} reached` : void 0,
182
185
  onCreate: isSearchable === true ? onCreate : void 0,
186
+ selectAllLabel,
187
+ onSelectAll: (ids, shouldSelect) => setValue(applySelectAll(currentValue, ids, shouldSelect, limit)),
183
188
  ...className === void 0 ? {} : { className },
184
189
  ...style === void 0 ? {} : { style }
185
190
  });
@@ -14,7 +14,7 @@ export declare enum SelectInputSize {
14
14
  /** 40px field, body_lg text, 16px icons, 12px caret; 32px rows, 14px row icons. */
15
15
  X_LARGE = "X_LARGE"
16
16
  }
17
- /** Resting fill of the field (Constitution V-A surface set; 1.x `InputVariant` unchanged). */
17
+ /** Resting fill of the field (AGENTS.md "Variant": surface set; 1.x `InputVariant` unchanged). */
18
18
  export declare enum SelectInputVariant {
19
19
  /** `background.base` fill. */
20
20
  BASE = "BASE",
@@ -198,6 +198,13 @@ export type SelectInputRootProps<TId extends string = string> = Omit<SelectInput
198
198
  limitReason: string | undefined;
199
199
  /** When set and the term is non-empty with no exact label match, a "Create" row ends the list. */
200
200
  onCreate: ((label: string) => void) | undefined;
201
+ /** When set, a tri-state "select all" row opens the list (MultiSelectInput `selectAllLabel`). */
202
+ selectAllLabel: string | undefined;
203
+ /**
204
+ * Called when the select-all row is chosen, with the enabled options it covers (those matching
205
+ * the term, in display order) and whether to select them (`false`: they were all selected).
206
+ */
207
+ onSelectAll: ((ids: TId[], shouldSelect: boolean) => void) | undefined;
201
208
  };
202
209
  /** @internal Shared by SelectInput and MultiSelectInput; apps use those. */
203
210
  export declare const SelectInputRoot: <TId extends string = string>(props: SelectInputRootProps<TId> & RefAttributes<HTMLElement>) => ReactElement | null;