@parallelworks/ui 0.80.0 → 0.82.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 (54) hide show
  1. package/README.md +7 -1
  2. package/dist/ai/adapter/types.d.ts +1 -0
  3. package/dist/ai/ai.css +3 -92
  4. package/dist/ai/components/agent/AgentMessageParts.js +1 -0
  5. package/dist/ai/core/ChatProvider.js +10 -5
  6. package/dist/ai/strings.d.ts +3 -0
  7. package/dist/ai/strings.js +2 -0
  8. package/dist/ai/types.d.ts +5 -0
  9. package/dist/components/Avatar.d.ts +5 -3
  10. package/dist/components/Avatar.js +6 -2
  11. package/dist/components/Card.d.ts +16 -1
  12. package/dist/components/Card.js +13 -2
  13. package/dist/components/CodeBlock.d.ts +40 -0
  14. package/dist/components/CodeBlock.js +159 -0
  15. package/dist/components/CopyButton.d.ts +11 -4
  16. package/dist/components/CopyButton.js +86 -11
  17. package/dist/components/CreateModal.d.ts +3 -1
  18. package/dist/components/CreateModal.js +31 -11
  19. package/dist/components/DescriptionList.js +1 -1
  20. package/dist/components/Drawer.js +1 -1
  21. package/dist/components/Input.d.ts +5 -0
  22. package/dist/components/Input.js +4 -3
  23. package/dist/components/Listbox.d.ts +12 -3
  24. package/dist/components/Listbox.js +38 -15
  25. package/dist/components/MarkdownImpl.js +89 -2
  26. package/dist/components/MenuEntries.d.ts +3 -0
  27. package/dist/components/MenuEntries.js +19 -6
  28. package/dist/components/Modal.d.ts +1 -1
  29. package/dist/components/Modal.js +6 -5
  30. package/dist/components/PageHeader.d.ts +7 -1
  31. package/dist/components/PageHeader.js +11 -5
  32. package/dist/components/Provider.d.ts +3 -0
  33. package/dist/components/Provider.js +1 -0
  34. package/dist/components/Select.js +1 -1
  35. package/dist/components/SettingsCard.d.ts +7 -2
  36. package/dist/components/SettingsCard.js +42 -7
  37. package/dist/components/ToggleGroup.d.ts +3 -1
  38. package/dist/components/ToggleGroup.js +2 -2
  39. package/dist/components/Tooltip.js +35 -2
  40. package/dist/components/codeHighlight.d.ts +9 -0
  41. package/dist/components/codeHighlight.js +29 -0
  42. package/dist/components/pageHeaderStore.d.ts +4 -0
  43. package/dist/components/pageHeaderStore.js +5 -2
  44. package/dist/file-explorer/FileExplorer.js +1 -1
  45. package/dist/index.d.ts +2 -1
  46. package/dist/index.js +3 -2
  47. package/dist/list/ListFilterBar.js +6 -5
  48. package/dist/list/filterModel.d.ts +4 -0
  49. package/dist/list/filterModel.js +7 -1
  50. package/dist/styles/theme.css +1 -0
  51. package/dist/styles.css +1 -1
  52. package/dist/theme/derive.d.ts +1 -1
  53. package/dist/theme/derive.js +3 -1
  54. package/package.json +1 -1
@@ -10,7 +10,8 @@ import { AlertDialog } from "@base-ui/react/alert-dialog";
10
10
  import { Dialog } from "@base-ui/react/dialog";
11
11
  //#region src/components/Modal.tsx
12
12
  /** The panel a modal draws by default; pass `panel={false}` to paint your own. */
13
- var modalPanelClassName = "rounded-xl border border-(--theme-border) bg-(--theme-app-bg) text-(--theme-app) shadow-2xl";
13
+ var modalPanelClassName = "rounded-xl border border-(--theme-border) bg-(--theme-panel-bg) text-(--theme-app) shadow-2xl";
14
+ var phoneFooterClassName = "max-sm:flex-wrap max-sm:[&>:is(button,a)]:h-10 max-sm:[&>:is(button,a)]:flex-1 max-sm:[&>:not(button,a)]:basis-full";
14
15
  /** Names the modal for assistive technology; renders an `<h2>`. */
15
16
  var ModalTitle = Dialog.Title;
16
17
  /** Describes the modal for assistive technology; renders a `<p>`. */
@@ -32,7 +33,7 @@ function firstControlIn(panel) {
32
33
  * and focus returns to where it was on close. Give it a `title`, a `description`
33
34
  * and a `footer` for the standard layout, as a Drawer has, or lay out the whole
34
35
  * panel with the children. */
35
- function Modal({ open, onClose, title, description, footer, size, alert = false, dismissible = true, align = "top", panel = true, backdropClassName = "bg-black/40", closeButton = false, onSubmit, className, children, initialFocus, ...popupProps }) {
36
+ function Modal({ open, onClose, title, description, footer, size, alert = false, dismissible = true, align = "top", panel = true, backdropClassName = "bg-(--theme-backdrop)", closeButton = false, onSubmit, className, children, initialFocus, ...popupProps }) {
36
37
  const portal = usePopupContainer();
37
38
  const { common } = useStrings();
38
39
  const panelElement = useRef(null);
@@ -67,14 +68,14 @@ function Modal({ open, onClose, title, description, footer, size, alert = false,
67
68
  children
68
69
  }),
69
70
  footer !== void 0 && /* @__PURE__ */ jsx("div", {
70
- className: "flex shrink-0 items-center justify-end gap-2 border-t border-(--theme-border) px-4 py-3",
71
+ className: cx("flex shrink-0 items-center justify-end gap-2 border-t border-(--theme-border) px-4 py-3", phoneFooterClassName),
71
72
  children: footer
72
73
  })
73
74
  ] });
