@qilin-agent/client-ui-primitives 3.1.4 → 3.1.6

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/lib/index.js CHANGED
@@ -12,37 +12,41 @@ import css$6 from "./DisclosureRow.module.css";
12
12
  import css$7 from "./Button.module.css";
13
13
  import css$8 from "./Pill.module.css";
14
14
  import css$9 from "./SegmentedControl.module.css";
15
- import css$10 from "./Switch.module.css";
16
- import css$11 from "./Checkbox.module.css";
17
- import css$12 from "./Input.module.css";
15
+ import css$10 from "./SegmentedTabs.module.css";
16
+ import css$11 from "./Switch.module.css";
17
+ import css$12 from "./Checkbox.module.css";
18
+ import css$13 from "./Input.module.css";
19
+ import css$14 from "./InlineEditor.module.css";
18
20
  import { createPortal } from "react-dom";
19
- import css$13 from "./ShortcutKeys.module.css";
20
- import css$14 from "./Menu.module.css";
21
- import css$15 from "./Tooltip.module.css";
22
- import css$16 from "./HoverCard.module.css";
23
- import css$17 from "./Modal.module.css";
24
- import css$18 from "./OnboardingSurface.module.css";
25
- import css$19 from "./RiskConfirmation.module.css";
26
- import css$20 from "./ConnectionIndicator.module.css";
27
- import css$21 from "./FileTypeIcon.module.css";
21
+ import css$15 from "./ShortcutKeys.module.css";
22
+ import css$16 from "./MenuSurface.module.css";
23
+ import css$17 from "./Menu.module.css";
24
+ import css$18 from "./Tooltip.module.css";
25
+ import css$19 from "./HoverCard.module.css";
26
+ import css$20 from "./Modal.module.css";
27
+ import css$21 from "./OnboardingSurface.module.css";
28
+ import css$22 from "./RiskConfirmation.module.css";
29
+ import css$23 from "./ConnectionIndicator.module.css";
30
+ import css$24 from "./FileTypeIcon.module.css";
28
31
  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";
29
32
  import { pathPartsOf } from "@qilin-agent/util-workspace-path";
30
- import css$22 from "./PathLabel.module.css";
31
- import css$23 from "./user-text.module.css";
33
+ import css$25 from "./PathLabel.module.css";
34
+ import css$26 from "./SecretText.module.css";
35
+ import css$27 from "./user-text.module.css";
32
36
  import markdownCss from "./markdown/MarkdownText.module.css";
33
- import css$24 from "./Toast.module.css";
34
- import css$25 from "./JsonTree.module.css";
37
+ import css$28 from "./Toast.module.css";
38
+ import css$29 from "./JsonTree.module.css";
35
39
  import Anser from "anser";
36
- import css$26 from "./TerminalBlock.module.css";
40
+ import css$30 from "./TerminalBlock.module.css";
37
41
  import { createCssVariablesTheme, createHighlighterCoreSync } from "shiki/core";
38
42
  import { createJavaScriptRegexEngine, defaultJavaScriptRegexConstructor } from "shiki/engine/javascript";
39
43
  import langTs from "@shikijs/langs/typescript";
40
44
  import langBash from "@shikijs/langs/shellscript";
41
45
  import langJson from "@shikijs/langs/json";
42
- import css$27 from "./ReadBlock.module.css";
46
+ import css$31 from "./ReadBlock.module.css";
43
47
  import { structuredPatch } from "diff";
44
- import css$28 from "./DiffBlock.module.css";
45
- import css$29 from "./SearchBlock.module.css";
48
+ import css$32 from "./DiffBlock.module.css";
49
+ import css$33 from "./SearchBlock.module.css";
46
50
  import { fromMarkdown } from "mdast-util-from-markdown";
47
51
  import { gfmFromMarkdown } from "mdast-util-gfm";
48
52
  import { mathFromMarkdown } from "mdast-util-math";
@@ -54,16 +58,15 @@ import { classifyCharacter } from "micromark-util-classify-character";
54
58
  import { codes, constants, types } from "micromark-util-symbol";
55
59
  import { factorySpace } from "micromark-factory-space";
56
60
  import { normalizeUri } from "micromark-util-sanitize-uri";
57
- import css$30 from "./markdown/CodeBlock.module.css";
58
- import css$31 from "./markdown/mermaid.module.css";
61
+ import css$34 from "./markdown/CodeBlock.module.css";
62
+ import css$35 from "./markdown/mermaid.module.css";
59
63
  import katex from "katex";
60
- import css$32 from "./ImageLightbox.module.css";
61
- import css$33 from "./ImagePreview.module.css";
64
+ import css$36 from "./ImageLightbox.module.css";
65
+ import css$37 from "./ImagePreview.module.css";
62
66
  import "katex/dist/katex.min.css";
63
- import css$34 from "./WebBlock.module.css";
64
- import css$35 from "./markdown/JsonBlock.module.css";
65
- import css$36 from "./MenuGroup.module.css";
66
- import css$37 from "./MenuSurface.module.css";
67
+ import css$38 from "./WebBlock.module.css";
68
+ import css$39 from "./markdown/JsonBlock.module.css";
69
+ import css$40 from "./MenuGroup.module.css";
67
70
  //#region lib/types/settings-form/SettingsForm.js
68
71
  /**
69
72
  * One plugin's settings form as its page on the Plugins page shows it: the
@@ -1900,6 +1903,127 @@ const IconPinFillRegular = ({ size = 16, className }) => jsxs("svg", {
1900
1903
  fill: "currentColor"
1901
1904
  })]
1902
1905
  });
1906
+ /**
1907
+ * Upstream-named icon surface. Community plugins written against
1908
+ * `@deepseek-ai/dsh-client-ui-primitives` import weight-suffixed names
1909
+ * (`OutlineRegular`/`OutlineMedium`) that this set spells with size
1910
+ * suffixes; each alias binds the same-name glyph in the nearest size. The
1911
+ * two names with no drawn QiLin glyph (Users, WorkspaceTree) port the
1912
+ * upstream artwork verbatim (dsh-context is the current consumer).
1913
+ */
1914
+ const ICON_REGULAR_STROKE = 1;
1915
+ const ICON_MEDIUM_STROKE = 1.3;
1916
+ /** Circle-and-tick glyph the plugin page marks shipped rows with; upstream artwork. */
1917
+ const IconCheckCircleFillRegular = ({ size = 16, className }) => jsxs("svg", {
1918
+ width: size,
1919
+ height: size,
1920
+ className,
1921
+ viewBox: "0 0 36 36",
1922
+ fill: "none",
1923
+ xmlns: "http://www.w3.org/2000/svg",
1924
+ "aria-hidden": "true",
1925
+ children: [jsx("path", {
1926
+ d: "M28.1936 14.6936L19.8066 23.0806C19.2373 23.65 18.7159 24.1742 18.24 24.5571C17.7389 24.9602 17.1365 25.3359 16.3657 25.458C15.9581 25.5225 15.5428 25.5225 15.1353 25.458C14.3645 25.3359 13.7621 24.9602 13.261 24.5571C12.7851 24.1742 12.2637 23.65 11.6943 23.0806L7.80737 19.1936L10.1936 16.8074L14.0806 20.6943C14.7033 21.317 15.0763 21.6873 15.377 21.9292C15.6523 22.1507 15.7109 22.1325 15.6626 22.1248C15.7208 22.1339 15.7802 22.1339 15.8384 22.1248C15.7901 22.1325 15.8486 22.1507 16.124 21.9292C16.4247 21.6873 16.7977 21.317 17.4204 20.6943L25.8074 12.3074L28.1936 14.6936Z",
1927
+ fill: "currentColor"
1928
+ }), jsx("path", {
1929
+ d: "M32.8496 18.0005C32.8496 9.79906 26.2019 3.15137 18.0005 3.15137C9.79906 3.15137 3.15137 9.79906 3.15137 18.0005C3.15137 26.2019 9.79906 32.8496 18.0005 32.8496C26.2019 32.8496 32.8496 26.2019 32.8496 18.0005ZM35.7764 18.0005C35.7764 27.8173 27.8173 35.7764 18.0005 35.7764C8.18363 35.7764 0.224609 27.8173 0.224609 18.0005C0.224609 8.18363 8.18363 0.224609 18.0005 0.224609C27.8173 0.224609 35.7764 8.18363 35.7764 18.0005Z",
1930
+ fill: "currentColor"
1931
+ })]
1932
+ });
1933
+ const IconUsersOutlineRegular = ({ size = 16, className }) => jsxs("svg", {
1934
+ width: size,
1935
+ height: size,
1936
+ className,
1937
+ viewBox: "0 0 16 16",
1938
+ fill: "none",
1939
+ xmlns: "http://www.w3.org/2000/svg",
1940
+ "aria-hidden": "true",
1941
+ strokeWidth: ICON_REGULAR_STROKE,
1942
+ children: [
1943
+ jsx("path", {
1944
+ d: "M6 8.25C7.51878 8.25 8.75 7.01878 8.75 5.5C8.75 3.98122 7.51878 2.75 6 2.75C4.48122 2.75 3.25 3.98122 3.25 5.5C3.25 7.01878 4.48122 8.25 6 8.25Z",
1945
+ stroke: "currentColor"
1946
+ }),
1947
+ jsx("path", {
1948
+ d: "M1 14.5C1 11.5 3.5 10.25 6 10.25C8.5 10.25 11 11.5 11 14.5",
1949
+ stroke: "currentColor"
1950
+ }),
1951
+ jsx("path", {
1952
+ d: "M10.5 2.9C11.65 3.35 12.45 4.35 12.45 5.5C12.45 6.65 11.65 7.65 10.5 8.1",
1953
+ stroke: "currentColor"
1954
+ }),
1955
+ jsx("path", {
1956
+ d: "M12.4 10.6C13.9 11.3 15 12.6 15 14.5",
1957
+ stroke: "currentColor"
1958
+ })
1959
+ ]
1960
+ });
1961
+ const IconWorkspaceTreeOutlineRegular = ({ size = 16, className }) => jsxs("svg", {
1962
+ width: size,
1963
+ height: size,
1964
+ className,
1965
+ viewBox: "0 0 16 16",
1966
+ fill: "none",
1967
+ xmlns: "http://www.w3.org/2000/svg",
1968
+ "aria-hidden": "true",
1969
+ stroke: "currentColor",
1970
+ strokeLinecap: "round",
1971
+ strokeLinejoin: "round",
1972
+ strokeWidth: ICON_REGULAR_STROKE,
1973
+ children: [jsx("path", { d: "M14 12.05c0 .8-.65 1.45-1.46 1.45H3.46C2.65 13.5 2 12.85 2 12.05v-8.1c0-.8.65-1.45 1.46-1.45h2.4c.49 0 .94.24 1.21.65l.5.73c.27.4.73.65 1.21.65h3.76c.8 0 1.46.65 1.46 1.45v6.02Z" }), jsx("path", { d: "M8.7 8.1v3M11.2 8.1v3" })]
1974
+ });
1975
+ /** Regular one-pixel IconSlidersTwoOutline artwork (Filters and Labels menu rows). */
1976
+ const IconSlidersTwoOutlineRegular = ({ size = 16, className }) => jsxs("svg", {
1977
+ "aria-hidden": "true",
1978
+ width: size,
1979
+ height: size,
1980
+ className,
1981
+ viewBox: "0 0 16 16",
1982
+ fill: "none",
1983
+ stroke: "currentColor",
1984
+ strokeLinecap: "round",
1985
+ strokeWidth: ICON_REGULAR_STROKE,
1986
+ children: [
1987
+ jsx("path", { d: "M2.3 5h5.85M12.05 5h1.65" }),
1988
+ jsx("circle", {
1989
+ cx: "9.95",
1990
+ cy: "5",
1991
+ r: "1.45"
1992
+ }),
1993
+ jsx("path", { d: "M2.3 11h1.65M7.85 11h5.85" }),
1994
+ jsx("circle", {
1995
+ cx: "5.75",
1996
+ cy: "11",
1997
+ r: "1.45"
1998
+ })
1999
+ ]
2000
+ });
2001
+ /** Medium IconSlidersTwoOutline artwork with a 1.3px stroke. */
2002
+ const IconSlidersTwoOutlineMedium = ({ size = 16, className }) => jsxs("svg", {
2003
+ "aria-hidden": "true",
2004
+ width: size,
2005
+ height: size,
2006
+ className,
2007
+ viewBox: "0 0 16 16",
2008
+ fill: "none",
2009
+ stroke: "currentColor",
2010
+ strokeLinecap: "round",
2011
+ strokeWidth: ICON_MEDIUM_STROKE,
2012
+ children: [
2013
+ jsx("path", { d: "M2.3 5h5.85M12.05 5h1.65" }),
2014
+ jsx("circle", {
2015
+ cx: "9.95",
2016
+ cy: "5",
2017
+ r: "1.45"
2018
+ }),
2019
+ jsx("path", { d: "M2.3 11h1.65M7.85 11h5.85" }),
2020
+ jsx("circle", {
2021
+ cx: "5.75",
2022
+ cy: "11",
2023
+ r: "1.45"
2024
+ })
2025
+ ]
2026
+ });
1903
2027
  //#endregion
1904
2028
  //#region lib/types/Tag.js
1905
2029
  /**
@@ -2377,6 +2501,29 @@ function CommandText({ text, label, className }) {
2377
2501
  }
2378
2502
  //#endregion
2379
2503
  //#region lib/types/StateDot.js
2504
+ /**
2505
+ * Pin the loader's CSS animations to document time zero. A CSS animation starts
2506
+ * when its element is inserted and restarts when the element is moved or shown
2507
+ * again, so loaders started at different moments animate out of phase; one shared
2508
+ * start time keeps every visible loader in step. Mount pins the first start; the
2509
+ * element's own `animationstart` listener pins each restart.
2510
+ * @param element - the mounted loader, or null on unmount.
2511
+ */
2512
+ function syncSpinner(element) {
2513
+ if (element === null) return;
2514
+ pinSpinner(element);
2515
+ element.addEventListener("animationstart", () => {
2516
+ pinSpinner(element);
2517
+ });
2518
+ }
2519
+ /**
2520
+ * Set every CSS animation in the loader's subtree to start at document time zero.
2521
+ * @param element - the mounted loader.
2522
+ */
2523
+ function pinSpinner(element) {
2524
+ const spinner = element;
2525
+ for (const animation of spinner.getAnimations?.({ subtree: true }) ?? []) animation.startTime = 0;
2526
+ }
2380
2527
  /** Outer 3x3 matrix cells (2px pixels on a 10px grid), clockwise from top-left. */
