@zaly/tui 0.0.4
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/LICENSE +21 -0
- package/README.md +59 -0
- package/assets/schemas/theme.schema.json +899 -0
- package/assets/themes/LICENSE-tokyonight.txt +201 -0
- package/assets/themes/NOTICES.md +69 -0
- package/assets/themes/ayu-dark.json +119 -0
- package/assets/themes/catppuccin-frappe.json +124 -0
- package/assets/themes/catppuccin-latte.json +124 -0
- package/assets/themes/catppuccin-macchiato.json +124 -0
- package/assets/themes/catppuccin-mocha.json +124 -0
- package/assets/themes/dracula-soft.json +119 -0
- package/assets/themes/dracula.json +119 -0
- package/assets/themes/everforest-dark.json +118 -0
- package/assets/themes/everforest-light.json +118 -0
- package/assets/themes/github-dark.json +123 -0
- package/assets/themes/github-light.json +123 -0
- package/assets/themes/gruvbox-dark-medium.json +112 -0
- package/assets/themes/kanagawa-dragon.json +115 -0
- package/assets/themes/kanagawa-wave.json +115 -0
- package/assets/themes/material-theme-palenight.json +114 -0
- package/assets/themes/min-dark.json +55 -0
- package/assets/themes/min-light.json +59 -0
- package/assets/themes/monokai.json +116 -0
- package/assets/themes/night-owl.json +116 -0
- package/assets/themes/nord.json +101 -0
- package/assets/themes/one-dark-pro.json +110 -0
- package/assets/themes/one-light.json +108 -0
- package/assets/themes/poimandres.json +123 -0
- package/assets/themes/rose-pine.json +98 -0
- package/assets/themes/solarized-dark.json +116 -0
- package/assets/themes/solarized-light.json +116 -0
- package/assets/themes/synthwave-84.json +100 -0
- package/assets/themes/tokyonight-day.json +157 -0
- package/assets/themes/tokyonight-moon.json +157 -0
- package/assets/themes/tokyonight-night.json +157 -0
- package/assets/themes/tokyonight-storm.json +157 -0
- package/assets/themes/vesper.json +103 -0
- package/assets/themes/vitesse-dark.json +126 -0
- package/assets/themes/vitesse-light.json +126 -0
- package/dist/ansi-Clq0ozyA.mjs +206 -0
- package/dist/ansi-Clq0ozyA.mjs.map +1 -0
- package/dist/ansi.d.mts +48 -0
- package/dist/ansi.d.mts.map +1 -0
- package/dist/ansi.mjs +2 -0
- package/dist/autocomplete-Dfw-yQDa.d.mts +100 -0
- package/dist/autocomplete-Dfw-yQDa.d.mts.map +1 -0
- package/dist/box-DyaByEiG.mjs +386 -0
- package/dist/box-DyaByEiG.mjs.map +1 -0
- package/dist/builder-D49ECBEf.mjs +385 -0
- package/dist/builder-D49ECBEf.mjs.map +1 -0
- package/dist/callbacks-CNjGNxVw.mjs +279 -0
- package/dist/callbacks-CNjGNxVw.mjs.map +1 -0
- package/dist/client-D6C_uczF.mjs +142 -0
- package/dist/client-D6C_uczF.mjs.map +1 -0
- package/dist/clipboard.d.mts +104 -0
- package/dist/clipboard.d.mts.map +1 -0
- package/dist/clipboard.mjs +404 -0
- package/dist/clipboard.mjs.map +1 -0
- package/dist/flex-Bguo-fUe.mjs +202 -0
- package/dist/flex-Bguo-fUe.mjs.map +1 -0
- package/dist/image-Cm5T-uw-.mjs +108 -0
- package/dist/image-Cm5T-uw-.mjs.map +1 -0
- package/dist/image.d.mts +123 -0
- package/dist/image.d.mts.map +1 -0
- package/dist/image.mjs +2 -0
- package/dist/index.d.mts +64 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +222 -0
- package/dist/index.mjs.map +1 -0
- package/dist/input-B5Vy-iaa.d.mts +141 -0
- package/dist/input-B5Vy-iaa.d.mts.map +1 -0
- package/dist/inspect-D1d9t-ni.mjs +101 -0
- package/dist/inspect-D1d9t-ni.mjs.map +1 -0
- package/dist/inspect-D6FW_QUo.d.mts +67 -0
- package/dist/inspect-D6FW_QUo.d.mts.map +1 -0
- package/dist/kitty-JbCJC0iQ.mjs +673 -0
- package/dist/kitty-JbCJC0iQ.mjs.map +1 -0
- package/dist/markdown.d.mts +24 -0
- package/dist/markdown.d.mts.map +1 -0
- package/dist/markdown.mjs +2 -0
- package/dist/md.bun.d.mts +14 -0
- package/dist/md.bun.d.mts.map +1 -0
- package/dist/md.bun.mjs +28 -0
- package/dist/md.bun.mjs.map +1 -0
- package/dist/md.node.d.mts +14 -0
- package/dist/md.node.d.mts.map +1 -0
- package/dist/md.node.mjs +126 -0
- package/dist/md.node.mjs.map +1 -0
- package/dist/node-BZ7f6HzU.mjs +316 -0
- package/dist/node-BZ7f6HzU.mjs.map +1 -0
- package/dist/picker-D8OLb6kZ.d.mts +36 -0
- package/dist/picker-D8OLb6kZ.d.mts.map +1 -0
- package/dist/picker-ndVVt6qF.mjs +621 -0
- package/dist/picker-ndVVt6qF.mjs.map +1 -0
- package/dist/queries-DH3bj74K.d.mts +1963 -0
- package/dist/queries-DH3bj74K.d.mts.map +1 -0
- package/dist/reactive-f7NpAi69.mjs +623 -0
- package/dist/reactive-f7NpAi69.mjs.map +1 -0
- package/dist/registry-U654j61Y.mjs +356 -0
- package/dist/registry-U654j61Y.mjs.map +1 -0
- package/dist/render-DxVLqqB9.mjs +74 -0
- package/dist/render-DxVLqqB9.mjs.map +1 -0
- package/dist/renderer-CdLCkJB-.mjs +42 -0
- package/dist/renderer-CdLCkJB-.mjs.map +1 -0
- package/dist/renderer-CxL4xbkl.mjs +2644 -0
- package/dist/renderer-CxL4xbkl.mjs.map +1 -0
- package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/dist/search-FvGnswRl.d.mts +49 -0
- package/dist/search-FvGnswRl.d.mts.map +1 -0
- package/dist/select-CbmAZdpt.d.mts +116 -0
- package/dist/select-CbmAZdpt.d.mts.map +1 -0
- package/dist/services/logger.d.mts +2 -0
- package/dist/services/logger.mjs +71 -0
- package/dist/services/logger.mjs.map +1 -0
- package/dist/services/notifier.d.mts +17 -0
- package/dist/services/notifier.d.mts.map +1 -0
- package/dist/services/notifier.mjs +71 -0
- package/dist/services/notifier.mjs.map +1 -0
- package/dist/services/picker.d.mts +36 -0
- package/dist/services/picker.d.mts.map +1 -0
- package/dist/services/picker.mjs +137 -0
- package/dist/services/picker.mjs.map +1 -0
- package/dist/services/prompt.d.mts +30 -0
- package/dist/services/prompt.d.mts.map +1 -0
- package/dist/services/prompt.mjs +83 -0
- package/dist/services/prompt.mjs.map +1 -0
- package/dist/shiki-BrjVUkeh.mjs +423 -0
- package/dist/shiki-BrjVUkeh.mjs.map +1 -0
- package/dist/size-D8JogYLy.mjs +34 -0
- package/dist/size-D8JogYLy.mjs.map +1 -0
- package/dist/style.d.mts +10 -0
- package/dist/style.d.mts.map +1 -0
- package/dist/style.mjs +4 -0
- package/dist/text.d.mts +33 -0
- package/dist/text.d.mts.map +1 -0
- package/dist/text.mjs +111 -0
- package/dist/text.mjs.map +1 -0
- package/dist/theme.config-CU3B50HN.mjs +832 -0
- package/dist/theme.config-CU3B50HN.mjs.map +1 -0
- package/dist/themes.d.mts +113 -0
- package/dist/themes.d.mts.map +1 -0
- package/dist/themes.mjs +2 -0
- package/dist/tree-C28QOVIK.d.mts +23 -0
- package/dist/tree-C28QOVIK.d.mts.map +1 -0
- package/dist/types-B9Eh7k2v.d.mts +212 -0
- package/dist/types-B9Eh7k2v.d.mts.map +1 -0
- package/dist/types-D3jk1rtk.d.mts +140 -0
- package/dist/types-D3jk1rtk.d.mts.map +1 -0
- package/dist/utils-3M4D_AXZ.mjs +40 -0
- package/dist/utils-3M4D_AXZ.mjs.map +1 -0
- package/dist/widgets/autocomplete.d.mts +2 -0
- package/dist/widgets/autocomplete.mjs +165 -0
- package/dist/widgets/autocomplete.mjs.map +1 -0
- package/dist/widgets/box.d.mts +2 -0
- package/dist/widgets/box.mjs +2 -0
- package/dist/widgets/code.d.mts +48 -0
- package/dist/widgets/code.d.mts.map +1 -0
- package/dist/widgets/code.mjs +59 -0
- package/dist/widgets/code.mjs.map +1 -0
- package/dist/widgets/completions/actions.d.mts +41 -0
- package/dist/widgets/completions/actions.d.mts.map +1 -0
- package/dist/widgets/completions/actions.mjs +48 -0
- package/dist/widgets/completions/actions.mjs.map +1 -0
- package/dist/widgets/completions/files.d.mts +29 -0
- package/dist/widgets/completions/files.d.mts.map +1 -0
- package/dist/widgets/completions/files.mjs +42 -0
- package/dist/widgets/completions/files.mjs.map +1 -0
- package/dist/widgets/completions/github.d.mts +64 -0
- package/dist/widgets/completions/github.d.mts.map +1 -0
- package/dist/widgets/completions/github.mjs +137 -0
- package/dist/widgets/completions/github.mjs.map +1 -0
- package/dist/widgets/completions/index.d.mts +4 -0
- package/dist/widgets/completions/index.mjs +4 -0
- package/dist/widgets/diff.d.mts +57 -0
- package/dist/widgets/diff.d.mts.map +1 -0
- package/dist/widgets/diff.mjs +199 -0
- package/dist/widgets/diff.mjs.map +1 -0
- package/dist/widgets/divider.d.mts +11 -0
- package/dist/widgets/divider.d.mts.map +1 -0
- package/dist/widgets/divider.mjs +9 -0
- package/dist/widgets/divider.mjs.map +1 -0
- package/dist/widgets/image.d.mts +37 -0
- package/dist/widgets/image.d.mts.map +1 -0
- package/dist/widgets/image.mjs +77 -0
- package/dist/widgets/image.mjs.map +1 -0
- package/dist/widgets/input.d.mts +2 -0
- package/dist/widgets/input.mjs +497 -0
- package/dist/widgets/input.mjs.map +1 -0
- package/dist/widgets/log.d.mts +2 -0
- package/dist/widgets/log.mjs +130 -0
- package/dist/widgets/log.mjs.map +1 -0
- package/dist/widgets/markdown.d.mts +45 -0
- package/dist/widgets/markdown.d.mts.map +1 -0
- package/dist/widgets/markdown.mjs +124 -0
- package/dist/widgets/markdown.mjs.map +1 -0
- package/dist/widgets/overlay.d.mts +2 -0
- package/dist/widgets/overlay.mjs +18 -0
- package/dist/widgets/overlay.mjs.map +1 -0
- package/dist/widgets/picker.d.mts +2 -0
- package/dist/widgets/picker.mjs +2 -0
- package/dist/widgets/progress.d.mts +48 -0
- package/dist/widgets/progress.d.mts.map +1 -0
- package/dist/widgets/progress.mjs +48 -0
- package/dist/widgets/progress.mjs.map +1 -0
- package/dist/widgets/select.d.mts +2 -0
- package/dist/widgets/select.mjs +195 -0
- package/dist/widgets/select.mjs.map +1 -0
- package/dist/widgets/show.d.mts +55 -0
- package/dist/widgets/show.d.mts.map +1 -0
- package/dist/widgets/show.mjs +85 -0
- package/dist/widgets/show.mjs.map +1 -0
- package/dist/widgets/spinner.d.mts +65 -0
- package/dist/widgets/spinner.d.mts.map +1 -0
- package/dist/widgets/spinner.mjs +147 -0
- package/dist/widgets/spinner.mjs.map +1 -0
- package/dist/widgets/text.d.mts +2 -0
- package/dist/widgets/text.mjs +32 -0
- package/dist/widgets/text.mjs.map +1 -0
- package/dist/widgets/tree.d.mts +2 -0
- package/dist/widgets/tree.mjs +73 -0
- package/dist/widgets/tree.mjs.map +1 -0
- package/dist/widgets/widget.d.mts +49 -0
- package/dist/widgets/widget.d.mts.map +1 -0
- package/dist/widgets/widget.mjs +40 -0
- package/dist/widgets/widget.mjs.map +1 -0
- package/dist/worker-DjHuQSbY.mjs +27 -0
- package/dist/worker-DjHuQSbY.mjs.map +1 -0
- package/package.json +117 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "file:./../schemas/theme.schema.json",
|
|
3
|
+
"id": "vitesse-light",
|
|
4
|
+
"name": "Vitesse Light",
|
|
5
|
+
"shiki": "vitesse-light",
|
|
6
|
+
"text": "#393a34",
|
|
7
|
+
"subtle": "#aaaaaa",
|
|
8
|
+
"ui": {
|
|
9
|
+
"bg": "#ffffff",
|
|
10
|
+
"fg": "#393a34"
|
|
11
|
+
},
|
|
12
|
+
"primary": "#1c6b48",
|
|
13
|
+
"accent": "#1c6b48",
|
|
14
|
+
"success": "#1e754f",
|
|
15
|
+
"info": "#2993a3",
|
|
16
|
+
"warn": "#a65e2b",
|
|
17
|
+
"error": "#ab5959",
|
|
18
|
+
"muted": "#aaaaaa",
|
|
19
|
+
"border": "#f0f0f0",
|
|
20
|
+
"code": {
|
|
21
|
+
"bg": "#ffffff"
|
|
22
|
+
},
|
|
23
|
+
"mdCodeBlock": {
|
|
24
|
+
"bg": "#ffffff"
|
|
25
|
+
},
|
|
26
|
+
"overlay": {
|
|
27
|
+
"bg": "#ffffff"
|
|
28
|
+
},
|
|
29
|
+
"highlight": {
|
|
30
|
+
"bg": "#eaeaea"
|
|
31
|
+
},
|
|
32
|
+
"selection": {
|
|
33
|
+
"bg": "#eaeaea"
|
|
34
|
+
},
|
|
35
|
+
"diffAdd": {
|
|
36
|
+
"bg": "#d4e3dd",
|
|
37
|
+
"fg": "#22863a"
|
|
38
|
+
},
|
|
39
|
+
"diffDel": {
|
|
40
|
+
"bg": "#ead5d5",
|
|
41
|
+
"fg": "#b31d28"
|
|
42
|
+
},
|
|
43
|
+
"diffTitle": {
|
|
44
|
+
"fg": "#b31d28",
|
|
45
|
+
"bg": "#ffeef0"
|
|
46
|
+
},
|
|
47
|
+
"comment": {
|
|
48
|
+
"fg": "#a0ada0"
|
|
49
|
+
},
|
|
50
|
+
"syntaxNumber": {
|
|
51
|
+
"fg": "#2f798a"
|
|
52
|
+
},
|
|
53
|
+
"syntaxString": {
|
|
54
|
+
"fg": "#b56959"
|
|
55
|
+
},
|
|
56
|
+
"syntaxBoolean": {
|
|
57
|
+
"fg": "#1e754f"
|
|
58
|
+
},
|
|
59
|
+
"syntaxFunction": {
|
|
60
|
+
"fg": "#59873a"
|
|
61
|
+
},
|
|
62
|
+
"syntaxField": {
|
|
63
|
+
"fg": "#b07d48"
|
|
64
|
+
},
|
|
65
|
+
"syntaxConstant": {
|
|
66
|
+
"fg": "#a65e2b"
|
|
67
|
+
},
|
|
68
|
+
"syntaxSpecial": {
|
|
69
|
+
"fg": "#1e754f"
|
|
70
|
+
},
|
|
71
|
+
"syntaxDelimiter": {
|
|
72
|
+
"fg": "#999999"
|
|
73
|
+
},
|
|
74
|
+
"syntaxBracket": {
|
|
75
|
+
"fg": "#999999"
|
|
76
|
+
},
|
|
77
|
+
"mdHeading": {
|
|
78
|
+
"bold": true,
|
|
79
|
+
"fg": "#1c6b48"
|
|
80
|
+
},
|
|
81
|
+
"mdHeading1": {
|
|
82
|
+
"bold": true,
|
|
83
|
+
"fg": "#1c6b48"
|
|
84
|
+
},
|
|
85
|
+
"mdHeading2": {
|
|
86
|
+
"bold": true,
|
|
87
|
+
"fg": "#1c6b48"
|
|
88
|
+
},
|
|
89
|
+
"mdHeading3": {
|
|
90
|
+
"bold": true,
|
|
91
|
+
"fg": "#1c6b48"
|
|
92
|
+
},
|
|
93
|
+
"mdHeading4": {
|
|
94
|
+
"bold": true,
|
|
95
|
+
"fg": "#1c6b48"
|
|
96
|
+
},
|
|
97
|
+
"mdHeading5": {
|
|
98
|
+
"bold": true,
|
|
99
|
+
"fg": "#1c6b48"
|
|
100
|
+
},
|
|
101
|
+
"mdHeading6": {
|
|
102
|
+
"bold": true,
|
|
103
|
+
"fg": "#1c6b48"
|
|
104
|
+
},
|
|
105
|
+
"mdBold": {
|
|
106
|
+
"bold": true,
|
|
107
|
+
"fg": "#393a34"
|
|
108
|
+
},
|
|
109
|
+
"mdItalic": {
|
|
110
|
+
"italic": true,
|
|
111
|
+
"fg": "#393a34"
|
|
112
|
+
},
|
|
113
|
+
"mdLink": {
|
|
114
|
+
"fg": "#b56959"
|
|
115
|
+
},
|
|
116
|
+
"mdQuote": {
|
|
117
|
+
"fg": "#2e808f"
|
|
118
|
+
},
|
|
119
|
+
"mdCode": {
|
|
120
|
+
"fg": "#1c6b48"
|
|
121
|
+
},
|
|
122
|
+
"mdHr": {
|
|
123
|
+
"bold": true,
|
|
124
|
+
"fg": "#005cc5"
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { clamp } from "@zaly/shared";
|
|
2
|
+
import { sliceAnsi } from "@zaly/shared/ansi";
|
|
3
|
+
import { hasColors } from "@zaly/shared/env";
|
|
4
|
+
//#region src/style/color.ts
|
|
5
|
+
const hexByte = (n) => clamp(Math.round(n), 0, 255).toString(16).padStart(2, "0");
|
|
6
|
+
function toHex(x, y, z) {
|
|
7
|
+
const [r, g, b] = Array.isArray(x) ? x : [
|
|
8
|
+
x,
|
|
9
|
+
y,
|
|
10
|
+
z
|
|
11
|
+
];
|
|
12
|
+
return `#${hexByte(r)}${hexByte(g)}${hexByte(b)}`;
|
|
13
|
+
}
|
|
14
|
+
function parseHex(hex) {
|
|
15
|
+
let s = hex.charCodeAt(0) === 35 ? hex.slice(1) : hex;
|
|
16
|
+
if (s.length === 4) s = s.slice(0, 3);
|
|
17
|
+
if (s.length === 8) s = s.slice(0, 6);
|
|
18
|
+
if (s.length === 3) s = s[0] + s[0] + s[1] + s[1] + s[2] + s[2];
|
|
19
|
+
if (s.length !== 6) throw new Error(`invalid hex color: ${hex}`);
|
|
20
|
+
const n = Number.parseInt(s, 16);
|
|
21
|
+
if (Number.isNaN(n)) throw new Error(`invalid hex color: ${hex}`);
|
|
22
|
+
return [
|
|
23
|
+
n >> 16 & 255,
|
|
24
|
+
n >> 8 & 255,
|
|
25
|
+
n & 255
|
|
26
|
+
];
|
|
27
|
+
}
|
|
28
|
+
function isHexColor(s) {
|
|
29
|
+
return /^#[0-9a-fA-F]{3,8}$/.test(s);
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/style/ansi.ts
|
|
33
|
+
const OSC8 = "\x1B]8;;";
|
|
34
|
+
const ST = "\x1B\\";
|
|
35
|
+
const RESET = "\x1B[0m";
|
|
36
|
+
const ATTRS = [
|
|
37
|
+
["bold", 1],
|
|
38
|
+
["dim", 2],
|
|
39
|
+
["italic", 3],
|
|
40
|
+
["underline", 4],
|
|
41
|
+
["inverse", 7],
|
|
42
|
+
["strikethrough", 9]
|
|
43
|
+
];
|
|
44
|
+
const ANSI_OFFSET = {
|
|
45
|
+
black: 0,
|
|
46
|
+
blue: 4,
|
|
47
|
+
cyan: 6,
|
|
48
|
+
green: 2,
|
|
49
|
+
magenta: 5,
|
|
50
|
+
red: 1,
|
|
51
|
+
white: 7,
|
|
52
|
+
yellow: 3
|
|
53
|
+
};
|
|
54
|
+
const ANSI_BG = {
|
|
55
|
+
100: "gray",
|
|
56
|
+
101: "brightRed",
|
|
57
|
+
102: "brightGreen",
|
|
58
|
+
103: "brightYellow",
|
|
59
|
+
104: "brightBlue",
|
|
60
|
+
105: "brightMagenta",
|
|
61
|
+
106: "brightCyan",
|
|
62
|
+
107: "brightWhite",
|
|
63
|
+
40: "black",
|
|
64
|
+
41: "red",
|
|
65
|
+
42: "green",
|
|
66
|
+
43: "yellow",
|
|
67
|
+
44: "blue",
|
|
68
|
+
45: "magenta",
|
|
69
|
+
46: "cyan",
|
|
70
|
+
47: "white"
|
|
71
|
+
};
|
|
72
|
+
const notFound = Symbol("not found");
|
|
73
|
+
const colorCache = /* @__PURE__ */ new Map();
|
|
74
|
+
/**
|
|
75
|
+
* Wrap `text` in an OSC 8 hyperlink pointing at `url`. Modern terminals
|
|
76
|
+
* (iTerm2, kitty, WezTerm, VS Code, Ghostty, …) render the text as
|
|
77
|
+
* clickable while falling back gracefully to plain text elsewhere.
|
|
78
|
+
*
|
|
79
|
+
* Safe to nest ANSI SGR styling inside the `text` argument — OSC 8 is a
|
|
80
|
+
* separate escape category and doesn't conflict.
|
|
81
|
+
*
|
|
82
|
+
* An empty `url` short-circuits and returns `text` unchanged, so callers
|
|
83
|
+
* can unconditionally pipe link text through this helper.
|
|
84
|
+
*
|
|
85
|
+
* @internal
|
|
86
|
+
*/
|
|
87
|
+
function hyperlink(url, text) {
|
|
88
|
+
if (url === "") return text;
|
|
89
|
+
return `${OSC8}${url}${ST}${text}${OSC8}${ST}`;
|
|
90
|
+
}
|
|
91
|
+
function ansiColor(color, kind) {
|
|
92
|
+
if (!hasColors) return;
|
|
93
|
+
const key = `${color}-${kind}`;
|
|
94
|
+
let cached = colorCache.get(key);
|
|
95
|
+
if (cached === void 0) colorCache.set(key, (cached = _ansiColor(color, kind)) ?? notFound);
|
|
96
|
+
return cached === notFound ? void 0 : cached;
|
|
97
|
+
}
|
|
98
|
+
function _ansiColor(color, kind) {
|
|
99
|
+
if (color === "inherit") return;
|
|
100
|
+
if (color === "gray" || color === "grey") return String(kind === "fg" ? 90 : 100);
|
|
101
|
+
const base = color in ANSI_OFFSET ? color : void 0;
|
|
102
|
+
if (base !== void 0) return String((kind === "fg" ? 30 : 40) + ANSI_OFFSET[base]);
|
|
103
|
+
if (color.startsWith("bright")) {
|
|
104
|
+
const rest = color.slice(6).toLowerCase();
|
|
105
|
+
if (rest in ANSI_OFFSET) return String((kind === "fg" ? 90 : 100) + ANSI_OFFSET[rest]);
|
|
106
|
+
}
|
|
107
|
+
const rgb = isHexColor(color) ? parseHex(color) : void 0;
|
|
108
|
+
if (rgb) return `${kind === "fg" ? 38 : 48};2;${rgb[0]};${rgb[1]};${rgb[2]}`;
|
|
109
|
+
}
|
|
110
|
+
function openAnsi(style) {
|
|
111
|
+
if (!hasColors) return "";
|
|
112
|
+
const params = [];
|
|
113
|
+
for (const [key, code] of ATTRS) if (style[key]) params.push(code);
|
|
114
|
+
if (style.fg !== void 0) params.push(ansiColor(style.fg, "fg"));
|
|
115
|
+
if (style.bg !== void 0) params.push(ansiColor(style.bg, "bg"));
|
|
116
|
+
const attrs = params.filter((p) => p !== void 0);
|
|
117
|
+
if (attrs.length === 0) return "";
|
|
118
|
+
return `\x1b[${attrs.join(";")}m`;
|
|
119
|
+
}
|
|
120
|
+
function styleAnsi(text, style) {
|
|
121
|
+
if (!style) return text;
|
|
122
|
+
const open = openAnsi(style);
|
|
123
|
+
if (open === "") return text;
|
|
124
|
+
return `${open}${text}${RESET}`;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Post-process a styled string so an outer style is re-applied after any
|
|
128
|
+
* inner full-reset (`\x1b[0m`). Without this, a child's reset clobbers
|
|
129
|
+
* the parent's bg/fg/attrs for the remainder of the line.
|
|
130
|
+
*
|
|
131
|
+
* `escape` is the already-built SGR run to re-emit after each reset
|
|
132
|
+
* (typically the return value of `openStyle(parentStyle, theme)`). If
|
|
133
|
+
* empty, the input is returned unchanged.
|
|
134
|
+
*
|
|
135
|
+
* Inlined indexOf loop rather than `String.prototype.replaceAll` — the
|
|
136
|
+
* manual version avoids the regex/object allocation overhead of
|
|
137
|
+
* `replaceAll` and runs meaningfully faster on short strings (hot in
|
|
138
|
+
* the builder's `apply`, called once per styled span). Pattern taken
|
|
139
|
+
* from ansis's nested-style resolver.
|
|
140
|
+
*
|
|
141
|
+
* @internal
|
|
142
|
+
*/
|
|
143
|
+
function reapplyStyle(s, escape) {
|
|
144
|
+
if (escape === "" || !s.includes("\x1B[0m")) return s;
|
|
145
|
+
const replacement = RESET + escape;
|
|
146
|
+
const searchLength = 4;
|
|
147
|
+
let result = "";
|
|
148
|
+
let lastPos = 0;
|
|
149
|
+
let pos = s.indexOf(RESET);
|
|
150
|
+
while (pos !== -1) {
|
|
151
|
+
result += s.slice(lastPos, pos) + replacement;
|
|
152
|
+
lastPos = pos + searchLength;
|
|
153
|
+
pos = s.indexOf(RESET, lastPos);
|
|
154
|
+
}
|
|
155
|
+
return result + s.slice(lastPos);
|
|
156
|
+
}
|
|
157
|
+
function stripAnsiBg(s) {
|
|
158
|
+
return s.replaceAll(/\x1b\[([0-9;]*)m/g, (match, raw) => {
|
|
159
|
+
const next = stripBgParams(raw);
|
|
160
|
+
if (next === raw) return match;
|
|
161
|
+
return next === "" ? "" : `\x1b[${next}m`;
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
function stripBgParams(raw) {
|
|
165
|
+
if (raw === "") return raw;
|
|
166
|
+
const params = raw.split(";").map(Number);
|
|
167
|
+
const ret = [];
|
|
168
|
+
for (let i = 0; i < params.length; i++) {
|
|
169
|
+
const p = params[i];
|
|
170
|
+
if (p >= 40 && p <= 47 || p >= 100 && p <= 107 || p === 49) continue;
|
|
171
|
+
if (p === 48) {
|
|
172
|
+
const mode = params[i + 1];
|
|
173
|
+
if (mode === 2) {
|
|
174
|
+
i += 4;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (mode === 5) {
|
|
178
|
+
i += 2;
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
ret.push(p);
|
|
184
|
+
}
|
|
185
|
+
return ret.join(";");
|
|
186
|
+
}
|
|
187
|
+
function ansiBg(str, idx) {
|
|
188
|
+
const cell = sliceAnsi(str, idx, idx + 1);
|
|
189
|
+
let bg;
|
|
190
|
+
for (const match of cell.matchAll(/\x1b\[([0-9;]*)m/g)) {
|
|
191
|
+
const params = match[1].split(";").map(Number);
|
|
192
|
+
for (let i = 0; i < params.length; i++) {
|
|
193
|
+
const p = params[i];
|
|
194
|
+
if (p >= 40 && p <= 47 || p >= 100 && p <= 107) bg = ANSI_BG[p];
|
|
195
|
+
else if (p === 48 && params[i + 1] === 2) {
|
|
196
|
+
bg = toHex(params[i + 2], params[i + 3], params[i + 4]);
|
|
197
|
+
i += 4;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return bg;
|
|
202
|
+
}
|
|
203
|
+
//#endregion
|
|
204
|
+
export { openAnsi as a, styleAnsi as c, toHex as d, hyperlink as i, isHexColor as l, ansiBg as n, reapplyStyle as o, ansiColor as r, stripAnsiBg as s, RESET as t, parseHex as u };
|
|
205
|
+
|
|
206
|
+
//# sourceMappingURL=ansi-Clq0ozyA.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ansi-Clq0ozyA.mjs","names":[],"sources":["../src/style/color.ts","../src/style/ansi.ts"],"sourcesContent":["import type { HexColor, RGB } from \"./types.ts\"\n\nimport { clamp } from \"@zaly/shared\"\n\nconst hexByte = (n: number): string => clamp(Math.round(n), 0, 255).toString(16).padStart(2, \"0\")\n\nexport function toHex(c: RGB): HexColor\nexport function toHex(r: number, g: number, b: number): HexColor\nexport function toHex(x: number | RGB, y?: number, z?: number): HexColor {\n const [r, g, b] = Array.isArray(x) ? x : [x, y!, z!]\n return `#${hexByte(r)}${hexByte(g)}${hexByte(b)}`\n}\n\nexport function parseHex(hex: string): RGB {\n let s = hex.charCodeAt(0) === 0x23 ? hex.slice(1) : hex // strip leading #\n if (s.length === 4) s = s.slice(0, 3) // strip alpha\n if (s.length === 8) s = s.slice(0, 6) // strip alpha\n if (s.length === 3) {\n // Expand \"abc\" → \"aabbcc\" without allocating an array.\n s = s[0] + s[0] + s[1] + s[1] + s[2] + s[2]\n }\n if (s.length !== 6) throw new Error(`invalid hex color: ${hex}`)\n const n = Number.parseInt(s, 16)\n if (Number.isNaN(n)) throw new Error(`invalid hex color: ${hex}`)\n return [(n >> 16) & 0xff, (n >> 8) & 0xff, n & 0xff]\n}\n\nexport function isHexColor(s: string): s is HexColor {\n return /^#[0-9a-fA-F]{3,8}$/.test(s)\n}\n","import type { AnsiColor, AnsiStyle } from \"./types.ts\"\n\nimport { sliceAnsi } from \"@zaly/shared/ansi\"\nimport { hasColors } from \"@zaly/shared/env\"\nimport { isHexColor, parseHex, toHex } from \"./color.ts\"\n\n/** Optional wrap mode: `\"word\"` (default) breaks at word boundaries;\n * `\"char\"` hard-wraps mid-word. */\nexport interface WrapOpts {\n mode?: \"word\" | \"char\"\n}\n\n// ---- ANSI escape categories -------------------------------------------\n// OSC 8 hyperlink sequence. ESC + backslash is the \"string terminator\" (ST)\n// that closes the OSC. Format: `ESC]8;;URL ST TEXT ESC]8;; ST`.\nconst OSC8 = \"\\x1b]8;;\"\nconst ST = \"\\x1b\\\\\"\nexport const RESET = \"\\x1b[0m\"\n\n// Attribute → SGR code. Order matters for stable output.\nconst ATTRS = [\n [\"bold\", 1],\n [\"dim\", 2],\n [\"italic\", 3],\n [\"underline\", 4],\n [\"inverse\", 7],\n [\"strikethrough\", 9],\n] as const satisfies readonly (readonly [keyof AnsiStyle, number])[]\n\n// Standard 8-color ANSI palette. Offsets from SGR 30 (fg) and 40 (bg).\nconst ANSI_OFFSET: Record<string, number> = {\n black: 0,\n blue: 4,\n cyan: 6,\n green: 2,\n magenta: 5,\n red: 1,\n white: 7,\n yellow: 3,\n}\n\nconst ANSI_BG: Record<number, AnsiColor> = {\n 100: \"gray\", // or \"brightBlack\" if that exists\n 101: \"brightRed\",\n 102: \"brightGreen\",\n 103: \"brightYellow\",\n 104: \"brightBlue\",\n 105: \"brightMagenta\",\n 106: \"brightCyan\",\n 107: \"brightWhite\",\n 40: \"black\",\n 41: \"red\",\n 42: \"green\",\n 43: \"yellow\",\n 44: \"blue\",\n 45: \"magenta\",\n 46: \"cyan\",\n 47: \"white\",\n}\n\nconst notFound = Symbol(\"not found\")\nconst colorCache = new Map<string, string | typeof notFound>()\n\n/**\n * Wrap `text` in an OSC 8 hyperlink pointing at `url`. Modern terminals\n * (iTerm2, kitty, WezTerm, VS Code, Ghostty, …) render the text as\n * clickable while falling back gracefully to plain text elsewhere.\n *\n * Safe to nest ANSI SGR styling inside the `text` argument — OSC 8 is a\n * separate escape category and doesn't conflict.\n *\n * An empty `url` short-circuits and returns `text` unchanged, so callers\n * can unconditionally pipe link text through this helper.\n *\n * @internal\n */\nexport function hyperlink(url: string, text: string): string {\n if (url === \"\") return text\n return `${OSC8}${url}${ST}${text}${OSC8}${ST}`\n}\n\nexport function ansiColor(color: AnsiColor, kind: \"fg\" | \"bg\"): string | undefined {\n if (!hasColors) return\n const key = `${color}-${kind}`\n let cached = colorCache.get(key)\n if (cached === undefined) colorCache.set(key, (cached = _ansiColor(color, kind)) ?? notFound)\n return cached === notFound ? undefined : cached\n}\n\nfunction _ansiColor(color: AnsiColor, kind: \"fg\" | \"bg\"): string | undefined {\n if (color === \"inherit\") return\n // Gray aliases to brightBlack.\n if (color === \"gray\" || color === \"grey\") return String(kind === \"fg\" ? 90 : 100)\n\n const base = color in ANSI_OFFSET ? color : undefined\n if (base !== undefined) return String((kind === \"fg\" ? 30 : 40) + ANSI_OFFSET[base])\n\n if (color.startsWith(\"bright\")) {\n const rest = color.slice(\"bright\".length).toLowerCase()\n if (rest in ANSI_OFFSET) return String((kind === \"fg\" ? 90 : 100) + ANSI_OFFSET[rest])\n }\n\n const rgb = isHexColor(color) ? parseHex(color) : undefined\n if (rgb) {\n const indicator = kind === \"fg\" ? 38 : 48\n return `${indicator};2;${rgb[0]};${rgb[1]};${rgb[2]}`\n }\n}\n\nexport function openAnsi(style: AnsiStyle) {\n if (!hasColors) return \"\"\n const params: (number | string | undefined)[] = []\n for (const [key, code] of ATTRS) if (style[key]) params.push(code)\n if (style.fg !== undefined) params.push(ansiColor(style.fg, \"fg\"))\n if (style.bg !== undefined) params.push(ansiColor(style.bg, \"bg\"))\n const attrs = params.filter((p) => p !== undefined)\n if (attrs.length === 0) return \"\"\n return `\\x1b[${attrs.join(\";\")}m`\n}\n\nexport function styleAnsi(text: string, style?: AnsiStyle): string {\n if (!style) return text\n const open = openAnsi(style)\n if (open === \"\") return text\n return `${open}${text}${RESET}`\n}\n\n/**\n * Post-process a styled string so an outer style is re-applied after any\n * inner full-reset (`\\x1b[0m`). Without this, a child's reset clobbers\n * the parent's bg/fg/attrs for the remainder of the line.\n *\n * `escape` is the already-built SGR run to re-emit after each reset\n * (typically the return value of `openStyle(parentStyle, theme)`). If\n * empty, the input is returned unchanged.\n *\n * Inlined indexOf loop rather than `String.prototype.replaceAll` — the\n * manual version avoids the regex/object allocation overhead of\n * `replaceAll` and runs meaningfully faster on short strings (hot in\n * the builder's `apply`, called once per styled span). Pattern taken\n * from ansis's nested-style resolver.\n *\n * @internal\n */\nexport function reapplyStyle(s: string, escape: string): string {\n if (escape === \"\" || !s.includes(RESET)) return s\n const replacement = RESET + escape\n const searchLength = RESET.length\n let result = \"\"\n let lastPos = 0\n let pos = s.indexOf(RESET)\n while (pos !== -1) {\n result += s.slice(lastPos, pos) + replacement\n lastPos = pos + searchLength\n pos = s.indexOf(RESET, lastPos)\n }\n return result + s.slice(lastPos)\n}\n\nexport function stripAnsiBg(s: string): string {\n return s.replaceAll(/\\x1b\\[([0-9;]*)m/g, (match, raw: string) => {\n const next = stripBgParams(raw)\n if (next === raw) return match\n return next === \"\" ? \"\" : `\\x1b[${next}m`\n })\n}\n\nfunction stripBgParams(raw: string): string {\n if (raw === \"\") return raw\n const params = raw.split(\";\").map(Number)\n const ret: number[] = []\n for (let i = 0; i < params.length; i++) {\n const p = params[i]\n if ((p >= 40 && p <= 47) || (p >= 100 && p <= 107) || p === 49) continue\n if (p === 48) {\n const mode = params[i + 1]\n if (mode === 2) {\n i += 4\n continue\n }\n if (mode === 5) {\n i += 2\n continue\n }\n continue\n }\n ret.push(p)\n }\n return ret.join(\";\")\n}\n\nexport function ansiBg(str: string, idx: number): AnsiColor | undefined {\n const cell = sliceAnsi(str, idx, idx + 1)\n\n let bg: AnsiColor | undefined\n\n for (const match of cell.matchAll(/\\x1b\\[([0-9;]*)m/g)) {\n const params = match[1].split(\";\").map(Number)\n\n for (let i = 0; i < params.length; i++) {\n const p = params[i]\n\n if ((p >= 40 && p <= 47) || (p >= 100 && p <= 107)) {\n bg = ANSI_BG[p]\n } else if (p === 48 && params[i + 1] === 2) {\n bg = toHex(params[i + 2], params[i + 3], params[i + 4])\n i += 4\n }\n }\n }\n\n return bg\n}\n"],"mappings":"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"}
|
package/dist/ansi.d.mts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { a as AnsiStyle, r as AnsiColor } from "./types-B9Eh7k2v.mjs";
|
|
2
|
+
//#region src/style/ansi.d.ts
|
|
3
|
+
/** Optional wrap mode: `"word"` (default) breaks at word boundaries;
|
|
4
|
+
* `"char"` hard-wraps mid-word. */
|
|
5
|
+
interface WrapOpts {
|
|
6
|
+
mode?: "word" | "char";
|
|
7
|
+
}
|
|
8
|
+
declare const RESET = "[0m";
|
|
9
|
+
/**
|
|
10
|
+
* Wrap `text` in an OSC 8 hyperlink pointing at `url`. Modern terminals
|
|
11
|
+
* (iTerm2, kitty, WezTerm, VS Code, Ghostty, …) render the text as
|
|
12
|
+
* clickable while falling back gracefully to plain text elsewhere.
|
|
13
|
+
*
|
|
14
|
+
* Safe to nest ANSI SGR styling inside the `text` argument — OSC 8 is a
|
|
15
|
+
* separate escape category and doesn't conflict.
|
|
16
|
+
*
|
|
17
|
+
* An empty `url` short-circuits and returns `text` unchanged, so callers
|
|
18
|
+
* can unconditionally pipe link text through this helper.
|
|
19
|
+
*
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
declare function hyperlink(url: string, text: string): string;
|
|
23
|
+
declare function ansiColor(color: AnsiColor, kind: "fg" | "bg"): string | undefined;
|
|
24
|
+
declare function openAnsi(style: AnsiStyle): string;
|
|
25
|
+
declare function styleAnsi(text: string, style?: AnsiStyle): string;
|
|
26
|
+
/**
|
|
27
|
+
* Post-process a styled string so an outer style is re-applied after any
|
|
28
|
+
* inner full-reset (`\x1b[0m`). Without this, a child's reset clobbers
|
|
29
|
+
* the parent's bg/fg/attrs for the remainder of the line.
|
|
30
|
+
*
|
|
31
|
+
* `escape` is the already-built SGR run to re-emit after each reset
|
|
32
|
+
* (typically the return value of `openStyle(parentStyle, theme)`). If
|
|
33
|
+
* empty, the input is returned unchanged.
|
|
34
|
+
*
|
|
35
|
+
* Inlined indexOf loop rather than `String.prototype.replaceAll` — the
|
|
36
|
+
* manual version avoids the regex/object allocation overhead of
|
|
37
|
+
* `replaceAll` and runs meaningfully faster on short strings (hot in
|
|
38
|
+
* the builder's `apply`, called once per styled span). Pattern taken
|
|
39
|
+
* from ansis's nested-style resolver.
|
|
40
|
+
*
|
|
41
|
+
* @internal
|
|
42
|
+
*/
|
|
43
|
+
declare function reapplyStyle(s: string, escape: string): string;
|
|
44
|
+
declare function stripAnsiBg(s: string): string;
|
|
45
|
+
declare function ansiBg(str: string, idx: number): AnsiColor | undefined;
|
|
46
|
+
//#endregion
|
|
47
|
+
export { RESET, WrapOpts, ansiBg, ansiColor, hyperlink, openAnsi, reapplyStyle, stripAnsiBg, styleAnsi };
|
|
48
|
+
//# sourceMappingURL=ansi.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ansi.d.mts","names":[],"sources":["../src/style/ansi.ts"],"mappings":";;;;UAQiB;EACf;;cAQW;;;;;;;;;;;;;;iBA2DG,UAAU,aAAa;iBAKvB,UAAU,OAAO,WAAW;iBA4B5B,SAAS,OAAO;iBAWhB,UAAU,cAAc,QAAQ;;;;;;;;;;;;;;;;;;iBAwBhC,aAAa,WAAW;iBAexB,YAAY;iBAgCZ,OAAO,aAAa,cAAc"}
|
package/dist/ansi.mjs
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { P as RenderCtx, Z as StyleState, f as BaseEvents, nt as Reactive, p as Node, rt as Ref } from "./queries-DH3bj74K.mjs";
|
|
2
|
+
import { t as Input } from "./input-B5Vy-iaa.mjs";
|
|
3
|
+
import { n as SearchOptions, t as SearchItems } from "./search-FvGnswRl.mjs";
|
|
4
|
+
import { i as Select, n as OptionRender, t as Option } from "./select-CbmAZdpt.mjs";
|
|
5
|
+
//#region src/widgets/autocomplete.d.ts
|
|
6
|
+
/** Called when the user picks `item` from this source. Return a string
|
|
7
|
+
* to insert in place of the trigger + query range, or `undefined`
|
|
8
|
+
* when the source handled the selection itself (dispatched an action,
|
|
9
|
+
* opened a modal, …) and the trigger range should just be removed. */
|
|
10
|
+
type AcceptFn<T> = (item: T, query: string) => string | undefined;
|
|
11
|
+
/** Single completion source. `triggers` are regexes run against the text
|
|
12
|
+
* *before the cursor*; the first regex whose match ends in the trailing
|
|
13
|
+
* word wins. The slice between match-end and the cursor becomes the
|
|
14
|
+
* `query` passed to `complete`.
|
|
15
|
+
*
|
|
16
|
+
* `complete` receives a `match` helper bound to `query` — call it on
|
|
17
|
+
* whatever string the source considers the matching field (action id,
|
|
18
|
+
* file basename, contact email, etc.) and either filter or rank.
|
|
19
|
+
*
|
|
20
|
+
* `accept` controls what happens on selection. Default: insert
|
|
21
|
+
* `item.value + " "`. Return `undefined` to have the source do its own
|
|
22
|
+
* side effect (dispatch an action, open a picker, …) and just clear
|
|
23
|
+
* the trigger range in the input.
|
|
24
|
+
*
|
|
25
|
+
* `render` is forwarded to the internal `Menu` so the source can carry
|
|
26
|
+
* its own row presentation — handy when `T` isn't a plain `MenuItem`. */
|
|
27
|
+
interface CompletionSource<T extends Option = Option> {
|
|
28
|
+
triggers: readonly RegExp[];
|
|
29
|
+
complete: Reactive<SearchItems<T>>;
|
|
30
|
+
accept?: AcceptFn<T>;
|
|
31
|
+
render?: OptionRender<T>;
|
|
32
|
+
}
|
|
33
|
+
interface AutocompleteState extends StyleState {}
|
|
34
|
+
interface AutocompleteOptions extends SearchOptions {
|
|
35
|
+
/** The `Input` to watch. Pass the node directly, or a `Ref<Input>`
|
|
36
|
+
* populated by `node.ref(ref)` elsewhere in the tree — the latter
|
|
37
|
+
* enables fully inline composition where the input doesn't need a
|
|
38
|
+
* local binding. The ref is dereferenced on mount, so wiring is
|
|
39
|
+
* type-safe and ordering-flexible (autocomplete can be constructed
|
|
40
|
+
* before the Input is). */
|
|
41
|
+
input: Input | Ref<Input>;
|
|
42
|
+
sources: Record<string, CompletionSource<any>>;
|
|
43
|
+
/** Cap on rows the popup shows at once. Default: 8. */
|
|
44
|
+
maxHeight?: Reactive<number>;
|
|
45
|
+
enabled?: Reactive<boolean>;
|
|
46
|
+
reverse?: boolean;
|
|
47
|
+
}
|
|
48
|
+
interface AutocompleteEvents extends BaseEvents {
|
|
49
|
+
/** Fired after an item is inserted into the input. Payload item type
|
|
50
|
+
* is `unknown` because sources may have different `T`; discriminate
|
|
51
|
+
* by source name and cast. */
|
|
52
|
+
complete: {
|
|
53
|
+
source: string;
|
|
54
|
+
item: Option;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Autocomplete popup bound to an `Input`. Watches the input's value and
|
|
59
|
+
* cursor; when one of the configured sources' trigger regexes matches
|
|
60
|
+
* the text before the cursor, the source's `complete(query)` is called
|
|
61
|
+
* and the resulting items are shown in a `Menu` child.
|
|
62
|
+
*
|
|
63
|
+
* Selecting an item replaces the matched trigger-prefix + query with
|
|
64
|
+
* the item's `value` and fires `"complete"` for apps that want to react
|
|
65
|
+
* beyond plain text insertion.
|
|
66
|
+
*
|
|
67
|
+
* ```ts
|
|
68
|
+
* autocomplete({
|
|
69
|
+
* input: "chat-input",
|
|
70
|
+
* sources: {
|
|
71
|
+
* slash: {
|
|
72
|
+
* triggers: [/^\s*\//],
|
|
73
|
+
* complete: (q) => slashCommands.filter((c) => c.startsWith(q)),
|
|
74
|
+
* },
|
|
75
|
+
* },
|
|
76
|
+
* }).on("complete", (src, item) => { ... })
|
|
77
|
+
* ```
|
|
78
|
+
*
|
|
79
|
+
* Positioning is layout-based — place the `Autocomplete` in your tree
|
|
80
|
+
* (typically directly above the input inside the UI footer) and it
|
|
81
|
+
* takes as many rows as it has items (up to `maxHeight`). When no
|
|
82
|
+
* source matches, `visible` flips to `false` and the widget takes
|
|
83
|
+
* zero rows, so the footer naturally collapses.
|
|
84
|
+
*/
|
|
85
|
+
declare class Autocomplete extends Node<AutocompleteState, AutocompleteEvents> {
|
|
86
|
+
#private;
|
|
87
|
+
static readonly type = "autocomplete";
|
|
88
|
+
readonly type = "autocomplete";
|
|
89
|
+
readonly select: Select;
|
|
90
|
+
constructor(opts: AutocompleteOptions);
|
|
91
|
+
get enabled(): boolean;
|
|
92
|
+
protected _render(ctx: RenderCtx): string[] | Promise<string[]>;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Factory for `Autocomplete`. See the class doc for the full API.
|
|
96
|
+
*/
|
|
97
|
+
declare function autocomplete(opts: AutocompleteOptions): Autocomplete;
|
|
98
|
+
//#endregion
|
|
99
|
+
export { AutocompleteState as a, AutocompleteOptions as i, Autocomplete as n, CompletionSource as o, AutocompleteEvents as r, autocomplete as s, AcceptFn as t };
|
|
100
|
+
//# sourceMappingURL=autocomplete-Dfw-yQDa.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autocomplete-Dfw-yQDa.d.mts","names":[],"sources":["../src/widgets/autocomplete.ts"],"mappings":";;;;;;;;;KAgBY,SAAS,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;UAkBnB,iBAAiB,UAAU,SAAS;EACnD,mBAAmB;EACnB,UAAU,SAAS,YAAY;EAC/B,SAAS,SAAS;EAClB,SAAS,aAAa;;UAIP,0BAA0B;UAE1B,4BAA4B;;;;;;;EAO3C,OAAO,QAAQ,IAAI;EAMnB,SAAS,eAAe;;EAExB,YAAY;EACZ,UAAU;EACV;;UAGe,2BAA2B;;;;EAI1C;IAAY;IAAgB,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA6CvB,qBAAqB,KAAK,mBAAmB;;kBACxC;WACE;WAET,QAAQ;EAKjB,YAAY,MAAM;MAoDd;YAiFM,QAAQ,KAAK,uBAAuB;;;;;iBAmBhC,aAAa,MAAM,sBAAsB"}
|