@parallelworks/ui 0.78.0 → 0.80.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 (37) hide show
  1. package/README.md +12 -1
  2. package/dist/access/AccessDrawer.d.ts +22 -1
  3. package/dist/access/AccessDrawer.js +33 -9
  4. package/dist/access/index.d.ts +1 -1
  5. package/dist/access/strings.d.ts +7 -1
  6. package/dist/access/strings.js +7 -1
  7. package/dist/ai/components/ChatMessageList.js +21 -6
  8. package/dist/components/Combobox.js +56 -32
  9. package/dist/components/ConfirmModal.d.ts +5 -3
  10. package/dist/components/ConfirmModal.js +22 -3
  11. package/dist/components/ContextMenu.d.ts +8 -0
  12. package/dist/components/ContextMenu.js +42 -6
  13. package/dist/components/CreateModal.d.ts +5 -1
  14. package/dist/components/CreateModal.js +2 -2
  15. package/dist/components/Disclosure.d.ts +6 -2
  16. package/dist/components/Disclosure.js +24 -2
  17. package/dist/components/MenuEntries.d.ts +3 -2
  18. package/dist/components/MenuEntries.js +1 -1
  19. package/dist/components/Popover.d.ts +4 -1
  20. package/dist/components/Popover.js +3 -3
  21. package/dist/components/Provider.d.ts +32 -2
  22. package/dist/components/Provider.js +16 -3
  23. package/dist/components/segmented.js +1 -1
  24. package/dist/graph/InputsEditor.js +3 -2
  25. package/dist/graph/ProblemPageLink.d.ts +9 -0
  26. package/dist/graph/ProblemPageLink.js +21 -0
  27. package/dist/graph/ProblemsButton.js +23 -13
  28. package/dist/graph/RunWarningsList.js +20 -11
  29. package/dist/graph/editorApi.d.ts +10 -0
  30. package/dist/graph/editorRows.js +3 -1
  31. package/dist/graph/editorStrings.d.ts +1 -0
  32. package/dist/graph/editorStrings.js +1 -0
  33. package/dist/graph/runWarnings.d.ts +12 -1
  34. package/dist/index.d.ts +2 -2
  35. package/dist/index.js +3 -3
  36. package/dist/styles.css +1 -1
  37. package/package.json +2 -2
@@ -1,4 +1,4 @@
1
- import type { MouseEventHandler, ReactNode } from 'react';
1
+ import { type MouseEventHandler, type ReactNode } from 'react';
2
2
  /** The height a collapsible panel animates as it opens and closes. It clips
3
3
  * only while it moves, so focus rings and overflowing content show once open. */
4
4
  export declare const collapsePanelClassName = "h-(--collapsible-panel-height) transition-[height,opacity] duration-200 ease-out motion-reduce:transition-none data-starting-style:h-0 data-starting-style:overflow-hidden data-starting-style:opacity-0 data-ending-style:h-0 data-ending-style:overflow-hidden data-ending-style:opacity-0";
