@parallelworks/ui 0.55.0 → 0.56.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 (40) hide show
  1. package/README.md +52 -22
  2. package/dist/access/AccessDrawer.d.ts +30 -19
  3. package/dist/access/AccessDrawer.js +92 -67
  4. package/dist/access/AccessList.d.ts +17 -16
  5. package/dist/access/AccessList.js +218 -114
  6. package/dist/access/GrantView.d.ts +9 -8
  7. package/dist/access/GrantView.js +34 -36
  8. package/dist/access/PrincipalPicker.d.ts +38 -0
  9. package/dist/access/{GroupPicker.js → PrincipalPicker.js} +173 -80
  10. package/dist/access/index.d.ts +1 -1
  11. package/dist/access/model.d.ts +67 -24
  12. package/dist/access/model.js +111 -47
  13. package/dist/access/strings.d.ts +63 -39
  14. package/dist/access/strings.js +114 -84
  15. package/dist/access/types.d.ts +32 -14
  16. package/dist/ai/adapter/mock/mockAdapter.js +1 -1
  17. package/dist/ai/core/useSSEStream.d.ts +1 -1
  18. package/dist/components/Checkbox.js +1 -1
  19. package/dist/components/Combobox.js +25 -20
  20. package/dist/components/DatePicker.js +58 -53
  21. package/dist/components/Drawer.js +3 -1
  22. package/dist/components/HoverCard.js +15 -10
  23. package/dist/components/Menu.js +3 -0
  24. package/dist/components/Modal.js +32 -27
  25. package/dist/components/Popover.js +30 -25
  26. package/dist/components/Radio.js +1 -1
  27. package/dist/components/Select.js +47 -42
  28. package/dist/components/Slider.js +3 -3
  29. package/dist/components/Switch.js +1 -1
  30. package/dist/components/Tooltip.js +16 -11
  31. package/dist/components/fieldBox.js +1 -1
  32. package/dist/components/fullscreen.d.ts +4 -0
  33. package/dist/components/fullscreen.js +18 -0
  34. package/dist/graph/GraphEditorDialogs.d.ts +1 -1
  35. package/dist/styles/theme.css +1 -1
  36. package/dist/styles.css +1 -1
  37. package/dist/theme/derive.d.ts +2 -0
  38. package/dist/theme/derive.js +12 -13
  39. package/package.json +1 -1
  40. package/dist/access/GroupPicker.d.ts +0 -35
@@ -1,4 +1,5 @@
1
1
  import { cardClassName, positionerClassName } from "./floating.js";
2
+ import { useFullscreenContainer } from "./fullscreen.js";
2
3
  import { jsx, jsxs } from "react/jsx-runtime";
3
4
  import { PreviewCard } from "@base-ui/react/preview-card";
4
5
  //#region src/components/HoverCard.tsx
@@ -7,23 +8,27 @@ import { PreviewCard } from "@base-ui/react/preview-card";
7
8
  * reachable another way, such as the page the anchor links to. The card
8
9
  * stays open while the pointer is over it. */
9
10
  function HoverCard({ card, children, defaultOpen = false }) {
11
+ const fullscreen = useFullscreenContainer();
10
12
  return /* @__PURE__ */ jsxs(PreviewCard.Root, {
11
13
  defaultOpen,
12
14
  children: [/* @__PURE__ */ jsx(PreviewCard.Trigger, {
13
15
  delay: 350,
14
16
  closeDelay: 150,
15
17
  render: children
16
- }), /* @__PURE__ */ jsx(PreviewCard.Portal, { children: /* @__PURE__ */ jsx(PreviewCard.Positioner, {
17
- side: "bottom",
18
- align: "start",
19
- sideOffset: 8,
20
- collisionPadding: 8,
21
- className: positionerClassName,
22
- children: /* @__PURE__ */ jsx(PreviewCard.Popup, {
23
- className: cardClassName,
24
- children: card
18
+ }), /* @__PURE__ */ jsx(PreviewCard.Portal, {
19
+ container: fullscreen,
20
+ children: /* @__PURE__ */ jsx(PreviewCard.Positioner, {
21
+ side: "bottom",
22
+ align: "start",
23
+ sideOffset: 8,
24
+ collisionPadding: 8,
25
+ className: positionerClassName,
26
+ children: /* @__PURE__ */ jsx(PreviewCard.Popup, {
27
+ className: cardClassName,
28
+ children: card
29
+ })
25
30
  })
26
- }) })]
31
+ })]
27
32
  });
