@tangle-network/ui 11.32.2 → 11.34.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.
- package/CHANGELOG.md +23 -0
- package/dist/editor/document-editor-pane.d.ts +7 -1
- package/dist/editor/document-editor-pane.js +27 -12
- package/dist/editor/markdown-document-editor.js +30 -12
- package/dist/editor/source-markdown-editor.js +256 -0
- package/dist/editor/source-markdown.js +495 -0
- package/dist/files/file-artifact-pane.d.ts +2 -0
- package/dist/files/file-artifact-pane.js +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/lib/control-presentation.js +2 -1
- package/dist/lib/focus.d.ts +5 -1
- package/dist/lib/focus.js +6 -1
- package/dist/lib/interaction.d.ts +41 -0
- package/dist/lib/interaction.js +42 -0
- package/dist/markdown/markdown-table.js +1 -1
- package/dist/primitives/button.js +19 -18
- package/dist/primitives/card.d.ts +14 -1
- package/dist/primitives/card.js +15 -5
- package/dist/primitives/dropdown-menu.js +7 -6
- package/dist/primitives/segmented-control.d.ts +5 -1
- package/dist/primitives/segmented-control.js +12 -5
- package/dist/primitives/select.js +4 -3
- package/dist/primitives/tabs.js +4 -3
- package/dist/run/inline-thinking-item.d.ts +7 -1
- package/dist/run/inline-thinking-item.js +6 -5
- package/dist/utils/format.d.ts +6 -0
- package/dist/utils/format.js +9 -1
- package/dist/utils.d.ts +3 -2
- package/dist/utils.js +3 -2
- package/package.json +2 -2
- package/src/editor/document-editor-pane.tsx +54 -16
- package/src/editor/markdown-document-editor.tsx +33 -18
- package/src/editor/source-markdown-editor.test.tsx +156 -0
- package/src/editor/source-markdown-editor.ts +296 -0
- package/src/editor/source-markdown.fixtures.ts +90 -0
- package/src/editor/source-markdown.test.ts +235 -0
- package/src/editor/source-markdown.ts +627 -0
- package/src/files/file-artifact-pane.test.tsx +38 -3
- package/src/files/file-artifact-pane.tsx +3 -0
- package/src/lib/control-presentation.ts +10 -4
- package/src/lib/focus.ts +7 -1
- package/src/lib/interaction.ts +64 -0
- package/src/markdown/markdown-table.test.tsx +9 -0
- package/src/markdown/markdown-table.tsx +5 -1
- package/src/primitives/button.tsx +29 -10
- package/src/primitives/card.tsx +23 -6
- package/src/primitives/control-presentation.test.tsx +6 -3
- package/src/primitives/date-picker.test.tsx +1 -1
- package/src/primitives/dropdown-menu.tsx +15 -10
- package/src/primitives/interaction-states.test.tsx +285 -0
- package/src/primitives/segmented-control.test.tsx +4 -2
- package/src/primitives/segmented-control.tsx +13 -14
- package/src/primitives/select.tsx +11 -5
- package/src/primitives/tabs.tsx +7 -3
- package/src/run/inline-thinking-item.test.tsx +29 -0
- package/src/run/inline-thinking-item.tsx +11 -4
- package/src/utils/format.test.ts +16 -1
- package/src/utils/format.ts +17 -0
- package/src/utils/index.ts +10 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//#region src/lib/interaction.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The interaction states every control shares: one palette in five shapes, all
|
|
4
|
+
* read from `@tangle-network/brand`'s `--ix-*` tokens (tokens.css), which derive
|
|
5
|
+
* from the focus ring hue `--hsl-ring`. So hover, press, after-click and
|
|
6
|
+
* selected are the same green in Hospitality and the same indigo on the spine
|
|
7
|
+
* as the keyboard focus ring.
|
|
8
|
+
*
|
|
9
|
+
* hover 1px edge at .45 plus a 4px halo at .16 (`--ix-hover`)
|
|
10
|
+
* press 1px edge at .95 plus a 4px halo at .30 (`--ix-press`)
|
|
11
|
+
* after a control focused by a mouse click keeps a soft ring (`--ix-after`)
|
|
12
|
+
* selected a tint plus a 1px inset ring at .85 (`--ix-sel-bg`, `--ix-sel-ring`)
|
|
13
|
+
*
|
|
14
|
+
* The keyboard focus-visible glow stays exactly as `focusRing` / `focusField`
|
|
15
|
+
* (lib/focus.ts) draw it. Tailwind composes `--tw-ring-shadow` with
|
|
16
|
+
* `--tw-shadow`, so these shadows coexist with that ring, and
|
|
17
|
+
* `focus-visible:shadow-none` drops the hover glow while the keyboard ring shows.
|
|
18
|
+
*
|
|
19
|
+
* Every class is written out in full because Tailwind reads class names
|
|
20
|
+
* statically.
|
|
21
|
+
*/
|
|
22
|
+
/** Bordered or filled control: green edge on hover, deeper on press, a persistent soft ring after a mouse click. */
|
|
23
|
+
export declare const ixControl: string;
|
|
24
|
+
/** The after-click part of `ixControl` alone, for a field that opens a menu (SelectTrigger). */
|
|
25
|
+
export declare const ixControlAfter = "focus:not-focus-visible:border-[var(--ix-hover-border)] focus:not-focus-visible:shadow-[var(--ix-after)]";
|
|
26
|
+
/** Ghost, icon, link and bare controls: a wash, never a glow (too noisy in sidebars and toolbars). */
|
|
27
|
+
export declare const ixControlSoft = "hover:bg-[var(--ix-hover-bg)] active:bg-[var(--ix-sel-bg)]";
|
|
28
|
+
/**
|
|
29
|
+
* Field: its own well and a visible border; hover replaces `focusField`'s
|
|
30
|
+
* neutral `--border-strong`. The well is the `--well` context variable, which a
|
|
31
|
+
* card re-declares for its descendants, so a field never takes its parent's
|
|
32
|
+
* colour. `--field-surface` still lets a context such as Toolbar pick the fill.
|
|
33
|
+
*/
|
|
34
|
+
export declare const ixField: string;
|
|
35
|
+
/** Selected / on / current: tint plus a 1px inset green ring. */
|
|
36
|
+
export declare const ixSelected: string;
|
|
37
|
+
/** Underline tab: 2px green underline plus a faint tint, never a box; a faint underline on hover. */
|
|
38
|
+
export declare const ixTabUnderline: string;
|
|
39
|
+
/** List row / menu item: wash plus inset edge on hover or keyboard highlight; checked = selected. */
|
|
40
|
+
export declare const ixRow: string;
|
|
41
|
+
//#endregion
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//#region src/lib/interaction.ts
|
|
2
|
+
/**
|
|
3
|
+
* The interaction states every control shares: one palette in five shapes, all
|
|
4
|
+
* read from `@tangle-network/brand`'s `--ix-*` tokens (tokens.css), which derive
|
|
5
|
+
* from the focus ring hue `--hsl-ring`. So hover, press, after-click and
|
|
6
|
+
* selected are the same green in Hospitality and the same indigo on the spine
|
|
7
|
+
* as the keyboard focus ring.
|
|
8
|
+
*
|
|
9
|
+
* hover 1px edge at .45 plus a 4px halo at .16 (`--ix-hover`)
|
|
10
|
+
* press 1px edge at .95 plus a 4px halo at .30 (`--ix-press`)
|
|
11
|
+
* after a control focused by a mouse click keeps a soft ring (`--ix-after`)
|
|
12
|
+
* selected a tint plus a 1px inset ring at .85 (`--ix-sel-bg`, `--ix-sel-ring`)
|
|
13
|
+
*
|
|
14
|
+
* The keyboard focus-visible glow stays exactly as `focusRing` / `focusField`
|
|
15
|
+
* (lib/focus.ts) draw it. Tailwind composes `--tw-ring-shadow` with
|
|
16
|
+
* `--tw-shadow`, so these shadows coexist with that ring, and
|
|
17
|
+
* `focus-visible:shadow-none` drops the hover glow while the keyboard ring shows.
|
|
18
|
+
*
|
|
19
|
+
* Every class is written out in full because Tailwind reads class names
|
|
20
|
+
* statically.
|
|
21
|
+
*/
|
|
22
|
+
/** Bordered or filled control: green edge on hover, deeper on press, a persistent soft ring after a mouse click. */
|
|
23
|
+
const ixControl = "hover:border-[var(--ix-hover-border)] hover:shadow-[var(--ix-hover)] focus:not-focus-visible:border-[var(--ix-hover-border)] focus:not-focus-visible:shadow-[var(--ix-after)] active:border-[hsl(var(--hsl-ring))] active:shadow-[var(--ix-press)] focus-visible:shadow-none";
|
|
24
|
+
/** The after-click part of `ixControl` alone, for a field that opens a menu (SelectTrigger). */
|
|
25
|
+
const ixControlAfter = "focus:not-focus-visible:border-[var(--ix-hover-border)] focus:not-focus-visible:shadow-[var(--ix-after)]";
|
|
26
|
+
/** Ghost, icon, link and bare controls: a wash, never a glow (too noisy in sidebars and toolbars). */
|
|
27
|
+
const ixControlSoft = "hover:bg-[var(--ix-hover-bg)] active:bg-[var(--ix-sel-bg)]";
|
|
28
|
+
/**
|
|
29
|
+
* Field: its own well and a visible border; hover replaces `focusField`'s
|
|
30
|
+
* neutral `--border-strong`. The well is the `--well` context variable, which a
|
|
31
|
+
* card re-declares for its descendants, so a field never takes its parent's
|
|
32
|
+
* colour. `--field-surface` still lets a context such as Toolbar pick the fill.
|
|
33
|
+
*/
|
|
34
|
+
const ixField = "bg-[var(--field-surface,var(--well))] border-[var(--field-border)] shadow-[var(--shadow-well)] hover:border-[var(--ix-hover-border)] hover:shadow-[var(--shadow-well),var(--ix-hover)]";
|
|
35
|
+
/** Selected / on / current: tint plus a 1px inset green ring. */
|
|
36
|
+
const ixSelected = "aria-pressed:bg-[var(--ix-sel-bg)] aria-pressed:text-[var(--accent-text)] aria-pressed:shadow-[inset_0_0_0_1px_var(--ix-sel-ring)] aria-checked:bg-[var(--ix-sel-bg)] aria-checked:text-[var(--accent-text)] aria-checked:shadow-[inset_0_0_0_1px_var(--ix-sel-ring)] aria-[current=page]:bg-[var(--ix-sel-bg)] aria-[current=page]:text-[var(--accent-text)] aria-[current=page]:shadow-[inset_0_0_0_1px_var(--ix-sel-ring)] data-[state=on]:bg-[var(--ix-sel-bg)] data-[state=on]:shadow-[inset_0_0_0_1px_var(--ix-sel-ring)] data-[state=active]:bg-[var(--ix-sel-bg)] data-[state=active]:text-[var(--accent-text)] data-[state=active]:shadow-[inset_0_0_0_1px_var(--ix-sel-ring)]";
|
|
37
|
+
/** Underline tab: 2px green underline plus a faint tint, never a box; a faint underline on hover. */
|
|
38
|
+
const ixTabUnderline = "hover:shadow-[inset_0_-2px_0_hsl(var(--hsl-ring)/0.4)] data-[state=active]:bg-[hsl(var(--hsl-ring)/0.07)] data-[state=active]:text-[var(--accent-text)] data-[state=active]:shadow-[inset_0_-2px_0_var(--ix-sel-ring)] aria-checked:bg-[hsl(var(--hsl-ring)/0.07)] aria-checked:text-[var(--accent-text)] aria-checked:shadow-[inset_0_-2px_0_var(--ix-sel-ring)]";
|
|
39
|
+
/** List row / menu item: wash plus inset edge on hover or keyboard highlight; checked = selected. */
|
|
40
|
+
const ixRow = "hover:bg-[var(--ix-hover-bg)] hover:shadow-[inset_0_0_0_1px_var(--ix-hover-border)] data-[highlighted]:bg-[var(--ix-sel-bg)] data-[highlighted]:shadow-[inset_0_0_0_1px_var(--ix-hover-border)] focus:bg-[var(--ix-sel-bg)] data-[state=checked]:bg-[var(--ix-sel-bg)] data-[state=checked]:shadow-[inset_0_0_0_1px_var(--ix-sel-ring)] active:shadow-[inset_0_0_0_1px_hsl(var(--hsl-ring))]";
|
|
41
|
+
//#endregion
|
|
42
|
+
export { ixControl, ixControlAfter, ixControlSoft, ixField, ixRow, ixSelected, ixTabUnderline };
|
|
@@ -113,7 +113,7 @@ function MarkdownTable({ node, className, children, ...props }) {
|
|
|
113
113
|
};
|
|
114
114
|
}, [node]);
|
|
115
115
|
return /* @__PURE__ */ jsxs("div", {
|
|
116
|
-
className: "not-prose my-4 overflow-hidden rounded-lg border border-border bg-card",
|
|
116
|
+
className: "not-prose relative my-4 overflow-hidden rounded-lg border border-border bg-card",
|
|
117
117
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
118
118
|
className: "flex items-center justify-between gap-2 border-b border-border px-3 py-1",
|
|
119
119
|
children: [/* @__PURE__ */ jsx("span", {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ixControl, ixControlSoft, ixSelected } from "../lib/interaction.js";
|
|
1
2
|
import { focusRing } from "../lib/focus.js";
|
|
2
3
|
import { cn } from "../lib/utils.js";
|
|
3
4
|
import { controlHeight, controlMotion, controlRadius, controlSizes, controlSquare, controlText } from "../lib/control-presentation.js";
|
|
@@ -9,13 +10,13 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
9
10
|
const buttonVariants = cva(`inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg font-medium transition-[color,background-color,border-color,box-shadow,transform,scale] ${controlMotion} ${focusRing} disabled:pointer-events-none disabled:opacity-50 aria-disabled:cursor-not-allowed aria-disabled:opacity-50 motion-reduce:active:scale-100 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0`, {
|
|
10
11
|
variants: {
|
|
11
12
|
variant: {
|
|
12
|
-
default:
|
|
13
|
-
destructive:
|
|
14
|
-
outline:
|
|
15
|
-
secondary:
|
|
16
|
-
ghost:
|
|
17
|
-
link:
|
|
18
|
-
sandbox:
|
|
13
|
+
default: `bg-primary text-primary-foreground hover:bg-primary/90 active:scale-[0.97] ${ixControl}`,
|
|
14
|
+
destructive: `bg-destructive text-destructive-foreground hover:bg-destructive/90 active:scale-[0.97] ${ixControl}`,
|
|
15
|
+
outline: `border border-border bg-card hover:bg-muted active:scale-[0.97] text-foreground ${ixControl}`,
|
|
16
|
+
secondary: `bg-muted border border-border text-foreground hover:bg-muted/80 active:scale-[0.97] ${ixControl}`,
|
|
17
|
+
ghost: `hover:text-foreground text-muted-foreground border border-transparent ${ixControlSoft}`,
|
|
18
|
+
link: `text-[var(--accent-text)] underline-offset-4 hover:underline ${ixControlSoft}`,
|
|
19
|
+
sandbox: `bg-[var(--btn-primary-bg)] text-[var(--btn-primary-text)] border border-[var(--border-accent)] hover:bg-[var(--btn-primary-hover)] active:scale-[0.97] ${ixControl}`
|
|
19
20
|
},
|
|
20
21
|
size: {
|
|
21
22
|
default: `${controlHeight.md} ${controlText.md} ${controlRadius.md} px-4 py-2`,
|
|
@@ -34,7 +35,15 @@ const buttonVariants = cva(`inline-flex items-center justify-center gap-2 whites
|
|
|
34
35
|
size: "default"
|
|
35
36
|
}
|
|
36
37
|
});
|
|
37
|
-
const bareButton = `${focusRing} disabled:pointer-events-none disabled:opacity-50 aria-disabled:cursor-not-allowed aria-disabled:opacity-50`;
|
|
38
|
+
const bareButton = `${focusRing} ${ixControlSoft} disabled:pointer-events-none disabled:opacity-50 aria-disabled:cursor-not-allowed aria-disabled:opacity-50`;
|
|
39
|
+
/** One Button render's classes: variant and size, the toggle states, then the caller's. */
|
|
40
|
+
function buttonClassName(variant, size, pressed, className) {
|
|
41
|
+
const toggle = pressed === void 0 ? void 0 : `${ixControl} ${ixSelected}`;
|
|
42
|
+
return variant === "bare" ? cn(bareButton, toggle, className) : cn(buttonVariants({
|
|
43
|
+
variant,
|
|
44
|
+
size
|
|
45
|
+
}), toggle, className);
|
|
46
|
+
}
|
|
38
47
|
function preventActivation(event) {
|
|
39
48
|
event.preventDefault();
|
|
40
49
|
event.stopPropagation();
|
|
@@ -61,11 +70,7 @@ const Button = React.forwardRef(({ className, variant, size, asChild = false, lo
|
|
|
61
70
|
const child = React.isValidElement(children) ? children : null;
|
|
62
71
|
const isDisabled = disabled || loading || child?.props.disabled;
|
|
63
72
|
return /* @__PURE__ */ jsx(Slot, {
|
|
64
|
-
className: variant
|
|
65
|
-
variant,
|
|
66
|
-
size,
|
|
67
|
-
className
|
|
68
|
-
})),
|
|
73
|
+
className: buttonClassName(variant, size, props["aria-pressed"], className),
|
|
69
74
|
ref,
|
|
70
75
|
...props,
|
|
71
76
|
...isDisabled ? disabledHandlers(props) : {},
|
|
@@ -84,11 +89,7 @@ const Button = React.forwardRef(({ className, variant, size, asChild = false, lo
|
|
|
84
89
|
});
|
|
85
90
|
}
|
|
86
91
|
return /* @__PURE__ */ jsxs("button", {
|
|
87
|
-
className: variant
|
|
88
|
-
variant,
|
|
89
|
-
size,
|
|
90
|
-
className
|
|
91
|
-
})),
|
|
92
|
+
className: buttonClassName(variant, size, props["aria-pressed"], className),
|
|
92
93
|
ref,
|
|
93
94
|
...props,
|
|
94
95
|
disabled: disabled || loading,
|
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
//#region src/primitives/card.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* A card is one level of the brand surface ladder. It carries
|
|
5
|
+
* `data-slot="card"`, and the brand's surface-context rule (tokens.css)
|
|
6
|
+
* re-declares `--card` and `--well` for everything inside it: a Card or a
|
|
7
|
+
* `bg-card` box inside a card paints the raised level, one inside that the
|
|
8
|
+
* raised-2 level, and a field in any of them takes the well that is the
|
|
9
|
+
* opposite step from its parent. Nesting needs no prop and no app selector.
|
|
10
|
+
*/
|
|
3
11
|
declare const Card: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
|
|
4
12
|
variant?: "default" | "glass" | "sandbox" | "elevated";
|
|
5
|
-
/** Decorative
|
|
13
|
+
/** Decorative hover feedback only (the shared green edge). Put actions in a native button or link. */
|
|
6
14
|
hover?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* The card is itself the control, such as a card wrapped in a link: it takes
|
|
17
|
+
* the full control states (hover glow, press, the ring after a click).
|
|
18
|
+
*/
|
|
19
|
+
interactive?: boolean;
|
|
7
20
|
} & React.RefAttributes<HTMLDivElement>>;
|
|
8
21
|
declare const CardHeader: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
|
|
9
22
|
export interface CardTitleProps extends React.HTMLAttributes<HTMLHeadingElement> {
|
package/dist/primitives/card.js
CHANGED
|
@@ -1,17 +1,27 @@
|
|
|
1
|
+
import "../lib/interaction.js";
|
|
1
2
|
import { cn } from "../lib/utils.js";
|
|
2
3
|
import { Heading } from "./heading.js";
|
|
3
4
|
import * as React from "react";
|
|
4
5
|
import { jsx } from "react/jsx-runtime";
|
|
5
6
|
//#region src/primitives/card.tsx
|
|
6
|
-
|
|
7
|
+
/**
|
|
8
|
+
* A card is one level of the brand surface ladder. It carries
|
|
9
|
+
* `data-slot="card"`, and the brand's surface-context rule (tokens.css)
|
|
10
|
+
* re-declares `--card` and `--well` for everything inside it: a Card or a
|
|
11
|
+
* `bg-card` box inside a card paints the raised level, one inside that the
|
|
12
|
+
* raised-2 level, and a field in any of them takes the well that is the
|
|
13
|
+
* opposite step from its parent. Nesting needs no prop and no app selector.
|
|
14
|
+
*/
|
|
15
|
+
const Card = React.forwardRef(({ className, variant = "default", hover = false, interactive = false, ...props }, ref) => {
|
|
7
16
|
return /* @__PURE__ */ jsx("div", {
|
|
8
17
|
ref,
|
|
9
|
-
className: cn("rounded-[var(--radius-lg)] border text-card-foreground transition-[border-color,box-shadow]", "duration-[var(--transition-default)]", {
|
|
10
|
-
default: "bg-card border-border",
|
|
18
|
+
className: cn("rounded-[var(--radius-lg)] border text-card-foreground transition-[border-color,box-shadow,background-color]", "duration-[var(--transition-default)]", {
|
|
19
|
+
default: "bg-card border-border shadow-[var(--edge-highlight),var(--shadow-card)]",
|
|
11
20
|
elevated: "bg-muted/50 border-border shadow-[var(--shadow-card)]",
|
|
12
21
|
glass: "bg-card/80 backdrop-blur-xl border-border shadow-[var(--shadow-card)]",
|
|
13
22
|
sandbox: "bg-muted/50 border-primary/20 shadow-[var(--shadow-accent)]"
|
|
14
|
-
}[variant], hover && "hover:border-[var(--border-
|
|
23
|
+
}[variant], (hover || interactive) && "hover:border-[var(--ix-hover-border)] hover:shadow-[var(--ix-hover)] focus:not-focus-visible:border-[var(--ix-hover-border)] focus:not-focus-visible:shadow-[var(--ix-after)] active:border-[hsl(var(--hsl-ring))] active:shadow-[var(--ix-press)] focus-visible:shadow-none", className),
|
|
24
|
+
"data-slot": "card",
|
|
15
25
|
...props
|
|
16
26
|
});
|
|
17
27
|
});
|
|
@@ -32,7 +42,7 @@ const CardTitle = React.forwardRef(({ className, as = "h3", ...props }, ref) =>
|
|
|
32
42
|
CardTitle.displayName = "CardTitle";
|
|
33
43
|
const CardDescription = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("p", {
|
|
34
44
|
ref,
|
|
35
|
-
className: cn("text-muted-foreground text-sm", className),
|
|
45
|
+
className: cn("text-muted-foreground text-sm line-clamp-2", className),
|
|
36
46
|
...props
|
|
37
47
|
}));
|
|
38
48
|
CardDescription.displayName = "CardDescription";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ixRow } from "../lib/interaction.js";
|
|
1
2
|
import { cn } from "../lib/utils.js";
|
|
2
3
|
import * as React from "react";
|
|
3
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -12,33 +13,33 @@ const DropdownMenuSub = DropdownMenuPrimitive.Sub;
|
|
|
12
13
|
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
|
|
13
14
|
const DropdownMenuSubTrigger = React.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxs(DropdownMenuPrimitive.SubTrigger, {
|
|
14
15
|
ref,
|
|
15
|
-
className: cn("flex cursor-default select-none items-center rounded-md px-2 py-1.5 text-sm outline-none", "
|
|
16
|
+
className: cn("flex cursor-default select-none items-center rounded-md px-2 py-1.5 text-sm outline-none transition-[color,background-color,box-shadow]", "data-[state=open]:bg-[var(--ix-sel-bg)]", ixRow, inset && "pl-8", className),
|
|
16
17
|
...props,
|
|
17
18
|
children: [children, /* @__PURE__ */ jsx(ChevronRight, { className: "ml-auto h-4 w-4" })]
|
|
18
19
|
}));
|
|
19
20
|
DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
|
|
20
21
|
const DropdownMenuSubContent = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(DropdownMenuPrimitive.SubContent, {
|
|
21
22
|
ref,
|
|
22
|
-
className: cn("z-50 min-w-[8rem] overflow-hidden rounded-xl border border-border bg-
|
|
23
|
+
className: cn("z-50 min-w-[8rem] overflow-hidden rounded-xl border border-border bg-popover p-1 text-popover-foreground shadow-[var(--edge-highlight),var(--shadow-card)]", "data-[state=closed]:animate-out data-[state=open]:animate-in", "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95", "data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2", "data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className),
|
|
23
24
|
...props
|
|
24
25
|
}));
|
|
25
26
|
DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
|
|
26
27
|
const DropdownMenuContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx(DropdownMenuPrimitive.Content, {
|
|
27
28
|
ref,
|
|
28
29
|
sideOffset,
|
|
29
|
-
className: cn("z-50 min-w-[8rem] overflow-hidden rounded-xl border border-border bg-
|
|
30
|
+
className: cn("z-50 min-w-[8rem] overflow-hidden rounded-xl border border-border bg-popover p-1 text-popover-foreground shadow-[var(--edge-highlight),var(--shadow-card)]", "data-[state=closed]:animate-out data-[state=open]:animate-in", "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95", "data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2", "data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className),
|
|
30
31
|
...props
|
|
31
32
|
}) }));
|
|
32
33
|
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
|
|
33
34
|
const DropdownMenuItem = React.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx(DropdownMenuPrimitive.Item, {
|
|
34
35
|
ref,
|
|
35
|
-
className: cn("relative flex cursor-pointer select-none items-center rounded-md px-2 py-1.5 text-sm outline-none transition-
|
|
36
|
+
className: cn("relative flex cursor-pointer select-none items-center rounded-md px-2 py-1.5 text-sm outline-none transition-[color,background-color,box-shadow]", "focus:text-foreground", ixRow, "data-[disabled]:pointer-events-none data-[disabled]:opacity-50", inset && "pl-8", className),
|
|
36
37
|
...props
|
|
37
38
|
}));
|
|
38
39
|
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
|
|
39
40
|
const DropdownMenuCheckboxItem = React.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxs(DropdownMenuPrimitive.CheckboxItem, {
|
|
40
41
|
ref,
|
|
41
|
-
className: cn("relative flex cursor-pointer select-none items-center rounded-md py-1.5 pr-2 pl-8 text-sm outline-none transition-
|
|
42
|
+
className: cn("relative flex cursor-pointer select-none items-center rounded-md py-1.5 pr-2 pl-8 text-sm outline-none transition-[color,background-color,box-shadow]", "focus:text-foreground", ixRow, "data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className),
|
|
42
43
|
checked,
|
|
43
44
|
...props,
|
|
44
45
|
children: [/* @__PURE__ */ jsx("span", {
|
|
@@ -49,7 +50,7 @@ const DropdownMenuCheckboxItem = React.forwardRef(({ className, children, checke
|
|
|
49
50
|
DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
|
|
50
51
|
const DropdownMenuRadioItem = React.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(DropdownMenuPrimitive.RadioItem, {
|
|
51
52
|
ref,
|
|
52
|
-
className: cn("relative flex cursor-pointer select-none items-center rounded-md py-1.5 pr-2 pl-8 text-sm outline-none transition-
|
|
53
|
+
className: cn("relative flex cursor-pointer select-none items-center rounded-md py-1.5 pr-2 pl-8 text-sm outline-none transition-[color,background-color,box-shadow]", "focus:text-foreground", ixRow, "data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className),
|
|
53
54
|
...props,
|
|
54
55
|
children: [/* @__PURE__ */ jsx("span", {
|
|
55
56
|
className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center",
|
|
@@ -12,7 +12,11 @@ import * as React from "react";
|
|
|
12
12
|
* console warning fires when both are omitted.
|
|
13
13
|
*
|
|
14
14
|
* Design rules baked into the default variant:
|
|
15
|
-
* -
|
|
15
|
+
* - The row track is a field well (`--well`, `--field-border`), so the
|
|
16
|
+
* control reads as one inset group on whatever plane it sits on.
|
|
17
|
+
* - Only the SELECTED segment shows a surface colour + accent text: the
|
|
18
|
+
* shared selected state (`ixSelected`: tint plus an inset ring). A tab
|
|
19
|
+
* shows it as an underline instead (`ixTabUnderline`).
|
|
16
20
|
* - Unselected segments have NO background — they're plain-text labels
|
|
17
21
|
* that darken on hover. This keeps the selected segment as the
|
|
18
22
|
* single visual anchor instead of the whole group competing with
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import "../lib/interaction.js";
|
|
2
3
|
import { focusRing, focusRingInset } from "../lib/focus.js";
|
|
3
4
|
import { cn } from "../lib/utils.js";
|
|
4
5
|
import "../lib/control-presentation.js";
|
|
@@ -83,7 +84,7 @@ function SegmentedControl({ value, onValueChange, options, variant = "row", clas
|
|
|
83
84
|
ref: stripRef,
|
|
84
85
|
onKeyDown: handleKeyDown,
|
|
85
86
|
onScroll: tabs ? measureOverflow : void 0,
|
|
86
|
-
className: cn("flex gap-1", variant === "row" && "flex-wrap items-center rounded-lg border border-border bg-
|
|
87
|
+
className: cn("flex gap-1", variant === "row" && "flex-wrap items-center rounded-lg border border-[var(--field-border)] bg-[var(--well)] p-1", variant === "tabs" && ["relative flex-nowrap items-end border-b border-border pb-0 overflow-x-auto", tabEdgeFade], className),
|
|
87
88
|
children: options.map((option, i) => {
|
|
88
89
|
const active = option.value === value;
|
|
89
90
|
const focusable = active || !hasMatch && i === 0;
|
|
@@ -100,11 +101,17 @@ function SegmentedControl({ value, onValueChange, options, variant = "row", clas
|
|
|
100
101
|
onClick: () => {
|
|
101
102
|
if (!active) onValueChange(option.value);
|
|
102
103
|
},
|
|
103
|
-
className: cn("relative inline-flex items-center gap-2 whitespace-nowrap text-sm font-medium transition-[color,background-color,border-color,box-shadow]", variant === "row" && [
|
|
104
|
-
"
|
|
104
|
+
className: cn("relative inline-flex items-center gap-2 whitespace-nowrap text-sm font-medium transition-[color,background-color,border-color,box-shadow]", variant === "row" && [
|
|
105
|
+
"rounded-md border border-transparent px-3 py-1.5",
|
|
106
|
+
focusRing,
|
|
107
|
+
"hover:bg-[var(--ix-hover-bg)] active:bg-[var(--ix-sel-bg)]",
|
|
108
|
+
"aria-pressed:bg-[var(--ix-sel-bg)] aria-pressed:text-[var(--accent-text)] aria-pressed:shadow-[inset_0_0_0_1px_var(--ix-sel-ring)] aria-checked:bg-[var(--ix-sel-bg)] aria-checked:text-[var(--accent-text)] aria-checked:shadow-[inset_0_0_0_1px_var(--ix-sel-ring)] aria-[current=page]:bg-[var(--ix-sel-bg)] aria-[current=page]:text-[var(--accent-text)] aria-[current=page]:shadow-[inset_0_0_0_1px_var(--ix-sel-ring)] data-[state=on]:bg-[var(--ix-sel-bg)] data-[state=on]:shadow-[inset_0_0_0_1px_var(--ix-sel-ring)] data-[state=active]:bg-[var(--ix-sel-bg)] data-[state=active]:text-[var(--accent-text)] data-[state=active]:shadow-[inset_0_0_0_1px_var(--ix-sel-ring)]"
|
|
109
|
+
], variant === "tabs" && [
|
|
110
|
+
"shrink-0 rounded-none border-b-2 border-transparent -mb-px px-4 py-2",
|
|
105
111
|
"pointer-coarse:min-h-11",
|
|
106
|
-
focusRingInset
|
|
107
|
-
|
|
112
|
+
focusRingInset,
|
|
113
|
+
"hover:shadow-[inset_0_-2px_0_hsl(var(--hsl-ring)/0.4)] data-[state=active]:bg-[hsl(var(--hsl-ring)/0.07)] data-[state=active]:text-[var(--accent-text)] data-[state=active]:shadow-[inset_0_-2px_0_var(--ix-sel-ring)] aria-checked:bg-[hsl(var(--hsl-ring)/0.07)] aria-checked:text-[var(--accent-text)] aria-checked:shadow-[inset_0_-2px_0_var(--ix-sel-ring)]"
|
|
114
|
+
], active ? "text-[var(--accent-text)]" : "text-muted-foreground hover:text-foreground"),
|
|
108
115
|
children: [/* @__PURE__ */ jsx("span", { children: option.label }), option.adornment && /* @__PURE__ */ jsx("span", {
|
|
109
116
|
className: cn("text-xs", active ? "text-[var(--accent-text)]/80" : "text-muted-foreground"),
|
|
110
117
|
children: option.adornment
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { ixControlAfter, ixRow } from "../lib/interaction.js";
|
|
2
3
|
import { cn } from "../lib/utils.js";
|
|
3
4
|
import { controlSizes, fieldPresentation, fieldSizes, fieldTouchText } from "../lib/control-presentation.js";
|
|
4
5
|
import * as React from "react";
|
|
@@ -11,7 +12,7 @@ const SelectGroup = SelectPrimitive.Group;
|
|
|
11
12
|
const SelectValue = SelectPrimitive.Value;
|
|
12
13
|
const SelectTrigger = React.forwardRef(({ className, children, size = "default", ...props }, ref) => /* @__PURE__ */ jsxs(SelectPrimitive.Trigger, {
|
|
13
14
|
ref,
|
|
14
|
-
className: cn("flex w-full items-center justify-between gap-2 whitespace-nowrap border py-1
|
|
15
|
+
className: cn("flex w-full items-center justify-between gap-2 whitespace-nowrap border py-1 placeholder:text-[var(--text-dim)] disabled:cursor-not-allowed disabled:opacity-50", fieldPresentation, ixControlAfter, fieldTouchText, "data-[placeholder]:text-[var(--text-dim)] [&>span]:min-w-0 [&>span]:truncate [&>span]:text-left", "data-[state=open]:border-[var(--ix-hover-border)] data-[state=open]:shadow-[var(--ix-after)] [&[data-state=open]>svg]:rotate-180 [&>svg]:transition-transform", size === "compact" || size === "touch" ? cn(fieldSizes.md, controlSizes[size]) : fieldSizes[size === "default" ? "md" : size], className),
|
|
15
16
|
...props,
|
|
16
17
|
children: [children, /* @__PURE__ */ jsx(SelectPrimitive.Icon, {
|
|
17
18
|
asChild: true,
|
|
@@ -35,7 +36,7 @@ const SelectScrollDownButton = React.forwardRef(({ className, ...props }, ref) =
|
|
|
35
36
|
SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
|
|
36
37
|
const SelectContent = React.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(SelectPrimitive.Content, {
|
|
37
38
|
ref,
|
|
38
|
-
className: cn("data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-lg border border-border bg-
|
|
39
|
+
className: cn("data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-lg border border-border bg-popover text-popover-foreground shadow-[var(--edge-highlight),var(--shadow-card)] data-[state=closed]:animate-out data-[state=open]:animate-in", position === "popper" && "data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=bottom]:translate-y-1 data-[side=top]:-translate-y-1", className),
|
|
39
40
|
position,
|
|
40
41
|
...props,
|
|
41
42
|
children: [
|
|
@@ -56,7 +57,7 @@ const SelectLabel = React.forwardRef(({ className, ...props }, ref) => /* @__PUR
|
|
|
56
57
|
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
|
57
58
|
const SelectItem = React.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(SelectPrimitive.Item, {
|
|
58
59
|
ref,
|
|
59
|
-
className: cn("relative flex w-full cursor-default select-none items-center rounded-md py-1.5 pr-8 pl-2 text-sm outline-none transition-
|
|
60
|
+
className: cn("relative flex w-full cursor-default select-none items-center rounded-md py-1.5 pr-8 pl-2 text-sm outline-none transition-[color,background-color,box-shadow] focus:text-foreground data-[state=checked]:font-medium data-[disabled]:pointer-events-none data-[disabled]:opacity-50", ixRow, className),
|
|
60
61
|
...props,
|
|
61
62
|
children: [/* @__PURE__ */ jsx("span", {
|
|
62
63
|
className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center",
|
package/dist/primitives/tabs.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ixControlSoft, ixSelected, ixTabUnderline } from "../lib/interaction.js";
|
|
1
2
|
import { focusRing } from "../lib/focus.js";
|
|
2
3
|
import { cn } from "../lib/utils.js";
|
|
3
4
|
import * as React from "react";
|
|
@@ -19,9 +20,9 @@ const TabsList = React.forwardRef(({ className, variant = "default", ...props },
|
|
|
19
20
|
TabsList.displayName = TabsPrimitive.List.displayName;
|
|
20
21
|
const TabsTrigger = React.forwardRef(({ className, variant = "default", ...props }, ref) => {
|
|
21
22
|
const variants = {
|
|
22
|
-
default: `inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1.5 text-sm font-medium transition-all ${focusRing} disabled:pointer-events-none disabled:opacity-50
|
|
23
|
-
pills: `inline-flex items-center justify-center whitespace-nowrap rounded-full px-4 py-2 text-sm font-medium transition-all ${focusRing} disabled:pointer-events-none disabled:opacity-50 data-[state=
|
|
24
|
-
underline: `inline-flex items-center justify-center whitespace-nowrap rounded-t-md pb-3 text-sm font-medium transition-all ${focusRing} disabled:pointer-events-none disabled:opacity-50 border-b-2 border-transparent data-[state=
|
|
23
|
+
default: `inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1.5 text-sm font-medium transition-all ${focusRing} disabled:pointer-events-none disabled:opacity-50 ${ixControlSoft} ${ixSelected}`,
|
|
24
|
+
pills: `inline-flex items-center justify-center whitespace-nowrap rounded-full px-4 py-2 text-sm font-medium transition-all ${focusRing} disabled:pointer-events-none disabled:opacity-50 data-[state=inactive]:text-muted-foreground ${ixControlSoft} ${ixSelected}`,
|
|
25
|
+
underline: `inline-flex items-center justify-center whitespace-nowrap rounded-t-md pb-3 text-sm font-medium transition-all ${focusRing} disabled:pointer-events-none disabled:opacity-50 border-b-2 border-transparent data-[state=inactive]:text-muted-foreground ${ixTabUnderline}`
|
|
25
26
|
};
|
|
26
27
|
return /* @__PURE__ */ jsx(TabsPrimitive.Trigger, {
|
|
27
28
|
ref,
|
|
@@ -4,8 +4,14 @@ export interface InlineThinkingItemProps {
|
|
|
4
4
|
part: ReasoningPart;
|
|
5
5
|
defaultOpen?: boolean;
|
|
6
6
|
autoCollapse?: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Open the row while the model is still thinking. A product that keeps
|
|
9
|
+
* deliberation out of the reader's way passes false: the row stays as
|
|
10
|
+
* `defaultOpen` left it, with its one-line preview, until the reader opens it.
|
|
11
|
+
*/
|
|
12
|
+
openWhileActive?: boolean;
|
|
7
13
|
className?: string;
|
|
8
14
|
contentClassName?: string;
|
|
9
15
|
}
|
|
10
|
-
export declare const InlineThinkingItem: import("react").MemoExoticComponent<({ part, defaultOpen, autoCollapse, className, contentClassName }: InlineThinkingItemProps) => import("react").JSX.Element>;
|
|
16
|
+
export declare const InlineThinkingItem: import("react").MemoExoticComponent<({ part, defaultOpen, autoCollapse, openWhileActive, className, contentClassName }: InlineThinkingItemProps) => import("react").JSX.Element>;
|
|
11
17
|
//#endregion
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TextShimmer } from "../primitives/text-shimmer.js";
|
|
2
|
-
import { truncateText } from "../utils/format.js";
|
|
2
|
+
import { plainTextFromMarkdown, truncateText } from "../utils/format.js";
|
|
3
3
|
import { ExpandableContent } from "./expandable-content.js";
|
|
4
4
|
import { RunRowShell } from "./run-row-shell.js";
|
|
5
5
|
import { Markdown } from "../markdown/markdown.js";
|
|
@@ -7,18 +7,18 @@ import { memo, useEffect, useRef, useState } from "react";
|
|
|
7
7
|
import { jsx } from "react/jsx-runtime";
|
|
8
8
|
import { Brain } from "lucide-react";
|
|
9
9
|
//#region src/run/inline-thinking-item.tsx
|
|
10
|
-
const InlineThinkingItem = memo(({ part, defaultOpen = false, autoCollapse = true, className, contentClassName }) => {
|
|
10
|
+
const InlineThinkingItem = memo(({ part, defaultOpen = false, autoCollapse = true, openWhileActive = true, className, contentClassName }) => {
|
|
11
11
|
const [open, setOpen] = useState(defaultOpen);
|
|
12
12
|
const autoCollapsedRef = useRef(false);
|
|
13
13
|
const startTime = part.time?.start;
|
|
14
14
|
const endTime = part.time?.end;
|
|
15
15
|
const durationMs = startTime != null && endTime != null ? endTime - startTime : void 0;
|
|
16
16
|
const isActive = startTime != null && endTime == null;
|
|
17
|
-
const preview = part.text ? truncateText(part.text, 120) : void 0;
|
|
17
|
+
const preview = part.text ? truncateText(plainTextFromMarkdown(part.text), 120) : void 0;
|
|
18
18
|
useEffect(() => {
|
|
19
19
|
if (isActive) {
|
|
20
20
|
autoCollapsedRef.current = false;
|
|
21
|
-
setOpen(true);
|
|
21
|
+
if (openWhileActive) setOpen(true);
|
|
22
22
|
return;
|
|
23
23
|
}
|
|
24
24
|
if (autoCollapse && !autoCollapsedRef.current && durationMs != null) {
|
|
@@ -31,7 +31,8 @@ const InlineThinkingItem = memo(({ part, defaultOpen = false, autoCollapse = tru
|
|
|
31
31
|
}, [
|
|
32
32
|
autoCollapse,
|
|
33
33
|
durationMs,
|
|
34
|
-
isActive
|
|
34
|
+
isActive,
|
|
35
|
+
openWhileActive
|
|
35
36
|
]);
|
|
36
37
|
return /* @__PURE__ */ jsx(RunRowShell, {
|
|
37
38
|
icon: /* @__PURE__ */ jsx(Brain, { className: "h-3.5 w-3.5" }),
|
package/dist/utils/format.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
//#region src/utils/format.d.ts
|
|
2
2
|
/** Format a duration in milliseconds to a human-readable string. */
|
|
3
3
|
export declare function formatDuration(ms: number): string;
|
|
4
|
+
/**
|
|
5
|
+
* Markdown read as plain text, for a one-line preview: code fences, emphasis,
|
|
6
|
+
* headings, list and quote markers, and link syntax are removed, so a preview
|
|
7
|
+
* never shows `**` or `#`. Underscores inside words (`snake_case`) are kept.
|
|
8
|
+
*/
|
|
9
|
+
export declare function plainTextFromMarkdown(text: string): string;
|
|
4
10
|
/** Truncate text to `max` characters, appending "..." if truncated. */
|
|
5
11
|
export declare function truncateText(text: string, max: number): string;
|
|
6
12
|
/**
|
package/dist/utils/format.js
CHANGED
|
@@ -8,6 +8,14 @@ function formatDuration(ms) {
|
|
|
8
8
|
const remaining = seconds % 60;
|
|
9
9
|
return remaining > 0 ? `${minutes}m ${remaining}s` : `${minutes}m`;
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Markdown read as plain text, for a one-line preview: code fences, emphasis,
|
|
13
|
+
* headings, list and quote markers, and link syntax are removed, so a preview
|
|
14
|
+
* never shows `**` or `#`. Underscores inside words (`snake_case`) are kept.
|
|
15
|
+
*/
|
|
16
|
+
function plainTextFromMarkdown(text) {
|
|
17
|
+
return text.replace(/```[^\n]*\n?([\s\S]*?)```/g, "$1").replace(/`([^`]*)`/g, "$1").replace(/!?\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/^[ \t]{0,3}(?:#{1,6}[ \t]+|>[ \t]?|[-*+][ \t]+|\d+[.)][ \t]+)/gm, "").replace(/(\*\*|__)(?=\S)([\s\S]*?\S)\1/g, "$2").replace(/(^|[^\w*])\*(?=\S)([^*\n]*?\S)\*(?![\w*])/g, "$1$2").replace(/(^|[^\w])_(?=\S)([^_\n]*?\S)_(?!\w)/g, "$1$2").replace(/~~(?=\S)([\s\S]*?\S)~~/g, "$1");
|
|
18
|
+
}
|
|
11
19
|
/** Truncate text to `max` characters, appending "..." if truncated. */
|
|
12
20
|
function truncateText(text, max) {
|
|
13
21
|
const cleaned = text.replace(/\s+/g, " ").trim();
|
|
@@ -51,4 +59,4 @@ function formatBytes(bytes) {
|
|
|
51
59
|
return `${gb < 10 ? gb.toFixed(2) : gb.toFixed(1)} GB`;
|
|
52
60
|
}
|
|
53
61
|
//#endregion
|
|
54
|
-
export { formatBytes, formatDuration, formatUptime, truncateText };
|
|
62
|
+
export { formatBytes, formatDuration, formatUptime, plainTextFromMarkdown, truncateText };
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { copyText } from "./utils/copy-text.js";
|
|
2
|
-
import { formatBytes, formatDuration, formatUptime, truncateText } from "./utils/format.js";
|
|
2
|
+
import { formatBytes, formatDuration, formatUptime, plainTextFromMarkdown, truncateText } from "./utils/format.js";
|
|
3
3
|
import { timeAgo } from "./utils/time-ago.js";
|
|
4
4
|
import { TOOL_CATEGORY_ICONS, getToolCategory, getToolDisplayMetadata, getToolErrorText } from "./utils/tool-display.js";
|
|
5
5
|
import { cn } from "./lib/utils.js";
|
|
6
6
|
import { focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset } from "./lib/focus.js";
|
|
7
|
-
|
|
7
|
+
import { ixControl, ixControlAfter, ixControlSoft, ixField, ixRow, ixSelected, ixTabUnderline } from "./lib/interaction.js";
|
|
8
|
+
export { TOOL_CATEGORY_ICONS, cn, copyText, focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset, formatBytes, formatDuration, formatUptime, getToolCategory, getToolDisplayMetadata, getToolErrorText, ixControl, ixControlAfter, ixControlSoft, ixField, ixRow, ixSelected, ixTabUnderline, plainTextFromMarkdown, timeAgo, truncateText };
|
package/dist/utils.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { ixControl, ixControlAfter, ixControlSoft, ixField, ixRow, ixSelected, ixTabUnderline } from "./lib/interaction.js";
|
|
1
2
|
import { focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset } from "./lib/focus.js";
|
|
2
3
|
import { cn } from "./lib/utils.js";
|
|
3
4
|
import { TOOL_CATEGORY_ICONS, getToolCategory, getToolDisplayMetadata, getToolErrorText } from "./utils/tool-display.js";
|
|
4
|
-
import { formatBytes, formatDuration, formatUptime, truncateText } from "./utils/format.js";
|
|
5
|
+
import { formatBytes, formatDuration, formatUptime, plainTextFromMarkdown, truncateText } from "./utils/format.js";
|
|
5
6
|
import { copyText } from "./utils/copy-text.js";
|
|
6
7
|
import { timeAgo } from "./utils/time-ago.js";
|
|
7
|
-
export { TOOL_CATEGORY_ICONS, cn, copyText, focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset, formatBytes, formatDuration, formatUptime, getToolCategory, getToolDisplayMetadata, getToolErrorText, timeAgo, truncateText };
|
|
8
|
+
export { TOOL_CATEGORY_ICONS, cn, copyText, focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset, formatBytes, formatDuration, formatUptime, getToolCategory, getToolDisplayMetadata, getToolErrorText, ixControl, ixControlAfter, ixControlSoft, ixField, ixRow, ixSelected, ixTabUnderline, plainTextFromMarkdown, timeAgo, truncateText };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/ui",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.34.0",
|
|
4
4
|
"description": "Generic React UI components for Tangle products — primitives, chat, run, files, editor, markdown.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -150,7 +150,7 @@
|
|
|
150
150
|
"peerDependencies": {
|
|
151
151
|
"@hocuspocus/provider": ">=2.15.0 <5.0.0",
|
|
152
152
|
"@nanostores/react": ">=0.8.4 <3.0.0",
|
|
153
|
-
"@tangle-network/brand": "^1.
|
|
153
|
+
"@tangle-network/brand": "^1.24.1",
|
|
154
154
|
"@tiptap/core": ">=3.20.4 <4.0.0",
|
|
155
155
|
"@tiptap/extension-collaboration": ">=3.20.4 <4.0.0",
|
|
156
156
|
"@tiptap/extension-collaboration-caret": ">=3.7.0 <4.0.0",
|