@miragon/mcp-toolkit-ui 2.8.0 → 2.8.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/components/DrillButton.d.ts +5 -0
- package/dist/components/DrillButton.d.ts.map +1 -1
- package/dist/components/DrillButton.js +9 -4
- package/dist/components/DrillButton.js.map +1 -1
- package/package.json +3 -3
- package/src/components/DrillButton.test.tsx +48 -0
- package/src/components/DrillButton.tsx +10 -8
|
@@ -20,6 +20,11 @@ export interface DrillButtonProps {
|
|
|
20
20
|
* it for every in-app drill (row "Open", header nav) so they read identically
|
|
21
21
|
* and stay visually quieter than primary/agentic actions. Decoupled from any
|
|
22
22
|
* host — pass an `onDrill` callback (e.g. wrapping `useHostActions().showWidget`).
|
|
23
|
+
*
|
|
24
|
+
* It IS the toolkit's outline `Button` (`buttonVariants`): `sm` is 32 px,
|
|
25
|
+
* 14 px, weight 600, the size of a `Button size="sm"` or an `AskAiButton`
|
|
26
|
+
* beside it in a row; `md` is the `Button` default (36 px). The design
|
|
27
|
+
* system gives every button weight 600 and one radius.
|
|
23
28
|
*/
|
|
24
29
|
export declare function DrillButton({ children, onDrill, icon, size, ariaLabel }: DrillButtonProps): import("react").JSX.Element;
|
|
25
30
|
//# sourceMappingURL=DrillButton.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DrillButton.d.ts","sourceRoot":"","sources":["../../src/components/DrillButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"DrillButton.d.ts","sourceRoot":"","sources":["../../src/components/DrillButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItC,MAAM,WAAW,gBAAgB;IAC/B,oBAAoB;IACpB,QAAQ,EAAE,SAAS,CAAA;IACnB,mFAAmF;IACnF,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,qEAAqE;IACrE,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;IAClB,iGAAiG;IACjG,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAKD;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,IAAW,EAAE,SAAS,EAAE,EAAE,gBAAgB,+BAiBhG"}
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { ArrowRight } from "lucide-react";
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import { buttonVariants } from "../primitives/button.js";
|
|
4
|
+
/** The `Button` size each drill size is: one scale for every action of a view. */
|
|
5
|
+
const BUTTON_SIZE = { sm: "sm", md: "default" };
|
|
5
6
|
/**
|
|
6
7
|
* The single, deterministic in-widget navigation control: a neutral outline
|
|
7
8
|
* button with a trailing Lucide arrow that drills into a detail/sub-view. Use
|
|
8
9
|
* it for every in-app drill (row "Open", header nav) so they read identically
|
|
9
10
|
* and stay visually quieter than primary/agentic actions. Decoupled from any
|
|
10
11
|
* host — pass an `onDrill` callback (e.g. wrapping `useHostActions().showWidget`).
|
|
12
|
+
*
|
|
13
|
+
* It IS the toolkit's outline `Button` (`buttonVariants`): `sm` is 32 px,
|
|
14
|
+
* 14 px, weight 600, the size of a `Button size="sm"` or an `AskAiButton`
|
|
15
|
+
* beside it in a row; `md` is the `Button` default (36 px). The design
|
|
16
|
+
* system gives every button weight 600 and one radius.
|
|
11
17
|
*/
|
|
12
18
|
export function DrillButton({ children, onDrill, icon, size = "sm", ariaLabel }) {
|
|
13
|
-
|
|
14
|
-
return (_jsxs("button", { type: "button", onClick: onDrill, "aria-label": ariaLabel, className: cn("border-border text-foreground hover:border-focus hover:bg-accent hover:text-accent-foreground inline-flex items-center gap-1 rounded-md border font-medium transition-colors [&_svg:not([class*='size-'])]:size-4", FOCUS_RING, pad), children: [icon && (_jsx("span", { "aria-hidden": "true", className: "inline-flex", children: icon })), children, _jsx(ArrowRight, { "aria-hidden": "true", className: "size-4 shrink-0" })] }));
|
|
19
|
+
return (_jsxs("button", { type: "button", onClick: onDrill, "aria-label": ariaLabel, className: buttonVariants({ variant: "outline", size: BUTTON_SIZE[size] }), children: [icon && (_jsx("span", { "aria-hidden": "true", className: "inline-flex", children: icon })), children, _jsx(ArrowRight, { "aria-hidden": "true", className: "size-4 shrink-0" })] }));
|
|
15
20
|
}
|
|
16
21
|
//# sourceMappingURL=DrillButton.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DrillButton.js","sourceRoot":"","sources":["../../src/components/DrillButton.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"DrillButton.js","sourceRoot":"","sources":["../../src/components/DrillButton.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAkBxD,kFAAkF;AAClF,MAAM,WAAW,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAW,CAAA;AAExD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,WAAW,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,SAAS,EAAoB;IAC/F,OAAO,CACL,kBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,OAAO,gBACJ,SAAS,EACrB,SAAS,EAAE,cAAc,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,aAEzE,IAAI,IAAI,CACP,8BAAkB,MAAM,EAAC,SAAS,EAAC,aAAa,YAC7C,IAAI,GACA,CACR,EACA,QAAQ,EACT,KAAC,UAAU,mBAAa,MAAM,EAAC,SAAS,EAAC,iBAAiB,GAAG,IACtD,CACV,CAAA;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miragon/mcp-toolkit-ui",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.1",
|
|
4
4
|
"description": "React UI for MCP servers in the Miragon design system (white-label through role tokens): primitives, composite components, TanStack Query hooks, and the MCP App shell (McpAppView + WidgetRenderer).",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"react": "^19.2.0",
|
|
46
46
|
"react-dom": "^19.2.0",
|
|
47
47
|
"tailwindcss": "^4.3.0",
|
|
48
|
-
"@miragon/mcp-toolkit-core": "~2.8.
|
|
48
|
+
"@miragon/mcp-toolkit-core": "~2.8.1"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@base-ui/react": "1.8.0",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"tailwindcss": "4.3.3",
|
|
75
75
|
"typescript": "6.0.3",
|
|
76
76
|
"vitest": "4.1.11",
|
|
77
|
-
"@miragon/mcp-toolkit-core": "2.8.
|
|
77
|
+
"@miragon/mcp-toolkit-core": "2.8.1"
|
|
78
78
|
},
|
|
79
79
|
"engines": {
|
|
80
80
|
"node": ">=22.22.2"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { renderToStaticMarkup } from "react-dom/server"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
import { ExternalLink } from "lucide-react"
|
|
4
|
+
import { attribute, openingTags, userFacingTexts } from "../render-scan.js"
|
|
5
|
+
import { buttonVariants } from "../primitives/button.js"
|
|
6
|
+
import { DrillButton } from "./DrillButton.js"
|
|
7
|
+
|
|
8
|
+
const noop = () => undefined
|
|
9
|
+
const classOf = (tag: string | undefined) => attribute(tag ?? "", "class") ?? ""
|
|
10
|
+
|
|
11
|
+
describe("DrillButton: the outline Button with a trailing arrow (mcp-toolkit#194)", () => {
|
|
12
|
+
it("sm is a Button size sm: 32 px, 14 px, weight 600, like the buttons beside it in a row", () => {
|
|
13
|
+
const html = renderToStaticMarkup(<DrillButton onDrill={noop}>Open</DrillButton>)
|
|
14
|
+
const [button] = openingTags(html, "button")
|
|
15
|
+
expect(classOf(button)).toBe(buttonVariants({ variant: "outline", size: "sm" }))
|
|
16
|
+
expect(classOf(button)).toMatch(/\bh-8\b/)
|
|
17
|
+
expect(classOf(button)).toMatch(/\btext-sm\b/)
|
|
18
|
+
expect(classOf(button)).toMatch(/\bfont-semibold\b/)
|
|
19
|
+
expect(attribute(button ?? "", "type")).toBe("button")
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it("md is the Button default size (surface headers)", () => {
|
|
23
|
+
const html = renderToStaticMarkup(
|
|
24
|
+
<DrillButton onDrill={noop} size="md">
|
|
25
|
+
View running instances
|
|
26
|
+
</DrillButton>,
|
|
27
|
+
)
|
|
28
|
+
expect(classOf(openingTags(html, "button")[0])).toBe(
|
|
29
|
+
buttonVariants({ variant: "outline", size: "default" }),
|
|
30
|
+
)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it("keeps its words: the label, a decorative leading icon and a decorative trailing arrow", () => {
|
|
34
|
+
const html = renderToStaticMarkup(
|
|
35
|
+
<DrillButton onDrill={noop} icon={<ExternalLink />} ariaLabel="Open order o-1001">
|
|
36
|
+
Open
|
|
37
|
+
</DrillButton>,
|
|
38
|
+
)
|
|
39
|
+
const [button] = openingTags(html, "button")
|
|
40
|
+
expect(attribute(button ?? "", "aria-label")).toBe("Open order o-1001")
|
|
41
|
+
expect(userFacingTexts(html).map((t) => t.value)).toContain("Open")
|
|
42
|
+
const svgs = openingTags(html, "svg")
|
|
43
|
+
expect(svgs).toHaveLength(2)
|
|
44
|
+
expect(svgs.at(-1)).toContain("lucide-arrow-right")
|
|
45
|
+
for (const svg of svgs) expect(attribute(svg, "aria-hidden")).toBe("true")
|
|
46
|
+
expect(openingTags(html, "span")[0]).toContain('aria-hidden="true"')
|
|
47
|
+
})
|
|
48
|
+
})
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from "react"
|
|
2
2
|
import { ArrowRight } from "lucide-react"
|
|
3
|
-
import {
|
|
4
|
-
import { cn } from "../lib/utils.js"
|
|
3
|
+
import { buttonVariants } from "../primitives/button.js"
|
|
5
4
|
|
|
6
5
|
export interface DrillButtonProps {
|
|
7
6
|
/** Button label. */
|
|
@@ -19,25 +18,28 @@ export interface DrillButtonProps {
|
|
|
19
18
|
ariaLabel?: string
|
|
20
19
|
}
|
|
21
20
|
|
|
21
|
+
/** The `Button` size each drill size is: one scale for every action of a view. */
|
|
22
|
+
const BUTTON_SIZE = { sm: "sm", md: "default" } as const
|
|
23
|
+
|
|
22
24
|
/**
|
|
23
25
|
* The single, deterministic in-widget navigation control: a neutral outline
|
|
24
26
|
* button with a trailing Lucide arrow that drills into a detail/sub-view. Use
|
|
25
27
|
* it for every in-app drill (row "Open", header nav) so they read identically
|
|
26
28
|
* and stay visually quieter than primary/agentic actions. Decoupled from any
|
|
27
29
|
* host — pass an `onDrill` callback (e.g. wrapping `useHostActions().showWidget`).
|
|
30
|
+
*
|
|
31
|
+
* It IS the toolkit's outline `Button` (`buttonVariants`): `sm` is 32 px,
|
|
32
|
+
* 14 px, weight 600, the size of a `Button size="sm"` or an `AskAiButton`
|
|
33
|
+
* beside it in a row; `md` is the `Button` default (36 px). The design
|
|
34
|
+
* system gives every button weight 600 and one radius.
|
|
28
35
|
*/
|
|
29
36
|
export function DrillButton({ children, onDrill, icon, size = "sm", ariaLabel }: DrillButtonProps) {
|
|
30
|
-
const pad = size === "md" ? "px-3 py-1.5 text-dense" : "px-2.5 py-1 text-small"
|
|
31
37
|
return (
|
|
32
38
|
<button
|
|
33
39
|
type="button"
|
|
34
40
|
onClick={onDrill}
|
|
35
41
|
aria-label={ariaLabel}
|
|
36
|
-
className={
|
|
37
|
-
"border-border text-foreground hover:border-focus hover:bg-accent hover:text-accent-foreground inline-flex items-center gap-1 rounded-md border font-medium transition-colors [&_svg:not([class*='size-'])]:size-4",
|
|
38
|
-
FOCUS_RING,
|
|
39
|
-
pad,
|
|
40
|
-
)}
|
|
42
|
+
className={buttonVariants({ variant: "outline", size: BUTTON_SIZE[size] })}
|
|
41
43
|
>
|
|
42
44
|
{icon && (
|
|
43
45
|
<span aria-hidden="true" className="inline-flex">
|