2381
2528
  const MATRIX_CELLS = [
2382
2529
  [0, 0],
@@ -2397,6 +2544,7 @@ const MATRIX_CELLS = [
2397
2544
  */
2398
2545
  function StateDot({ state, size = 10, className }) {
2399
2546
  if (state === "ongoing") return jsx("svg", {
2547
+ ref: syncSpinner,
2400
2548
  className: clsx(css$4.matrix, className),
2401
2549
  "data-state": "ongoing",
2402
2550
  width: size,
@@ -2659,6 +2807,274 @@ function SegmentedControl({ id, value, options, onChange, label, disabled = fals
2659
2807
  });
2660
2808
  }
2661
2809
  //#endregion
2810
+ //#region lib/types/SegmentedTabs.js
2811
+ /**
2812
+ * Render equal-width, controlled tabs with a sliding selection indicator.
2813
+ * @param props.items - non-empty ordered tabs with unique values and DOM ids.
2814
+ * @param props.value - selected value, which must belong to items.
2815
+ * @param props.onChange - selection requested by click, Left/Right, or Home/End.
2816
+ * Keyboard selection also moves focus; only the selected tab is a tab stop.
2817
+ * @param props.label - localized accessible name for the tab list.
2818
+ * @param props.className - layout placement; panels remain caller-owned.
2819
+ * @returns the tab list, without its panels.
2820
+ */
2821
+ function SegmentedTabs({ items, value, onChange, label, className }) {
2822
+ const selectedIndex = items.findIndex((item) => item.value === value);
2823
+ const onKeyDown = (event, index) => {
2824
+ let next;
2825
+ switch (event.key) {
2826
+ case "ArrowLeft":
2827
+ next = (index + items.length - 1) % items.length;
2828
+ break;
2829
+ case "ArrowRight":
2830
+ next = (index + 1) % items.length;
2831
+ break;
2832
+ case "Home":
2833
+ next = 0;
2834
+ break;
2835
+ case "End":
2836
+ next = items.length - 1;
2837
+ break;
2838
+ default: return;
2839
+ }
2840
+ event.preventDefault();
2841
+ event.stopPropagation();
2842
+ const tablist = event.currentTarget.parentElement;
2843
+ const nextItem = items[next];
2844
+ /* v8 ignore next -- the event comes from a mounted direct child and next is bounded by non-empty items. */
2845
+ if (tablist === null || nextItem === void 0) return;
2846
+ tablist.querySelectorAll("[role=\"tab\"]").item(next).focus();
2847
+ onChange(nextItem.value);
2848
+ };
2849
+ return jsxs("div", {
2850
+ role: "tablist",
2851
+ "aria-label": label,
2852
+ className: clsx(css$10.tabs, className),
2853
+ style: { gridTemplateColumns: `repeat(${items.length}, minmax(0, 1fr))` },
2854
+ children: [jsx("span", {
2855
+ className: css$10.indicator,
2856
+ "aria-hidden": "true",
2857
+ style: {
2858
+ width: `calc((100% - 8px) / ${items.length})`,
2859
+ transform: `translateX(${selectedIndex * 100}%)`
2860
+ }
2861
+ }), items.map((item, index) => jsx(Pill, {
2862
+ id: item.id,
2863
+ role: "tab",
2864
+ className: css$10.tab,
2865
+ "aria-selected": value === item.value,
2866
+ "aria-controls": item.panelId,
2867
+ tabIndex: value === item.value ? 0 : -1,
2868
+ onClick: () => {
2869
+ onChange(item.value);
2870
+ },
2871
+ onKeyDown: (event) => {
2872
+ onKeyDown(event, index);
2873
+ },
2874
+ children: item.label
2875
+ }, item.value))]
2876
+ });
2877
+ }
2878
+ //#endregion
2879
+ //#region lib/types/plugin-artwork.js
2880
+ /**
2881
+ * Fixed-palette plugin artwork for the plugin management surfaces. Unlike the
2882
+ * ic_ds_* set these glyphs carry their own brand colors and gradients instead
2883
+ * of riding currentColor; all draw on a 36×36 viewBox and take {size, className}.
2884
+ */
2885
+ /**
2886
+ * A per-instance SVG def id prefix: the artwork repeats across cards and rows,
2887
+ * and duplicate document ids would make every `url(#…)` resolve to the first instance.
2888
+ */
2889
+ const useArtworkId = () => `qilin_plugin_art_${useId().replaceAll(":", "")}`;
2890
+ /** Light-blue terminal artwork shared by plugin cards and sidebar guide entries. */
2891
+ const PluginArtworkTerminal = ({ size = 36, className }) => jsxs("svg", {
2892
+ width: size,
2893
+ height: size,
2894
+ className,
2895
+ viewBox: "0 0 36 36",
2896
+ fill: "none",
2897
+ xmlns: "http://www.w3.org/2000/svg",
2898
+ children: [jsx("path", {
2899
+ d: "M10 11L16.606 17.606C16.6841 17.6841 16.6841 17.8107 16.606 17.8888L10 24.4948",
2900
+ stroke: "#679EFE",
2901
+ strokeWidth: "3.5"
2902
+ }), jsx("path", {
2903
+ d: "M20.1211 24.4946H26.8685",
2904
+ stroke: "#679EFE",
2905
+ strokeWidth: "3.5"
2906
+ })]
2907
+ });
2908
+ /** Agent-loop plugin artwork (four leaves circling a center). */
2909
+ const PluginArtworkLoop = ({ size = 36, className }) => {
2910
+ const uid = useArtworkId();
2911
+ return jsxs("svg", {
2912
+ width: size,
2913
+ height: size,
2914
+ className,
2915
+ viewBox: "0 0 36 36",
2916
+ fill: "none",
2917
+ xmlns: "http://www.w3.org/2000/svg",
2918
+ children: [
2919
+ jsx("path", {
2920
+ d: "M18.0486 28.4901C12.0858 28.4901 7.25195 23.6562 7.25195 17.6934C13.2148 17.6934 18.0486 22.5272 18.0486 28.4901Z",
2921
+ fill: "#A797FC"
2922
+ }),
2923
+ jsx("path", {
2924
+ d: "M18.0486 6.89667C12.0858 6.89667 7.25195 11.7305 7.25195 17.6934C13.2148 17.6934 18.0486 12.8595 18.0486 6.89667Z",
2925
+ fill: `url(#${uid}a)`
2926
+ }),
2927
+ jsx("path", {
2928
+ d: "M18.0485 28.4901C24.0114 28.4901 28.8452 23.6562 28.8452 17.6934C22.8824 17.6934 18.0485 22.5272 18.0485 28.4901Z",
2929
+ fill: "#4561EE"
2930
+ }),
2931
+ jsx("path", {
2932
+ d: "M18.0485 6.89667C24.0114 6.89667 28.8452 11.7305 28.8452 17.6934C22.8824 17.6934 18.0485 12.8595 18.0485 6.89667Z",
2933
+ fill: "#658EFF"
2934
+ }),
2935
+ jsx("defs", { children: jsxs("linearGradient", {
2936
+ id: `${uid}a`,
2937
+ x1: "16.7911",
2938
+ y1: "16.1655",
2939
+ x2: "8.98192",
2940
+ y2: "8.74289",
2941
+ gradientUnits: "userSpaceOnUse",
2942
+ children: [jsx("stop", { stopColor: "#A23AE7" }), jsx("stop", {
2943
+ offset: "1",
2944
+ stopColor: "#E2E2E2"
2945
+ })]
2946
+ }) })
2947
+ ]
2948
+ });
2949
+ };
2950
+ /** Subagent plugin artwork (two stacked rounded squares); also marks every row inside a bundle. */
2951
+ const PluginArtworkSubagent = ({ size = 36, className }) => {
2952
+ const uid = useArtworkId();
2953
+ return jsxs("svg", {
2954
+ width: size,
2955
+ height: size,
2956
+ className,
2957
+ viewBox: "0 0 36 36",
2958
+ fill: "none",
2959
+ xmlns: "http://www.w3.org/2000/svg",
2960
+ children: [
2961
+ jsx("rect", {
2962
+ x: "14.9893",
2963
+ y: "15.1877",
2964
+ width: "12.2365",
2965
+ height: "12.2365",
2966
+ rx: "2",
2967
+ fill: `url(#${uid}a)`,
2968
+ fillOpacity: "0.8"
2969
+ }),
2970
+ jsx("rect", {
2971
+ x: "8.87109",
2972
+ y: "9.0697",
2973
+ width: "12.2365",
2974
+ height: "12.2365",
2975
+ rx: "2",
2976
+ fill: `url(#${uid}b)`,
2977
+ fillOpacity: "0.8"
2978
+ }),
2979
+ jsxs("defs", { children: [jsxs("linearGradient", {
2980
+ id: `${uid}a`,
2981
+ x1: "21.1075",
2982
+ y1: "15.1877",
2983
+ x2: "21.1075",
2984
+ y2: "27.4243",
2985
+ gradientUnits: "userSpaceOnUse",
2986
+ children: [jsx("stop", { stopColor: "#45E7A4" }), jsx("stop", {
2987
+ offset: "1",
2988
+ stopColor: "#05909D"
2989
+ })]
2990
+ }), jsxs("linearGradient", {
2991
+ id: `${uid}b`,
2992
+ x1: "14.9894",
2993
+ y1: "9.0697",
2994
+ x2: "14.9894",
2995
+ y2: "21.3063",
2996
+ gradientUnits: "userSpaceOnUse",
2997
+ children: [jsx("stop", { stopColor: "#69B9FF" }), jsx("stop", {
2998
+ offset: "1",
2999
+ stopColor: "#324DE2"
3000
+ })]
3001
+ })] })
3002
+ ]
3003
+ });
3004
+ };
3005
+ /**
3006
+ * Web-search plugin artwork (conic-gradient ring and handle). SVG has no
3007
+ * native conic gradient, so the ring clips an HTML div painted with CSS
3008
+ * `conic-gradient` — the same emulation Figma exports; it renders inline in
3009
+ * the browser UI but would stay empty in an `<img>` or mask context.
3010
+ */
3011
+ const PluginArtworkSearch = ({ size = 36, className }) => {
3012
+ const uid = useArtworkId();
3013
+ return jsxs("svg", {
3014
+ width: size,
3015
+ height: size,
3016
+ className,
3017
+ viewBox: "0 0 36 36",
3018
+ fill: "none",
3019
+ xmlns: "http://www.w3.org/2000/svg",
3020
+ children: [
3021
+ jsx("path", {
3022
+ d: "M26.5362 26.9865L22.3813 22.8317",
3023
+ stroke: "#658EFF",
3024
+ strokeWidth: "3"
3025
+ }),
3026
+ jsx("g", {
3027
+ clipPath: `url(#${uid}ring)`,
3028
+ children: jsx("g", {
3029
+ transform: "matrix(0.0119394 -0.00173904 0.00173904 0.0119394 15.7661 16.2159)",
3030
+ children: jsx("foreignObject", {
3031
+ x: "-958.94",
3032
+ y: "-958.94",
3033
+ width: "1917.88",
3034
+ height: "1917.88",
3035
+ children: jsx("div", { style: {
3036
+ background: "conic-gradient(from 90deg, rgb(65, 225, 172) 0deg, rgb(101, 142, 255) 62.0619deg, rgb(65, 225, 172) 360deg)",
3037
+ height: "100%",
3038
+ width: "100%"
3039
+ } })
3040
+ })
3041
+ })
3042
+ }),
3043
+ jsx("defs", { children: jsx("clipPath", {
3044
+ id: `${uid}ring`,
3045
+ children: jsx("path", { d: "M21.9717 16.2159H19.9717C19.9717 18.5386 18.0888 20.4215 15.7661 20.4215V22.4215V24.4215C20.2979 24.4215 23.9717 20.7478 23.9717 16.2159H21.9717ZM15.7661 22.4215V20.4215C13.4434 20.4215 11.5605 18.5386 11.5605 16.2159H9.56055H7.56055C7.56055 20.7478 11.2343 24.4215 15.7661 24.4215V22.4215ZM9.56055 16.2159H11.5605C11.5605 13.8933 13.4434 12.0104 15.7661 12.0104V10.0104V8.01038C11.2343 8.01038 7.56055 11.6841 7.56055 16.2159H9.56055ZM15.7661 10.0104V12.0104C18.0888 12.0104 19.9717 13.8933 19.9717 16.2159H21.9717H23.9717C23.9717 11.6841 20.2979 8.01038 15.7661 8.01038V10.0104Z" })
3046
+ }) })
3047
+ ]
3048
+ });
3049
+ };
3050
+ /** Default plugin artwork for plugins without one of their own (connector blocks and a node). */
3051
+ const PluginArtworkDefault = ({ size = 36, className }) => {
3052
+ const uid = useArtworkId();
3053
+ return jsxs("svg", {
3054
+ width: size,
3055
+ height: size,
3056
+ className,
3057
+ viewBox: "0 0 36 36",
3058
+ fill: "none",
3059
+ xmlns: "http://www.w3.org/2000/svg",
3060
+ children: [jsx("path", {
3061
+ d: "M24.6294 8.63696C26.2862 8.63705 27.6294 9.98016 27.6294 11.637V12.7825C27.6292 14.4391 26.2861 15.7824 24.6294 15.7825H23.4839C22.6519 15.7825 21.5454 16.3459 21.5454 17.1778V18.1573C21.5454 18.7757 22.216 19.1966 22.8345 19.1965H24.6294C26.2861 19.1965 27.6292 20.5398 27.6294 22.1965V23.9924C27.6292 25.6491 26.2861 26.9924 24.6294 26.9924H22.8345C21.1778 26.9924 19.8347 25.649 19.8345 23.9924V22.1965C19.8345 21.7148 19.4957 21.2327 19.014 21.2327H16.4792C15.7975 21.2327 15.3374 22.0061 15.3374 22.6877V23.8333C15.3373 25.49 13.9942 26.8333 12.3374 26.8333H11.1919C9.53509 26.8333 8.19198 25.49 8.19189 23.8333V22.6877C8.19189 21.0309 9.53504 19.6877 11.1919 19.6877H12.3374C13.1964 19.6877 14.3999 19.0959 14.3999 18.2369V16.0185C14.3999 14.9518 15.2646 14.0872 16.3312 14.0872H19.435C20.0596 14.0872 20.484 13.4071 20.4839 12.7825V11.637C20.4839 9.98011 21.827 8.63696 23.4839 8.63696H24.6294ZM13.4116 11.2468C13.4116 12.6882 12.2431 13.8567 10.8018 13.8567C9.36037 13.8567 8.19189 12.6882 8.19189 11.2468C8.19189 9.80544 9.36037 8.63696 10.8018 8.63696C12.2431 8.63696 13.4116 9.80544 13.4116 11.2468Z",
3062
+ fill: `url(#${uid}a)`
3063
+ }), jsx("defs", { children: jsxs("linearGradient", {
3064
+ id: `${uid}a`,
3065
+ x1: "15.1481",
3066
+ y1: "9.94188",
3067
+ x2: "15.1481",
3068
+ y2: "13.6375",
3069
+ gradientUnits: "userSpaceOnUse",
3070
+ children: [jsx("stop", { stopColor: "#54ECE7" }), jsx("stop", {
3071
+ offset: "1",
3072
+ stopColor: "#658EFF"
3073
+ })]
3074
+ }) })]
3075
+ });
3076
+ };
3077
+ //#endregion
2662
3078
  //#region lib/types/Switch.js
2663
3079
  /**
2664
3080
  * Render a toggle switch.
@@ -2679,11 +3095,11 @@ function Switch({ checked, onChange, label, disabled = false, title, className }
2679
3095
  "aria-label": label,
2680
3096
  title,
2681
3097
  disabled,
2682
- className: clsx(css$10.switch, className),
3098
+ className: clsx(css$11.switch, className),
2683
3099
  onClick: () => {
2684
3100
  onChange(!checked);
2685
3101
  },
2686
- children: jsx("span", { className: css$10.thumb })
3102
+ children: jsx("span", { className: css$11.thumb })
2687
3103
  });
2688
3104
  }
2689
3105
  //#endregion
@@ -2701,7 +3117,7 @@ function Switch({ checked, onChange, label, disabled = false, title, className }
2701
3117
  */
2702
3118
  function Checkbox({ checked, onChange, label, disabled = false, title, className }) {
2703
3119
  return jsxs("label", {
2704
- className: clsx(css$11.checkbox, className),
3120
+ className: clsx(css$12.checkbox, className),
2705
3121
  title,
2706
3122
  children: [jsx("input", {
2707
3123
  type: "checkbox",
@@ -2723,17 +3139,85 @@ function Checkbox({ checked, onChange, label, disabled = false, title, className
2723
3139
  */
2724
3140
  const Input = forwardRef(function Input({ icon, className, ...rest }, ref) {
2725
3141
  return jsxs("span", {
2726
- className: clsx(css$12.wrap, className),
3142
+ className: clsx(css$13.wrap, className),
2727
3143
  children: [icon != null && jsx("span", {
2728
- className: css$12.icon,
3144
+ className: css$13.icon,
2729
3145
  children: icon
2730
3146
  }), jsx("input", {
2731
3147
  ref,
2732
- className: css$12.input,
3148
+ className: css$13.input,
2733
3149
  ...rest
2734
3150
  })]
2735
3151
  });
2736
3152
  });
3153
+ //#endregion
3154
+ //#region lib/types/InlineEditor.js
3155
+ /** Multi-line inline editor for short saved-on-Enter drafts such as queued messages and goals. */
3156
+ /**
3157
+ * Render an autofocused textarea that grows with its text up to six lines, then scrolls.
3158
+ * A textarea rather than an input: HTML strips newlines from single-line input values.
3159
+ * Enter saves, Shift+Enter breaks the line, Enter during IME composition does nothing,
3160
+ * and Escape cancels.
3161
+ * @param props.value - current draft text.
3162
+ * @param props.label - localized accessible name.
3163
+ * @param props.onChange - receives the edited text.
3164
+ * @param props.onSave - called for a plain Enter.
3165
+ * @param props.onCancel - called for Escape.
3166
+ * @param props.className - extra class for the editor's placement.
3167
+ * @returns the textarea.
3168
+ */
3169
+ function InlineEditor({ value, label, onChange, onSave, onCancel, className }) {
3170
+ const ref = useRef(null);
3171
+ useLayoutEffect(() => {
3172
+ const node = ref.current;
3173
+ const fit = () => {
3174
+ node.style.height = "auto";
3175
+ node.style.height = `${node.scrollHeight + node.offsetHeight - node.clientHeight}px`;
3176
+ };
3177
+ fit();
3178
+ const observer = new ResizeObserver(fit);
3179
+ observer.observe(node);
3180
+ return () => {
3181
+ observer.disconnect();
3182
+ };
3183
+ }, [value]);
3184
+ const onKeyDown = (event) => {
3185
+ if (event.key === "Escape") {
3186
+ onCancel();
3187
+ return;
3188
+ }
3189
+ const composing = event.nativeEvent.isComposing || Reflect.get(event.nativeEvent, "keyCode") === 229;
3190
+ if (event.key !== "Enter" || event.shiftKey || composing) return;
3191
+ event.preventDefault();
3192
+ onSave();
3193
+ };
3194
+ return jsx("textarea", {
3195
+ ref,
3196
+ autoFocus: true,
3197
+ rows: 1,
3198
+ className: clsx(css$14.editor, className),
3199
+ "aria-label": label,
3200
+ value,
3201
+ onChange: (event) => {
3202
+ onChange(event.currentTarget.value);
3203
+ },
3204
+ onKeyDown
3205
+ });
3206
+ }
3207
+ //#endregion
3208
+ //#region lib/types/overlay-top-margin.js
3209
+ /** Shared viewport inset for overlays, derived from the desktop frame's reserved top strip. */
3210
+ /**
3211
+ * Resolve the top margin an overlay keeps from the viewport edge.
3212
+ * @param min - the overlay's own viewport margin in px, used as the floor.
3213
+ * @returns the larger of `min` and the frame clearance plus 20px; fullscreen keeps only the 20px gap.
3214
+ */
3215
+ function overlayTopMargin(min) {
3216
+ const root = document.documentElement;
3217
+ const clearance = Number.parseFloat(getComputedStyle(root).getPropertyValue("--dsh-frame-top-clearance"));
3218
+ if (Number.isNaN(clearance)) return min;
3219
+ return Math.max(min, (root.hasAttribute("data-fullscreen") ? 0 : clearance) + 20);
3220
+ }
2737
3221
  /**
2738
3222
  * Delay a pointer-dismissed popup's close so the pointer can cross the gap
2739
3223
  * between anchor and popup. A pending close is dropped on unmount.
@@ -2943,14 +3427,55 @@ function useModalLayer(dialog, open, onClose) {
2943
3427
  */
2944
3428
  function ShortcutKeys({ keys, variant = "plain", className }) {
2945
3429
  return jsx("span", {
2946
- className: clsx(css$13.keys, variant === "tooltip" && css$13.tooltip, variant === "tooltip" && keys.includes("+") && css$13.joined, className),
3430
+ className: clsx(css$15.keys, variant === "tooltip" && css$15.tooltip, variant === "tooltip" && keys.includes("+") && css$15.joined, className),
2947
3431
  children: keys.map((key, index) => jsx("kbd", {
2948
- className: key === "+" ? css$13.separator : css$13.key,
3432
+ className: key === "+" ? css$15.separator : css$15.key,
2949
3433
  children: key
2950
3434
  }, index))
2951
3435
  });
2952
3436
  }
2953
3437
  //#endregion
3438
+ //#region lib/types/MenuSurface.js
3439
+ /** Shared menu material and the macOS backing that lets Chromium blur transparent windows. */
3440
+ /**
3441
+ * Paint a menu and, on macOS, an opaque backing behind the page content within its bounds.
3442
+ * CSS anchors keep each backing aligned during placement, resizing, and nested-menu movement.
3443
+ * @param props - Div content and placement, and compact geometry.
3444
+ * @param ref - The visible menu div, excluding the non-interactive backing.
3445
+ * @returns Menu content plus a backing portal removed with the menu.
3446
+ */
3447
+ const MenuSurface = forwardRef(function MenuSurface({ compact = false, className, style, children, ...props }, ref) {
3448
+ const id = useId();
3449
+ const backingRef = useRef(null);
3450
+ useLayoutEffect(() => {
3451
+ document.body.appendChild(backingRef.current);
3452
+ }, []);
3453
+ const anchorStyle = { "--qilin-menu-anchor": `--qilin-menu-${id.replaceAll(":", "")}` };
3454
+ return jsxs(Fragment, { children: [jsxs("div", {
3455
+ ...props,
3456
+ ref,
3457
+ "data-menu-material": "translucent",
3458
+ className: clsx(css$16.surface, compact && css$16.compact, className),
3459
+ style: {
3460
+ ...style,
3461
+ ...anchorStyle
3462
+ },
3463
+ children: [jsx("div", {
3464
+ "aria-hidden": "true",
3465
+ className: css$16.material
3466
+ }), children]
3467
+ }), createPortal(jsx("div", {
3468
+ ref: backingRef,
3469
+ "aria-hidden": "true",
3470
+ "data-menu-backing": "",
3471
+ className: clsx(css$16.backing, compact && css$16.compact),
3472
+ style: {
3473
+ ...anchorStyle,
3474
+ visibility: style?.visibility
3475
+ }
3476
+ }), document.body)] });
3477
+ });
3478
+ //#endregion
2954
3479
  //#region lib/types/Menu.js
2955
3480
  /**
2956
3481
  * Render one `role="menuitem"` row for a {@link Menu} whose rows are
@@ -2969,32 +3494,32 @@ function ShortcutKeys({ keys, variant = "plain", className }) {
2969
3494
  */
2970
3495
  function MenuItemButton({ children, shortcut, icon, disabled = false, danger = false, separatorBefore = false, onSelect }) {
2971
3496
  return jsxs("div", {
2972
- className: css$14.itemWrap,
3497
+ className: css$17.itemWrap,
2973
3498
  children: [separatorBefore && jsx("div", {
2974
- className: css$14.separator,
3499
+ className: css$17.separator,
2975
3500
  role: "separator"
2976
3501
  }), jsxs("button", {
2977
3502
  type: "button",
2978
3503
  role: "menuitem",
2979
- className: clsx(css$14.item, danger && css$14.danger),
3504
+ className: clsx(css$17.item, danger && css$17.danger),
2980
3505
  disabled,
2981
3506
  "aria-keyshortcuts": shortcut?.aria,
2982
3507
  onClick: onSelect,
2983
3508
  children: [
2984
3509
  icon !== void 0 && jsx("span", {
2985
- className: css$14.itemIcon,
3510
+ className: css$17.itemIcon,
2986
3511
  children: icon
2987
3512
  }),
2988
3513
  jsx("span", {
2989
- className: css$14.itemLabel,
3514
+ className: css$17.itemLabel,
2990
3515
  children
2991
3516
  }),
2992
3517
  shortcut !== void 0 && jsx("span", {
2993
3518
  "aria-hidden": "true",
2994
- className: css$14.shortcut,
3519
+ className: css$17.shortcut,
2995
3520
  children: jsx(ShortcutKeys, {
2996
3521
  keys: shortcut.keys,
2997
- className: css$14.shortcutKeys
3522
+ className: css$17.shortcutKeys
2998
3523
  })
2999
3524
  })
3000
3525
  ]
@@ -3023,17 +3548,17 @@ const MEASURE_STYLE = {
3023
3548
  * @param props.autoFocus - focus the first item on open; the arrow keys walk the list either way.
3024
3549
  * @param props.open - whether the list is showing (owner-controlled).
3025
3550
  * @param props.anchor - the trigger element (rendered in place).
3026
- * @param props.items - selectable rows and optional separators.
3551
+ * @param props.items - selectable data rows and optional separators (default none; with no `children` either, the list is empty).
3027
3552
  * @param props.selectedId - row shown as selected.
3028
3553
  * @param props.selectedIds - rows shown as selected when a menu contains independent option groups.
3029
- * @param props.onSelect - row click callback (not called for disabled rows or submenu parents that only open children).
3554
+ * @param props.onSelect - data-row activation callback (not called for disabled rows or submenu parents that only open children).
3030
3555
  * @param props.onClose - invoked on outside click, Escape, or a window blur
3031
3556
  * that moved focus into an iframe (the only signal a pointerdown inside a
3032
3557
  * cross-origin iframe leaves).
3033
3558
  * @param props.align - list alignment against the anchor (default 'start').
3034
3559
  * @param props.side - open below (`bottom`, default) or above (`top`) the anchor.
3035
3560
  * @param props.portal - render the list into document.body, fixed-positioned
3036
- * from the anchor rect (repositions on scroll/resize while open). Use when an
3561
+ * from the anchor rect (follows movement and resizing while open). Use when an
3037
3562
  * ancestor's overflow clipping would crop the in-place list; default false
3038
3563
  * keeps the pure-CSS in-place behavior.
3039
3564
  * @param props.closeOnPointerLeave - close the list once the pointer has left
@@ -3046,17 +3571,25 @@ const MEASURE_STYLE = {
3046
3571
  * directly (e.g. from a host-owned trigger button) instead of measuring the
3047
3572
  * Menu's own wrapper span. Required when the wrapper isn't itself laid out at
3048
3573
  * the trigger (render-prop anchors, effect-positioned proxies — measuring the
3049
- * wrapper there races the host's layout effects). Called on open and on every
3050
- * scroll/resize; return null to skip placement for that frame.
3574
+ * wrapper there races the host's layout effects). Called on open, each animation
3575
+ * frame, and scroll/resize; return null to skip placement for that frame.
3051
3576
  * @param props.footer - rows pinned below the scrolling items area, separated
3052
3577
  * by a hairline; they stay visible while the items above scroll.
3578
+ * @param props.children - component rows rendered after `items` in the same
3579
+ * list, each a `role="menuitem"` button such as {@link MenuItemButton}; they
3580
+ * share the keyboard walk, the submenu exclusivity, and the post-selection
3581
+ * focus return.
3053
3582
  * @param props.selection - how a selected row is marked: a trailing check
3054
3583
  * (`'check'`, default — figma .Menu_cell) or the hover fill held on the row
3055
3584
  * with no check (`'fill'`, for icon-labelled rows where a trailing glyph
3056
3585
  * crowds the cell).
3586
+ * @param props.className - extra class on the anchor wrapper span.
3587
+ * @param props.listClassName - extra class on the dropdown card itself; the
3588
+ * only style hook that reaches a portaled list, which renders under
3589
+ * document.body outside the owner's DOM subtree.
3057
3590
  * @returns anchor wrapper with the conditional list.
3058
3591
  */
3059
- 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 }) {
3592
+ function Menu({ open, anchor, items = [], children, selectedId, selectedIds, onSelect, onClose, align = "start", side = "bottom", portal = false, closeOnPointerLeave = false, dense = false, compact = false, autoFocus = false, selection = "check", getAnchorRect, footer, className, listClassName }) {
3060
3593
  const rootRef = useRef(null);
3061
3594
  const listRef = useRef(null);
3062
3595
  /** Index the arrow walk last focused, the resume point when focus left the rows. */
@@ -3073,6 +3606,7 @@ function Menu({ open, anchor, items, selectedId, selectedIds, onSelect, onClose,
3073
3606
  * anchor never held it, to the anchor's first button. Focus left on a removed
3074
3607
  * row otherwise falls to the page body, where the next Tab restarts from the
3075
3608
  * top of the page.
3609
+ * @param navigation - whether explicit keyboard traversal should retain its focus indicator.
3076
3610
  */
3077
3611
  const refocusAnchor = (navigation = false) => {
3078
3612
  const trigger = triggerRef.current;
@@ -3089,10 +3623,10 @@ function Menu({ open, anchor, items, selectedId, selectedIds, onSelect, onClose,
3089
3623
  * its removal produced) comes back to the trigger.
3090
3624
  */
3091
3625
  const refocusAfterSelection = () => {
3626
+ const navigation = selectingWithTab.current;
3092
3627
  queueMicrotask(() => {
3093
3628
  if (openRef.current) return;
3094
3629
  const active = document.activeElement;
3095
- const navigation = selectingWithTab.current;
3096
3630
  if (active === null || active === document.body || listRef.current?.contains(active) === true) refocusAnchor(navigation);
3097
3631
  });
3098
3632
  };
@@ -3132,16 +3666,22 @@ function Menu({ open, anchor, items, selectedId, selectedIds, onSelect, onClose,
3132
3666
  y = side === "bottom" ? r.bottom + 4 : r.top - lh - 4;
3133
3667
  }
3134
3668
  if (lw > 0) x = Math.min(Math.max(x, MARGIN), vw - lw - MARGIN);
3135
- if (lh > 0) y = Math.min(Math.max(y, MARGIN), vh - lh - MARGIN);
3136
- setFixedPos({
3669
+ if (lh > 0) y = Math.min(Math.max(y, overlayTopMargin(MARGIN)), vh - lh - MARGIN);
3670
+ setFixedPos((current) => current?.left === x && current.top === y ? current : {
3137
3671
  left: x,
3138
3672
  top: y
3139
3673
  });
3140
3674
  };
3141
3675
  place();
3676
+ const track = () => {
3677
+ place();
3678
+ frame = requestAnimationFrame(track);
3679
+ };
3680
+ let frame = requestAnimationFrame(track);
3142
3681
  window.addEventListener("scroll", place, true);
3143
3682
  window.addEventListener("resize", place);
3144
3683
  return () => {
3684
+ cancelAnimationFrame(frame);
3145
3685
  window.removeEventListener("scroll", place, true);
3146
3686
  window.removeEventListener("resize", place);
3147
3687
  };
@@ -3172,6 +3712,7 @@ function Menu({ open, anchor, items, selectedId, selectedIds, onSelect, onClose,
3172
3712
  walkIndex.current = null;
3173
3713
  return;
3174
3714
  }
3715
+ const composition = observeComposition(document);
3175
3716
  const onPointerDown = (e) => {
3176
3717
  if (!(e.target instanceof Node)) return;
3177
3718
  if (rootRef.current?.contains(e.target) === true) return;
@@ -3179,15 +3720,15 @@ function Menu({ open, anchor, items, selectedId, selectedIds, onSelect, onClose,
3179
3720
  onClose();
3180
3721
  };
3181
3722
  const onKeyDown = (e) => {
3723
+ if (composition.guards(e) || isBehindModal(rootRef.current) || e.defaultPrevented || e.ctrlKey || e.altKey || e.metaKey) return;
3182
3724
  const focused = document.activeElement;
3183
3725
  const insideList = listRef.current?.contains(focused) === true;
3184
3726
  const anchored = rootRef.current?.contains(focused) === true || insideList;
3185
- if (composition.guards(e) || isBehindModal(rootRef.current) || e.defaultPrevented || e.ctrlKey || e.altKey || e.metaKey) return;
3186
3727
  if (e.key === "Escape" && !e.shiftKey) {
3187
3728
  e.preventDefault();
3188
3729
  if (e.repeat) return;
3189
3730
  onClose();
3190
- if (anchored || autoFocus) refocusAnchor(true);
3731
+ if (anchored || autoFocus) refocusAnchor();
3191
3732
  }
3192
3733
  if (e.key === "Tab") {
3193
3734
  const list = listRef.current;
@@ -3195,7 +3736,7 @@ function Menu({ open, anchor, items, selectedId, selectedIds, onSelect, onClose,
3195
3736
  if (e.shiftKey) {
3196
3737
  e.preventDefault();
3197
3738
  onClose();
3198
- refocusAnchor();
3739
+ refocusAnchor(true);
3199
3740
  return;
3200
3741
  }
3201
3742
  if (insideList) {
@@ -3237,14 +3778,13 @@ function Menu({ open, anchor, items, selectedId, selectedIds, onSelect, onClose,
3237
3778
  const onWindowBlur = () => {
3238
3779
  if (document.activeElement instanceof HTMLIFrameElement) onClose();
3239
3780
  };
3781
+ document.addEventListener("pointerdown", onPointerDown);
3240
3782
  const onEscape = (event) => {
3241
3783
  if (event.key === "Escape") onKeyDown(event);
3242
3784
  };
3243
3785
  const onOtherKey = (event) => {
3244
3786
  if (event.key !== "Escape") onKeyDown(event);
3245
3787
  };
3246
- const composition = observeComposition(document);
3247
- document.addEventListener("pointerdown", onPointerDown);
3248
3788
  document.addEventListener("keydown", onOtherKey);
3249
3789
  document.addEventListener("keydown", onEscape, true);
3250
3790
  window.addEventListener("blur", onWindowBlur);
@@ -3266,11 +3806,11 @@ function Menu({ open, anchor, items, selectedId, selectedIds, onSelect, onClose,
3266
3806
  const scrollable = !items.some((entry) => !isSeparator(entry) && !isLabel(entry) && entry.submenu !== void 0 && entry.submenu.length > 0);
3267
3807
  const renderEntry = (entry) => {
3268
3808
  if (isSeparator(entry)) return jsx("div", {
3269
- className: css$14.separator,
3809
+ className: css$17.separator,
3270
3810
  role: "separator"
3271
3811
  }, entry.id);
3272
3812
  if (isLabel(entry)) return jsx("div", {
3273
- className: css$14.label,
3813
+ className: css$17.label,
3274
3814
  role: "presentation",
3275
3815
  children: entry.text
3276
3816
  }, entry.id);
@@ -3278,79 +3818,79 @@ function Menu({ open, anchor, items, selectedId, selectedIds, onSelect, onClose,
3278
3818
  const subOpen = hasSub && openSubmenuId === entry.id;
3279
3819
  const selected = entry.id === selectedId || selectedIds?.includes(entry.id) === true;
3280
3820
  return jsxs("div", {
3281
- className: css$14.itemWrap,
3282
- onMouseEnter: () => {
3283
- setOpenSubmenuId(hasSub ? entry.id : null);
3284
- },
3821
+ className: css$17.itemWrap,
3822
+ onMouseEnter: hasSub ? () => {
3823
+ setOpenSubmenuId(entry.id);
3824
+ } : void 0,
3285
3825
  onMouseLeave: () => {
3286
3826
  setOpenSubmenuId(null);
3287
3827
  },
3288
3828
  children: [jsxs("button", {
3289
3829
  type: "button",
3290
3830
  role: "menuitem",
3291
- className: clsx(css$14.item, selected && (selection === "fill" ? css$14.selectedFill : css$14.selected), entry.danger === true && css$14.danger),
3831
+ className: clsx(css$17.item, selected && (selection === "fill" ? css$17.selectedFill : css$17.selected), entry.danger === true && css$17.danger),
3292
3832
  disabled: entry.disabled,
3293
3833
  "aria-keyshortcuts": entry.shortcut?.aria,
3294
3834
  "aria-haspopup": hasSub ? "menu" : void 0,
3295
3835
  "aria-expanded": hasSub ? subOpen : void 0,
3296
- onFocus: () => {
3297
- setOpenSubmenuId(hasSub ? entry.id : null);
3298
- },
3836
+ onFocus: hasSub ? () => {
3837
+ setOpenSubmenuId(entry.id);
3838
+ } : void 0,
3299
3839
  onClick: () => {
3300
3840
  if (hasSub) {
3301
3841
  setOpenSubmenuId(entry.id);
3302
3842
  return;
3303
3843
  }
3304
- onSelect(entry.id);
3305
- refocusAfterSelection();
3844
+ onSelect?.(entry.id);
3306
3845
  },
3307
3846
  children: [
3308
3847
  entry.icon !== void 0 && jsx("span", {
3309
- className: css$14.itemIcon,
3848
+ className: css$17.itemIcon,
3310
3849
  children: entry.icon
3311
3850
  }),
3312
3851
  jsx("span", {
3313
- className: css$14.itemLabel,
3852
+ className: css$17.itemLabel,
3314
3853
  children: entry.label
3315
3854
  }),
3316
3855
  entry.shortcut !== void 0 && jsx("span", {
3317
3856
  "aria-hidden": "true",
3318
- className: css$14.shortcut,
3857
+ className: css$17.shortcut,
3319
3858
  children: jsx(ShortcutKeys, {
3320
3859
  keys: entry.shortcut.keys,
3321
- className: css$14.shortcutKeys
3860
+ className: css$17.shortcutKeys
3322
3861
  })
3323
3862
  }),
3324
- selected && selection === "check" && jsx(IconCheckOutline16, { className: css$14.check })
3863
+ selected && selection === "check" && jsx(IconCheckOutline16, { className: css$17.check })
3325
3864
  ]
3326
- }), subOpen && entry.submenu !== void 0 && jsx("div", {
3327
- className: clsx(css$14.submenu, compact && css$14.compactList),
3865
+ }), subOpen && entry.submenu !== void 0 && jsx(MenuSurface, {
3866
+ compact,
3867
+ className: clsx(css$17.submenu, compact && css$17.compactList),
3328
3868
  role: "menu",
3329
3869
  children: entry.submenu.map((sub) => jsxs("button", {
3330
3870
  type: "button",
3331
3871
  role: "menuitem",
3332
- className: css$14.item,
3872
+ className: css$17.item,
3333
3873
  disabled: sub.disabled,
3334
3874
  "aria-keyshortcuts": sub.shortcut?.aria,
3335
3875
  onClick: () => {
3336
- onSelect(sub.id);
3876
+ onSelect?.(sub.id);
3337
3877
  refocusAfterSelection();
3338
3878
  },
3339
3879
  children: [
3340
3880
  sub.icon !== void 0 && jsx("span", {
3341
- className: css$14.itemIcon,
3881
+ className: css$17.itemIcon,
3342
3882
  children: sub.icon
3343
3883
  }),
3344
3884
  jsx("span", {
3345
- className: css$14.itemLabel,
3885
+ className: css$17.itemLabel,
3346
3886
  children: sub.label
3347
3887
  }),
3348
3888
  sub.shortcut !== void 0 && jsx("span", {
3349
3889
  "aria-hidden": "true",
3350
- className: css$14.shortcut,
3890
+ className: css$17.shortcut,
3351
3891
  children: jsx(ShortcutKeys, {
3352
3892
  keys: sub.shortcut.keys,
3353
- className: css$14.shortcutKeys
3893
+ className: css$17.shortcutKeys
3354
3894
  })
3355
3895
  })
3356
3896
  ]
@@ -3358,27 +3898,38 @@ function Menu({ open, anchor, items, selectedId, selectedIds, onSelect, onClose,
3358
3898
  })]
3359
3899
  }, entry.id);
3360
3900
  };
3361
- const list = open && jsxs("div", {
3901
+ const collapseSubmenuFrom = (e) => {
3902
+ const row = e.target instanceof Element ? e.target.closest("button[role=\"menuitem\"]") : null;
3903
+ if (row === null || row.getAttribute("aria-haspopup") === "menu") return;
3904
+ if (row.closest("[role=\"menu\"]") !== e.currentTarget) return;
3905
+ setOpenSubmenuId(null);
3906
+ };
3907
+ const list = open && jsxs(MenuSurface, {
3908
+ compact,
3362
3909
  ref: listRef,
3363
- className: clsx(css$14.list, dense && css$14.denseList, compact && css$14.compactList, scrollable && css$14.scrollable, portal && css$14.portal, side === "top" && !portal && css$14.sideTop, align === "end" && !portal && css$14.alignEnd),
3910
+ className: clsx(css$17.list, listClassName, dense && css$17.denseList, compact && css$17.compactList, scrollable && css$17.scrollable, portal && css$17.portal, side === "top" && !portal && css$17.sideTop, align === "end" && !portal && css$17.alignEnd),
3364
3911
  style: portal ? fixedPos ?? MEASURE_STYLE : void 0,
3365
3912
  role: "menu",
3366
3913
  onClick: (e) => {
3367
3914
  e.stopPropagation();
3915
+ const row = e.target instanceof Element ? e.target.closest("button[role=\"menuitem\"]") : null;
3916
+ if (row !== null && row.getAttribute("aria-haspopup") !== "menu") refocusAfterSelection();
3368
3917
  },
3369
- children: [jsx("div", {
3370
- className: css$14.viewport,
3918
+ onMouseOver: collapseSubmenuFrom,
3919
+ onFocus: collapseSubmenuFrom,
3920
+ children: [jsxs("div", {
3921
+ className: css$17.viewport,
3371
3922
  role: "presentation",
3372
- children: items.map(renderEntry)
3923
+ children: [items.map(renderEntry), children]
3373
3924
  }), footer !== void 0 && footer.length > 0 && jsx("div", {
3374
- className: css$14.footer,
3925
+ className: css$17.footer,
3375
3926
  role: "presentation",
3376
3927
  children: footer.map(renderEntry)
3377
3928
  })]
3378
3929
  });
3379
3930
  return jsxs("span", {
3380
3931
  ref: rootRef,
3381
- className: clsx(css$14.root, className),
3932
+ className: clsx(css$17.root, className),
3382
3933
  onPointerEnter: closeOnPointerLeave ? cancelClose : void 0,
3383
3934
  onPointerLeave: closeOnPointerLeave ? () => {
3384
3935
  if (open) armClose();
@@ -3427,20 +3978,6 @@ function useAnchoredMaxHeight(ref, cap, signal) {
3427
3978
  return maxHeight;
3428
3979
  }
3429
3980
  //#endregion
3430
- //#region lib/types/overlay-top-margin.js
3431
- /** Shared viewport inset for overlays, derived from the desktop frame's reserved top strip. */
3432
- /**
3433
- * Resolve the top margin an overlay keeps from the viewport edge.
3434
- * @param min - the overlay's own viewport margin in px, used as the floor.
3435
- * @returns the larger of `min` and the frame clearance plus 20px; fullscreen keeps only the 20px gap.
3436
- */
3437
- function overlayTopMargin(min) {
3438
- const root = document.documentElement;
3439
- const clearance = Number.parseFloat(getComputedStyle(root).getPropertyValue("--qilin-frame-top-clearance"));
3440
- if (Number.isNaN(clearance)) return min;
3441
- return Math.max(min, (root.hasAttribute("data-fullscreen") ? 0 : clearance) + 20);
3442
- }
3443
- //#endregion
3444
3981
  //#region lib/types/useAnchoredPosition.js
3445
3982
  /**
3446
3983
  * Keep a fixed-position floating element anchored to a trigger.
@@ -3455,11 +3992,11 @@ function overlayTopMargin(min) {
3455
3992
  */
3456
3993
  /**
3457
3994
  * Track an anchor and return the panel's fixed coordinates.
3458
- * @param options - the open state, the two refs, the placement side, and the gap/margin distances.
3995
+ * @param options - the open state, the two refs, the placement side and alignment, and the gap/margin distances.
3459
3996
  * @returns `left`/`top` for the panel, or `null` before the first measurement.
3460
3997
  */
3461
3998
  function useAnchoredPosition(options) {
3462
- const { open, anchorRef, panelRef, side = "bottom", gap, margin } = options;
3999
+ const { open, anchorRef, panelRef, side = "bottom", align = "start", gap, margin } = options;
3463
4000
  const [position, setPosition] = useState(null);
3464
4001
  useLayoutEffect(() => {
3465
4002
  if (!open) {
@@ -3475,7 +4012,7 @@ function useAnchoredPosition(options) {
3475
4012
  const panel = panelRef.current;
3476
4013
  const width = panel?.offsetWidth ?? 0;
3477
4014
  const height = panel?.offsetHeight ?? 0;
3478
- let left = rect.left;
4015
+ let left = align === "end" ? rect.right - width : rect.left;
3479
4016
  let top = side === "top" ? rect.top - gap - height : rect.bottom + gap;
3480
4017
  if (width > 0) left = Math.min(Math.max(left, margin), window.innerWidth - width - margin);
3481
4018
  if (height > 0) top = Math.min(Math.max(top, margin), window.innerHeight - height - margin);
@@ -3504,6 +4041,7 @@ function useAnchoredPosition(options) {
3504
4041
  anchorRef,
3505
4042
  panelRef,
3506
4043
  side,
4044
+ align,
3507
4045
  gap,
3508
4046
  margin
3509
4047
  ]);
@@ -3649,18 +4187,25 @@ const TooltipSuppression = createContext(null);
3649
4187
  * @param props.label - bubble text, or a resolver evaluated only while the bubble is visible.
3650
4188
  * @param props.shortcutKeys - effective key labels rendered as platform-formatted keycaps after optional text.
3651
4189
  * @param props.side - placement relative to the anchor (default 'right').
3652
- * @param props.delayMs - hover delay in milliseconds; keyboard focus remains immediate.
4190
+ * @param props.delayMs - hover delay in milliseconds (default 0).
4191
+ * @param props.focusDelayMs - keyboard focus delay in milliseconds (default 0); blur, mouse
4192
+ * leave, disabling, and unmount cancel a pending show.
3653
4193
  * @param props.disabled - suppress the bubble while true; the anchor renders identically so
3654
4194
  * toggling never remounts it (which would cut its CSS transitions).
3655
4195
  * @param props.portal - render the bubble under document.body, so an ancestor's clipping or its
3656
4196
  * stacking context can neither clip the bubble nor paint over it.
3657
4197
  * @param props.maxWidth - bubble width cap in pixels, for labels long enough that the default
3658
4198
  * half-viewport cap would render a slab wider than the surface the anchor sits on.
4199
+ * @param props.openOnClick - clicking also pins the bubble for reading; another click, Escape,
4200
+ * Tab, or an outside pointerdown dismisses it. Defaults to false, leaving an ordinary action
4201
+ * tooltip to hover and focus alone.
3659
4202
  * @param props.children - a single anchor element; its own ref (callback or object) is forwarded alongside the tooltip's.
3660
4203
  * An anchor that accepts no ref still positions the bubble: a raise records the element the event ran on.
3661
4204
  * @returns the cloned anchor plus a fixed-position bubble while hovered/focused.
3662
4205
  */
3663
- function Tooltip({ label, shortcutKeys, side = "right", delayMs = 0, disabled = false, portal = false, maxWidth, children }) {
4206
+ function Tooltip({ label, shortcutKeys, side = "right", delayMs = 0, focusDelayMs = 0, disabled = false, portal = false, maxWidth, openOnClick = false, children }) {
4207
+ const id = useId();
4208
+ const [pinned, setPinned] = useState(false);
3664
4209
  const anchor = useRef(null);
3665
4210
  const childRef = children.ref;
3666
4211
  const mergedRef = useCallback((el) => {
@@ -3730,6 +4275,7 @@ function Tooltip({ label, shortcutKeys, side = "right", delayMs = 0, disabled =
3730
4275
  showTimer.current = null;
3731
4276
  }, []);
3732
4277
  useEffect(() => {
4278
+ if (pinned && (disabled || !openOnClick)) setPinned(false);
3733
4279
  if (disabled) {
3734
4280
  cancelShow();
3735
4281
  triggers.current = {
@@ -3739,7 +4285,12 @@ function Tooltip({ label, shortcutKeys, side = "right", delayMs = 0, disabled =
3739
4285
  setPos(null);
3740
4286
  }
3741
4287
  return cancelShow;
3742
- }, [cancelShow, disabled]);
4288
+ }, [
4289
+ cancelShow,
4290
+ disabled,
4291
+ openOnClick,
4292
+ pinned
4293
+ ]);
3743
4294
  const show = () => {
3744
4295
  if (disabled) return;
3745
4296
  const el = anchor.current ?? eventAnchor.current;
@@ -3754,30 +4305,61 @@ function Tooltip({ label, shortcutKeys, side = "right", delayMs = 0, disabled =
3754
4305
  });
3755
4306
  announce(true);
3756
4307
  };
3757
- const showAfterHoverDelay = () => {
4308
+ const showAfterDelay = (delay) => {
3758
4309
  cancelShow();
3759
- if (delayMs <= 0) {
4310
+ if (delay <= 0) {
3760
4311
  show();
3761
4312
  return;
3762
4313
  }
3763
4314
  showTimer.current = setTimeout(() => {
3764
4315
  showTimer.current = null;
3765
4316
  show();
3766
- }, delayMs);
4317
+ }, delay);
3767
4318
  };
3768
- const withdraw = () => {
4319
+ const withdraw = useCallback(() => {
4320
+ setPinned(false);
3769
4321
  setPos(null);
3770
4322
  announce(false);
3771
- };
4323
+ }, [announce]);
3772
4324
  const hide = () => {
3773
4325
  cancelShow();
3774
- if (!triggers.current.hover && !triggers.current.focus) withdraw();
4326
+ if (!triggers.current.hover && !triggers.current.focus && !pinned) withdraw();
3775
4327
  };
4328
+ const dismiss = useCallback(() => {
4329
+ cancelShow();
4330
+ triggers.current = {
4331
+ hover: false,
4332
+ focus: false
4333
+ };
4334
+ withdraw();
4335
+ }, [cancelShow, withdraw]);
4336
+ useDismissOnOutsidePointer(anchor, openOnClick && visible, dismiss, bubble);
4337
+ useEffect(() => {
4338
+ if (!openOnClick || !visible) return;
4339
+ const onKeyDown = (event) => {
4340
+ if (event.key !== "Escape" && event.key !== "Tab") return;
4341
+ if (event.key === "Escape") {
4342
+ event.preventDefault();
4343
+ event.stopPropagation();
4344
+ }
4345
+ dismiss();
4346
+ };
4347
+ document.addEventListener("keydown", onKeyDown, true);
4348
+ return () => {
4349
+ document.removeEventListener("keydown", onKeyDown, true);
4350
+ };
4351
+ }, [
4352
+ dismiss,
4353
+ openOnClick,
4354
+ visible
4355
+ ]);
3776
4356
  const bubbleNode = visible && !suppressed && jsxs("span", {
3777
4357
  ref: bubble,
3778
- className: css$15.bubble,
4358
+ id: openOnClick ? id : void 0,
4359
+ className: css$18.bubble,
3779
4360
  "data-side": placement,
3780
4361
  "data-portal": portal || void 0,
4362
+ "data-pinned": pinned || void 0,
3781
4363
  "data-has-shortcut": shortcutKeys?.length ? true : void 0,
3782
4364
  style: {
3783
4365
  left: pos.x,
@@ -3787,7 +4369,7 @@ function Tooltip({ label, shortcutKeys, side = "right", delayMs = 0, disabled =
3787
4369
  role: "tooltip",
3788
4370
  "aria-label": shortcutKeys?.length ? [resolvedLabel, shortcutKeys.join(" ")].filter(Boolean).join(" ") : void 0,
3789
4371
  children: [resolvedLabel && jsx("span", {
3790
- className: css$15.label,
4372
+ className: css$18.label,
3791
4373
  children: resolvedLabel
3792
4374
  }), shortcutKeys !== void 0 && shortcutKeys.length > 0 && jsx(ShortcutKeys, {
3793
4375
  keys: shortcutKeys,
@@ -3798,25 +4380,35 @@ function Tooltip({ label, shortcutKeys, side = "right", delayMs = 0, disabled =
3798
4380
  value: setSuppressed,
3799
4381
  children: [cloneElement(children, {
3800
4382
  ref: mergedRef,
4383
+ "aria-describedby": openOnClick && visible ? [children.props["aria-describedby"], id].filter(Boolean).join(" ") : children.props["aria-describedby"],
3801
4384
  onMouseEnter: (e) => {
3802
4385
  children.props.onMouseEnter?.(e);
3803
4386
  trackAnchor(e);
3804
4387
  triggers.current.hover = true;
3805
- showAfterHoverDelay();
4388
+ showAfterDelay(delayMs);
3806
4389
  },
3807
4390
  onMouseLeave: (e) => {
3808
4391
  children.props.onMouseLeave?.(e);
3809
4392
  triggers.current.hover = false;
3810
4393
  cancelShow();
3811
- withdraw();
4394
+ if (!pinned) withdraw();
4395
+ },
4396
+ onClick: (e) => {
4397
+ children.props.onClick?.(e);
4398
+ if (!openOnClick) return;
4399
+ triggers.current.focus = false;
4400
+ cancelShow();
4401
+ if (!disabled && !pinned) {
4402
+ setPinned(true);
4403
+ show();
4404
+ } else withdraw();
3812
4405
  },
3813
4406
  onFocus: (e) => {
3814
4407
  children.props.onFocus?.(e);
3815
4408
  trackAnchor(e);
3816
4409
  if (pointerModality()) return;
3817
4410
  triggers.current.focus = true;
3818
- cancelShow();
3819
- show();
4411
+ showAfterDelay(focusDelayMs);
3820
4412
  },
3821
4413
  onBlur: (e) => {
3822
4414
  children.props.onBlur?.(e);
@@ -3993,7 +4585,7 @@ function HoverCard({ anchor, content, openDelayMs = 500, disabled = false, copyT
3993
4585
  const copyable = copyText !== void 0;
3994
4586
  const card = open && pos !== null && !suppressed && jsx("div", {
3995
4587
  ref: cardRef,
3996
- className: clsx(css$16.card, inline && css$16.media, copyable && css$16.copyable, copied && css$16.feedback),
4588
+ className: clsx(css$19.card, inline && css$19.media, copyable && css$19.copyable, copied && css$19.feedback),
3997
4589
  style: {
3998
4590
  ...pos,
3999
4591
  minHeight: copied && copyHeightRef.current !== null ? copyHeightRef.current : void 0
@@ -4014,14 +4606,14 @@ function HoverCard({ anchor, content, openDelayMs = 500, disabled = false, copyT
4014
4606
  copy(copyText);
4015
4607
  } : void 0,
4016
4608
  children: copied ? jsx("span", {
4017
- className: css$16.copied,
4609
+ className: css$19.copied,
4018
4610
  "aria-hidden": "true",
4019
4611
  children: copiedLabel
4020
4612
  }) : content
4021
4613
  });
4022
4614
  return jsxs("span", {
4023
4615
  ref: rootRef,
4024
- className: clsx(css$16.root, inline && css$16.inline),
4616
+ className: clsx(css$19.root, inline && css$19.inline),
4025
4617
  onFocus: inline ? (event) => {
4026
4618
  if (!disabled && event.target.matches(":focus-visible")) {
4027
4619
  cancelClose();
@@ -4060,7 +4652,7 @@ function HoverCard({ anchor, content, openDelayMs = 500, disabled = false, copyT
4060
4652
  children: anchor
4061
4653
  }),
4062
4654
  open && !suppressed && copyable && jsx("span", {
4063
- className: css$16.status,
4655
+ className: css$19.status,
4064
4656
  role: "status",
4065
4657
  children: copied ? copiedLabel : ""
4066
4658
  }),
@@ -4095,11 +4687,11 @@ function Modal({ open, onClose, title, closeLabel, description, children, footer
4095
4687
  useModalLayer(dialog, open, onClose);
4096
4688
  if (!open) return null;
4097
4689
  return createPortal(jsxs("div", {
4098
- className: css$17.root,
4690
+ className: css$20.root,
4099
4691
  role: "presentation",
4100
4692
  onKeyDownCapture,
4101
4693
  children: [jsx("div", {
4102
- className: css$17.mask,
4694
+ className: css$20.mask,
4103
4695
  style: backdropBlur ? void 0 : { backdropFilter: "none" },
4104
4696
  "aria-hidden": "true",
4105
4697
  onClick: onClose
@@ -4107,37 +4699,37 @@ function Modal({ open, onClose, title, closeLabel, description, children, footer
4107
4699
  ref: dialog,
4108
4700
  tabIndex: -1,
4109
4701
  "data-shortcut-modal": shortcutModal,
4110
- className: clsx(css$17.dialog, className),
4702
+ className: clsx(css$20.dialog, className),
4111
4703
  role: "dialog",
4112
4704
  "aria-modal": "true",
4113
4705
  "aria-label": title,
4114
4706
  children: headless ? children : jsxs(Fragment, { children: [jsxs("div", {
4115
- className: clsx(css$17.content, contentClassName),
4707
+ className: clsx(css$20.content, contentClassName),
4116
4708
  children: [
4117
4709
  jsxs("div", {
4118
- className: css$17.header,
4710
+ className: css$20.header,
4119
4711
  children: [jsx("h2", {
4120
- className: css$17.title,
4712
+ className: css$20.title,
4121
4713
  children: title
4122
4714
  }), jsx("button", {
4123
4715
  type: "button",
4124
- className: css$17.close,
4716
+ className: css$20.close,
4125
4717
  "aria-label": closeLabel,
4126
4718
  onClick: onClose,
4127
4719
  children: jsx(IconCloseOutline16, { size: 14 })
4128
4720
  })]
4129
4721
  }),
4130
4722
  description !== void 0 && description !== "" && jsx("p", {
4131
- className: css$17.description,
4723
+ className: css$20.description,
4132
4724
  children: description
4133
4725
  }),
4134
4726
  children !== void 0 && jsx("div", {
4135
- className: css$17.body,
4727
+ className: css$20.body,
4136
4728
  children
4137
4729
  })
4138
4730
  ]
4139
4731
  }), footer !== void 0 && jsx("div", {
4140
- className: css$17.footer,
4732
+ className: css$20.footer,
4141
4733
  children: footer
4142
4734
  })] })
4143
4735
  })]
@@ -4161,13 +4753,13 @@ function OnboardingSurface({ children }) {
4161
4753
  };
4162
4754
  }, []);
4163
4755
  return createPortal(jsxs("div", {
4164
- className: css$18.onboardingOverlay,
4756
+ className: css$21.onboardingOverlay,
4165
4757
  role: "presentation",
4166
4758
  children: [jsx("div", {
4167
- className: css$18.onboardingMask,
4759
+ className: css$21.onboardingMask,
4168
4760
  "aria-hidden": "true"
4169
4761
  }), jsx("div", {
4170
- className: css$18.onboardingStage,
4762
+ className: css$21.onboardingStage,
4171
4763
  children
4172
4764
  })]
4173
4765
  }), document.body);
@@ -4188,28 +4780,28 @@ function RiskConfirmation({ open, title, description, acknowledgeLabel, cancelLa
4188
4780
  onClose: onCancel,
4189
4781
  title,
4190
4782
  closeLabel,
4191
- className: css$19.confirmation ?? "",
4192
- contentClassName: css$19.confirmationContent ?? "",
4783
+ className: css$22.confirmation ?? "",
4784
+ contentClassName: css$22.confirmationContent ?? "",
4193
4785
  footer: jsxs(Fragment, { children: [jsx(Button, {
4194
4786
  variant: "outline",
4195
- className: css$19.modalAction,
4787
+ className: css$22.modalAction,
4196
4788
  onClick: onCancel,
4197
4789
  children: cancelLabel
4198
4790
  }), jsx(Button, {
4199
4791
  variant: "primary",
4200
- className: css$19.confirmAction,
4792
+ className: css$22.confirmAction,
4201
4793
  disabled: disabled || !acknowledged,
4202
4794
  onClick: onConfirm,
4203
4795
  children: confirmLabel
4204
4796
  })] }),
4205
4797
  children: [jsxs("div", {
4206
- className: css$19.warning,
4798
+ className: css$22.warning,
4207
4799
  children: [jsx(IconWarningOutline16, {
4208
4800
  size: 18,
4209
- className: css$19.warningIcon
4801
+ className: css$22.warningIcon
4210
4802
  }), jsx("p", { children: description })]
4211
4803
  }), jsxs("label", {
4212
- className: css$19.acknowledgement,
4804
+ className: css$22.acknowledgement,
4213
4805
  children: [jsx("input", {
4214
4806
  type: "checkbox",
4215
4807
  checked: acknowledged,
@@ -4257,47 +4849,47 @@ function ConnectionIndicator({ state, disconnectedLabel, connectingLabel, recove
4257
4849
  };
4258
4850
  }, [state, rendered]);
4259
4851
  if (rendered === void 0) return null;
4260
- const leavingClass = leaving ? ` ${css$20.leaving}` : "";
4852
+ const leavingClass = leaving ? ` ${css$23.leaving}` : "";
4261
4853
  if (rendered === "recovered") return jsxs("div", {
4262
- className: `${css$20.indicator} ${css$20.success}${leavingClass}`,
4854
+ className: `${css$23.indicator} ${css$23.success}${leavingClass}`,
4263
4855
  role: "status",
4264
4856
  "aria-label": recoveredLabel,
4265
4857
  children: [jsx("span", {
4266
- className: css$20.icon,
4858
+ className: css$23.icon,
4267
4859
  "aria-hidden": "true",
4268
4860
  children: jsx(IconCheckOutline16, { size: 14 })
4269
4861
  }), jsx("span", {
4270
- className: css$20.label,
4862
+ className: css$23.label,
4271
4863
  children: recoveredLabel
4272
4864
  })]
4273
4865
  });
4274
4866
  const connecting = rendered === "connecting";
4275
4867
  return jsxs("button", {
4276
4868
  type: "button",
4277
- className: `${css$20.indicator} ${css$20.warning}${leavingClass}`,
4869
+ className: `${css$23.indicator} ${css$23.warning}${leavingClass}`,
4278
4870
  "data-phase": rendered,
4279
4871
  "aria-label": connecting ? restartActionLabel : reconnectActionLabel,
4280
4872
  onClick: onReconnect,
4281
4873
  children: [jsx("span", {
4282
- className: css$20.icon,
4874
+ className: css$23.icon,
4283
4875
  "aria-hidden": "true",
4284
4876
  children: connecting ? jsx(IconLoadingOutline16, {
4285
4877
  size: 14,
4286
- className: css$20.spinner
4878
+ className: css$23.spinner
4287
4879
  }) : jsx(IconRefreshOutline14, { size: 14 })
4288
4880
  }), jsx("span", {
4289
- className: css$20.label,
4881
+ className: css$23.label,
4290
4882
  children: connecting ? jsxs(Fragment, { children: [connectingLabel, jsxs("span", {
4291
- className: css$20.dots,
4883
+ className: css$23.dots,
4292
4884
  "aria-hidden": "true",
4293
4885
  children: [
4294
4886
  jsx("span", { children: "." }),
4295
4887
  jsx("span", {
4296
- className: css$20.secondDot,
4888
+ className: css$23.secondDot,
4297
4889
  children: "."
4298
4890
  }),
4299
4891
  jsx("span", {
4300
- className: css$20.thirdDot,
4892
+ className: css$23.thirdDot,
4301
4893
  children: "."
4302
4894
  })
4303
4895
  ]
@@ -5122,7 +5714,7 @@ function FileTypeIcon(props) {
5122
5714
  type: resolvedType,
5123
5715
  size,
5124
5716
  className
5125
- }) : glyph(resolvedType, size, clsx(css$21.icon, css$21[resolvedType], className));
5717
+ }) : glyph(resolvedType, size, clsx(css$24.icon, css$24[resolvedType], className));
5126
5718
  }
5127
5719
  //#endregion
5128
5720
  //#region lib/types/SiteGlyph.js
@@ -5435,22 +6027,772 @@ function PathLabel({ path, className, ...attributes }) {
5435
6027
  return jsx("span", {
5436
6028
  ...attributes,
5437
6029
  ref: boxRef,
5438
- className: clsx(css$22.path, className),
6030
+ className: clsx(css$25.path, className),
5439
6031
  title: path,
5440
6032
  "data-path-label": true,
5441
6033
  children: jsxs("span", {
5442
6034
  ref: textRef,
5443
- className: css$22.text,
6035
+ className: css$25.text,
5444
6036
  children: [directory !== "" && jsx("span", {
5445
- className: css$22.directory,
6037
+ className: css$25.directory,
5446
6038
  children: directory
5447
6039
  }), jsx("span", {
5448
- className: css$22.name,
6040
+ className: css$25.name,
5449
6041
  children: name
5450
6042
  })]
5451
6043
  })
5452
6044
  });
5453
6045
  }
6046
+ const prefixed = (literal, check, run, min, max = 0) => ({
6047
+ literal,
6048
+ kind: 2,
6049
+ check,
6050
+ run,
6051
+ min,
6052
+ max
6053
+ });
6054
+ /**
6055
+ * Every prefixed format matches more than the eight characters a mask leaves
6056
+ * readable, so a near miss never exposes a whole value.
6057
+ */
6058
+ const CREDENTIAL_FORMATS = [
6059
+ {
6060
+ literal: "-----BEGIN ",
6061
+ kind: 0,
6062
+ check: 0,
6063
+ run: 0,
6064
+ min: 0,
6065
+ max: 0
6066
+ },
6067
+ {
6068
+ literal: "://",
6069
+ kind: 1,
6070
+ check: 0,
6071
+ run: 0,
6072
+ min: 0,
6073
+ max: 0
6074
+ },
6075
+ prefixed("sk-", 2, 1, 20),
6076
+ prefixed("AIza", 3, 1, 35),
6077
+ prefixed("ghp_", 0, 2, 36),
6078
+ prefixed("gho_", 0, 2, 36),
6079
+ prefixed("ghu_", 0, 2, 36),
6080
+ prefixed("ghs_", 0, 2, 36),
6081
+ prefixed("ghr_", 0, 2, 36),
6082
+ prefixed("github_pat_", 0, 4, 22),
6083
+ prefixed("glpat-", 0, 1, 20),
6084
+ prefixed("npm_", 0, 2, 36),
6085
+ prefixed("hf_", 0, 2, 30),
6086
+ prefixed("AKIA", 1, 16, 16, 16),
6087
+ prefixed("ASIA", 1, 16, 16, 16),
6088
+ prefixed("LTAI", 1, 2, 12, 20),
6089
+ prefixed("AKID", 1, 2, 28, 36),
6090
+ prefixed("xoxa-", 0, 8, 10),
6091
+ prefixed("xoxb-", 0, 8, 10),
6092
+ prefixed("xoxp-", 0, 8, 10),
6093
+ prefixed("xoxr-", 0, 8, 10),
6094
+ prefixed("xoxs-", 0, 8, 10),
6095
+ prefixed("sk_live_", 0, 2, 16),
6096
+ prefixed("sk_test_", 0, 2, 16),
6097
+ prefixed("rk_live_", 0, 2, 16),
6098
+ prefixed("rk_test_", 0, 2, 16),
6099
+ prefixed("whsec_", 0, 2, 24),
6100
+ prefixed("eyJ", 4, 1, 8, 2048)
6101
+ ];
6102
+ /** Leading characters of a prefixed key left readable: the provider prefix and little else. */
6103
+ const VISIBLE_PREFIX = 8;
6104
+ const SHARED_MARKS = 4096;
6105
+ /** Builds masks; owns the shared mark strings and its sticky run pattern. */
6106
+ var CredentialMasks = class {
6107
+ marksOnly = "*".repeat(SHARED_MARKS);
6108
+ marksLf = `${this.marksOnly}\n`;
6109
+ marksCr = `${this.marksOnly}\r`;
6110
+ /** Code units that `lines` counts without inspection: neither line breaks nor surrogates. Set `lastIndex` before each test. */
6111
+ ordinary = /[^\r\n\ud800-\udfff]*/y;
6112
+ /**
6113
+ * The display form of `text[start, end)`, whose earliest candidate has `kind`.
6114
+ * @param text - the queried text.
6115
+ * @param kind - the literal kind of the range's earliest candidate.
6116
+ * @param plain - the range holds only prefixed-format characters: ASCII without line breaks.
6117
+ * @param start - first offset of the range.
6118
+ * @param end - offset after the range.
6119
+ * @returns the mask; line breaks stay in place, one mark per code point.
6120
+ */
6121
+ masked(text, kind, plain, start, end) {
6122
+ if (kind === 1) return this.range(text, start, end);
6123
+ if (kind === 2) return text.slice(start, start + VISIBLE_PREFIX) + (plain ? this.marks(end - start - VISIBLE_PREFIX) : this.range(text, start + VISIBLE_PREFIX, end));
6124
+ return this.keyBlock(text, start, end);
6125
+ }
6126
+ /**
6127
+ * Marks for a run of hidden characters.
6128
+ * @param count - how many marks.
6129
+ * @returns `count` marks, one slice of the shared string where it reaches.
6130
+ */
6131
+ marks(count) {
6132
+ return count <= SHARED_MARKS ? this.marksOnly.slice(0, count) : "*".repeat(count);
6133
+ }
6134
+ /**
6135
+ * Marks, then one line break, in a single slice.
6136
+ * @param count - how many marks.
6137
+ * @param code - the line break's code unit, 10 or 13.
6138
+ * @returns `count` marks and that line break.
6139
+ */
6140
+ marksThen(count, code) {
6141
+ return count <= SHARED_MARKS ? (code === 10 ? this.marksLf : this.marksCr).slice(SHARED_MARKS - count) : "*".repeat(count) + (code === 10 ? "\n" : "\r");
6142
+ }
6143
+ /**
6144
+ * Keep the `BEGIN` line, the `END` line when present, and every line break; a block written on
6145
+ * one line is masked whole. Both searches stay inside the range, so they cost what the mask costs.
6146
+ * @param text - the queried text.
6147
+ * @param start - first offset of the range.
6148
+ * @param end - offset after the range.
6149
+ * @returns the masked block.
6150
+ */
6151
+ keyBlock(text, start, end) {
6152
+ let bodyStart = start;
6153
+ for (let index = start; index < end; index++) if (text.charCodeAt(index) === 10) {
6154
+ bodyStart = index + 1;
6155
+ break;
6156
+ }
6157
+ let bodyEnd = end;
6158
+ for (let index = end - 9; index >= bodyStart; index--) if (text.charCodeAt(index) === 10 && text.startsWith("-----END", index + 1)) {
6159
+ bodyEnd = index;
6160
+ break;
6161
+ }
6162
+ const body = bodyEnd === text.length || text.charCodeAt(bodyEnd) === 10 || text.charCodeAt(bodyEnd) === 13 ? this.lines(text, bodyStart, bodyEnd) : this.range(text, bodyStart, bodyEnd);
6163
+ return text.slice(start, bodyStart) + body + text.slice(bodyEnd, end);
6164
+ }
6165
+ /**
6166
+ * Replace every character except line breaks; a surrogate pair is one character,
6167
+ * as `[^\r\n]` with the `u` flag counts it. A character loop: a native run could read far past `end`.
6168
+ * @param text - the queried text.
6169
+ * @param start - first offset of the range.
6170
+ * @param end - offset after the range.
6171
+ * @returns the masked range.
6172
+ */
6173
+ range(text, start, end) {
6174
+ let masked = "";
6175
+ let count = 0;
6176
+ for (let index = start; index < end; index++) {
6177
+ const code = text.charCodeAt(index);
6178
+ if (code === 10 || code === 13) {
6179
+ masked += this.marksThen(count, code);
6180
+ count = 0;
6181
+ continue;
6182
+ }
6183
+ if (code >= 55296 && code <= 56319 && index + 1 < end) {
6184
+ const next = text.charCodeAt(index + 1);
6185
+ if (next >= 56320 && next <= 57343) index++;
6186
+ }
6187
+ count++;
6188
+ }
6189
+ return masked + this.marks(count);
6190
+ }
6191
+ /**
6192
+ * `range` for a body that ends at a line break or the end of the text, where native runs stop.
6193
+ * @param text - the queried text.
6194
+ * @param start - first offset of the range.
6195
+ * @param end - offset after the range.
6196
+ * @returns the masked body.
6197
+ */
6198
+ lines(text, start, end) {
6199
+ const ordinary = this.ordinary;
6200
+ let masked = "";
6201
+ let count = 0;
6202
+ let index = start;
6203
+ while (index < end) {
6204
+ ordinary.lastIndex = index;
6205
+ ordinary.test(text);
6206
+ const stop = Math.min(ordinary.lastIndex, end);
6207
+ count += stop - index;
6208
+ if (stop === end) break;
6209
+ const code = text.charCodeAt(stop);
6210
+ index = stop + 1;
6211
+ if (code === 10 || code === 13) {
6212
+ masked += this.marksThen(count, code);
6213
+ count = 0;
6214
+ continue;
6215
+ }
6216
+ if (code <= 56319 && index < end) {
6217
+ const next = text.charCodeAt(index);
6218
+ if (next >= 56320 && next <= 57343) index++;
6219
+ }
6220
+ count++;
6221
+ }
6222
+ return masked + this.marks(count);
6223
+ }
6224
+ };
6225
+ //#endregion
6226
+ //#region lib/types/SecretText.js
6227
+ /**
6228
+ * Masked credential presentation: the masked form by default, plus a control
6229
+ * that reveals this one value in interactive text.
6230
+ */
6231
+ const EYE_PATH = "M1.5 8C2.9 5.25 5.25 3.5 8 3.5C10.75 3.5 13.1 5.25 14.5 8C13.1 10.75 10.75 12.5 8 12.5C5.25 12.5 2.9 10.75 1.5 8ZM10 8C10 9.1 9.1 10 8 10C6.9 10 6 9.1 6 8C6 6.9 6.9 6 8 6C9.1 6 10 6.9 10 8Z";
6232
+ /** The struck-through glyph drops the pupil so it stays distinct at text size. */
6233
+ const EYE_OFF_PATH = "M1.5 8C2.9 5.25 5.25 3.5 8 3.5C10.75 3.5 13.1 5.25 14.5 8C13.1 10.75 10.75 12.5 8 12.5C5.25 12.5 2.9 10.75 1.5 8ZM2.5 2.5L13.5 13.5";
6234
+ const MASK_RUNS = /* @__PURE__ */ new RegExp("(\\*+)", "u");
6235
+ /**
6236
+ * One eye glyph, drawn in the current text color.
6237
+ * @param props - the outline to draw.
6238
+ * @returns the glyph.
6239
+ */
6240
+ function EyeGlyph({ path }) {
6241
+ return jsx("svg", {
6242
+ className: css$26.icon,
6243
+ viewBox: "0 0 16 16",
6244
+ fill: "none",
6245
+ stroke: "currentColor",
6246
+ strokeWidth: 1.3,
6247
+ strokeLinecap: "round",
6248
+ "aria-hidden": "true",
6249
+ children: jsx("path", { d: path })
6250
+ });
6251
+ }
6252
+ /**
6253
+ * Split a masked form into kept text and mask runs. A mask run keeps its
6254
+ * characters for copying and assistive technology but draws centered tiles,
6255
+ * because a font's own asterisk sits near the cap height.
6256
+ * @param props - the masked form.
6257
+ * @returns the inline parts covering it.
6258
+ */
6259
+ function MaskedText({ masked }) {
6260
+ let offset = 0;
6261
+ return masked.split(MASK_RUNS).map((part) => {
6262
+ const key = offset;
6263
+ offset += part.length;
6264
+ if (part === "") return null;
6265
+ return part.startsWith("*") ? jsx("span", {
6266
+ className: css$26.mask,
6267
+ children: part
6268
+ }, key) : jsx("span", { children: part }, key);
6269
+ });
6270
+ }
6271
+ /**
6272
+ * Draw one credential masked. Interactive text adds a control that reveals or
6273
+ * hides this value; every mount, and every different original value at the same
6274
+ * position, starts masked.
6275
+ * @param props - the masked form, the original spelling, and optional control copy.
6276
+ * @returns the masked run, with the reveal control when copy is supplied.
6277
+ */
6278
+ function SecretText({ masked, raw, labels }) {
6279
+ const [revealedRaw, setRevealedRaw] = useState();
6280
+ const revealed = labels !== void 0 && revealedRaw === raw;
6281
+ return jsxs("span", {
6282
+ className: css$26.secret,
6283
+ "data-secret": "",
6284
+ children: [jsx("span", { children: revealed ? raw : jsx(MaskedText, { masked }) }), labels !== void 0 && jsx("button", {
6285
+ type: "button",
6286
+ className: css$26.toggle,
6287
+ "aria-pressed": revealed,
6288
+ "aria-label": revealed ? labels.hide : labels.reveal,
6289
+ onClick: () => {
6290
+ setRevealedRaw(revealed ? void 0 : raw);
6291
+ },
6292
+ children: jsx(EyeGlyph, { path: revealed ? EYE_OFF_PATH : EYE_PATH })
6293
+ })]
6294
+ });
6295
+ }
6296
+ //#endregion
6297
+ //#region lib/types/format-tables.js
6298
+ /** Lookup tables derived from the credential formats, built once on first use. */
6299
+ let tables;
6300
+ /**
6301
+ * The tables for `CREDENTIAL_FORMATS`; the first call builds them.
6302
+ * @returns the shared, read-only tables.
6303
+ */
6304
+ function formatTables() {
6305
+ tables ??= buildTables();
6306
+ return tables;
6307
+ }
6308
+ /**
6309
+ * Build every lookup table once.
6310
+ * @returns the tables.
6311
+ */
6312
+ function buildTables() {
6313
+ const formats = CREDENTIAL_FORMATS;
6314
+ const literals = formats.map((f) => f.literal);
6315
+ const { ending, sharedEndings } = endingTables(literals);
6316
+ return {
6317
+ classes: charClasses(),
6318
+ literals,
6319
+ literalLength: Uint8Array.from(literals, (literal) => literal.length),
6320
+ literalKind: Uint8Array.from(formats, (f) => f.kind),
6321
+ literalCheck: Uint8Array.from(formats, (f) => f.check),
6322
+ literalRun: Uint16Array.from(formats, (f) => f.run),
6323
+ literalMin: Int32Array.from(formats, (f) => f.min),
6324
+ literalMax: Int32Array.from(formats, (f) => f.max),
6325
+ literalOverlap: Uint8Array.from(literals, (literal) => overlap(literal, literals)),
6326
+ prefixSource: alternation(literals),
6327
+ ending,
6328
+ sharedEndings
6329
+ };
6330
+ }
6331
+ /**
6332
+ * Class bits for every ASCII code unit; non-ASCII units carry none.
6333
+ * @returns the 128-entry table.
6334
+ */
6335
+ function charClasses() {
6336
+ const classes = new Uint16Array(128);
6337
+ for (let code = 0; code < 128; code++) {
6338
+ const upper = code >= 65 && code <= 90;
6339
+ const lower = code >= 97 && code <= 122;
6340
+ const digit = code >= 48 && code <= 57;
6341
+ const alnum = upper || lower || digit;
6342
+ const authority = !(code >= 9 && code <= 13 || code === 32 || code === 47 || code === 64 || code === 63 || code === 35);
6343
+ classes[code] = (alnum || code === 95 || code === 45 ? 1 : 0) | (alnum ? 2 : 0) | (alnum || code === 95 ? 4 : 0) | (alnum || code === 45 ? 8 : 0) | (upper || digit ? 16 : 0) | (upper || digit || code === 32 ? 32 : 0) | (lower || digit || code === 43 || code === 46 || code === 45 ? 64 : 0) | (lower ? 128 : 0) | (authority && code !== 58 ? 256 : 0) | (authority ? 512 : 0);
6344
+ }
6345
+ return classes;
6346
+ }
6347
+ /**
6348
+ * Length of the longest proper suffix of `literal` that begins another literal.
6349
+ * @param literal - the literal to measure.
6350
+ * @param literals - every literal.
6351
+ * @returns that suffix length, or 0.
6352
+ */
6353
+ function overlap(literal, literals) {
6354
+ for (let size = literal.length - 1; size > 0; size--) {
6355
+ const suffix = literal.slice(-size);
6356
+ if (literals.some((other) => other.startsWith(suffix))) return size;
6357
+ }
6358
+ return 0;
6359
+ }
6360
+ /**
6361
+ * Index the literals by their last two code units so the scan reads the matched
6362
+ * literal from the prefix alternation's end.
6363
+ * @param literals - every literal.
6364
+ * @returns the single-literal table and the table of endings several literals share.
6365
+ */
6366
+ function endingTables(literals) {
6367
+ const ending = new Int8Array(16384);
6368
+ const sharedEndings = [];
6369
+ literals.forEach((literal, index) => {
6370
+ const key = literal.charCodeAt(literal.length - 2) * 128 + literal.charCodeAt(literal.length - 1);
6371
+ const existing = ending[key];
6372
+ if (existing === 0) {
6373
+ ending[key] = index + 1;
6374
+ return;
6375
+ }
6376
+ if (existing > 0) {
6377
+ sharedEndings[key] = [existing - 1];
6378
+ ending[key] = -1;
6379
+ }
6380
+ sharedEndings[key].push(index);
6381
+ });
6382
+ return {
6383
+ ending,
6384
+ sharedEndings
6385
+ };
6386
+ }
6387
+ const escape = (literal) => literal.replace(/[.*+?^${}()|[\]\\/]/gu, "\\$&");
6388
+ /**
6389
+ * Literal alternatives grouped by shared leading characters; groups only factor literals and add no quantifier.
6390
+ * @param literals - every literal.
6391
+ * @returns the alternation source.
6392
+ */
6393
+ function alternation(literals) {
6394
+ const groups = /* @__PURE__ */ new Map();
6395
+ for (const literal of literals) groups.set(literal.charAt(0), [...groups.get(literal.charAt(0)) ?? [], literal.slice(1)]);
6396
+ return [...groups].map(([head, tails]) => tails.length === 1 ? escape(head + tails.join("")) : `${escape(head)}(?:${alternation(tails)})`).join("|");
6397
+ }
6398
+ //#endregion
6399
+ //#region lib/types/credential-scanner.js
6400
+ /**
6401
+ * Prefix-pruned, linear credential scanning that allocates nothing until it
6402
+ * returns a range. A literal-only alternation finds each place a format can
6403
+ * begin and resumes inside a literal that can overlap the next one. Format
6404
+ * checks are bounded character comparisons and sticky `[class]*` runs, which
6405
+ * end at the first character outside the class and leave nothing to backtrack
6406
+ * into. Run ends, the next digit, and the next key-block `END` line are
6407
+ * memoized per text across queries, so each is measured once per text.
6408
+ */
6409
+ const KEY_SLOTS = 0;
6410
+ const KEY_NEXT = 8;
6411
+ const ALNUM_SLOT = 9;
6412
+ const WORD_SLOT = 11;
6413
+ const ALNUM_DASH_SLOT = 13;
6414
+ const UPPER_ALNUM_SLOT = 15;
6415
+ const USER_SLOT = 17;
6416
+ const PASSWORD_SLOT = 19;
6417
+ const DIGIT_FROM = 21;
6418
+ const DIGIT_AT = 22;
6419
+ const BLOCK_FROM = 23;
6420
+ const BLOCK_END_START = 24;
6421
+ const BLOCK_END = 25;
6422
+ /** Start of the password that the last address check accepted. */
6423
+ const CANDIDATE_START = 26;
6424
+ const MEMO_SIZE = 27;
6425
+ /** `\s` above ASCII. */
6426
+ function isWideSpace(code) {
6427
+ return code === 160 || code === 5760 || code >= 8192 && code <= 8202 || code === 8232 || code === 8233 || code === 8239 || code === 8287 || code === 12288 || code === 65279;
6428
+ }
6429
+ /**
6430
+ * Offset after the run that sticky `pattern` matches at `start`.
6431
+ * @param pattern - sticky run pattern.
6432
+ * @param text - the text to measure.
6433
+ * @param start - offset the run starts at.
6434
+ * @returns offset after the run.
6435
+ */
6436
+ function runEnd(pattern, text, start) {
6437
+ pattern.lastIndex = start;
6438
+ pattern.test(text);
6439
+ return pattern.lastIndex;
6440
+ }
6441
+ /**
6442
+ * One scanner's state: the tables, its own patterns, and a memo of the last
6443
+ * queried text, which it keeps until a query for another text. Queries are
6444
+ * synchronous and never re-enter, so the patterns' cursors are never shared.
6445
+ */
6446
+ var CredentialScanner = class {
6447
+ classes;
6448
+ literals;
6449
+ literalLength;
6450
+ literalKind;
6451
+ literalCheck;
6452
+ literalMin;
6453
+ literalMax;
6454
+ literalOverlap;
6455
+ ending;
6456
+ sharedEndings;
6457
+ /** Memo slot of each prefixed format's run class; 0 for `[A-Za-z0-9_-]`, which has four. */
6458
+ literalSlot;
6459
+ literalPattern;
6460
+ prefixes;
6461
+ keyRun = /[A-Za-z0-9_-]*/y;
6462
+ userRun = /[^\s/:@?#]*/y;
6463
+ passwordRun = /[^\s/@?#]*/y;
6464
+ nonDigits = /\D*/y;
6465
+ masks = new CredentialMasks();
6466
+ memo = new Int32Array(MEMO_SIZE).fill(-1);
6467
+ text = "";
6468
+ /**
6469
+ * Build one scanner over shared tables.
6470
+ * @param tables - the tables every scanner shares.
6471
+ */
6472
+ constructor(tables) {
6473
+ this.classes = tables.classes;
6474
+ this.literals = tables.literals;
6475
+ this.literalLength = tables.literalLength;
6476
+ this.literalKind = tables.literalKind;
6477
+ this.literalCheck = tables.literalCheck;
6478
+ this.literalMin = tables.literalMin;
6479
+ this.literalMax = tables.literalMax;
6480
+ this.literalOverlap = tables.literalOverlap;
6481
+ this.ending = tables.ending;
6482
+ this.sharedEndings = tables.sharedEndings;
6483
+ this.prefixes = new RegExp(tables.prefixSource, "g");
6484
+ const patterns = new Map([
6485
+ [2, [ALNUM_SLOT, /[A-Za-z0-9]*/y]],
6486
+ [4, [WORD_SLOT, /\w*/y]],
6487
+ [8, [ALNUM_DASH_SLOT, /[A-Za-z0-9-]*/y]],
6488
+ [16, [UPPER_ALNUM_SLOT, /[A-Z0-9]*/y]]
6489
+ ]);
6490
+ this.literalSlot = Uint8Array.from(tables.literalRun, (run) => patterns.get(run)?.[0] ?? 0);
6491
+ this.literalPattern = Array.from(tables.literalRun, (run) => patterns.get(run)?.[1] ?? this.keyRun);
6492
+ }
6493
+ /**
6494
+ * The nearest credential at or after `from`. Overlapping candidates of any format join the earliest
6495
+ * one and take its mask, so no credential is drawn half masked. Candidates arrive in start order;
6496
+ * an address password waits until the scan passes its start, and no other `://` can occur before
6497
+ * then, because a user name and a password exclude `/`. A password that starts inside a range also
6498
+ * ends inside it: the range holds the `:` before the password, so it is a key block, whose `END`
6499
+ * line has spaces, or one that runs to the end of the text.
6500
+ * @param text - the complete original text.
6501
+ * @param from - the query offset.
6502
+ * @returns the nearest credential range, or undefined when none starts at or after `from`.
6503
+ */
6504
+ match(text, from) {
6505
+ if (text !== this.text) {
6506
+ this.memo.fill(-1);
6507
+ this.text = text;
6508
+ }
6509
+ const prefixes = this.prefixes;
6510
+ const length = text.length;
6511
+ let start = -1;
6512
+ let end = -1;
6513
+ let kind = 2;
6514
+ let plain = true;
6515
+ let deferredEnd = this.addressBefore(from);
6516
+ let deferredStart = deferredEnd < 0 ? -1 : this.slot(CANDIDATE_START);
6517
+ prefixes.lastIndex = from;
6518
+ while (prefixes.test(text)) {
6519
+ const literalEnd = prefixes.lastIndex;
6520
+ const literal = this.literalEndingAt(literalEnd);
6521
+ const at = literalEnd - this.literalLength[literal];
6522
+ prefixes.lastIndex = literalEnd - this.literalOverlap[literal];
6523
+ if (deferredStart >= 0 && deferredStart <= at) {
6524
+ if (start < 0) {
6525
+ start = deferredStart;
6526
+ end = deferredEnd;
6527
+ kind = 1;
6528
+ } else break;
6529
+ deferredStart = -1;
6530
+ }
6531
+ if (start >= 0 && (at >= end || end === length)) break;
6532
+ const literalKind = this.literalKind[literal];
6533
+ if (literalKind === 1) {
6534
+ deferredEnd = this.addressPassword(at);
6535
+ deferredStart = deferredEnd < 0 ? -1 : this.slot(CANDIDATE_START);
6536
+ continue;
6537
+ }
6538
+ const candidateEnd = literalKind === 0 ? this.keyBlockEnd(at) : this.prefixedEnd(literal, at);
6539
+ if (candidateEnd < 0) continue;
6540
+ if (start < 0) {
6541
+ start = at;
6542
+ end = candidateEnd;
6543
+ kind = literalKind;
6544
+ plain = literalKind === 2;
6545
+ } else if (candidateEnd > end) {
6546
+ end = candidateEnd;
6547
+ if (literalKind !== 2) plain = false;
6548
+ }
6549
+ }
6550
+ if (start < 0 && deferredStart >= 0) {
6551
+ start = deferredStart;
6552
+ end = deferredEnd;
6553
+ kind = 1;
6554
+ }
6555
+ if (start < 0) return void 0;
6556
+ return {
6557
+ start,
6558
+ end,
6559
+ masked: this.masks.masked(text, kind, plain, start, end)
6560
+ };
6561
+ }
6562
+ /**
6563
+ * Memo entry at `index`; the layout keeps every index inside the array.
6564
+ * @param index - the memo index.
6565
+ * @returns the stored offset.
6566
+ */
6567
+ slot(index) {
6568
+ return this.memo[index];
6569
+ }
6570
+ /**
6571
+ * `\w` at one offset; out of range is not a word character.
6572
+ * @param index - the offset to read.
6573
+ * @returns whether the code unit is a word character.
6574
+ */
6575
+ isWordAt(index) {
6576
+ const code = this.text.charCodeAt(index);
6577
+ return code < 128 && (this.classes[code] & 4) !== 0;
6578
+ }
6579
+ /**
6580
+ * `[^\s/:@?#]` for one UTF-16 code unit; NaN, read out of range, is not one.
6581
+ * @param code - the code unit.
6582
+ * @returns whether the code unit may appear in an address user name.
6583
+ */
6584
+ isUserCode(code) {
6585
+ return code < 128 ? (this.classes[code] & 256) !== 0 : code === code && !isWideSpace(code);
6586
+ }
6587
+ /**
6588
+ * Index of the literal the prefix scan matched ending at `end`; one literal sharing the ending matches, so the last needs no check.
6589
+ * @param end - the offset after the matched literal.
6590
+ * @returns the literal's index.
6591
+ */
6592
+ literalEndingAt(end) {
6593
+ const text = this.text;
6594
+ const key = text.charCodeAt(end - 2) * 128 + text.charCodeAt(end - 1);
6595
+ const literal = this.ending[key];
6596
+ if (literal > 0) return literal - 1;
6597
+ const shared = this.sharedEndings[key];
6598
+ let index = 0;
6599
+ for (; index < shared.length - 1; index++) {
6600
+ const candidate = shared[index];
6601
+ if (text.startsWith(this.literals[candidate], end - this.literalLength[candidate])) break;
6602
+ }
6603
+ return shared[index];
6604
+ }
6605
+ /**
6606
+ * End of the `[A-Za-z0-9_-]*` run at `start`, through four memo pairs replaced in turn.
6607
+ * @param start - the run's first offset.
6608
+ * @returns the offset after the run.
6609
+ */
6610
+ keyRunEnd(start) {
6611
+ for (let slot = KEY_SLOTS; slot < KEY_NEXT; slot += 2) if (this.slot(slot) <= start && start <= this.slot(slot + 1)) return this.slot(slot + 1);
6612
+ const end = runEnd(this.keyRun, this.text, start);
6613
+ const next = this.slot(KEY_NEXT) + 1 & 3;
6614
+ this.memo[KEY_NEXT] = next;
6615
+ this.memo[KEY_SLOTS + 2 * next] = start;
6616
+ this.memo[KEY_SLOTS + 2 * next + 1] = end;
6617
+ return end;
6618
+ }
6619
+ /**
6620
+ * End of the run `pattern` matches at `start`, through the memo pair at `slot`.
6621
+ * @param pattern - the sticky run pattern.
6622
+ * @param start - the run's first offset.
6623
+ * @param slot - the memo pair to fill.
6624
+ * @returns the offset after the run.
6625
+ */
6626
+ memoRunEnd(pattern, start, slot) {
6627
+ if (this.slot(slot) <= start && start <= this.slot(slot + 1)) return this.slot(slot + 1);
6628
+ const end = runEnd(pattern, this.text, start);
6629
+ this.memo[slot] = start;
6630
+ this.memo[slot + 1] = end;
6631
+ return end;
6632
+ }
6633
+ /**
6634
+ * Offset of the first digit at or after `start`, or the text length.
6635
+ * @param start - the offset to search from.
6636
+ * @returns the digit's offset.
6637
+ */
6638
+ nextDigit(start) {
6639
+ if (this.slot(DIGIT_FROM) <= start && start <= this.slot(DIGIT_AT)) return this.slot(DIGIT_AT);
6640
+ this.memo[DIGIT_FROM] = start;
6641
+ this.memo[DIGIT_AT] = runEnd(this.nonDigits, this.text, start);
6642
+ return this.slot(DIGIT_AT);
6643
+ }
6644
+ /**
6645
+ * Offset after `[A-Z0-9 ]{0,40}PRIVATE KEY-----` at `start`, or -1; reads at most 52 characters.
6646
+ * @param start - the offset the label starts at.
6647
+ * @returns the offset after the header label, or -1.
6648
+ */
6649
+ labelEnd(start) {
6650
+ const text = this.text;
6651
+ const limit = Math.min(text.length, start + 52);
6652
+ let index = start;
6653
+ while (index < limit) {
6654
+ const code = text.charCodeAt(index);
6655
+ if (code > 127 || (this.classes[code] & 32) === 0) break;
6656
+ index++;
6657
+ }
6658
+ const tail = index - 11;
6659
+ return index < start + 52 && tail >= start && text.startsWith("PRIVATE KEY-----", tail) ? tail + 16 : -1;
6660
+ }
6661
+ /**
6662
+ * End of the `-----BEGIN [A-Z0-9 ]{0,40}PRIVATE KEY-----` block at `at`: after its first complete
6663
+ * `END` line, or the end of the text; -1 for an invalid header.
6664
+ * @param at - the offset of the `-----BEGIN ` literal.
6665
+ * @returns the offset after the block, or -1.
6666
+ */
6667
+ keyBlockEnd(at) {
6668
+ const header = this.labelEnd(at + 11);
6669
+ if (header < 0) return -1;
6670
+ if (this.slot(BLOCK_FROM) <= header && header <= this.slot(BLOCK_END_START)) return this.slot(BLOCK_END);
6671
+ const text = this.text;
6672
+ this.memo[BLOCK_FROM] = header;
6673
+ this.memo[BLOCK_END_START] = text.length;
6674
+ this.memo[BLOCK_END] = text.length;
6675
+ for (let line = text.indexOf("-----END ", header); line >= 0; line = text.indexOf("-----END ", line + 1)) {
6676
+ const end = this.labelEnd(line + 9);
6677
+ if (end < 0) continue;
6678
+ this.memo[BLOCK_END_START] = line;
6679
+ this.memo[BLOCK_END] = end;
6680
+ break;
6681
+ }
6682
+ return this.slot(BLOCK_END);
6683
+ }
6684
+ /**
6685
+ * Whether `\b[a-z][a-z0-9+.-]{1,15}` ends at `at`; reads at most 17 characters back.
6686
+ * @param at - the offset after the scheme.
6687
+ * @returns whether a scheme ends there.
6688
+ */
6689
+ schemeBefore(at) {
6690
+ const text = this.text;
6691
+ for (let start = at - 1; start >= 0 && start >= at - 16; start--) {
6692
+ const code = text.charCodeAt(start);
6693
+ const bits = code < 128 ? this.classes[code] : 0;
6694
+ if ((bits & 64) === 0) return false;
6695
+ if ((bits & 128) !== 0 && at - start >= 2 && !this.isWordAt(start - 1)) return true;
6696
+ }
6697
+ return false;
6698
+ }
6699
+ /**
6700
+ * The password in `\b[a-z][a-z0-9+.-]{1,15}://[^\s/:@?#]{0,256}:[^\s/@?#]+@` for the `://` at
6701
+ * `at`; neither part crosses `?` or `#`, where the authority ends. Callers pass a `://` at or after
6702
+ * the query offset, or one whose user name reaches it, so the password never starts before it.
6703
+ * @param at - the offset of the `://` literal.
6704
+ * @returns the password end with its start in the memo, or -1.
6705
+ */
6706
+ addressPassword(at) {
6707
+ if (!this.schemeBefore(at)) return -1;
6708
+ const text = this.text;
6709
+ const userStart = at + 3;
6710
+ const userEnd = this.memoRunEnd(this.userRun, userStart, USER_SLOT);
6711
+ if (userEnd - userStart > 256 || text.charCodeAt(userEnd) !== 58) return -1;
6712
+ const start = userEnd + 1;
6713
+ const end = this.memoRunEnd(this.passwordRun, start, PASSWORD_SLOT);
6714
+ if (end === start || text.charCodeAt(end) !== 64) return -1;
6715
+ this.memo[CANDIDATE_START] = start;
6716
+ return end;
6717
+ }
6718
+ /**
6719
+ * The address password at or after `from` whose `://` starts before `from`, as `addressPassword`
6720
+ * returns it. The walk back over the user name runs only when a `:`, a password, and `@` follow.
6721
+ * @param from - the query offset.
6722
+ * @returns the password end with its start in the memo, or -1.
6723
+ */
6724
+ addressBefore(from) {
6725
+ const text = this.text;
6726
+ if (from < 3) return -1;
6727
+ if (text.startsWith("://", from - 1)) return this.addressPassword(from - 1);
6728
+ if (text.startsWith("://", from - 2)) return this.addressPassword(from - 2);
6729
+ let index = from - 1;
6730
+ const before = text.charCodeAt(index);
6731
+ let passwordStart;
6732
+ if (before === 58) {
6733
+ passwordStart = from;
6734
+ index--;
6735
+ } else if (this.isUserCode(before)) {
6736
+ const userEnd = this.memoRunEnd(this.userRun, from, USER_SLOT);
6737
+ if (text.charCodeAt(userEnd) !== 58) return -1;
6738
+ passwordStart = userEnd + 1;
6739
+ } else return text.startsWith("://", from - 3) ? this.addressPassword(from - 3) : -1;
6740
+ const passwordEnd = this.memoRunEnd(this.passwordRun, passwordStart, PASSWORD_SLOT);
6741
+ if (passwordEnd === passwordStart || text.charCodeAt(passwordEnd) !== 64) return -1;
6742
+ const lowest = Math.max(0, passwordStart - 258);
6743
+ while (index >= lowest && this.isUserCode(text.charCodeAt(index))) index--;
6744
+ return index >= 2 && text.startsWith("://", index - 2) ? this.addressPassword(index - 2) : -1;
6745
+ }
6746
+ /**
6747
+ * End of the prefixed credential whose literal starts at `at`, or -1.
6748
+ * @param literal - the literal's index.
6749
+ * @param at - the offset of the literal.
6750
+ * @returns the offset after the credential, or -1.
6751
+ */
6752
+ prefixedEnd(literal, at) {
6753
+ if (this.isWordAt(at - 1)) return -1;
6754
+ const text = this.text;
6755
+ const start = at + this.literalLength[literal];
6756
+ const check = this.literalCheck[literal];
6757
+ const min = this.literalMin[literal];
6758
+ if (check === 2) {
6759
+ const digit = this.nextDigit(start);
6760
+ if (digit - start > 255) return -1;
6761
+ const end = this.keyRunEnd(start);
6762
+ return end - start >= min && digit < end ? end : -1;
6763
+ }
6764
+ const slot = this.literalSlot[literal];
6765
+ const end = slot === 0 ? this.keyRunEnd(start) : this.memoRunEnd(this.literalPattern[literal], start, slot);
6766
+ const length = end - start;
6767
+ if (length < min) return -1;
6768
+ if (check === 0) return end;
6769
+ if (check === 3) return start + min;
6770
+ if (check === 1) return length <= this.literalMax[literal] && !this.isWordAt(end) ? end : -1;
6771
+ if (length > this.literalMax[literal] || !text.startsWith(".eyJ", end)) return -1;
6772
+ const payloadStart = end + 4;
6773
+ const payloadEnd = this.keyRunEnd(payloadStart);
6774
+ if (payloadEnd - payloadStart < min || text.charCodeAt(payloadEnd) !== 46) return -1;
6775
+ const signatureEnd = this.keyRunEnd(payloadEnd + 1);
6776
+ return signatureEnd - (payloadEnd + 1) >= min ? signatureEnd : -1;
6777
+ }
6778
+ };
6779
+ const scanner = new CredentialScanner(formatTables());
6780
+ /**
6781
+ * Every credential in `text`, in start order, each with the display form that
6782
+ * masks it.
6783
+ * @param text - the original user text.
6784
+ * @returns the masked ranges; empty when the text holds no recognized credential.
6785
+ */
6786
+ function scanSecrets(text) {
6787
+ const ranges = [];
6788
+ let from = 0;
6789
+ for (;;) {
6790
+ const match = scanner.match(text, from);
6791
+ if (match === void 0) return ranges;
6792
+ ranges.push(match);
6793
+ from = match.end;
6794
+ }
6795
+ }
5454
6796
  //#endregion
5455
6797
  //#region lib/types/user-text.js
5456
6798
  /** The wire form a session chip serializes to; label is the display text. */
@@ -5466,24 +6808,35 @@ const TRAILING_PUNCTUATION_RE = /[.,;:!?,。;:!?]+$/u;
5466
6808
  * (unsent queue rows pass none).
5467
6809
  * @param slashKind - the chip kind those tokens render as.
5468
6810
  * @param references - optional file and skill preview actions; session and command tokens stay labels.
6811
+ * @param secretLabels - reveal-control copy for credentials; absent in text that stays masked.
5469
6812
  * @returns inline nodes covering the whole text.
5470
6813
  */
5471
- function projectUserText(text, sessionLabels, slashNames = [], slashKind = "skill", references) {
5472
- const ranges = [];
6814
+ function projectUserText(text, sessionLabels, slashNames = [], slashKind = "skill", references, secretLabels) {
6815
+ const secrets = scanSecrets(text);
6816
+ const ranges = secrets.map((secret) => ({
6817
+ start: secret.start,
6818
+ end: secret.end,
6819
+ kind: "secret",
6820
+ masked: secret.masked
6821
+ }));
6822
+ const maskedOver = (start, end) => secrets.some((secret) => start < secret.end && secret.start < end);
5473
6823
  SESSION_WIRE_RE.lastIndex = 0;
5474
6824
  let wire;
5475
- while ((wire = SESSION_WIRE_RE.exec(text)) !== null) ranges.push({
5476
- start: wire.index,
5477
- end: wire.index + wire[0].length,
5478
- label: wire[0],
5479
- kind: "session",
5480
- display: wire[1]
5481
- });
6825
+ while ((wire = SESSION_WIRE_RE.exec(text)) !== null) {
6826
+ if (maskedOver(wire.index, wire.index + wire[0].length)) continue;
6827
+ ranges.push({
6828
+ start: wire.index,
6829
+ end: wire.index + wire[0].length,
6830
+ label: wire[0],
6831
+ kind: "session",
6832
+ display: wire[1]
6833
+ });
6834
+ }
5482
6835
  for (const rawLabel of [...new Set(sessionLabels)].sort((a, b) => b.length - a.length)) {
5483
6836
  const label = `@${rawLabel}`;
5484
6837
  let start = text.indexOf(label);
5485
6838
  while (start >= 0) {
5486
- ranges.push({
6839
+ if (!maskedOver(start, start + label.length)) ranges.push({
5487
6840
  start,
5488
6841
  end: start + label.length,
5489
6842
  label,
@@ -5500,6 +6853,7 @@ function projectUserText(text, sessionLabels, slashNames = [], slashKind = "skil
5500
6853
  const label = rawLabel.startsWith("@\"") ? rawLabel : rawLabel.replace(TRAILING_PUNCTUATION_RE, "");
5501
6854
  if (label.length <= 1) continue;
5502
6855
  if (label.startsWith("/") && !slashNames.includes(label.slice(1))) continue;
6856
+ if (maskedOver(tokenStart, tokenStart + label.length)) continue;
5503
6857
  ranges.push({
5504
6858
  start: tokenStart,
5505
6859
  end: tokenStart + label.length,
@@ -5513,27 +6867,37 @@ function projectUserText(text, sessionLabels, slashNames = [], slashKind = "skil
5513
6867
  let cursor = 0;
5514
6868
  const pushPlain = (from, to) => {
5515
6869
  parts.push(jsx("span", {
5516
- className: css$23.plainRun,
6870
+ className: css$27.plainRun,
5517
6871
  children: text.slice(from, to)
5518
6872
  }, `t${from}`));
5519
6873
  };
5520
6874
  for (const range of ranges) {
5521
6875
  if (range.start < cursor) continue;
5522
- const { start: tokenStart, end, label, kind } = range;
6876
+ const { start: tokenStart, end } = range;
5523
6877
  if (tokenStart > cursor) pushPlain(cursor, tokenStart);
6878
+ if (range.kind === "secret") {
6879
+ parts.push(jsx(SecretText, {
6880
+ masked: range.masked,
6881
+ raw: text.slice(tokenStart, end),
6882
+ labels: secretLabels
6883
+ }, `sec${tokenStart}`));
6884
+ cursor = end;
6885
+ continue;
6886
+ }
6887
+ const { label, kind } = range;
5524
6888
  const referenceKind = kind === "session" ? "session" : label.startsWith("@") ? label.replace(/^@"|"$/gu, "").endsWith("/") ? "folder" : "file" : void 0;
5525
6889
  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));
5526
6890
  const contents = jsxs(Fragment, { children: [referenceKind !== void 0 && jsx(ReferenceIcon, {
5527
6891
  kind: referenceKind,
5528
6892
  size: 16,
5529
- className: css$23.refIcon
6893
+ className: css$27.refIcon
5530
6894
  }), displayLabel] });
5531
6895
  const open = references === void 0 ? void 0 : referenceKind === "file" ? () => {
5532
6896
  references.openFile(label.slice(1).replace(/^"|"$/gu, ""));
5533
6897
  } : referenceKind === void 0 && slashKind === "skill" ? () => {
5534
6898
  references.openSkill(label.slice(1));
5535
6899
  } : void 0;
5536
- const className = clsx(css$23.refChip, referenceKind === void 0 && css$23.slashChip);
6900
+ const className = clsx(css$27.refChip, referenceKind === void 0 && css$27.slashChip);
5537
6901
  parts.push(open === void 0 ? jsx("span", {
5538
6902
  className,
5539
6903
  "data-ref-chip": referenceKind ?? slashKind,
@@ -5553,7 +6917,7 @@ function projectUserText(text, sessionLabels, slashNames = [], slashKind = "skil
5553
6917
  cursor = end;
5554
6918
  }
5555
6919
  if (parts.length === 0) return jsx("span", {
5556
- className: css$23.plainRun,
6920
+ className: css$27.plainRun,
5557
6921
  children: text
5558
6922
  });
5559
6923
  if (cursor < text.length) pushPlain(cursor, text.length);
@@ -5612,22 +6976,22 @@ function Toast({ text, icon, tone, anchor, holdMs = HOLD_MS, onDone }) {
5612
6976
  };
5613
6977
  }, [anchor]);
5614
6978
  return createPortal(jsxs("div", {
5615
- className: css$24.toast,
6979
+ className: css$28.toast,
5616
6980
  role: "alert",
5617
6981
  style: {
5618
6982
  ...left === null ? {} : { left },
5619
6983
  "--qilin-toast-hold": `${String(holdMs)}ms`
5620
6984
  },
5621
6985
  children: [tone === "success" ? jsx("span", {
5622
- className: `${css$24.icon} ${css$24.success}`,
6986
+ className: `${css$28.icon} ${css$28.success}`,
5623
6987
  "aria-hidden": true,
5624
6988
  children: jsx(IconCheckOutline16, {})
5625
6989
  }) : icon !== void 0 && jsx("span", {
5626
- className: css$24.icon,
6990
+ className: css$28.icon,
5627
6991
  "aria-hidden": true,
5628
6992
  children: icon
5629
6993
  }), jsx("span", {
5630
- className: css$24.text,
6994
+ className: css$28.text,
5631
6995
  children: text
5632
6996
  })]
5633
6997
  }), document.body);
@@ -5921,7 +7285,7 @@ function JsonCopyAction({ store, target, persistent, labels, onCopy, onClose })
5921
7285
  const object = typeof target.value === "object" && target.value !== null;
5922
7286
  const copyTitle = state === "copied" ? labels.copied : state === "failed" ? labels.copyFailed : object ? labels.copyPrettyJson : labels.copyValue;
5923
7287
  return jsx("span", {
5924
- className: css$25.copySlot,
7288
+ className: css$29.copySlot,
5925
7289
  children: (persistent || snapshot !== void 0) && jsx(Menu, {
5926
7290
  open: snapshot?.menuOpen === true,
5927
7291
  compact: true,
@@ -5930,7 +7294,7 @@ function JsonCopyAction({ store, target, persistent, labels, onCopy, onClose })
5930
7294
  anchor: jsx("button", {
5931
7295
  ref: buttonRef,
5932
7296
  type: "button",
5933
- className: css$25.actionButton,
7297
+ className: css$29.actionButton,
5934
7298
  "data-json-copy-button": true,
5935
7299
  "data-state": state,
5936
7300
  "aria-label": copyTitle,
@@ -5969,35 +7333,35 @@ function bracketOf(value) {
5969
7333
  }
5970
7334
  function previewPrimitive(value) {
5971
7335
  if (value === null) return jsx("span", {
5972
- className: css$25.keywordValue,
7336
+ className: css$29.keywordValue,
5973
7337
  children: "null"
5974
7338
  });
5975
7339
  if (typeof value === "string") return jsx("span", {
5976
- className: css$25.stringValue,
7340
+ className: css$29.stringValue,
5977
7341
  children: JSON.stringify(value)
5978
7342
  });
5979
7343
  if (typeof value === "number") return jsx("span", {
5980
- className: css$25.numberValue,
7344
+ className: css$29.numberValue,
5981
7345
  children: String(value)
5982
7346
  });
5983
7347
  if (typeof value === "boolean") return jsx("span", {
5984
- className: css$25.keywordValue,
7348
+ className: css$29.keywordValue,
5985
7349
  children: String(value)
5986
7350
  });
5987
7351
  if (typeof value === "bigint") return jsx("span", {
5988
- className: css$25.otherValue,
7352
+ className: css$29.otherValue,
5989
7353
  children: value.toString()
5990
7354
  });
5991
7355
  if (typeof value === "undefined") return jsx("span", {
5992
- className: css$25.otherValue,
7356
+ className: css$29.otherValue,
5993
7357
  children: "undefined"
5994
7358
  });
5995
7359
  if (typeof value === "symbol") return jsx("span", {
5996
- className: css$25.otherValue,
7360
+ className: css$29.otherValue,
5997
7361
  children: value.description ?? "Symbol"
5998
7362
  });
5999
7363
  if (typeof value === "function") return jsx("span", {
6000
- className: css$25.otherValue,
7364
+ className: css$29.otherValue,
6001
7365
  children: value.name || "Function"
6002
7366
  });
6003
7367
  return null;
@@ -6011,71 +7375,71 @@ function previewValue(value, depth) {
6011
7375
  const [open, close] = bracketOf(value);
6012
7376
  return jsxs(Fragment, { children: [
6013
7377
  jsx("span", {
6014
- className: css$25.punctuation,
7378
+ className: css$29.punctuation,
6015
7379
  children: open
6016
7380
  }),
6017
7381
  depth >= PREVIEW_DEPTH_LIMIT ? jsx("span", {
6018
- className: css$25.previewEllipsis,
7382
+ className: css$29.previewEllipsis,
6019
7383
  children: "…"
6020
7384
  }) : visible.map(([key, item], index) => jsxs("span", { children: [
6021
7385
  index > 0 && jsx("span", {
6022
- className: css$25.punctuation,
7386
+ className: css$29.punctuation,
6023
7387
  children: ", "
6024
7388
  }),
6025
7389
  !array && jsxs(Fragment, { children: [jsx("span", {
6026
- className: css$25.previewProperty,
7390
+ className: css$29.previewProperty,
6027
7391
  children: key
6028
7392
  }), jsx("span", {
6029
- className: css$25.punctuation,
7393
+ className: css$29.punctuation,
6030
7394
  children: ": "
6031
7395
  })] }),
6032
7396
  previewValue(item, depth + 1)
6033
7397
  ] }, key)),
6034
7398
  depth < PREVIEW_DEPTH_LIMIT && entries.length > limit && jsx("span", {
6035
- className: css$25.previewEllipsis,
7399
+ className: css$29.previewEllipsis,
6036
7400
  children: ", …"
6037
7401
  }),
6038
7402
  jsx("span", {
6039
- className: css$25.punctuation,
7403
+ className: css$29.punctuation,
6040
7404
  children: close
6041
7405
  })
6042
7406
  ] });
6043
7407
  }
6044
7408
  function primitiveValue(value) {
6045
7409
  if (value === null) return jsx("span", {
6046
- className: css$25.keywordValue,
7410
+ className: css$29.keywordValue,
6047
7411
  children: "null"
6048
7412
  });
6049
7413
  if (typeof value === "string") return jsx("span", {
6050
- className: css$25.stringValue,
7414
+ className: css$29.stringValue,
6051
7415
  children: JSON.stringify(value)
6052
7416
  });
6053
7417
  if (typeof value === "boolean") return jsx("span", {
6054
- className: css$25.keywordValue,
7418
+ className: css$29.keywordValue,
6055
7419
  children: String(value)
6056
7420
  });
6057
7421
  if (typeof value === "number") return jsx("span", {
6058
- className: css$25.numberValue,
7422
+ className: css$29.numberValue,
6059
7423
  children: String(value)
6060
7424
  });
6061
7425
  if (typeof value === "bigint") return jsx("span", {
6062
- className: css$25.numberValue,
7426
+ className: css$29.numberValue,
6063
7427
  children: `${value.toString()}n`
6064
7428
  });
6065
7429
  if (value instanceof Date) return jsx("span", {
6066
- className: css$25.otherValue,
7430
+ className: css$29.otherValue,
6067
7431
  children: value.toISOString()
6068
7432
  });
6069
7433
  if (typeof value === "function") return jsxs("span", {
6070
- className: css$25.otherValue,
7434
+ className: css$29.otherValue,
6071
7435
  children: ["function() ", "{ }"]
6072
7436
  });
6073
7437
  if (typeof value === "undefined") return jsx("span", {
6074
- className: css$25.otherValue,
7438
+ className: css$29.otherValue,
6075
7439
  children: "undefined"
6076
7440
  });
6077
7441
  return jsx("span", {
6078
- className: css$25.otherValue,
7442
+ className: css$29.otherValue,
6079
7443
  children: value.toString()
6080
7444
  });
6081
7445
  }
@@ -6103,7 +7467,7 @@ function moveFocus(button, direction) {
6103
7467
  function NodeField({ field, expandable, onToggle }) {
6104
7468
  if (field === void 0) return null;
6105
7469
  return jsxs("span", {
6106
- className: clsx(css$25.label, expandable && css$25.clickableLabel),
7470
+ className: clsx(css$29.label, expandable && css$29.clickableLabel),
6107
7471
  onClick: expandable ? onToggle : void 0,
6108
7472
  children: [fieldText(field), ":"]
6109
7473
  });
@@ -6140,7 +7504,7 @@ function JsonString({ collapsedStringLines, stringWrapping, field, labels, lastE
6140
7504
  if (!expanded) return;
6141
7505
  const raw = rawRef.current;
6142
7506
  const clips = [];
6143
- const tree = raw.closest(`.${css$25.root}`);
7507
+ const tree = raw.closest(`.${css$29.root}`);
6144
7508
  for (let parent = tree.parentElement; parent !== null; parent = parent.parentElement) if (/auto|scroll|hidden|clip/.test(getComputedStyle(parent).overflowY)) clips.push(parent);
6145
7509
  const measure = () => {
6146
7510
  let top = 0;
@@ -6169,33 +7533,33 @@ function JsonString({ collapsedStringLines, stringWrapping, field, labels, lastE
6169
7533
  if (expanded) {
6170
7534
  const fieldId = `${contentsId}-field`;
6171
7535
  return jsxs("div", {
6172
- className: css$25.stringField,
7536
+ className: css$29.stringField,
6173
7537
  "data-expanded": true,
6174
7538
  children: [
6175
7539
  field !== void 0 && jsxs("span", {
6176
7540
  id: fieldId,
6177
- className: css$25.label,
7541
+ className: css$29.label,
6178
7542
  children: [fieldText(field), ":"]
6179
7543
  }),
6180
7544
  jsx("pre", {
6181
7545
  ref: rawRef,
6182
7546
  id: contentsId,
6183
- className: css$25.stringRaw,
7547
+ className: css$29.stringRaw,
6184
7548
  "data-wrap": wrapped,
6185
7549
  tabIndex: 0,
6186
7550
  "aria-labelledby": field === void 0 ? void 0 : fieldId,
6187
7551
  children: value
6188
7552
  }),
6189
7553
  !lastElement && jsx("span", {
6190
- className: css$25.punctuation,
7554
+ className: css$29.punctuation,
6191
7555
  children: ","
6192
7556
  }),
6193
7557
  jsxs("div", {
6194
- className: css$25.stringActions,
7558
+ className: css$29.stringActions,
6195
7559
  children: [
6196
7560
  stringWrapping !== void 0 && jsx("button", {
6197
7561
  type: "button",
6198
- className: css$25.actionButton,
7562
+ className: css$29.actionButton,
6199
7563
  "aria-label": stringWrapping.label,
6200
7564
  title: stringWrapping.label,
6201
7565
  "aria-pressed": wrapped,
@@ -6209,7 +7573,7 @@ function JsonString({ collapsedStringLines, stringWrapping, field, labels, lastE
6209
7573
  }),
6210
7574
  jsx("button", {
6211
7575
  type: "button",
6212
- className: css$25.actionButton,
7576
+ className: css$29.actionButton,
6213
7577
  "aria-label": labels.collapseNode,
6214
7578
  title: labels.collapseNode,
6215
7579
  "aria-expanded": true,
@@ -6235,18 +7599,18 @@ function JsonString({ collapsedStringLines, stringWrapping, field, labels, lastE
6235
7599
  });
6236
7600
  }
6237
7601
  return jsxs(Fragment, { children: [renderCopy?.(), jsx("span", {
6238
- className: css$25.stringField,
7602
+ className: css$29.stringField,
6239
7603
  "data-expanded": expanded,
6240
7604
  children: jsxs("span", {
6241
7605
  ref: contentRef,
6242
7606
  id: contentsId,
6243
- className: css$25.stringText,
7607
+ className: css$29.stringText,
6244
7608
  children: [
6245
7609
  truncated && jsx("span", {
6246
- className: css$25.stringToggleSlot,
7610
+ className: css$29.stringToggleSlot,
6247
7611
  children: jsxs("button", {
6248
7612
  type: "button",
6249
- className: css$25.stringToggle,
7613
+ className: css$29.stringToggle,
6250
7614
  "aria-label": labels.expandNode,
6251
7615
  "aria-expanded": false,
6252
7616
  "aria-controls": contentsId,
@@ -6261,12 +7625,12 @@ function JsonString({ collapsedStringLines, stringWrapping, field, labels, lastE
6261
7625
  })
6262
7626
  }),
6263
7627
  field !== void 0 && jsxs("span", {
6264
- className: css$25.label,
7628
+ className: css$29.label,
6265
7629
  children: [fieldText(field), ":"]
6266
7630
  }),
6267
7631
  primitiveValue(value),
6268
7632
  !lastElement && jsx("span", {
6269
- className: css$25.punctuation,
7633
+ className: css$29.punctuation,
6270
7634
  children: ","
6271
7635
  })
6272
7636
  ]
@@ -6297,7 +7661,7 @@ function JsonTreeNode({ collapsedStringLines, stringWrapping, field, initialExpa
6297
7661
  }
6298
7662
  };
6299
7663
  const row = (children, ariaExpanded) => jsxs("div", {
6300
- className: css$25.row,
7664
+ className: css$29.row,
6301
7665
  role: "treeitem",
6302
7666
  "aria-expanded": ariaExpanded,
6303
7667
  onMouseOver: (event) => {
@@ -6332,7 +7696,7 @@ function JsonTreeNode({ collapsedStringLines, stringWrapping, field, initialExpa
6332
7696
  }),
6333
7697
  primitiveValue(value),
6334
7698
  !lastElement && jsx("span", {
6335
- className: css$25.punctuation,
7699
+ className: css$29.punctuation,
6336
7700
  children: ","
6337
7701
  })
6338
7702
  ] }));
@@ -6344,22 +7708,22 @@ function JsonTreeNode({ collapsedStringLines, stringWrapping, field, initialExpa
6344
7708
  onToggle: toggle
6345
7709
  }),
6346
7710
  jsx("span", {
6347
- className: css$25.punctuation,
7711
+ className: css$29.punctuation,
6348
7712
  children: open
6349
7713
  }),
6350
7714
  jsx("span", {
6351
- className: css$25.punctuation,
7715
+ className: css$29.punctuation,
6352
7716
  children: close
6353
7717
  }),
6354
7718
  !lastElement && jsx("span", {
6355
- className: css$25.punctuation,
7719
+ className: css$29.punctuation,
6356
7720
  children: ","
6357
7721
  })
6358
7722
  ] }));
6359
7723
  return row(jsxs(Fragment, { children: [
6360
7724
  jsx("span", {
6361
7725
  ref: expanderRef,
6362
- className: clsx(css$25.expander, expanded ? css$25.collapseIcon : css$25.expandIcon),
7726
+ className: clsx(css$29.expander, expanded ? css$29.collapseIcon : css$29.expandIcon),
6363
7727
  "data-json-expander": true,
6364
7728
  role: "button",
6365
7729
  "aria-label": expanded ? labels.collapseNode : labels.expandNode,
@@ -6373,7 +7737,7 @@ function JsonTreeNode({ collapsedStringLines, stringWrapping, field, initialExpa
6373
7737
  onKeyDown: onExpanderKeyDown
6374
7738
  }),
6375
7739
  jsxs("span", {
6376
- className: css$25.summary,
7740
+ className: css$29.summary,
6377
7741
  children: [
6378
7742
  jsx(NodeField, {
6379
7743
  field,
@@ -6381,11 +7745,11 @@ function JsonTreeNode({ collapsedStringLines, stringWrapping, field, initialExpa
6381
7745
  onToggle: toggle
6382
7746
  }),
6383
7747
  jsx("span", {
6384
- className: css$25.preview,
7748
+ className: css$29.preview,
6385
7749
  children: previewValue(value, 0)
6386
7750
  }),
6387
7751
  !lastElement && jsx("span", {
6388
- className: css$25.punctuation,
7752
+ className: css$29.punctuation,
6389
7753
  children: ","
6390
7754
  })
6391
7755
  ]
@@ -6393,7 +7757,7 @@ function JsonTreeNode({ collapsedStringLines, stringWrapping, field, initialExpa
6393
7757
  expanded && jsx("ul", {
6394
7758
  id: contentsId,
6395
7759
  role: "group",
6396
- className: css$25.children,
7760
+ className: css$29.children,
6397
7761
  children: entries.map(([key, item], index) => jsx(JsonTreeNode, {
6398
7762
  collapsedStringLines,
6399
7763
  stringWrapping,
@@ -6525,17 +7889,17 @@ function JsonTree({ data, label, className, collapsedStringLines = 3, stringWrap
6525
7889
  onClose: clearCopyTarget
6526
7890
  }) : void 0;
6527
7891
  return jsx("div", {
6528
- className: clsx(css$25.root, className),
7892
+ className: clsx(css$29.root, className),
6529
7893
  style: { "--json-tree-collapsed-lines": collapsedStringLines },
6530
7894
  onMouseOver: handleRootMouseOver,
6531
7895
  onMouseLeave: () => {
6532
7896
  if (!copyStore.get()?.menuOpen) clearCopyTarget();
6533
7897
  },
6534
7898
  children: expandTopLevel ? jsxs("div", {
6535
- className: css$25.expandedTopLevel,
7899
+ className: css$29.expandedTopLevel,
6536
7900
  children: [
6537
7901
  jsxs("div", {
6538
- className: clsx(css$25.row, css$25.topLevelBracket),
7902
+ className: clsx(css$29.row, css$29.topLevelBracket),
6539
7903
  "data-json-root-row": true,
6540
7904
  onMouseOver: (event) => {
6541
7905
  event.stopPropagation();
@@ -6548,13 +7912,13 @@ function JsonTree({ data, label, className, collapsedStringLines = 3, stringWrap
6548
7912
  path: [],
6549
7913
  value: data
6550
7914
  }), jsx("span", {
6551
- className: css$25.punctuation,
7915
+ className: css$29.punctuation,
6552
7916
  children: rootOpen
6553
7917
  })]
6554
7918
  }),
6555
7919
  jsx("div", {
6556
7920
  "aria-label": label,
6557
- className: clsx(css$25.container, css$25.expandedTopLevelContainer),
7921
+ className: clsx(css$29.container, css$29.expandedTopLevelContainer),
6558
7922
  role: "tree",
6559
7923
  children: rootEntries.map(([key, value], index) => jsx(JsonTreeNode, {
6560
7924
  collapsedStringLines,
@@ -6572,16 +7936,16 @@ function JsonTree({ data, label, className, collapsedStringLines = 3, stringWrap
6572
7936
  }, key))
6573
7937
  }),
6574
7938
  jsx("div", {
6575
- className: clsx(css$25.row, css$25.topLevelBracket),
7939
+ className: clsx(css$29.row, css$29.topLevelBracket),
6576
7940
  children: jsx("span", {
6577
- className: css$25.punctuation,
7941
+ className: css$29.punctuation,
6578
7942
  children: rootClose
6579
7943
  })
6580
7944
  })
6581
7945
  ]
6582
7946
  }) : jsx("div", {
6583
7947
  "aria-label": label,
6584
- className: css$25.container,
7948
+ className: css$29.container,
6585
7949
  role: "tree",
6586
7950
  children: jsx(JsonTreeNode, {
6587
7951
  collapsedStringLines,
@@ -7097,7 +8461,7 @@ function renderLine$1(line) {
7097
8461
  * @param props - see {@link TerminalBlockProps}.
7098
8462
  * @returns the terminal block element.
7099
8463
  */
7100
- function TerminalBlock({ command, cwd, home, output, exitCode, signal, running = false, maxLines = 16, className, labels }) {
8464
+ function TerminalBlock({ command, cwd, home, output, exitCode, signal, running = false, background = false, maxLines = 16, className, labels }) {
7101
8465
  const copy = labels;
7102
8466
  const text = output ?? "";
7103
8467
  const lines = useMemo(() => {
@@ -7110,40 +8474,41 @@ function TerminalBlock({ command, cwd, home, output, exitCode, signal, running =
7110
8474
  const onToggle = useCallback(() => {
7111
8475
  setExpanded((value) => !value);
7112
8476
  }, []);
7113
- const status = statusText(exitCode, signal, copy);
8477
+ const status = background ? void 0 : statusText(exitCode, signal, copy);
7114
8478
  const state = runState(running, exitCode, signal, copy);
8479
+ const showState = !background || running;
7115
8480
  const commandLines = useMemo(() => {
7116
8481
  return (command.endsWith("\n") ? command.slice(0, -1) : command).split("\n");
7117
8482
  }, [command]);
7118
8483
  const empty = lines.every((line) => line.every((span) => span.text.trim() === ""));
7119
8484
  const { hidden, capped, headLines, tailLines } = headTailCap(lines.length, maxLines, expanded);
7120
- const body = !running || !empty;
8485
+ const body = !background && (!running || !empty);
7121
8486
  return jsxs("div", {
7122
- className: clsx(css$26.block, className),
8487
+ className: clsx(css$30.block, className),
7123
8488
  "data-terminal": "",
7124
8489
  "data-running": running ? "" : void 0,
7125
8490
  "data-body": body ? "" : void 0,
7126
8491
  children: [jsxs("div", {
7127
- className: css$26.header,
8492
+ className: css$30.header,
7128
8493
  children: [
7129
8494
  jsxs("div", {
7130
- className: css$26.prompt,
7131
- children: [jsx("span", {
7132
- className: css$26.runStateLabel,
8495
+ className: css$30.prompt,
8496
+ children: [showState && jsx("span", {
8497
+ className: css$30.runStateLabel,
7133
8498
  children: state.label
7134
8499
  }), commandLines.map((line, index) => jsxs("div", {
7135
- className: css$26.promptLine,
8500
+ className: css$30.promptLine,
7136
8501
  children: [
7137
- index === 0 && jsx(StateDot, {
8502
+ index === 0 && showState && jsx(StateDot, {
7138
8503
  state: state.state,
7139
- className: css$26.runState
8504
+ className: css$30.runState
7140
8505
  }),
7141
8506
  jsx("span", {
7142
- className: css$26.cwd,
8507
+ className: css$30.cwd,
7143
8508
  children: index > 0 || cwd === void 0 ? "$" : promptLabel(cwd, home)
7144
8509
  }),
7145
8510
  jsx(CommandText, {
7146
- className: css$26.command,
8511
+ className: css$30.command,
7147
8512
  text: line,
7148
8513
  label: copy.commandLine(index + 1)
7149
8514
  })
@@ -7151,36 +8516,36 @@ function TerminalBlock({ command, cwd, home, output, exitCode, signal, running =
7151
8516
  }, index))]
7152
8517
  }),
7153
8518
  status !== void 0 && jsx(Pill, {
7154
- className: css$26.status,
8519
+ className: css$30.status,
7155
8520
  children: status
7156
8521
  }),
7157
- !running && !empty && jsx("button", {
8522
+ !background && !running && !empty && jsx("button", {
7158
8523
  type: "button",
7159
- className: css$26.copyButton,
8524
+ className: css$30.copyButton,
7160
8525
  onClick: onCopy,
7161
8526
  children: copied ? copy.copied : copy.copy
7162
8527
  })
7163
8528
  ]
7164
8529
  }), body && (empty ? jsx("div", {
7165
- className: css$26.empty,
8530
+ className: css$30.empty,
7166
8531
  children: copy.noOutput
7167
8532
  }) : jsxs("div", {
7168
- className: css$26.output,
8533
+ className: css$30.output,
7169
8534
  children: [
7170
8535
  (capped ? lines.slice(0, headLines) : lines).map((line, index) => jsx("div", {
7171
- className: css$26.line,
8536
+ className: css$30.line,
7172
8537
  children: renderLine$1(line)
7173
8538
  }, index)),
7174
8539
  hidden > 0 && jsx("button", {
7175
8540
  type: "button",
7176
- className: css$26.expand,
8541
+ className: css$30.expand,
7177
8542
  "aria-expanded": expanded,
7178
8543
  "aria-label": expanded ? copy.collapseAria : copy.expandAria(hidden),
7179
8544
  onClick: onToggle,
7180
8545
  children: expanded ? copy.collapse : copy.expand(hidden)
7181
8546
  }),
7182
8547
  capped && lines.slice(lines.length - tailLines).map((line, index) => jsx("div", {
7183
- className: css$26.line,
8548
+ className: css$30.line,
7184
8549
  children: renderLine$1(line)
7185
8550
  }, index))
7186
8551
  ]
@@ -7768,51 +9133,51 @@ function ReadBlock({ label, labels, lines, totalLines, lang, maxLines = 16, clas
7768
9133
  const tailLines = maxLines - headLines;
7769
9134
  const windowed = lines.length < totalLines;
7770
9135
  const rows = (slice) => slice.map(([line, spans]) => jsxs("div", {
7771
- className: css$27.line,
9136
+ className: css$31.line,
7772
9137
  children: [jsx("span", {
7773
- className: css$27.gutter,
9138
+ className: css$31.gutter,
7774
9139
  "aria-hidden": true,
7775
9140
  children: line.number
7776
9141
  }), jsx("span", {
7777
- className: css$27.content,
9142
+ className: css$31.content,
7778
9143
  children: spans === void 0 ? line.text : renderSpans(spans)
7779
9144
  })]
7780
9145
  }, line.number));
7781
9146
  const paired = lines.map((line, index) => [line, highlighted?.[index]]);
7782
9147
  return jsxs("div", {
7783
9148
  ref: rootRef,
7784
- className: clsx(css$27.block, className),
9149
+ className: clsx(css$31.block, className),
7785
9150
  "data-read": "",
7786
9151
  children: [jsxs("div", {
7787
- className: css$27.banner,
9152
+ className: css$31.banner,
7788
9153
  children: [jsx("div", {
7789
- className: css$27.label,
9154
+ className: css$31.label,
7790
9155
  children: label ?? ""
7791
9156
  }), jsxs("div", {
7792
- className: css$27.action,
9157
+ className: css$31.action,
7793
9158
  children: [
7794
9159
  windowed && jsx("span", {
7795
- className: css$27.count,
9160
+ className: css$31.count,
7796
9161
  children: labels.window(lines.length, totalLines)
7797
9162
  }),
7798
9163
  jsx("span", {
7799
- className: css$27.lang,
9164
+ className: css$31.lang,
7800
9165
  children: lang ?? ""
7801
9166
  }),
7802
9167
  lines.length > 0 && jsx("button", {
7803
9168
  type: "button",
7804
- className: css$27.copyButton,
9169
+ className: css$31.copyButton,
7805
9170
  onClick: onCopy,
7806
9171
  children: copied ? labels.copied : labels.copy
7807
9172
  })
7808
9173
  ]
7809
9174
  })]
7810
9175
  }), jsxs("div", {
7811
- className: css$27.body,
9176
+ className: css$31.body,
7812
9177
  children: [
7813
9178
  rows(capped ? paired.slice(0, headLines) : paired),
7814
9179
  hidden > 0 && jsx(FoldToggle, {
7815
- className: css$27.expand,
9180
+ className: css$31.expand,
7816
9181
  expanded,
7817
9182
  hidden,
7818
9183
  labels,
@@ -7834,11 +9199,11 @@ function assertNever(value) {
7834
9199
  }
7835
9200
  /** The dim class per row kind (path/gap chrome vs the diff's own +/- colors). */
7836
9201
  const ROW_CLASS = {
7837
- path: css$28.path,
7838
- del: css$28.del,
7839
- add: css$28.add,
7840
- context: css$28.context,
7841
- gap: css$28.gap
9202
+ path: css$32.path,
9203
+ del: css$32.del,
9204
+ add: css$32.add,
9205
+ context: css$32.context,
9206
+ gap: css$32.gap
7842
9207
  };
7843
9208
  /** Bound synchronous edit-graph search; one replacement consumes two edits. */
7844
9209
  const MAX_DIFF_EDIT_LENGTH = 256;
@@ -7976,37 +9341,37 @@ function DiffBlock({ diffs, labels, maxLines = 16, className }) {
7976
9341
  const head = capped ? rows.slice(0, headLines) : rows;
7977
9342
  const tail = capped ? rows.slice(rows.length - tailLines) : [];
7978
9343
  return jsxs("div", {
7979
- className: clsx(css$28.block, className),
9344
+ className: clsx(css$32.block, className),
7980
9345
  "data-diff": "",
7981
9346
  children: [
7982
9347
  jsx("button", {
7983
9348
  type: "button",
7984
- className: css$28.copyButton,
9349
+ className: css$32.copyButton,
7985
9350
  onClick: onCopy,
7986
9351
  children: copied ? labels.copied : labels.copy
7987
9352
  }),
7988
9353
  jsxs("div", {
7989
- className: css$28.body,
9354
+ className: css$32.body,
7990
9355
  children: [
7991
9356
  head.map((row, index) => jsx("div", {
7992
- className: clsx(css$28.line, ROW_CLASS[row.kind]),
9357
+ className: clsx(css$32.line, ROW_CLASS[row.kind]),
7993
9358
  children: row.text
7994
9359
  }, index)),
7995
9360
  hidden > 0 && jsx(FoldToggle, {
7996
- className: css$28.expand,
9361
+ className: css$32.expand,
7997
9362
  expanded,
7998
9363
  hidden,
7999
9364
  labels,
8000
9365
  onToggle
8001
9366
  }),
8002
9367
  tail.map((row, index) => jsx("div", {
8003
- className: clsx(css$28.line, ROW_CLASS[row.kind]),
9368
+ className: clsx(css$32.line, ROW_CLASS[row.kind]),
8004
9369
  children: row.text
8005
9370
  }, index))
8006
9371
  ]
8007
9372
  }),
8008
9373
  jsxs("div", {
8009
- className: css$28.footer,
9374
+ className: css$32.footer,
8010
9375
  children: [
8011
9376
  "└ +",
8012
9377
  added,
@@ -8142,56 +9507,56 @@ function SearchBlock(props) {
8142
9507
  const tail = tailHeader === void 0 ? naturalTail : naturalTail.slice(1);
8143
9508
  const renderRow = (row) => {
8144
9509
  if (row.type === "path") return jsx("div", {
8145
- className: css$29.line,
9510
+ className: css$33.line,
8146
9511
  children: row.path
8147
9512
  });
8148
9513
  if (row.type === "match") return jsxs("div", {
8149
- className: css$29.line,
9514
+ className: css$33.line,
8150
9515
  children: [jsxs("span", {
8151
- className: css$29.lineNumber,
9516
+ className: css$33.lineNumber,
8152
9517
  children: [row.lineNumber, ": "]
8153
9518
  }), row.line]
8154
9519
  });
8155
9520
  return jsxs("button", {
8156
9521
  type: "button",
8157
- className: css$29.fileHeader,
9522
+ className: css$33.fileHeader,
8158
9523
  "aria-expanded": !row.collapsed,
8159
9524
  onClick: () => {
8160
9525
  toggleFile(row.index);
8161
9526
  },
8162
9527
  children: [jsx("span", {
8163
- className: css$29.filePath,
9528
+ className: css$33.filePath,
8164
9529
  children: row.path
8165
9530
  }), jsx("span", {
8166
- className: css$29.fileCount,
9531
+ className: css$33.fileCount,
8167
9532
  children: row.count
8168
9533
  })]
8169
9534
  });
8170
9535
  };
8171
9536
  return jsxs("div", {
8172
- className: clsx(css$29.block, className),
9537
+ className: clsx(css$33.block, className),
8173
9538
  "data-search": props.kind,
8174
9539
  children: [jsxs("div", {
8175
- className: css$29.header,
9540
+ className: css$33.header,
8176
9541
  children: [jsx("span", {
8177
- className: css$29.summary,
9542
+ className: css$33.summary,
8178
9543
  children: summaryText(props, shown, truncated, total)
8179
9544
  }), !empty && jsx("button", {
8180
9545
  type: "button",
8181
- className: css$29.copyButton,
9546
+ className: css$33.copyButton,
8182
9547
  onClick: onCopy,
8183
9548
  children: copied ? props.labels.copied : props.labels.copy
8184
9549
  })]
8185
9550
  }), empty ? jsx("div", {
8186
- className: css$29.empty,
9551
+ className: css$33.empty,
8187
9552
  children: props.labels.noResults
8188
9553
  }) : jsxs("div", {
8189
- className: css$29.body,
9554
+ className: css$33.body,
8190
9555
  children: [
8191
9556
  head.map((row) => jsx("div", { children: renderRow(row) }, rowKey(row))),
8192
9557
  hidden > 0 && jsx("button", {
8193
9558
  type: "button",
8194
- className: css$29.expand,
9559
+ className: css$33.expand,
8195
9560
  "aria-expanded": expanded,
8196
9561
  "aria-label": expanded ? props.labels.collapseAria : props.labels.expandAria(hidden),
8197
9562
  onClick: onToggle,
@@ -9019,7 +10384,7 @@ function CodeBlock({ code, lang, streaming, className, contentRef, lineNumbers =
9019
10384
  });
9020
10385
  }, [copied, trimmed]);
9021
10386
  const body = streamedBody !== void 0 ? streamedBody : html === void 0 ? jsx("pre", {
9022
- className: css$30.plain,
10387
+ className: css$34.plain,
9023
10388
  children: jsx("code", { children: sourceLines === void 0 ? trimmed : sourceLines.map((line, index) => jsxs(Fragment$1, { children: [index > 0 && "\n", jsx("span", {
9024
10389
  className: "line",
9025
10390
  children: line
@@ -9027,22 +10392,22 @@ function CodeBlock({ code, lang, streaming, className, contentRef, lineNumbers =
9027
10392
  }) : jsx("div", { dangerouslySetInnerHTML: { __html: html } });
9028
10393
  return jsxs("div", {
9029
10394
  ref: rootRef,
9030
- className: clsx(css$30.block, "md-code-block", lineNumbers && css$30.numbered, className),
10395
+ className: clsx(css$34.block, "md-code-block", lineNumbers && css$34.numbered, className),
9031
10396
  "data-line-numbers": lineNumbers || void 0,
9032
10397
  style: sourceLines === void 0 ? void 0 : { "--dsl-code-block-line-number-width": `${Math.max(2, String(sourceLines.length).length)}ch` },
9033
10398
  children: [showHeader && jsx("div", {
9034
- className: css$30.bannerWrap,
10399
+ className: css$34.bannerWrap,
9035
10400
  children: jsxs("div", {
9036
- className: css$30.banner,
10401
+ className: css$34.banner,
9037
10402
  "data-code-block-banner": true,
9038
10403
  children: [jsx("div", {
9039
- className: css$30.infostring,
10404
+ className: css$34.infostring,
9040
10405
  children: lang ?? ""
9041
10406
  }), jsx("div", {
9042
- className: css$30.action,
10407
+ className: css$34.action,
9043
10408
  children: jsx("button", {
9044
10409
  type: "button",
9045
- className: css$30.copyButton,
10410
+ className: css$34.copyButton,
9046
10411
  onClick: onCopy,
9047
10412
  children: copied ? copiedLabel : copyLabel
9048
10413
  })
@@ -9050,7 +10415,7 @@ function CodeBlock({ code, lang, streaming, className, contentRef, lineNumbers =
9050
10415
  })
9051
10416
  }), jsx("div", {
9052
10417
  ref: contentRef,
9053
- className: css$30.content,
10418
+ className: css$34.content,
9054
10419
  "data-code-block-content": true,
9055
10420
  children: body
9056
10421
  })]
@@ -9201,15 +10566,15 @@ function MermaidDiagram({ code, copyLabel, copiedLabel, diagramLabel, enlargedLa
9201
10566
  };
9202
10567
  }, [code, domId]);
9203
10568
  if (state.status === "loading") return jsx("div", {
9204
- className: css$31.stage,
10569
+ className: css$35.stage,
9205
10570
  "data-mermaid-loading": true,
9206
10571
  "aria-hidden": "true"
9207
10572
  });
9208
10573
  if (state.status === "error") return jsxs("div", {
9209
- className: css$31.error,
10574
+ className: css$35.error,
9210
10575
  role: "alert",
9211
10576
  children: [jsx("span", {
9212
- className: css$31.errorLine,
10577
+ className: css$35.errorLine,
9213
10578
  children: state.message
9214
10579
  }), jsx(CodeBlock, {
9215
10580
  code: `${code}\n`,
@@ -9218,7 +10583,7 @@ function MermaidDiagram({ code, copyLabel, copiedLabel, diagramLabel, enlargedLa
9218
10583
  })]
9219
10584
  });
9220
10585
  const stage = jsx("div", {
9221
- className: css$31.stage,
10586
+ className: css$35.stage,
9222
10587
  "data-mermaid-diagram": true,
9223
10588
  dangerouslySetInnerHTML: { __html: state.svg },
9224
10589
  onClick: () => {
@@ -9233,13 +10598,13 @@ function MermaidDiagram({ code, copyLabel, copiedLabel, diagramLabel, enlargedLa
9233
10598
  });
9234
10599
  if (zoom === null) return stage;
9235
10600
  return jsxs(Fragment, { children: [stage, createPortal(jsx("div", {
9236
- className: css$31.zoomOverlay,
10601
+ className: css$35.zoomOverlay,
9237
10602
  onClick: () => {
9238
10603
  setZoom(null);
9239
10604
  },
9240
10605
  role: "presentation",
9241
10606
  children: jsx("div", {
9242
- className: css$31.zoomStage,
10607
+ className: css$35.zoomStage,
9243
10608
  dangerouslySetInnerHTML: { __html: zoom },
9244
10609
  onClick: (event) => {
9245
10610
  event.stopPropagation();
@@ -9432,31 +10797,34 @@ function ImageLightbox({ src, alt, labels, onClose }) {
9432
10797
  restoreRef.current?.focus();
9433
10798
  };
9434
10799
  }, [onClose]);
9435
- return createPortal(jsxs("div", {
9436
- className: css$32.backdrop,
10800
+ return createPortal(jsx("div", {
10801
+ className: css$36.backdrop,
9437
10802
  role: "dialog",
9438
10803
  "aria-modal": "true",
9439
10804
  "aria-label": labels.dialog,
9440
- children: [
9441
- jsx("div", {
9442
- className: css$32.mask,
9443
- "aria-hidden": "true",
9444
- onMouseDown: onClose
9445
- }),
9446
- jsx("img", {
9447
- className: css$32.image,
9448
- src,
9449
- alt
9450
- }),
9451
- jsx("button", {
9452
- ref: closeRef,
9453
- type: "button",
9454
- className: css$32.close,
9455
- "aria-label": labels.close,
9456
- onClick: onClose,
9457
- children: jsx(IconCloseOutline16, { size: 16 })
9458
- })
9459
- ]
10805
+ children: jsxs("div", {
10806
+ className: css$36.stage,
10807
+ children: [
10808
+ jsx("div", {
10809
+ className: css$36.mask,
10810
+ "aria-hidden": "true",
10811
+ onMouseDown: onClose
10812
+ }),
10813
+ jsx("img", {
10814
+ className: css$36.image,
10815
+ src,
10816
+ alt
10817
+ }),
10818
+ jsx("button", {
10819
+ ref: closeRef,
10820
+ type: "button",
10821
+ className: css$36.close,
10822
+ "aria-label": labels.close,
10823
+ onClick: onClose,
10824
+ children: jsx(IconCloseOutline16, { size: 16 })
10825
+ })
10826
+ ]
10827
+ })
9460
10828
  }), document.body);
9461
10829
  }
9462
10830
  //#endregion
@@ -9478,14 +10846,14 @@ function ImagePreview({ src, alt, loadingLabel, failedLabel }) {
9478
10846
  function Preview({ src, alt, loadingLabel, failedLabel }) {
9479
10847
  const [state, setState] = useState("loading");
9480
10848
  return jsxs("span", {
9481
- className: css$33.frame,
10849
+ className: css$37.frame,
9482
10850
  children: [state !== "failed" && jsx("img", {
9483
10851
  src,
9484
10852
  alt,
9485
10853
  loading: "lazy",
9486
10854
  decoding: "async",
9487
10855
  referrerPolicy: "no-referrer",
9488
- className: css$33.image,
10856
+ className: css$37.image,
9489
10857
  "data-ready": state === "ready" || void 0,
9490
10858
  onLoad: () => {
9491
10859
  setState("ready");
@@ -9494,7 +10862,7 @@ function Preview({ src, alt, loadingLabel, failedLabel }) {
9494
10862
  setState("failed");
9495
10863
  }
9496
10864
  }), state !== "ready" && jsxs("span", {
9497
- className: css$33.status,
10865
+ className: css$37.status,
9498
10866
  role: "status",
9499
10867
  children: [state === "loading" && jsx(IconLoadingOutline16, { size: 16 }), jsx("span", { children: state === "loading" ? loadingLabel : failedLabel })]
9500
10868
  })]
@@ -10265,7 +11633,7 @@ function SafeLink({ url, label, className }) {
10265
11633
  children: [jsx(LinkIcon, {
10266
11634
  kind: "url",
10267
11635
  href,
10268
- className: css$34.linkIcon
11636
+ className: css$38.linkIcon
10269
11637
  }), label]
10270
11638
  });
10271
11639
  }
@@ -10280,20 +11648,20 @@ function SafeLink({ url, label, className }) {
10280
11648
  */
10281
11649
  function SourceItem({ source, ordinal }) {
10282
11650
  return jsxs("li", {
10283
- className: css$34.source,
11651
+ className: css$38.source,
10284
11652
  value: ordinal,
10285
11653
  children: [
10286
11654
  jsx(SafeLink, {
10287
11655
  url: source.url,
10288
11656
  label: linkLabel(source.url, source.title),
10289
- className: css$34.sourceLink
11657
+ className: css$38.sourceLink
10290
11658
  }),
10291
11659
  source.snippet !== void 0 && source.snippet !== "" && jsx("div", {
10292
- className: css$34.snippet,
11660
+ className: css$38.snippet,
10293
11661
  children: source.snippet
10294
11662
  }),
10295
11663
  source.publishedAt !== void 0 && source.publishedAt !== "" && jsx("div", {
10296
- className: css$34.published,
11664
+ className: css$38.published,
10297
11665
  children: source.publishedAt
10298
11666
  })
10299
11667
  ]
@@ -10308,28 +11676,28 @@ function SourceItem({ source, ordinal }) {
10308
11676
  function WebSearchBlock({ answer, sources, truncated, labels, className }) {
10309
11677
  const empty = (answer === void 0 || answer === "") && sources.length === 0;
10310
11678
  return jsxs("div", {
10311
- className: clsx(css$34.block, className),
11679
+ className: clsx(css$38.block, className),
10312
11680
  "data-web": "search",
10313
11681
  children: [
10314
11682
  answer !== void 0 && answer !== "" && jsx("div", {
10315
- className: css$34.answer,
11683
+ className: css$38.answer,
10316
11684
  children: jsx(MarkdownText, {
10317
11685
  text: answer,
10318
11686
  labels: labels.markdown
10319
11687
  })
10320
11688
  }),
10321
11689
  empty ? jsx("div", {
10322
- className: css$34.empty,
11690
+ className: css$38.empty,
10323
11691
  children: labels.noResults
10324
11692
  }) : jsx("ol", {
10325
- className: css$34.sources,
11693
+ className: css$38.sources,
10326
11694
  children: sources.map((source, index) => jsx(SourceItem, {
10327
11695
  source,
10328
11696
  ordinal: index + 1
10329
11697
  }, index))
10330
11698
  }),
10331
11699
  truncated && jsx("div", {
10332
- className: css$34.truncated,
11700
+ className: css$38.truncated,
10333
11701
  children: labels.sourcesTruncated
10334
11702
  })
10335
11703
  ]
@@ -10342,23 +11710,23 @@ function WebSearchBlock({ answer, sources, truncated, labels, className }) {
10342
11710
  */
10343
11711
  function WebFetchBlock({ url, statusCode, truncated, labels, className }) {
10344
11712
  return jsxs("div", {
10345
- className: clsx(css$34.block, css$34.fetch, className),
11713
+ className: clsx(css$38.block, css$38.fetch, className),
10346
11714
  "data-web": "fetch",
10347
11715
  children: [jsx(SafeLink, {
10348
11716
  url,
10349
11717
  label: url,
10350
- className: css$34.fetchUrl
11718
+ className: css$38.fetchUrl
10351
11719
  }), jsxs("div", {
10352
- className: css$34.fetchMeta,
11720
+ className: css$38.fetchMeta,
10353
11721
  children: [jsxs("span", {
10354
- className: css$34.status,
11722
+ className: css$38.status,
10355
11723
  children: [
10356
11724
  labels.http,
10357
11725
  " ",
10358
11726
  statusCode
10359
11727
  ]
10360
11728
  }), truncated && jsx("span", {
10361
- className: css$34.truncated,
11729
+ className: css$38.truncated,
10362
11730
  children: labels.contentTruncated
10363
11731
  })]
10364
11732
  })]
@@ -10392,10 +11760,10 @@ function JsonBlock({ label, payload, defaultOpen = false, truncatedLabel }) {
10392
11760
  truncatedLabel
10393
11761
  ]);
10394
11762
  return jsxs("div", {
10395
- className: css$35.root,
11763
+ className: css$39.root,
10396
11764
  children: [jsxs("button", {
10397
11765
  type: "button",
10398
- className: css$35.toggle,
11766
+ className: css$39.toggle,
10399
11767
  onClick: () => {
10400
11768
  setOpen((v) => !v);
10401
11769
  },
@@ -10405,7 +11773,7 @@ function JsonBlock({ label, payload, defaultOpen = false, truncatedLabel }) {
10405
11773
  label
10406
11774
  ]
10407
11775
  }), open && jsx("pre", {
10408
- className: css$35.body,
11776
+ className: css$39.body,
10409
11777
  children: body
10410
11778
  })]
10411
11779
  });
@@ -10495,17 +11863,17 @@ function MenuGroup({ label, children }) {
10495
11863
  role: "group",
10496
11864
  "aria-labelledby": headingId,
10497
11865
  "data-menu-group": "",
10498
- className: css$36.group,
11866
+ className: css$40.group,
10499
11867
  children: [
10500
11868
  jsx("span", {
10501
11869
  "aria-hidden": "true",
10502
11870
  "data-menu-group-start": "",
10503
- className: css$36.start
11871
+ className: css$40.start
10504
11872
  }),
10505
11873
  jsx("div", {
10506
11874
  id: headingId,
10507
11875
  "data-menu-group-heading": "",
10508
- className: css$36.heading,
11876
+ className: css$40.heading,
10509
11877
  children: label
10510
11878
  }),
10511
11879
  children
@@ -10601,47 +11969,6 @@ function observeStickyMenuGroups(viewport) {
10601
11969
  };
10602
11970
  }
10603
11971
  //#endregion
10604
- //#region lib/types/MenuSurface.js
10605
- /** Shared menu material and the macOS backing that lets Chromium blur transparent windows. */
10606
- /**
10607
- * Paint a menu and, on macOS, an opaque backing behind the page content within its bounds.
10608
- * CSS anchors keep each backing aligned during placement, resizing, and nested-menu movement.
10609
- * @param props - Div content and placement, and compact geometry.
10610
- * @param ref - The visible menu div, excluding the non-interactive backing.
10611
- * @returns Menu content plus a backing portal removed with the menu.
10612
- */
10613
- const MenuSurface = forwardRef(function MenuSurface({ compact = false, className, style, children, ...props }, ref) {
10614
- const id = useId();
10615
- const backingRef = useRef(null);
10616
- useLayoutEffect(() => {
10617
- document.body.appendChild(backingRef.current);
10618
- }, []);
10619
- const anchorStyle = { "--dsh-menu-anchor": `--dsh-menu-${id.replaceAll(":", "")}` };
10620
- return jsxs(Fragment, { children: [jsxs("div", {
10621
- ...props,
10622
- ref,
10623
- "data-menu-material": "translucent",
10624
- className: clsx(css$37.surface, compact && css$37.compact, className),
10625
- style: {
10626
- ...style,
10627
- ...anchorStyle
10628
- },
10629
- children: [jsx("div", {
10630
- "aria-hidden": "true",
10631
- className: css$37.material
10632
- }), children]
10633
- }), createPortal(jsx("div", {
10634
- ref: backingRef,
10635
- "aria-hidden": "true",
10636
- "data-menu-backing": "",
10637
- className: clsx(css$37.backing, compact && css$37.compact),
10638
- style: {
10639
- ...anchorStyle,
10640
- visibility: style?.visibility
10641
- }
10642
- }), document.body)] });
10643
- });
10644
- //#endregion
10645
- export { Button, Checkbox, CodeBlock, CommandText, ConnectionIndicator, DEFAULT_DIFF_MAX_LINES, DEFAULT_READ_MAX_LINES, DEFAULT_SEARCH_MAX_LINES, DEFAULT_TERMINAL_MAX_LINES, DiffBlock, DisclosureRow, FileTypeIcon, 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, IconLogoutOutline16, IconMicrophoneOutline16, IconNewChatOutline16, IconPanelLeftOutline16, IconPaperPlaneOutline14, IconPaperclipOutline16, IconPauseOutline16, IconPersonalizationOutline16, IconPinFillRegular, IconPinOutlineRegular, IconPlanOutline14, IconPlayOutline16, IconPluginPinwheelOutline16, IconPlusOutline16, IconProjectAddOutline16, IconQuestionOutline14, IconQueueOutline14, IconRefreshOutline14, IconRefreshOutline16, IconRightUpOutline14, IconRightUpOutline16, IconSearchOutline16, IconSendOutline14, IconSendOutline16, IconSettingsOutline14, IconSettingsOutline16, IconShareOutline16, IconShieldOutline16, IconSkillOutline16, IconSparkle16, IconStopFill16, IconTerminalOutline16, IconThinkOutline14, IconThinkOutline16, IconTrashOutline16, IconTreeCorner8x10, IconTriangleRightFill14, IconUserOutline16, IconWarningOutline16, IconWrapLinesOutline16, ImageLightbox, Input, JsonBlock, JsonTree, LinkIcon, MarkdownDelegateProvider, MarkdownText, Menu, MenuGroup, MenuItemButton, MenuSurface, Modal, OnboardingSurface, PathLabel, Pill, QilinSeal, ReadBlock, ReferenceIcon, RiskConfirmation, SHIELD_OUTLINE_PATH, SHIELD_OUTLINE_STROKE, SearchBlock, SegmentedControl, SettingsForm, SettingsFormModel, SettingsSecretField, SettingsValueField, ShortcutKeys, StateDot, Switch, Tag, TerminalBlock, TextShimmer, Toast, Tooltip, WebBlock, classifyFileType, classifyLinkPath, closeTopModal, diffTotals, extractMarkdownPlainText, fileExtension, fileSizeRoundedText, fileSizeText, focusWithoutRing, isBehindModal, isDarwinDesktop, modalSelector, observeComposition, observeStickyMenuGroups, overlayTopMargin, projectUserText, rankByName, relativeTime, settingsNumberField, settingsTextField, useAnchoredMaxHeight, useAnchoredPosition, useCopyFeedback, useDismissOnOutsidePointer, useModalLayer, watchDarwinDesktop, writeClipboard };
11972
+ export { Button, Checkbox, CodeBlock, CommandText, ConnectionIndicator, DEFAULT_DIFF_MAX_LINES, DEFAULT_READ_MAX_LINES, DEFAULT_SEARCH_MAX_LINES, DEFAULT_TERMINAL_MAX_LINES, DiffBlock, DisclosureRow, FileTypeIcon, HoverCard, IconAgentPresetOutline16, IconAlarmClockOutline16, IconApiOutline14, IconArchiveOutline20, IconBranchOutline16, IconBranchOutline16 as IconBranchOutlineRegular, IconBrowseOutline16, IconCheckCircleFillRegular, IconCheckOutline14, IconCheckOutline16, IconCheckOutline16 as IconCheckOutlineRegular, IconChecklistOutline14, IconChecklistOutline14 as IconChecklistOutlineRegular, IconChevronDownOutline14, IconChevronDownOutline14 as IconChevronDownOutlineMedium, IconChevronDownOutline14 as IconChevronDownOutlineRegular, IconChevronLeftOutline14, IconChevronLeftOutline14 as IconChevronLeftOutlineMedium, IconChevronRightOutline14, IconChevronRightOutline14 as IconChevronRightOutlineRegular, IconChevronUpOutline14, IconChevronUpOutline14 as IconChevronUpOutlineMedium, IconClockOutline16, IconCloseFill14, IconCloseOutline16, IconCloseOutline16 as IconCloseOutlineMedium, IconCloseOutline16 as IconCloseOutlineRegular, IconCodeOutline16, IconCompactOutline16, IconContextInjectionOutline16, IconCopyOutline16, IconCopyOutline16 as IconCopyOutlineRegular, IconCordisPluginOutline14, IconDarkOutline16, IconDataOutline16, IconDatabaseOutline16, IconDislikeFill16, IconDislikeOutline16, IconDownloadOutline16, IconDownloadOutline16 as IconDownloadOutlineRegular, IconEditOutline16, IconEllipsisOutline16, IconEnhanceOutline16, IconFolderClose16, IconFolderOpen16, IconFolderOpenOutline16, IconFollowsystemOutline16, IconFullscreenOutline16, IconGaugeOutline16, IconGlobeOutline14, IconGoalOutline16, IconInfoOutline14, IconInfoOutline14 as IconInfoOutlineRegular, IconInspectOutline12, IconLightOutline16, IconLikeFill16, IconLikeOutline16, IconLinkOutline14, IconLinkOutline16, IconListPenOutline16, IconLoadingOutline16, IconLogoutOutline16, IconMicrophoneOutline16, IconNewChatOutline16, IconPanelLeftOutline16, IconPaperPlaneOutline14, IconPaperclipOutline16, IconPauseOutline16, IconPersonalizationOutline16, IconPinFillRegular, IconPinOutlineRegular, IconPlanOutline14, IconPlayOutline16, IconPluginPinwheelOutline16, IconPluginPinwheelOutline16 as IconPluginPinwheelOutlineRegular, IconPlusOutline16, IconPlusOutline16 as IconPlusOutlineRegular, IconProjectAddOutline16, IconQuestionOutline14, IconQueueOutline14, IconRefreshOutline14, IconRefreshOutline14 as IconRefreshOutlineRegular, IconRefreshOutline16, IconRightUpOutline14, IconRightUpOutline16, IconSearchOutline16, IconSearchOutline16 as IconSearchOutlineRegular, IconSendOutline14, IconSendOutline16, IconSendOutline16 as IconSendOutlineRegular, IconSettingsOutline14, IconSettingsOutline14 as IconSettingsOutlineMedium, IconSettingsOutline16, IconShareOutline16, IconShieldOutline16, IconSkillOutline16, IconSlidersTwoOutlineMedium, IconSlidersTwoOutlineRegular, IconSparkle16, IconStopFill16, IconTerminalOutline16, IconThinkOutline14, IconThinkOutline16, IconTrashOutline16, IconTrashOutline16 as IconTrashOutlineRegular, IconTreeCorner8x10, IconTriangleRightFill14, IconUserOutline16, IconUserOutline16 as IconUserOutlineRegular, IconUsersOutlineRegular, IconWarningOutline16, IconWarningOutline16 as IconWarningOutlineRegular, IconWorkspaceTreeOutlineRegular, IconWrapLinesOutline16, ImageLightbox, InlineEditor, Input, JsonBlock, JsonTree, LinkIcon, MarkdownDelegateProvider, MarkdownText, Menu, MenuGroup, MenuItemButton, MenuSurface, Modal, OnboardingSurface, PathLabel, Pill, PluginArtworkDefault, PluginArtworkLoop, PluginArtworkSearch, PluginArtworkSubagent, PluginArtworkTerminal, QilinSeal, ReadBlock, ReferenceIcon, RiskConfirmation, SHIELD_OUTLINE_PATH, SHIELD_OUTLINE_STROKE, SearchBlock, SegmentedControl, SegmentedTabs, SettingsForm, SettingsFormModel, SettingsSecretField, SettingsValueField, ShortcutKeys, StateDot, Switch, Tag, TerminalBlock, TextShimmer, Toast, Tooltip, WebBlock, classifyFileType, classifyLinkPath, closeTopModal, diffTotals, extractMarkdownPlainText, fileExtension, fileSizeRoundedText, fileSizeText, focusWithoutRing, isBehindModal, isDarwinDesktop, modalSelector, observeComposition, observeStickyMenuGroups, overlayTopMargin, pointerModality, projectUserText, rankByName, relativeTime, settingsNumberField, settingsTextField, useAnchoredMaxHeight, useAnchoredPosition, useCopyFeedback, useDismissOnOutsidePointer, useModalLayer, watchDarwinDesktop, writeClipboard };
10646
11973
 
10647
11974
  //# sourceMappingURL=index.js.map