28
33
  }
29
34
  //#endregion
@@ -1,13 +1,16 @@
1
1
  import { cx } from "../cx.js";
2
2
  import { CheckIcon, ChevronRightIcon } from "../icons.js";
3
3
  import { panelClassName, panelItemClassName, positionerClassName } from "./floating.js";
4
+ import { useFullscreenContainer } from "./fullscreen.js";
4
5
  import { Menu } from "@base-ui/react/menu";
5
6
  import { jsx, jsxs } from "react/jsx-runtime";
6
7
  //#region src/components/Menu.tsx
7
8
  var itemClassName = panelItemClassName;
8
9
  /** The portal, positioner and popup every menu needs. */
9
10
  function MenuPopup({ children, className, side = "bottom", align = "start", anchor, keepMounted = false }) {
11
+ const fullscreen = useFullscreenContainer();
10
12
  return /* @__PURE__ */ jsx(Menu.Portal, {
13
+ container: fullscreen,
11
14
  keepMounted,
12
15
  children: /* @__PURE__ */ jsx(Menu.Positioner, {
13
16
  side,
@@ -1,4 +1,5 @@
1
1
  import { cx } from "../cx.js";
2
+ import { useFullscreenContainer } from "./fullscreen.js";
2
3
  import { closeHandler } from "./dismiss.js";
3
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
5
  import { AlertDialog } from "@base-ui/react/alert-dialog";
@@ -21,37 +22,41 @@ var sizeClasses = {
21
22
  * and a `footer` for the standard layout, as a Drawer has, or lay out the whole
22
23
  * panel with the children. */
23
24
  function Modal({ open, onClose, title, description, footer, size, alert = false, dismissible = true, align = "top", panel = true, backdropClassName = "bg-black/40", className, children, ...popupProps }) {
25
+ const fullscreen = useFullscreenContainer();
24
26
  const onOpenChange = closeHandler(dismissible, onClose);
25
27
  const header = title !== void 0 || description !== void 0;
26
28
  const body = children !== void 0 && children !== null && children !== false;
27
29
  const laidOut = header || footer !== void 0;
28
- const content = /* @__PURE__ */ jsxs(Dialog.Portal, { children: [/* @__PURE__ */ jsx(Dialog.Backdrop, { className: cx("fixed inset-0 z-(--layer-modal)", backdropClassName) }), /* @__PURE__ */ jsx(Dialog.Viewport, {
29
- className: cx("fixed inset-0 z-(--layer-modal) flex justify-center px-4 pt-20 pb-8", align === "center" ? "items-center" : "items-start sm:pt-[max(14vh,5rem)]"),
30
- children: /* @__PURE__ */ jsx(Dialog.Popup, {
31
- ...popupProps,
32
- className: cx(panel && "rounded-xl border border-(--theme-border) bg-(--theme-app-bg) text-(--theme-app) shadow-2xl", size && [sizeClasses[size], "max-w-full"], laidOut && "flex max-h-full flex-col", "outline-none", className),
33
- children: laidOut ? /* @__PURE__ */ jsxs(Fragment, { children: [
34
- header && /* @__PURE__ */ jsxs("div", {
35
- className: cx("shrink-0 px-5 pt-5", !body && "pb-5"),
36
- children: [title !== void 0 && /* @__PURE__ */ jsx(ModalTitle, {
37
- className: "m-0 text-lg font-semibold",
38
- children: title
39
- }), description !== void 0 && /* @__PURE__ */ jsx(ModalDescription, {
40
- className: "m-0 mt-1.5 text-sm text-(--theme-muted-text-color)",
41
- children: description
42
- })]
43
- }),
44
- body && /* @__PURE__ */ jsx("div", {
45
- className: "min-h-0 flex-1 overflow-y-auto overscroll-contain px-5 py-4",
46
- children
47
- }),
48
- footer !== void 0 && /* @__PURE__ */ jsx("div", {
49
- className: "flex shrink-0 items-center justify-end gap-2 border-t border-(--theme-border) px-5 py-3",
50
- children: footer
51
- })
52
- ] }) : children
53
- })
54
- })] });
30
+ const content = /* @__PURE__ */ jsxs(Dialog.Portal, {
31
+ container: fullscreen,
32
+ children: [/* @__PURE__ */ jsx(Dialog.Backdrop, { className: cx("fixed inset-0 z-(--layer-modal)", backdropClassName) }), /* @__PURE__ */ jsx(Dialog.Viewport, {
33
+ className: cx("fixed inset-0 z-(--layer-modal) flex justify-center px-4 pt-20 pb-8", align === "center" ? "items-center" : "items-start sm:pt-[max(14vh,5rem)]"),
34
+ children: /* @__PURE__ */ jsx(Dialog.Popup, {
35
+ ...popupProps,
36
+ className: cx(panel && "rounded-xl border border-(--theme-border) bg-(--theme-app-bg) text-(--theme-app) shadow-2xl", size && [sizeClasses[size], "max-w-full"], laidOut && "flex max-h-full flex-col", "outline-none", className),
37
+ children: laidOut ? /* @__PURE__ */ jsxs(Fragment, { children: [
38
+ header && /* @__PURE__ */ jsxs("div", {
39
+ className: cx("shrink-0 px-5 pt-5", !body && "pb-5"),
40
+ children: [title !== void 0 && /* @__PURE__ */ jsx(ModalTitle, {
41
+ className: "m-0 text-lg font-semibold",
42
+ children: title
43
+ }), description !== void 0 && /* @__PURE__ */ jsx(ModalDescription, {
44
+ className: "m-0 mt-1.5 text-sm text-(--theme-muted-text-color)",
45
+ children: description
46
+ })]
47
+ }),
48
+ body && /* @__PURE__ */ jsx("div", {
49
+ className: "min-h-0 flex-1 overflow-y-auto overscroll-contain px-5 py-4",
50
+ children
51
+ }),
52
+ footer !== void 0 && /* @__PURE__ */ jsx("div", {
53
+ className: "flex shrink-0 items-center justify-end gap-2 border-t border-(--theme-border) px-5 py-3",
54
+ children: footer
55
+ })
56
+ ] }) : children
57
+ })
58
+ })]
59
+ });
55
60
  return alert ? /* @__PURE__ */ jsx(AlertDialog.Root, {
56
61
  open,
57
62
  onOpenChange,
@@ -1,5 +1,6 @@
1
1
  import { cx } from "../cx.js";
2
2
  import { panelClassName, positionerClassName, tipClassName, toPositionerAnchor } from "./floating.js";
3
+ import { useFullscreenContainer } from "./fullscreen.js";
3
4
  import { jsx, jsxs } from "react/jsx-runtime";
4
5
  import { createContext, use, useCallback, useRef } from "react";
5
6
  import { Popover } from "@base-ui/react/popover";
@@ -17,6 +18,7 @@ function useClosePopover() {
17
18
  * returns focus to the trigger. Use a Menu for a list of actions, and a
18
19
  * HoverCard for a preview a link already leads to. */
19
20
  function Popover$1({ trigger, at, title, open, defaultOpen, onOpenChange, side = "bottom", align = "center", openOnHover = false, initialFocus = "first-control", anchor, keepSide = false, variant = "panel", className, children, ...popupProps }) {
21
+ const fullscreen = useFullscreenContainer();
20
22
  const tip = variant === "tip";
21
23
  const popup = useRef(null);
22
24
  const actions = useRef(null);
@@ -33,32 +35,35 @@ function Popover$1({ trigger, at, title, open, defaultOpen, onOpenChange, side =
33
35
  delay: 300,
34
36
  closeDelay: 150
35
37
  } : {}
36
- }), /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(Popover.Positioner, {
37
- side,
38
- align,
39
- sideOffset: tip ? 8 : 6,
40
- collisionPadding: 8,
41
- ...keepSide && { collisionAvoidance: { side: "none" } },
42
- ...at ? { anchor: toPositionerAnchor(at) } : anchor ? { anchor } : {},
43
- className: positionerClassName,
44
- children: /* @__PURE__ */ jsxs(Popover.Popup, {
45
- ...popupProps,
46
- ref: popup,
47
- initialFocus: initialFocus === "popup" ? popup : initialFocus === "first-control",
48
- className: cx(tip ? cx("max-w-sm text-left", tipClassName) : cx(panelClassName, "max-h-(--available-height) max-w-[calc(100vw-16px)] overflow-y-auto p-3"), className),
49
- children: [
50
- tip && /* @__PURE__ */ jsx(Popover.Arrow, { className: "size-2 rotate-45 bg-(--theme-app) data-[side=top]:-bottom-1 data-[side=bottom]:-top-1 data-[side=left]:-right-1 data-[side=right]:-left-1" }),
51
- title && /* @__PURE__ */ jsx(Popover.Title, {
52
- className: "mb-2 text-sm font-semibold",
53
- children: title
54
- }),
55
- /* @__PURE__ */ jsx(CloseContext, {
56
- value: close,
57
- children
58
- })
59
- ]
38
+ }), /* @__PURE__ */ jsx(Popover.Portal, {
39
+ container: fullscreen,
40
+ children: /* @__PURE__ */ jsx(Popover.Positioner, {
41
+ side,
42
+ align,
43
+ sideOffset: tip ? 8 : 6,
44
+ collisionPadding: 8,
45
+ ...keepSide && { collisionAvoidance: { side: "none" } },
46
+ ...at ? { anchor: toPositionerAnchor(at) } : anchor ? { anchor } : {},
47
+ className: positionerClassName,
48
+ children: /* @__PURE__ */ jsxs(Popover.Popup, {
49
+ ...popupProps,
50
+ ref: popup,
51
+ initialFocus: initialFocus === "popup" ? popup : initialFocus === "first-control",
52
+ className: cx(tip ? cx("max-w-sm text-left", tipClassName) : cx(panelClassName, "max-h-(--available-height) max-w-[calc(100vw-16px)] overflow-y-auto p-3"), className),
53
+ children: [
54
+ tip && /* @__PURE__ */ jsx(Popover.Arrow, { className: "size-2 rotate-45 bg-(--theme-app) data-[side=top]:-bottom-1 data-[side=bottom]:-top-1 data-[side=left]:-right-1 data-[side=right]:-left-1" }),
55
+ title && /* @__PURE__ */ jsx(Popover.Title, {
56
+ className: "mb-2 text-sm font-semibold",
57
+ children: title
58
+ }),
59
+ /* @__PURE__ */ jsx(CloseContext, {
60
+ value: close,
61
+ children
62
+ })
63
+ ]
64
+ })
60
65
  })
61
- }) })]
66
+ })]
62
67
  });
63
68
  }
64
69
  //#endregion
@@ -9,7 +9,7 @@ import { RadioGroup } from "@base-ui/react/radio-group";
9
9
  function Radio$1({ className, ...props }) {
10
10
  return /* @__PURE__ */ jsx(Radio.Root, {
11
11
  ...props,
12
- className: cx("flex size-4 shrink-0 items-center justify-center rounded-full border border-(--theme-border-strong) bg-(--theme-input-bg) cursor-pointer transition-colors motion-reduce:transition-none", focusOutline, "data-checked:border-(--theme-accent) data-checked:bg-(--theme-accent)", "aria-invalid:border-(--theme-error)", "data-disabled:cursor-not-allowed data-disabled:opacity-50", className),
12
+ className: cx("flex size-4 shrink-0 items-center justify-center rounded-full border border-(--theme-border-strong) bg-(--theme-input-bg) cursor-pointer transition-colors motion-reduce:transition-none", focusOutline, "data-checked:border-(--theme-focus) data-checked:bg-(--theme-accent)", "aria-invalid:border-(--theme-error)", "data-disabled:cursor-not-allowed data-disabled:opacity-50", className),
13
13
  children: /* @__PURE__ */ jsx(Radio.Indicator, { className: "size-1.5 rounded-full bg-(--theme-accent-text)" })
14
14
  });
15
15
  }
@@ -1,6 +1,7 @@
1
1
  import { cx } from "../cx.js";
2
2
  import { CheckIcon, ChevronDownIcon } from "../icons.js";
3
3
  import { panelClassName, positionerClassName } from "./floating.js";
4
+ import { useFullscreenContainer } from "./fullscreen.js";
4
5
  import { Tooltip } from "./Tooltip.js";
5
6
  import { fieldBox } from "./fieldBox.js";
6
7
  import { optionNaming, pickerItemClassName } from "./comboboxItems.js";
@@ -13,6 +14,7 @@ var triggerClassName = "flex cursor-pointer items-center justify-between gap-2 p
13
14
  /** Picks one value, or several with `multiple`, from a short list. Use
14
15
  * Combobox when the list is long enough to need filtering. */
15
16
  function Select$1({ items, placeholder, className, "aria-label": ariaLabel, "aria-labelledby": labelledBy, "aria-describedby": describedBy, "aria-invalid": invalid, "aria-required": required, trigger, triggerTooltip, size = "md", onItemHighlighted, ...rootProps }) {
17
+ const fullscreen = useFullscreenContainer();
16
18
  const uid = useId();
17
19
  const labelOf = (value) => items.find((item) => Object.is(item.value, value))?.label;
18
20
  const triggerProps = {
@@ -46,51 +48,54 @@ function Select$1({ items, placeholder, className, "aria-label": ariaLabel, "ari
46
48
  className: "shrink-0 text-(--theme-muted-text-color)",
47
49
  children: /* @__PURE__ */ jsx(ChevronDownIcon, { "aria-hidden": "true" })
48
50
  })]
49
- }), /* @__PURE__ */ jsx(Select.Portal, { children: /* @__PURE__ */ jsx(Select.Positioner, {
50
- alignItemWithTrigger: false,
51
- sideOffset: 4,
52
- className: positionerClassName,
53
- children: /* @__PURE__ */ jsx(Select.Popup, {
54
- className: cx("min-w-(--anchor-width) max-w-[min(20rem,var(--available-width))]", panelClassName),
55
- children: /* @__PURE__ */ jsx(Select.List, {
56
- className: cx("max-h-[min(15rem,var(--available-height))] overflow-y-auto", "p-1"),
57
- children: items.map((item, index) => /* @__PURE__ */ jsxs(Select.Item, {
58
- value: item.value,
59
- disabled: item.disabled,
60
- ...optionNaming(`${uid}${index}`, item),
61
- onFocus: onItemHighlighted && (() => onItemHighlighted(item.value)),
62
- className: pickerItemClassName,
63
- children: [
64
- item.icon && /* @__PURE__ */ jsx("span", {
65
- className: "flex shrink-0 items-center",
66
- children: item.icon
67
- }),
68
- /* @__PURE__ */ jsxs("span", {
69
- className: "flex min-w-0 flex-col",
70
- children: [/* @__PURE__ */ jsxs("span", {
71
- className: "flex min-w-0 items-center gap-2",
72
- children: [/* @__PURE__ */ jsx(Select.ItemText, {
73
- id: `${uid}${index}label`,
74
- className: "truncate",
75
- children: item.label
76
- }), item.badge]
77
- }), /* @__PURE__ */ jsx(OptionDescription, {
78
- id: `${uid}${index}description`,
79
- item
80
- })]
81
- }),
82
- /* @__PURE__ */ jsx(Select.ItemIndicator, {
83
- className: "ml-auto flex shrink-0 items-center",
84
- children: /* @__PURE__ */ jsx(CheckIcon, {
85
- "aria-hidden": "true",
86
- className: "size-3.5"
51
+ }), /* @__PURE__ */ jsx(Select.Portal, {
52
+ container: fullscreen,
53
+ children: /* @__PURE__ */ jsx(Select.Positioner, {
54
+ alignItemWithTrigger: false,
55
+ sideOffset: 4,
56
+ className: positionerClassName,
57
+ children: /* @__PURE__ */ jsx(Select.Popup, {
58
+ className: cx("min-w-(--anchor-width) max-w-[min(20rem,var(--available-width))]", panelClassName),
59
+ children: /* @__PURE__ */ jsx(Select.List, {
60
+ className: cx("max-h-[min(15rem,var(--available-height))] overflow-y-auto", "p-1"),
61
+ children: items.map((item, index) => /* @__PURE__ */ jsxs(Select.Item, {
62
+ value: item.value,
63
+ disabled: item.disabled,
64
+ ...optionNaming(`${uid}${index}`, item),
65
+ onFocus: onItemHighlighted && (() => onItemHighlighted(item.value)),
66
+ className: pickerItemClassName,
67
+ children: [
68
+ item.icon && /* @__PURE__ */ jsx("span", {
69
+ className: "flex shrink-0 items-center",
70
+ children: item.icon
71
+ }),
72
+ /* @__PURE__ */ jsxs("span", {
73
+ className: "flex min-w-0 flex-col",
74
+ children: [/* @__PURE__ */ jsxs("span", {
75
+ className: "flex min-w-0 items-center gap-2",
76
+ children: [/* @__PURE__ */ jsx(Select.ItemText, {
77
+ id: `${uid}${index}label`,
78
+ className: "truncate",
79
+ children: item.label
80
+ }), item.badge]
81
+ }), /* @__PURE__ */ jsx(OptionDescription, {
82
+ id: `${uid}${index}description`,
83
+ item
84
+ })]
85
+ }),
86
+ /* @__PURE__ */ jsx(Select.ItemIndicator, {
87
+ className: "ml-auto flex shrink-0 items-center",
88
+ children: /* @__PURE__ */ jsx(CheckIcon, {
89
+ "aria-hidden": "true",
90
+ className: "size-3.5"
91
+ })
87
92
  })
88
- })
89
- ]
90
- }, String(item.value)))
93
+ ]
94
+ }, String(item.value)))
95
+ })
91
96
  })
92
97
  })
93
- }) })]
98
+ })]
94
99
  });
95
100
  }
96
101
  //#endregion
@@ -17,10 +17,10 @@ function Slider$1({ value, onValueChange, min, max, step = 1, disabled = false,
17
17
  children: /* @__PURE__ */ jsx(Slider.Control, {
18
18
  className: "flex w-full touch-none select-none items-center py-2 data-disabled:cursor-not-allowed data-disabled:opacity-50",
19
19
  children: /* @__PURE__ */ jsxs(Slider.Track, {
20
- className: "h-1 w-full rounded-full bg-(--theme-border)",
21
- children: [/* @__PURE__ */ jsx(Slider.Indicator, { className: "rounded-full bg-(--theme-accent)" }), /* @__PURE__ */ jsx(Slider.Thumb, {
20
+ className: "h-1 w-full rounded-full bg-(--theme-border-strong)",
21
+ children: [/* @__PURE__ */ jsx(Slider.Indicator, { className: "rounded-full bg-(--theme-focus)" }), /* @__PURE__ */ jsx(Slider.Thumb, {
22
22
  "aria-label": ariaLabel,
23
- className: "size-4 rounded-full border-2 border-(--theme-accent) bg-(--theme-panel-bg) shadow-sm has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-(--theme-focus)"
23
+ className: "size-4 rounded-full border-2 border-(--theme-focus) bg-(--theme-panel-bg) shadow-sm has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-(--theme-focus)"
24
24
  })]
25
25
  })
26
26
  })
@@ -21,7 +21,7 @@ var sizes = {
21
21
  function Switch$1({ size = "md", className, onLabel, offLabel, ...props }) {
22
22
  const control = /* @__PURE__ */ jsx(Switch.Root, {
23
23
  ...props,
24
- className: cx("peer inline-flex shrink-0 items-center rounded-full p-0.5 bg-(--theme-border-strong) transition-colors duration-200 cursor-pointer motion-reduce:transition-none", "data-checked:bg-(--theme-accent)", focusOutline, "aria-invalid:ring-2 aria-invalid:ring-(--theme-error)", "data-disabled:cursor-not-allowed data-disabled:opacity-50", sizes[size].root, className),
24
+ className: cx("peer inline-flex shrink-0 items-center rounded-full p-0.5 bg-(--theme-border-strong) transition-colors duration-200 cursor-pointer motion-reduce:transition-none", "data-checked:bg-(--theme-focus)", focusOutline, "aria-invalid:ring-2 aria-invalid:ring-(--theme-error)", "data-disabled:cursor-not-allowed data-disabled:opacity-50", sizes[size].root, className),
25
25
  children: /* @__PURE__ */ jsx(Switch.Thumb, { className: cx("rounded-full bg-white shadow-sm transition-transform duration-200 motion-reduce:transition-none", sizes[size].thumb) })
26
26
  });
27
27
  if (onLabel === void 0 && offLabel === void 0) return control;
@@ -1,4 +1,5 @@
1
1
  import { positionerClassName, tipArrowClassName, tipClassName } from "./floating.js";
2
+ import { useFullscreenContainer } from "./fullscreen.js";
2
3
  import { keyedByContent } from "./keys.js";
3
4
  import { jsx, jsxs } from "react/jsx-runtime";
4
5
  import { Fragment as Fragment$1, createContext, use, useState } from "react";
@@ -19,18 +20,22 @@ function KbdShortcut({ keys }) {
19
20
  });
20
21
  }
21
22
  function TooltipPopup({ content, shortcut, side }) {
22
- return /* @__PURE__ */ jsx(Tooltip.Portal, { children: /* @__PURE__ */ jsx(Tooltip.Positioner, {
23
- side,
24
- sideOffset: 8,
25
- className: positionerClassName,
26
- children: /* @__PURE__ */ jsxs(Tooltip.Popup, {
27
- className: `max-w-xs ${tipClassName}`,
28
- children: [/* @__PURE__ */ jsx(Tooltip.Arrow, { className: tipArrowClassName }), shortcut ? /* @__PURE__ */ jsxs("span", {
29
- className: "inline-flex items-center gap-2",
30
- children: [content, /* @__PURE__ */ jsx(KbdShortcut, { keys: shortcut })]
31
- }) : content]
23
+ const fullscreen = useFullscreenContainer();
24
+ return /* @__PURE__ */ jsx(Tooltip.Portal, {
25
+ container: fullscreen,
26
+ children: /* @__PURE__ */ jsx(Tooltip.Positioner, {
27
+ side,
28
+ sideOffset: 8,
29
+ className: positionerClassName,
30
+ children: /* @__PURE__ */ jsxs(Tooltip.Popup, {
31
+ className: `max-w-xs ${tipClassName}`,
32
+ children: [/* @__PURE__ */ jsx(Tooltip.Arrow, { className: tipArrowClassName }), shortcut ? /* @__PURE__ */ jsxs("span", {
33
+ className: "inline-flex items-center gap-2",
34
+ children: [content, /* @__PURE__ */ jsx(KbdShortcut, { keys: shortcut })]
35
+ }) : content]
36
+ })
32
37
  })
33
- }) });
38
+ });
34
39
  }
35
40
  /** One popup serves every Tooltip below it, so each anchor costs only a trigger.
36
41
  * UIProvider mounts it; nothing else needs to. */
@@ -20,7 +20,7 @@ var sizes = {
20
20
  * thumb: an outline in the theme's focus color, which is solved for 3:1 on every surface a
21
21
  * control sits on, so it shows on a checked control as well as an empty one. */
22
22
  var focusOutline = "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--theme-focus)";
23
- var base = "w-full min-w-0 rounded-md border border-(--theme-border) bg-(--theme-input-bg) text-(--theme-app) outline-none transition-colors placeholder:text-(--theme-placeholder)";
23
+ var base = "w-full min-w-0 rounded-md border border-(--theme-border-strong) bg-(--theme-input-bg) text-(--theme-app) outline-none transition-colors placeholder:text-(--theme-placeholder)";
24
24
  var own = cx("focus-visible:border-(--theme-focus) focus-visible:ring-1 focus-visible:ring-(--theme-focus)", "aria-invalid:border-(--theme-error) aria-invalid:focus-visible:ring-(--theme-error)", "disabled:cursor-not-allowed disabled:bg-(--theme-input-disabled-bg) disabled:text-(--theme-placeholder)", "data-disabled:cursor-not-allowed data-disabled:bg-(--theme-input-disabled-bg) data-disabled:text-(--theme-placeholder)");
25
25
  var inside = cx("has-[:focus-visible]:border-(--theme-focus) has-[:focus-visible]:ring-1 has-[:focus-visible]:ring-(--theme-focus)", "has-[[aria-invalid=true]]:border-(--theme-error) has-[[aria-invalid=true]:focus-visible]:ring-(--theme-error)", "has-[input:disabled]:cursor-not-allowed has-[input:disabled]:bg-(--theme-input-disabled-bg) has-[input:disabled]:text-(--theme-placeholder)", "data-disabled:cursor-not-allowed data-disabled:bg-(--theme-input-disabled-bg) data-disabled:text-(--theme-placeholder)");
26
26
  /** The box every input-like control draws: text inputs, textareas, and the triggers of
@@ -0,0 +1,4 @@
1
+ /** Where a popup portals while an element is fullscreen: that element. The browser
2
+ * shows only the fullscreen element's subtree, so a popup portaled to the body
3
+ * would open unseen behind it. Undefined otherwise, which keeps the body. */
4
+ export declare function useFullscreenContainer(): HTMLElement | undefined;
@@ -0,0 +1,18 @@
1
+ import { useSyncExternalStore } from "react";
2
+ //#region src/components/fullscreen.ts
3
+ function subscribe(onChange) {
4
+ document.addEventListener("fullscreenchange", onChange);
5
+ return () => document.removeEventListener("fullscreenchange", onChange);
6
+ }
7
+ function snapshot() {
8
+ const element = document.fullscreenElement;
9
+ return element instanceof HTMLElement ? element : void 0;
10
+ }
11
+ /** Where a popup portals while an element is fullscreen: that element. The browser
12
+ * shows only the fullscreen element's subtree, so a popup portaled to the body
13
+ * would open unseen behind it. Undefined otherwise, which keeps the body. */
14
+ function useFullscreenContainer() {
15
+ return useSyncExternalStore(subscribe, snapshot, () => void 0);
16
+ }
17
+ //#endregion
18
+ export { useFullscreenContainer };
@@ -12,7 +12,7 @@ export declare const STEP_FIELDS: readonly ['name', 'run', 'shell', 'uses', 'wit
12
12
  export declare const RETRY_FIELDS: readonly ['max-retries', 'interval', 'timeout', 'clean-on-retry'];
13
13
  interface ViewProps {
14
14
  source?: string | undefined;
15
- /** Adds the job or step being edited; applied with the first save, so cancelling adds nothing. */
15
+ /** Adds the job or step being edited; applied with the first save, so canceling adds nothing. */
16
16
  addition?: GraphEdit | undefined;
17
17
  /** The view to open in; YAML unless the host says form. */
18
18
  view?: SettingsView | undefined;
@@ -23,7 +23,7 @@
23
23
  --theme-placeholder: light-dark(#7e8796, #9da5ad);
24
24
  --theme-link: light-dark(#06354f, #9dd7ff);
25
25
  --theme-border: light-dark(#cacdd0, #30363d);
26
- --theme-border-strong: light-dark(#a3a6a9, #4f565d);
26
+ --theme-border-strong: light-dark(#848689, #676e76);
27
27
  --theme-accent: light-dark(#06354f, #5b9ccf);
28
28
  --theme-accent-text: light-dark(#ffffff, #000000);
29
29
  --theme-accent-hover: light-dark(#002841, #6aace0);