@parallelworks/ui 0.89.0 → 0.90.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.
@@ -1,5 +1,5 @@
1
1
  import { ChevronDownIcon } from "../../icons.js";
2
- import { Select } from "../../components/Select.js";
2
+ import { Combobox } from "../../components/Combobox.js";
3
3
  import { useChatConfig } from "../core/config.js";
4
4
  import { useChat } from "../core/ChatProvider.js";
5
5
  import { chipClassName } from "../ui/chip.js";
@@ -42,8 +42,9 @@ function AllocationSelector({ model, allocation } = {}) {
42
42
  const selected = allocations.find((a) => a.name === selectedAllocation);
43
43
  return /* @__PURE__ */ jsxs("div", {
44
44
  className: "flex min-w-0 shrink-[3] items-center gap-2",
45
- children: [/* @__PURE__ */ jsx(Select, {
45
+ children: [/* @__PURE__ */ jsx(Combobox, {
46
46
  "aria-label": t.choose,
47
+ placeholder: t.search,
47
48
  items: allocations.map((a) => ({
48
49
  value: a.name,
49
50
  label: a.name,
@@ -75,6 +75,7 @@ export interface ChatStrings {
75
75
  allocationPicker: {
76
76
  choose: string;
77
77
  placeholder: string;
78
+ search: string;
78
79
  usage: (used: string, total: string) => string;
79
80
  };
80
81
  queue: {
@@ -71,6 +71,7 @@ var defaultChatStrings = {
71
71
  allocationPicker: {
72
72
  choose: "Allocation",
73
73
  placeholder: "Select allocation",
74
+ search: "Search allocations…",
74
75
  usage: (used, total) => `${used} / ${total}`
75
76
  },
76
77
  activity: {
@@ -585,6 +585,19 @@ export interface UIStrings {
585
585
  backspace: string;
586
586
  delete: string;
587
587
  };
588
+ /** A run's status in words, beside its icon: one ended in an error or a fault reads as
589
+ * failed, and one skipped after a failure as skipped. */
590
+ runStatus: {
591
+ queued: string;
592
+ running: string;
593
+ canceling: string;
594
+ completed: string;
595
+ warning: string;
596
+ failed: string;
597
+ canceled: string;
598
+ skipped: string;
599
+ notRun: string;
600
+ };
588
601
  chart: {
589
602
  /** The row under a chart's tooltip that sums its series. */
590
603
  total: string;
@@ -580,6 +580,17 @@ var DEFAULTS = {
580
580
  backspace: "Backspace",
581
581
  delete: "Delete"
582
582
  },
583
+ runStatus: {
584
+ queued: "Queued",
585
+ running: "Running",
586
+ canceling: "Canceling",
587
+ completed: "Completed",
588
+ warning: "Warning",
589
+ failed: "Failed",
590
+ canceled: "Canceled",
591
+ skipped: "Skipped",
592
+ notRun: "Not run"
593
+ },
583
594
  chart: {
584
595
  total: "Total",
585
596
  other: "Other"
@@ -4,8 +4,8 @@ import { type Tone } from './tone.js';
4
4
  /** A status the icon shows: a run's, or one a host maps onto it, such as
5
5
  * `pending` for something queued and `warning` for something done with problems. */
6
6
  export type RunStatusIconStatus = RunStatus | 'pending' | 'warning';
7
- /** The tone a run status reads in, so a badge that says the status in words matches the
8
- * icon: `<StatusBadge variant={runStatusTone(status)}>`. */
7
+ /** The tone a run status reads in, so a host's own mark for it, such as a lamp, matches the
8
+ * icon: `<StatusLabel variant={runStatusTone(status)}>`. */
9
9
  export declare function runStatusTone(status: RunStatusIconStatus): Tone;
10
10
  /** Any other span attribute and the ref reach the icon's element, so it can be a Tooltip's or a
11
11
  * popover's direct child. */
@@ -19,6 +19,6 @@ export interface RunStatusIconProps extends Omit<ComponentPropsWithRef<'span'>,
19
19
  className?: string | undefined;
20
20
  }
21
21
  /** A run's, job's or step's status as an icon in its tone, beside the name of what ran. It
22
- * is named by `label`, or else `strings.dag.statusLabel`. To say the status in words, use
23
- * `StatusBadge` with `runStatusTone`. */
22
+ * is named by `label`, or else `strings.dag.statusLabel`. To say the status in words beside it,
23
+ * use `RunStatusLabel`. */
24
24
  export declare function RunStatusIcon({ status, label: ownLabel, tooltip, className, ...rest }: RunStatusIconProps): import("react").JSX.Element;
@@ -60,14 +60,14 @@ var looks = {
60
60
  faint: true
61
61
  }
62
62
  };
63
- /** The tone a run status reads in, so a badge that says the status in words matches the
64
- * icon: `<StatusBadge variant={runStatusTone(status)}>`. */
63
+ /** The tone a run status reads in, so a host's own mark for it, such as a lamp, matches the
64
+ * icon: `<StatusLabel variant={runStatusTone(status)}>`. */
65
65
  function runStatusTone(status) {
66
66
  return looks[status ?? ""].tone;
67
67
  }
68
68
  /** A run's, job's or step's status as an icon in its tone, beside the name of what ran. It
69
- * is named by `label`, or else `strings.dag.statusLabel`. To say the status in words, use
70
- * `StatusBadge` with `runStatusTone`. */
69
+ * is named by `label`, or else `strings.dag.statusLabel`. To say the status in words beside it,
70
+ * use `RunStatusLabel`. */
71
71
  function RunStatusIcon({ status, label: ownLabel, tooltip = false, className, ...rest }) {
72
72
  const { dag } = useStrings();
73
73
  const look = looks[status ?? ""];
@@ -6,11 +6,9 @@ export type BadgeVariant = Tone | 'accent';
6
6
  /** How loud a badge is: `soft` tints it, `solid` fills it for the one thing that
7
7
  * must catch the eye, and `outline` leaves only its edge and text. */
8
8
  export type BadgeEmphasis = 'soft' | 'solid' | 'outline';
9
- /** A badge's outline: a `pill`, or a squarer `tag` for a label such as "Beta". */
10
- export type BadgeShape = 'pill' | 'tag';
11
9
  declare const sizeClasses: {
12
- readonly sm: 'gap-1 py-px text-[10px] leading-3.5';
13
- readonly md: 'gap-1.5 py-0.5 text-[11px] leading-4';
10
+ readonly sm: 'gap-1 px-1.5 py-px text-[10px] leading-3.5';
11
+ readonly md: 'gap-1.5 px-2 py-0.5 text-[11px] leading-4';
14
12
  };
15
13
  export type BadgeSize = keyof typeof sizeClasses;
16
14
  /** Any other span attribute and the ref reach its element, so it can be a Tooltip's or a popover's
@@ -22,8 +20,6 @@ export interface StatusBadgeProps extends Omit<ComponentPropsWithRef<'span'>, 'c
22
20
  variant?: BadgeVariant | undefined;
23
21
  /** `soft` (the default) tints it; `solid` fills it; `outline` draws only its edge. */
24
22
  emphasis?: BadgeEmphasis | undefined;
25
- /** `pill` (the default), or `tag` for a squarer label such as "Preview". */
26
- shape?: BadgeShape | undefined;
27
23
  /** Uppercase, tracked letters, for a short label such as "Beta". */
28
24
  caps?: boolean | undefined;
29
25
  /** Cuts a long label off with an ellipsis instead of growing past its cell. */
@@ -44,8 +40,16 @@ export interface StatusBadgeProps extends Omit<ComponentPropsWithRef<'span'>, 'c
44
40
  /** A line of text in a variant's color, for a status that stands beside a
45
41
  * dot rather than inside a badge. */
46
42
  export declare function statusTextClass(variant: BadgeVariant): string;
47
- /** A short status or label in a tone, such as "Running" or "Preview". */
48
- export declare function StatusBadge({ children, variant, emphasis, shape, caps, truncate, pulse, dot, off, size, render, className, ref, ...rest }: StatusBadgeProps): ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
43
+ /** A flag: what's notable about this one. A small soft pill right after a name, for a fixed
44
+ * fact worth noticing, such as Inline, New, Your version, Preview, Ends soon or Read only: short
45
+ * and rare, at most one or two on a row. It's neutral by default (`muted`, such as Inline, Your
46
+ * version or Read only), `accent` for something new to you (New, Preview, Beta), `warning` when
47
+ * it warns (Ends soon), and never `success` or `error`, which are statuses.
48
+ *
49
+ * Not for a state, which changes over time: that is a status (`StatusLabel`, or
50
+ * `RunStatusLabel` for a run), never a tinted pill. Not for a label someone gave it: that is a
51
+ * `Tag`. See "UI/Badges/Which one". */
52
+ export declare function StatusBadge({ children, variant, emphasis, caps, truncate, pulse, dot, off, size, render, className, ref, ...rest }: StatusBadgeProps): ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
49
53
  /** Any other span attribute and the ref reach its element, so it can be a Tooltip's or a popover's
50
54
  * direct child. */
51
55
  export interface CountBadgeProps extends Omit<ComponentPropsWithRef<'span'>, 'children' | 'className'> {
@@ -32,35 +32,29 @@ var emphasisClasses = {
32
32
  var LAMP = "bg-[linear-gradient(var(--lamp-from),var(--lamp-to))] shadow-[0_0_3px_rgb(0_0_0/0.5)]";
33
33
  var LAMP_OFF = "shadow-[inset_0_0_0_1.5px_var(--theme-border-strong)]";
34
34
  var sizeClasses = {
35
- sm: "gap-1 py-px text-[10px] leading-3.5",
36
- md: "gap-1.5 py-0.5 text-[11px] leading-4"
37
- };
38
- var padClasses = {
39
- pill: {
40
- sm: "px-1.5",
41
- md: "px-2"
42
- },
43
- tag: {
44
- sm: "px-1",
45
- md: "px-1.5"
46
- }
47
- };
48
- var shapeClasses = {
49
- pill: "rounded-full",
50
- tag: "rounded-[4px]"
35
+ sm: "gap-1 px-1.5 py-px text-[10px] leading-3.5",
36
+ md: "gap-1.5 px-2 py-0.5 text-[11px] leading-4"
51
37
  };
52
38
  /** A line of text in a variant's color, for a status that stands beside a
53
39
  * dot rather than inside a badge. */
54
40
  function statusTextClass(variant) {
55
41
  return variant === "accent" ? "text-(--theme-link)" : toneText[variant];
56
42
  }
57
- /** A short status or label in a tone, such as "Running" or "Preview". */
58
- function StatusBadge({ children, variant = "default", emphasis = "soft", shape = "pill", caps = false, truncate = false, pulse = false, dot = false, off = false, size = "sm", render, className, ref, ...rest }) {
43
+ /** A flag: what's notable about this one. A small soft pill right after a name, for a fixed
44
+ * fact worth noticing, such as Inline, New, Your version, Preview, Ends soon or Read only: short
45
+ * and rare, at most one or two on a row. It's neutral by default (`muted`, such as Inline, Your
46
+ * version or Read only), `accent` for something new to you (New, Preview, Beta), `warning` when
47
+ * it warns (Ends soon), and never `success` or `error`, which are statuses.
48
+ *
49
+ * Not for a state, which changes over time: that is a status (`StatusLabel`, or
50
+ * `RunStatusLabel` for a run), never a tinted pill. Not for a label someone gave it: that is a
51
+ * `Tag`. See "UI/Badges/Which one". */
52
+ function StatusBadge({ children, variant = "default", emphasis = "soft", caps = false, truncate = false, pulse = false, dot = false, off = false, size = "sm", render, className, ref, ...rest }) {
59
53
  return useRender({
60
54
  render: render ?? /* @__PURE__ */ jsx("span", {}),
61
55
  ref,
62
56
  props: mergeProps(rest, {
63
- className: cx("inline-flex items-center border font-medium no-underline", "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--theme-focus)", sizeClasses[size], padClasses[shape][size], shapeClasses[shape], caps && "uppercase tracking-wider", truncate && "min-w-0 max-w-full", emphasisClasses[emphasis][variant], className),
57
+ className: cx("inline-flex items-center border font-medium no-underline", "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--theme-focus)", sizeClasses[size], "rounded-full", caps && "uppercase tracking-wider", truncate && "min-w-0 max-w-full", emphasisClasses[emphasis][variant], className),
64
58
  children: /* @__PURE__ */ jsxs(Fragment, { children: [(pulse || dot) && /* @__PURE__ */ jsx(StatusDot, {
65
59
  variant,
66
60
  pulse,
@@ -0,0 +1,44 @@
1
+ import type { ComponentPropsWithRef, ReactNode } from 'react';
2
+ import { type RunStatusIconStatus } from './RunStatusIcon.js';
3
+ import { type BadgeVariant } from './StatusBadge.js';
4
+ /** Any other span attribute and the ref reach its element, so it can be a Tooltip's or a popover's
5
+ * direct child. */
6
+ export interface StatusLabelProps extends Omit<ComponentPropsWithRef<'span'>, 'children' | 'className'> {
7
+ /** The state's name, such as "Running". */
8
+ children: ReactNode;
9
+ /** The lamp's tone, lit; `off` shows it unlit. Ignored with `icon`. */
10
+ variant?: BadgeVariant | undefined;
11
+ /** An unlit lamp, a hollow ring, for something off or not known, such as an offline agent. */
12
+ off?: boolean | undefined;
13
+ /** A ping from the lamp, for something under way. */
14
+ pulse?: boolean | undefined;
15
+ /** An icon in place of the lamp, such as a `RunStatusIcon`. */
16
+ icon?: ReactNode | undefined;
17
+ className?: string | undefined;
18
+ }
19
+ /** A status: what state something is in, as a lamp or icon and the state's name, in muted text
20
+ * with no fill. It sits in a status column or under a title, and looks the same for a run, a
21
+ * resource or an agent. The name says the status, so the lamp or icon is hidden from assistive
22
+ * technology and the status is not read twice. A long name truncates.
23
+ *
24
+ * Not for a fixed fact worth noticing, such as "Preview" (a flag: `StatusBadge`), or a label
25
+ * someone gave it (a `Tag`). See "UI/Badges/Which one". */
26
+ export declare function StatusLabel({ children, variant, off, pulse, icon, className, ...rest }: StatusLabelProps): import("react").JSX.Element;
27
+ /** A run's status in the run status icon's look: a status the server sent, or none for one it
28
+ * has no look for. */
29
+ export declare function runStatusLook(status: string | null | undefined): RunStatusIconStatus;
30
+ /** Names a run's status in words, from `strings.runStatus`: every status the run status icon
31
+ * draws has a name, an error, a fault or a failure reads as failed, and no status reads as not
32
+ * run. Only a status the icon doesn't know reads as `fallback` says, or as the server sent it. */
33
+ export declare function useRunStatusName(): (status: string | null | undefined, fallback?: (status: string | null | undefined) => string) => string;
34
+ /** Any other span attribute and the ref reach its element, so it can be a Tooltip's or a popover's
35
+ * direct child. */
36
+ export interface RunStatusLabelProps extends Omit<StatusLabelProps, 'children' | 'variant' | 'off' | 'pulse' | 'icon'> {
37
+ /** The run's status as the server sent it; one with no look shows no icon's shape. */
38
+ status: string | null | undefined;
39
+ /** The name for a status the run status icon doesn't know; the status as sent by default. */
40
+ fallback?: ((status: string | null | undefined) => string) | undefined;
41
+ }
42
+ /** A run's status: the run status icon and its name, as a status (`StatusLabel`). A running or
43
+ * canceling run's icon moves. See "UI/Badges/Which one". */
44
+ export declare function RunStatusLabel({ status, fallback, ...rest }: RunStatusLabelProps): import("react").JSX.Element;
@@ -0,0 +1,92 @@
1
+ import { cx } from "../cx.js";
2
+ import { useStrings } from "./Provider.js";
3
+ import { RunStatusIcon } from "./RunStatusIcon.js";
4
+ import { StatusDot } from "./StatusBadge.js";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ //#region src/components/StatusLabel.tsx
7
+ /** A status: what state something is in, as a lamp or icon and the state's name, in muted text
8
+ * with no fill. It sits in a status column or under a title, and looks the same for a run, a
9
+ * resource or an agent. The name says the status, so the lamp or icon is hidden from assistive
10
+ * technology and the status is not read twice. A long name truncates.
11
+ *
12
+ * Not for a fixed fact worth noticing, such as "Preview" (a flag: `StatusBadge`), or a label
13
+ * someone gave it (a `Tag`). See "UI/Badges/Which one". */
14
+ function StatusLabel({ children, variant = "default", off = false, pulse = false, icon, className, ...rest }) {
15
+ return /* @__PURE__ */ jsxs("span", {
16
+ ...rest,
17
+ className: cx("inline-flex min-w-0 items-center gap-1.5 text-(--theme-muted-text-color)", className),
18
+ children: [icon != null ? /* @__PURE__ */ jsx("span", {
19
+ "aria-hidden": "true",
20
+ className: "inline-flex shrink-0 items-center",
21
+ children: icon
22
+ }) : /* @__PURE__ */ jsx(StatusDot, {
23
+ variant,
24
+ off,
25
+ pulse,
26
+ className: "shrink-0"
27
+ }), /* @__PURE__ */ jsx("span", {
28
+ className: "min-w-0 truncate",
29
+ children
30
+ })]
31
+ });
32
+ }
33
+ var RUN_LOOKS = /* @__PURE__ */ new Set([
34
+ "pending",
35
+ "started",
36
+ "running",
37
+ "completed",
38
+ "warning",
39
+ "failed",
40
+ "error",
41
+ "skipped",
42
+ "skipped-failed",
43
+ "canceled",
44
+ "faulted",
45
+ "canceling"
46
+ ]);
47
+ /** A run's status in the run status icon's look: a status the server sent, or none for one it
48
+ * has no look for. */
49
+ function runStatusLook(status) {
50
+ return status && RUN_LOOKS.has(status) ? status : "";
51
+ }
52
+ /** Names a run's status in words, from `strings.runStatus`: every status the run status icon
53
+ * draws has a name, an error, a fault or a failure reads as failed, and no status reads as not
54
+ * run. Only a status the icon doesn't know reads as `fallback` says, or as the server sent it. */
55
+ function useRunStatusName() {
56
+ const { runStatus: t } = useStrings();
57
+ return (status, fallback) => {
58
+ switch (status) {
59
+ case void 0:
60
+ case null:
61
+ case "": return t.notRun;
62
+ case "pending": return t.queued;
63
+ case "started":
64
+ case "running": return t.running;
65
+ case "canceling": return t.canceling;
66
+ case "completed": return t.completed;
67
+ case "error":
68
+ case "faulted":
69
+ case "failed": return t.failed;
70
+ case "canceled": return t.canceled;
71
+ case "warning": return t.warning;
72
+ case "skipped":
73
+ case "skipped-failed": return t.skipped;
74
+ default: return fallback ? fallback(status) : status;
75
+ }
76
+ };
77
+ }
78
+ /** A run's status: the run status icon and its name, as a status (`StatusLabel`). A running or
79
+ * canceling run's icon moves. See "UI/Badges/Which one". */
80
+ function RunStatusLabel({ status, fallback, ...rest }) {
81
+ const name = useRunStatusName();
82
+ return /* @__PURE__ */ jsx(StatusLabel, {
83
+ ...rest,
84
+ icon: /* @__PURE__ */ jsx(RunStatusIcon, {
85
+ status: runStatusLook(status),
86
+ label: ""
87
+ }),
88
+ children: name(status, fallback)
89
+ });
90
+ }
91
+ //#endregion
92
+ export { RunStatusLabel, StatusLabel, runStatusLook, useRunStatusName };
@@ -24,8 +24,13 @@ export interface TagProps extends TagStyle, Omit<ComponentPropsWithRef<'span'>,
24
24
  title?: string | undefined;
25
25
  className?: string | undefined;
26
26
  }
27
- /** A tag or label on a thing: a pill with an optional color dot, a link with `href`, and an ×
28
- * with `onRemove`. */
27
+ /** A tag: what someone has labelled a thing. A neutral hairline pill with an optional color
28
+ * dot; people add, remove and filter by tags, so it can be a link with `href` and have an ×
29
+ * with `onRemove`. For marketplace tags, labels, key=value pairs, and a report's schedule or
30
+ * format.
31
+ *
32
+ * Not for a fixed fact worth noticing, such as "Preview" (a flag: `StatusBadge`), or a state
33
+ * (a status: `StatusLabel`). See "UI/Badges/Which one". */
29
34
  export declare function Tag({ children, color, href, onRemove, removeLabel, title, mono, caps, className, ref, ...rest }: TagProps): import("react").JSX.Element;
30
35
  /** One tag of a `TagList`: a string is its own key and label. */
31
36
  export type TagItem = string | {
@@ -12,8 +12,13 @@ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
12
12
  function tagClasses({ mono = false, caps = false } = {}) {
13
13
  return cx("inline-flex h-5 max-w-full min-w-0 shrink-0 items-center gap-1 rounded-full border border-(--theme-border) bg-(--theme-panel-bg) px-2 text-[11px] leading-none whitespace-nowrap text-(--theme-app)", mono ? "font-mono" : "font-sans", caps && "text-[10px] font-medium tracking-wide uppercase");
14
14
  }
15
- /** A tag or label on a thing: a pill with an optional color dot, a link with `href`, and an ×
16
- * with `onRemove`. */
15
+ /** A tag: what someone has labelled a thing. A neutral hairline pill with an optional color
16
+ * dot; people add, remove and filter by tags, so it can be a link with `href` and have an ×
17
+ * with `onRemove`. For marketplace tags, labels, key=value pairs, and a report's schedule or
18
+ * format.
19
+ *
20
+ * Not for a fixed fact worth noticing, such as "Preview" (a flag: `StatusBadge`), or a state
21
+ * (a status: `StatusLabel`). See "UI/Badges/Which one". */
17
22
  function Tag({ children, color, href, onRemove, removeLabel, title, mono, caps, className, ref, ...rest }) {
18
23
  const { dropdown } = useStrings();
19
24
  const content = /* @__PURE__ */ jsxs(Fragment$1, { children: [color && /* @__PURE__ */ jsx("span", {
package/dist/index.d.ts CHANGED
@@ -63,7 +63,8 @@ export { SettingModeOption } from './components/SettingModeOption.js';
63
63
  export { SettingRow, SettingsCard, type SettingsCardProps, SettingsHeading, } from './components/SettingsCard.js';
64
64
  export { LoadingRegion, Skeleton, type SkeletonProps } from './components/Skeleton.js';
65
65
  export { Slider, type SliderProps } from './components/Slider.js';
66
- export { type BadgeEmphasis, type BadgeShape, type BadgeSize, type BadgeVariant, CountBadge, type CountBadgeProps, StatusBadge, type StatusBadgeProps, StatusDot, type StatusDotProps, statusTextClass, } from './components/StatusBadge.js';
66
+ export { type BadgeEmphasis, type BadgeSize, type BadgeVariant, CountBadge, type CountBadgeProps, StatusBadge, type StatusBadgeProps, StatusDot, type StatusDotProps, statusTextClass, } from './components/StatusBadge.js';
67
+ export { RunStatusLabel, type RunStatusLabelProps, runStatusLook, StatusLabel, type StatusLabelProps, useRunStatusName, } from './components/StatusLabel.js';
67
68
  export { StickyBar, type StickyBarProps } from './components/StickyBar.js';
68
69
  export { Switch, type SwitchProps } from './components/Switch.js';
69
70
  export type { SegmentTone } from './components/segmented.js';
package/dist/index.js CHANGED
@@ -76,6 +76,7 @@ import { SettingModeOption } from "./components/SettingModeOption.js";
76
76
  import { SettingRow, SettingsCard, SettingsHeading } from "./components/SettingsCard.js";
77
77
  import { Slider } from "./components/Slider.js";
78
78
  import { CountBadge, StatusBadge, StatusDot, statusTextClass } from "./components/StatusBadge.js";
79
+ import { RunStatusLabel, StatusLabel, runStatusLook, useRunStatusName } from "./components/StatusLabel.js";
79
80
  import { StickyBar } from "./components/StickyBar.js";
80
81
  import { Table } from "./components/Table.js";
81
82
  import { TabPanel, Tabs } from "./components/Tabs.js";
@@ -84,4 +85,4 @@ import { ToggleGroup } from "./components/ToggleGroup.js";
84
85
  import { useClosingValue } from "./components/useClosingValue.js";
85
86
  import { useCssIsDark } from "./components/useCssIsDark.js";
86
87
  import { useApplyTheme, useColorMode } from "./components/useTheme.js";
87
- export { ActionMenu, AppLink, Autocomplete, Avatar, AvatarGroup, Breadcrumbs, Button, CODE_STYLES, Calendar, Callout, Card, CardHeader, ChartLegendList, ChartReadout, ChartTooltipBeside, ChartTooltipContent, ChartTooltipFrame, 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, OTHER_SERIES_COLOR, OTHER_SERIES_KEY, OneTimeCodeInput, Overview, PAGE_SIZES, PageHeader, PageHeaderAction, PageHeaderAddButton, PageHeaderBar, PageHeaderMenu, PageHeaderProvider, Pagination, Popover, PopoverClose, ProgressBar, Radio, RadioGroup, RefreshButton, RelativeTime, RequiredMark, RevealToggle, RunStatusIcon, SERIES_LIMIT, 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, chartTooltipPlacement, collapsePanelClassName, composite, contrastRatio, cx, deltaE, deriveTheme, errorPageKind, fieldBox, fitSeed, foldSeries, 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, 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 };
88
+ export { ActionMenu, AppLink, Autocomplete, Avatar, AvatarGroup, Breadcrumbs, Button, CODE_STYLES, Calendar, Callout, Card, CardHeader, ChartLegendList, ChartReadout, ChartTooltipBeside, ChartTooltipContent, ChartTooltipFrame, 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, OTHER_SERIES_COLOR, OTHER_SERIES_KEY, OneTimeCodeInput, Overview, PAGE_SIZES, PageHeader, PageHeaderAction, PageHeaderAddButton, PageHeaderBar, PageHeaderMenu, PageHeaderProvider, Pagination, Popover, PopoverClose, ProgressBar, Radio, RadioGroup, RefreshButton, RelativeTime, RequiredMark, RevealToggle, RunStatusIcon, RunStatusLabel, SERIES_LIMIT, SIDEBAR_TOKENS, SearchInput, Section, SegmentedControl, Select, SelectionCopy, SeriesSwatch, SettingModeOption, SettingRow, SettingsCard, SettingsHeading, Skeleton, Slider, StatusBadge, StatusDot, StatusLabel, 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, chartTooltipPlacement, collapsePanelClassName, composite, contrastRatio, cx, deltaE, deriveTheme, errorPageKind, fieldBox, fitSeed, foldSeries, formatBytes, formatCount, formatDateTime, formatDuration, formatInfoTipContent, formatShortcut, formatTimeLeft, generateTheme, isApplePlatform, isDarkColor, isMenuDivider, isMenuGroup, isMenuSubmenu, isPlainClick, isTextEntryContext, levelTone, menuDivider, modalPanelClassName, modeOf, normalizeTags, parseColor, parseTheme, prefersWideGamut, resolveMode, runStatusLook, runStatusTone, schemeFor, serializeTheme, 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, useRunStatusName, useSeriesHighlight, useShortcutFormat, useShortcutKey, useSlots, useStrings, useWorkflowActions, useWorkflowEditing, useWorkflowEngine, useWorkflowEngineLoader };
@@ -732,7 +732,7 @@ function QuickRow({ filters, groups, narrow, onMore, end, stacked = false }) {
732
732
  const tops = /* @__PURE__ */ new Set();
733
733
  for (const button of el.querySelectorAll("button")) tops.add(Math.round(button.getBoundingClientRect().top));
734
734
  const shown = limit ?? total;
735
- if (tops.size > 1 && shown > 1) setLimit(shown - 1);
735
+ if (tops.size > 1 && shown > 0) setLimit(shown - 1);
736
736
  });
737
737
  const cap = fits && limit !== null ? limit : total;
738
738
  let index = 0;
@@ -812,6 +812,7 @@ function ListFilterBar({ filters, trailing, label, className }) {
812
812
  const [narrow, setNarrow] = useState(false);
813
813
  const [width, setWidth] = useState(0);
814
814
  const [limit, setLimit] = useState(null);
815
+ const [clearFolded, setClearFolded] = useState(false);
815
816
  const [sheet, setSheet] = useState(false);
816
817
  const [focusAt, setFocusAt] = useState(null);
817
818
  const chips = filters ? orderedChips(filters) : [];
@@ -826,6 +827,7 @@ function ListFilterBar({ filters, trailing, label, className }) {
826
827
  const empty = chips.length === 0;
827
828
  const hasQuick = quick.length > 0;
828
829
  const chipKeys = chips.map((c) => c.filter.field).join("\0");
830
+ const fixedChips = chips.filter((c) => c.field.required || c.field.pinned).length;
829
831
  useLayoutEffect(() => {
830
832
  const el = box.current;
831
833
  if (!el) return;
@@ -839,7 +841,10 @@ function ListFilterBar({ filters, trailing, label, className }) {
839
841
  observer.observe(el);
840
842
  return () => observer.disconnect();
841
843
  }, [empty, hasQuick]);
842
- useLayoutEffect(() => setLimit(null), [
844
+ useLayoutEffect(() => {
845
+ setLimit(null);
846
+ setClearFolded(false);
847
+ }, [
843
848
  width,
844
849
  chipKeys,
845
850
  narrow
@@ -848,9 +853,15 @@ function ListFilterBar({ filters, trailing, label, className }) {
848
853
  const el = row.current;
849
854
  if (!el || !narrow) return;
850
855
  const tops = /* @__PURE__ */ new Set();
851
- for (const child of el.children) tops.add(Math.round(child.offsetTop));
856
+ for (const child of el.children) if (!child.hasAttribute("data-filter-clear")) tops.add(Math.round(child.offsetTop));
852
857
  const shown = limit ?? chips.length;
853
- if (tops.size > 2 && shown > 1) setLimit(shown - 1);
858
+ if (tops.size > 2 && shown > Math.max(fixedChips, 1)) {
859
+ setLimit(shown - 1);
860
+ return;
861
+ }
862
+ const add = el.querySelector("[data-filter-add]");
863
+ const clear = el.querySelector("[data-filter-clear]");
864
+ if (add && clear && Math.round(clear.offsetTop) > Math.round(add.offsetTop)) setClearFolded(true);
854
865
  });
855
866
  useEffect(() => {
856
867
  if (focusAt === null || !row.current) return;
@@ -858,7 +869,7 @@ function ListFilterBar({ filters, trailing, label, className }) {
858
869
  setFocusAt(null);
859
870
  }, [focusAt]);
860
871
  const visible = narrow && limit !== null ? limit : chips.length;
861
- const shownChips = chips.filter((c, i) => i < visible || c.filter.field === filters?.draft);
872
+ const shownChips = chips.filter((c, i) => i < visible || c.field.required || c.field.pinned || c.filter.field === filters?.draft);
862
873
  const overflow = chips.length - shownChips.length;
863
874
  const request = filters?.editRequest;
864
875
  const hiddenRequest = request && !shownChips.some((c) => c.filter.field === request.field) && chips.some((c) => c.filter.field === request.field);
@@ -870,6 +881,7 @@ function ListFilterBar({ filters, trailing, label, className }) {
870
881
  const resetting = filters.hasDefaults;
871
882
  const clearButton = (resetting ? !filters.isDefault : removable) && /* @__PURE__ */ jsx("button", {
872
883
  type: "button",
884
+ "data-filter-clear": "",
873
885
  onClick: resetting ? filters.reset : filters.clear,
874
886
  className: buttonClasses({
875
887
  variant: "ghost",
@@ -939,7 +951,7 @@ function ListFilterBar({ filters, trailing, label, className }) {
939
951
  children: t.overflow(overflow)
940
952
  }),
941
953
  addButton(narrow),
942
- clearButton,
954
+ !(narrow && clearFolded) && clearButton,
943
955
  trailing && /* @__PURE__ */ jsx("div", {
944
956
  className: "ml-auto flex items-center gap-1.5",
945
957
  children: trailing