@deepseek-ai/dsh-client-ui-primitives 0.1.5-rc.2 → 0.1.6-alpha.2
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/README.i18n.yaml +2 -2
- package/README.md +17 -9
- package/README.zh.md +20 -12
- package/lib/Checkbox.module.css +28 -0
- package/lib/ConnectionIndicator.module.css +42 -26
- package/lib/DiffBlock.module.css +8 -0
- package/lib/JsonTree.module.css +141 -18
- package/lib/Menu.module.css +13 -0
- package/lib/TerminalBlock.module.css +3 -3
- package/lib/index.js +1271 -513
- package/lib/markdown/MarkdownText.module.css +149 -8
- package/lib/types/Checkbox.d.ts +20 -0
- package/lib/types/ConnectionIndicator.d.ts +6 -5
- package/lib/types/DiffBlock.d.ts +6 -7
- package/lib/types/JsonTree.d.ts +12 -1
- package/lib/types/LinkIcon.d.ts +14 -3
- package/lib/types/Menu.d.ts +7 -2
- package/lib/types/Modal.d.ts +2 -1
- package/lib/types/SiteGlyph.d.ts +25 -0
- package/lib/types/TerminalBlock.d.ts +8 -3
- package/lib/types/darwin-desktop.d.ts +9 -0
- package/lib/types/icons/index.d.ts +36 -5
- package/lib/types/index.d.ts +5 -1
- package/lib/types/markdown/CodeBlock.d.ts +3 -1
- package/lib/types/markdown/MarkdownDelegate.d.ts +36 -0
- package/lib/types/markdown/MarkdownText.d.ts +13 -6
- package/lib/types/markdown/file-link.d.ts +13 -0
- package/lib/types/markdown/render.d.ts +2 -2
- package/lib/types/rank-by-name.d.ts +8 -4
- package/lib/types/user-text.d.ts +9 -1
- package/package.json +3 -1
package/lib/index.js
CHANGED
|
@@ -6,30 +6,34 @@ import css$2 from "./Button.module.css";
|
|
|
6
6
|
import css$3 from "./Pill.module.css";
|
|
7
7
|
import css$4 from "./Tag.module.css";
|
|
8
8
|
import css$5 from "./Switch.module.css";
|
|
9
|
-
import css$6 from "./
|
|
10
|
-
import
|
|
9
|
+
import css$6 from "./Checkbox.module.css";
|
|
10
|
+
import css$7 from "./Input.module.css";
|
|
11
|
+
import { Fragment as Fragment$1, cloneElement, createContext, createElement, memo, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
11
12
|
import { createPortal } from "react-dom";
|
|
12
|
-
import css$
|
|
13
|
-
import css$
|
|
14
|
-
import css$
|
|
15
|
-
import css$
|
|
16
|
-
import css$
|
|
17
|
-
import css$
|
|
18
|
-
import css$
|
|
19
|
-
import
|
|
20
|
-
import css$15 from "./
|
|
21
|
-
import
|
|
22
|
-
import css$
|
|
13
|
+
import css$8 from "./Menu.module.css";
|
|
14
|
+
import css$9 from "./HoverCard.module.css";
|
|
15
|
+
import css$10 from "./Modal.module.css";
|
|
16
|
+
import css$11 from "./OnboardingSurface.module.css";
|
|
17
|
+
import css$12 from "./RiskConfirmation.module.css";
|
|
18
|
+
import css$13 from "./ConnectionIndicator.module.css";
|
|
19
|
+
import css$14 from "./FileTypeIcon.module.css";
|
|
20
|
+
import { siAliexpress, siApple, siBaidu, siBilibili, siCsdn, siDuckduckgo, siEbay, siFacebook, siGithub, siGitlab, siGoogle, siInstagram, siJuejin, siMdnwebdocs, siNetflix, siNpm, siPypi, siQq, siQuora, siReddit, siSinaweibo, siSpotify, siStackoverflow, siTaobao, siTelegram, siTiktok, siV2ex, siWechat, siWhatsapp, siWikipedia, siX, siYcombinator, siYoutube, siZhihu } from "simple-icons";
|
|
21
|
+
import css$15 from "./user-text.module.css";
|
|
22
|
+
import markdownCss from "./markdown/MarkdownText.module.css";
|
|
23
|
+
import css$16 from "./Tooltip.module.css";
|
|
24
|
+
import css$17 from "./Toast.module.css";
|
|
25
|
+
import css$18 from "./JsonTree.module.css";
|
|
23
26
|
import Anser from "anser";
|
|
24
|
-
import css$
|
|
27
|
+
import css$19 from "./TerminalBlock.module.css";
|
|
25
28
|
import { createCssVariablesTheme, createHighlighterCoreSync } from "shiki/core";
|
|
26
29
|
import { createJavaScriptRegexEngine, defaultJavaScriptRegexConstructor } from "shiki/engine/javascript";
|
|
27
30
|
import langTs from "@shikijs/langs/typescript";
|
|
28
31
|
import langBash from "@shikijs/langs/shellscript";
|
|
29
32
|
import langJson from "@shikijs/langs/json";
|
|
30
|
-
import css$
|
|
31
|
-
import
|
|
32
|
-
import css$21 from "./
|
|
33
|
+
import css$20 from "./ReadBlock.module.css";
|
|
34
|
+
import { structuredPatch } from "diff";
|
|
35
|
+
import css$21 from "./DiffBlock.module.css";
|
|
36
|
+
import css$22 from "./SearchBlock.module.css";
|
|
33
37
|
import { fromMarkdown } from "mdast-util-from-markdown";
|
|
34
38
|
import { gfmFromMarkdown } from "mdast-util-gfm";
|
|
35
39
|
import { mathFromMarkdown } from "mdast-util-math";
|
|
@@ -41,9 +45,8 @@ import { classifyCharacter } from "micromark-util-classify-character";
|
|
|
41
45
|
import { codes, constants, types } from "micromark-util-symbol";
|
|
42
46
|
import { factorySpace } from "micromark-factory-space";
|
|
43
47
|
import { normalizeUri } from "micromark-util-sanitize-uri";
|
|
44
|
-
import css$
|
|
48
|
+
import css$23 from "./markdown/CodeBlock.module.css";
|
|
45
49
|
import katex from "katex";
|
|
46
|
-
import css$23 from "./markdown/MarkdownText.module.css";
|
|
47
50
|
import "katex/dist/katex.min.css";
|
|
48
51
|
import css$24 from "./WebBlock.module.css";
|
|
49
52
|
import css$25 from "./markdown/JsonBlock.module.css";
|
|
@@ -787,16 +790,16 @@ const IconUserOutline16 = ({ size = 16, className }) => jsxs("svg", {
|
|
|
787
790
|
fill: "currentColor"
|
|
788
791
|
})]
|
|
789
792
|
});
|
|
790
|
-
/**
|
|
791
|
-
const
|
|
793
|
+
/** ic_ds_paper_plane_outline_14 */
|
|
794
|
+
const IconPaperPlaneOutline14 = ({ size = 14, className }) => jsx("svg", {
|
|
792
795
|
width: size,
|
|
793
796
|
height: size,
|
|
794
797
|
className,
|
|
795
|
-
viewBox: "0 0
|
|
798
|
+
viewBox: "0 0 14 14",
|
|
796
799
|
fill: "none",
|
|
797
800
|
xmlns: "http://www.w3.org/2000/svg",
|
|
798
801
|
children: jsx("path", {
|
|
799
|
-
d: "
|
|
802
|
+
d: "M11.8249 1.11733C12.4401 0.929305 13.0795 1.42149 13.0238 2.08968L12.2321 11.5935C12.1751 12.2735 11.4312 12.6646 10.8386 12.3263L7.99539 10.7011L6.0967 12.7005L6.07413 12.7248L6.04808 12.7465C5.55601 13.1565 4.80867 12.8069 4.80833 12.1665V8.69211C4.80843 8.44469 4.90686 8.20727 5.08181 8.0323L9.79684 3.31641L2.46775 6.6988L4.10251 7.35253L3.67364 8.42559L1.57874 7.5878V7.5852C0.807611 7.2988 0.757207 6.21577 1.5145 5.86622L11.7025 1.16421L11.8249 1.11733ZM5.96474 11.1603L6.9614 10.1107L5.96474 9.54118V11.1603ZM6.32937 8.41864L11.1086 11.149L11.791 2.95698L6.32937 8.41864Z",
|
|
800
803
|
fill: "currentColor"
|
|
801
804
|
})
|
|
802
805
|
});
|
|
@@ -1428,6 +1431,29 @@ const IconQuestionOutline14 = ({ size = 14, className }) => jsxs("svg", {
|
|
|
1428
1431
|
})
|
|
1429
1432
|
]
|
|
1430
1433
|
});
|
|
1434
|
+
/** Info companion to the question outline: the same ring with an "i" glyph. */
|
|
1435
|
+
const IconInfoOutline14 = ({ size = 14, className }) => jsxs("svg", {
|
|
1436
|
+
width: size,
|
|
1437
|
+
height: size,
|
|
1438
|
+
className,
|
|
1439
|
+
viewBox: "0 0 14 14",
|
|
1440
|
+
fill: "none",
|
|
1441
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1442
|
+
children: [
|
|
1443
|
+
jsx("path", {
|
|
1444
|
+
d: "M12.5757 7.00012C12.5757 3.92085 10.0794 1.42463 7.00012 1.42456C3.9208 1.42456 1.42456 3.9208 1.42456 7.00012C1.42463 10.0794 3.92085 12.5757 7.00012 12.5757C10.0793 12.5756 12.5756 10.0793 12.5757 7.00012ZM13.8002 7.00012C13.8001 10.7559 10.7559 13.8001 7.00012 13.8002C3.2443 13.8002 0.199291 10.7559 0.199219 7.00012C0.199219 3.24426 3.24426 0.199219 7.00012 0.199219C10.7559 0.199291 13.8002 3.2443 13.8002 7.00012Z",
|
|
1445
|
+
fill: "currentColor"
|
|
1446
|
+
}),
|
|
1447
|
+
jsx("path", {
|
|
1448
|
+
d: "M7.6127 3.18921V4.55986H6.38735V3.18921H7.6127Z",
|
|
1449
|
+
fill: "currentColor"
|
|
1450
|
+
}),
|
|
1451
|
+
jsx("path", {
|
|
1452
|
+
d: "M7.6127 5.68921V10.8109H6.38735V5.68921H7.6127Z",
|
|
1453
|
+
fill: "currentColor"
|
|
1454
|
+
})
|
|
1455
|
+
]
|
|
1456
|
+
});
|
|
1431
1457
|
/** Alarm clock outline for active scheduled-task indicators. */
|
|
1432
1458
|
const IconAlarmClockOutline16 = ({ size = 16, className }) => jsxs("svg", {
|
|
1433
1459
|
"aria-hidden": "true",
|
|
@@ -1498,6 +1524,140 @@ const IconArchiveOutline20 = ({ size = 20, className }) => jsxs("svg", {
|
|
|
1498
1524
|
fill: "currentColor"
|
|
1499
1525
|
})]
|
|
1500
1526
|
});
|
|
1527
|
+
/** Line-wrapping toggle glyph. */
|
|
1528
|
+
const IconWrapLinesOutline16 = ({ size = 16, className }) => jsx("svg", {
|
|
1529
|
+
width: size,
|
|
1530
|
+
height: size,
|
|
1531
|
+
className,
|
|
1532
|
+
viewBox: "0 0 16 16",
|
|
1533
|
+
fill: "none",
|
|
1534
|
+
stroke: "currentColor",
|
|
1535
|
+
strokeWidth: "1.5",
|
|
1536
|
+
strokeLinejoin: "round",
|
|
1537
|
+
"aria-hidden": "true",
|
|
1538
|
+
children: jsx("path", { d: "M1.5 3.5h13M1.5 7.5h10.25a2.5 2.5 0 0 1 0 5H8m2-2-2 2 2 2M1.5 11.5h3" })
|
|
1539
|
+
});
|
|
1540
|
+
/**
|
|
1541
|
+
* Plan row glyph of the composer menu (#3567): a document with three ruled
|
|
1542
|
+
* lines and a pencil over its corner. Drawn on a 14 grid whose content spans
|
|
1543
|
+
* 0.5..13.5, so at the menu's 16px render it fills the same extent as the
|
|
1544
|
+
* 16-grid glyphs beside it.
|
|
1545
|
+
*/
|
|
1546
|
+
const IconPlanOutline14 = ({ size = 14, className }) => jsxs("svg", {
|
|
1547
|
+
width: size,
|
|
1548
|
+
height: size,
|
|
1549
|
+
className,
|
|
1550
|
+
viewBox: "0 0 14 14",
|
|
1551
|
+
fill: "none",
|
|
1552
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1553
|
+
children: [
|
|
1554
|
+
jsx("path", {
|
|
1555
|
+
d: "M9.56143 3.14672V4.24774H3.94716V3.14672H9.56143Z",
|
|
1556
|
+
fill: "currentColor"
|
|
1557
|
+
}),
|
|
1558
|
+
jsx("path", {
|
|
1559
|
+
d: "M9.56143 5.44201V6.54304H3.94716V5.44201H9.56143Z",
|
|
1560
|
+
fill: "currentColor"
|
|
1561
|
+
}),
|
|
1562
|
+
jsx("path", {
|
|
1563
|
+
d: "M7.97328 7.73731V8.83833H3.94716V7.73731H7.97328Z",
|
|
1564
|
+
fill: "currentColor"
|
|
1565
|
+
}),
|
|
1566
|
+
jsx("path", {
|
|
1567
|
+
d: "M8.02789 0.500001C8.82106 0.500001 9.46528 0.499108 9.97973 0.553797C10.5054 0.609708 10.9678 0.729732 11.3714 1.01734C11.6057 1.18436 11.8125 1.38729 11.9827 1.61716C12.2758 2.01317 12.3982 2.46699 12.4552 2.98269C12.5109 3.48743 12.51 4.11964 12.51 4.89782V5.48599L11.2928 6.72061V4.89782C11.2928 4.09333 11.2923 3.53731 11.2453 3.1118C11.1995 2.69759 11.1162 2.47711 10.9986 2.31831C10.9034 2.18976 10.7879 2.07638 10.6568 1.98298C10.495 1.86762 10.2704 1.7858 9.84814 1.7409C9.41445 1.69482 8.84789 1.69427 8.02789 1.69427H5.4821C4.66215 1.69427 4.09555 1.69485 3.66184 1.7409C3.23978 1.78576 3.01501 1.86773 2.85315 1.98298C2.72221 2.07632 2.60657 2.18986 2.51139 2.31831C2.39384 2.4771 2.31045 2.69763 2.26467 3.1118C2.21772 3.53731 2.21716 4.09333 2.21716 4.89782V8.91011C2.21716 9.71498 2.21771 10.2714 2.26467 10.697C2.3104 11.111 2.39397 11.3308 2.51139 11.4896C2.60659 11.6182 2.72214 11.7315 2.85315 11.825C3.01505 11.9404 3.23938 12.023 3.66184 12.0679C4.09555 12.114 4.66212 12.1146 5.4821 12.1146H5.97554L4.80224 13.3034C4.3108 13.3002 3.88905 13.2923 3.53026 13.2541C3.00445 13.1982 2.5423 13.0784 2.13857 12.7906C1.90424 12.6235 1.6975 12.4216 1.52725 12.1917C1.23396 11.7955 1.1118 11.3412 1.05483 10.8252C0.999149 10.3205 1 9.68831 1 8.91011V4.89782C1 4.11964 0.999094 3.48743 1.05483 2.98269C1.11182 2.46701 1.23416 2.01316 1.52725 1.61716C1.69745 1.3874 1.90437 1.1843 2.13857 1.01734C2.54218 0.729872 3.00468 0.609682 3.53026 0.553797C4.04472 0.499135 4.68896 0.500001 5.4821 0.500001H8.02789Z",
|
|
1568
|
+
fill: "currentColor"
|
|
1569
|
+
}),
|
|
1570
|
+
jsx("path", {
|
|
1571
|
+
d: "M12.6413 13.2999H8.82536L10.0608 12.1056H12.6413V13.2999Z",
|
|
1572
|
+
fill: "currentColor"
|
|
1573
|
+
}),
|
|
1574
|
+
jsx("path", {
|
|
1575
|
+
d: "M7.22216 11.8899L6.53753 13.2335C6.4571 13.3913 6.62775 13.5587 6.78861 13.4798L8.15787 12.8081L13 8.08806L12.0643 7.16994L7.22216 11.8899Z",
|
|
1576
|
+
fill: "currentColor"
|
|
1577
|
+
})
|
|
1578
|
+
]
|
|
1579
|
+
});
|
|
1580
|
+
/**
|
|
1581
|
+
* Compact row glyph of the composer menu: the composer's context-usage ring
|
|
1582
|
+
* (ContextMeter) frozen at its resting look — a quiet track with one filled
|
|
1583
|
+
* quarter arc. A restyle of the live ring revisits this copy.
|
|
1584
|
+
*/
|
|
1585
|
+
const IconCompactOutline16 = ({ size = 16, className }) => jsxs("svg", {
|
|
1586
|
+
width: size,
|
|
1587
|
+
height: size,
|
|
1588
|
+
className,
|
|
1589
|
+
viewBox: "0 0 16 16",
|
|
1590
|
+
fill: "none",
|
|
1591
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1592
|
+
children: [jsx("circle", {
|
|
1593
|
+
cx: "8",
|
|
1594
|
+
cy: "8",
|
|
1595
|
+
r: "6.4",
|
|
1596
|
+
stroke: "currentColor",
|
|
1597
|
+
strokeWidth: "1.6",
|
|
1598
|
+
opacity: "0.35"
|
|
1599
|
+
}), jsx("path", {
|
|
1600
|
+
d: "M8 1.6A6.4 6.4 0 0 1 14.4 8",
|
|
1601
|
+
stroke: "currentColor",
|
|
1602
|
+
strokeWidth: "1.6",
|
|
1603
|
+
strokeLinecap: "round"
|
|
1604
|
+
})]
|
|
1605
|
+
});
|
|
1606
|
+
/**
|
|
1607
|
+
* The permission shield contour on the 16 grid (design set 1556), stroked at
|
|
1608
|
+
* {@link SHIELD_OUTLINE_STROKE}. The composer's permission selector composes
|
|
1609
|
+
* its mode marks (check, pencil, exclamation) over this same path inside one
|
|
1610
|
+
* svg, so the geometry lives here once.
|
|
1611
|
+
*/
|
|
1612
|
+
const SHIELD_OUTLINE_PATH = "M8.20554 0.899994L14.7901 3.36857V7.01026C14.7901 12 11.0466 14.2103 8.20554 15.3C5.36446 14.2103 1.62012 12 1.62012 7.01026V3.36857L8.20554 0.899994Z";
|
|
1613
|
+
/** Stroke width of {@link SHIELD_OUTLINE_PATH}. */
|
|
1614
|
+
const SHIELD_OUTLINE_STROKE = "1.31831";
|
|
1615
|
+
/** Permission row glyph of the composer menu: the shield contour alone, without a mode mark. */
|
|
1616
|
+
const IconShieldOutline16 = ({ size = 16, className }) => jsx("svg", {
|
|
1617
|
+
width: size,
|
|
1618
|
+
height: size,
|
|
1619
|
+
className,
|
|
1620
|
+
viewBox: "0 0 16 16",
|
|
1621
|
+
fill: "none",
|
|
1622
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1623
|
+
children: jsx("path", {
|
|
1624
|
+
d: SHIELD_OUTLINE_PATH,
|
|
1625
|
+
stroke: "currentColor",
|
|
1626
|
+
strokeWidth: SHIELD_OUTLINE_STROKE,
|
|
1627
|
+
strokeLinejoin: "round"
|
|
1628
|
+
})
|
|
1629
|
+
});
|
|
1630
|
+
/** Plugin pinwheel (design handoff for the plugin manager): four interleaved arcs on the 16 grid. */
|
|
1631
|
+
const IconPluginPinwheelOutline16 = ({ size = 16, className }) => jsxs("svg", {
|
|
1632
|
+
width: size,
|
|
1633
|
+
height: size,
|
|
1634
|
+
className,
|
|
1635
|
+
viewBox: "0 0 16 16",
|
|
1636
|
+
fill: "none",
|
|
1637
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1638
|
+
children: [
|
|
1639
|
+
jsx("path", {
|
|
1640
|
+
d: "M7.84457 5.06199C11.6605 4.93876 14.7962 6.14848 14.8484 7.76397C14.8875 8.97461 13.1838 10.0696 10.7215 10.5942",
|
|
1641
|
+
stroke: "currentColor",
|
|
1642
|
+
strokeWidth: "1.2"
|
|
1643
|
+
}),
|
|
1644
|
+
jsx("path", {
|
|
1645
|
+
d: "M5.12742 8.07731C5.00419 4.26138 6.21391 1.12568 7.8294 1.07351C9.04004 1.03441 10.135 2.73808 10.6596 5.20037",
|
|
1646
|
+
stroke: "currentColor",
|
|
1647
|
+
strokeWidth: "1.2"
|
|
1648
|
+
}),
|
|
1649
|
+
jsx("path", {
|
|
1650
|
+
d: "M8.02457 10.6802C4.20865 10.8034 1.07294 9.5937 1.02077 7.97821C0.981678 6.76758 2.68535 5.67262 5.14763 5.14798",
|
|
1651
|
+
stroke: "currentColor",
|
|
1652
|
+
strokeWidth: "1.2"
|
|
1653
|
+
}),
|
|
1654
|
+
jsx("path", {
|
|
1655
|
+
d: "M10.7476 7.89535C10.8708 11.7113 9.66109 14.847 8.0456 14.8991C6.83496 14.9382 5.74 13.2346 5.21536 10.7723",
|
|
1656
|
+
stroke: "currentColor",
|
|
1657
|
+
strokeWidth: "1.2"
|
|
1658
|
+
})
|
|
1659
|
+
]
|
|
1660
|
+
});
|
|
1501
1661
|
//#endregion
|
|
1502
1662
|
//#region lib/types/DisclosureRow.js
|
|
1503
1663
|
/**
|
|
@@ -1639,6 +1799,33 @@ function Switch({ checked, onChange, label, disabled = false, title, className }
|
|
|
1639
1799
|
});
|
|
1640
1800
|
}
|
|
1641
1801
|
//#endregion
|
|
1802
|
+
//#region lib/types/Checkbox.js
|
|
1803
|
+
/** Controlled native checkbox with a caller-owned visible and accessible label. */
|
|
1804
|
+
/**
|
|
1805
|
+
* Render a labeled checkbox with native keyboard and form semantics.
|
|
1806
|
+
* @param props.checked - current checked state.
|
|
1807
|
+
* @param props.onChange - receives the requested checked state.
|
|
1808
|
+
* @param props.label - localized visible and accessible label.
|
|
1809
|
+
* @param props.disabled - whether the control refuses changes.
|
|
1810
|
+
* @param props.title - optional localized hover text.
|
|
1811
|
+
* @param props.className - extra class for the label's placement.
|
|
1812
|
+
* @returns the label containing its checkbox.
|
|
1813
|
+
*/
|
|
1814
|
+
function Checkbox({ checked, onChange, label, disabled = false, title, className }) {
|
|
1815
|
+
return jsxs("label", {
|
|
1816
|
+
className: clsx(css$6.checkbox, className),
|
|
1817
|
+
title,
|
|
1818
|
+
children: [jsx("input", {
|
|
1819
|
+
type: "checkbox",
|
|
1820
|
+
checked,
|
|
1821
|
+
disabled,
|
|
1822
|
+
onChange: (event) => {
|
|
1823
|
+
onChange(event.target.checked);
|
|
1824
|
+
}
|
|
1825
|
+
}), jsx("span", { children: label })]
|
|
1826
|
+
});
|
|
1827
|
+
}
|
|
1828
|
+
//#endregion
|
|
1642
1829
|
//#region lib/types/Input.js
|
|
1643
1830
|
/**
|
|
1644
1831
|
* Render a text input with an optional leading icon.
|
|
@@ -1647,12 +1834,12 @@ function Switch({ checked, onChange, label, disabled = false, title, className }
|
|
|
1647
1834
|
*/
|
|
1648
1835
|
function Input({ icon, className, ...rest }) {
|
|
1649
1836
|
return jsxs("span", {
|
|
1650
|
-
className: clsx(css$
|
|
1837
|
+
className: clsx(css$7.wrap, className),
|
|
1651
1838
|
children: [icon != null && jsx("span", {
|
|
1652
|
-
className: css$
|
|
1839
|
+
className: css$7.icon,
|
|
1653
1840
|
children: icon
|
|
1654
1841
|
}), jsx("input", {
|
|
1655
|
-
className: css$
|
|
1842
|
+
className: css$7.input,
|
|
1656
1843
|
...rest
|
|
1657
1844
|
})]
|
|
1658
1845
|
});
|
|
@@ -1701,8 +1888,13 @@ const MEASURE_STYLE = {
|
|
|
1701
1888
|
top: 0
|
|
1702
1889
|
};
|
|
1703
1890
|
/**
|
|
1704
|
-
* Render an anchored dropdown menu.
|
|
1705
|
-
*
|
|
1891
|
+
* Render an anchored dropdown menu. While the list is open its keys mirror the
|
|
1892
|
+
* composer's: Tab settles the focused row — from the trigger, Tab enters the
|
|
1893
|
+
* list instead — and Escape or Shift+Tab close it and return focus to the
|
|
1894
|
+
* anchor's first button, and selecting a row does the same — the rows unmount
|
|
1895
|
+
* with the list. Only a keyboard on the trigger or inside the list is
|
|
1896
|
+
* intercepted; Tab presses elsewhere on the page stay the browser's.
|
|
1897
|
+
* @param props.autoFocus - focus the first item on open; the arrow keys walk the list either way.
|
|
1706
1898
|
* @param props.open - whether the list is showing (owner-controlled).
|
|
1707
1899
|
* @param props.anchor - the trigger element (rendered in place).
|
|
1708
1900
|
* @param props.items - selectable rows and optional separators.
|
|
@@ -1741,6 +1933,44 @@ const MEASURE_STYLE = {
|
|
|
1741
1933
|
function Menu({ open, anchor, items, selectedId, selectedIds, onSelect, onClose, align = "start", side = "bottom", portal = false, closeOnPointerLeave = false, dense = false, compact = false, autoFocus = false, selection = "check", getAnchorRect, footer, className }) {
|
|
1742
1934
|
const rootRef = useRef(null);
|
|
1743
1935
|
const listRef = useRef(null);
|
|
1936
|
+
/** Index the arrow walk last focused, the resume point when focus left the rows. */
|
|
1937
|
+
const walkIndex = useRef(null);
|
|
1938
|
+
/**
|
|
1939
|
+
* The control that had the keyboard when this menu opened — its own trigger,
|
|
1940
|
+
* which an anchor that wraps several controls (a split button) would not be
|
|
1941
|
+
* able to name by position.
|
|
1942
|
+
*/
|
|
1943
|
+
const triggerRef = useRef(null);
|
|
1944
|
+
/**
|
|
1945
|
+
* Hand the keyboard back to the trigger that opened the menu — or, when the
|
|
1946
|
+
* anchor never held it, to the anchor's first button. Focus left on a removed
|
|
1947
|
+
* row otherwise falls to the page body, where the next Tab restarts from the
|
|
1948
|
+
* top of the page.
|
|
1949
|
+
*/
|
|
1950
|
+
const refocusAnchor = () => {
|
|
1951
|
+
const trigger = triggerRef.current;
|
|
1952
|
+
if (trigger !== null && document.contains(trigger) && !trigger.disabled) {
|
|
1953
|
+
trigger.focus();
|
|
1954
|
+
return;
|
|
1955
|
+
}
|
|
1956
|
+
rootRef.current?.querySelector("button:not(:disabled)")?.focus();
|
|
1957
|
+
};
|
|
1958
|
+
/**
|
|
1959
|
+
* Post-selection focus, for the paths where the rows unmount with the list.
|
|
1960
|
+
* A selection whose owner keeps the menu open is left alone, and so is an
|
|
1961
|
+
* owner that moved focus itself (a presented file card hands it to its
|
|
1962
|
+
* preview button): only a keyboard left on the closing list (or on the body
|
|
1963
|
+
* its removal produced) comes back to the trigger.
|
|
1964
|
+
*/
|
|
1965
|
+
const refocusAfterSelection = () => {
|
|
1966
|
+
queueMicrotask(() => {
|
|
1967
|
+
if (openRef.current) return;
|
|
1968
|
+
const active = document.activeElement;
|
|
1969
|
+
if (active === null || active === document.body || listRef.current?.contains(active) === true) refocusAnchor();
|
|
1970
|
+
});
|
|
1971
|
+
};
|
|
1972
|
+
const openRef = useRef(open);
|
|
1973
|
+
openRef.current = open;
|
|
1744
1974
|
const [openSubmenuId, setOpenSubmenuId] = useState(null);
|
|
1745
1975
|
const [fixedPos, setFixedPos] = useState(null);
|
|
1746
1976
|
const { arm: armClose, cancel: cancelClose } = usePointerGrace(onClose);
|
|
@@ -1796,11 +2026,23 @@ function Menu({ open, anchor, items, selectedId, selectedIds, onSelect, onClose,
|
|
|
1796
2026
|
getAnchorRect
|
|
1797
2027
|
]);
|
|
1798
2028
|
useEffect(() => {
|
|
1799
|
-
if (open
|
|
2029
|
+
if (!open) {
|
|
2030
|
+
triggerRef.current = null;
|
|
2031
|
+
return;
|
|
2032
|
+
}
|
|
2033
|
+
const active = document.activeElement;
|
|
2034
|
+
triggerRef.current = active instanceof HTMLElement && rootRef.current?.contains(active) === true ? active : null;
|
|
2035
|
+
}, [open]);
|
|
2036
|
+
useEffect(() => {
|
|
2037
|
+
if (!open || !autoFocus) return;
|
|
2038
|
+
const first = listRef.current?.querySelector("button:not(:disabled)");
|
|
2039
|
+
walkIndex.current = first === void 0 || first === null ? null : 0;
|
|
2040
|
+
first?.focus();
|
|
1800
2041
|
}, [open, autoFocus]);
|
|
1801
2042
|
useEffect(() => {
|
|
1802
2043
|
if (!open) {
|
|
1803
2044
|
setOpenSubmenuId(null);
|
|
2045
|
+
walkIndex.current = null;
|
|
1804
2046
|
return;
|
|
1805
2047
|
}
|
|
1806
2048
|
const onPointerDown = (e) => {
|
|
@@ -1810,21 +2052,52 @@ function Menu({ open, anchor, items, selectedId, selectedIds, onSelect, onClose,
|
|
|
1810
2052
|
onClose();
|
|
1811
2053
|
};
|
|
1812
2054
|
const onKeyDown = (e) => {
|
|
2055
|
+
const focused = document.activeElement;
|
|
2056
|
+
const insideList = listRef.current?.contains(focused) === true;
|
|
2057
|
+
const anchored = rootRef.current?.contains(focused) === true || insideList;
|
|
1813
2058
|
if (e.key === "Escape") {
|
|
1814
2059
|
onClose();
|
|
1815
|
-
if (autoFocus)
|
|
2060
|
+
if (anchored || autoFocus) refocusAnchor();
|
|
2061
|
+
}
|
|
2062
|
+
if (e.key === "Tab") {
|
|
2063
|
+
const list = listRef.current;
|
|
2064
|
+
if (list === null || !anchored) return;
|
|
2065
|
+
if (e.shiftKey) {
|
|
2066
|
+
e.preventDefault();
|
|
2067
|
+
onClose();
|
|
2068
|
+
refocusAnchor();
|
|
2069
|
+
return;
|
|
2070
|
+
}
|
|
2071
|
+
if (insideList) {
|
|
2072
|
+
if (focused instanceof Element && focused.getAttribute("role") === "menuitem") {
|
|
2073
|
+
e.preventDefault();
|
|
2074
|
+
focused.click();
|
|
2075
|
+
}
|
|
2076
|
+
return;
|
|
2077
|
+
}
|
|
2078
|
+
const row = list.querySelector("button:not(:disabled)");
|
|
2079
|
+
if (row === null) return;
|
|
2080
|
+
e.preventDefault();
|
|
2081
|
+
row.focus();
|
|
2082
|
+
walkIndex.current = 0;
|
|
2083
|
+
return;
|
|
1816
2084
|
}
|
|
1817
|
-
if (!
|
|
2085
|
+
if (![
|
|
1818
2086
|
"ArrowDown",
|
|
1819
2087
|
"ArrowUp",
|
|
1820
2088
|
"Home",
|
|
1821
2089
|
"End"
|
|
1822
2090
|
].includes(e.key)) return;
|
|
1823
|
-
const
|
|
1824
|
-
|
|
1825
|
-
|
|
2091
|
+
const list = listRef.current;
|
|
2092
|
+
if (list === null || !anchored) return;
|
|
2093
|
+
const buttons = Array.from(list.querySelectorAll("button:not(:disabled)"));
|
|
2094
|
+
if (buttons.length === 0) return;
|
|
2095
|
+
const index = buttons.indexOf(focused);
|
|
2096
|
+
const from = index >= 0 ? index : walkIndex.current;
|
|
2097
|
+
const next = e.key === "Home" ? 0 : e.key === "End" ? buttons.length - 1 : from === null ? e.key === "ArrowDown" ? 0 : buttons.length - 1 : (from + (e.key === "ArrowDown" ? 1 : -1) + buttons.length) % buttons.length;
|
|
1826
2098
|
e.preventDefault();
|
|
1827
|
-
|
|
2099
|
+
walkIndex.current = next;
|
|
2100
|
+
buttons[next]?.focus();
|
|
1828
2101
|
};
|
|
1829
2102
|
const onWindowBlur = () => {
|
|
1830
2103
|
if (document.activeElement instanceof HTMLIFrameElement) onClose();
|
|
@@ -1848,11 +2121,11 @@ function Menu({ open, anchor, items, selectedId, selectedIds, onSelect, onClose,
|
|
|
1848
2121
|
const scrollable = !items.some((entry) => !isSeparator(entry) && !isLabel(entry) && entry.submenu !== void 0 && entry.submenu.length > 0);
|
|
1849
2122
|
const renderEntry = (entry) => {
|
|
1850
2123
|
if (isSeparator(entry)) return jsx("div", {
|
|
1851
|
-
className: css$
|
|
2124
|
+
className: css$8.separator,
|
|
1852
2125
|
role: "separator"
|
|
1853
2126
|
}, entry.id);
|
|
1854
2127
|
if (isLabel(entry)) return jsx("div", {
|
|
1855
|
-
className: css$
|
|
2128
|
+
className: css$8.label,
|
|
1856
2129
|
role: "presentation",
|
|
1857
2130
|
children: entry.text
|
|
1858
2131
|
}, entry.id);
|
|
@@ -1860,7 +2133,7 @@ function Menu({ open, anchor, items, selectedId, selectedIds, onSelect, onClose,
|
|
|
1860
2133
|
const subOpen = hasSub && openSubmenuId === entry.id;
|
|
1861
2134
|
const selected = entry.id === selectedId || selectedIds?.includes(entry.id) === true;
|
|
1862
2135
|
return jsxs("div", {
|
|
1863
|
-
className: css$
|
|
2136
|
+
className: css$8.itemWrap,
|
|
1864
2137
|
onMouseEnter: () => {
|
|
1865
2138
|
setOpenSubmenuId(hasSub ? entry.id : null);
|
|
1866
2139
|
},
|
|
@@ -1870,7 +2143,7 @@ function Menu({ open, anchor, items, selectedId, selectedIds, onSelect, onClose,
|
|
|
1870
2143
|
children: [jsxs("button", {
|
|
1871
2144
|
type: "button",
|
|
1872
2145
|
role: "menuitem",
|
|
1873
|
-
className: clsx(css$
|
|
2146
|
+
className: clsx(css$8.item, selected && (selection === "fill" ? css$8.selectedFill : css$8.selected), entry.danger === true && css$8.danger),
|
|
1874
2147
|
disabled: entry.disabled,
|
|
1875
2148
|
"aria-haspopup": hasSub ? "menu" : void 0,
|
|
1876
2149
|
"aria-expanded": hasSub ? subOpen : void 0,
|
|
@@ -1883,34 +2156,36 @@ function Menu({ open, anchor, items, selectedId, selectedIds, onSelect, onClose,
|
|
|
1883
2156
|
return;
|
|
1884
2157
|
}
|
|
1885
2158
|
onSelect(entry.id);
|
|
2159
|
+
refocusAfterSelection();
|
|
1886
2160
|
},
|
|
1887
2161
|
children: [
|
|
1888
2162
|
entry.icon !== void 0 && jsx("span", {
|
|
1889
|
-
className: css$
|
|
2163
|
+
className: css$8.itemIcon,
|
|
1890
2164
|
children: entry.icon
|
|
1891
2165
|
}),
|
|
1892
2166
|
jsx("span", {
|
|
1893
|
-
className: css$
|
|
2167
|
+
className: css$8.itemLabel,
|
|
1894
2168
|
children: entry.label
|
|
1895
2169
|
}),
|
|
1896
|
-
selected && selection === "check" && jsx(IconCheckOutline16, { className: css$
|
|
2170
|
+
selected && selection === "check" && jsx(IconCheckOutline16, { className: css$8.check })
|
|
1897
2171
|
]
|
|
1898
2172
|
}), subOpen && entry.submenu !== void 0 && jsx("div", {
|
|
1899
|
-
className: clsx(css$
|
|
2173
|
+
className: clsx(css$8.submenu, compact && css$8.compactList),
|
|
1900
2174
|
role: "menu",
|
|
1901
2175
|
children: entry.submenu.map((sub) => jsxs("button", {
|
|
1902
2176
|
type: "button",
|
|
1903
2177
|
role: "menuitem",
|
|
1904
|
-
className: css$
|
|
2178
|
+
className: css$8.item,
|
|
1905
2179
|
disabled: sub.disabled,
|
|
1906
2180
|
onClick: () => {
|
|
1907
2181
|
onSelect(sub.id);
|
|
2182
|
+
refocusAfterSelection();
|
|
1908
2183
|
},
|
|
1909
2184
|
children: [sub.icon !== void 0 && jsx("span", {
|
|
1910
|
-
className: css$
|
|
2185
|
+
className: css$8.itemIcon,
|
|
1911
2186
|
children: sub.icon
|
|
1912
2187
|
}), jsx("span", {
|
|
1913
|
-
className: css$
|
|
2188
|
+
className: css$8.itemLabel,
|
|
1914
2189
|
children: sub.label
|
|
1915
2190
|
})]
|
|
1916
2191
|
}, sub.id))
|
|
@@ -1919,25 +2194,25 @@ function Menu({ open, anchor, items, selectedId, selectedIds, onSelect, onClose,
|
|
|
1919
2194
|
};
|
|
1920
2195
|
const list = open && jsxs("div", {
|
|
1921
2196
|
ref: listRef,
|
|
1922
|
-
className: clsx(css$
|
|
2197
|
+
className: clsx(css$8.list, dense && css$8.denseList, compact && css$8.compactList, scrollable && css$8.scrollable, portal && css$8.portal, side === "top" && !portal && css$8.sideTop, align === "end" && !portal && css$8.alignEnd),
|
|
1923
2198
|
style: portal ? fixedPos ?? MEASURE_STYLE : void 0,
|
|
1924
2199
|
role: "menu",
|
|
1925
2200
|
onClick: (e) => {
|
|
1926
2201
|
e.stopPropagation();
|
|
1927
2202
|
},
|
|
1928
2203
|
children: [jsx("div", {
|
|
1929
|
-
className: css$
|
|
2204
|
+
className: css$8.viewport,
|
|
1930
2205
|
role: "presentation",
|
|
1931
2206
|
children: items.map(renderEntry)
|
|
1932
2207
|
}), footer !== void 0 && footer.length > 0 && jsx("div", {
|
|
1933
|
-
className: css$
|
|
2208
|
+
className: css$8.footer,
|
|
1934
2209
|
role: "presentation",
|
|
1935
2210
|
children: footer.map(renderEntry)
|
|
1936
2211
|
})]
|
|
1937
2212
|
});
|
|
1938
2213
|
return jsxs("span", {
|
|
1939
2214
|
ref: rootRef,
|
|
1940
|
-
className: clsx(css$
|
|
2215
|
+
className: clsx(css$8.root, className),
|
|
1941
2216
|
onPointerEnter: closeOnPointerLeave ? cancelClose : void 0,
|
|
1942
2217
|
onPointerLeave: closeOnPointerLeave ? () => {
|
|
1943
2218
|
if (open) armClose();
|
|
@@ -2237,7 +2512,7 @@ function HoverCard({ anchor, content, openDelayMs = 500, disabled = false, copyT
|
|
|
2237
2512
|
const copyable = copyText !== void 0;
|
|
2238
2513
|
const card = open && pos !== null && jsx("div", {
|
|
2239
2514
|
ref: cardRef,
|
|
2240
|
-
className: `${css$
|
|
2515
|
+
className: `${css$9.card}${copyable ? ` ${css$9.copyable}` : ""}${copied ? ` ${css$9.feedback}` : ""}`,
|
|
2241
2516
|
style: {
|
|
2242
2517
|
...pos,
|
|
2243
2518
|
minHeight: copied && copyHeightRef.current !== null ? copyHeightRef.current : void 0
|
|
@@ -2258,14 +2533,14 @@ function HoverCard({ anchor, content, openDelayMs = 500, disabled = false, copyT
|
|
|
2258
2533
|
copy(copyText);
|
|
2259
2534
|
} : void 0,
|
|
2260
2535
|
children: copied ? jsx("span", {
|
|
2261
|
-
className: css$
|
|
2536
|
+
className: css$9.copied,
|
|
2262
2537
|
"aria-hidden": "true",
|
|
2263
2538
|
children: copiedLabel
|
|
2264
2539
|
}) : content
|
|
2265
2540
|
});
|
|
2266
2541
|
return jsxs("span", {
|
|
2267
2542
|
ref: rootRef,
|
|
2268
|
-
className: css$
|
|
2543
|
+
className: css$9.root,
|
|
2269
2544
|
onPointerEnter: () => {
|
|
2270
2545
|
if (disabled) return;
|
|
2271
2546
|
cancelClose();
|
|
@@ -2288,7 +2563,7 @@ function HoverCard({ anchor, content, openDelayMs = 500, disabled = false, copyT
|
|
|
2288
2563
|
children: [
|
|
2289
2564
|
anchor,
|
|
2290
2565
|
open && copyable && jsx("span", {
|
|
2291
|
-
className: css$
|
|
2566
|
+
className: css$9.status,
|
|
2292
2567
|
role: "status",
|
|
2293
2568
|
children: copied ? copiedLabel : ""
|
|
2294
2569
|
}),
|
|
@@ -2301,7 +2576,8 @@ function HoverCard({ anchor, content, openDelayMs = 500, disabled = false, copyT
|
|
|
2301
2576
|
/**
|
|
2302
2577
|
* Render a centered, body-portaled modal over a blurred page mask.
|
|
2303
2578
|
* @param props.open - whether the dialog is showing.
|
|
2304
|
-
* @param props.onClose - Escape or mask click
|
|
2579
|
+
* @param props.onClose - Escape or mask click; while a menu is open inside the
|
|
2580
|
+
* dialog, Escape belongs to that menu first.
|
|
2305
2581
|
* @param props.title - dialog heading (aria-label in every mode).
|
|
2306
2582
|
* @param props.closeLabel - localized accessible close-button label.
|
|
2307
2583
|
* @param props.description - optional supporting sentence under the title.
|
|
@@ -2325,44 +2601,44 @@ function Modal({ open, onClose, title, closeLabel, description, children, footer
|
|
|
2325
2601
|
}, [open, onClose]);
|
|
2326
2602
|
if (!open) return null;
|
|
2327
2603
|
return createPortal(jsxs("div", {
|
|
2328
|
-
className: css$
|
|
2604
|
+
className: css$10.root,
|
|
2329
2605
|
role: "presentation",
|
|
2330
2606
|
children: [jsx("div", {
|
|
2331
|
-
className: css$
|
|
2607
|
+
className: css$10.mask,
|
|
2332
2608
|
"aria-hidden": "true",
|
|
2333
2609
|
onClick: onClose
|
|
2334
2610
|
}), jsx("div", {
|
|
2335
|
-
className: clsx(css$
|
|
2611
|
+
className: clsx(css$10.dialog, className),
|
|
2336
2612
|
role: "dialog",
|
|
2337
2613
|
"aria-modal": "true",
|
|
2338
2614
|
"aria-label": title,
|
|
2339
2615
|
children: headless ? children : jsxs(Fragment, { children: [jsxs("div", {
|
|
2340
|
-
className: clsx(css$
|
|
2616
|
+
className: clsx(css$10.content, contentClassName),
|
|
2341
2617
|
children: [
|
|
2342
2618
|
jsxs("div", {
|
|
2343
|
-
className: css$
|
|
2619
|
+
className: css$10.header,
|
|
2344
2620
|
children: [jsx("h2", {
|
|
2345
|
-
className: css$
|
|
2621
|
+
className: css$10.title,
|
|
2346
2622
|
children: title
|
|
2347
2623
|
}), jsx("button", {
|
|
2348
2624
|
type: "button",
|
|
2349
|
-
className: css$
|
|
2625
|
+
className: css$10.close,
|
|
2350
2626
|
"aria-label": closeLabel,
|
|
2351
2627
|
onClick: onClose,
|
|
2352
2628
|
children: jsx(IconCloseOutline16, { size: 14 })
|
|
2353
2629
|
})]
|
|
2354
2630
|
}),
|
|
2355
2631
|
description !== void 0 && description !== "" && jsx("p", {
|
|
2356
|
-
className: css$
|
|
2632
|
+
className: css$10.description,
|
|
2357
2633
|
children: description
|
|
2358
2634
|
}),
|
|
2359
2635
|
children !== void 0 && jsx("div", {
|
|
2360
|
-
className: css$
|
|
2636
|
+
className: css$10.body,
|
|
2361
2637
|
children
|
|
2362
2638
|
})
|
|
2363
2639
|
]
|
|
2364
2640
|
}), footer !== void 0 && jsx("div", {
|
|
2365
|
-
className: css$
|
|
2641
|
+
className: css$10.footer,
|
|
2366
2642
|
children: footer
|
|
2367
2643
|
})] })
|
|
2368
2644
|
})]
|
|
@@ -2386,13 +2662,13 @@ function OnboardingSurface({ children }) {
|
|
|
2386
2662
|
};
|
|
2387
2663
|
}, []);
|
|
2388
2664
|
return createPortal(jsxs("div", {
|
|
2389
|
-
className: css$
|
|
2665
|
+
className: css$11.onboardingOverlay,
|
|
2390
2666
|
role: "presentation",
|
|
2391
2667
|
children: [jsx("div", {
|
|
2392
|
-
className: css$
|
|
2668
|
+
className: css$11.onboardingMask,
|
|
2393
2669
|
"aria-hidden": "true"
|
|
2394
2670
|
}), jsx("div", {
|
|
2395
|
-
className: css$
|
|
2671
|
+
className: css$11.onboardingStage,
|
|
2396
2672
|
children
|
|
2397
2673
|
})]
|
|
2398
2674
|
}), document.body);
|
|
@@ -2413,28 +2689,28 @@ function RiskConfirmation({ open, title, description, acknowledgeLabel, cancelLa
|
|
|
2413
2689
|
onClose: onCancel,
|
|
2414
2690
|
title,
|
|
2415
2691
|
closeLabel,
|
|
2416
|
-
className: css$
|
|
2417
|
-
contentClassName: css$
|
|
2692
|
+
className: css$12.confirmation ?? "",
|
|
2693
|
+
contentClassName: css$12.confirmationContent ?? "",
|
|
2418
2694
|
footer: jsxs(Fragment, { children: [jsx(Button, {
|
|
2419
2695
|
variant: "outline",
|
|
2420
|
-
className: css$
|
|
2696
|
+
className: css$12.modalAction,
|
|
2421
2697
|
onClick: onCancel,
|
|
2422
2698
|
children: cancelLabel
|
|
2423
2699
|
}), jsx(Button, {
|
|
2424
2700
|
variant: "primary",
|
|
2425
|
-
className: css$
|
|
2701
|
+
className: css$12.confirmAction,
|
|
2426
2702
|
disabled: disabled || !acknowledged,
|
|
2427
2703
|
onClick: onConfirm,
|
|
2428
2704
|
children: confirmLabel
|
|
2429
2705
|
})] }),
|
|
2430
2706
|
children: [jsxs("div", {
|
|
2431
|
-
className: css$
|
|
2707
|
+
className: css$12.warning,
|
|
2432
2708
|
children: [jsx(IconWarningOutline16, {
|
|
2433
2709
|
size: 18,
|
|
2434
|
-
className: css$
|
|
2710
|
+
className: css$12.warningIcon
|
|
2435
2711
|
}), jsx("p", { children: description })]
|
|
2436
2712
|
}), jsxs("label", {
|
|
2437
|
-
className: css$
|
|
2713
|
+
className: css$12.acknowledgement,
|
|
2438
2714
|
children: [jsx("input", {
|
|
2439
2715
|
type: "checkbox",
|
|
2440
2716
|
checked: acknowledged,
|
|
@@ -2449,11 +2725,15 @@ function RiskConfirmation({ open, title, description, acknowledgeLabel, cancelLa
|
|
|
2449
2725
|
}
|
|
2450
2726
|
//#endregion
|
|
2451
2727
|
//#region lib/types/ConnectionIndicator.js
|
|
2728
|
+
/** Exit-transition length; keep equal to the `.leaving` transition duration in the stylesheet. */
|
|
2729
|
+
const EXIT_MS = 150;
|
|
2452
2730
|
/**
|
|
2453
|
-
* Render an inline connection-recovery control.
|
|
2731
|
+
* Render an inline connection-recovery control. The outage and retry-attempt
|
|
2732
|
+
* states are one button whose static label already names the retry action;
|
|
2733
|
+
* clicking it requests an immediate reconnect. The indicator animates in on
|
|
2734
|
+
* appearance and fades out for {@link EXIT_MS} before unmounting.
|
|
2454
2735
|
* @param props.state - visible outage, retry-attempt, or recovered state.
|
|
2455
|
-
* @param props.disconnectedLabel - localized outage text.
|
|
2456
|
-
* @param props.reconnectLabel - localized action text shown on hover or focus.
|
|
2736
|
+
* @param props.disconnectedLabel - localized outage text naming the retry action.
|
|
2457
2737
|
* @param props.connectingLabel - localized retry text followed by the attempt dots.
|
|
2458
2738
|
* @param props.recoveredLabel - localized recovery confirmation.
|
|
2459
2739
|
* @param props.reconnectActionLabel - accessible label for the outage action.
|
|
@@ -2461,87 +2741,68 @@ function RiskConfirmation({ open, title, description, acknowledgeLabel, cancelLa
|
|
|
2461
2741
|
* @param props.onReconnect - request an immediate reconnect attempt.
|
|
2462
2742
|
* @returns the indicator, or null when no connection feedback is active.
|
|
2463
2743
|
*/
|
|
2464
|
-
function ConnectionIndicator({ state, disconnectedLabel,
|
|
2465
|
-
|
|
2466
|
-
const
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
}
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
}),
|
|
2485
|
-
jsx("span", {
|
|
2486
|
-
className: css$12.sizeLabel,
|
|
2487
|
-
"aria-hidden": "true",
|
|
2488
|
-
children: recoveredLabel
|
|
2489
|
-
})
|
|
2490
|
-
] });
|
|
2491
|
-
if (state === "recovered") return jsxs("div", {
|
|
2492
|
-
className: `${css$12.indicator} ${css$12.success}`,
|
|
2744
|
+
function ConnectionIndicator({ state, disconnectedLabel, connectingLabel, recoveredLabel, reconnectActionLabel, restartActionLabel, onReconnect }) {
|
|
2745
|
+
const [rendered, setRendered] = useState(state);
|
|
2746
|
+
const leaving = state === void 0 && rendered !== void 0;
|
|
2747
|
+
useEffect(() => {
|
|
2748
|
+
if (state !== void 0) {
|
|
2749
|
+
setRendered(state);
|
|
2750
|
+
return;
|
|
2751
|
+
}
|
|
2752
|
+
if (rendered === void 0) return;
|
|
2753
|
+
const timeout = window.setTimeout(() => {
|
|
2754
|
+
setRendered(void 0);
|
|
2755
|
+
}, EXIT_MS);
|
|
2756
|
+
return () => {
|
|
2757
|
+
window.clearTimeout(timeout);
|
|
2758
|
+
};
|
|
2759
|
+
}, [state, rendered]);
|
|
2760
|
+
if (rendered === void 0) return null;
|
|
2761
|
+
const leavingClass = leaving ? ` ${css$13.leaving}` : "";
|
|
2762
|
+
if (rendered === "recovered") return jsxs("div", {
|
|
2763
|
+
className: `${css$13.indicator} ${css$13.success}${leavingClass}`,
|
|
2493
2764
|
role: "status",
|
|
2494
2765
|
"aria-label": recoveredLabel,
|
|
2495
2766
|
children: [jsx("span", {
|
|
2496
|
-
className: css$
|
|
2767
|
+
className: css$13.icon,
|
|
2497
2768
|
"aria-hidden": "true",
|
|
2498
2769
|
children: jsx(IconCheckOutline16, { size: 14 })
|
|
2499
|
-
}),
|
|
2500
|
-
className: css$
|
|
2501
|
-
children:
|
|
2502
|
-
className: css$12.stateLabel,
|
|
2503
|
-
children: recoveredLabel
|
|
2504
|
-
})]
|
|
2770
|
+
}), jsx("span", {
|
|
2771
|
+
className: css$13.label,
|
|
2772
|
+
children: recoveredLabel
|
|
2505
2773
|
})]
|
|
2506
2774
|
});
|
|
2507
|
-
const connecting =
|
|
2775
|
+
const connecting = rendered === "connecting";
|
|
2508
2776
|
return jsxs("button", {
|
|
2509
2777
|
type: "button",
|
|
2510
|
-
className: `${css$
|
|
2511
|
-
"data-phase":
|
|
2778
|
+
className: `${css$13.indicator} ${css$13.warning}${leavingClass}`,
|
|
2779
|
+
"data-phase": rendered,
|
|
2512
2780
|
"aria-label": connecting ? restartActionLabel : reconnectActionLabel,
|
|
2513
2781
|
onClick: onReconnect,
|
|
2514
2782
|
children: [jsx("span", {
|
|
2515
|
-
className: css$
|
|
2783
|
+
className: css$13.icon,
|
|
2516
2784
|
"aria-hidden": "true",
|
|
2517
|
-
children: jsx(
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
})] }) : disconnectedLabel
|
|
2539
|
-
}),
|
|
2540
|
-
jsx("span", {
|
|
2541
|
-
className: css$12.hoverLabel,
|
|
2542
|
-
children: reconnectLabel
|
|
2543
|
-
})
|
|
2544
|
-
]
|
|
2785
|
+
children: connecting ? jsx(IconLoadingOutline16, {
|
|
2786
|
+
size: 14,
|
|
2787
|
+
className: css$13.spinner
|
|
2788
|
+
}) : jsx(IconRefreshOutline14, { size: 14 })
|
|
2789
|
+
}), jsx("span", {
|
|
2790
|
+
className: css$13.label,
|
|
2791
|
+
children: connecting ? jsxs(Fragment, { children: [connectingLabel, jsxs("span", {
|
|
2792
|
+
className: css$13.dots,
|
|
2793
|
+
"aria-hidden": "true",
|
|
2794
|
+
children: [
|
|
2795
|
+
jsx("span", { children: "." }),
|
|
2796
|
+
jsx("span", {
|
|
2797
|
+
className: css$13.secondDot,
|
|
2798
|
+
children: "."
|
|
2799
|
+
}),
|
|
2800
|
+
jsx("span", {
|
|
2801
|
+
className: css$13.thirdDot,
|
|
2802
|
+
children: "."
|
|
2803
|
+
})
|
|
2804
|
+
]
|
|
2805
|
+
})] }) : disconnectedLabel
|
|
2545
2806
|
})]
|
|
2546
2807
|
});
|
|
2547
2808
|
}
|
|
@@ -3378,7 +3639,103 @@ function FileTypeIcon(props) {
|
|
|
3378
3639
|
type: resolvedType,
|
|
3379
3640
|
size,
|
|
3380
3641
|
className
|
|
3381
|
-
}) : glyph(resolvedType, size, clsx(css$
|
|
3642
|
+
}) : glyph(resolvedType, size, clsx(css$14.icon, css$14[resolvedType], className));
|
|
3643
|
+
}
|
|
3644
|
+
//#endregion
|
|
3645
|
+
//#region lib/types/SiteGlyph.js
|
|
3646
|
+
/**
|
|
3647
|
+
* Host suffix to site mark, covering the developer sites the transcript
|
|
3648
|
+
* usually cites plus the mainstream search, video, social, shopping, and
|
|
3649
|
+
* reference sites a general audience links. A host matches a suffix when it
|
|
3650
|
+
* equals it or is a subdomain of it, and the longest matching suffix wins, so
|
|
3651
|
+
* `weixin.qq.com` keeps WeChat while `qq.com` keeps QQ and `gist.github.com`
|
|
3652
|
+
* needs no entry of its own.
|
|
3653
|
+
*/
|
|
3654
|
+
const SITE_HOSTS = {
|
|
3655
|
+
"github.com": siGithub,
|
|
3656
|
+
"github.io": siGithub,
|
|
3657
|
+
"raw.githubusercontent.com": siGithub,
|
|
3658
|
+
"gitlab.com": siGitlab,
|
|
3659
|
+
"npmjs.com": siNpm,
|
|
3660
|
+
"pypi.org": siPypi,
|
|
3661
|
+
"stackoverflow.com": siStackoverflow,
|
|
3662
|
+
"developer.mozilla.org": siMdnwebdocs,
|
|
3663
|
+
"wikipedia.org": siWikipedia,
|
|
3664
|
+
"news.ycombinator.com": siYcombinator,
|
|
3665
|
+
"youtube.com": siYoutube,
|
|
3666
|
+
"youtu.be": siYoutube,
|
|
3667
|
+
"x.com": siX,
|
|
3668
|
+
"twitter.com": siX,
|
|
3669
|
+
"bilibili.com": siBilibili,
|
|
3670
|
+
"zhihu.com": siZhihu,
|
|
3671
|
+
"juejin.cn": siJuejin,
|
|
3672
|
+
"csdn.net": siCsdn,
|
|
3673
|
+
"google.com": siGoogle,
|
|
3674
|
+
"baidu.com": siBaidu,
|
|
3675
|
+
"duckduckgo.com": siDuckduckgo,
|
|
3676
|
+
"tiktok.com": siTiktok,
|
|
3677
|
+
"netflix.com": siNetflix,
|
|
3678
|
+
"spotify.com": siSpotify,
|
|
3679
|
+
"facebook.com": siFacebook,
|
|
3680
|
+
"instagram.com": siInstagram,
|
|
3681
|
+
"reddit.com": siReddit,
|
|
3682
|
+
"telegram.org": siTelegram,
|
|
3683
|
+
"t.me": siTelegram,
|
|
3684
|
+
"weixin.qq.com": siWechat,
|
|
3685
|
+
"qq.com": siQq,
|
|
3686
|
+
"whatsapp.com": siWhatsapp,
|
|
3687
|
+
"wa.me": siWhatsapp,
|
|
3688
|
+
"weibo.com": siSinaweibo,
|
|
3689
|
+
"taobao.com": siTaobao,
|
|
3690
|
+
"aliexpress.com": siAliexpress,
|
|
3691
|
+
"ebay.com": siEbay,
|
|
3692
|
+
"quora.com": siQuora,
|
|
3693
|
+
"v2ex.com": siV2ex,
|
|
3694
|
+
"apple.com": siApple
|
|
3695
|
+
};
|
|
3696
|
+
/**
|
|
3697
|
+
* Resolve the mark named by an external destination.
|
|
3698
|
+
* @param href - The link destination; only an absolute http(s) URL can name a host.
|
|
3699
|
+
* @returns The matched site mark, or undefined when the host is unknown or not http(s).
|
|
3700
|
+
*/
|
|
3701
|
+
function siteIcon(href) {
|
|
3702
|
+
let host;
|
|
3703
|
+
try {
|
|
3704
|
+
const url = new URL(href);
|
|
3705
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return void 0;
|
|
3706
|
+
host = url.hostname.toLowerCase();
|
|
3707
|
+
} catch {
|
|
3708
|
+
return;
|
|
3709
|
+
}
|
|
3710
|
+
let match;
|
|
3711
|
+
let matched = 0;
|
|
3712
|
+
for (const [suffix, icon] of Object.entries(SITE_HOSTS)) if ((host === suffix || host.endsWith(`.${suffix}`)) && suffix.length > matched) {
|
|
3713
|
+
match = icon;
|
|
3714
|
+
matched = suffix.length;
|
|
3715
|
+
}
|
|
3716
|
+
return match;
|
|
3717
|
+
}
|
|
3718
|
+
/**
|
|
3719
|
+
* Render the site mark for a known external destination.
|
|
3720
|
+
* @param props - The destination and the icon sizing seat.
|
|
3721
|
+
* @returns The site's mark riding currentColor, or undefined for an unknown site.
|
|
3722
|
+
*/
|
|
3723
|
+
function siteGlyph({ href, size, className }) {
|
|
3724
|
+
const icon = href === void 0 ? void 0 : siteIcon(href);
|
|
3725
|
+
if (icon === void 0) return void 0;
|
|
3726
|
+
return jsx("svg", {
|
|
3727
|
+
width: size,
|
|
3728
|
+
height: size,
|
|
3729
|
+
className,
|
|
3730
|
+
viewBox: "-2 -2 28 28",
|
|
3731
|
+
fill: "none",
|
|
3732
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
3733
|
+
"aria-hidden": true,
|
|
3734
|
+
children: jsx("path", {
|
|
3735
|
+
d: icon.path,
|
|
3736
|
+
fill: "currentColor"
|
|
3737
|
+
})
|
|
3738
|
+
});
|
|
3382
3739
|
}
|
|
3383
3740
|
//#endregion
|
|
3384
3741
|
//#region lib/types/LinkIcon.js
|
|
@@ -3525,13 +3882,18 @@ function assertNever$1(value) {
|
|
|
3525
3882
|
}
|
|
3526
3883
|
/**
|
|
3527
3884
|
* Render the leading glyph for one clickable artifact link.
|
|
3528
|
-
* @param props - The link category, optional
|
|
3529
|
-
*
|
|
3885
|
+
* @param props - The link category, the optional destination that can select a
|
|
3886
|
+
* site mark, optional size (default 14px — the inline link text size these
|
|
3887
|
+
* glyphs sit beside), and optional CSS class.
|
|
3530
3888
|
* @returns The category's SVG glyph, riding currentColor.
|
|
3531
3889
|
*/
|
|
3532
|
-
function LinkIcon({ kind, size = 14, className }) {
|
|
3890
|
+
function LinkIcon({ kind, href, size = 14, className }) {
|
|
3533
3891
|
switch (kind) {
|
|
3534
|
-
case "url": return
|
|
3892
|
+
case "url": return siteGlyph({
|
|
3893
|
+
href,
|
|
3894
|
+
size,
|
|
3895
|
+
className
|
|
3896
|
+
}) ?? jsx(GlobeGlyph, {
|
|
3535
3897
|
size,
|
|
3536
3898
|
className
|
|
3537
3899
|
});
|
|
@@ -3573,9 +3935,10 @@ const TRAILING_PUNCTUATION_RE = /[.,;:!?,。;:!?]+$/u;
|
|
|
3573
3935
|
* host loaded for this message, or the command a command bubble echoes
|
|
3574
3936
|
* (unsent queue rows pass none).
|
|
3575
3937
|
* @param slashKind - the chip kind those tokens render as.
|
|
3938
|
+
* @param references - optional file and skill preview actions; session and command tokens stay labels.
|
|
3576
3939
|
* @returns inline nodes covering the whole text.
|
|
3577
3940
|
*/
|
|
3578
|
-
function projectUserText(text, sessionLabels, slashNames = [], slashKind = "skill") {
|
|
3941
|
+
function projectUserText(text, sessionLabels, slashNames = [], slashKind = "skill", references) {
|
|
3579
3942
|
const ranges = [];
|
|
3580
3943
|
SESSION_WIRE_RE.lastIndex = 0;
|
|
3581
3944
|
let wire;
|
|
@@ -3620,7 +3983,7 @@ function projectUserText(text, sessionLabels, slashNames = [], slashKind = "skil
|
|
|
3620
3983
|
let cursor = 0;
|
|
3621
3984
|
const pushPlain = (from, to) => {
|
|
3622
3985
|
parts.push(jsx("span", {
|
|
3623
|
-
className: css$
|
|
3986
|
+
className: css$15.plainRun,
|
|
3624
3987
|
children: text.slice(from, to)
|
|
3625
3988
|
}, `t${from}`));
|
|
3626
3989
|
};
|
|
@@ -3628,22 +3991,39 @@ function projectUserText(text, sessionLabels, slashNames = [], slashKind = "skil
|
|
|
3628
3991
|
if (range.start < cursor) continue;
|
|
3629
3992
|
const { start: tokenStart, end, label, kind } = range;
|
|
3630
3993
|
if (tokenStart > cursor) pushPlain(cursor, tokenStart);
|
|
3631
|
-
const referenceKind = kind === "session" ? "session" : label.startsWith("@") ? label.endsWith("/") ? "folder" : "file" : void 0;
|
|
3994
|
+
const referenceKind = kind === "session" ? "session" : label.startsWith("@") ? label.replace(/^@"|"$/gu, "").endsWith("/") ? "folder" : "file" : void 0;
|
|
3632
3995
|
const displayLabel = range.display ?? (referenceKind === void 0 ? label : referenceKind === "session" ? label.slice(1) : label.slice(1).replace(/^"|"$/gu, "").split(/[\\/]/u).filter(Boolean).at(-1) ?? label.slice(1));
|
|
3633
|
-
|
|
3634
|
-
|
|
3996
|
+
const contents = jsxs(Fragment, { children: [referenceKind !== void 0 && jsx(ReferenceIcon, {
|
|
3997
|
+
kind: referenceKind,
|
|
3998
|
+
size: 16,
|
|
3999
|
+
className: css$15.refIcon
|
|
4000
|
+
}), displayLabel] });
|
|
4001
|
+
const open = references === void 0 ? void 0 : referenceKind === "file" ? () => {
|
|
4002
|
+
references.openFile(label.slice(1).replace(/^"|"$/gu, ""));
|
|
4003
|
+
} : referenceKind === void 0 && slashKind === "skill" ? () => {
|
|
4004
|
+
references.openSkill(label.slice(1));
|
|
4005
|
+
} : void 0;
|
|
4006
|
+
const className = clsx(css$15.refChip, referenceKind === void 0 && css$15.slashChip);
|
|
4007
|
+
parts.push(open === void 0 ? jsx("span", {
|
|
4008
|
+
className,
|
|
4009
|
+
"data-ref-chip": referenceKind ?? slashKind,
|
|
4010
|
+
title: label,
|
|
4011
|
+
children: contents
|
|
4012
|
+
}, tokenStart) : jsx("button", {
|
|
4013
|
+
type: "button",
|
|
4014
|
+
className: clsx(className, markdownCss.fileMention),
|
|
3635
4015
|
"data-ref-chip": referenceKind ?? slashKind,
|
|
3636
4016
|
title: label,
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
4017
|
+
onClick: (event) => {
|
|
4018
|
+
if (event.detail > 1 || event.detail !== 0 && event.currentTarget.ownerDocument.getSelection()?.isCollapsed === false) return;
|
|
4019
|
+
open();
|
|
4020
|
+
},
|
|
4021
|
+
children: contents
|
|
3642
4022
|
}, tokenStart));
|
|
3643
4023
|
cursor = end;
|
|
3644
4024
|
}
|
|
3645
4025
|
if (parts.length === 0) return jsx("span", {
|
|
3646
|
-
className: css$
|
|
4026
|
+
className: css$15.plainRun,
|
|
3647
4027
|
children: text
|
|
3648
4028
|
});
|
|
3649
4029
|
if (cursor < text.length) pushPlain(cursor, text.length);
|
|
@@ -3652,6 +4032,12 @@ function projectUserText(text, sessionLabels, slashNames = [], slashKind = "skil
|
|
|
3652
4032
|
//#endregion
|
|
3653
4033
|
//#region lib/types/Tooltip.js
|
|
3654
4034
|
/**
|
|
4035
|
+
* Suppression channel from a tooltip to the tooltips above it: a tooltip hands
|
|
4036
|
+
* this setter to its own descendants, and a visible descendant bubble calls it
|
|
4037
|
+
* so the ancestor withdraws its bubble for as long as the descendant shows one.
|
|
4038
|
+
*/
|
|
4039
|
+
const TooltipSuppression = createContext(null);
|
|
4040
|
+
/**
|
|
3655
4041
|
* Attach a hover/focus tooltip to an anchor element.
|
|
3656
4042
|
* @param props.label - bubble text, or a resolver evaluated only while the bubble is visible.
|
|
3657
4043
|
* @param props.side - placement relative to the anchor (default 'right').
|
|
@@ -3711,6 +4097,18 @@ function Tooltip({ label, side = "right", delayMs = 0, disabled = false, maxWidt
|
|
|
3711
4097
|
hover: false,
|
|
3712
4098
|
focus: false
|
|
3713
4099
|
});
|
|
4100
|
+
const suppressAncestors = useContext(TooltipSuppression);
|
|
4101
|
+
const [suppressed, setSuppressed] = useState(false);
|
|
4102
|
+
const announce = useCallback((active) => {
|
|
4103
|
+
suppressAncestors?.(active);
|
|
4104
|
+
}, [suppressAncestors]);
|
|
4105
|
+
const visible = pos !== null && !disabled;
|
|
4106
|
+
useEffect(() => {
|
|
4107
|
+
announce(visible);
|
|
4108
|
+
return () => {
|
|
4109
|
+
announce(false);
|
|
4110
|
+
};
|
|
4111
|
+
}, [announce, visible]);
|
|
3714
4112
|
const cancelShow = useCallback(() => {
|
|
3715
4113
|
if (showTimer.current === null) return;
|
|
3716
4114
|
clearTimeout(showTimer.current);
|
|
@@ -3739,6 +4137,7 @@ function Tooltip({ label, side = "right", delayMs = 0, disabled = false, maxWidt
|
|
|
3739
4137
|
top: r.top,
|
|
3740
4138
|
bottom: r.bottom
|
|
3741
4139
|
});
|
|
4140
|
+
announce(true);
|
|
3742
4141
|
};
|
|
3743
4142
|
const showAfterHoverDelay = () => {
|
|
3744
4143
|
cancelShow();
|
|
@@ -3751,46 +4150,53 @@ function Tooltip({ label, side = "right", delayMs = 0, disabled = false, maxWidt
|
|
|
3751
4150
|
show();
|
|
3752
4151
|
}, delayMs);
|
|
3753
4152
|
};
|
|
4153
|
+
const withdraw = () => {
|
|
4154
|
+
setPos(null);
|
|
4155
|
+
announce(false);
|
|
4156
|
+
};
|
|
3754
4157
|
const hide = () => {
|
|
3755
4158
|
cancelShow();
|
|
3756
|
-
if (!triggers.current.hover && !triggers.current.focus)
|
|
4159
|
+
if (!triggers.current.hover && !triggers.current.focus) withdraw();
|
|
3757
4160
|
};
|
|
3758
|
-
return jsxs(
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
4161
|
+
return jsxs(TooltipSuppression.Provider, {
|
|
4162
|
+
value: setSuppressed,
|
|
4163
|
+
children: [cloneElement(children, {
|
|
4164
|
+
ref: mergedRef,
|
|
4165
|
+
onMouseEnter: (e) => {
|
|
4166
|
+
children.props.onMouseEnter?.(e);
|
|
4167
|
+
triggers.current.hover = true;
|
|
4168
|
+
showAfterHoverDelay();
|
|
4169
|
+
},
|
|
4170
|
+
onMouseLeave: (e) => {
|
|
4171
|
+
children.props.onMouseLeave?.(e);
|
|
4172
|
+
triggers.current.hover = false;
|
|
4173
|
+
cancelShow();
|
|
4174
|
+
withdraw();
|
|
4175
|
+
},
|
|
4176
|
+
onFocus: (e) => {
|
|
4177
|
+
children.props.onFocus?.(e);
|
|
4178
|
+
triggers.current.focus = true;
|
|
4179
|
+
cancelShow();
|
|
4180
|
+
show();
|
|
4181
|
+
},
|
|
4182
|
+
onBlur: (e) => {
|
|
4183
|
+
children.props.onBlur?.(e);
|
|
4184
|
+
triggers.current.focus = false;
|
|
4185
|
+
hide();
|
|
4186
|
+
}
|
|
4187
|
+
}), visible && !suppressed && jsx("span", {
|
|
4188
|
+
ref: bubble,
|
|
4189
|
+
className: css$16.bubble,
|
|
4190
|
+
"data-side": placement,
|
|
4191
|
+
style: {
|
|
4192
|
+
left: pos.x,
|
|
4193
|
+
top: y,
|
|
4194
|
+
...maxWidth === void 0 ? {} : { maxWidth }
|
|
4195
|
+
},
|
|
4196
|
+
role: "tooltip",
|
|
4197
|
+
children: resolvedLabel
|
|
4198
|
+
})]
|
|
4199
|
+
});
|
|
3794
4200
|
}
|
|
3795
4201
|
//#endregion
|
|
3796
4202
|
//#region lib/types/Toast.js
|
|
@@ -3842,18 +4248,18 @@ function Toast({ text, icon, anchor, holdMs = HOLD_MS, onDone }) {
|
|
|
3842
4248
|
};
|
|
3843
4249
|
}, [anchor]);
|
|
3844
4250
|
return createPortal(jsxs("div", {
|
|
3845
|
-
className: css$
|
|
4251
|
+
className: css$17.toast,
|
|
3846
4252
|
role: "alert",
|
|
3847
4253
|
style: {
|
|
3848
4254
|
...left === null ? {} : { left },
|
|
3849
4255
|
"--dsh-toast-hold": `${String(holdMs)}ms`
|
|
3850
4256
|
},
|
|
3851
4257
|
children: [icon !== void 0 && jsx("span", {
|
|
3852
|
-
className: css$
|
|
4258
|
+
className: css$17.icon,
|
|
3853
4259
|
"aria-hidden": true,
|
|
3854
4260
|
children: icon
|
|
3855
4261
|
}), jsx("span", {
|
|
3856
|
-
className: css$
|
|
4262
|
+
className: css$17.text,
|
|
3857
4263
|
children: text
|
|
3858
4264
|
})]
|
|
3859
4265
|
}), document.body);
|
|
@@ -3925,9 +4331,10 @@ function relativeTime(at, now) {
|
|
|
3925
4331
|
//#region lib/types/rank-by-name.js
|
|
3926
4332
|
/**
|
|
3927
4333
|
* Shared ranking for `/` menu candidates: the query must be a
|
|
3928
|
-
* case-insensitive ordered subsequence of the candidate name
|
|
3929
|
-
*
|
|
3930
|
-
* the
|
|
4334
|
+
* case-insensitive ordered subsequence of the candidate name or, when the
|
|
4335
|
+
* candidate carries one, of its display label (a localized title). Prefix
|
|
4336
|
+
* hits rank first, then the strongest alignment score over either key, then
|
|
4337
|
+
* the source order of the input. Decision record:
|
|
3931
4338
|
* .agents/notes/archived/feature/2026-08-04-web-slash-command-fuzzy-discovery.md
|
|
3932
4339
|
*/
|
|
3933
4340
|
/** Extra weight for name starts and separator boundaries. */
|
|
@@ -3969,7 +4376,9 @@ function alignmentScore(name, query) {
|
|
|
3969
4376
|
}
|
|
3970
4377
|
/**
|
|
3971
4378
|
* Rank named items by a menu query.
|
|
3972
|
-
* @param items - candidates in source order (a host catalog, then client
|
|
4379
|
+
* @param items - candidates in source order (a host catalog, then client
|
|
4380
|
+
* contributions); an item's optional `label` is a second search key beside
|
|
4381
|
+
* its name.
|
|
3973
4382
|
* @param rawQuery - the text typed after the trigger, matched case-insensitively.
|
|
3974
4383
|
* @returns the matching items: prefix hits first, then by alignment score,
|
|
3975
4384
|
* then in source order. The input list itself for an empty query.
|
|
@@ -3979,12 +4388,20 @@ function rankByName(items, rawQuery) {
|
|
|
3979
4388
|
if (query === "") return items;
|
|
3980
4389
|
const ranked = [];
|
|
3981
4390
|
items.forEach((item, index) => {
|
|
3982
|
-
const
|
|
3983
|
-
|
|
4391
|
+
const keys = item.label === void 0 ? [item.name] : [item.name, item.label];
|
|
4392
|
+
let prefix = false;
|
|
4393
|
+
let score;
|
|
4394
|
+
for (const key of keys) {
|
|
4395
|
+
const lower = key.toLowerCase();
|
|
4396
|
+
const keyScore = alignmentScore(lower, query);
|
|
4397
|
+
if (keyScore === void 0) continue;
|
|
4398
|
+
prefix ||= lower.startsWith(query);
|
|
4399
|
+
score = score === void 0 ? keyScore : Math.max(score, keyScore);
|
|
4400
|
+
}
|
|
3984
4401
|
if (score !== void 0) ranked.push({
|
|
3985
4402
|
item,
|
|
3986
4403
|
index,
|
|
3987
|
-
prefix
|
|
4404
|
+
prefix,
|
|
3988
4405
|
score
|
|
3989
4406
|
});
|
|
3990
4407
|
});
|
|
@@ -3992,6 +4409,18 @@ function rankByName(items, rawQuery) {
|
|
|
3992
4409
|
return ranked.map((match) => match.item);
|
|
3993
4410
|
}
|
|
3994
4411
|
//#endregion
|
|
4412
|
+
//#region lib/types/darwin-desktop.js
|
|
4413
|
+
/** macOS desktop detection for hiddenInset-titlebar layout variants. */
|
|
4414
|
+
/**
|
|
4415
|
+
* Whether the client runs in the macOS desktop shell: the Electron preload
|
|
4416
|
+
* marks `<html>` with `data-platform="darwin"`; plain web never sets it.
|
|
4417
|
+
* Read at render time — the mark may arrive as late as DOMContentLoaded.
|
|
4418
|
+
* @returns true only inside the macOS Electron shell.
|
|
4419
|
+
*/
|
|
4420
|
+
function isDarwinDesktop() {
|
|
4421
|
+
return document.documentElement.dataset.platform === "darwin";
|
|
4422
|
+
}
|
|
4423
|
+
//#endregion
|
|
3995
4424
|
//#region lib/types/JsonTree.js
|
|
3996
4425
|
const OBJECT_PREVIEW_LIMIT = 4;
|
|
3997
4426
|
const ARRAY_PREVIEW_LIMIT = 5;
|
|
@@ -4028,6 +4457,80 @@ function objectCopyMenuItems(labels) {
|
|
|
4028
4457
|
}
|
|
4029
4458
|
];
|
|
4030
4459
|
}
|
|
4460
|
+
/** Notify only the old and new row actions; JSON values do not subscribe to hover state. */
|
|
4461
|
+
function createCopyStore() {
|
|
4462
|
+
let current;
|
|
4463
|
+
const listeners = /* @__PURE__ */ new Map();
|
|
4464
|
+
return {
|
|
4465
|
+
get: () => current,
|
|
4466
|
+
set(next) {
|
|
4467
|
+
const previous = current?.id;
|
|
4468
|
+
current = next;
|
|
4469
|
+
for (const id of new Set([previous, next?.id])) {
|
|
4470
|
+
if (id === void 0) continue;
|
|
4471
|
+
for (const listener of listeners.get(id) ?? []) listener();
|
|
4472
|
+
}
|
|
4473
|
+
},
|
|
4474
|
+
subscribe(id, listener) {
|
|
4475
|
+
let row = listeners.get(id);
|
|
4476
|
+
if (row === void 0) listeners.set(id, row = /* @__PURE__ */ new Set());
|
|
4477
|
+
row.add(listener);
|
|
4478
|
+
return () => {
|
|
4479
|
+
row.delete(listener);
|
|
4480
|
+
if (row.size === 0) listeners.delete(id);
|
|
4481
|
+
};
|
|
4482
|
+
}
|
|
4483
|
+
};
|
|
4484
|
+
}
|
|
4485
|
+
function JsonCopyAction({ store, target, persistent, labels, onCopy, onClose }) {
|
|
4486
|
+
const id = pathId(target.path);
|
|
4487
|
+
const subscribe = useCallback((listener) => store.subscribe(id, listener), [id, store]);
|
|
4488
|
+
const getSnapshot = () => {
|
|
4489
|
+
const current = store.get();
|
|
4490
|
+
return current?.id === id ? current : void 0;
|
|
4491
|
+
};
|
|
4492
|
+
const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
4493
|
+
const buttonRef = useRef(null);
|
|
4494
|
+
const state = snapshot?.state ?? "idle";
|
|
4495
|
+
const object = typeof target.value === "object" && target.value !== null;
|
|
4496
|
+
const copyTitle = state === "copied" ? labels.copied : state === "failed" ? labels.copyFailed : object ? labels.copyPrettyJson : labels.copyValue;
|
|
4497
|
+
return jsx("span", {
|
|
4498
|
+
className: css$18.copySlot,
|
|
4499
|
+
children: (persistent || snapshot !== void 0) && jsx(Menu, {
|
|
4500
|
+
open: snapshot?.menuOpen === true,
|
|
4501
|
+
compact: true,
|
|
4502
|
+
portal: true,
|
|
4503
|
+
align: "end",
|
|
4504
|
+
anchor: jsx("button", {
|
|
4505
|
+
ref: buttonRef,
|
|
4506
|
+
type: "button",
|
|
4507
|
+
className: css$18.actionButton,
|
|
4508
|
+
"data-json-copy-button": true,
|
|
4509
|
+
"data-state": state,
|
|
4510
|
+
"aria-label": copyTitle,
|
|
4511
|
+
title: labels.copyButtonTitle(copyTitle),
|
|
4512
|
+
onClick: () => void onCopy(target, object ? "prettyJson" : "value"),
|
|
4513
|
+
onContextMenu: (event) => {
|
|
4514
|
+
event.preventDefault();
|
|
4515
|
+
event.stopPropagation();
|
|
4516
|
+
store.set({
|
|
4517
|
+
id,
|
|
4518
|
+
target,
|
|
4519
|
+
state,
|
|
4520
|
+
menuOpen: true
|
|
4521
|
+
});
|
|
4522
|
+
},
|
|
4523
|
+
children: state === "copied" ? jsx(IconCheckOutline16, { size: 12 }) : jsx(IconCopyOutline16, { size: 12 })
|
|
4524
|
+
}),
|
|
4525
|
+
items: object ? objectCopyMenuItems(labels) : valueCopyMenuItems(labels),
|
|
4526
|
+
onSelect: (mode) => {
|
|
4527
|
+
onCopy(target, mode);
|
|
4528
|
+
},
|
|
4529
|
+
onClose,
|
|
4530
|
+
getAnchorRect: () => buttonRef.current.getBoundingClientRect()
|
|
4531
|
+
})
|
|
4532
|
+
});
|
|
4533
|
+
}
|
|
4031
4534
|
function isExpandableValue(value) {
|
|
4032
4535
|
return typeof value === "object" && value !== null && !(value instanceof Date);
|
|
4033
4536
|
}
|
|
@@ -4040,35 +4543,35 @@ function bracketOf(value) {
|
|
|
4040
4543
|
}
|
|
4041
4544
|
function previewPrimitive(value) {
|
|
4042
4545
|
if (value === null) return jsx("span", {
|
|
4043
|
-
className: css$
|
|
4546
|
+
className: css$18.keywordValue,
|
|
4044
4547
|
children: "null"
|
|
4045
4548
|
});
|
|
4046
4549
|
if (typeof value === "string") return jsx("span", {
|
|
4047
|
-
className: css$
|
|
4550
|
+
className: css$18.stringValue,
|
|
4048
4551
|
children: JSON.stringify(value)
|
|
4049
4552
|
});
|
|
4050
4553
|
if (typeof value === "number") return jsx("span", {
|
|
4051
|
-
className: css$
|
|
4554
|
+
className: css$18.numberValue,
|
|
4052
4555
|
children: String(value)
|
|
4053
4556
|
});
|
|
4054
4557
|
if (typeof value === "boolean") return jsx("span", {
|
|
4055
|
-
className: css$
|
|
4558
|
+
className: css$18.keywordValue,
|
|
4056
4559
|
children: String(value)
|
|
4057
4560
|
});
|
|
4058
4561
|
if (typeof value === "bigint") return jsx("span", {
|
|
4059
|
-
className: css$
|
|
4562
|
+
className: css$18.otherValue,
|
|
4060
4563
|
children: value.toString()
|
|
4061
4564
|
});
|
|
4062
4565
|
if (typeof value === "undefined") return jsx("span", {
|
|
4063
|
-
className: css$
|
|
4566
|
+
className: css$18.otherValue,
|
|
4064
4567
|
children: "undefined"
|
|
4065
4568
|
});
|
|
4066
4569
|
if (typeof value === "symbol") return jsx("span", {
|
|
4067
|
-
className: css$
|
|
4570
|
+
className: css$18.otherValue,
|
|
4068
4571
|
children: value.description ?? "Symbol"
|
|
4069
4572
|
});
|
|
4070
4573
|
if (typeof value === "function") return jsx("span", {
|
|
4071
|
-
className: css$
|
|
4574
|
+
className: css$18.otherValue,
|
|
4072
4575
|
children: value.name || "Function"
|
|
4073
4576
|
});
|
|
4074
4577
|
return null;
|
|
@@ -4082,71 +4585,71 @@ function previewValue(value, depth) {
|
|
|
4082
4585
|
const [open, close] = bracketOf(value);
|
|
4083
4586
|
return jsxs(Fragment, { children: [
|
|
4084
4587
|
jsx("span", {
|
|
4085
|
-
className: css$
|
|
4588
|
+
className: css$18.punctuation,
|
|
4086
4589
|
children: open
|
|
4087
4590
|
}),
|
|
4088
4591
|
depth >= PREVIEW_DEPTH_LIMIT ? jsx("span", {
|
|
4089
|
-
className: css$
|
|
4592
|
+
className: css$18.previewEllipsis,
|
|
4090
4593
|
children: "…"
|
|
4091
4594
|
}) : visible.map(([key, item], index) => jsxs("span", { children: [
|
|
4092
4595
|
index > 0 && jsx("span", {
|
|
4093
|
-
className: css$
|
|
4596
|
+
className: css$18.punctuation,
|
|
4094
4597
|
children: ", "
|
|
4095
4598
|
}),
|
|
4096
4599
|
!array && jsxs(Fragment, { children: [jsx("span", {
|
|
4097
|
-
className: css$
|
|
4600
|
+
className: css$18.previewProperty,
|
|
4098
4601
|
children: key
|
|
4099
4602
|
}), jsx("span", {
|
|
4100
|
-
className: css$
|
|
4603
|
+
className: css$18.punctuation,
|
|
4101
4604
|
children: ": "
|
|
4102
4605
|
})] }),
|
|
4103
4606
|
previewValue(item, depth + 1)
|
|
4104
4607
|
] }, key)),
|
|
4105
4608
|
depth < PREVIEW_DEPTH_LIMIT && entries.length > limit && jsx("span", {
|
|
4106
|
-
className: css$
|
|
4609
|
+
className: css$18.previewEllipsis,
|
|
4107
4610
|
children: ", …"
|
|
4108
4611
|
}),
|
|
4109
4612
|
jsx("span", {
|
|
4110
|
-
className: css$
|
|
4613
|
+
className: css$18.punctuation,
|
|
4111
4614
|
children: close
|
|
4112
4615
|
})
|
|
4113
4616
|
] });
|
|
4114
4617
|
}
|
|
4115
4618
|
function primitiveValue(value) {
|
|
4116
4619
|
if (value === null) return jsx("span", {
|
|
4117
|
-
className: css$
|
|
4620
|
+
className: css$18.keywordValue,
|
|
4118
4621
|
children: "null"
|
|
4119
4622
|
});
|
|
4120
4623
|
if (typeof value === "string") return jsx("span", {
|
|
4121
|
-
className: css$
|
|
4624
|
+
className: css$18.stringValue,
|
|
4122
4625
|
children: JSON.stringify(value)
|
|
4123
4626
|
});
|
|
4124
4627
|
if (typeof value === "boolean") return jsx("span", {
|
|
4125
|
-
className: css$
|
|
4628
|
+
className: css$18.keywordValue,
|
|
4126
4629
|
children: String(value)
|
|
4127
4630
|
});
|
|
4128
4631
|
if (typeof value === "number") return jsx("span", {
|
|
4129
|
-
className: css$
|
|
4632
|
+
className: css$18.numberValue,
|
|
4130
4633
|
children: String(value)
|
|
4131
4634
|
});
|
|
4132
4635
|
if (typeof value === "bigint") return jsx("span", {
|
|
4133
|
-
className: css$
|
|
4636
|
+
className: css$18.numberValue,
|
|
4134
4637
|
children: `${value.toString()}n`
|
|
4135
4638
|
});
|
|
4136
4639
|
if (value instanceof Date) return jsx("span", {
|
|
4137
|
-
className: css$
|
|
4640
|
+
className: css$18.otherValue,
|
|
4138
4641
|
children: value.toISOString()
|
|
4139
4642
|
});
|
|
4140
4643
|
if (typeof value === "function") return jsxs("span", {
|
|
4141
|
-
className: css$
|
|
4644
|
+
className: css$18.otherValue,
|
|
4142
4645
|
children: ["function() ", "{ }"]
|
|
4143
4646
|
});
|
|
4144
4647
|
if (typeof value === "undefined") return jsx("span", {
|
|
4145
|
-
className: css$
|
|
4648
|
+
className: css$18.otherValue,
|
|
4146
4649
|
children: "undefined"
|
|
4147
4650
|
});
|
|
4148
4651
|
return jsx("span", {
|
|
4149
|
-
className: css$
|
|
4652
|
+
className: css$18.otherValue,
|
|
4150
4653
|
children: value.toString()
|
|
4151
4654
|
});
|
|
4152
4655
|
}
|
|
@@ -4174,12 +4677,177 @@ function moveFocus(button, direction) {
|
|
|
4174
4677
|
function NodeField({ field, expandable, onToggle }) {
|
|
4175
4678
|
if (field === void 0) return null;
|
|
4176
4679
|
return jsxs("span", {
|
|
4177
|
-
className: clsx(css$
|
|
4680
|
+
className: clsx(css$18.label, expandable && css$18.clickableLabel),
|
|
4178
4681
|
onClick: expandable ? onToggle : void 0,
|
|
4179
4682
|
children: [fieldText(field), ":"]
|
|
4180
4683
|
});
|
|
4181
4684
|
}
|
|
4182
|
-
function
|
|
4685
|
+
function JsonString({ collapsedStringLines, stringWrapping, field, labels, lastElement, renderCopy, value }) {
|
|
4686
|
+
const contentsId = useId();
|
|
4687
|
+
const contentRef = useRef(null);
|
|
4688
|
+
const rawRef = useRef(null);
|
|
4689
|
+
const [expanded, setExpanded] = useState(false);
|
|
4690
|
+
const [wrapped, setWrapped] = useState(false);
|
|
4691
|
+
const [truncated, setTruncated] = useState(false);
|
|
4692
|
+
useLayoutEffect(() => {
|
|
4693
|
+
if (expanded) return;
|
|
4694
|
+
const content = contentRef.current;
|
|
4695
|
+
const measure = () => {
|
|
4696
|
+
const lineHeight = Number.parseFloat(getComputedStyle(content).lineHeight);
|
|
4697
|
+
setTruncated(content.scrollHeight > lineHeight * collapsedStringLines);
|
|
4698
|
+
};
|
|
4699
|
+
measure();
|
|
4700
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
4701
|
+
const observer = new ResizeObserver(measure);
|
|
4702
|
+
observer.observe(content);
|
|
4703
|
+
return () => {
|
|
4704
|
+
observer.disconnect();
|
|
4705
|
+
};
|
|
4706
|
+
}, [
|
|
4707
|
+
collapsedStringLines,
|
|
4708
|
+
expanded,
|
|
4709
|
+
field,
|
|
4710
|
+
lastElement,
|
|
4711
|
+
value
|
|
4712
|
+
]);
|
|
4713
|
+
useLayoutEffect(() => {
|
|
4714
|
+
if (!expanded) return;
|
|
4715
|
+
const raw = rawRef.current;
|
|
4716
|
+
const clips = [];
|
|
4717
|
+
const tree = raw.closest(`.${css$18.root}`);
|
|
4718
|
+
for (let parent = tree.parentElement; parent !== null; parent = parent.parentElement) if (/auto|scroll|hidden|clip/.test(getComputedStyle(parent).overflowY)) clips.push(parent);
|
|
4719
|
+
const measure = () => {
|
|
4720
|
+
let top = 0;
|
|
4721
|
+
let bottom = window.innerHeight;
|
|
4722
|
+
for (const clip of clips) {
|
|
4723
|
+
const rect = clip.getBoundingClientRect();
|
|
4724
|
+
const style = getComputedStyle(clip);
|
|
4725
|
+
top = Math.max(top, rect.top + clip.clientTop);
|
|
4726
|
+
bottom = Math.min(bottom, rect.top + clip.clientTop + clip.clientHeight - Number.parseFloat(style.paddingBottom));
|
|
4727
|
+
}
|
|
4728
|
+
const available = bottom - Math.max(top, raw.getBoundingClientRect().top);
|
|
4729
|
+
raw.style.maxHeight = `${Math.max(16, available - 4)}px`;
|
|
4730
|
+
};
|
|
4731
|
+
measure();
|
|
4732
|
+
const observer = typeof ResizeObserver === "undefined" ? void 0 : new ResizeObserver(measure);
|
|
4733
|
+
observer?.observe(raw);
|
|
4734
|
+
for (const clip of clips) observer?.observe(clip);
|
|
4735
|
+
window.addEventListener("resize", measure);
|
|
4736
|
+
window.addEventListener("scroll", measure, true);
|
|
4737
|
+
return () => {
|
|
4738
|
+
observer?.disconnect();
|
|
4739
|
+
window.removeEventListener("resize", measure);
|
|
4740
|
+
window.removeEventListener("scroll", measure, true);
|
|
4741
|
+
};
|
|
4742
|
+
}, [expanded, value]);
|
|
4743
|
+
if (expanded) {
|
|
4744
|
+
const fieldId = `${contentsId}-field`;
|
|
4745
|
+
return jsxs("div", {
|
|
4746
|
+
className: css$18.stringField,
|
|
4747
|
+
"data-expanded": true,
|
|
4748
|
+
children: [
|
|
4749
|
+
field !== void 0 && jsxs("span", {
|
|
4750
|
+
id: fieldId,
|
|
4751
|
+
className: css$18.label,
|
|
4752
|
+
children: [fieldText(field), ":"]
|
|
4753
|
+
}),
|
|
4754
|
+
jsx("pre", {
|
|
4755
|
+
ref: rawRef,
|
|
4756
|
+
id: contentsId,
|
|
4757
|
+
className: css$18.stringRaw,
|
|
4758
|
+
"data-wrap": wrapped,
|
|
4759
|
+
tabIndex: 0,
|
|
4760
|
+
"aria-labelledby": field === void 0 ? void 0 : fieldId,
|
|
4761
|
+
children: value
|
|
4762
|
+
}),
|
|
4763
|
+
!lastElement && jsx("span", {
|
|
4764
|
+
className: css$18.punctuation,
|
|
4765
|
+
children: ","
|
|
4766
|
+
}),
|
|
4767
|
+
jsxs("div", {
|
|
4768
|
+
className: css$18.stringActions,
|
|
4769
|
+
children: [
|
|
4770
|
+
stringWrapping !== void 0 && jsx("button", {
|
|
4771
|
+
type: "button",
|
|
4772
|
+
className: css$18.actionButton,
|
|
4773
|
+
"aria-label": stringWrapping.label,
|
|
4774
|
+
title: stringWrapping.label,
|
|
4775
|
+
"aria-pressed": wrapped,
|
|
4776
|
+
"aria-controls": contentsId,
|
|
4777
|
+
onClick: () => {
|
|
4778
|
+
const next = !wrapped;
|
|
4779
|
+
setWrapped(next);
|
|
4780
|
+
stringWrapping.setDefault(next);
|
|
4781
|
+
},
|
|
4782
|
+
children: jsx(IconWrapLinesOutline16, { size: 12 })
|
|
4783
|
+
}),
|
|
4784
|
+
jsx("button", {
|
|
4785
|
+
type: "button",
|
|
4786
|
+
className: css$18.actionButton,
|
|
4787
|
+
"aria-label": labels.collapseNode,
|
|
4788
|
+
title: labels.collapseNode,
|
|
4789
|
+
"aria-expanded": true,
|
|
4790
|
+
"aria-controls": contentsId,
|
|
4791
|
+
onClick: () => {
|
|
4792
|
+
setExpanded(false);
|
|
4793
|
+
},
|
|
4794
|
+
children: jsx("svg", {
|
|
4795
|
+
width: "12",
|
|
4796
|
+
height: "12",
|
|
4797
|
+
viewBox: "0 0 16 16",
|
|
4798
|
+
fill: "none",
|
|
4799
|
+
stroke: "currentColor",
|
|
4800
|
+
strokeWidth: "1.5",
|
|
4801
|
+
"aria-hidden": "true",
|
|
4802
|
+
children: jsx("path", { d: "M9.5 1.5v5h5M1.5 9.5h5v5" })
|
|
4803
|
+
})
|
|
4804
|
+
}),
|
|
4805
|
+
renderCopy?.(true)
|
|
4806
|
+
]
|
|
4807
|
+
})
|
|
4808
|
+
]
|
|
4809
|
+
});
|
|
4810
|
+
}
|
|
4811
|
+
return jsxs(Fragment, { children: [renderCopy?.(), jsx("span", {
|
|
4812
|
+
className: css$18.stringField,
|
|
4813
|
+
"data-expanded": expanded,
|
|
4814
|
+
children: jsxs("span", {
|
|
4815
|
+
ref: contentRef,
|
|
4816
|
+
id: contentsId,
|
|
4817
|
+
className: css$18.stringText,
|
|
4818
|
+
children: [
|
|
4819
|
+
truncated && jsx("span", {
|
|
4820
|
+
className: css$18.stringToggleSlot,
|
|
4821
|
+
children: jsxs("button", {
|
|
4822
|
+
type: "button",
|
|
4823
|
+
className: css$18.stringToggle,
|
|
4824
|
+
"aria-label": labels.expandNode,
|
|
4825
|
+
"aria-expanded": false,
|
|
4826
|
+
"aria-controls": contentsId,
|
|
4827
|
+
onClick: () => {
|
|
4828
|
+
setWrapped(stringWrapping?.getDefault() ?? false);
|
|
4829
|
+
setExpanded(true);
|
|
4830
|
+
},
|
|
4831
|
+
children: [jsx("span", {
|
|
4832
|
+
"aria-hidden": "true",
|
|
4833
|
+
children: "…"
|
|
4834
|
+
}), labels.expandNode]
|
|
4835
|
+
})
|
|
4836
|
+
}),
|
|
4837
|
+
field !== void 0 && jsxs("span", {
|
|
4838
|
+
className: css$18.label,
|
|
4839
|
+
children: [fieldText(field), ":"]
|
|
4840
|
+
}),
|
|
4841
|
+
primitiveValue(value),
|
|
4842
|
+
!lastElement && jsx("span", {
|
|
4843
|
+
className: css$18.punctuation,
|
|
4844
|
+
children: ","
|
|
4845
|
+
})
|
|
4846
|
+
]
|
|
4847
|
+
})
|
|
4848
|
+
})] });
|
|
4849
|
+
}
|
|
4850
|
+
function JsonTreeNode({ collapsedStringLines, stringWrapping, field, initialExpanded, labels, lastElement, onClaimTabStop, onRowHover, path, renderCopy, tabStopId, value }) {
|
|
4183
4851
|
const contentsId = useId();
|
|
4184
4852
|
const expanderRef = useRef(null);
|
|
4185
4853
|
const [expanded, setExpanded] = useState(initialExpanded);
|
|
@@ -4202,8 +4870,8 @@ function JsonTreeNode({ field, initialExpanded, labels, lastElement, onClaimTabS
|
|
|
4202
4870
|
moveFocus(event.currentTarget, event.key === "ArrowUp" ? -1 : 1);
|
|
4203
4871
|
}
|
|
4204
4872
|
};
|
|
4205
|
-
const row = (children, ariaExpanded) =>
|
|
4206
|
-
className: css$
|
|
4873
|
+
const row = (children, ariaExpanded) => jsxs("div", {
|
|
4874
|
+
className: css$18.row,
|
|
4207
4875
|
role: "treeitem",
|
|
4208
4876
|
"aria-expanded": ariaExpanded,
|
|
4209
4877
|
onMouseOver: (event) => {
|
|
@@ -4213,8 +4881,23 @@ function JsonTreeNode({ field, initialExpanded, labels, lastElement, onClaimTabS
|
|
|
4213
4881
|
value
|
|
4214
4882
|
});
|
|
4215
4883
|
},
|
|
4216
|
-
children
|
|
4884
|
+
children: [typeof value !== "string" && renderCopy?.({
|
|
4885
|
+
path,
|
|
4886
|
+
value
|
|
4887
|
+
}), children]
|
|
4217
4888
|
});
|
|
4889
|
+
if (typeof value === "string") return row(jsx(JsonString, {
|
|
4890
|
+
collapsedStringLines,
|
|
4891
|
+
stringWrapping,
|
|
4892
|
+
field,
|
|
4893
|
+
value,
|
|
4894
|
+
labels,
|
|
4895
|
+
lastElement,
|
|
4896
|
+
renderCopy: renderCopy === void 0 ? void 0 : (persistent) => renderCopy({
|
|
4897
|
+
path,
|
|
4898
|
+
value
|
|
4899
|
+
}, persistent)
|
|
4900
|
+
}));
|
|
4218
4901
|
if (!container) return row(jsxs(Fragment, { children: [
|
|
4219
4902
|
jsx(NodeField, {
|
|
4220
4903
|
field,
|
|
@@ -4223,7 +4906,7 @@ function JsonTreeNode({ field, initialExpanded, labels, lastElement, onClaimTabS
|
|
|
4223
4906
|
}),
|
|
4224
4907
|
primitiveValue(value),
|
|
4225
4908
|
!lastElement && jsx("span", {
|
|
4226
|
-
className: css$
|
|
4909
|
+
className: css$18.punctuation,
|
|
4227
4910
|
children: ","
|
|
4228
4911
|
})
|
|
4229
4912
|
] }));
|
|
@@ -4235,22 +4918,22 @@ function JsonTreeNode({ field, initialExpanded, labels, lastElement, onClaimTabS
|
|
|
4235
4918
|
onToggle: toggle
|
|
4236
4919
|
}),
|
|
4237
4920
|
jsx("span", {
|
|
4238
|
-
className: css$
|
|
4921
|
+
className: css$18.punctuation,
|
|
4239
4922
|
children: open
|
|
4240
4923
|
}),
|
|
4241
4924
|
jsx("span", {
|
|
4242
|
-
className: css$
|
|
4925
|
+
className: css$18.punctuation,
|
|
4243
4926
|
children: close
|
|
4244
4927
|
}),
|
|
4245
4928
|
!lastElement && jsx("span", {
|
|
4246
|
-
className: css$
|
|
4929
|
+
className: css$18.punctuation,
|
|
4247
4930
|
children: ","
|
|
4248
4931
|
})
|
|
4249
4932
|
] }));
|
|
4250
4933
|
return row(jsxs(Fragment, { children: [
|
|
4251
4934
|
jsx("span", {
|
|
4252
4935
|
ref: expanderRef,
|
|
4253
|
-
className: clsx(css$
|
|
4936
|
+
className: clsx(css$18.expander, expanded ? css$18.collapseIcon : css$18.expandIcon),
|
|
4254
4937
|
"data-json-expander": true,
|
|
4255
4938
|
role: "button",
|
|
4256
4939
|
"aria-label": expanded ? labels.collapseNode : labels.expandNode,
|
|
@@ -4263,24 +4946,31 @@ function JsonTreeNode({ field, initialExpanded, labels, lastElement, onClaimTabS
|
|
|
4263
4946
|
onClick: toggle,
|
|
4264
4947
|
onKeyDown: onExpanderKeyDown
|
|
4265
4948
|
}),
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4949
|
+
jsxs("span", {
|
|
4950
|
+
className: css$18.summary,
|
|
4951
|
+
children: [
|
|
4952
|
+
jsx(NodeField, {
|
|
4953
|
+
field,
|
|
4954
|
+
expandable: true,
|
|
4955
|
+
onToggle: toggle
|
|
4956
|
+
}),
|
|
4957
|
+
jsx("span", {
|
|
4958
|
+
className: css$18.preview,
|
|
4959
|
+
children: previewValue(value, 0)
|
|
4960
|
+
}),
|
|
4961
|
+
!lastElement && jsx("span", {
|
|
4962
|
+
className: css$18.punctuation,
|
|
4963
|
+
children: ","
|
|
4964
|
+
})
|
|
4965
|
+
]
|
|
4278
4966
|
}),
|
|
4279
4967
|
expanded && jsx("ul", {
|
|
4280
4968
|
id: contentsId,
|
|
4281
4969
|
role: "group",
|
|
4282
|
-
className: css$
|
|
4970
|
+
className: css$18.children,
|
|
4283
4971
|
children: entries.map(([key, item], index) => jsx(JsonTreeNode, {
|
|
4972
|
+
collapsedStringLines,
|
|
4973
|
+
stringWrapping,
|
|
4284
4974
|
field: key,
|
|
4285
4975
|
value: item,
|
|
4286
4976
|
path: [...path, Array.isArray(value) ? index : key],
|
|
@@ -4289,7 +4979,8 @@ function JsonTreeNode({ field, initialExpanded, labels, lastElement, onClaimTabS
|
|
|
4289
4979
|
initialExpanded: false,
|
|
4290
4980
|
tabStopId,
|
|
4291
4981
|
onClaimTabStop,
|
|
4292
|
-
onRowHover
|
|
4982
|
+
onRowHover,
|
|
4983
|
+
renderCopy
|
|
4293
4984
|
}, key))
|
|
4294
4985
|
})
|
|
4295
4986
|
] }), expanded);
|
|
@@ -4316,19 +5007,15 @@ function copyText$2(target, mode) {
|
|
|
4316
5007
|
* @param props - Parsed data, accessible label, and display options.
|
|
4317
5008
|
* @returns A read-only JSON tree with an optionally fixed-open top level.
|
|
4318
5009
|
*/
|
|
4319
|
-
function JsonTree({ data, label, className, copyable = true, expandTopLevel = true, labels }) {
|
|
5010
|
+
function JsonTree({ data, label, className, collapsedStringLines = 3, stringWrapping, copyable = true, expandTopLevel = true, labels }) {
|
|
4320
5011
|
const rootEntries = entriesOf(data);
|
|
4321
5012
|
const firstExpandableIndex = rootEntries.findIndex(([, value]) => isExpandableValue(value) && entriesOf(value).length > 0);
|
|
4322
5013
|
const firstExpandableEntry = rootEntries[firstExpandableIndex];
|
|
4323
5014
|
const initialTabStopId = expandTopLevel ? firstExpandableEntry === void 0 ? null : pathId([Array.isArray(data) ? firstExpandableIndex : firstExpandableEntry[0]]) : isExpandableValue(data) && rootEntries.length > 0 ? pathId([]) : null;
|
|
4324
|
-
const rootRef = useRef(null);
|
|
4325
5015
|
const activeRowRef = useRef();
|
|
4326
|
-
const copyButtonRef = useRef(null);
|
|
4327
|
-
const copyMenuOpenRef = useRef(false);
|
|
4328
5016
|
const resetTimer = useRef();
|
|
4329
|
-
const
|
|
4330
|
-
const [
|
|
4331
|
-
const [copyMenuOpen, setCopyMenuOpen] = useState(false);
|
|
5017
|
+
const copySequence = useRef(0);
|
|
5018
|
+
const [copyStore] = useState(createCopyStore);
|
|
4332
5019
|
const [tabStopId, setTabStopId] = useState(initialTabStopId);
|
|
4333
5020
|
const setActiveRow = (row) => {
|
|
4334
5021
|
activeRowRef.current?.removeAttribute("data-json-copy-active");
|
|
@@ -4336,121 +5023,93 @@ function JsonTree({ data, label, className, copyable = true, expandTopLevel = tr
|
|
|
4336
5023
|
row?.setAttribute("data-json-copy-active", "");
|
|
4337
5024
|
};
|
|
4338
5025
|
const clearCopyTarget = () => {
|
|
5026
|
+
copySequence.current += 1;
|
|
5027
|
+
if (resetTimer.current !== void 0) clearTimeout(resetTimer.current);
|
|
4339
5028
|
setActiveRow(void 0);
|
|
4340
|
-
|
|
4341
|
-
setCopyState("idle");
|
|
4342
|
-
copyMenuOpenRef.current = false;
|
|
4343
|
-
setCopyMenuOpen(false);
|
|
4344
|
-
};
|
|
4345
|
-
const copyPosition = (row) => {
|
|
4346
|
-
const root = rootRef.current;
|
|
4347
|
-
/* v8 ignore next -- row events and viewport listeners run only after the root ref mounts. */
|
|
4348
|
-
if (root === null) throw new Error("JsonTree root is not mounted");
|
|
4349
|
-
const rootRect = root.getBoundingClientRect();
|
|
4350
|
-
const rowRect = row.getBoundingClientRect();
|
|
4351
|
-
return {
|
|
4352
|
-
left: rootRect.left + root.clientWidth - 26,
|
|
4353
|
-
side: rowRect.top - rootRect.top > root.clientHeight / 2 ? "top" : "bottom",
|
|
4354
|
-
top: rowRect.top
|
|
4355
|
-
};
|
|
4356
|
-
};
|
|
4357
|
-
const positionCopyButton = (row, target) => {
|
|
4358
|
-
const position = copyPosition(row);
|
|
4359
|
-
setCopyTarget({
|
|
4360
|
-
...target,
|
|
4361
|
-
...position
|
|
4362
|
-
});
|
|
4363
|
-
};
|
|
4364
|
-
const repositionCopyButton = (row) => {
|
|
4365
|
-
const position = copyPosition(row);
|
|
4366
|
-
setCopyTarget((current) => {
|
|
4367
|
-
/* v8 ignore next -- an active row and its copy target are installed together. */
|
|
4368
|
-
if (current === void 0) return current;
|
|
4369
|
-
return {
|
|
4370
|
-
...current,
|
|
4371
|
-
...position
|
|
4372
|
-
};
|
|
4373
|
-
});
|
|
5029
|
+
copyStore.set(void 0);
|
|
4374
5030
|
};
|
|
4375
5031
|
useEffect(() => () => {
|
|
5032
|
+
copySequence.current += 1;
|
|
4376
5033
|
if (resetTimer.current !== void 0) clearTimeout(resetTimer.current);
|
|
4377
5034
|
activeRowRef.current?.removeAttribute("data-json-copy-active");
|
|
4378
5035
|
}, []);
|
|
4379
5036
|
useEffect(() => {
|
|
4380
|
-
|
|
4381
|
-
activeRowRef.current = void 0;
|
|
4382
|
-
copyMenuOpenRef.current = false;
|
|
4383
|
-
setCopyTarget(void 0);
|
|
4384
|
-
setCopyState("idle");
|
|
4385
|
-
setCopyMenuOpen(false);
|
|
5037
|
+
clearCopyTarget();
|
|
4386
5038
|
setTabStopId(initialTabStopId);
|
|
4387
5039
|
}, [
|
|
4388
5040
|
data,
|
|
4389
5041
|
expandTopLevel,
|
|
4390
5042
|
initialTabStopId
|
|
4391
5043
|
]);
|
|
4392
|
-
useEffect(() => {
|
|
4393
|
-
const reposition = () => {
|
|
4394
|
-
const row = activeRowRef.current;
|
|
4395
|
-
if (row !== void 0) repositionCopyButton(row);
|
|
4396
|
-
};
|
|
4397
|
-
window.addEventListener("scroll", reposition, true);
|
|
4398
|
-
window.addEventListener("resize", reposition);
|
|
4399
|
-
return () => {
|
|
4400
|
-
window.removeEventListener("scroll", reposition, true);
|
|
4401
|
-
window.removeEventListener("resize", reposition);
|
|
4402
|
-
};
|
|
4403
|
-
}, []);
|
|
4404
5044
|
const handleRowHover = (row, target) => {
|
|
4405
|
-
if (!copyable ||
|
|
5045
|
+
if (!copyable || copyStore.get()?.menuOpen) return;
|
|
4406
5046
|
if (activeRowRef.current === row) return;
|
|
4407
5047
|
setActiveRow(row);
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
5048
|
+
copyStore.set({
|
|
5049
|
+
id: pathId(target.path),
|
|
5050
|
+
target,
|
|
5051
|
+
state: "idle",
|
|
5052
|
+
menuOpen: false
|
|
5053
|
+
});
|
|
4412
5054
|
};
|
|
4413
5055
|
const handleRootMouseOver = (event) => {
|
|
4414
|
-
if (!copyable ||
|
|
5056
|
+
if (!copyable || copyStore.get()?.menuOpen) return;
|
|
4415
5057
|
/* v8 ignore next -- browser mouse events delivered through React target an Element. */
|
|
4416
5058
|
if (!(event.target instanceof Element)) return;
|
|
4417
5059
|
if (event.target.closest("[data-json-copy-button]") === null) clearCopyTarget();
|
|
4418
5060
|
};
|
|
4419
|
-
const
|
|
4420
|
-
const
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
5061
|
+
const copy = async (target, mode) => {
|
|
5062
|
+
const sequence = ++copySequence.current;
|
|
5063
|
+
const snapshot = {
|
|
5064
|
+
id: pathId(target.path),
|
|
5065
|
+
target,
|
|
5066
|
+
state: "idle",
|
|
5067
|
+
menuOpen: false
|
|
5068
|
+
};
|
|
5069
|
+
copyStore.set(snapshot);
|
|
5070
|
+
let state;
|
|
4426
5071
|
try {
|
|
4427
|
-
await navigator.clipboard.writeText(copyText$2(
|
|
4428
|
-
|
|
5072
|
+
await navigator.clipboard.writeText(copyText$2(target, mode));
|
|
5073
|
+
state = "copied";
|
|
4429
5074
|
} catch {
|
|
4430
|
-
|
|
5075
|
+
state = "failed";
|
|
4431
5076
|
}
|
|
5077
|
+
const current = copyStore.get();
|
|
5078
|
+
if (sequence !== copySequence.current || current?.target !== target) return;
|
|
5079
|
+
copyStore.set({
|
|
5080
|
+
...current,
|
|
5081
|
+
state
|
|
5082
|
+
});
|
|
4432
5083
|
if (resetTimer.current !== void 0) clearTimeout(resetTimer.current);
|
|
4433
5084
|
resetTimer.current = setTimeout(() => {
|
|
4434
|
-
|
|
5085
|
+
const current = copyStore.get();
|
|
5086
|
+
if (current?.target === target) copyStore.set({
|
|
5087
|
+
...current,
|
|
5088
|
+
state: "idle"
|
|
5089
|
+
});
|
|
4435
5090
|
}, 1500);
|
|
4436
5091
|
};
|
|
4437
5092
|
const [rootOpen, rootClose] = bracketOf(data);
|
|
4438
|
-
const
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
5093
|
+
const renderCopy = copyable ? (target, persistent = false) => jsx(JsonCopyAction, {
|
|
5094
|
+
store: copyStore,
|
|
5095
|
+
target,
|
|
5096
|
+
persistent,
|
|
5097
|
+
labels,
|
|
5098
|
+
onCopy: copy,
|
|
5099
|
+
onClose: clearCopyTarget
|
|
5100
|
+
}) : void 0;
|
|
5101
|
+
return jsx("div", {
|
|
5102
|
+
className: clsx(css$18.root, className),
|
|
5103
|
+
style: { "--json-tree-collapsed-lines": collapsedStringLines },
|
|
4444
5104
|
onMouseOver: handleRootMouseOver,
|
|
4445
5105
|
onMouseLeave: () => {
|
|
4446
|
-
if (!
|
|
5106
|
+
if (!copyStore.get()?.menuOpen) clearCopyTarget();
|
|
4447
5107
|
},
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
className: css$17.expandedTopLevel,
|
|
5108
|
+
children: expandTopLevel ? jsxs("div", {
|
|
5109
|
+
className: css$18.expandedTopLevel,
|
|
4451
5110
|
children: [
|
|
4452
|
-
|
|
4453
|
-
className: clsx(css$
|
|
5111
|
+
jsxs("div", {
|
|
5112
|
+
className: clsx(css$18.row, css$18.topLevelBracket),
|
|
4454
5113
|
"data-json-root-row": true,
|
|
4455
5114
|
onMouseOver: (event) => {
|
|
4456
5115
|
event.stopPropagation();
|
|
@@ -4459,16 +5118,21 @@ function JsonTree({ data, label, className, copyable = true, expandTopLevel = tr
|
|
|
4459
5118
|
value: data
|
|
4460
5119
|
});
|
|
4461
5120
|
},
|
|
4462
|
-
children:
|
|
4463
|
-
|
|
5121
|
+
children: [renderCopy?.({
|
|
5122
|
+
path: [],
|
|
5123
|
+
value: data
|
|
5124
|
+
}), jsx("span", {
|
|
5125
|
+
className: css$18.punctuation,
|
|
4464
5126
|
children: rootOpen
|
|
4465
|
-
})
|
|
5127
|
+
})]
|
|
4466
5128
|
}),
|
|
4467
5129
|
jsx("div", {
|
|
4468
5130
|
"aria-label": label,
|
|
4469
|
-
className: clsx(css$
|
|
5131
|
+
className: clsx(css$18.container, css$18.expandedTopLevelContainer),
|
|
4470
5132
|
role: "tree",
|
|
4471
5133
|
children: rootEntries.map(([key, value], index) => jsx(JsonTreeNode, {
|
|
5134
|
+
collapsedStringLines,
|
|
5135
|
+
stringWrapping,
|
|
4472
5136
|
field: key,
|
|
4473
5137
|
value,
|
|
4474
5138
|
path: [Array.isArray(data) ? index : key],
|
|
@@ -4477,22 +5141,25 @@ function JsonTree({ data, label, className, copyable = true, expandTopLevel = tr
|
|
|
4477
5141
|
initialExpanded: false,
|
|
4478
5142
|
tabStopId,
|
|
4479
5143
|
onClaimTabStop: setTabStopId,
|
|
4480
|
-
onRowHover: handleRowHover
|
|
5144
|
+
onRowHover: handleRowHover,
|
|
5145
|
+
renderCopy
|
|
4481
5146
|
}, key))
|
|
4482
5147
|
}),
|
|
4483
5148
|
jsx("div", {
|
|
4484
|
-
className: clsx(css$
|
|
5149
|
+
className: clsx(css$18.row, css$18.topLevelBracket),
|
|
4485
5150
|
children: jsx("span", {
|
|
4486
|
-
className: css$
|
|
5151
|
+
className: css$18.punctuation,
|
|
4487
5152
|
children: rootClose
|
|
4488
5153
|
})
|
|
4489
5154
|
})
|
|
4490
5155
|
]
|
|
4491
5156
|
}) : jsx("div", {
|
|
4492
5157
|
"aria-label": label,
|
|
4493
|
-
className: css$
|
|
5158
|
+
className: css$18.container,
|
|
4494
5159
|
role: "tree",
|
|
4495
5160
|
children: jsx(JsonTreeNode, {
|
|
5161
|
+
collapsedStringLines,
|
|
5162
|
+
stringWrapping,
|
|
4496
5163
|
value: data,
|
|
4497
5164
|
path: [],
|
|
4498
5165
|
labels,
|
|
@@ -4500,47 +5167,10 @@ function JsonTree({ data, label, className, copyable = true, expandTopLevel = tr
|
|
|
4500
5167
|
initialExpanded: true,
|
|
4501
5168
|
tabStopId,
|
|
4502
5169
|
onClaimTabStop: setTabStopId,
|
|
4503
|
-
onRowHover: handleRowHover
|
|
5170
|
+
onRowHover: handleRowHover,
|
|
5171
|
+
renderCopy
|
|
4504
5172
|
})
|
|
4505
|
-
})
|
|
4506
|
-
className: css$17.copyAnchor,
|
|
4507
|
-
style: {
|
|
4508
|
-
left: copyTarget.left,
|
|
4509
|
-
top: copyTarget.top
|
|
4510
|
-
},
|
|
4511
|
-
children: jsx(Menu, {
|
|
4512
|
-
open: copyMenuOpen,
|
|
4513
|
-
compact: true,
|
|
4514
|
-
portal: true,
|
|
4515
|
-
align: "end",
|
|
4516
|
-
side: copyTarget.side,
|
|
4517
|
-
anchor: jsx("button", {
|
|
4518
|
-
ref: copyButtonRef,
|
|
4519
|
-
type: "button",
|
|
4520
|
-
className: css$17.copyButton,
|
|
4521
|
-
"data-json-copy-button": true,
|
|
4522
|
-
"data-state": copyState,
|
|
4523
|
-
"aria-label": copyTitle,
|
|
4524
|
-
title: labels.copyButtonTitle(copyTitle),
|
|
4525
|
-
onClick: () => void copy(defaultCopyMode),
|
|
4526
|
-
onContextMenu: (event) => {
|
|
4527
|
-
event.preventDefault();
|
|
4528
|
-
event.stopPropagation();
|
|
4529
|
-
copyMenuOpenRef.current = true;
|
|
4530
|
-
setCopyMenuOpen(true);
|
|
4531
|
-
},
|
|
4532
|
-
children: copyState === "copied" ? jsx(IconCheckOutline16, { size: 12 }) : jsx(IconCopyOutline16, { size: 12 })
|
|
4533
|
-
}),
|
|
4534
|
-
items: copyTargetIsObject ? objectCopyMenuItems(labels) : valueCopyMenuItems(labels),
|
|
4535
|
-
onSelect: (id) => {
|
|
4536
|
-
copy(id);
|
|
4537
|
-
copyMenuOpenRef.current = false;
|
|
4538
|
-
setCopyMenuOpen(false);
|
|
4539
|
-
},
|
|
4540
|
-
onClose: clearCopyTarget,
|
|
4541
|
-
getAnchorRect: () => copyButtonRef.current.getBoundingClientRect()
|
|
4542
|
-
})
|
|
4543
|
-
})]
|
|
5173
|
+
})
|
|
4544
5174
|
});
|
|
4545
5175
|
}
|
|
4546
5176
|
//#endregion
|
|
@@ -4551,8 +5181,10 @@ function JsonTree({ data, label, className, copyable = true, expandTopLevel = tr
|
|
|
4551
5181
|
* semantic. Black and white both resolve to the primary label color so text
|
|
4552
5182
|
* stays legible under either theme instead of matching the surface it sits
|
|
4553
5183
|
* on; bright black takes the tertiary label color (the muted-gray role).
|
|
4554
|
-
*
|
|
4555
|
-
*
|
|
5184
|
+
* Cyan and bright cyan take two static blues: the design system has no cyan,
|
|
5185
|
+
* and anser's literal bright cyan is unreadable on the light theme's code
|
|
5186
|
+
* surface. Magenta has no token equivalent and falls through to anser's
|
|
5187
|
+
* literal rgb, as do all 256-palette and truecolor values.
|
|
4556
5188
|
*/
|
|
4557
5189
|
const TOKEN_BY_BASIC_RGB = {
|
|
4558
5190
|
"0,0,0": "var(--dsw-alias-label-primary)",
|
|
@@ -4565,7 +5197,9 @@ const TOKEN_BY_BASIC_RGB = {
|
|
|
4565
5197
|
"187,187,0": "var(--dsw-alias-state-warn-primary)",
|
|
4566
5198
|
"255,255,85": "var(--dsw-alias-state-warn-secondary)",
|
|
4567
5199
|
"0,0,187": "var(--dsw-alias-state-business-primary)",
|
|
4568
|
-
"85,85,255": "var(--dsw-static-blue-400)"
|
|
5200
|
+
"85,85,255": "var(--dsw-static-blue-400)",
|
|
5201
|
+
"0,187,187": "var(--dsw-static-blue-600)",
|
|
5202
|
+
"85,255,255": "var(--dsw-static-blue-500)"
|
|
4569
5203
|
};
|
|
4570
5204
|
/**
|
|
4571
5205
|
* CSS for each SGR attribute anser reports. `blink` is deliberately absent —
|
|
@@ -5005,13 +5639,14 @@ function promptLabel(cwd, home) {
|
|
|
5005
5639
|
* Status pill text for a settled command, or undefined when the command
|
|
5006
5640
|
* settled cleanly (exit 0, no signal) and needs no pill — the same
|
|
5007
5641
|
* distinction the bash tool's own exit-status markers draw.
|
|
5008
|
-
* @param exitCode - settled exit code, when known.
|
|
5642
|
+
* @param exitCode - settled exit code, when known; null when the command settled without one.
|
|
5009
5643
|
* @param signal - settled terminating signal name, when known.
|
|
5010
5644
|
* @param labels - display copy for the pill text.
|
|
5011
5645
|
* @returns the pill text, or undefined for a clean exit.
|
|
5012
5646
|
*/
|
|
5013
5647
|
function statusText(exitCode, signal, labels) {
|
|
5014
5648
|
if (signal !== void 0) return labels.signal(signal);
|
|
5649
|
+
if (exitCode === null) return labels.noExitCode;
|
|
5015
5650
|
if (exitCode !== void 0 && exitCode !== 0) return labels.exitCode(exitCode);
|
|
5016
5651
|
}
|
|
5017
5652
|
/**
|
|
@@ -5025,7 +5660,7 @@ function statusText(exitCode, signal, labels) {
|
|
|
5025
5660
|
* settled command whose exit status never reached the view counts as a clean
|
|
5026
5661
|
* settle: the view says it finished and says nothing went wrong.
|
|
5027
5662
|
* @param running - the command has not settled.
|
|
5028
|
-
* @param exitCode - settled exit code, when known.
|
|
5663
|
+
* @param exitCode - settled exit code, when known; null when the command settled without one.
|
|
5029
5664
|
* @param signal - settled terminating signal name, when known.
|
|
5030
5665
|
* @param labels - display copy for the text label.
|
|
5031
5666
|
* @returns the dot's state and its text label, since the dot is aria-hidden.
|
|
@@ -5081,67 +5716,69 @@ function TerminalBlock({ command, cwd, home, output, exitCode, signal, running =
|
|
|
5081
5716
|
}, [command]);
|
|
5082
5717
|
const empty = lines.every((line) => line.every((span) => span.text.trim() === ""));
|
|
5083
5718
|
const { hidden, capped, headLines, tailLines } = headTailCap(lines.length, maxLines, expanded);
|
|
5719
|
+
const body = !running || !empty;
|
|
5084
5720
|
return jsxs("div", {
|
|
5085
|
-
className: clsx(css$
|
|
5721
|
+
className: clsx(css$19.block, className),
|
|
5086
5722
|
"data-terminal": "",
|
|
5087
5723
|
"data-running": running ? "" : void 0,
|
|
5724
|
+
"data-body": body ? "" : void 0,
|
|
5088
5725
|
children: [jsxs("div", {
|
|
5089
|
-
className: css$
|
|
5726
|
+
className: css$19.header,
|
|
5090
5727
|
children: [
|
|
5091
5728
|
jsxs("div", {
|
|
5092
|
-
className: css$
|
|
5729
|
+
className: css$19.prompt,
|
|
5093
5730
|
children: [jsx("span", {
|
|
5094
|
-
className: css$
|
|
5731
|
+
className: css$19.runStateLabel,
|
|
5095
5732
|
children: state.label
|
|
5096
5733
|
}), commandLines.map((line, index) => jsxs("div", {
|
|
5097
|
-
className: css$
|
|
5734
|
+
className: css$19.promptLine,
|
|
5098
5735
|
children: [
|
|
5099
5736
|
index === 0 && jsx(StateDot, {
|
|
5100
5737
|
state: state.state,
|
|
5101
|
-
className: css$
|
|
5738
|
+
className: css$19.runState
|
|
5102
5739
|
}),
|
|
5103
5740
|
jsx("span", {
|
|
5104
|
-
className: css$
|
|
5741
|
+
className: css$19.cwd,
|
|
5105
5742
|
children: index > 0 || cwd === void 0 ? "$" : promptLabel(cwd, home)
|
|
5106
5743
|
}),
|
|
5107
5744
|
jsx("span", {
|
|
5108
|
-
className: css$
|
|
5745
|
+
className: css$19.command,
|
|
5109
5746
|
children: line
|
|
5110
5747
|
})
|
|
5111
5748
|
]
|
|
5112
5749
|
}, index))]
|
|
5113
5750
|
}),
|
|
5114
5751
|
status !== void 0 && jsx(Pill, {
|
|
5115
|
-
className: css$
|
|
5752
|
+
className: css$19.status,
|
|
5116
5753
|
children: status
|
|
5117
5754
|
}),
|
|
5118
5755
|
!running && !empty && jsx("button", {
|
|
5119
5756
|
type: "button",
|
|
5120
|
-
className: css$
|
|
5757
|
+
className: css$19.copyButton,
|
|
5121
5758
|
onClick: onCopy,
|
|
5122
5759
|
children: copied ? copy.copied : copy.copy
|
|
5123
5760
|
})
|
|
5124
5761
|
]
|
|
5125
|
-
}),
|
|
5126
|
-
className: css$
|
|
5762
|
+
}), body && (empty ? jsx("div", {
|
|
5763
|
+
className: css$19.empty,
|
|
5127
5764
|
children: copy.noOutput
|
|
5128
5765
|
}) : jsxs("div", {
|
|
5129
|
-
className: css$
|
|
5766
|
+
className: css$19.output,
|
|
5130
5767
|
children: [
|
|
5131
5768
|
(capped ? lines.slice(0, headLines) : lines).map((line, index) => jsx("div", {
|
|
5132
|
-
className: css$
|
|
5769
|
+
className: css$19.line,
|
|
5133
5770
|
children: renderLine$1(line)
|
|
5134
5771
|
}, index)),
|
|
5135
5772
|
hidden > 0 && jsx("button", {
|
|
5136
5773
|
type: "button",
|
|
5137
|
-
className: css$
|
|
5774
|
+
className: css$19.expand,
|
|
5138
5775
|
"aria-expanded": expanded,
|
|
5139
5776
|
"aria-label": expanded ? copy.collapseAria : copy.expandAria(hidden),
|
|
5140
5777
|
onClick: onToggle,
|
|
5141
5778
|
children: expanded ? copy.collapse : copy.expand(hidden)
|
|
5142
5779
|
}),
|
|
5143
5780
|
capped && lines.slice(lines.length - tailLines).map((line, index) => jsx("div", {
|
|
5144
|
-
className: css$
|
|
5781
|
+
className: css$19.line,
|
|
5145
5782
|
children: renderLine$1(line)
|
|
5146
5783
|
}, index))
|
|
5147
5784
|
]
|
|
@@ -5719,51 +6356,51 @@ function ReadBlock({ label, labels, lines, totalLines, lang, maxLines = 16, clas
|
|
|
5719
6356
|
const tailLines = maxLines - headLines;
|
|
5720
6357
|
const windowed = lines.length < totalLines;
|
|
5721
6358
|
const rows = (slice) => slice.map(([line, spans]) => jsxs("div", {
|
|
5722
|
-
className: css$
|
|
6359
|
+
className: css$20.line,
|
|
5723
6360
|
children: [jsx("span", {
|
|
5724
|
-
className: css$
|
|
6361
|
+
className: css$20.gutter,
|
|
5725
6362
|
"aria-hidden": true,
|
|
5726
6363
|
children: line.number
|
|
5727
6364
|
}), jsx("span", {
|
|
5728
|
-
className: css$
|
|
6365
|
+
className: css$20.content,
|
|
5729
6366
|
children: spans === void 0 ? line.text : renderSpans(spans)
|
|
5730
6367
|
})]
|
|
5731
6368
|
}, line.number));
|
|
5732
6369
|
const paired = lines.map((line, index) => [line, highlighted?.[index]]);
|
|
5733
6370
|
return jsxs("div", {
|
|
5734
6371
|
ref: rootRef,
|
|
5735
|
-
className: clsx(css$
|
|
6372
|
+
className: clsx(css$20.block, className),
|
|
5736
6373
|
"data-read": "",
|
|
5737
6374
|
children: [jsxs("div", {
|
|
5738
|
-
className: css$
|
|
6375
|
+
className: css$20.banner,
|
|
5739
6376
|
children: [jsx("div", {
|
|
5740
|
-
className: css$
|
|
6377
|
+
className: css$20.label,
|
|
5741
6378
|
children: label ?? ""
|
|
5742
6379
|
}), jsxs("div", {
|
|
5743
|
-
className: css$
|
|
6380
|
+
className: css$20.action,
|
|
5744
6381
|
children: [
|
|
5745
6382
|
windowed && jsx("span", {
|
|
5746
|
-
className: css$
|
|
6383
|
+
className: css$20.count,
|
|
5747
6384
|
children: labels.window(lines.length, totalLines)
|
|
5748
6385
|
}),
|
|
5749
6386
|
jsx("span", {
|
|
5750
|
-
className: css$
|
|
6387
|
+
className: css$20.lang,
|
|
5751
6388
|
children: lang ?? ""
|
|
5752
6389
|
}),
|
|
5753
6390
|
lines.length > 0 && jsx("button", {
|
|
5754
6391
|
type: "button",
|
|
5755
|
-
className: css$
|
|
6392
|
+
className: css$20.copyButton,
|
|
5756
6393
|
onClick: onCopy,
|
|
5757
6394
|
children: copied ? labels.copied : labels.copy
|
|
5758
6395
|
})
|
|
5759
6396
|
]
|
|
5760
6397
|
})]
|
|
5761
6398
|
}), jsxs("div", {
|
|
5762
|
-
className: css$
|
|
6399
|
+
className: css$20.body,
|
|
5763
6400
|
children: [
|
|
5764
6401
|
rows(capped ? paired.slice(0, headLines) : paired),
|
|
5765
6402
|
hidden > 0 && jsx(FoldToggle, {
|
|
5766
|
-
className: css$
|
|
6403
|
+
className: css$20.expand,
|
|
5767
6404
|
expanded,
|
|
5768
6405
|
hidden,
|
|
5769
6406
|
labels,
|
|
@@ -5785,25 +6422,37 @@ function assertNever(value) {
|
|
|
5785
6422
|
}
|
|
5786
6423
|
/** The dim class per row kind (path/gap chrome vs the diff's own +/- colors). */
|
|
5787
6424
|
const ROW_CLASS = {
|
|
5788
|
-
path: css$
|
|
5789
|
-
del: css$
|
|
5790
|
-
add: css$
|
|
5791
|
-
|
|
6425
|
+
path: css$21.path,
|
|
6426
|
+
del: css$21.del,
|
|
6427
|
+
add: css$21.add,
|
|
6428
|
+
context: css$21.context,
|
|
6429
|
+
gap: css$21.gap
|
|
5792
6430
|
};
|
|
5793
|
-
/**
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
|
|
6431
|
+
/** Bound synchronous edit-graph search; one replacement consumes two edits. */
|
|
6432
|
+
const MAX_DIFF_EDIT_LENGTH = 256;
|
|
6433
|
+
/** Derive exact local patches or a whole-fragment replacement when search exceeds the limit. */
|
|
6434
|
+
function localHunks(diff) {
|
|
6435
|
+
const oldLines = contentLines(diff.oldText ?? "");
|
|
6436
|
+
const newLines = contentLines(diff.newText);
|
|
6437
|
+
const normalize = (lines) => lines.map((line) => `${line}\n`).join("");
|
|
6438
|
+
return structuredPatch("", "", normalize(oldLines), normalize(newLines), void 0, void 0, {
|
|
6439
|
+
context: 3,
|
|
6440
|
+
maxEditLength: MAX_DIFF_EDIT_LENGTH
|
|
6441
|
+
})?.hunks ?? [{ lines: [...oldLines.map((line) => `-${line}`), ...newLines.map((line) => `+${line}`)] }];
|
|
6442
|
+
}
|
|
6443
|
+
/**
|
|
6444
|
+
* Count displayed additions and deletions. Exact patches exclude shared context;
|
|
6445
|
+
* comparisons exceeding the edit limit count both complete fragments as replaced.
|
|
6446
|
+
* Text follows {@link contentLines}'s terminator rule.
|
|
5798
6447
|
* @param diffs - the hunks to count.
|
|
5799
|
-
* @returns the +/- totals.
|
|
6448
|
+
* @returns the +/- totals for summaries and the card footer.
|
|
5800
6449
|
*/
|
|
5801
6450
|
function diffTotals(diffs) {
|
|
5802
6451
|
let added = 0;
|
|
5803
6452
|
let removed = 0;
|
|
5804
|
-
for (const diff of diffs) {
|
|
5805
|
-
if (
|
|
5806
|
-
|
|
6453
|
+
for (const diff of diffs) for (const hunk of localHunks(diff)) for (const line of hunk.lines) {
|
|
6454
|
+
if (line.startsWith("+")) added++;
|
|
6455
|
+
if (line.startsWith("-")) removed++;
|
|
5807
6456
|
}
|
|
5808
6457
|
return {
|
|
5809
6458
|
added,
|
|
@@ -5811,12 +6460,9 @@ function diffTotals(diffs) {
|
|
|
5811
6460
|
};
|
|
5812
6461
|
}
|
|
5813
6462
|
/**
|
|
5814
|
-
* Flatten
|
|
5815
|
-
* opens each new file
|
|
5816
|
-
*
|
|
5817
|
-
* {@link diffTotals}'s. The file count is of DISTINCT paths, matching the TUI
|
|
5818
|
-
* diff card's footer, so two hunks in one file read as `1 file` on both front
|
|
5819
|
-
* ends.
|
|
6463
|
+
* Flatten local patches into rows and count only added and removed lines.
|
|
6464
|
+
* A path header opens each new file. A `⋯` gap separates consecutive same-file
|
|
6465
|
+
* fragments and distant patches within a fragment. File counts use distinct paths.
|
|
5820
6466
|
* @param diffs - the hunks to render.
|
|
5821
6467
|
* @returns the body rows, the +/- totals, and the distinct-file count.
|
|
5822
6468
|
*/
|
|
@@ -5835,18 +6481,24 @@ function buildRows(diffs) {
|
|
|
5835
6481
|
text: "⋯"
|
|
5836
6482
|
});
|
|
5837
6483
|
prevPath = diff.path;
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
6484
|
+
for (const [index, hunk] of localHunks(diff).entries()) {
|
|
6485
|
+
if (index > 0) rows.push({
|
|
6486
|
+
kind: "gap",
|
|
6487
|
+
text: "⋯"
|
|
6488
|
+
});
|
|
6489
|
+
for (const line of hunk.lines) {
|
|
6490
|
+
const kind = line.startsWith("-") ? "del" : line.startsWith("+") ? "add" : "context";
|
|
6491
|
+
rows.push({
|
|
6492
|
+
kind,
|
|
6493
|
+
text: line.slice(1)
|
|
6494
|
+
});
|
|
6495
|
+
}
|
|
6496
|
+
}
|
|
5846
6497
|
}
|
|
5847
6498
|
return {
|
|
5848
6499
|
rows,
|
|
5849
|
-
|
|
6500
|
+
added: rows.filter((row) => row.kind === "add").length,
|
|
6501
|
+
removed: rows.filter((row) => row.kind === "del").length,
|
|
5850
6502
|
files: paths.size
|
|
5851
6503
|
};
|
|
5852
6504
|
}
|
|
@@ -5864,9 +6516,8 @@ function contentLines(text) {
|
|
|
5864
6516
|
return (text.endsWith("\n") ? text.slice(0, -1) : text).split("\n");
|
|
5865
6517
|
}
|
|
5866
6518
|
/**
|
|
5867
|
-
*
|
|
5868
|
-
*
|
|
5869
|
-
* change; the path headers keep a multi-file copy attributable.
|
|
6519
|
+
* Copy the full local diff, including folded rows: removed/added lines have
|
|
6520
|
+
* `- `/`+ ` prefixes, context has two spaces, and paths and gaps stay verbatim.
|
|
5870
6521
|
* @param rows - the flattened body rows.
|
|
5871
6522
|
* @returns the diff as plain text.
|
|
5872
6523
|
*/
|
|
@@ -5875,6 +6526,7 @@ function copyText$1(rows) {
|
|
|
5875
6526
|
switch (row.kind) {
|
|
5876
6527
|
case "del": return `- ${row.text}`;
|
|
5877
6528
|
case "add": return `+ ${row.text}`;
|
|
6529
|
+
case "context": return ` ${row.text}`;
|
|
5878
6530
|
case "path": return row.text;
|
|
5879
6531
|
case "gap": return row.text;
|
|
5880
6532
|
/* v8 ignore next -- closed-union backstop; only reached if a row kind is forged */
|
|
@@ -5912,37 +6564,37 @@ function DiffBlock({ diffs, labels, maxLines = 16, className }) {
|
|
|
5912
6564
|
const head = capped ? rows.slice(0, headLines) : rows;
|
|
5913
6565
|
const tail = capped ? rows.slice(rows.length - tailLines) : [];
|
|
5914
6566
|
return jsxs("div", {
|
|
5915
|
-
className: clsx(css$
|
|
6567
|
+
className: clsx(css$21.block, className),
|
|
5916
6568
|
"data-diff": "",
|
|
5917
6569
|
children: [
|
|
5918
6570
|
jsx("button", {
|
|
5919
6571
|
type: "button",
|
|
5920
|
-
className: css$
|
|
6572
|
+
className: css$21.copyButton,
|
|
5921
6573
|
onClick: onCopy,
|
|
5922
6574
|
children: copied ? labels.copied : labels.copy
|
|
5923
6575
|
}),
|
|
5924
6576
|
jsxs("div", {
|
|
5925
|
-
className: css$
|
|
6577
|
+
className: css$21.body,
|
|
5926
6578
|
children: [
|
|
5927
6579
|
head.map((row, index) => jsx("div", {
|
|
5928
|
-
className: clsx(css$
|
|
6580
|
+
className: clsx(css$21.line, ROW_CLASS[row.kind]),
|
|
5929
6581
|
children: row.text
|
|
5930
6582
|
}, index)),
|
|
5931
6583
|
hidden > 0 && jsx(FoldToggle, {
|
|
5932
|
-
className: css$
|
|
6584
|
+
className: css$21.expand,
|
|
5933
6585
|
expanded,
|
|
5934
6586
|
hidden,
|
|
5935
6587
|
labels,
|
|
5936
6588
|
onToggle
|
|
5937
6589
|
}),
|
|
5938
6590
|
tail.map((row, index) => jsx("div", {
|
|
5939
|
-
className: clsx(css$
|
|
6591
|
+
className: clsx(css$21.line, ROW_CLASS[row.kind]),
|
|
5940
6592
|
children: row.text
|
|
5941
6593
|
}, index))
|
|
5942
6594
|
]
|
|
5943
6595
|
}),
|
|
5944
6596
|
jsxs("div", {
|
|
5945
|
-
className: css$
|
|
6597
|
+
className: css$21.footer,
|
|
5946
6598
|
children: [
|
|
5947
6599
|
"└ +",
|
|
5948
6600
|
added,
|
|
@@ -6078,56 +6730,56 @@ function SearchBlock(props) {
|
|
|
6078
6730
|
const tail = tailHeader === void 0 ? naturalTail : naturalTail.slice(1);
|
|
6079
6731
|
const renderRow = (row) => {
|
|
6080
6732
|
if (row.type === "path") return jsx("div", {
|
|
6081
|
-
className: css$
|
|
6733
|
+
className: css$22.line,
|
|
6082
6734
|
children: row.path
|
|
6083
6735
|
});
|
|
6084
6736
|
if (row.type === "match") return jsxs("div", {
|
|
6085
|
-
className: css$
|
|
6737
|
+
className: css$22.line,
|
|
6086
6738
|
children: [jsxs("span", {
|
|
6087
|
-
className: css$
|
|
6739
|
+
className: css$22.lineNumber,
|
|
6088
6740
|
children: [row.lineNumber, ": "]
|
|
6089
6741
|
}), row.line]
|
|
6090
6742
|
});
|
|
6091
6743
|
return jsxs("button", {
|
|
6092
6744
|
type: "button",
|
|
6093
|
-
className: css$
|
|
6745
|
+
className: css$22.fileHeader,
|
|
6094
6746
|
"aria-expanded": !row.collapsed,
|
|
6095
6747
|
onClick: () => {
|
|
6096
6748
|
toggleFile(row.index);
|
|
6097
6749
|
},
|
|
6098
6750
|
children: [jsx("span", {
|
|
6099
|
-
className: css$
|
|
6751
|
+
className: css$22.filePath,
|
|
6100
6752
|
children: row.path
|
|
6101
6753
|
}), jsx("span", {
|
|
6102
|
-
className: css$
|
|
6754
|
+
className: css$22.fileCount,
|
|
6103
6755
|
children: row.count
|
|
6104
6756
|
})]
|
|
6105
6757
|
});
|
|
6106
6758
|
};
|
|
6107
6759
|
return jsxs("div", {
|
|
6108
|
-
className: clsx(css$
|
|
6760
|
+
className: clsx(css$22.block, className),
|
|
6109
6761
|
"data-search": props.kind,
|
|
6110
6762
|
children: [jsxs("div", {
|
|
6111
|
-
className: css$
|
|
6763
|
+
className: css$22.header,
|
|
6112
6764
|
children: [jsx("span", {
|
|
6113
|
-
className: css$
|
|
6765
|
+
className: css$22.summary,
|
|
6114
6766
|
children: summaryText(props, shown, truncated, total)
|
|
6115
6767
|
}), !empty && jsx("button", {
|
|
6116
6768
|
type: "button",
|
|
6117
|
-
className: css$
|
|
6769
|
+
className: css$22.copyButton,
|
|
6118
6770
|
onClick: onCopy,
|
|
6119
6771
|
children: copied ? props.labels.copied : props.labels.copy
|
|
6120
6772
|
})]
|
|
6121
6773
|
}), empty ? jsx("div", {
|
|
6122
|
-
className: css$
|
|
6774
|
+
className: css$22.empty,
|
|
6123
6775
|
children: props.labels.noResults
|
|
6124
6776
|
}) : jsxs("div", {
|
|
6125
|
-
className: css$
|
|
6777
|
+
className: css$22.body,
|
|
6126
6778
|
children: [
|
|
6127
6779
|
head.map((row) => jsx("div", { children: renderRow(row) }, rowKey(row))),
|
|
6128
6780
|
hidden > 0 && jsx("button", {
|
|
6129
6781
|
type: "button",
|
|
6130
|
-
className: css$
|
|
6782
|
+
className: css$22.expand,
|
|
6131
6783
|
"aria-expanded": expanded,
|
|
6132
6784
|
"aria-label": expanded ? props.labels.collapseAria : props.labels.expandAria(hidden),
|
|
6133
6785
|
onClick: onToggle,
|
|
@@ -6833,7 +7485,7 @@ function renderLine(line, index) {
|
|
|
6833
7485
|
}, spanIndex))
|
|
6834
7486
|
})] }, index);
|
|
6835
7487
|
}
|
|
6836
|
-
function CodeBlock({ code, lang, streaming, className, contentRef, lineNumbers = false, copyLabel, copiedLabel }) {
|
|
7488
|
+
function CodeBlock({ code, lang, streaming, className, contentRef, lineNumbers = false, showHeader = true, copyLabel, copiedLabel }) {
|
|
6837
7489
|
const trimmed = code.endsWith("\n") ? code.slice(0, -1) : code;
|
|
6838
7490
|
const sourceLines = lineNumbers ? trimmed.split("\n") : void 0;
|
|
6839
7491
|
const rootRef = useRef(null);
|
|
@@ -6929,7 +7581,7 @@ function CodeBlock({ code, lang, streaming, className, contentRef, lineNumbers =
|
|
|
6929
7581
|
});
|
|
6930
7582
|
}, [copied, trimmed]);
|
|
6931
7583
|
const body = streamedBody !== void 0 ? streamedBody : html === void 0 ? jsx("pre", {
|
|
6932
|
-
className: css$
|
|
7584
|
+
className: css$23.plain,
|
|
6933
7585
|
children: jsx("code", { children: sourceLines === void 0 ? trimmed : sourceLines.map((line, index) => jsxs(Fragment$1, { children: [index > 0 && "\n", jsx("span", {
|
|
6934
7586
|
className: "line",
|
|
6935
7587
|
children: line
|
|
@@ -6937,22 +7589,22 @@ function CodeBlock({ code, lang, streaming, className, contentRef, lineNumbers =
|
|
|
6937
7589
|
}) : jsx("div", { dangerouslySetInnerHTML: { __html: html } });
|
|
6938
7590
|
return jsxs("div", {
|
|
6939
7591
|
ref: rootRef,
|
|
6940
|
-
className: clsx(css$
|
|
7592
|
+
className: clsx(css$23.block, "md-code-block", lineNumbers && css$23.numbered, className),
|
|
6941
7593
|
"data-line-numbers": lineNumbers || void 0,
|
|
6942
7594
|
style: sourceLines === void 0 ? void 0 : { "--dsl-code-block-line-number-width": `${Math.max(2, String(sourceLines.length).length)}ch` },
|
|
6943
|
-
children: [jsx("div", {
|
|
6944
|
-
className: css$
|
|
7595
|
+
children: [showHeader && jsx("div", {
|
|
7596
|
+
className: css$23.bannerWrap,
|
|
6945
7597
|
children: jsxs("div", {
|
|
6946
|
-
className: css$
|
|
7598
|
+
className: css$23.banner,
|
|
6947
7599
|
"data-code-block-banner": true,
|
|
6948
7600
|
children: [jsx("div", {
|
|
6949
|
-
className: css$
|
|
7601
|
+
className: css$23.infostring,
|
|
6950
7602
|
children: lang ?? ""
|
|
6951
7603
|
}), jsx("div", {
|
|
6952
|
-
className: css$
|
|
7604
|
+
className: css$23.action,
|
|
6953
7605
|
children: jsx("button", {
|
|
6954
7606
|
type: "button",
|
|
6955
|
-
className: css$
|
|
7607
|
+
className: css$23.copyButton,
|
|
6956
7608
|
onClick: onCopy,
|
|
6957
7609
|
children: copied ? copiedLabel : copyLabel
|
|
6958
7610
|
})
|
|
@@ -6960,13 +7612,46 @@ function CodeBlock({ code, lang, streaming, className, contentRef, lineNumbers =
|
|
|
6960
7612
|
})
|
|
6961
7613
|
}), jsx("div", {
|
|
6962
7614
|
ref: contentRef,
|
|
6963
|
-
className: css$
|
|
7615
|
+
className: css$23.content,
|
|
6964
7616
|
"data-code-block-content": true,
|
|
6965
7617
|
children: body
|
|
6966
7618
|
})]
|
|
6967
7619
|
});
|
|
6968
7620
|
}
|
|
6969
7621
|
//#endregion
|
|
7622
|
+
//#region lib/types/markdown/file-link.js
|
|
7623
|
+
/** Local Markdown destinations accepted by the file-preview callback. */
|
|
7624
|
+
/**
|
|
7625
|
+
* Decode a file destination and its optional GitHub-style line fragment.
|
|
7626
|
+
* Literal `?` and `#` in filenames must be percent-encoded.
|
|
7627
|
+
* @param value - Parsed Markdown link destination.
|
|
7628
|
+
* @returns A local path and optional first line, or undefined for URLs,
|
|
7629
|
+
* fragment-only links, queries, malformed escapes, or invalid line ranges.
|
|
7630
|
+
*/
|
|
7631
|
+
function parseFileLink(value) {
|
|
7632
|
+
const hash = value.indexOf("#");
|
|
7633
|
+
const destination = hash < 0 ? value : value.slice(0, hash);
|
|
7634
|
+
if (destination.includes("?")) return void 0;
|
|
7635
|
+
let path;
|
|
7636
|
+
try {
|
|
7637
|
+
path = decodeURIComponent(destination);
|
|
7638
|
+
} catch (_error) {
|
|
7639
|
+
return;
|
|
7640
|
+
}
|
|
7641
|
+
if (path.length === 0 || /[\u0000-\u001f\u007f]/.test(path) || /^[\\/]{2}/.test(path) || /^[a-z][a-z\d+.-]*:/i.test(path) && !/^[a-z]:[\\/]/i.test(path)) return void 0;
|
|
7642
|
+
if (hash < 0) return { path };
|
|
7643
|
+
const fragment = value.slice(hash + 1);
|
|
7644
|
+
const match = /^L([1-9]\d*)(?:-L([1-9]\d*))?$/.exec(fragment);
|
|
7645
|
+
if (match === null) return void 0;
|
|
7646
|
+
const line = Number(match[1]);
|
|
7647
|
+
const end = match[2] === void 0 ? line : Number(match[2]);
|
|
7648
|
+
if (!Number.isSafeInteger(line) || !Number.isSafeInteger(end) || end < line) return void 0;
|
|
7649
|
+
return {
|
|
7650
|
+
path,
|
|
7651
|
+
line
|
|
7652
|
+
};
|
|
7653
|
+
}
|
|
7654
|
+
//#endregion
|
|
6970
7655
|
//#region lib/types/markdown/katex.js
|
|
6971
7656
|
/**
|
|
6972
7657
|
* TeX-to-React via KaTeX, replicating the rehype-katex pipeline this renderer
|
|
@@ -7048,6 +7733,33 @@ function renderTexToReact(value, displayMode) {
|
|
|
7048
7733
|
return [...new DOMParser().parseFromString(html, "text/html").body.childNodes].map(domToReact);
|
|
7049
7734
|
}
|
|
7050
7735
|
//#endregion
|
|
7736
|
+
//#region lib/types/markdown/MarkdownDelegate.js
|
|
7737
|
+
/** Consumer-owned navigation for Markdown links. */
|
|
7738
|
+
const MarkdownDelegateContext = createContext({});
|
|
7739
|
+
/**
|
|
7740
|
+
* Scope Markdown navigation without threading callbacks through renderers.
|
|
7741
|
+
* Nested providers replace the enclosing capabilities. Handler changes reach cached links.
|
|
7742
|
+
* @param props - Child tree and its file and HTTP(S) link handlers.
|
|
7743
|
+
* @returns the scoped child tree.
|
|
7744
|
+
*/
|
|
7745
|
+
function MarkdownDelegateProvider({ children, openExternalLink, openFile }) {
|
|
7746
|
+
const delegate = useMemo(() => ({
|
|
7747
|
+
openExternalLink,
|
|
7748
|
+
openFile
|
|
7749
|
+
}), [openExternalLink, openFile]);
|
|
7750
|
+
return jsx(MarkdownDelegateContext.Provider, {
|
|
7751
|
+
value: delegate,
|
|
7752
|
+
children
|
|
7753
|
+
});
|
|
7754
|
+
}
|
|
7755
|
+
/**
|
|
7756
|
+
* Read the nearest Markdown navigation capabilities.
|
|
7757
|
+
* @returns Owner callbacks, or an empty delegate outside a provider.
|
|
7758
|
+
*/
|
|
7759
|
+
function useMarkdownDelegate() {
|
|
7760
|
+
return useContext(MarkdownDelegateContext);
|
|
7761
|
+
}
|
|
7762
|
+
//#endregion
|
|
7051
7763
|
//#region lib/types/markdown/render.js
|
|
7052
7764
|
/**
|
|
7053
7765
|
* Direct mdast→React markdown renderer. Replaces the react-markdown /
|
|
@@ -7055,8 +7767,8 @@ function renderTexToReact(value, displayMode) {
|
|
|
7055
7767
|
* cache frozen blocks as React elements; the rendered DOM is pinned
|
|
7056
7768
|
* byte-for-byte by `tests/fixtures/markdown-dom` and must not drift.
|
|
7057
7769
|
*
|
|
7058
|
-
*
|
|
7059
|
-
*
|
|
7770
|
+
* External link and image destinations pass a protocol allowlist; settled
|
|
7771
|
+
* local file links use an explicit owner callback. Images additionally require
|
|
7060
7772
|
* absolute HTTP(S), raw HTML renders as literal text (no HTML enters the
|
|
7061
7773
|
* DOM), and KaTeX runs without trusted commands. Fragment-anchor URLs fail
|
|
7062
7774
|
* the allowlist, so footnote references and back-references render as plain
|
|
@@ -7201,13 +7913,13 @@ function renderNode(node, key, context) {
|
|
|
7201
7913
|
const mention = context.inLink === true ? void 0 : context.fileMentions?.resolve(value);
|
|
7202
7914
|
if (mention !== void 0) return jsx("code", { children: jsxs("button", {
|
|
7203
7915
|
type: "button",
|
|
7204
|
-
className:
|
|
7916
|
+
className: markdownCss.fileMention,
|
|
7205
7917
|
title: mention.title,
|
|
7206
7918
|
"aria-label": mention.label,
|
|
7207
7919
|
onClick: mention.open,
|
|
7208
7920
|
children: [jsx(LinkIcon, {
|
|
7209
7921
|
kind: classifyLinkPath(value),
|
|
7210
|
-
className:
|
|
7922
|
+
className: markdownCss.linkIcon
|
|
7211
7923
|
}), value]
|
|
7212
7924
|
}) }, key);
|
|
7213
7925
|
return jsx("code", { children: value }, key);
|
|
@@ -7222,7 +7934,7 @@ function renderNode(node, key, context) {
|
|
|
7222
7934
|
case "link": return renderAnchor(node.url, renderChildren(node.children, {
|
|
7223
7935
|
...context,
|
|
7224
7936
|
inLink: true
|
|
7225
|
-
}), key, !anchorWrapsOnlyImages(node.children));
|
|
7937
|
+
}), key, !anchorWrapsOnlyImages(node.children), context.streaming);
|
|
7226
7938
|
case "linkReference": return renderLinkReference(node, key, context);
|
|
7227
7939
|
case "image": return renderImage(node.url, node.alt ?? "", key, context);
|
|
7228
7940
|
case "imageReference": return renderImageReference(node, key, context);
|
|
@@ -7299,7 +8011,7 @@ function renderTable(node, key, context) {
|
|
|
7299
8011
|
const [headRow, ...bodyRows] = node.children;
|
|
7300
8012
|
const wide = (align === null ? headRow?.children.length ?? 0 : align.length) >= 4 && context.inBlockquote !== true;
|
|
7301
8013
|
return jsx("div", {
|
|
7302
|
-
className: clsx(
|
|
8014
|
+
className: clsx(markdownCss.tableScroll, wide ? "md-table-wide" : markdownCss.tableFill),
|
|
7303
8015
|
tabIndex: wide ? 0 : void 0,
|
|
7304
8016
|
children: jsxs("table", { children: [headRow !== void 0 && jsx("thead", { children: renderTableRow(headRow, "th", align, 0, context) }), bodyRows.length > 0 && jsx("tbody", { children: bodyRows.map((row, index) => renderTableRow(row, "td", align, index + 1, context)) })] })
|
|
7305
8017
|
}, key);
|
|
@@ -7325,26 +8037,64 @@ function renderTableRow(row, cellTag, align, key, context) {
|
|
|
7325
8037
|
function anchorWrapsOnlyImages(children) {
|
|
7326
8038
|
return children.length > 0 && children.every((child) => child.type === "image" || child.type === "imageReference");
|
|
7327
8039
|
}
|
|
7328
|
-
/** Anchor over an already-authored href: allowlisted or unwrapped,
|
|
8040
|
+
/** Anchor over an already-authored href: allowlisted or unwrapped, with optional owner navigation for HTTP(S). */
|
|
7329
8041
|
function renderSafeLink(href, children, key, glyph = true) {
|
|
7330
8042
|
const safeHref = sanitizeUrl(href);
|
|
7331
8043
|
if (safeHref === "") return jsx(Fragment$1, { children }, key);
|
|
7332
|
-
return
|
|
8044
|
+
return jsx(MarkdownAnchor, {
|
|
7333
8045
|
href: safeHref,
|
|
7334
|
-
|
|
8046
|
+
glyph,
|
|
8047
|
+
children
|
|
8048
|
+
}, key);
|
|
8049
|
+
}
|
|
8050
|
+
function MarkdownAnchor({ href, glyph, children }) {
|
|
8051
|
+
const { openExternalLink } = useMarkdownDelegate();
|
|
8052
|
+
const external = ["http:", "https:"].includes(new URL(href).protocol);
|
|
8053
|
+
const open = external ? openExternalLink : void 0;
|
|
8054
|
+
return jsxs("a", {
|
|
8055
|
+
href,
|
|
8056
|
+
...external ? {
|
|
7335
8057
|
target: "_blank",
|
|
7336
8058
|
rel: "noopener noreferrer"
|
|
7337
8059
|
} : {},
|
|
8060
|
+
onClick: open === void 0 ? void 0 : (event) => {
|
|
8061
|
+
if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
|
8062
|
+
event.preventDefault();
|
|
8063
|
+
open(href);
|
|
8064
|
+
},
|
|
7338
8065
|
children: [glyph && jsx(LinkIcon, {
|
|
7339
8066
|
kind: "url",
|
|
7340
|
-
|
|
8067
|
+
href,
|
|
8068
|
+
className: markdownCss.linkIcon
|
|
7341
8069
|
}), children]
|
|
7342
|
-
}
|
|
8070
|
+
});
|
|
7343
8071
|
}
|
|
7344
|
-
/**
|
|
7345
|
-
function renderAnchor(url, children, key, glyph = true) {
|
|
8072
|
+
/** Local destinations use the scoped file delegate after settlement. */
|
|
8073
|
+
function renderAnchor(url, children, key, glyph = true, streaming = false) {
|
|
8074
|
+
const file = streaming ? void 0 : parseFileLink(url);
|
|
8075
|
+
if (file !== void 0) return jsx(MarkdownFileLink, {
|
|
8076
|
+
file,
|
|
8077
|
+
glyph,
|
|
8078
|
+
children
|
|
8079
|
+
}, key);
|
|
7346
8080
|
return renderSafeLink(normalizeUri(url), children, key, glyph);
|
|
7347
8081
|
}
|
|
8082
|
+
function MarkdownFileLink({ file, glyph, children }) {
|
|
8083
|
+
const { openFile } = useMarkdownDelegate();
|
|
8084
|
+
if (openFile === void 0) return jsx(Fragment, { children });
|
|
8085
|
+
return jsxs("button", {
|
|
8086
|
+
type: "button",
|
|
8087
|
+
className: clsx(markdownCss.fileMention, markdownCss.fileLink),
|
|
8088
|
+
title: file.path,
|
|
8089
|
+
onClick: () => {
|
|
8090
|
+
openFile(file.path, file.line === void 0 ? void 0 : { line: file.line });
|
|
8091
|
+
},
|
|
8092
|
+
children: [glyph && jsx(LinkIcon, {
|
|
8093
|
+
kind: classifyLinkPath(file.path),
|
|
8094
|
+
className: markdownCss.linkIcon
|
|
8095
|
+
}), children]
|
|
8096
|
+
});
|
|
8097
|
+
}
|
|
7348
8098
|
/**
|
|
7349
8099
|
* The complete inline-code value when it is exactly an absolute HTTP(S) URL
|
|
7350
8100
|
* (no surrounding whitespace); anything else stays inert code.
|
|
@@ -7361,7 +8111,7 @@ function inlineCodeHttpUrl(value) {
|
|
|
7361
8111
|
function renderImage(url, alt, key, context) {
|
|
7362
8112
|
const imageSrc = imageSource(url, context.pathImages);
|
|
7363
8113
|
if (imageSrc === void 0) return jsx("span", {
|
|
7364
|
-
className:
|
|
8114
|
+
className: markdownCss.imageAlt,
|
|
7365
8115
|
children: alt
|
|
7366
8116
|
}, key);
|
|
7367
8117
|
return jsx(MarkdownImage, {
|
|
@@ -7374,11 +8124,11 @@ function renderImage(url, alt, key, context) {
|
|
|
7374
8124
|
function MarkdownImage({ src, alt, destination }) {
|
|
7375
8125
|
const [failed, setFailed] = useState(false);
|
|
7376
8126
|
if (failed) return jsx("span", {
|
|
7377
|
-
className:
|
|
8127
|
+
className: markdownCss.imageAlt,
|
|
7378
8128
|
children: alt || destination
|
|
7379
8129
|
});
|
|
7380
8130
|
return jsx("img", {
|
|
7381
|
-
className:
|
|
8131
|
+
className: markdownCss.image,
|
|
7382
8132
|
src,
|
|
7383
8133
|
alt,
|
|
7384
8134
|
onError: () => {
|
|
@@ -7406,7 +8156,7 @@ function renderLinkReference(node, key, context) {
|
|
|
7406
8156
|
...context,
|
|
7407
8157
|
inLink: true
|
|
7408
8158
|
});
|
|
7409
|
-
return renderAnchor(definition.url, rendered, key, !anchorWrapsOnlyImages(node.children));
|
|
8159
|
+
return renderAnchor(definition.url, rendered, key, !anchorWrapsOnlyImages(node.children), context.streaming);
|
|
7410
8160
|
}
|
|
7411
8161
|
function renderImageReference(node, key, context) {
|
|
7412
8162
|
const definition = context.targets.definitions.get(node.identifier.toUpperCase());
|
|
@@ -7594,15 +8344,21 @@ var StreamingRenderer = class {
|
|
|
7594
8344
|
* identity discards the streaming render cache mid-message. `fileMentions`
|
|
7595
8345
|
* links inline-code tokens its resolver recognizes as real files, and
|
|
7596
8346
|
* `pathImages` rewrites image destinations that are local file paths into
|
|
7597
|
-
* displayable URLs its resolver vouches for
|
|
8347
|
+
* displayable URLs its resolver vouches for. Those two vocabularies are the
|
|
7598
8348
|
* single streaming gate — they apply to settled renders only, because a
|
|
7599
8349
|
* streaming message's vocabulary is not final and frozen cached elements
|
|
7600
|
-
* must not bake in handlers that could go stale.
|
|
7601
|
-
*
|
|
7602
|
-
*
|
|
7603
|
-
*
|
|
7604
|
-
|
|
7605
|
-
|
|
8350
|
+
* must not bake in handlers that could go stale. A surrounding
|
|
8351
|
+
* `MarkdownDelegateProvider` can delegate ordinary HTTP(S) activation while
|
|
8352
|
+
* modified clicks retain native behavior. `variant="compact"` uses secondary
|
|
8353
|
+
* text sizing, uniform bold headings, and tight block spacing; the default
|
|
8354
|
+
* `body` variant uses the full document typography.
|
|
8355
|
+
* The provider's `openFile` enables local Markdown links in settled messages,
|
|
8356
|
+
* including `#L24` and `#L24-L30` destinations (ranges open at their first line).
|
|
8357
|
+
* @returns A GFM document with TeX math rendered through KaTeX; raw HTML and
|
|
8358
|
+
* unsafe protocols are disabled. Local links without an opener remain text;
|
|
8359
|
+
* absolute HTTP(S) images render directly.
|
|
8360
|
+
*/
|
|
8361
|
+
const MarkdownText = memo(function MarkdownText({ text, streaming = false, labels, fileMentions, pathImages, variant = "body" }) {
|
|
7606
8362
|
const streamRef = useRef(null);
|
|
7607
8363
|
const streamLabelsRef = useRef(labels);
|
|
7608
8364
|
const children = useMemo(() => {
|
|
@@ -7623,7 +8379,8 @@ const MarkdownText = memo(function MarkdownText({ text, streaming = false, label
|
|
|
7623
8379
|
pathImages
|
|
7624
8380
|
]);
|
|
7625
8381
|
return jsx("div", {
|
|
7626
|
-
className:
|
|
8382
|
+
className: clsx(markdownCss.markdown, variant === "compact" && markdownCss.compact),
|
|
8383
|
+
"data-markdown-variant": variant === "compact" ? variant : void 0,
|
|
7627
8384
|
children
|
|
7628
8385
|
});
|
|
7629
8386
|
});
|
|
@@ -7686,6 +8443,7 @@ function SafeLink({ url, label, className }) {
|
|
|
7686
8443
|
rel: "noopener noreferrer",
|
|
7687
8444
|
children: [jsx(LinkIcon, {
|
|
7688
8445
|
kind: "url",
|
|
8446
|
+
href,
|
|
7689
8447
|
className: css$24.linkIcon
|
|
7690
8448
|
}), label]
|
|
7691
8449
|
});
|
|
@@ -7903,6 +8661,6 @@ function extractMarkdownPlainText(markdown, options = {}) {
|
|
|
7903
8661
|
}
|
|
7904
8662
|
}
|
|
7905
8663
|
//#endregion
|
|
7906
|
-
export { BrandWordmark, Button, CodeBlock, ConnectionIndicator, DEFAULT_DIFF_MAX_LINES, DEFAULT_READ_MAX_LINES, DEFAULT_SEARCH_MAX_LINES, DEFAULT_TERMINAL_MAX_LINES, DiffBlock, DisclosureRow, FISH_LOGO_PATH, FISH_LOGO_VIEWBOX, FileTypeIcon, FishLogo, HoverCard, IconAgentPresetOutline16, IconAlarmClockOutline16, IconApiOutline14, IconArchiveOutline20, IconBranchOutline16, IconBrowseOutline16, IconCheckOutline14, IconCheckOutline16, IconChecklistOutline14, IconChevronDownOutline14, IconChevronLeftOutline14, IconChevronRightOutline14, IconChevronUpOutline14, IconClockOutline16, IconCloseFill14, IconCloseOutline16, IconCodeOutline16, IconContextInjectionOutline16, IconCopyOutline16, IconCordisPluginOutline14, IconDarkOutline16, IconDataOutline16, IconDatabaseOutline16, IconDislikeFill16, IconDislikeOutline16, IconDownloadOutline16, IconEditOutline16, IconEllipsisOutline16, IconEnhanceOutline16, IconFolderClose16, IconFolderOpen16, IconFolderOpenOutline16, IconFollowsystemOutline16, IconFullscreenOutline16, IconGaugeOutline16, IconGlobeOutline14, IconGoalOutline16, IconInspectOutline12, IconLightOutline16, IconLikeFill16, IconLikeOutline16, IconLinkOutline14, IconLinkOutline16, IconListPenOutline16, IconLoadingOutline16, IconNewChatOutline16, IconPanelLeftOutline16, IconPaperclipOutline16, IconPauseOutline16, IconPersonalizationOutline16, IconPlayOutline16, IconPlusOutline16, IconProjectAddOutline16, IconQuestionOutline14, IconQueueOutline14, IconRefreshOutline14, IconRefreshOutline16, IconRightUpOutline14, IconRightUpOutline16, IconSearchOutline16, IconSendOutline14,
|
|
8664
|
+
export { BrandWordmark, Button, Checkbox, CodeBlock, ConnectionIndicator, DEFAULT_DIFF_MAX_LINES, DEFAULT_READ_MAX_LINES, DEFAULT_SEARCH_MAX_LINES, DEFAULT_TERMINAL_MAX_LINES, DiffBlock, DisclosureRow, FISH_LOGO_PATH, FISH_LOGO_VIEWBOX, FileTypeIcon, FishLogo, HoverCard, IconAgentPresetOutline16, IconAlarmClockOutline16, IconApiOutline14, IconArchiveOutline20, IconBranchOutline16, IconBrowseOutline16, IconCheckOutline14, IconCheckOutline16, IconChecklistOutline14, IconChevronDownOutline14, IconChevronLeftOutline14, IconChevronRightOutline14, IconChevronUpOutline14, IconClockOutline16, IconCloseFill14, IconCloseOutline16, IconCodeOutline16, IconCompactOutline16, IconContextInjectionOutline16, IconCopyOutline16, IconCordisPluginOutline14, IconDarkOutline16, IconDataOutline16, IconDatabaseOutline16, IconDislikeFill16, IconDislikeOutline16, IconDownloadOutline16, IconEditOutline16, IconEllipsisOutline16, IconEnhanceOutline16, IconFolderClose16, IconFolderOpen16, IconFolderOpenOutline16, IconFollowsystemOutline16, IconFullscreenOutline16, IconGaugeOutline16, IconGlobeOutline14, IconGoalOutline16, IconInfoOutline14, IconInspectOutline12, IconLightOutline16, IconLikeFill16, IconLikeOutline16, IconLinkOutline14, IconLinkOutline16, IconListPenOutline16, IconLoadingOutline16, IconNewChatOutline16, IconPanelLeftOutline16, IconPaperPlaneOutline14, IconPaperclipOutline16, IconPauseOutline16, IconPersonalizationOutline16, IconPlanOutline14, IconPlayOutline16, IconPluginPinwheelOutline16, IconPlusOutline16, IconProjectAddOutline16, IconQuestionOutline14, IconQueueOutline14, IconRefreshOutline14, IconRefreshOutline16, IconRightUpOutline14, IconRightUpOutline16, IconSearchOutline16, IconSendOutline14, IconSettingsOutline14, IconSettingsOutline16, IconShareOutline16, IconShieldOutline16, IconSkillOutline16, IconSparkle16, IconStopFill16, IconThinkOutline14, IconThinkOutline16, IconTrashOutline16, IconTreeCorner8x10, IconTriangleRightFill14, IconUserOutline16, IconWarningOutline16, IconWrapLinesOutline16, Input, JsonBlock, JsonTree, LinkIcon, MarkdownDelegateProvider, MarkdownText, Menu, Modal, OnboardingSurface, Pill, ReadBlock, ReferenceIcon, RiskConfirmation, SHIELD_OUTLINE_PATH, SHIELD_OUTLINE_STROKE, SearchBlock, StateDot, Switch, Tag, TerminalBlock, Toast, Tooltip, WebBlock, classifyFileType, classifyLinkPath, diffTotals, extractMarkdownPlainText, fileExtension, fileSizeText, isDarwinDesktop, projectUserText, rankByName, relativeTime, useAnchoredMaxHeight, useAnchoredPosition, useDismissOnOutsidePointer, writeClipboard };
|
|
7907
8665
|
|
|
7908
8666
|
//# sourceMappingURL=index.js.map
|