74
75
  const content = /* @__PURE__ */ jsxs(Dialog.Portal, {
75
76
  ...portal,
76
77
  children: [/* @__PURE__ */ jsx(Dialog.Backdrop, { className: cx("fixed inset-0 z-(--layer-modal)", backdropMotion, backdropClassName) }), /* @__PURE__ */ jsx(Dialog.Viewport, {
77
- 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)]"),
78
+ className: cx("fixed inset-0 z-(--layer-modal) flex justify-center px-4 pt-20 pb-8 max-sm:px-2 max-sm:pb-[max(8px,env(safe-area-inset-bottom))]", align === "center" ? "items-center" : "items-start sm:pt-[max(14vh,5rem)]"),
78
79
  children: /* @__PURE__ */ jsx(Dialog.Popup, {
79
80
  ...popupProps,
80
81
  ref: (element) => {
@@ -84,7 +85,7 @@ function Modal({ open, onClose, title, description, footer, size, alert = false,
84
85
  else if (forward) forward.current = element;
85
86
  },
86
87
  initialFocus: initialFocus ?? (closeButton ? () => firstControlIn(panelElement.current) : void 0),
87
- 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", popupMotion, className),
88
+ className: cx(panel && "rounded-xl border border-(--theme-border) bg-(--theme-panel-bg) text-(--theme-app) shadow-2xl", size && [sizeClasses[size], "max-w-full"], panel && (size || laidOut) && "max-sm:w-full", laidOut && "flex max-h-full flex-col", "outline-none", popupMotion, className),
88
89
  children: !laidOut ? children : onSubmit ? /* @__PURE__ */ jsx("form", {
89
90
  className: "flex min-h-0 flex-1 flex-col",
90
91
  onSubmit: (event) => {
@@ -13,6 +13,10 @@ export interface PageHeaderProps {
13
13
  * `h1`. A crumb with an empty label, such as a name still loading, shows a
14
14
  * placeholder. */
15
15
  breadcrumbs?: readonly Breadcrumb[] | undefined;
16
+ /** False keeps the last crumb out of the page's outline, for a page whose `h1` is in its
17
+ * body, such as a title field or a section's heading: the crumb still says it is the
18
+ * current page, and the page has one `h1`. */
19
+ heading?: boolean | undefined;
16
20
  /** Beside the title: actions on the page's subject, such as edit, rename or
17
21
  * favorite, or its `PageHeaderMenu`. */
18
22
  titleActions?: ReactNode;
@@ -29,7 +33,9 @@ export interface PageHeaderProps {
29
33
  * toolbar. Under a `PageHeaderProvider` it renders nothing in place: the
30
34
  * shell's `PageHeaderBar` shows it, while the actions stay in the page's React
31
35
  * tree, with its context and state. Without a provider it renders the bar
32
- * itself, for a page with no shell.
36
+ * itself, for a page with no shell, with no fill of its own, so it shows the
37
+ * surface it sits on. A host that pins it gives its pinned wrapper the page's
38
+ * surface, so content scrolling under it is covered.
33
39
  *
34
40
  * Any component may render one, such as a form adding its Save button: the bar
35
41
  * shows the actions of all of them, outermost first, and the trail of the last
@@ -42,7 +42,9 @@ function createRegionNodes() {
42
42
  * toolbar. Under a `PageHeaderProvider` it renders nothing in place: the
43
43
  * shell's `PageHeaderBar` shows it, while the actions stay in the page's React
44
44
  * tree, with its context and state. Without a provider it renders the bar
45
- * itself, for a page with no shell.
45
+ * itself, for a page with no shell, with no fill of its own, so it shows the
46
+ * surface it sits on. A host that pins it gives its pinned wrapper the page's
47
+ * surface, so content scrolling under it is covered.
46
48
  *
47
49
  * Any component may render one, such as a form adding its Save button: the bar
48
50
  * shows the actions of all of them, outermost first, and the trail of the last
@@ -51,7 +53,9 @@ function createRegionNodes() {
51
53
  function PageHeader(props) {
52
54
  const store = use(StoreContext);
53
55
  if (!store) return props.hidden ? null : /* @__PURE__ */ jsx(HeaderLayout, {
56
+ inPlace: true,
54
57
  breadcrumbs: props.breadcrumbs ?? [],
58
+ heading: props.heading ?? true,
55
59
  titleActions: props.titleActions,
56
60
  actions: props.actions,
57
61
  toolbar: props.toolbar
@@ -61,7 +65,7 @@ function PageHeader(props) {
61
65
  ...props
62
66
  });
63
67
  }
64
- function DeclaredHeader({ store, breadcrumbs, titleActions, actions, toolbar, hidden = false }) {
68
+ function DeclaredHeader({ store, breadcrumbs, heading = true, titleActions, actions, toolbar, hidden = false }) {
65
69
  const [order] = useState(() => ++renderOrder);
66
70
  const [nodes] = useState(createRegionNodes);
67
71
  const client = useSyncExternalStore(subscribeNever, () => true, () => false);
@@ -73,6 +77,7 @@ function DeclaredHeader({ store, breadcrumbs, titleActions, actions, toolbar, hi
73
77
  useLayoutEffect(() => {
74
78
  store.set(order, {
75
79
  breadcrumbs,
80
+ heading,
76
81
  hidden,
77
82
  nodes,
78
83
  fills
@@ -105,6 +110,7 @@ function PageHeaderBar({ compact = false, persistent = false, className }) {
105
110
  if (header.hidden || empty && !persistent) return null;
106
111
  return /* @__PURE__ */ jsx(HeaderLayout, {
107
112
  breadcrumbs: header.breadcrumbs,
113
+ heading: header.heading,
108
114
  titleActions: header.titleActions.length > 0 && /* @__PURE__ */ jsx(Mounts, { nodes: header.titleActions }),
109
115
  actions: header.actions.length > 0 && /* @__PURE__ */ jsx(Mounts, { nodes: header.actions }),
110
116
  toolbar: header.toolbar.length > 0 && /* @__PURE__ */ jsx(Mounts, { nodes: header.toolbar }),
@@ -137,7 +143,7 @@ function Mount({ node }) {
137
143
  className: "contents"
138
144
  });
139
145
  }
140
- function HeaderLayout({ breadcrumbs, titleActions, actions, toolbar, fit: sharedFit, compact = false, className }) {
146
+ function HeaderLayout({ breadcrumbs, heading, titleActions, actions, toolbar, fit: sharedFit, compact = false, inPlace = false, className }) {
141
147
  const { breadcrumbPin, navToggle } = useSlots();
142
148
  const { list: t } = useStrings();
143
149
  const [ownFit] = useState(() => new HeaderActionsFit());
@@ -150,7 +156,7 @@ function HeaderLayout({ breadcrumbs, titleActions, actions, toolbar, fit: shared
150
156
  const moved = fit.menu();
151
157
  const hasTrail = breadcrumbs.length > 0;
152
158
  return /* @__PURE__ */ jsxs("div", {
153
- className: cx("@container w-full shrink-0 bg-(--theme-app-bg)", className),
159
+ className: cx("@container w-full shrink-0", !inPlace && "bg-(--theme-app-bg)", className),
154
160
  children: [/* @__PURE__ */ jsxs("div", {
155
161
  ref: setRow,
156
162
  className: cx("flex items-center justify-between gap-4 border-b border-(--theme-border) px-4", compact ? "h-8" : "h-12"),
@@ -161,7 +167,7 @@ function HeaderLayout({ breadcrumbs, titleActions, actions, toolbar, fit: shared
161
167
  navToggle?.(),
162
168
  hasTrail && /* @__PURE__ */ jsx(Breadcrumbs, {
163
169
  crumbs: breadcrumbs,
164
- heading: true
170
+ heading
165
171
  }),
166
172
  present(titleActions) && /* @__PURE__ */ jsx("div", {
167
173
  className: "flex shrink-0 items-center gap-0.5",
@@ -102,6 +102,9 @@ export interface UIStrings {
102
102
  opensInNewTab: string;
103
103
  /** Names a code editor that has no label of its own. */
104
104
  codeEditor: string;
105
+ /** Names a block of code that has no title of its own, by its language,
106
+ * such as "yaml code"; `language` is empty when it has none. */
107
+ codeOf: (language: string) => string;
105
108
  /** Shown when someone types in a read-only code editor. */
106
109
  readOnlyText: string;
107
110
  /** Names the handle that resizes a panel. */
@@ -148,6 +148,7 @@ var DEFAULTS = {
148
148
  no: "No",
149
149
  opensInNewTab: "(opens in a new tab)",
150
150
  codeEditor: "Code editor",
151
+ codeOf: (language) => language ? `${language} code` : "Code",
151
152
  readOnlyText: "This text is read-only.",
152
153
  resizePanel: "Resize panel",
153
154
  panelWidth: (px) => `${px} pixels wide`,
@@ -59,7 +59,7 @@ function Select$1({ items, placeholder, className, "aria-label": ariaLabel, "ari
59
59
  content: tip,
60
60
  children: /* @__PURE__ */ jsxs(Select.Trigger, {
61
61
  ...triggerProps,
62
- className: cx(fieldBox({ size }), triggerClassName, content && "w-fit max-w-full", explained && explainedDisabledClassName, className),
62
+ className: cx(fieldBox({ size }), triggerClassName, content && "w-fit max-w-full shrink-0", explained && explainedDisabledClassName, className),
63
63
  children: [/* @__PURE__ */ jsx(Select.Value, {
64
64
  placeholder,
65
65
  className: cx("truncate data-placeholder:text-(--theme-placeholder)", content && !rootProps.multiple && "grid"),
@@ -17,7 +17,9 @@ export interface SettingsCardProps {
17
17
  children: ReactNode;
18
18
  }
19
19
  /** A page's settings, grouped: a titled panel of SettingRows, each ruled off from
20
- * the next. Cards stack with room between them. */
20
+ * the next. Cards stack with room between them. An error about one setting, such as its
21
+ * Save failing, is its row's `error`; one about the whole card goes outside it, such as
22
+ * an ErrorText under the card, since every child of the card is ruled off as a row. */
21
23
  export declare function SettingsCard({ title, description, action, actionAlign, headingLevel, overflowVisible, className, children, }: SettingsCardProps): import("react").JSX.Element;
22
24
  /** A heading between groups of rows inside a SettingsCard, a level below the card's title. */
23
25
  export declare function SettingsHeading({ children }: {
@@ -25,7 +27,7 @@ export declare function SettingsHeading({ children }: {
25
27
  }): import("react").JSX.Element;
26
28
  /** One setting in a SettingsCard: its name and help on the left, its control on
27
29
  * the right, or under the name across the row with `fill`. */
28
- export declare function SettingRow({ label, htmlFor, helpText, fill, onClick, children, }: {
30
+ export declare function SettingRow({ label, htmlFor, helpText, fill, onClick, error, children, }: {
29
31
  label: string;
30
32
  /** The control's id, so the name labels it. */
31
33
  htmlFor?: string | undefined;
@@ -35,5 +37,8 @@ export declare function SettingRow({ label, htmlFor, helpText, fill, onClick, ch
35
37
  /** Makes the whole row press its control, such as a switch. The control still
36
38
  * handles its own press; stop it propagating there so it doesn't toggle twice. */
37
39
  onClick?: (() => void) | undefined;
40
+ /** An error about this setting, such as its Save failing: under the control, at its start,
41
+ * announced, and describing the control that `htmlFor` names. */
42
+ error?: ReactNode;
38
43
  children: ReactNode;
39
44
  }): import("react").JSX.Element;
@@ -1,10 +1,13 @@
1
1
  import { cx } from "../cx.js";
2
- import { createContext, useContext } from "react";
2
+ import { ErrorText } from "./Field.js";
3
+ import { createContext, useContext, useId, useLayoutEffect } from "react";
3
4
  import { jsx, jsxs } from "react/jsx-runtime";
4
5
  //#region src/components/SettingsCard.tsx
5
6
  var HeadingLevel = createContext(3);
6
7
  /** A page's settings, grouped: a titled panel of SettingRows, each ruled off from
7
- * the next. Cards stack with room between them. */
8
+ * the next. Cards stack with room between them. An error about one setting, such as its
9
+ * Save failing, is its row's `error`; one about the whole card goes outside it, such as
10
+ * an ErrorText under the card, since every child of the card is ruled off as a row. */
8
11
  function SettingsCard({ title, description, action, actionAlign = "beside", headingLevel = 2, overflowVisible = false, className, children }) {
9
12
  const Heading = `h${headingLevel}`;
10
13
  return /* @__PURE__ */ jsx(HeadingLevel, {
@@ -40,7 +43,34 @@ function SettingsHeading({ children }) {
40
43
  }
41
44
  /** One setting in a SettingsCard: its name and help on the left, its control on
42
45
  * the right, or under the name across the row with `fill`. */
43
- function SettingRow({ label, htmlFor, helpText, fill = false, onClick, children }) {
46
+ function SettingRow({ label, htmlFor, helpText, fill = false, onClick, error, children }) {
47
+ const errorId = useId();
48
+ const hasError = error !== void 0 && error !== null && error !== false && error !== "";
49
+ useLayoutEffect(() => {
50
+ const control = hasError && htmlFor ? document.getElementById(htmlFor) : null;
51
+ if (!control) return;
52
+ const ids = (control.getAttribute("aria-describedby") ?? "").split(/\s+/).filter(Boolean);
53
+ if (!ids.includes(errorId)) control.setAttribute("aria-describedby", [...ids, errorId].join(" "));
54
+ return () => {
55
+ const rest = (control.getAttribute("aria-describedby") ?? "").split(/\s+/).filter((id) => id && id !== errorId);
56
+ if (rest.length > 0) control.setAttribute("aria-describedby", rest.join(" "));
57
+ else control.removeAttribute("aria-describedby");
58
+ };
59
+ }, [
60
+ hasError,
61
+ htmlFor,
62
+ errorId
63
+ ]);
64
+ const control = /* @__PURE__ */ jsx("div", {
65
+ className: cx("min-w-0", !fill && [
66
+ "flex items-center justify-end",
67
+ "max-md:has-[input:not([type=checkbox],[type=radio],[type=hidden],[type=range]),textarea,[role=combobox]]:justify-start",
68
+ "max-md:has-[input:not([type=checkbox],[type=radio],[type=hidden],[type=range]),textarea,[role=combobox]]:*:grow",
69
+ "max-md:[&_:is(input:not([type=checkbox],[type=radio],[type=hidden],[type=range]),textarea,[role=combobox])]:min-w-0",
70
+ "max-md:[&_:is(input:not([type=checkbox],[type=radio],[type=hidden],[type=range]),textarea,[role=combobox])]:flex-1"
71
+ ]),
72
+ children
73
+ });
44
74
  return /* @__PURE__ */ jsxs("div", {
45
75
  role: "none",
46
76
  onClick,
@@ -55,10 +85,15 @@ function SettingRow({ label, htmlFor, helpText, fill = false, onClick, children
55
85
  className: "text-xs leading-snug theme-muted-text",
56
86
  children: helpText
57
87
  })]
58
- }), /* @__PURE__ */ jsx("div", {
59
- className: cx("min-w-0", !fill && "flex items-center justify-end"),
60
- children
61
- })]
88
+ }), hasError ? /* @__PURE__ */ jsxs("div", {
89
+ className: "flex min-w-0 flex-col gap-y-2",
90
+ children: [control, /* @__PURE__ */ jsx(ErrorText, {
91
+ id: errorId,
92
+ size: "md",
93
+ className: "md:w-0 md:min-w-full",
94
+ children: error
95
+ })]
96
+ }) : control]
62
97
  });
63
98
  }
64
99
  //#endregion
@@ -25,6 +25,8 @@ export interface ToggleGroupProps<T extends string> {
25
25
  all?: boolean | {
26
26
  count?: number | undefined;
27
27
  } | undefined;
28
+ /** The All option's words, for one that names what it covers, such as "All types". */
29
+ allLabel?: ReactNode;
28
30
  size?: 'sm' | 'md' | undefined;
29
31
  disabled?: boolean | undefined;
30
32
  /** Names an element that says more about the group, such as a live summary
@@ -42,4 +44,4 @@ export interface ToggleGroupProps<T extends string> {
42
44
  * value, such as a time range, what to group by, or which view of the same
43
45
  * data to show. A filter that may be off, or takes several values, is a
44
46
  * `ToggleGroup`. */
45
- export declare function ToggleGroup<T extends string>({ label, options, value, onValueChange, multiple, all, size, disabled, 'aria-describedby': describedBy, testId, }: ToggleGroupProps<T>): import("react").JSX.Element;
47
+ export declare function ToggleGroup<T extends string>({ label, options, value, onValueChange, multiple, all, allLabel, size, disabled, 'aria-describedby': describedBy, testId, }: ToggleGroupProps<T>): import("react").JSX.Element;
@@ -18,7 +18,7 @@ var ALL = "\0all";
18
18
  * value, such as a time range, what to group by, or which view of the same
19
19
  * data to show. A filter that may be off, or takes several values, is a
20
20
  * `ToggleGroup`. */
21
- function ToggleGroup$1({ label, options, value, onValueChange, multiple = true, all = false, size = "sm", disabled = false, "aria-describedby": describedBy, testId }) {
21
+ function ToggleGroup$1({ label, options, value, onValueChange, multiple = true, all = false, allLabel, size = "sm", disabled = false, "aria-describedby": describedBy, testId }) {
22
22
  const strings = useStrings();
23
23
  const allCount = typeof all === "object" ? all.count : void 0;
24
24
  const pressed = all && value.length === 0 ? [ALL] : value;
@@ -40,7 +40,7 @@ function ToggleGroup$1({ label, options, value, onValueChange, multiple = true,
40
40
  children: [
41
41
  all && /* @__PURE__ */ jsx(Chip, {
42
42
  value: ALL,
43
- label: strings.common.all,
43
+ label: allLabel ?? strings.common.all,
44
44
  count: allCount,
45
45
  size
46
46
  }),
@@ -1,7 +1,7 @@
1
1
  import { positionerClassName, tipClassName } from "./floating.js";
2
2
  import { usePopupContainer } from "./popupContainer.js";
3
3
  import { Kbd } from "./Kbd.js";
4
- import { cloneElement, createContext, use, useId, useState } from "react";
4
+ import { cloneElement, createContext, use, useEffect, useId, useState } from "react";
5
5
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
6
6
  import { Tooltip } from "@base-ui/react/tooltip";
7
7
  //#region src/components/Tooltip.tsx
@@ -52,12 +52,44 @@ function skipUnclipped(open, details) {
52
52
  const anchor = details.trigger;
53
53
  if (open && anchor instanceof HTMLElement && anchor.hasAttribute("data-overflow-only") && anchor.scrollWidth <= anchor.clientWidth) details.cancel();
54
54
  }
55
+ /** True from when the anchor's own popup, such as its menu, closes until the pointer leaves the
56
+ * anchor or focus does. Closing the popup hands focus back to the anchor, and a tip opening
57
+ * then would take the next Escape, meant for the dialog around it, and repeat a label the
58
+ * reader has just seen. */
59
+ function useRestAfterPopup(anchor) {
60
+ const [resting, setResting] = useState(false);
61
+ useEffect(() => {
62
+ if (!anchor || typeof MutationObserver === "undefined") return;
63
+ let expanded = anchor.getAttribute("aria-expanded") === "true";
64
+ const observer = new MutationObserver(() => {
65
+ const now = anchor.getAttribute("aria-expanded") === "true";
66
+ if (expanded && !now) setResting(true);
67
+ else if (now) setResting(false);
68
+ expanded = now;
69
+ });
70
+ observer.observe(anchor, {
71
+ attributes: true,
72
+ attributeFilter: ["aria-expanded"]
73
+ });
74
+ const wake = () => setResting(false);
75
+ anchor.addEventListener("blur", wake);
76
+ anchor.addEventListener("pointerleave", wake);
77
+ return () => {
78
+ observer.disconnect();
79
+ anchor.removeEventListener("blur", wake);
80
+ anchor.removeEventListener("pointerleave", wake);
81
+ };
82
+ }, [anchor]);
83
+ return resting;
84
+ }
55
85
  /** A visual hint for sighted pointer and keyboard users. The anchor still needs
56
86
  * its own accessible name; `describesAnchor` also gives assistive technology the
57
87
  * hint. Use InfoTip for content everyone must reach, such as on a touch screen. */
58
88
  function Tooltip$1({ content, children, side = "top", shortcut, disabled = false, overflowOnly = false, describesAnchor = false, ...anchorProps }) {
59
89
  const handle = use(TooltipHandleContext);
60
90
  const descriptionId = useId();
91
+ const [anchorElement, setAnchorElement] = useState(null);
92
+ const resting = useRestAfterPopup(anchorElement);
61
93
  const payload = {
62
94
  content,
63
95
  shortcut,
@@ -75,7 +107,8 @@ function Tooltip$1({ content, children, side = "top", shortcut, disabled = false
75
107
  ...!handle && anchorProps.delay === void 0 && { delay: OPEN_DELAY },
76
108
  handle: handle ?? void 0,
77
109
  payload,
78
- disabled: disabled || !content,
110
+ ref: setAnchorElement,
111
+ disabled: disabled || !content || resting,
79
112
  "data-overflow-only": overflowOnly || void 0,
80
113
  render: described ? cloneElement(anchor, { "aria-describedby": describedBy }) : children
81
114
  });
@@ -0,0 +1,9 @@
1
+ export interface CodeToken {
2
+ content: string;
3
+ color?: string;
4
+ fontStyle?: 'italic';
5
+ }
6
+ /** Tokens for each line of `source`, at once when they are cached, otherwise
7
+ * null now and `onReady` once the language has loaded. A language the
8
+ * highlighter doesn't know reads as plain text. */
9
+ export declare function highlightCode(source: string, language: string, incomplete: boolean, onReady: (lines: CodeToken[][]) => void): CodeToken[][] | null;
@@ -0,0 +1,29 @@
1
+ import { CODE_THEMES } from "./codeTheme.js";
2
+ import { code } from "@streamdown/code";
3
+ //#region src/components/codeHighlight.ts
4
+ var ITALIC = 1;
5
+ function toLines(tokens) {
6
+ return tokens.map((line) => line.map((token) => {
7
+ const color = token.htmlStyle?.["color"] ?? token.color;
8
+ const italic = token.htmlStyle?.["font-style"] === "italic" || ((token.fontStyle ?? 0) & ITALIC) === ITALIC;
9
+ return {
10
+ content: token.content,
11
+ ...color ? { color } : {},
12
+ ...italic ? { fontStyle: "italic" } : {}
13
+ };
14
+ }));
15
+ }
16
+ /** Tokens for each line of `source`, at once when they are cached, otherwise
17
+ * null now and `onReady` once the language has loaded. A language the
18
+ * highlighter doesn't know reads as plain text. */
19
+ function highlightCode(source, language, incomplete, onReady) {
20
+ const result = code.highlight({
21
+ code: source,
22
+ language: language || "text",
23
+ themes: CODE_THEMES,
24
+ isIncomplete: incomplete
25
+ }, (later) => onReady(toLines(later.tokens)));
26
+ return result ? toLines(result.tokens) : null;
27
+ }
28
+ //#endregion
29
+ export { highlightCode };
@@ -7,12 +7,16 @@ export type PageHeaderRegion = 'titleActions' | 'actions' | 'toolbar';
7
7
  export type RegionNodes = Readonly<Record<PageHeaderRegion, HTMLElement>>;
8
8
  export interface Declaration {
9
9
  breadcrumbs: readonly Breadcrumb[] | undefined;
10
+ /** Whether the trail's last crumb is the page's `h1`. */
11
+ heading: boolean;
10
12
  hidden: boolean;
11
13
  nodes: RegionNodes | null;
12
14
  fills: Readonly<Record<PageHeaderRegion, boolean>>;
13
15
  }
14
16
  export interface PageHeaderSnapshot {
15
17
  breadcrumbs: readonly Breadcrumb[];
18
+ /** Whether the trail's last crumb is the page's `h1`, as the page whose trail it is says. */
19
+ heading: boolean;
16
20
  hidden: boolean;
17
21
  titleActions: readonly HTMLElement[];
18
22
  actions: readonly HTMLElement[];
@@ -4,6 +4,7 @@ var NO_NODES = [];
4
4
  var NO_CRUMBS = [];
5
5
  var EMPTY = {
6
6
  breadcrumbs: NO_CRUMBS,
7
+ heading: true,
7
8
  hidden: false,
8
9
  titleActions: NO_NODES,
9
10
  actions: NO_NODES,
@@ -15,7 +16,7 @@ function sameCrumbs(a, b) {
15
16
  return a.every((crumb, i) => crumb.label === b[i]?.label && crumb.href === b[i]?.href);
16
17
  }
17
18
  function sameDeclaration(a, b) {
18
- return sameCrumbs(a.breadcrumbs, b.breadcrumbs) && a.hidden === b.hidden && a.nodes === b.nodes && a.fills.titleActions === b.fills.titleActions && a.fills.actions === b.fills.actions && a.fills.toolbar === b.fills.toolbar;
19
+ return sameCrumbs(a.breadcrumbs, b.breadcrumbs) && a.heading === b.heading && a.hidden === b.hidden && a.nodes === b.nodes && a.fills.titleActions === b.fills.titleActions && a.fills.actions === b.fills.actions && a.fills.toolbar === b.fills.toolbar;
19
20
  }
20
21
  function sameNodes(a, b) {
21
22
  return a.length === b.length && a.every((node, i) => node === b[i]);
@@ -54,10 +55,12 @@ var PageHeaderStore = class {
54
55
  const next = ordered.flatMap((d) => d.nodes && d.fills[region] ? [d.nodes[region]] : []);
55
56
  return sameNodes(next, prev) ? prev : next;
56
57
  };
57
- const trail = ordered.findLast((d) => d.breadcrumbs !== void 0)?.breadcrumbs ?? NO_CRUMBS;
58
+ const owner = ordered.findLast((d) => d.breadcrumbs !== void 0);
59
+ const trail = owner?.breadcrumbs ?? NO_CRUMBS;
58
60
  const prev = this.snapshot;
59
61
  this.snapshot = {
60
62
  breadcrumbs: sameCrumbs(trail, prev.breadcrumbs) ? prev.breadcrumbs : trail,
63
+ heading: owner?.heading ?? true,
61
64
  hidden: ordered.some((d) => d.hidden),
62
65
  titleActions: regionNodes("titleActions", prev.titleActions),
63
66
  actions: regionNodes("actions", prev.actions),
@@ -13,9 +13,9 @@ import { useCopy } from "../components/useCopy.js";
13
13
  import { Breadcrumbs } from "../components/Breadcrumbs.js";
14
14
  import { Button } from "../components/Button.js";
15
15
  import { Callout } from "../components/Callout.js";
16
+ import { CopyButton, CopyCodeBlock } from "../components/CopyButton.js";
16
17
  import { InfoTip } from "../components/InfoTip.js";
17
18
  import { ConfirmModal } from "../components/ConfirmModal.js";
18
- import { CopyButton, CopyCodeBlock } from "../components/CopyButton.js";
19
19
  import { CreateModal } from "../components/CreateModal.js";
20
20
  import { useSplitter } from "../components/splitter.js";
21
21
  import { formatBytes, formatDateTime } from "../format.js";
package/dist/index.d.ts CHANGED
@@ -5,8 +5,9 @@ export { type Breadcrumb, Breadcrumbs, type BreadcrumbsProps } from './component
5
5
  export { Button, type ButtonProps, MethodButton } from './components/Button.js';
6
6
  export { type ButtonSize, type ButtonStyle, type ButtonVariant, buttonClasses, } from './components/buttonClasses.js';
7
7
  export { Callout, type CalloutProps, type CalloutTone } from './components/Callout.js';
8
- export { Card, CardHeader, type CardHeaderProps, type CardPadding, type CardProps, type CardSize, } from './components/Card.js';
8
+ export { Card, CardHeader, type CardHeaderProps, type CardPadding, type CardProps, type CardSize, type CardTone, } from './components/Card.js';
9
9
  export { Checkbox, CheckboxGroup, type CheckboxProps } from './components/Checkbox.js';
10
+ export { CodeBlock, type CodeBlockProps } from './components/CodeBlock.js';
10
11
  export { ColorInput, type ColorInputProps } from './components/ColorInput.js';
11
12
  export { Autocomplete, type AutocompleteProps, Combobox, type ComboboxGroup, type ComboboxItem, type ComboboxItems, type ComboboxProps, } from './components/Combobox.js';
12
13
  export { ConfirmModal, type ConfirmModalProps, type ConfirmRequest, useConfirm, } from './components/ConfirmModal.js';
package/dist/index.js CHANGED
@@ -23,6 +23,8 @@ import { Callout } from "./components/Callout.js";
23
23
  import { Card, CardHeader } from "./components/Card.js";
24
24
  import { fieldBox } from "./components/fieldBox.js";
25
25
  import { Checkbox, CheckboxGroup } from "./components/Checkbox.js";
26
+ import { CopyButton, CopyCodeBlock } from "./components/CopyButton.js";
27
+ import { CodeBlock } from "./components/CodeBlock.js";
26
28
  import { JND, composite, deltaE, parseColor, toHex, toP3 } from "./theme/color.js";
27
29
  import { apcaContrast, contrastRatio, isDarkColor } from "./theme/contrast.js";
28
30
  import { CODE_STYLES, DEFAULT_CONTRAST, DEFAULT_PRESET, DEFAULT_THEME, THEME_PRESETS, modeOf, parseTheme, resolveMode, schemeFor, serializeTheme } from "./theme/model.js";
@@ -40,7 +42,6 @@ import { Tag, TagList, normalizeTags, tagClasses } from "./components/Tag.js";
40
42
  import { Autocomplete, Combobox } from "./components/Combobox.js";
41
43
  import { Modal, ModalDescription, ModalTitle, modalPanelClassName } from "./components/Modal.js";
42
44
  import { ConfirmModal, useConfirm } from "./components/ConfirmModal.js";
43
- import { CopyButton, CopyCodeBlock } from "./components/CopyButton.js";
44
45
  import { Disclosure, DisclosurePanel, collapsePanelClassName } from "./components/Disclosure.js";
45
46
  import { Switch } from "./components/Switch.js";
46
47
  import { CreateModal, CreateModalSelect, CreateModalSwitch } from "./components/CreateModal.js";
@@ -83,4 +84,4 @@ import { ToggleGroup } from "./components/ToggleGroup.js";
83
84
  import { useClosingValue } from "./components/useClosingValue.js";
84
85
  import { useCssIsDark } from "./components/useCssIsDark.js";
85
86
  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, 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 };
87
+ export { ActionMenu, AppLink, Autocomplete, Avatar, AvatarGroup, Breadcrumbs, Button, CODE_STYLES, Calendar, Callout, Card, CardHeader, ChartLegendList, ChartTooltipContent, Checkbox, CheckboxGroup, CodeBlock, 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 };
@@ -9,7 +9,7 @@ import { Input } from "../components/Input.js";
9
9
  import { Combobox } from "../components/Combobox.js";
10
10
  import { Calendar } from "../components/DatePicker.js";
11
11
  import { Drawer } from "../components/Drawer.js";
12
- import { DATE_PRESETS, fieldOperators, isDatePreset, isMultiple, parseDay, toDay } from "./filterModel.js";
12
+ import { DATE_PRESETS, fieldOperators, isDatePreset, isMultiple, operatorCount, parseDay, toDay } from "./filterModel.js";
13
13
  import { Menu } from "@base-ui/react/menu";
14
14
  import { useEffect, useLayoutEffect, useRef, useState } from "react";
15
15
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -81,7 +81,7 @@ function FilterChip({ filters, filter, field, stretch = false, answers, onRemove
81
81
  const shown = all.slice(0, 2);
82
82
  const hidden = all.length - shown.length;
83
83
  const valueText = unset ? showsAny ? t.any : t.pending : t.list(shown);
84
- const operatorText = t.operator(filter.op, filter.values.length);
84
+ const operatorText = t.operator(filter.op, operatorCount(field, filter));
85
85
  const noValuePart = filter.op === "isSet" || filter.op === "isNotSet" || field.kind === "boolean" && filter.values[0] !== "false";
86
86
  const noOperatorPart = showsAny || field.kind === "boolean" && filter.values[0] !== "false";
87
87
  const readAll = unset ? valueText : t.list(all);
@@ -121,6 +121,7 @@ function FilterChip({ filters, filter, field, stretch = false, answers, onRemove
121
121
  }),
122
122
  !noOperatorPart && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Divider, {}), operators.length > 1 ? /* @__PURE__ */ jsx(OperatorMenu, {
123
123
  filters,
124
+ field,
124
125
  filter,
125
126
  operators,
126
127
  open: open === "operator",
@@ -218,9 +219,9 @@ function FieldMenu({ filters, field, open, onOpenChange }) {
218
219
  })]
219
220
  });
220
221
  }
221
- function OperatorMenu({ filters, filter, operators, open, onOpenChange }) {
222
+ function OperatorMenu({ filters, field, filter, operators, open, onOpenChange }) {
222
223
  const t = useStrings().filters;
223
- const count = filter.values.length;
224
+ const count = operatorCount(field, filter);
224
225
  const text = t.operator(filter.op, count);
225
226
  return /* @__PURE__ */ jsxs(Menu.Root, {
226
227
  open,
@@ -246,7 +247,7 @@ function OperatorMenu({ filters, filter, operators, open, onOpenChange }) {
246
247
  },
247
248
  children: operators.map((op) => /* @__PURE__ */ jsx(MenuRadioItem, {
248
249
  value: op,
249
- children: t.operator(op, Math.max(count, 1))
250
+ children: t.operator(op, count)
250
251
  }, op))
251
252
  }) })]
252
253
  });
@@ -79,6 +79,10 @@ export type DatePreset = (typeof DATE_PRESETS)[number];
79
79
  type AnyField = FilterField<any>;
80
80
  export declare function fieldOperators(field: AnyField): readonly FilterOperator[];
81
81
  export declare function isMultiple(field: AnyField): boolean;
82
+ /** How many values a condition's words are for: the values chosen, and one while none is, so a
83
+ * chip just added reads "is" rather than "is any of"; never more than one where only one can be
84
+ * chosen. Hosts that word the condition by count, as a plural rule does, get the right form. */
85
+ export declare function operatorCount(field: AnyField, filter: ActiveFilter): number;
82
86
  /** Whether a filter narrows anything yet: a value chosen, or a condition that needs none. */
83
87
  export declare function isComplete(filter: ActiveFilter): boolean;
84
88
  /** Whether two sets of filters say the same, ignoring order, as Save or Update buttons ask. */
@@ -25,6 +25,12 @@ function fieldOperators(field) {
25
25
  function isMultiple(field) {
26
26
  return (field.kind === "enum" || field.kind === "people") && field.multiple !== false;
27
27
  }
28
+ /** How many values a condition's words are for: the values chosen, and one while none is, so a
29
+ * chip just added reads "is" rather than "is any of"; never more than one where only one can be
30
+ * chosen. Hosts that word the condition by count, as a plural rule does, get the right form. */
31
+ function operatorCount(field, filter) {
32
+ return isMultiple(field) ? Math.max(filter.values.length, 1) : 1;
33
+ }
28
34
  /** Whether a filter narrows anything yet: a value chosen, or a condition that needs none. */
29
35
  function isComplete(filter) {
30
36
  if (filter.op === "isSet" || filter.op === "isNotSet") return true;
@@ -305,4 +311,4 @@ function applyFilterList(rows, filters, fields, now = /* @__PURE__ */ new Date()
305
311
  return rows.filter((row) => checks.every(({ field, filter }) => matchFilter(field, filter, row, now)));
306
312
  }
307
313
  //#endregion
308
- export { DATE_PRESETS, applyFilterList, dateFilterRange, decodeFilters, encodeFilters, fieldOperators, filterParamKeys, fromStored, isComplete, isDatePreset, isMultiple, matchFilter, parseDay, sameFilters, toDay, toStored, withFilterParams };
314
+ export { DATE_PRESETS, applyFilterList, dateFilterRange, decodeFilters, encodeFilters, fieldOperators, filterParamKeys, fromStored, isComplete, isDatePreset, isMultiple, matchFilter, operatorCount, parseDay, sameFilters, toDay, toStored, withFilterParams };
@@ -61,6 +61,7 @@
61
61
  --theme-shadow-xl:
62
62
  0 25px 80px -20px light-dark(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.6)),
63
63
  0 10px 30px -10px light-dark(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.4));
64
+ --theme-backdrop: light-dark(rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.65));
64
65
  --theme-code-bg: light-dark(#e7eaee, #1c242c);
65
66
  --theme-code-text: light-dark(#1c2330, #e1e9f2);
66
67
  --theme-code-comment: light-dark(#555d6c, #c0c8d1);