@@ -23,6 +23,10 @@ export interface DisclosureProps {
23
23
  /** Controls beside the summary, outside the toggle, so a row can hold buttons without
24
24
  * nesting them in it. */
25
25
  actions?: ReactNode;
26
+ /** Controls that read as part of the summary, right after it on its line, such as a button
27
+ * that says why a row failed. They sit outside the toggle, so no button holds another and
28
+ * each is its own stop for Tab; a click on the rest of the line still toggles. */
29
+ summaryControls?: ReactNode;
26
30
  /** On the whole disclosure, summary and detail, such as a row's own menu. */
27
31
  onContextMenu?: MouseEventHandler<HTMLDivElement> | undefined;
28
32
  children: ReactNode;
@@ -30,7 +34,7 @@ export interface DisclosureProps {
30
34
  /** A line inside content that reveals more detail beneath it, such as a tool
31
35
  * call's arguments or a model's reasoning. For a titled part of a page or
32
36
  * form, which belongs in the page's outline, use Section. */
33
- export declare function Disclosure({ summary, open, onOpenChange, defaultOpen, disabled, keepMounted, className, summaryClassName, panelClassName, chevron, actions, onContextMenu, children, }: DisclosureProps): import("react").JSX.Element;
37
+ export declare function Disclosure({ summary, open, onOpenChange, defaultOpen, disabled, keepMounted, className, summaryClassName, panelClassName, chevron, actions, summaryControls, onContextMenu, children, }: DisclosureProps): import("react").JSX.Element;
34
38
  /** The revealing panel alone, for a toggle that lives elsewhere, such as a
35
39
  * tree row's chevron that names this panel with `aria-controls`. */
36
40
  export declare function DisclosurePanel({ open, id, keepMounted, className, children, }: {
@@ -1,5 +1,6 @@
1
1
  import { cx } from "../cx.js";
2
2
  import { ChevronRightIcon } from "../icons.js";
3
+ import { useRef } from "react";
3
4
  import { jsx, jsxs } from "react/jsx-runtime";
4
5
  import { Collapsible } from "@base-ui/react/collapsible";
5
6
  //#region src/components/Disclosure.tsx
@@ -9,8 +10,11 @@ var collapsePanelClassName = "h-(--collapsible-panel-height) transition-[height,
9
10
  /** A line inside content that reveals more detail beneath it, such as a tool
10
11
  * call's arguments or a model's reasoning. For a titled part of a page or
11
12
  * form, which belongs in the page's outline, use Section. */
12
- function Disclosure({ summary, open, onOpenChange, defaultOpen = false, disabled = false, keepMounted = false, className, summaryClassName, panelClassName, chevron = true, actions, onContextMenu, children }) {
13
+ function Disclosure({ summary, open, onOpenChange, defaultOpen = false, disabled = false, keepMounted = false, className, summaryClassName, panelClassName, chevron = true, actions, summaryControls, onContextMenu, children }) {
14
+ const trigger = useRef(null);
15
+ const hasControls = summaryControls !== void 0 && summaryControls !== null && summaryControls !== false;
13
16
  const toggle = /* @__PURE__ */ jsxs(Collapsible.Trigger, {
17
+ ref: trigger,
14
18
  className: cx("group/disclosure flex min-w-0 items-start gap-2 rounded-sm text-left focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--theme-focus)", disabled ? "cursor-default" : "cursor-pointer", summaryClassName),
15
19
  children: [summary, !disabled && chevron && /* @__PURE__ */ jsx(ChevronRightIcon, {
16
20
  "aria-hidden": "true",
@@ -24,7 +28,25 @@ function Disclosure({ summary, open, onOpenChange, defaultOpen = false, disabled
24
28
  disabled,
25
29
  className,
26
30
  onContextMenu,
27
- children: [actions ? /* @__PURE__ */ jsxs("div", {
31
+ children: [hasControls ? /* @__PURE__ */ jsxs("div", {
32
+ className: "flex min-w-0 items-center gap-2",
33
+ children: [
34
+ toggle,
35
+ /* @__PURE__ */ jsx("div", {
36
+ className: "flex shrink-0 items-center gap-1",
37
+ children: summaryControls
38
+ }),
39
+ /* @__PURE__ */ jsx("div", {
40
+ "aria-hidden": "true",
41
+ className: cx("min-w-0 flex-1 self-stretch", !disabled && "cursor-pointer"),
42
+ onClick: () => trigger.current?.click()
43
+ }),
44
+ actions && /* @__PURE__ */ jsx("div", {
45
+ className: "flex shrink-0 items-center gap-1",
46
+ children: actions
47
+ })
48
+ ]
49
+ }) : actions ? /* @__PURE__ */ jsxs("div", {
28
50
  className: "flex min-w-0 items-center gap-2",
29
51
  children: [/* @__PURE__ */ jsx("div", {
30
52
  className: "flex min-w-0 flex-1",
@@ -45,11 +45,12 @@ interface MenuLinkAction extends MenuActionBase {
45
45
  checked?: never;
46
46
  copy?: never;
47
47
  }
48
- /** Copies `copy.text` to the clipboard, confirmed with a toast naming `copy.label`. */
48
+ /** Copies `copy.text` to the clipboard, confirmed with a toast naming `copy.label`, or
49
+ * saying only that it copied without one. A failure says so too. */
49
50
  interface MenuCopyAction extends MenuActionBase {
50
51
  copy: {
51
52
  text: string;
52
- label: string;
53
+ label?: string | undefined;
53
54
  };
54
55
  onClick?: never;
55
56
  checked?: never;
@@ -188,7 +188,7 @@ var shortcutClassName = "ps-3 text-xs text-(--theme-muted-text-color) tabular-nu
188
188
  function RowContent({ icon, label, description, end }) {
189
189
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [
190
190
  icon !== void 0 && icon !== null && /* @__PURE__ */ jsx("span", {
191
- className: "flex h-5 shrink-0 items-center in-data-[size=sm]:h-4",
191
+ className: "flex h-5 min-w-4 shrink-0 items-center justify-center in-data-[size=sm]:h-4",
192
192
  children: icon
193
193
  }),
194
194
  /* @__PURE__ */ jsxs("span", {
@@ -52,6 +52,9 @@ export interface PopoverOptions extends Omit<BasePopover.Popup.Props, 'className
52
52
  sheet?: boolean | undefined;
53
53
  /** `panel` holds controls or a list; `tip` is a tooltip-sized note in the tooltip's look. */
54
54
  variant?: 'panel' | 'tip';
55
+ /** A panel's content reaches its edges, such as a list of suggestions whose rows pad
56
+ * themselves and highlight edge to edge. A title keeps its own padding. */
57
+ flush?: boolean | undefined;
55
58
  /** On the popup: its width, padding or text size. */
56
59
  className?: string;
57
60
  children: ReactNode;
@@ -60,5 +63,5 @@ export interface PopoverOptions extends Omit<BasePopover.Popup.Props, 'className
60
63
  * flips and shifts to stay on screen, closes on Escape or a press outside, and
61
64
  * returns focus to the trigger. Use a Menu for a list of actions, and a
62
65
  * HoverCard for a preview a link already leads to. */
63
- export declare function Popover({ trigger, at, title, open, defaultOpen, onOpenChange, side, align, openOnHover, hoverDelay, hoverCloseDelay, initialFocus, anchor, keepSide, variant, sheet, className, children, ...popupProps }: PopoverProps): import("react").JSX.Element;
66
+ export declare function Popover({ trigger, at, title, open, defaultOpen, onOpenChange, side, align, openOnHover, hoverDelay, hoverCloseDelay, initialFocus, anchor, keepSide, variant, sheet, flush, className, children, ...popupProps }: PopoverProps): import("react").JSX.Element;
64
67
  export {};
@@ -19,7 +19,7 @@ var sheetPopupClassName = "max-sm:w-auto! max-sm:max-w-none! max-sm:max-h-[min(7
19
19
  * flips and shifts to stay on screen, closes on Escape or a press outside, and
20
20
  * returns focus to the trigger. Use a Menu for a list of actions, and a
21
21
  * HoverCard for a preview a link already leads to. */
22
- function Popover$1({ trigger, at, title, open, defaultOpen, onOpenChange, side = "bottom", align = "center", openOnHover = false, hoverDelay = 300, hoverCloseDelay = 150, initialFocus = "first-control", anchor, keepSide = false, variant = "panel", sheet, className, children, ...popupProps }) {
22
+ function Popover$1({ trigger, at, title, open, defaultOpen, onOpenChange, side = "bottom", align = "center", openOnHover = false, hoverDelay = 300, hoverCloseDelay = 150, initialFocus = "first-control", anchor, keepSide = false, variant = "panel", sheet, flush = false, className, children, ...popupProps }) {
23
23
  const portal = usePopupContainer();
24
24
  const tip = variant === "tip";
25
25
  const asSheet = sheet ?? (!tip && !at);
@@ -52,9 +52,9 @@ function Popover$1({ trigger, at, title, open, defaultOpen, onOpenChange, side =
52
52
  ...popupProps,
53
53
  ref: popup,
54
54
  initialFocus: initialFocus === "popup" ? popup : initialFocus === "first-control",
55
- className: cx(tip ? cx("text-left", tipClassName) : cx(panelClassName, "max-h-(--available-height) max-w-[calc(100vw-16px)] overflow-y-auto p-3"), className, asSheet && sheetPopupClassName),
55
+ className: cx(tip ? cx("text-left", tipClassName) : cx(panelClassName, "max-h-(--available-height) max-w-[calc(100vw-16px)] overflow-y-auto", !flush && "p-3"), className, asSheet && sheetPopupClassName),
56
56
  children: [title && /* @__PURE__ */ jsx(Popover.Title, {
57
- className: "mb-2 text-sm font-semibold",
57
+ className: cx("mb-2 text-sm font-semibold", flush && !tip && "px-3 pt-3"),
58
58
  children: title
59
59
  }), /* @__PURE__ */ jsx(CloseContext, {
60
60
  value: close,
@@ -288,6 +288,8 @@ export interface UIStrings {
288
288
  /** How many warnings: the title of a run's list of warnings, and the name of the mark on a job
289
289
  * or step they're about, such as "2 warnings". */
290
290
  warningCount: (count: number) => string;
291
+ /** The link from a warning to the page that explains it, when it has one. */
292
+ warningAbout: string;
291
293
  };
292
294
  jobActions: {
293
295
  openSubworkflowLogs: string;
@@ -733,6 +735,22 @@ export interface RunFileResult {
733
735
  error: unknown;
734
736
  }
735
737
  export type PersistedStateHook = <T>(key: string, defaultValue: T) => [T, Dispatch<SetStateAction<T>>];
738
+ /** The values a problem's message shows, by name, as a problem's `params` carries them. */
739
+ export type ProblemParams = Readonly<Record<string, string | number>>;
740
+ /** A problem code's message in the reader's language, with its params; undefined when the host has
741
+ * none for the code. `type` is the problem's type URI: one that names an application, such as
742
+ * `/problems/workflow/undefined_input`, picks that application's message for the code over the
743
+ * host's own. */
744
+ export type ProblemMessage = (code: string, params?: ProblemParams, type?: string) => string | undefined;
745
+ /** A problem that may carry a code: a run's warning, or one the workflow editor marks. */
746
+ export interface CodedProblem {
747
+ /** Its text as the server wrote it, shown when the host has no message for its code. */
748
+ message: string;
749
+ code?: string | null | undefined;
750
+ params?: ProblemParams | null | undefined;
751
+ /** Its type URI, which the host's message for its code is looked up by too. */
752
+ type?: string | null | undefined;
753
+ }
736
754
  export interface UIData {
737
755
  /**
738
756
  * Host-bound hook resolving a file in a run's artifact tree (logs, scripts).
@@ -763,6 +781,14 @@ export interface UIData {
763
781
  error?: string;
764
782
  }>;
765
783
  usePersistedState: PersistedStateHook;
784
+ /**
785
+ * Host-bound hook returning a problem code's message in the reader's language, such as
786
+ * `useCodeMessage` from `@parallelworks/problem/react`. A run's warnings and the editor's
787
+ * problems that carry a `code` show it, given their `params` and `type`, and their own `message`
788
+ * when it gives nothing. Absent, they show their `message`. Must be a stable function reference —
789
+ * components call it as a hook.
790
+ */
791
+ useProblemMessage: () => ProblemMessage;
766
792
  }
767
793
  import type { FieldComponent } from '../form/fieldRegistry.js';
768
794
  import type { Breadcrumb } from './Breadcrumbs.js';
@@ -864,6 +890,9 @@ export declare function useProvisionCorsRules(): UIData['provisionCorsRules'];
864
890
  export declare function useRunFile(slug: string, path: string | null, options?: {
865
891
  refreshInterval?: number;
866
892
  }): RunFileResult;
893
+ /** A coded problem's text in the reader's language: the host's message for its code and type, or
894
+ * else its own `message`. */
895
+ export declare function useProblemText(): (problem: CodedProblem) => string;
867
896
  export declare function usePersistedState<T>(key: string, defaultValue: T): [T, Dispatch<SetStateAction<T>>];
868
897
  export interface UIProviderProps {
869
898
  /** Translations over the English defaults, at any depth. Define them outside a component, or
@@ -871,8 +900,9 @@ export interface UIProviderProps {
871
900
  strings?: UIStringOverrides | undefined;
872
901
  /** How the package navigates; read at the moment it navigates, so a new one never re-renders. */
873
902
  navigation?: Partial<UINavigation> | undefined;
874
- /** The host's data hooks and resolvers. `useRunFile` and `usePersistedState` are called as
875
- * hooks, so each must stay the same function for the life of the app. */
903
+ /** The host's data hooks and resolvers. `useRunFile`, `usePersistedState` and
904
+ * `useProblemMessage` are called as hooks, so each must stay the same function for the life of
905
+ * the app. */
876
906
  data?: Partial<UIData> | undefined;
877
907
  /** Components the host renders inside the package's; a component made each render would
878
908
  * remount everything it renders. */
@@ -320,7 +320,8 @@ var DEFAULTS = {
320
320
  ].filter(([count]) => count).map(([count, one, many]) => `${count} ${count === 1 ? one : many}`).join(", ")}`,
321
321
  annotationSource: (job, step) => `in ${job} → ${step}`,
322
322
  stepNumber: (index) => `step ${index}`,
323
- warningCount: (count) => count === 1 ? "1 warning" : `${count} warnings`
323
+ warningCount: (count) => count === 1 ? "1 warning" : `${count} warnings`,
324
+ warningAbout: "About this warning"
324
325
  },
325
326
  jobActions: {
326
327
  openSubworkflowLogs: "Open subworkflow logs",
@@ -692,7 +693,8 @@ var DEFAULTS = {
692
693
  },
693
694
  data: {
694
695
  useRunFile: defaultUseRunFile,
695
- usePersistedState: useLocalPersistedState
696
+ usePersistedState: useLocalPersistedState,
697
+ useProblemMessage: useNoProblemMessage
696
698
  },
697
699
  slots: {}
698
700
  };
@@ -802,6 +804,17 @@ function useRunFile(slug, path, options) {
802
804
  const { useRunFile: boundUseRunFile } = useContext(DataContext);
803
805
  return boundUseRunFile(slug, path, options);
804
806
  }
807
+ var noProblemMessage = () => void 0;
808
+ function useNoProblemMessage() {
809
+ return noProblemMessage;
810
+ }
811
+ /** A coded problem's text in the reader's language: the host's message for its code and type, or
812
+ * else its own `message`. */
813
+ function useProblemText() {
814
+ const { useProblemMessage: boundUseProblemMessage } = useContext(DataContext);
815
+ const message = boundUseProblemMessage();
816
+ return useCallback((problem) => (problem.code ? message(problem.code, problem.params ?? void 0, problem.type ?? void 0) : void 0) ?? problem.message, [message]);
817
+ }
805
818
  function usePersistedState(key, defaultValue) {
806
819
  const { usePersistedState: boundUsePersistedState } = useContext(DataContext);
807
820
  return boundUsePersistedState(key, defaultValue);
@@ -869,4 +882,4 @@ function UIProvider({ strings, navigation, data, slots, engine: engineProp, nonc
869
882
  });
870
883
  }
871
884
  //#endregion
872
- export { UIProvider, useAvatarColoring, useLink, useLoadedWorkflowEngine, useLocale, useNavigation, useOptionalWorkflowEngine, usePersistedState, useProvisionCorsRules, useRepoSuggestions, useRunFile, useSecretVariablesResolver, useSlots, useStrings, useWorkflowActions, useWorkflowEditing, useWorkflowEngine, useWorkflowEngineLoader, useWorkflowJsonResolver };
885
+ export { UIProvider, useAvatarColoring, useLink, useLoadedWorkflowEngine, useLocale, useNavigation, useOptionalWorkflowEngine, usePersistedState, useProblemText, useProvisionCorsRules, useRepoSuggestions, useRunFile, useSecretVariablesResolver, useSlots, useStrings, useWorkflowActions, useWorkflowEditing, useWorkflowEngine, useWorkflowEngineLoader, useWorkflowJsonResolver };
@@ -34,7 +34,7 @@ function segmentGroupClassName({ fill, iconOnly }) {
34
34
  return cx("gap-0.5", iconOnly ? "flex flex-col items-center" : cx("rounded-lg theme-muted-panel p-0.5", fillGroup[fillKey(fill)]));
35
35
  }
36
36
  function segmentClassName(current, { fill, iconOnly, size = "md" }, tone) {
37
- return cx("relative flex min-w-0 cursor-pointer items-center justify-center rounded-md font-medium transition-colors duration-150 focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-(--theme-focus) data-disabled:cursor-not-allowed data-disabled:opacity-50", current ? "bg-(--theme-panel-bg) shadow-sm ring-1 ring-(--theme-border)" : "hover:not-data-disabled:bg-(--theme-hover)", tone ? toneText[tone] : current ? "theme-text" : "theme-muted-text hover:not-data-disabled:theme-text", iconOnly ? "h-8 w-8" : segmentSizes[size][fillKey(fill)]);
37
+ return cx("relative flex min-w-0 cursor-pointer items-center justify-center rounded-md font-medium transition-colors duration-150 focus-visible:z-10 focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-(--theme-focus) data-disabled:cursor-not-allowed data-disabled:opacity-50", current ? "bg-(--theme-panel-bg) shadow-sm ring-1 ring-(--theme-border)" : "hover:not-data-disabled:bg-(--theme-hover)", tone ? toneText[tone] : current ? "theme-text" : "theme-muted-text hover:not-data-disabled:theme-text", iconOnly ? "h-8 w-8" : segmentSizes[size][fillKey(fill)]);
38
38
  }
39
39
  /** How many things a tab or segment holds, as a pill after its label. */
40
40
  function CountPill({ count, tone }) {
@@ -3,7 +3,7 @@ import { EmptyState } from "../components/EmptyState.js";
3
3
  import { AddIcon, ArrowDownIcon, ArrowUpIcon, CollapseIcon, DragHandleIcon, DuplicateIcon, EditIcon, FilesIcon, MinusIcon, MoreIcon, TrashIcon, WarningIcon } from "../icons.js";
4
4
  import { useContextMenu } from "../components/ContextMenu.js";
5
5
  import { Tooltip } from "../components/Tooltip.js";
6
- import { useWorkflowEditing } from "../components/Provider.js";
6
+ import { useProblemText, useWorkflowEditing } from "../components/Provider.js";
7
7
  import { menuDivider } from "../components/MenuEntries.js";
8
8
  import { IconButton } from "../components/IconButton.js";
9
9
  import { NumberInput } from "../components/NumberInput.js";
@@ -100,7 +100,8 @@ function InputRow({ path, hidden = false, instance, children }) {
100
100
  const copy = instance ?? rowKey;
101
101
  const active = useUi(api?.store ?? EMPTY_STORE, (state) => state.open.includes(copy) && !state.drag && !state.resizing);
102
102
  const selected = useUi(api?.store ?? EMPTY_STORE, (state) => state.selection.includes(rowKey));
103
- const problems = useUi(api?.store ?? EMPTY_STORE, (state) => state.problems.filter((problem) => problem.input && key(problem.input) === rowKey).map((problem) => `${problem.line}\n${problem.message}`).join("\n\n"));
103
+ const problemText = useProblemText();
104
+ const problems = useUi(api?.store ?? EMPTY_STORE, (state) => state.problems.filter((problem) => problem.input && key(problem.input) === rowKey).map((problem) => `${problem.line}\n${problemText(problem)}`).join("\n\n"));
104
105
  if (!api) return children;
105
106
  const found = problems ? problems.split("\n\n") : [];
106
107
  const definition = api.definition(path);
@@ -0,0 +1,9 @@
1
+ /** The page a problem's type URI resolves to, or undefined for `about:blank` and no type, which
2
+ * have none. */
3
+ export declare function problemPage(type: string | null | undefined): string | undefined;
4
+ /** Links a problem to the page that explains it, in a new tab, when its type has one. */
5
+ export declare function ProblemPageLink({ type, label, className, }: {
6
+ type: string | null | undefined;
7
+ label: string;
8
+ className?: string | undefined;
9
+ }): import("react").JSX.Element | null;
@@ -0,0 +1,21 @@
1
+ import { cx } from "../cx.js";
2
+ import { ExternalLink } from "../components/ExternalLink.js";
3
+ import { jsx } from "react/jsx-runtime";
4
+ //#region src/graph/ProblemPageLink.tsx
5
+ /** The page a problem's type URI resolves to, or undefined for `about:blank` and no type, which
6
+ * have none. */
7
+ function problemPage(type) {
8
+ return type && type !== "about:blank" ? type : void 0;
9
+ }
10
+ /** Links a problem to the page that explains it, in a new tab, when its type has one. */
11
+ function ProblemPageLink({ type, label, className }) {
12
+ const href = problemPage(type);
13
+ if (!href) return null;
14
+ return /* @__PURE__ */ jsx(ExternalLink, {
15
+ href,
16
+ className: cx("rounded-sm text-xs underline underline-offset-2 hover:decoration-2 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--theme-focus)", className),
17
+ children: label
18
+ });
19
+ }
20
+ //#endregion
21
+ export { ProblemPageLink, problemPage };
@@ -1,7 +1,9 @@
1
1
  import { WarningIcon } from "../icons.js";
2
2
  import { Tooltip } from "../components/Tooltip.js";
3
+ import { useProblemText } from "../components/Provider.js";
3
4
  import { keyedByContent } from "../components/keys.js";
4
5
  import { Popover } from "../components/Popover.js";
6
+ import { ProblemPageLink } from "./ProblemPageLink.js";
5
7
  import { useGraphEditorStrings } from "./editorStrings.js";
6
8
  import { toolbarPanel } from "./toolbarPanel.js";
7
9
  import { useState } from "react";
@@ -10,6 +12,7 @@ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
10
12
  /** A toolbar's count of the problems it lists, which opens the list. */
11
13
  function ProblemsButton({ problems }) {
12
14
  const t = useGraphEditorStrings();
15
+ const problemText = useProblemText();
13
16
  const [open, setOpen] = useState(false);
14
17
  if (problems.length === 0) return null;
15
18
  const label = t.problemCount(problems.length);
@@ -37,20 +40,27 @@ function ProblemsButton({ problems }) {
37
40
  children: t.problemLine(problem.line)
38
41
  }), /* @__PURE__ */ jsx("span", {
39
42
  className: "text-(--theme-error-text)",
40
- children: problem.message
43
+ children: problemText(problem)
41
44
  })] });
42
- return /* @__PURE__ */ jsx("li", { children: pick ? /* @__PURE__ */ jsx("button", {
43
- type: "button",
44
- className: "w-full cursor-pointer rounded px-1.5 py-1 text-left theme-hover",
45
- onClick: () => {
46
- setOpen(false);
47
- pick();
48
- },
49
- children: text
50
- }) : /* @__PURE__ */ jsx("div", {
51
- className: "px-1.5 py-1",
52
- children: text
53
- }) }, key);
45
+ return /* @__PURE__ */ jsxs("li", {
46
+ className: "flex items-baseline gap-2",
47
+ children: [pick ? /* @__PURE__ */ jsx("button", {
48
+ type: "button",
49
+ className: "min-w-0 flex-1 cursor-pointer rounded px-1.5 py-1 text-left theme-hover",
50
+ onClick: () => {
51
+ setOpen(false);
52
+ pick();
53
+ },
54
+ children: text
55
+ }) : /* @__PURE__ */ jsx("div", {
56
+ className: "min-w-0 flex-1 px-1.5 py-1",
57
+ children: text
58
+ }), /* @__PURE__ */ jsx(ProblemPageLink, {
59
+ type: problem.type,
60
+ label: t.problemAbout,
61
+ className: "shrink-0"
62
+ })]
63
+ }, key);
54
64
  })
55
65
  })
56
66
  });
@@ -2,10 +2,11 @@ import { cx } from "../cx.js";
2
2
  import { WarningIcon } from "../icons.js";
3
3
  import { toneIcon } from "../components/tone.js";
4
4
  import { Tooltip } from "../components/Tooltip.js";
5
- import { useStrings, useWorkflowEngine } from "../components/Provider.js";
5
+ import { useProblemText, useStrings, useWorkflowEngine } from "../components/Provider.js";
6
6
  import { keyedByContent, withPositionKeys } from "../components/keys.js";
7
7
  import { Callout } from "../components/Callout.js";
8
8
  import { jobLabel } from "./util.js";
9
+ import { ProblemPageLink } from "./ProblemPageLink.js";
9
10
  import { jsx, jsxs } from "react/jsx-runtime";
10
11
  //#region src/graph/RunWarningsList.tsx
11
12
  /** A warning's message, with the text it puts in backticks, such as a keyword, set as code. */
@@ -21,11 +22,12 @@ function WarningText({ message }) {
21
22
  * it lists them. */
22
23
  function WarningMark({ warnings, className }) {
23
24
  const { dag } = useStrings();
25
+ const problemText = useProblemText();
24
26
  if (warnings.length === 0) return null;
25
27
  return /* @__PURE__ */ jsx(Tooltip, {
26
28
  content: /* @__PURE__ */ jsx("ul", {
27
29
  className: "m-0 flex list-none flex-col gap-1 p-0",
28
- children: keyedByContent(warnings, (w) => w.message).map(({ key, item }) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(WarningText, { message: item.message }) }, key))
30
+ children: keyedByContent(warnings, (w) => w.message).map(({ key, item }) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(WarningText, { message: problemText(item) }) }, key))
29
31
  }),
30
32
  children: /* @__PURE__ */ jsx("span", {
31
33
  role: "img",
@@ -61,6 +63,7 @@ function placeOf({ warning, targets: [target] }, rootJobs, stepLabel, stepNumber
61
63
  function RunWarningsList({ warnings, rootJobs, onShow }) {
62
64
  const { dag } = useStrings();
63
65
  const engine = useWorkflowEngine();
66
+ const problemText = useProblemText();
64
67
  if (warnings.length === 0) return null;
65
68
  return /* @__PURE__ */ jsx(Callout, {
66
69
  tone: "warning",
@@ -75,15 +78,21 @@ function RunWarningsList({ warnings, rootJobs, onShow }) {
75
78
  className: "flex flex-col items-start gap-0.5",
76
79
  children: [/* @__PURE__ */ jsx("span", {
77
80
  className: "min-w-0 break-words",
78
- children: /* @__PURE__ */ jsx(WarningText, { message: item.warning.message })
79
- }), target && onShow ? /* @__PURE__ */ jsx("button", {
80
- type: "button",
81
- onClick: () => onShow(target),
82
- className: "cursor-pointer rounded-sm text-xs font-medium underline underline-offset-2 hover:decoration-2 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--theme-focus)",
83
- children: where
84
- }) : /* @__PURE__ */ jsx("span", {
85
- className: "text-xs",
86
- children: where
81
+ children: /* @__PURE__ */ jsx(WarningText, { message: problemText(item.warning) })
82
+ }), /* @__PURE__ */ jsxs("span", {
83
+ className: "flex flex-wrap items-baseline gap-x-3 gap-y-0.5",
84
+ children: [target && onShow ? /* @__PURE__ */ jsx("button", {
85
+ type: "button",
86
+ onClick: () => onShow(target),
87
+ className: "cursor-pointer rounded-sm text-xs font-medium underline underline-offset-2 hover:decoration-2 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--theme-focus)",
88
+ children: where
89
+ }) : /* @__PURE__ */ jsx("span", {
90
+ className: "text-xs",
91
+ children: where
92
+ }), /* @__PURE__ */ jsx(ProblemPageLink, {
93
+ type: item.warning.type,
94
+ label: dag.warningAbout
95
+ })]
87
96
  })]
88
97
  }, key);
89
98
  })
@@ -1,10 +1,20 @@
1
+ import type { ProblemParams } from '../components/Provider.js';
1
2
  import type { GraphEdit, GraphEditResult } from '../editing.js';
2
3
  import type { Box } from './editorPrimitives.js';
3
4
  import type { ListedProblem } from './ProblemsButton.js';
4
5
  import type { SettingsView } from './settingsViews.js';
5
6
  export type { Box };
6
7
  export interface EditorProblem {
8
+ /** Its text, shown when it has no `code` or the host has no message for it. */
7
9
  message: string;
10
+ /** Its stable code, which the host's `useProblemMessage` shows in the reader's language with
11
+ * `params`. */
12
+ code?: string | null | undefined;
13
+ /** The values the code's message shows, by name. */
14
+ params?: ProblemParams | null | undefined;
15
+ /** The URI of the page that explains it, which the problems list links to, and which the host's
16
+ * `useProblemMessage` gets with its `code`. `about:blank` has none. */
17
+ type?: string | null | undefined;
8
18
  line: number;
9
19
  job?: string;
10
20
  step?: number;
@@ -1,6 +1,7 @@
1
1
  import { cx } from "../cx.js";
2
2
  import { AddIcon, DragHandleIcon, MoreIcon, WarningIcon } from "../icons.js";
3
3
  import { Tooltip } from "../components/Tooltip.js";
4
+ import { useProblemText } from "../components/Provider.js";
4
5
  import { MarqueeBox, place } from "./editorPrimitives.js";
5
6
  import { EDITOR_HANDLE_CLASS, NO_SELECTION, labelsOf, problemsIn, sameEdge, sameStep, selectionBounds, useGraphEditor, useSelectedEdges, useUi } from "./graphEditorState.js";
6
7
  import { useEffect, useMemo, useRef } from "react";
@@ -145,12 +146,13 @@ var NO_PROBLEMS = [];
145
146
  function ProblemBadge({ api, job, step }) {
146
147
  const t = api.t;
147
148
  const problems = useUi(api, (state) => state.problems, NO_PROBLEMS);
149
+ const problemText = useProblemText();
148
150
  const mine = useMemo(() => step === void 0 ? problems.filter((problem) => problem.job === job) : problemsIn(problems, job, step), [
149
151
  problems,
150
152
  job,
151
153
  step
152
154
  ]);
153
- const messages = mine.map((problem) => problem.message).join("\n");
155
+ const messages = mine.map(problemText).join("\n");
154
156
  const line = mine[0]?.line ?? 0;
155
157
  if (!messages) return null;
156
158
  return /* @__PURE__ */ jsx(Tooltip, {
@@ -12,6 +12,7 @@ export declare const GRAPH_EDITOR_STRINGS: {
12
12
  stepCount: (count: number) => string;
13
13
  problemCount: (count: number) => string;
14
14
  problemLine: (line: number) => string;
15
+ problemAbout: string;
15
16
  connectOutHint: string;
16
17
  connectInHint: string;
17
18
  moveBoxHint: string;
@@ -13,6 +13,7 @@ var GRAPH_EDITOR_STRINGS = {
13
13
  stepCount: (count) => count === 1 ? "1 step" : `${count} steps`,
14
14
  problemCount: (count) => count === 1 ? "1 problem" : `${count} problems`,
15
15
  problemLine: (line) => `Line ${line}`,
16
+ problemAbout: "About this problem",
16
17
  connectOutHint: "Drag onto a job to make it depend on this node. Drop on a circle to cover every job in that node.",
17
18
  connectInHint: "Drag onto a job to make this node depend on it. Drop on a circle to cover every job in that node.",
18
19
  moveBoxHint: "Drag to move these jobs together",
@@ -1,3 +1,4 @@
1
+ import type { ProblemParams } from '../components/Provider.js';
1
2
  import type { WorkflowJob } from './types.js';
2
3
  /** Something probably wrong with a run's workflow, found when the run was created, about one of its jobs or steps. */
3
4
  export interface RunWarning {
@@ -8,8 +9,18 @@ export interface RunWarning {
8
9
  job: string;
9
10
  /** The step's index among the job's steps as the run lists them; absent for the job's own. */
10
11
  step?: number | null | undefined;
11
- /** What is wrong and what to write instead. Text in backticks shows as code. */
12
+ /** What is wrong and what to write instead. Text in backticks shows as code. It shows when the
13
+ * warning has no `code`, or the host has no message for it. */
12
14
  message: string;
15
+ /** The warning's stable code, such as `undefined_input`, which the host's `useProblemMessage`
16
+ * shows in the reader's language with `params`. */
17
+ code?: string | null | undefined;
18
+ /** The values the code's message shows, by name. */
19
+ params?: ProblemParams | null | undefined;
20
+ /** The URI of the page that explains it, such as `/problems/workflow/undefined_input`, which the
21
+ * warning links to, and which the host's `useProblemMessage` gets with its `code`. `about:blank`
22
+ * has none. */
23
+ type?: string | null | undefined;
13
24
  }
14
25
  /** A subworkflow step on the way to a warning: its level's prefix, its job and its index. */
15
26
  interface Via {
package/dist/index.d.ts CHANGED
@@ -10,7 +10,7 @@ export { Checkbox, CheckboxGroup, type CheckboxProps } from './components/Checkb
10
10
  export { ColorInput, type ColorInputProps } from './components/ColorInput.js';
11
11
  export { Autocomplete, type AutocompleteProps, Combobox, type ComboboxGroup, type ComboboxItem, type ComboboxItems, type ComboboxProps, } from './components/Combobox.js';
12
12
  export { ConfirmModal, type ConfirmModalProps, type ConfirmRequest, useConfirm, } from './components/ConfirmModal.js';
13
- export { ContextMenuProvider, type MenuOpener, type OpenMenu, type OpenMenuOptions, useContextMenu, useMenuOpenedBy, useOpenMenu, } from './components/ContextMenu.js';
13
+ export { ContextMenuProvider, type MenuCloseTrigger, type MenuOpener, type OpenMenu, type OpenMenuOptions, useCloseMenu, useContextMenu, useMenuOpenedBy, useOpenMenu, } from './components/ContextMenu.js';
14
14
  export { CopyButton, type CopyButtonProps, CopyCodeBlock, type CopyCodeBlockProps, } from './components/CopyButton.js';
15
15
  export { CreateModal, CreateModalSelect, CreateModalSwitch, } from './components/CreateModal.js';
16
16
  export { categoryClasses, categoryOf } from './components/category.js';
@@ -47,7 +47,7 @@ export { PageHeader, PageHeaderBar, type PageHeaderBarProps, type PageHeaderProp
47
47
  export { PageHeaderAction, type PageHeaderActionProps, PageHeaderAddButton, type PageHeaderAddButtonProps, PageHeaderMenu, } from './components/PageHeaderAction.js';
48
48
  export { PAGE_SIZES, Pagination, type PaginationProps } from './components/Pagination.js';
49
49
  export { Popover, PopoverClose, type PopoverProps, useClosePopover, } from './components/Popover.js';
50
- export { type AvatarColoring, type PersistedStateHook, type RunFileResult, type UIData, type UILinkComponent, type UINavigation, UIProvider, type UIProviderProps, type UISlots, type UIStringOverrides, type UIStrings, useAvatarColoring, useLocale, useNavigation, useOptionalWorkflowEngine, usePersistedState, useProvisionCorsRules, useRunFile, useSlots, useStrings, useWorkflowActions, useWorkflowEditing, useWorkflowEngine, useWorkflowEngineLoader, type WorkflowEngineSource, type WorkflowJsonRef, } from './components/Provider.js';
50
+ export { type AvatarColoring, type CodedProblem, type PersistedStateHook, type ProblemMessage, type ProblemParams, type RunFileResult, type UIData, type UILinkComponent, type UINavigation, UIProvider, type UIProviderProps, type UISlots, type UIStringOverrides, type UIStrings, useAvatarColoring, useLocale, useNavigation, useOptionalWorkflowEngine, usePersistedState, useProblemText, useProvisionCorsRules, useRunFile, useSlots, useStrings, useWorkflowActions, useWorkflowEditing, useWorkflowEngine, useWorkflowEngineLoader, type WorkflowEngineSource, type WorkflowJsonRef, } from './components/Provider.js';
51
51
  export { Radio, RadioGroup, type RadioProps } from './components/Radio.js';
52
52
  export { RefreshButton, type RefreshButtonProps } from './components/RefreshButton.js';
53
53
  export { RequiredMark } from './components/RequiredMark.js';
package/dist/index.js CHANGED
@@ -2,12 +2,12 @@ import { cx } from "./cx.js";
2
2
  import { buttonClasses } from "./components/buttonClasses.js";
3
3
  import { EmptyState } from "./components/EmptyState.js";
4
4
  import { MenuCheckboxItem, MenuGroupLabel, MenuItem, MenuLinkItem, MenuPopup, MenuRadioItem, MenuSeparator, MenuSubmenuTrigger } from "./components/Menu.js";
5
- import { ContextMenuProvider, useContextMenu, useMenuOpenedBy, useOpenMenu } from "./components/ContextMenu.js";
5
+ import { ContextMenuProvider, useCloseMenu, useContextMenu, useMenuOpenedBy, useOpenMenu } from "./components/ContextMenu.js";
6
6
  import { Loader } from "./components/Loader.js";
7
7
  import { toast } from "./components/Toast.js";
8
8
  import { Kbd, ariaKeyShortcuts, formatShortcut, isApplePlatform, shortcutText, useShortcutFormat } from "./components/Kbd.js";
9
9
  import { Tooltip, TooltipProvider } from "./components/Tooltip.js";
10
- import { UIProvider, useAvatarColoring, useLocale, useNavigation, useOptionalWorkflowEngine, usePersistedState, useProvisionCorsRules, useRunFile, useSlots, useStrings, useWorkflowActions, useWorkflowEditing, useWorkflowEngine, useWorkflowEngineLoader } from "./components/Provider.js";
10
+ import { UIProvider, useAvatarColoring, useLocale, useNavigation, useOptionalWorkflowEngine, usePersistedState, useProblemText, useProvisionCorsRules, useRunFile, useSlots, useStrings, useWorkflowActions, useWorkflowEditing, useWorkflowEngine, useWorkflowEngineLoader } from "./components/Provider.js";
11
11
  import { AppLink, isPlainClick } from "./components/AppLink.js";
12
12
  import { useCopy } from "./components/useCopy.js";
13
13
  import { MenuEntries, MenuFilter, isMenuDivider, isMenuGroup, isMenuSubmenu, menuDivider } from "./components/MenuEntries.js";
@@ -83,4 +83,4 @@ import { ToggleGroup } from "./components/ToggleGroup.js";
83
83
  import { useClosingValue } from "./components/useClosingValue.js";
84
84
  import { useCssIsDark } from "./components/useCssIsDark.js";
85
85
  import { useApplyTheme, useColorMode } from "./components/useTheme.js";
86
- export { ActionMenu, AppLink, Autocomplete, Avatar, AvatarGroup, Breadcrumbs, Button, CODE_STYLES, Calendar, Callout, Card, CardHeader, ChartLegendList, ChartTooltipContent, Checkbox, CheckboxGroup, ColorInput, Combobox, ConfirmModal, ContextMenuProvider, CopyButton, CopyCodeBlock, CountBadge, CreateModal, CreateModalSelect, CreateModalSwitch, DEFAULT_CONTRAST, DEFAULT_PRESET, DEFAULT_THEME, DatePicker, DescriptionList, DescriptionListGroup, DescriptionListItem, Disclosure, DisclosurePanel, Drawer, Elapsed, EmptyState, ErrorPage, ErrorText, ExternalLink, Field, FieldOption, FieldValue, FileButton, HoverCard, IconButton, InfoTip, Input, JND, Kbd, LetterBadge, ListboxGroup, ListboxOption, ListboxPanel, Loader, LoadingRegion, Markdown, MenuCheckboxItem, MenuEntries, MenuFilter, MenuGroupLabel, MenuItem, MenuLinkItem, MenuPopup, MenuRadioItem, MenuSeparator, MenuSubmenuTrigger, Meter, MethodButton, Modal, ModalDescription, ModalTitle, NumberInput, OneTimeCodeInput, Overview, PAGE_SIZES, PageHeader, PageHeaderAction, PageHeaderAddButton, PageHeaderBar, PageHeaderMenu, PageHeaderProvider, Pagination, Popover, PopoverClose, ProgressBar, Radio, RadioGroup, RefreshButton, RelativeTime, RequiredMark, RevealToggle, RunStatusIcon, SIDEBAR_TOKENS, SearchInput, Section, SegmentedControl, Select, SelectionCopy, SeriesSwatch, SettingModeOption, SettingRow, SettingsCard, SettingsHeading, Skeleton, Slider, StatusBadge, StatusDot, StickyBar, Switch, THEME_PRESETS, THEME_TOKENS, TabPanel, Table, Tabs, Tag, TagList, Textarea, ThemeEditor, ThemePreview, TitleInput, ToggleGroup, Tooltip, TooltipProvider, UIProvider, apcaContrast, applyTheme, ariaKeyShortcuts, avatarInitials, buttonClasses, categoryClasses, categoryOf, collapsePanelClassName, composite, contrastRatio, cx, deltaE, deriveTheme, errorPageKind, fieldBox, fitSeed, formatBytes, formatCount, formatDateTime, formatDuration, formatInfoTipContent, formatShortcut, formatTimeLeft, generateTheme, isApplePlatform, isDarkColor, isMenuDivider, isMenuGroup, isMenuSubmenu, isPlainClick, isTextEntryContext, levelTone, menuDivider, modalPanelClassName, modeOf, normalizeTags, parseColor, parseTheme, prefersWideGamut, resolveMode, runStatusTone, schemeFor, serializeTheme, seriesColor, seriesColors, seriesOpacity, seriesSlotColor, shortcutText, statusTextClass, tagClasses, themeStylesheet, toHex, toP3, toast, useApplyTheme, useAvatarColoring, useClock, useClosePopover, useClosingValue, useColorMode, useConfirm, useContextMenu, useCopy, useCssIsDark, useElapsed, useFieldControl, useFieldLabelledControl, useListboxNavigation, useLocale, useMenuOpenedBy, useNavigation, useOpenMenu, useOptionalWorkflowEngine, usePersistedState, useProvisionCorsRules, useRelativeTime, useRunFile, useSeriesHighlight, useShortcutFormat, useShortcutKey, useSlots, useStrings, useWorkflowActions, useWorkflowEditing, useWorkflowEngine, useWorkflowEngineLoader };
86
+ export { ActionMenu, AppLink, Autocomplete, Avatar, AvatarGroup, Breadcrumbs, Button, CODE_STYLES, Calendar, Callout, Card, CardHeader, ChartLegendList, ChartTooltipContent, Checkbox, CheckboxGroup, ColorInput, Combobox, ConfirmModal, ContextMenuProvider, CopyButton, CopyCodeBlock, CountBadge, CreateModal, CreateModalSelect, CreateModalSwitch, DEFAULT_CONTRAST, DEFAULT_PRESET, DEFAULT_THEME, DatePicker, DescriptionList, DescriptionListGroup, DescriptionListItem, Disclosure, DisclosurePanel, Drawer, Elapsed, EmptyState, ErrorPage, ErrorText, ExternalLink, Field, FieldOption, FieldValue, FileButton, HoverCard, IconButton, InfoTip, Input, JND, Kbd, LetterBadge, ListboxGroup, ListboxOption, ListboxPanel, Loader, LoadingRegion, Markdown, MenuCheckboxItem, MenuEntries, MenuFilter, MenuGroupLabel, MenuItem, MenuLinkItem, MenuPopup, MenuRadioItem, MenuSeparator, MenuSubmenuTrigger, Meter, MethodButton, Modal, ModalDescription, ModalTitle, NumberInput, OneTimeCodeInput, Overview, PAGE_SIZES, PageHeader, PageHeaderAction, PageHeaderAddButton, PageHeaderBar, PageHeaderMenu, PageHeaderProvider, Pagination, Popover, PopoverClose, ProgressBar, Radio, RadioGroup, RefreshButton, RelativeTime, RequiredMark, RevealToggle, RunStatusIcon, SIDEBAR_TOKENS, SearchInput, Section, SegmentedControl, Select, SelectionCopy, SeriesSwatch, SettingModeOption, SettingRow, SettingsCard, SettingsHeading, Skeleton, Slider, StatusBadge, StatusDot, StickyBar, Switch, THEME_PRESETS, THEME_TOKENS, TabPanel, Table, Tabs, Tag, TagList, Textarea, ThemeEditor, ThemePreview, TitleInput, ToggleGroup, Tooltip, TooltipProvider, UIProvider, apcaContrast, applyTheme, ariaKeyShortcuts, avatarInitials, buttonClasses, categoryClasses, categoryOf, collapsePanelClassName, composite, contrastRatio, cx, deltaE, deriveTheme, errorPageKind, fieldBox, fitSeed, formatBytes, formatCount, formatDateTime, formatDuration, formatInfoTipContent, formatShortcut, formatTimeLeft, generateTheme, isApplePlatform, isDarkColor, isMenuDivider, isMenuGroup, isMenuSubmenu, isPlainClick, isTextEntryContext, levelTone, menuDivider, modalPanelClassName, modeOf, normalizeTags, parseColor, parseTheme, prefersWideGamut, resolveMode, runStatusTone, schemeFor, serializeTheme, seriesColor, seriesColors, seriesOpacity, seriesSlotColor, shortcutText, statusTextClass, tagClasses, themeStylesheet, toHex, toP3, toast, useApplyTheme, useAvatarColoring, useClock, useCloseMenu, useClosePopover, useClosingValue, useColorMode, useConfirm, useContextMenu, useCopy, useCssIsDark, useElapsed, useFieldControl, useFieldLabelledControl, useListboxNavigation, useLocale, useMenuOpenedBy, useNavigation, useOpenMenu, useOptionalWorkflowEngine, usePersistedState, useProblemText, useProvisionCorsRules, useRelativeTime, useRunFile, useSeriesHighlight, useShortcutFormat, useShortcutKey, useSlots, useStrings, useWorkflowActions, useWorkflowEditing, useWorkflowEngine, useWorkflowEngineLoader };