@parallelworks/ui 0.83.3 → 0.84.1
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.
- package/dist/ai/adapter/openai/createOpenAIStream.js +1 -1
- package/dist/ai/adapter/openai/sse.d.ts +3 -2
- package/dist/ai/adapter/openai/sse.js +4 -2
- package/dist/ai/adapter/types.d.ts +2 -1
- package/dist/ai/agent/index.d.ts +1 -1
- package/dist/ai/agent/toolfmt.d.ts +1 -0
- package/dist/ai/agent/toolfmt.js +6 -2
- package/dist/ai/ai.css +14 -0
- package/dist/ai/components/ChatActivity.js +6 -4
- package/dist/ai/components/ChatMessage.js +42 -30
- package/dist/ai/components/ChatMessageList.js +17 -9
- package/dist/ai/components/agent/AgentMessageParts.d.ts +1 -1
- package/dist/ai/components/agent/AgentMessageParts.js +77 -23
- package/dist/ai/core/ChatProvider.d.ts +3 -1
- package/dist/ai/core/ChatProvider.js +27 -6
- package/dist/ai/core/chatReducer.d.ts +6 -1
- package/dist/ai/core/chatReducer.js +18 -1
- package/dist/ai/core/config.d.ts +2 -1
- package/dist/ai/core/parts.d.ts +7 -4
- package/dist/ai/core/parts.js +23 -2
- package/dist/ai/core/useSSEStream.d.ts +8 -0
- package/dist/ai/core/useSSEStream.js +80 -22
- package/dist/ai/index.js +2 -2
- package/dist/ai/types.d.ts +14 -0
- package/dist/components/Avatar.d.ts +4 -2
- package/dist/components/Avatar.js +2 -1
- package/dist/components/Kbd.d.ts +5 -2
- package/dist/components/Kbd.js +4 -1
- package/dist/components/LetterBadge.d.ts +7 -3
- package/dist/components/LetterBadge.js +2 -3
- package/dist/components/Loader.d.ts +6 -4
- package/dist/components/Loader.js +53 -1
- package/dist/components/MarkdownImpl.d.ts +3 -0
- package/dist/components/MarkdownImpl.js +16 -2
- package/dist/components/RefreshButton.d.ts +3 -2
- package/dist/components/RefreshButton.js +25 -14
- package/dist/components/RunStatusIcon.d.ts +5 -2
- package/dist/components/RunStatusIcon.js +2 -1
- package/dist/components/StatusBadge.d.ts +17 -11
- package/dist/components/StatusBadge.js +10 -5
- package/dist/components/Table.d.ts +11 -1
- package/dist/components/Table.js +15 -4
- package/dist/components/Tabs.js +1 -1
- package/dist/components/Tag.d.ts +5 -3
- package/dist/components/Tag.js +7 -1
- package/dist/components/relativeTime.d.ts +12 -9
- package/dist/components/relativeTime.js +4 -2
- package/dist/components/stickyTop.d.ts +9 -0
- package/dist/components/stickyTop.js +10 -1
- package/dist/graph/DependencyGraph.js +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/list/ActionToolbar.js +1 -1
- package/dist/list/ListPage.js +32 -14
- package/dist/list/ListTable.js +13 -4
- package/dist/styles.css +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { cx } from "../cx.js";
|
|
2
2
|
import { RunningIcon } from "../icons.js";
|
|
3
|
+
import { pinnedAbove, scrollContainer } from "./stickyTop.js";
|
|
3
4
|
import { useStrings } from "./Provider.js";
|
|
4
|
-
import {
|
|
5
|
+
import { useLayoutEffect, useRef, useState } from "react";
|
|
6
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
5
7
|
//#region src/components/Loader.tsx
|
|
6
8
|
var RIPPLE_STAGGER_S = .22;
|
|
7
9
|
var LOGO_RINGS = [
|
|
@@ -19,6 +21,10 @@ var fillClasses = {
|
|
|
19
21
|
* known, such as rows of a list, sketch it with `Skeleton` instead. */
|
|
20
22
|
function Loader({ fill, ...props }) {
|
|
21
23
|
if (!fill) return /* @__PURE__ */ jsx(LoaderMark, { ...props });
|
|
24
|
+
if (fill === "content") return /* @__PURE__ */ jsx(ContentArea, { children: /* @__PURE__ */ jsx(LoaderMark, {
|
|
25
|
+
...props,
|
|
26
|
+
size: props.size ?? 48
|
|
27
|
+
}) });
|
|
22
28
|
return /* @__PURE__ */ jsx("div", {
|
|
23
29
|
className: fillClasses[fill],
|
|
24
30
|
children: /* @__PURE__ */ jsx(LoaderMark, {
|
|
@@ -68,5 +74,51 @@ function LoaderMark({ size = 48, label, variant = "spinner", inline = false, col
|
|
|
68
74
|
})]
|
|
69
75
|
});
|
|
70
76
|
}
|
|
77
|
+
/** Centers its content in the box of the scrolling region it sits in, which in an app with a
|
|
78
|
+
* sidebar is its content area, below what that region pins at its top and held to what of it
|
|
79
|
+
* the window shows; the window, where the document itself scrolls. It lays nothing out around
|
|
80
|
+
* it and takes no pointer. */
|
|
81
|
+
function ContentArea({ children }) {
|
|
82
|
+
const anchor = useRef(null);
|
|
83
|
+
const [box, setBox] = useState(null);
|
|
84
|
+
useLayoutEffect(() => {
|
|
85
|
+
const el = anchor.current;
|
|
86
|
+
if (!el) return;
|
|
87
|
+
const area = scrollContainer(el);
|
|
88
|
+
if (area === el.ownerDocument.documentElement) return;
|
|
89
|
+
const view = el.ownerDocument.defaultView ?? window;
|
|
90
|
+
const pinned = pinnedAbove(el);
|
|
91
|
+
const place = () => {
|
|
92
|
+
const rect = area.getBoundingClientRect();
|
|
93
|
+
const chrome = Math.max(0, ...pinned.chrome.map((c) => c.getBoundingClientRect().bottom));
|
|
94
|
+
const top = Math.max(rect.top, chrome, 0);
|
|
95
|
+
const bottom = Math.min(rect.bottom, view.innerHeight);
|
|
96
|
+
setBox({
|
|
97
|
+
top,
|
|
98
|
+
left: rect.left,
|
|
99
|
+
width: rect.width,
|
|
100
|
+
height: Math.max(bottom - top, 0)
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
place();
|
|
104
|
+
view.addEventListener("resize", place);
|
|
105
|
+
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(place);
|
|
106
|
+
observer?.observe(area);
|
|
107
|
+
for (const chrome of pinned.chrome) observer?.observe(chrome);
|
|
108
|
+
return () => {
|
|
109
|
+
view.removeEventListener("resize", place);
|
|
110
|
+
observer?.disconnect();
|
|
111
|
+
};
|
|
112
|
+
}, []);
|
|
113
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
|
|
114
|
+
ref: anchor,
|
|
115
|
+
hidden: true
|
|
116
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
117
|
+
"data-loader-area": "",
|
|
118
|
+
className: "pointer-events-none fixed inset-0 flex items-center justify-center",
|
|
119
|
+
style: box ?? void 0,
|
|
120
|
+
children
|
|
121
|
+
})] });
|
|
122
|
+
}
|
|
71
123
|
//#endregion
|
|
72
124
|
export { Loader };
|
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
import 'katex/dist/katex.min.css';
|
|
2
2
|
import type { MarkdownProps } from './Markdown.js';
|
|
3
|
+
/** While a reply streams, a table's opening rows read as stray pipes until its
|
|
4
|
+
* delimiter row arrives; they are held back until then. */
|
|
5
|
+
export declare function withoutUnfinishedTable(text: string): string;
|
|
3
6
|
export default function MarkdownImpl({ children, isStreaming, controls, components, httpsImagesOnly, compact, }: MarkdownProps): import("react").JSX.Element;
|
|
@@ -112,6 +112,20 @@ function makeCode(controls, diagrams) {
|
|
|
112
112
|
});
|
|
113
113
|
};
|
|
114
114
|
}
|
|
115
|
+
var TABLE_ROW = /^\s*\|/;
|
|
116
|
+
var TABLE_DELIMITER = /^\s*\|?\s*:?-{3,}:?\s*(\|\s*:?-{3,}:?\s*)*\|?\s*$/;
|
|
117
|
+
/** While a reply streams, a table's opening rows read as stray pipes until its
|
|
118
|
+
* delimiter row arrives; they are held back until then. */
|
|
119
|
+
function withoutUnfinishedTable(text) {
|
|
120
|
+
if ((text.match(/^\s*(```|~~~)/gm)?.length ?? 0) % 2 === 1) return text;
|
|
121
|
+
const lines = text.split("\n");
|
|
122
|
+
let start = lines.length;
|
|
123
|
+
while (start > 0 && TABLE_ROW.test(lines[start - 1] ?? "")) start--;
|
|
124
|
+
if (start === lines.length) return text;
|
|
125
|
+
const rows = lines.slice(start);
|
|
126
|
+
if (rows.length >= 2 && TABLE_DELIMITER.test(rows[1] ?? "")) return text;
|
|
127
|
+
return lines.slice(0, start).join("\n");
|
|
128
|
+
}
|
|
115
129
|
function MarkdownImpl({ children, isStreaming, controls, components, httpsImagesOnly, compact }) {
|
|
116
130
|
const needsMermaid = !!children && children.includes("```mermaid");
|
|
117
131
|
const [, setMermaidReady] = useState(() => !!pluginsWithMermaid);
|
|
@@ -158,9 +172,9 @@ function MarkdownImpl({ children, isStreaming, controls, components, httpsImages
|
|
|
158
172
|
}),
|
|
159
173
|
...components
|
|
160
174
|
},
|
|
161
|
-
children: children || ""
|
|
175
|
+
children: (isStreaming ? withoutUnfinishedTable(children || "") : children) || ""
|
|
162
176
|
})
|
|
163
177
|
});
|
|
164
178
|
}
|
|
165
179
|
//#endregion
|
|
166
|
-
export { MarkdownImpl as default };
|
|
180
|
+
export { MarkdownImpl as default, withoutUnfinishedTable };
|
|
@@ -14,8 +14,9 @@ export interface RefreshButtonProps {
|
|
|
14
14
|
/** A button's look, `ghost` by default; `inline` is text-sized muted text with no box, for
|
|
15
15
|
* a line of details such as a header's "Updated 2 minutes ago". */
|
|
16
16
|
variant?: ButtonVariant | 'inline' | undefined;
|
|
17
|
-
/** Only the icon shows, with "Refresh" as its name and tooltip.
|
|
18
|
-
|
|
17
|
+
/** Only the icon shows, with "Refresh" as its name and tooltip. `phone` shows the label on a
|
|
18
|
+
* wider screen and only the icon on a phone, the label still its name for a screen reader. */
|
|
19
|
+
iconOnly?: boolean | 'phone' | undefined;
|
|
19
20
|
className?: string | undefined;
|
|
20
21
|
}
|
|
21
22
|
/** Fetches again on demand, and says so while it does, out loud too. */
|
|
@@ -7,6 +7,12 @@ import { useRelativeTime } from "./relativeTime.js";
|
|
|
7
7
|
import { useState } from "react";
|
|
8
8
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
//#region src/components/RefreshButton.tsx
|
|
10
|
+
var phoneSquares = {
|
|
11
|
+
xs: "max-sm:w-6 max-sm:px-0",
|
|
12
|
+
sm: "max-sm:w-7 max-sm:px-0",
|
|
13
|
+
md: "max-sm:w-8 max-sm:px-0",
|
|
14
|
+
lg: "max-sm:w-10 max-sm:px-0"
|
|
15
|
+
};
|
|
10
16
|
var inlineClasses = "inline-flex cursor-pointer items-center gap-1 rounded px-1 py-0.5 text-(--theme-muted-text-color) transition-colors hover:bg-(--theme-muted-panel-bg) hover:text-(--theme-app) focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-(--theme-focus) [&_svg]:size-3";
|
|
11
17
|
/** Fetches again on demand, and says so while it does, out loud too. */
|
|
12
18
|
function RefreshButton({ onRefresh, refreshing = false, updatedAt, size = "md", variant = "ghost", iconOnly = false, className }) {
|
|
@@ -14,6 +20,8 @@ function RefreshButton({ onRefresh, refreshing = false, updatedAt, size = "md",
|
|
|
14
20
|
const [pending, setPending] = useState(false);
|
|
15
21
|
const busy = refreshing || pending;
|
|
16
22
|
const ago = useRelativeTime(updatedAt);
|
|
23
|
+
const phone = iconOnly === "phone";
|
|
24
|
+
const square = iconOnly === true;
|
|
17
25
|
const refresh = () => {
|
|
18
26
|
if (busy) return;
|
|
19
27
|
const result = onRefresh();
|
|
@@ -27,27 +35,30 @@ function RefreshButton({ onRefresh, refreshing = false, updatedAt, size = "md",
|
|
|
27
35
|
type: "button",
|
|
28
36
|
onClick: refresh,
|
|
29
37
|
"aria-busy": busy,
|
|
30
|
-
"aria-label":
|
|
38
|
+
"aria-label": square ? t.refresh : void 0,
|
|
31
39
|
className: cx(variant === "inline" ? inlineClasses : buttonClasses({
|
|
32
40
|
variant,
|
|
33
41
|
size,
|
|
34
|
-
iconOnly
|
|
35
|
-
}), "group aria-busy:cursor-progress", className),
|
|
42
|
+
iconOnly: square
|
|
43
|
+
}), phone && variant !== "inline" && phoneSquares[size], "group aria-busy:cursor-progress", className),
|
|
36
44
|
children: [/* @__PURE__ */ jsx(RefreshIcon, {
|
|
37
45
|
"aria-hidden": "true",
|
|
38
46
|
className: cx("shrink-0 motion-reduce:animate-none motion-reduce:transition-none", busy ? "animate-spin" : "transition-transform duration-300 group-hover:rotate-180")
|
|
39
|
-
}), !
|
|
40
|
-
className: "sr-only",
|
|
41
|
-
children:
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
children:
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
}), !square && /* @__PURE__ */ jsx("span", {
|
|
48
|
+
className: phone ? "max-sm:sr-only" : void 0,
|
|
49
|
+
children: ago ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("span", {
|
|
50
|
+
className: "sr-only",
|
|
51
|
+
children: [t.refresh, ". "]
|
|
52
|
+
}), t.updated(ago)] }) : busy ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
|
|
53
|
+
className: "sr-only",
|
|
54
|
+
children: t.refresh
|
|
55
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
56
|
+
"aria-hidden": "true",
|
|
57
|
+
children: t.refreshing
|
|
58
|
+
})] }) : t.refresh
|
|
59
|
+
})]
|
|
49
60
|
});
|
|
50
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
61
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [square ? /* @__PURE__ */ jsx(Tooltip, {
|
|
51
62
|
content: t.refresh,
|
|
52
63
|
children: button
|
|
53
64
|
}) : button, /* @__PURE__ */ jsx("span", {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ComponentPropsWithRef } from 'react';
|
|
1
2
|
import type { RunStatus } from '../engine.js';
|
|
2
3
|
import { type Tone } from './tone.js';
|
|
3
4
|
/** A status the icon shows: a run's, or one a host maps onto it, such as
|
|
@@ -6,7 +7,9 @@ export type RunStatusIconStatus = RunStatus | 'pending' | 'warning';
|
|
|
6
7
|
/** The tone a run status reads in, so a badge that says the status in words matches the
|
|
7
8
|
* icon: `<StatusBadge variant={runStatusTone(status)}>`. */
|
|
8
9
|
export declare function runStatusTone(status: RunStatusIconStatus): Tone;
|
|
9
|
-
|
|
10
|
+
/** Any other span attribute and the ref reach the icon's element, so it can be a Tooltip's or a
|
|
11
|
+
* popover's direct child. */
|
|
12
|
+
export interface RunStatusIconProps extends Omit<ComponentPropsWithRef<'span'>, 'children' | 'className'> {
|
|
10
13
|
status: RunStatusIconStatus;
|
|
11
14
|
/** Names the icon in place of `strings.dag.statusLabel`, for a host's own status
|
|
12
15
|
* shown in a run's look, such as "Provisioning" as running. */
|
|
@@ -18,4 +21,4 @@ export interface RunStatusIconProps {
|
|
|
18
21
|
/** A run's, job's or step's status as an icon in its tone, beside the name of what ran. It
|
|
19
22
|
* is named by `label`, or else `strings.dag.statusLabel`. To say the status in words, use
|
|
20
23
|
* `StatusBadge` with `runStatusTone`. */
|
|
21
|
-
export declare function RunStatusIcon({ status, label: ownLabel, tooltip, className, }: RunStatusIconProps): import("react").JSX.Element;
|
|
24
|
+
export declare function RunStatusIcon({ status, label: ownLabel, tooltip, className, ...rest }: RunStatusIconProps): import("react").JSX.Element;
|
|
@@ -71,12 +71,13 @@ function runStatusTone(status) {
|
|
|
71
71
|
/** A run's, job's or step's status as an icon in its tone, beside the name of what ran. It
|
|
72
72
|
* is named by `label`, or else `strings.dag.statusLabel`. To say the status in words, use
|
|
73
73
|
* `StatusBadge` with `runStatusTone`. */
|
|
74
|
-
function RunStatusIcon({ status, label: ownLabel, tooltip = false, className }) {
|
|
74
|
+
function RunStatusIcon({ status, label: ownLabel, tooltip = false, className, ...rest }) {
|
|
75
75
|
const { dag } = useStrings();
|
|
76
76
|
const look = looks[status ?? ""];
|
|
77
77
|
const Icon = look.icon;
|
|
78
78
|
const label = ownLabel ?? dag.statusLabel(status ?? "");
|
|
79
79
|
const icon = /* @__PURE__ */ jsx("span", {
|
|
80
|
+
...rest,
|
|
80
81
|
...label ? {
|
|
81
82
|
role: "img",
|
|
82
83
|
"aria-label": label
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ReactElement, ReactNode } from 'react';
|
|
1
|
+
import type { ComponentPropsWithRef, ReactElement, ReactNode } from 'react';
|
|
2
2
|
import { type Tone } from './tone.js';
|
|
3
3
|
/** A badge's tone: a status, or the theme's accent for something set apart that
|
|
4
4
|
* isn't a status, such as "New". */
|
|
@@ -13,7 +13,9 @@ declare const sizeClasses: {
|
|
|
13
13
|
readonly md: 'gap-1.5 py-0.5 text-[11px] leading-4';
|
|
14
14
|
};
|
|
15
15
|
export type BadgeSize = keyof typeof sizeClasses;
|
|
16
|
-
|
|
16
|
+
/** Any other span attribute and the ref reach its element, so it can be a Tooltip's or a popover's
|
|
17
|
+
* direct child. */
|
|
18
|
+
export interface StatusBadgeProps extends Omit<ComponentPropsWithRef<'span'>, 'children' | 'className'> {
|
|
17
19
|
/** Badge content */
|
|
18
20
|
children: ReactNode;
|
|
19
21
|
/** Visual variant */
|
|
@@ -41,8 +43,10 @@ export interface StatusBadgeProps {
|
|
|
41
43
|
* dot rather than inside a badge. */
|
|
42
44
|
export declare function statusTextClass(variant: BadgeVariant): string;
|
|
43
45
|
/** A short status or label in a tone, such as "Running" or "Preview". */
|
|
44
|
-
export declare function StatusBadge({ children, variant, emphasis, shape, caps, truncate, pulse, dot, size, render, className, }: StatusBadgeProps): ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
45
|
-
|
|
46
|
+
export declare function StatusBadge({ children, variant, emphasis, shape, caps, truncate, pulse, dot, size, render, className, ref, ...rest }: StatusBadgeProps): ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
47
|
+
/** Any other span attribute and the ref reach its element, so it can be a Tooltip's or a popover's
|
|
48
|
+
* direct child. */
|
|
49
|
+
export interface CountBadgeProps extends Omit<ComponentPropsWithRef<'span'>, 'children' | 'className'> {
|
|
46
50
|
count: number;
|
|
47
51
|
/** Above it, the count reads as `max` and a plus, such as "99+". */
|
|
48
52
|
max?: number | undefined;
|
|
@@ -64,12 +68,14 @@ export interface CountBadgeProps {
|
|
|
64
68
|
}
|
|
65
69
|
/** A number beside a link or tab, such as unread messages or items waiting,
|
|
66
70
|
* capped at `max` so a big count doesn't widen what it sits in. */
|
|
67
|
-
export declare function CountBadge({ count, max, variant, emphasis, size, label, showZero, locale, className, }: CountBadgeProps): import("react").JSX.Element | null;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
export declare function CountBadge({ count, max, variant, emphasis, size, label, showZero, locale, className, ...rest }: CountBadgeProps): import("react").JSX.Element | null;
|
|
72
|
+
/** Any other span attribute and the ref reach its element, so it can be a Tooltip's or a popover's
|
|
73
|
+
* direct child. */
|
|
74
|
+
export interface StatusDotProps extends Omit<ComponentPropsWithRef<'span'>, 'children' | 'className'> {
|
|
75
|
+
variant?: BadgeVariant | undefined;
|
|
76
|
+
pulse?: boolean | undefined;
|
|
77
|
+
size?: number | undefined;
|
|
78
|
+
className?: string | undefined;
|
|
73
79
|
}
|
|
74
|
-
export declare function StatusDot({ variant, pulse, size, className, }: StatusDotProps): import("react").JSX.Element;
|
|
80
|
+
export declare function StatusDot({ variant, pulse, size, className, style, ...rest }: StatusDotProps): import("react").JSX.Element;
|
|
75
81
|
export {};
|
|
@@ -3,6 +3,7 @@ import { toneFill, toneSurface, toneText } from "./tone.js";
|
|
|
3
3
|
import { useStrings } from "./Provider.js";
|
|
4
4
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import { useRender } from "@base-ui/react/use-render";
|
|
6
|
+
import { mergeProps } from "@base-ui/react/merge-props";
|
|
6
7
|
//#region src/components/StatusBadge.tsx
|
|
7
8
|
var emphasisClasses = {
|
|
8
9
|
soft: {
|
|
@@ -56,11 +57,12 @@ function statusTextClass(variant) {
|
|
|
56
57
|
return variant === "accent" ? "text-(--theme-link)" : toneText[variant];
|
|
57
58
|
}
|
|
58
59
|
/** A short status or label in a tone, such as "Running" or "Preview". */
|
|
59
|
-
function StatusBadge({ children, variant = "default", emphasis = "soft", shape = "pill", caps = false, truncate = false, pulse = false, dot = false, size = "sm", render, className }) {
|
|
60
|
+
function StatusBadge({ children, variant = "default", emphasis = "soft", shape = "pill", caps = false, truncate = false, pulse = false, dot = false, size = "sm", render, className, ref, ...rest }) {
|
|
60
61
|
const indicator = emphasis === "solid" ? "bg-current" : dotFill[variant];
|
|
61
62
|
return useRender({
|
|
62
63
|
render: render ?? /* @__PURE__ */ jsx("span", {}),
|
|
63
|
-
|
|
64
|
+
ref,
|
|
65
|
+
props: mergeProps(rest, {
|
|
64
66
|
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),
|
|
65
67
|
children: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
66
68
|
pulse && /* @__PURE__ */ jsxs("span", {
|
|
@@ -73,7 +75,7 @@ function StatusBadge({ children, variant = "default", emphasis = "soft", shape =
|
|
|
73
75
|
children
|
|
74
76
|
}) : children
|
|
75
77
|
] })
|
|
76
|
-
}
|
|
78
|
+
})
|
|
77
79
|
});
|
|
78
80
|
}
|
|
79
81
|
var countSizeClasses = {
|
|
@@ -82,12 +84,13 @@ var countSizeClasses = {
|
|
|
82
84
|
};
|
|
83
85
|
/** A number beside a link or tab, such as unread messages or items waiting,
|
|
84
86
|
* capped at `max` so a big count doesn't widen what it sits in. */
|
|
85
|
-
function CountBadge({ count, max = 99, variant = "accent", emphasis = "solid", size = "md", label, showZero = false, locale, className }) {
|
|
87
|
+
function CountBadge({ count, max = 99, variant = "accent", emphasis = "solid", size = "md", label, showZero = false, locale, className, ...rest }) {
|
|
86
88
|
const { common } = useStrings();
|
|
87
89
|
if (count <= 0 && !showZero) return null;
|
|
88
90
|
const number = new Intl.NumberFormat(locale);
|
|
89
91
|
const text = count > max ? common.countOverflow(number.format(max)) : number.format(count);
|
|
90
92
|
return /* @__PURE__ */ jsxs("span", {
|
|
93
|
+
...rest,
|
|
91
94
|
"data-count": count,
|
|
92
95
|
className: cx("inline-flex shrink-0 items-center justify-center rounded-full font-semibold tabular-nums", countSizeClasses[size], emphasisClasses[emphasis][variant], className),
|
|
93
96
|
children: [text, label && /* @__PURE__ */ jsxs("span", {
|
|
@@ -96,10 +99,12 @@ function CountBadge({ count, max = 99, variant = "accent", emphasis = "solid", s
|
|
|
96
99
|
})]
|
|
97
100
|
});
|
|
98
101
|
}
|
|
99
|
-
function StatusDot({ variant = "default", pulse = false, size = 8, className }) {
|
|
102
|
+
function StatusDot({ variant = "default", pulse = false, size = 8, className, style, ...rest }) {
|
|
100
103
|
return /* @__PURE__ */ jsxs("span", {
|
|
104
|
+
...rest,
|
|
101
105
|
className: cx("relative inline-flex", className),
|
|
102
106
|
style: {
|
|
107
|
+
...style,
|
|
103
108
|
width: size,
|
|
104
109
|
height: size
|
|
105
110
|
},
|
|
@@ -5,11 +5,21 @@ export type SortDirection = 'ascending' | 'descending' | 'none';
|
|
|
5
5
|
* height, such as a key and value list or a dashboard card's runs; `dense`
|
|
6
6
|
* sets small type in tight rows, for a panel of figures. */
|
|
7
7
|
export type TableDensity = 'comfortable' | 'compact' | 'dense';
|
|
8
|
+
/** What a list row asks of the cell in a place, through whatever component of the host's renders
|
|
9
|
+
* it: its column's classes, content to show after its own, or that it shows stacked, under the
|
|
10
|
+
* first cell's, as a line in place of a cell. */
|
|
11
|
+
export interface CellPlacement {
|
|
12
|
+
className?: string | undefined;
|
|
13
|
+
after?: React.ReactNode;
|
|
14
|
+
stacked?: boolean | undefined;
|
|
15
|
+
}
|
|
16
|
+
/** Set by a list row around each of its cells; a `Table.Item` takes what it asks. */
|
|
17
|
+
export declare const CellPlacementContext: React.Context<CellPlacement | null>;
|
|
8
18
|
interface ItemProps extends React.TdHTMLAttributes<HTMLTableCellElement> {
|
|
9
19
|
/** Lets the text wrap; by default a cell keeps to one line. */
|
|
10
20
|
wrap?: boolean;
|
|
11
21
|
}
|
|
12
|
-
declare function Item({ wrap, children, className, ...tdProps }: ItemProps): React.JSX.Element;
|
|
22
|
+
declare function Item({ wrap, children, className, ...tdProps }: ItemProps): React.JSX.Element | null;
|
|
13
23
|
interface HeaderProps {
|
|
14
24
|
children?: React.ReactNode;
|
|
15
25
|
className?: string | undefined;
|
package/dist/components/Table.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { cx } from "../cx.js";
|
|
2
2
|
import { SortDownIcon, SortUnsortedIcon, SortUpIcon } from "../icons.js";
|
|
3
|
-
import { Loader } from "./Loader.js";
|
|
4
3
|
import { useStickyTop } from "./stickyTop.js";
|
|
4
|
+
import { Loader } from "./Loader.js";
|
|
5
5
|
import React, { createContext, useContext, useState } from "react";
|
|
6
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
//#region src/components/Table.tsx
|
|
@@ -23,12 +23,23 @@ var headerY = {
|
|
|
23
23
|
dense: "py-1"
|
|
24
24
|
};
|
|
25
25
|
var cellX = "px-3";
|
|
26
|
+
/** Set by a list row around each of its cells; a `Table.Item` takes what it asks. */
|
|
27
|
+
var CellPlacementContext = createContext(null);
|
|
26
28
|
function Item({ wrap = false, children, className, ...tdProps }) {
|
|
27
29
|
const density = useContext(DensityContext);
|
|
30
|
+
const placed = useContext(CellPlacementContext);
|
|
31
|
+
if (placed?.stacked) return React.Children.toArray(children).length > 0 ? /* @__PURE__ */ jsx("div", {
|
|
32
|
+
className: "mt-1 flex min-w-0 items-center @[36rem]:hidden",
|
|
33
|
+
"data-stacked": true,
|
|
34
|
+
children
|
|
35
|
+
}) : null;
|
|
28
36
|
return /* @__PURE__ */ jsx("td", {
|
|
29
37
|
...tdProps,
|
|
30
|
-
className: cx(cellX, cellY[density], wrap ? wrapY[density] : "whitespace-nowrap", className),
|
|
31
|
-
children
|
|
38
|
+
className: cx(cellX, cellY[density], wrap ? wrapY[density] : "whitespace-nowrap", className, placed?.className),
|
|
39
|
+
children: /* @__PURE__ */ jsxs(CellPlacementContext, {
|
|
40
|
+
value: null,
|
|
41
|
+
children: [children, placed?.after]
|
|
42
|
+
})
|
|
32
43
|
});
|
|
33
44
|
}
|
|
34
45
|
var sortIcons = {
|
|
@@ -107,4 +118,4 @@ function Table({ density = "comfortable", columns, caps = true, flush = false, c
|
|
|
107
118
|
Table.Header = Header;
|
|
108
119
|
Table.Item = Item;
|
|
109
120
|
//#endregion
|
|
110
|
-
export { Table };
|
|
121
|
+
export { CellPlacementContext, Table };
|
package/dist/components/Tabs.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { cx } from "../cx.js";
|
|
2
|
+
import { useStickyTop } from "./stickyTop.js";
|
|
2
3
|
import { Tooltip } from "./Tooltip.js";
|
|
3
4
|
import { AppLink } from "./AppLink.js";
|
|
4
5
|
import { SegmentContent, segmentClassName, segmentGroupClassName } from "./segmented.js";
|
|
5
|
-
import { useStickyTop } from "./stickyTop.js";
|
|
6
6
|
import { useState } from "react";
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
import { Tabs } from "@base-ui/react/tabs";
|
package/dist/components/Tag.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ReactNode } from 'react';
|
|
1
|
+
import { type ComponentPropsWithRef, type ReactNode } from 'react';
|
|
2
2
|
export interface TagStyle {
|
|
3
3
|
/** Monospace text, for a value read as code, such as a key=value label. */
|
|
4
4
|
mono?: boolean | undefined;
|
|
@@ -8,7 +8,9 @@ export interface TagStyle {
|
|
|
8
8
|
/** The one tag look: a pill with a hairline border and 11px text. Another component's chip,
|
|
9
9
|
* such as a picker's chosen value, uses it to look the same. */
|
|
10
10
|
export declare function tagClasses({ mono, caps }?: TagStyle): string;
|
|
11
|
-
|
|
11
|
+
/** Any other attribute and the ref reach the tag's element, its link with `href` and no `onRemove`,
|
|
12
|
+
* so it can be a Tooltip's or a popover's direct child. */
|
|
13
|
+
export interface TagProps extends TagStyle, Omit<ComponentPropsWithRef<'span'>, 'children' | 'className' | 'color' | 'title'> {
|
|
12
14
|
children: ReactNode;
|
|
13
15
|
/** A dot before the text in this color, any CSS color, such as a label's own. */
|
|
14
16
|
color?: string | undefined;
|
|
@@ -23,7 +25,7 @@ export interface TagProps extends TagStyle {
|
|
|
23
25
|
}
|
|
24
26
|
/** A tag or label on a thing: a pill with an optional color dot, a link with `href`, and an ×
|
|
25
27
|
* with `onRemove`. */
|
|
26
|
-
export declare function Tag({ children, color, href, onRemove, removeLabel, title, mono, caps, className, }: TagProps): import("react").JSX.Element;
|
|
28
|
+
export declare function Tag({ children, color, href, onRemove, removeLabel, title, mono, caps, className, ref, ...rest }: TagProps): import("react").JSX.Element;
|
|
27
29
|
/** One tag of a `TagList`: a string is its own key and label. */
|
|
28
30
|
export type TagItem = string | {
|
|
29
31
|
key: string;
|
package/dist/components/Tag.js
CHANGED
|
@@ -13,7 +13,7 @@ function tagClasses({ mono = false, caps = false } = {}) {
|
|
|
13
13
|
}
|
|
14
14
|
/** A tag or label on a thing: a pill with an optional color dot, a link with `href`, and an ×
|
|
15
15
|
* with `onRemove`. */
|
|
16
|
-
function Tag({ children, color, href, onRemove, removeLabel, title, mono, caps, className }) {
|
|
16
|
+
function Tag({ children, color, href, onRemove, removeLabel, title, mono, caps, className, ref, ...rest }) {
|
|
17
17
|
const { dropdown } = useStrings();
|
|
18
18
|
const content = /* @__PURE__ */ jsxs(Fragment$1, { children: [color && /* @__PURE__ */ jsx("span", {
|
|
19
19
|
"aria-hidden": "true",
|
|
@@ -29,17 +29,23 @@ function Tag({ children, color, href, onRemove, removeLabel, title, mono, caps,
|
|
|
29
29
|
}), className);
|
|
30
30
|
const hover = "transition-colors hover:bg-(--theme-hover)";
|
|
31
31
|
if (!onRemove) return href ? /* @__PURE__ */ jsx(AppLink, {
|
|
32
|
+
...rest,
|
|
33
|
+
ref,
|
|
32
34
|
href,
|
|
33
35
|
title,
|
|
34
36
|
className: cx(classes, hover, "no-underline"),
|
|
35
37
|
children: content
|
|
36
38
|
}) : /* @__PURE__ */ jsx("span", {
|
|
39
|
+
...rest,
|
|
40
|
+
ref,
|
|
37
41
|
title,
|
|
38
42
|
className: classes,
|
|
39
43
|
children: content
|
|
40
44
|
});
|
|
41
45
|
const name = removeLabel ?? dropdown.removeValue(typeof children === "string" ? children : "");
|
|
42
46
|
return /* @__PURE__ */ jsxs("span", {
|
|
47
|
+
...rest,
|
|
48
|
+
ref,
|
|
43
49
|
title,
|
|
44
50
|
className: cx(classes, "pr-0.5"),
|
|
45
51
|
children: [href ? /* @__PURE__ */ jsx(AppLink, {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ReactNode } from 'react';
|
|
1
|
+
import { type ComponentPropsWithRef, type ReactNode } from 'react';
|
|
2
2
|
import { type DateTimeStyle, type TimeValue } from '../format.js';
|
|
3
3
|
export type { TimeValue };
|
|
4
4
|
/** Something worked out from the time, kept current by one clock that ticks
|
|
@@ -15,7 +15,8 @@ export type RelativeTimeFormat = 'long' | 'compact';
|
|
|
15
15
|
/** How long ago, or until, `value` is, kept current as time passes. Empty for
|
|
16
16
|
* a missing or invalid time. */
|
|
17
17
|
export declare function useRelativeTime(value: TimeValue, format?: RelativeTimeFormat): string;
|
|
18
|
-
|
|
18
|
+
/** Any other attribute and the ref reach the `<time>`, so it can be a popover's direct child. */
|
|
19
|
+
export interface RelativeTimeProps extends Omit<ComponentPropsWithRef<'time'>, 'children' | 'className' | 'dateTime'> {
|
|
19
20
|
value: TimeValue;
|
|
20
21
|
format?: RelativeTimeFormat | undefined;
|
|
21
22
|
/** Shown in place of a missing or invalid time, such as "Never" or "—". Default nothing. */
|
|
@@ -31,17 +32,19 @@ export interface RelativeTimeProps {
|
|
|
31
32
|
/** A time shown relative to now ("5 minutes ago", or "5m" compact), counting
|
|
32
33
|
* on while it stays on screen, with the exact time on hover. Renders the
|
|
33
34
|
* `fallback`, or nothing, for a missing time. */
|
|
34
|
-
export declare function RelativeTime({ value, format, fallback, exact, show, className, }: RelativeTimeProps): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null;
|
|
35
|
+
export declare function RelativeTime({ value, format, fallback, exact, show, className, ...rest }: RelativeTimeProps): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null;
|
|
35
36
|
/** Milliseconds from `start` to `end`, or to now while `running`, in whole
|
|
36
37
|
* seconds so it changes at most once a second. Running defaults to having no
|
|
37
38
|
* end; pass false for something that stopped without recording when. Null
|
|
38
39
|
* without a start. */
|
|
39
40
|
export declare function useElapsed(start: TimeValue, end?: TimeValue, running?: boolean): number | null;
|
|
40
|
-
/**
|
|
41
|
-
|
|
42
|
-
export declare function Elapsed({ start, end, running, className, }: {
|
|
41
|
+
/** Any other attribute and the ref reach the `<time>`, so it can be a Tooltip's direct child. */
|
|
42
|
+
export interface ElapsedProps extends Omit<ComponentPropsWithRef<'time'>, 'children' | 'className' | 'dateTime'> {
|
|
43
43
|
start: TimeValue;
|
|
44
44
|
end?: TimeValue;
|
|
45
|
-
running?: boolean;
|
|
46
|
-
className?: string;
|
|
47
|
-
}
|
|
45
|
+
running?: boolean | undefined;
|
|
46
|
+
className?: string | undefined;
|
|
47
|
+
}
|
|
48
|
+
/** How long something took, or has taken so far while it runs: 45s, 2m 13s.
|
|
49
|
+
* Renders nothing without a start. */
|
|
50
|
+
export declare function Elapsed({ start, end, running, className, ...rest }: ElapsedProps): import("react").JSX.Element | null;
|
|
@@ -100,7 +100,7 @@ function useRelativeTime(value, format = "long") {
|
|
|
100
100
|
/** A time shown relative to now ("5 minutes ago", or "5m" compact), counting
|
|
101
101
|
* on while it stays on screen, with the exact time on hover. Renders the
|
|
102
102
|
* `fallback`, or nothing, for a missing time. */
|
|
103
|
-
function RelativeTime({ value, format = "long", fallback = null, exact = "seconds", show = "relative", className }) {
|
|
103
|
+
function RelativeTime({ value, format = "long", fallback = null, exact = "seconds", show = "relative", className, ...rest }) {
|
|
104
104
|
const label = useRelativeTime(value, format);
|
|
105
105
|
const locale = useLocale();
|
|
106
106
|
const time = toDateTime(value);
|
|
@@ -108,6 +108,7 @@ function RelativeTime({ value, format = "long", fallback = null, exact = "second
|
|
|
108
108
|
const absolute = formatDateTime(time, exact || "seconds", locale);
|
|
109
109
|
const [text, tip] = show === "absolute" ? [absolute, label] : [label, exact ? absolute : null];
|
|
110
110
|
const element = /* @__PURE__ */ jsx("time", {
|
|
111
|
+
...rest,
|
|
111
112
|
dateTime: time.toISO() ?? void 0,
|
|
112
113
|
className,
|
|
113
114
|
children: text
|
|
@@ -129,11 +130,12 @@ function useElapsed(start, end, running = toDateTime(end) === null) {
|
|
|
129
130
|
}
|
|
130
131
|
/** How long something took, or has taken so far while it runs: 45s, 2m 13s.
|
|
131
132
|
* Renders nothing without a start. */
|
|
132
|
-
function Elapsed({ start, end, running, className }) {
|
|
133
|
+
function Elapsed({ start, end, running, className, ...rest }) {
|
|
133
134
|
const elapsed = useElapsed(start, end, running);
|
|
134
135
|
const locale = useLocale();
|
|
135
136
|
if (elapsed === null) return null;
|
|
136
137
|
return /* @__PURE__ */ jsx("time", {
|
|
138
|
+
...rest,
|
|
137
139
|
dateTime: Duration.fromMillis(elapsed).toISO() ?? void 0,
|
|
138
140
|
className,
|
|
139
141
|
children: formatDuration(elapsed, locale)
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
/** Pins a bar to the top of its scroller, over what scrolls under it.
|
|
2
2
|
* `useStickyTop` moves it below whatever else is pinned there. */
|
|
3
3
|
export declare const stickyClasses = "sticky top-0 z-(--layer-sticky) bg-(--theme-app-bg)";
|
|
4
|
+
/** The box a sticky element sticks to: its nearest ancestor that scrolls, or
|
|
5
|
+
* the document's when none does. */
|
|
6
|
+
export declare function scrollContainer(el: Element): Element;
|
|
7
|
+
/** What a page pins at the top of `el`'s scroller over it, such as a page header and a toolbar:
|
|
8
|
+
* those elements, and how far below the scroller's top their bottom edge sits. */
|
|
9
|
+
export declare function pinnedAbove(el: Element): {
|
|
10
|
+
chrome: HTMLElement[];
|
|
11
|
+
bottom: number;
|
|
12
|
+
};
|
|
4
13
|
/**
|
|
5
14
|
* Pins a `sticky` element just below whatever its scroller already pins at
|
|
6
15
|
* the top, such as a page header, a toolbar and a tab row, rather than at
|
|
@@ -47,6 +47,15 @@ function pinnedBottom(chrome) {
|
|
|
47
47
|
const height = chrome.getBoundingClientRect().height;
|
|
48
48
|
return height > 0 ? (Number.parseFloat(getComputedStyle(chrome).top) || 0) + height : 0;
|
|
49
49
|
}
|
|
50
|
+
/** What a page pins at the top of `el`'s scroller over it, such as a page header and a toolbar:
|
|
51
|
+
* those elements, and how far below the scroller's top their bottom edge sits. */
|
|
52
|
+
function pinnedAbove(el) {
|
|
53
|
+
const { chrome } = chromeAbove(el, scrollContainer(el));
|
|
54
|
+
return {
|
|
55
|
+
chrome,
|
|
56
|
+
bottom: Math.max(0, ...chrome.map(pinnedBottom))
|
|
57
|
+
};
|
|
58
|
+
}
|
|
50
59
|
/**
|
|
51
60
|
* Pins a `sticky` element just below whatever its scroller already pins at
|
|
52
61
|
* the top, such as a page header, a toolbar and a tab row, rather than at
|
|
@@ -95,4 +104,4 @@ function useStickyTop(el, enabled) {
|
|
|
95
104
|
}, [el, enabled]);
|
|
96
105
|
}
|
|
97
106
|
//#endregion
|
|
98
|
-
export { stickyClasses, useStickyTop };
|
|
107
|
+
export { pinnedAbove, scrollContainer, stickyClasses, useStickyTop };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { cx } from "../cx.js";
|
|
2
2
|
import { ArrowLeftIcon, ArrowRightIcon, ChevronLeftIcon, ChevronRightIcon, CloseIcon, FileTextIcon, ZoomInIcon, ZoomOutIcon } from "../icons.js";
|
|
3
|
+
import { useStickyTop } from "../components/stickyTop.js";
|
|
3
4
|
import { Loader } from "../components/Loader.js";
|
|
4
5
|
import { useLocale, useRunFile, useSlots, useStrings, useWorkflowEngine } from "../components/Provider.js";
|
|
5
6
|
import { Button } from "../components/Button.js";
|
|
@@ -10,7 +11,6 @@ import { DisclosurePanel } from "../components/Disclosure.js";
|
|
|
10
11
|
import { formatDateTime } from "../format.js";
|
|
11
12
|
import { Elapsed } from "../components/relativeTime.js";
|
|
12
13
|
import { RunStatusIcon } from "../components/RunStatusIcon.js";
|
|
13
|
-
import { useStickyTop } from "../components/stickyTop.js";
|
|
14
14
|
import { Tabs } from "../components/Tabs.js";
|
|
15
15
|
import { LogViewer } from "../logviewer/LogViewer.js";
|
|
16
16
|
import { initializeValues } from "../form/lib.js";
|