@singapore-editor/plugin-ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +27 -0
  2. package/dist/anchoredSurface.d.ts +48 -0
  3. package/dist/anchoredSurface.d.ts.map +1 -0
  4. package/dist/anchoredSurface.js +140 -0
  5. package/dist/anchoredSurface.js.map +1 -0
  6. package/dist/codeTokens.d.ts +24 -0
  7. package/dist/codeTokens.d.ts.map +1 -0
  8. package/dist/codeTokens.js +78 -0
  9. package/dist/codeTokens.js.map +1 -0
  10. package/dist/hoverController.d.ts +30 -0
  11. package/dist/hoverController.d.ts.map +1 -0
  12. package/dist/hoverController.js +277 -0
  13. package/dist/hoverController.js.map +1 -0
  14. package/dist/hoverParticipant.d.ts +48 -0
  15. package/dist/hoverParticipant.d.ts.map +1 -0
  16. package/dist/hoverParticipant.js +2 -0
  17. package/dist/hoverPlugin.d.ts +14 -0
  18. package/dist/hoverPlugin.d.ts.map +1 -0
  19. package/dist/hoverPlugin.js +49 -0
  20. package/dist/hoverPlugin.js.map +1 -0
  21. package/dist/hoverRegistry.d.ts +7 -0
  22. package/dist/hoverRegistry.d.ts.map +1 -0
  23. package/dist/hoverRegistry.js +24 -0
  24. package/dist/hoverRegistry.js.map +1 -0
  25. package/dist/hoverToken.d.ts +9 -0
  26. package/dist/hoverToken.d.ts.map +1 -0
  27. package/dist/hoverToken.js +17 -0
  28. package/dist/hoverToken.js.map +1 -0
  29. package/dist/index.d.ts +11 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +11 -0
  32. package/dist/markdownTooltip.d.ts +12 -0
  33. package/dist/markdownTooltip.d.ts.map +1 -0
  34. package/dist/markdownTooltip.js +282 -0
  35. package/dist/markdownTooltip.js.map +1 -0
  36. package/dist/offsetRange.d.ts +24 -0
  37. package/dist/offsetRange.d.ts.map +1 -0
  38. package/dist/offsetRange.js +81 -0
  39. package/dist/offsetRange.js.map +1 -0
  40. package/dist/styles.d.ts +13 -0
  41. package/dist/styles.d.ts.map +1 -0
  42. package/dist/styles.js +39 -0
  43. package/dist/styles.js.map +1 -0
  44. package/dist/tooltip.d.ts +71 -0
  45. package/dist/tooltip.d.ts.map +1 -0
  46. package/dist/tooltip.js +786 -0
  47. package/dist/tooltip.js.map +1 -0
  48. package/package.json +100 -0
@@ -0,0 +1,282 @@
1
+ import { paintCodeTokens } from "./codeTokens.js";
2
+ import { applyEditorTheme } from "@singapore-editor/core/rendering";
3
+ import remarkGfm from "remark-gfm";
4
+ import remarkParse from "remark-parse";
5
+ import remarkStringify from "remark-stringify";
6
+ import { unified } from "unified";
7
+ //#region src/markdownTooltip.ts
8
+ var createMarkdownParser = () => unified().use(remarkParse).use(remarkGfm);
9
+ var createMarkdownStringifier = () => unified().use(remarkParse).use(remarkGfm).use(remarkStringify);
10
+ var parseProcessor = null;
11
+ var stringifyProcessor = null;
12
+ function markdownParser() {
13
+ parseProcessor ??= createMarkdownParser();
14
+ return parseProcessor;
15
+ }
16
+ function markdownStringifier() {
17
+ stringifyProcessor ??= createMarkdownStringifier();
18
+ return stringifyProcessor;
19
+ }
20
+ function normalizeTooltipMarkdown(markdown) {
21
+ return String(markdownStringifier().processSync(markdown));
22
+ }
23
+ /** The fenced blocks a render of this Markdown would ask tokens for. */
24
+ function tooltipCodeBlocks(markdown) {
25
+ const blocks = [];
26
+ collectCodeBlocks(markdownParser().parse(markdown), blocks);
27
+ return blocks;
28
+ }
29
+ function collectCodeBlocks(node, blocks) {
30
+ const languageId = codeLanguage(node.lang);
31
+ if (node.type === "code" && languageId) blocks.push({
32
+ text: stringValue(node.value),
33
+ languageId
34
+ });
35
+ for (const child of node.children ?? []) collectCodeBlocks(child, blocks);
36
+ }
37
+ function codeLanguage(lang) {
38
+ return typeof lang === "string" ? lang.toLowerCase() : "";
39
+ }
40
+ function renderTooltipMarkdown(document, markdown, theme, options = {}) {
41
+ const context = tooltipMarkdownRenderContext(options);
42
+ const root = document.createElement("div");
43
+ root.className = tooltipClassName(context.classNamespace, "markdown");
44
+ applyEditorTheme(root, theme);
45
+ applyCodeBackgroundVariables(root, options, context);
46
+ applyStyles(root, { display: "block" });
47
+ appendChildren(root, document, markdownParser().parse(markdown).children ?? [], context);
48
+ return root;
49
+ }
50
+ function tooltipMarkdownRenderContext(options) {
51
+ const classNamespace = options.classNamespace ?? "plugin";
52
+ return {
53
+ classNamespace,
54
+ codeTokenizer: options.codeTokenizer ?? null,
55
+ inlineCodeBackgroundVariable: `--editor-${classNamespace}-hover-inline-code-background`,
56
+ codeBlockBackgroundVariable: `--editor-${classNamespace}-hover-code-block-background`
57
+ };
58
+ }
59
+ function tooltipClassName(classNamespace, part) {
60
+ return `editor-${classNamespace}-hover-${part}`;
61
+ }
62
+ function appendChildren(parent, document, children, context) {
63
+ for (const child of children) appendNode(parent, document, child, context);
64
+ }
65
+ function appendNode(parent, document, node, context) {
66
+ const rendered = renderNode(document, node, context);
67
+ if (rendered) {
68
+ parent.appendChild(rendered);
69
+ return;
70
+ }
71
+ appendChildren(parent, document, node.children ?? [], context);
72
+ }
73
+ function renderNode(document, node, context) {
74
+ if (node.type === "text") return document.createTextNode(stringValue(node.value));
75
+ if (node.type === "paragraph") return parentElement(document, "p", node, context);
76
+ if (node.type === "inlineCode") return inlineCodeElement(document, stringValue(node.value), context);
77
+ if (node.type === "code") return codeBlockElement(document, stringValue(node.value), node.lang, context);
78
+ if (node.type === "break") return document.createElement("br");
79
+ if (node.type === "emphasis") return parentElement(document, "em", node, context);
80
+ if (node.type === "strong") return parentElement(document, "strong", node, context);
81
+ if (node.type === "delete") return parentElement(document, "del", node, context);
82
+ if (node.type === "link") return linkElement(document, node, context);
83
+ if (node.type === "list") return listElement(document, node, context);
84
+ if (node.type === "listItem") return listItemElement(document, node, context);
85
+ if (node.type === "table") return tableElement(document, node, context);
86
+ if (node.type === "heading") return headingElement(document, node, context);
87
+ if (node.type === "blockquote") return blockquoteElement(document, node, context);
88
+ if (node.type === "thematicBreak") return document.createElement("hr");
89
+ if (node.type === "html") return document.createTextNode(stringValue(node.value));
90
+ return fallbackNode(document, node, context);
91
+ }
92
+ function parentElement(document, tagName, node, context) {
93
+ const element = document.createElement(tagName);
94
+ appendChildren(element, document, node.children ?? [], context);
95
+ return element;
96
+ }
97
+ function inlineCodeElement(document, value, context) {
98
+ const element = document.createElement("code");
99
+ element.textContent = value;
100
+ applyStyles(element, {
101
+ padding: "1px 4px",
102
+ borderRadius: "4px",
103
+ background: `var(${context.inlineCodeBackgroundVariable}, transparent)`,
104
+ color: "var(--editor-foreground, #f4f4f5)",
105
+ font: "12px/1.4 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace"
106
+ });
107
+ return element;
108
+ }
109
+ function codeBlockElement(document, value, lang, context) {
110
+ const pre = document.createElement("pre");
111
+ const code = document.createElement("code");
112
+ const language = codeLanguage(lang);
113
+ renderCodeContent(document, code, value, language, context);
114
+ if (language) code.dataset.language = language;
115
+ applyStyles(pre, {
116
+ margin: "0",
117
+ padding: "0",
118
+ borderRadius: "5px",
119
+ background: `var(${context.codeBlockBackgroundVariable}, transparent)`,
120
+ color: "var(--editor-foreground, #f4f4f5)",
121
+ boxSizing: "border-box",
122
+ maxWidth: "100%",
123
+ overflow: "hidden"
124
+ });
125
+ applyStyles(code, {
126
+ display: "block",
127
+ font: "12px/1.45 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
128
+ whiteSpace: "pre-wrap",
129
+ overflowWrap: "break-word"
130
+ });
131
+ pre.append(code);
132
+ return pre;
133
+ }
134
+ function applyCodeBackgroundVariables(element, options, context) {
135
+ if (!options.codeBackground) return;
136
+ element.style.setProperty(context.inlineCodeBackgroundVariable, "color-mix(in srgb, var(--editor-foreground, #a1a1aa) 16%, transparent)");
137
+ element.style.setProperty(context.codeBlockBackgroundVariable, "color-mix(in srgb, var(--editor-background, #09090b) 88%, var(--editor-foreground, #f4f4f5) 12%)");
138
+ }
139
+ function renderCodeContent(document, code, value, language, context) {
140
+ code.textContent = value;
141
+ const tokenizer = context.codeTokenizer;
142
+ if (!tokenizer || !language) return;
143
+ const cached = tokenizer.cached(value, language);
144
+ if (cached) return paintCodeTokens(document, code, value, cached);
145
+ tokenizer.tokenize(value, language).then((tokens) => paintCodeTokens(document, code, value, tokens));
146
+ }
147
+ function linkElement(document, node, context) {
148
+ const href = safeLinkHref(node.url);
149
+ if (!href) return parentElement(document, "span", node, context);
150
+ const element = document.createElement("a");
151
+ element.href = href;
152
+ element.target = "_blank";
153
+ element.rel = "noreferrer";
154
+ applyStyles(element, {
155
+ color: "var(--editor-caret-color, #93c5fd)",
156
+ textDecoration: "underline"
157
+ });
158
+ appendChildren(element, document, node.children ?? [], context);
159
+ return element;
160
+ }
161
+ function listElement(document, node, context) {
162
+ const element = document.createElement(node.ordered === true ? "ol" : "ul");
163
+ applyStyles(element, {
164
+ margin: "0",
165
+ paddingLeft: "18px"
166
+ });
167
+ appendChildren(element, document, node.children ?? [], context);
168
+ return element;
169
+ }
170
+ function listItemElement(document, node, context) {
171
+ const element = document.createElement("li");
172
+ if (typeof node.checked === "boolean") element.append(taskCheckbox(document, node.checked));
173
+ appendChildren(element, document, node.children ?? [], context);
174
+ return element;
175
+ }
176
+ function taskCheckbox(document, checked) {
177
+ const input = document.createElement("input");
178
+ input.type = "checkbox";
179
+ input.checked = checked;
180
+ input.disabled = true;
181
+ input.tabIndex = -1;
182
+ applyStyles(input, {
183
+ margin: "0 6px 0 0",
184
+ verticalAlign: "-1px"
185
+ });
186
+ return input;
187
+ }
188
+ function tableElement(document, node, context) {
189
+ const table = document.createElement("table");
190
+ const rows = node.children ?? [];
191
+ applyStyles(table, {
192
+ borderCollapse: "collapse",
193
+ fontSize: "12px"
194
+ });
195
+ appendTableHead(table, document, rows[0] ?? null, node.align ?? [], context);
196
+ appendTableBody(table, document, rows.slice(1), node.align ?? [], context);
197
+ return table;
198
+ }
199
+ function appendTableHead(table, document, row, align, context) {
200
+ if (!row) return;
201
+ const head = document.createElement("thead");
202
+ head.append(tableRowElement(document, row, "th", align, context));
203
+ table.append(head);
204
+ }
205
+ function appendTableBody(table, document, rows, align, context) {
206
+ if (rows.length === 0) return;
207
+ const body = document.createElement("tbody");
208
+ for (const row of rows) body.append(tableRowElement(document, row, "td", align, context));
209
+ table.append(body);
210
+ }
211
+ function tableRowElement(document, row, cellTagName, align, context) {
212
+ const element = document.createElement("tr");
213
+ const cells = row.children ?? [];
214
+ for (let index = 0; index < cells.length; index += 1) element.append(tableCellElement(document, cells[index], cellTagName, align[index], context));
215
+ return element;
216
+ }
217
+ function tableCellElement(document, node, tagName, align, context) {
218
+ const element = document.createElement(tagName);
219
+ applyStyles(element, {
220
+ padding: "3px 7px",
221
+ border: "1px solid color-mix(in srgb, var(--editor-foreground, #a1a1aa) 22%, transparent)",
222
+ textAlign: tableTextAlign(align)
223
+ });
224
+ appendChildren(element, document, node.children ?? [], context);
225
+ return element;
226
+ }
227
+ function headingElement(document, node, context) {
228
+ const element = parentElement(document, "div", node, context);
229
+ element.setAttribute("role", "heading");
230
+ element.setAttribute("aria-level", String(headingDepth(node.depth)));
231
+ applyStyles(element, { fontWeight: "650" });
232
+ return element;
233
+ }
234
+ function blockquoteElement(document, node, context) {
235
+ const element = parentElement(document, "blockquote", node, context);
236
+ applyStyles(element, {
237
+ margin: "0",
238
+ paddingLeft: "10px",
239
+ borderLeft: "2px solid color-mix(in srgb, var(--editor-foreground, #a1a1aa) 46%, transparent)",
240
+ color: "color-mix(in srgb, var(--editor-foreground, #d4d4d8) 86%, transparent)"
241
+ });
242
+ return element;
243
+ }
244
+ function fallbackNode(document, node, context) {
245
+ if (typeof node.value === "string") return document.createTextNode(node.value);
246
+ if (!node.children || node.children.length === 0) return null;
247
+ const element = document.createElement("span");
248
+ appendChildren(element, document, node.children, context);
249
+ return element;
250
+ }
251
+ function safeLinkHref(url) {
252
+ if (typeof url !== "string") return null;
253
+ try {
254
+ const parsed = new URL(url);
255
+ if (parsed.protocol === "http:" || parsed.protocol === "https:") return parsed.href;
256
+ if (parsed.protocol === "mailto:") return parsed.href;
257
+ return null;
258
+ } catch {
259
+ return null;
260
+ }
261
+ }
262
+ function tableTextAlign(align) {
263
+ if (align === "left" || align === "right" || align === "center") return align;
264
+ return "left";
265
+ }
266
+ function headingDepth(depth) {
267
+ if (typeof depth !== "number") return 2;
268
+ return Math.min(6, Math.max(1, Math.trunc(depth)));
269
+ }
270
+ function stringValue(value) {
271
+ return typeof value === "string" ? value : "";
272
+ }
273
+ function applyStyles(element, styles) {
274
+ for (const [property, value] of Object.entries(styles)) element.style.setProperty(cssPropertyName(property), value);
275
+ }
276
+ function cssPropertyName(property) {
277
+ return property.replace(/[A-Z]/g, (character) => `-${character.toLowerCase()}`);
278
+ }
279
+ //#endregion
280
+ export { normalizeTooltipMarkdown, renderTooltipMarkdown, tooltipCodeBlocks };
281
+
282
+ //# sourceMappingURL=markdownTooltip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdownTooltip.js","names":[],"sources":["../src/markdownTooltip.ts"],"sourcesContent":["import { applyEditorTheme, type EditorTheme } from '@singapore-editor/core/rendering'\nimport remarkGfm from 'remark-gfm'\nimport remarkParse from 'remark-parse'\nimport remarkStringify from 'remark-stringify'\nimport { unified } from 'unified'\n\nimport { paintCodeTokens, type TooltipCodeBlock, type TooltipCodeTokenizer } from './codeTokens'\n\ntype MarkdownNode = {\n readonly type: string\n readonly value?: unknown\n readonly children?: readonly MarkdownNode[]\n readonly lang?: unknown\n readonly url?: unknown\n readonly ordered?: unknown\n readonly checked?: unknown\n readonly depth?: unknown\n readonly align?: readonly (string | null | undefined)[]\n}\n\nexport type TooltipMarkdownRenderOptions = {\n readonly codeBackground?: boolean\n readonly classNamespace?: string\n readonly codeTokenizer?: TooltipCodeTokenizer | null\n}\n\ntype TooltipMarkdownRenderContext = {\n readonly classNamespace: string\n readonly codeTokenizer: TooltipCodeTokenizer | null\n readonly inlineCodeBackgroundVariable: string\n readonly codeBlockBackgroundVariable: string\n}\n\n// Built on first use, not at import: a host that never shows a markdown hover\n// should not pay for two unified pipelines while it boots.\nconst createMarkdownParser = () => unified().use(remarkParse).use(remarkGfm)\nconst createMarkdownStringifier = () =>\n unified().use(remarkParse).use(remarkGfm).use(remarkStringify)\n\nlet parseProcessor: ReturnType<typeof createMarkdownParser> | null = null\nlet stringifyProcessor: ReturnType<typeof createMarkdownStringifier> | null = null\n\nfunction markdownParser() {\n parseProcessor ??= createMarkdownParser()\n return parseProcessor\n}\n\nfunction markdownStringifier() {\n stringifyProcessor ??= createMarkdownStringifier()\n return stringifyProcessor\n}\n\nexport function normalizeTooltipMarkdown(markdown: string): string {\n return String(markdownStringifier().processSync(markdown))\n}\n\n/** The fenced blocks a render of this Markdown would ask tokens for. */\nexport function tooltipCodeBlocks(markdown: string): readonly TooltipCodeBlock[] {\n const blocks: TooltipCodeBlock[] = []\n collectCodeBlocks(markdownParser().parse(markdown) as MarkdownNode, blocks)\n return blocks\n}\n\nfunction collectCodeBlocks(node: MarkdownNode, blocks: TooltipCodeBlock[]): void {\n const languageId = codeLanguage(node.lang)\n if (node.type === 'code' && languageId) blocks.push({ text: stringValue(node.value), languageId })\n for (const child of node.children ?? []) collectCodeBlocks(child, blocks)\n}\n\nfunction codeLanguage(lang: unknown): string {\n return typeof lang === 'string' ? lang.toLowerCase() : ''\n}\n\nexport function renderTooltipMarkdown(\n document: Document,\n markdown: string,\n theme?: EditorTheme | null,\n options: TooltipMarkdownRenderOptions = {},\n): HTMLElement {\n const context = tooltipMarkdownRenderContext(options)\n const root = document.createElement('div')\n root.className = tooltipClassName(context.classNamespace, 'markdown')\n applyEditorTheme(root, theme)\n applyCodeBackgroundVariables(root, options, context)\n applyStyles(root, {\n display: 'block',\n })\n\n const tree = markdownParser().parse(markdown) as MarkdownNode\n appendChildren(root, document, tree.children ?? [], context)\n return root\n}\n\nfunction tooltipMarkdownRenderContext(\n options: TooltipMarkdownRenderOptions,\n): TooltipMarkdownRenderContext {\n const classNamespace = options.classNamespace ?? 'plugin'\n return {\n classNamespace,\n codeTokenizer: options.codeTokenizer ?? null,\n inlineCodeBackgroundVariable: `--editor-${classNamespace}-hover-inline-code-background`,\n codeBlockBackgroundVariable: `--editor-${classNamespace}-hover-code-block-background`,\n }\n}\n\nfunction tooltipClassName(classNamespace: string, part: string): string {\n return `editor-${classNamespace}-hover-${part}`\n}\n\nfunction appendChildren(\n parent: Node,\n document: Document,\n children: readonly MarkdownNode[],\n context: TooltipMarkdownRenderContext,\n): void {\n for (const child of children) appendNode(parent, document, child, context)\n}\n\nfunction appendNode(\n parent: Node,\n document: Document,\n node: MarkdownNode,\n context: TooltipMarkdownRenderContext,\n): void {\n const rendered = renderNode(document, node, context)\n if (rendered) {\n parent.appendChild(rendered)\n return\n }\n\n appendChildren(parent, document, node.children ?? [], context)\n}\n\nfunction renderNode(\n document: Document,\n node: MarkdownNode,\n context: TooltipMarkdownRenderContext,\n): Node | null {\n if (node.type === 'text') return document.createTextNode(stringValue(node.value))\n if (node.type === 'paragraph') return parentElement(document, 'p', node, context)\n if (node.type === 'inlineCode')\n return inlineCodeElement(document, stringValue(node.value), context)\n if (node.type === 'code')\n return codeBlockElement(document, stringValue(node.value), node.lang, context)\n if (node.type === 'break') return document.createElement('br')\n if (node.type === 'emphasis') return parentElement(document, 'em', node, context)\n if (node.type === 'strong') return parentElement(document, 'strong', node, context)\n if (node.type === 'delete') return parentElement(document, 'del', node, context)\n if (node.type === 'link') return linkElement(document, node, context)\n if (node.type === 'list') return listElement(document, node, context)\n if (node.type === 'listItem') return listItemElement(document, node, context)\n if (node.type === 'table') return tableElement(document, node, context)\n if (node.type === 'heading') return headingElement(document, node, context)\n if (node.type === 'blockquote') return blockquoteElement(document, node, context)\n if (node.type === 'thematicBreak') return document.createElement('hr')\n if (node.type === 'html') return document.createTextNode(stringValue(node.value))\n return fallbackNode(document, node, context)\n}\n\nfunction parentElement<K extends keyof HTMLElementTagNameMap>(\n document: Document,\n tagName: K,\n node: MarkdownNode,\n context: TooltipMarkdownRenderContext,\n): HTMLElementTagNameMap[K] {\n const element = document.createElement(tagName)\n appendChildren(element, document, node.children ?? [], context)\n return element\n}\n\nfunction inlineCodeElement(\n document: Document,\n value: string,\n context: TooltipMarkdownRenderContext,\n): HTMLElement {\n const element = document.createElement('code')\n element.textContent = value\n applyStyles(element, {\n padding: '1px 4px',\n borderRadius: '4px',\n background: `var(${context.inlineCodeBackgroundVariable}, transparent)`,\n color: 'var(--editor-foreground, #f4f4f5)',\n font: '12px/1.4 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace',\n })\n return element\n}\n\nfunction codeBlockElement(\n document: Document,\n value: string,\n lang: unknown,\n context: TooltipMarkdownRenderContext,\n): HTMLElement {\n const pre = document.createElement('pre')\n const code = document.createElement('code')\n const language = codeLanguage(lang)\n renderCodeContent(document, code, value, language, context)\n if (language) code.dataset.language = language\n\n applyStyles(pre, {\n margin: '0',\n padding: '0',\n borderRadius: '5px',\n background: `var(${context.codeBlockBackgroundVariable}, transparent)`,\n color: 'var(--editor-foreground, #f4f4f5)',\n boxSizing: 'border-box',\n maxWidth: '100%',\n overflow: 'hidden',\n })\n applyStyles(code, {\n display: 'block',\n font: '12px/1.45 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace',\n whiteSpace: 'pre-wrap',\n overflowWrap: 'break-word',\n })\n\n pre.append(code)\n return pre\n}\n\nfunction applyCodeBackgroundVariables(\n element: HTMLElement,\n options: TooltipMarkdownRenderOptions,\n context: TooltipMarkdownRenderContext,\n): void {\n if (!options.codeBackground) return\n\n element.style.setProperty(\n context.inlineCodeBackgroundVariable,\n 'color-mix(in srgb, var(--editor-foreground, #a1a1aa) 16%, transparent)',\n )\n element.style.setProperty(\n context.codeBlockBackgroundVariable,\n 'color-mix(in srgb, var(--editor-background, #09090b) 88%, var(--editor-foreground, #f4f4f5) 12%)',\n )\n}\n\nfunction renderCodeContent(\n document: Document,\n code: HTMLElement,\n value: string,\n language: string,\n context: TooltipMarkdownRenderContext,\n): void {\n code.textContent = value\n const tokenizer = context.codeTokenizer\n if (!tokenizer || !language) return\n\n const cached = tokenizer.cached(value, language)\n if (cached) return paintCodeTokens(document, code, value, cached)\n\n // Reached only when the hold ran out. Colour only, so the block keeps its size.\n void tokenizer\n .tokenize(value, language)\n .then((tokens) => paintCodeTokens(document, code, value, tokens))\n}\n\nfunction linkElement(\n document: Document,\n node: MarkdownNode,\n context: TooltipMarkdownRenderContext,\n): HTMLElement {\n const href = safeLinkHref(node.url)\n if (!href) return parentElement(document, 'span', node, context)\n\n const element = document.createElement('a')\n element.href = href\n element.target = '_blank'\n element.rel = 'noreferrer'\n applyStyles(element, {\n color: 'var(--editor-caret-color, #93c5fd)',\n textDecoration: 'underline',\n })\n appendChildren(element, document, node.children ?? [], context)\n return element\n}\n\nfunction listElement(\n document: Document,\n node: MarkdownNode,\n context: TooltipMarkdownRenderContext,\n): HTMLElement {\n const element = document.createElement(node.ordered === true ? 'ol' : 'ul')\n applyStyles(element, {\n margin: '0',\n paddingLeft: '18px',\n })\n appendChildren(element, document, node.children ?? [], context)\n return element\n}\n\nfunction listItemElement(\n document: Document,\n node: MarkdownNode,\n context: TooltipMarkdownRenderContext,\n): HTMLElement {\n const element = document.createElement('li')\n if (typeof node.checked === 'boolean') element.append(taskCheckbox(document, node.checked))\n appendChildren(element, document, node.children ?? [], context)\n return element\n}\n\nfunction taskCheckbox(document: Document, checked: boolean): HTMLInputElement {\n const input = document.createElement('input')\n input.type = 'checkbox'\n input.checked = checked\n input.disabled = true\n input.tabIndex = -1\n applyStyles(input, {\n margin: '0 6px 0 0',\n verticalAlign: '-1px',\n })\n return input\n}\n\nfunction tableElement(\n document: Document,\n node: MarkdownNode,\n context: TooltipMarkdownRenderContext,\n): HTMLElement {\n const table = document.createElement('table')\n const rows = node.children ?? []\n applyStyles(table, {\n borderCollapse: 'collapse',\n fontSize: '12px',\n })\n appendTableHead(table, document, rows[0] ?? null, node.align ?? [], context)\n appendTableBody(table, document, rows.slice(1), node.align ?? [], context)\n return table\n}\n\nfunction appendTableHead(\n table: HTMLTableElement,\n document: Document,\n row: MarkdownNode | null,\n align: readonly (string | null | undefined)[],\n context: TooltipMarkdownRenderContext,\n): void {\n if (!row) return\n\n const head = document.createElement('thead')\n head.append(tableRowElement(document, row, 'th', align, context))\n table.append(head)\n}\n\nfunction appendTableBody(\n table: HTMLTableElement,\n document: Document,\n rows: readonly MarkdownNode[],\n align: readonly (string | null | undefined)[],\n context: TooltipMarkdownRenderContext,\n): void {\n if (rows.length === 0) return\n\n const body = document.createElement('tbody')\n for (const row of rows) body.append(tableRowElement(document, row, 'td', align, context))\n table.append(body)\n}\n\nfunction tableRowElement(\n document: Document,\n row: MarkdownNode,\n cellTagName: 'td' | 'th',\n align: readonly (string | null | undefined)[],\n context: TooltipMarkdownRenderContext,\n): HTMLTableRowElement {\n const element = document.createElement('tr')\n const cells = row.children ?? []\n for (let index = 0; index < cells.length; index += 1) {\n element.append(tableCellElement(document, cells[index]!, cellTagName, align[index], context))\n }\n return element\n}\n\nfunction tableCellElement(\n document: Document,\n node: MarkdownNode,\n tagName: 'td' | 'th',\n align: string | null | undefined,\n context: TooltipMarkdownRenderContext,\n): HTMLTableCellElement {\n const element = document.createElement(tagName)\n applyStyles(element, {\n padding: '3px 7px',\n border: '1px solid color-mix(in srgb, var(--editor-foreground, #a1a1aa) 22%, transparent)',\n textAlign: tableTextAlign(align),\n })\n appendChildren(element, document, node.children ?? [], context)\n return element\n}\n\nfunction headingElement(\n document: Document,\n node: MarkdownNode,\n context: TooltipMarkdownRenderContext,\n): HTMLElement {\n const element = parentElement(document, 'div', node, context)\n element.setAttribute('role', 'heading')\n element.setAttribute('aria-level', String(headingDepth(node.depth)))\n applyStyles(element, {\n fontWeight: '650',\n })\n return element\n}\n\nfunction blockquoteElement(\n document: Document,\n node: MarkdownNode,\n context: TooltipMarkdownRenderContext,\n): HTMLElement {\n const element = parentElement(document, 'blockquote', node, context)\n applyStyles(element, {\n margin: '0',\n paddingLeft: '10px',\n borderLeft: '2px solid color-mix(in srgb, var(--editor-foreground, #a1a1aa) 46%, transparent)',\n color: 'color-mix(in srgb, var(--editor-foreground, #d4d4d8) 86%, transparent)',\n })\n return element\n}\n\nfunction fallbackNode(\n document: Document,\n node: MarkdownNode,\n context: TooltipMarkdownRenderContext,\n): Node | null {\n if (typeof node.value === 'string') return document.createTextNode(node.value)\n if (!node.children || node.children.length === 0) return null\n\n const element = document.createElement('span')\n appendChildren(element, document, node.children, context)\n return element\n}\n\nfunction safeLinkHref(url: unknown): string | null {\n if (typeof url !== 'string') return null\n\n try {\n const parsed = new URL(url)\n if (parsed.protocol === 'http:' || parsed.protocol === 'https:') return parsed.href\n if (parsed.protocol === 'mailto:') return parsed.href\n return null\n } catch {\n return null\n }\n}\n\nfunction tableTextAlign(align: string | null | undefined): string {\n if (align === 'left' || align === 'right' || align === 'center') return align\n return 'left'\n}\n\nfunction headingDepth(depth: unknown): number {\n if (typeof depth !== 'number') return 2\n return Math.min(6, Math.max(1, Math.trunc(depth)))\n}\n\nfunction stringValue(value: unknown): string {\n return typeof value === 'string' ? value : ''\n}\n\nfunction applyStyles(element: HTMLElement, styles: Readonly<Record<string, string>>): void {\n for (const [property, value] of Object.entries(styles)) {\n element.style.setProperty(cssPropertyName(property), value)\n }\n}\n\nfunction cssPropertyName(property: string): string {\n return property.replace(/[A-Z]/g, (character) => `-${character.toLowerCase()}`)\n}\n"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { TextReadSnapshot } from '@singapore-editor/core/document';
2
+ /** Half-open `[start, end)` offset range into the editor text buffer. */
3
+ export type OffsetRange = {
4
+ readonly start: number;
5
+ readonly end: number;
6
+ };
7
+ export declare function sameOffsetRange(left: OffsetRange | null, right: OffsetRange): boolean;
8
+ /** The smallest range covering every range given, or null for none. */
9
+ export declare function unionOffsetRange(ranges: readonly OffsetRange[]): OffsetRange | null;
10
+ /**
11
+ * The identifier under `offset`, or null when the offset does not sit on an identifier character.
12
+ * An identifier character is `[A-Za-z0-9_$]`, the set TypeScript's language service treats as part
13
+ * of a name; an offset one past the last character still counts, so a caret right after a name
14
+ * asks about that name.
15
+ */
16
+ export declare function identifierRangeAtOffset(text: string, offset: number): OffsetRange | null;
17
+ /** The identifier at `offset`, else the single visible character there. */
18
+ export declare function hoverTargetRange(text: string, offset: number): OffsetRange;
19
+ /**
20
+ * `hoverTargetRange` over a document source, reading a window of the offset's line rather than the
21
+ * document. The window widens only while an identifier runs into its edge.
22
+ */
23
+ export declare function hoverTargetRangeInSource(source: TextReadSnapshot, offset: number): OffsetRange;
24
+ //# sourceMappingURL=offsetRange.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"offsetRange.d.ts","sourceRoot":"","sources":["../src/offsetRange.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AAEvE,yEAAyE;AACzE,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAErF;AAED,uEAAuE;AACvE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,WAAW,GAAG,IAAI,CAUnF;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAaxF;AAED,2EAA2E;AAC3E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAM1E;AAID;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAa9F"}
@@ -0,0 +1,81 @@
1
+ //#region src/offsetRange.ts
2
+ function sameOffsetRange(left, right) {
3
+ return left?.start === right.start && left.end === right.end;
4
+ }
5
+ /** The smallest range covering every range given, or null for none. */
6
+ function unionOffsetRange(ranges) {
7
+ let union = null;
8
+ for (const range of ranges) {
9
+ if (!union) {
10
+ union = range;
11
+ continue;
12
+ }
13
+ union = {
14
+ start: Math.min(union.start, range.start),
15
+ end: Math.max(union.end, range.end)
16
+ };
17
+ }
18
+ return union;
19
+ }
20
+ /**
21
+ * The identifier under `offset`, or null when the offset does not sit on an identifier character.
22
+ * An identifier character is `[A-Za-z0-9_$]`, the set TypeScript's language service treats as part
23
+ * of a name; an offset one past the last character still counts, so a caret right after a name
24
+ * asks about that name.
25
+ */
26
+ function identifierRangeAtOffset(text, offset) {
27
+ const index = identifierIndexAtOffset(text, Math.max(0, Math.min(offset, text.length)));
28
+ if (index === null) return null;
29
+ let start = index;
30
+ while (start > 0 && isIdentifierCharacter(text[start - 1] ?? "")) start -= 1;
31
+ let end = index + 1;
32
+ while (end < text.length && isIdentifierCharacter(text[end] ?? "")) end += 1;
33
+ if (end <= start) return null;
34
+ return {
35
+ start,
36
+ end
37
+ };
38
+ }
39
+ /** The identifier at `offset`, else the single visible character there. */
40
+ function hoverTargetRange(text, offset) {
41
+ const identifier = identifierRangeAtOffset(text, offset);
42
+ if (identifier) return identifier;
43
+ const start = Math.max(0, Math.min(offset, Math.max(0, text.length - 1)));
44
+ return {
45
+ start,
46
+ end: Math.min(text.length, start + 1)
47
+ };
48
+ }
49
+ var HOVER_WINDOW_RADIUS = 256;
50
+ /**
51
+ * `hoverTargetRange` over a document source, reading a window of the offset's line rather than the
52
+ * document. The window widens only while an identifier runs into its edge.
53
+ */
54
+ function hoverTargetRangeInSource(source, offset) {
55
+ const line = source.lineRange(source.lineAt(Math.min(offset, Math.max(0, source.length - 1))));
56
+ const lineEnd = Math.min(source.length, line.end + 1);
57
+ for (let radius = HOVER_WINDOW_RADIUS;; radius *= 2) {
58
+ const from = Math.max(line.start, offset - radius);
59
+ const to = Math.min(lineEnd, Math.max(from, offset + radius));
60
+ const local = hoverTargetRange(source.readRange(from, to), offset - from);
61
+ const range = {
62
+ start: from + local.start,
63
+ end: from + local.end
64
+ };
65
+ const clippedLeft = range.start === from && from > line.start;
66
+ const clippedRight = range.end === to && to < lineEnd;
67
+ if (!clippedLeft && !clippedRight) return range;
68
+ }
69
+ }
70
+ function identifierIndexAtOffset(text, offset) {
71
+ if (isIdentifierCharacter(text[offset] ?? "")) return offset;
72
+ if (offset > 0 && isIdentifierCharacter(text[offset - 1] ?? "")) return offset - 1;
73
+ return null;
74
+ }
75
+ function isIdentifierCharacter(character) {
76
+ return /^[A-Za-z0-9_$]$/.test(character);
77
+ }
78
+ //#endregion
79
+ export { hoverTargetRange, hoverTargetRangeInSource, identifierRangeAtOffset, sameOffsetRange, unionOffsetRange };
80
+
81
+ //# sourceMappingURL=offsetRange.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"offsetRange.js","names":[],"sources":["../src/offsetRange.ts"],"sourcesContent":["import type { TextReadSnapshot } from '@singapore-editor/core/document'\n\n/** Half-open `[start, end)` offset range into the editor text buffer. */\nexport type OffsetRange = {\n readonly start: number\n readonly end: number\n}\n\nexport function sameOffsetRange(left: OffsetRange | null, right: OffsetRange): boolean {\n return left?.start === right.start && left.end === right.end\n}\n\n/** The smallest range covering every range given, or null for none. */\nexport function unionOffsetRange(ranges: readonly OffsetRange[]): OffsetRange | null {\n let union: OffsetRange | null = null\n for (const range of ranges) {\n if (!union) {\n union = range\n continue\n }\n union = { start: Math.min(union.start, range.start), end: Math.max(union.end, range.end) }\n }\n return union\n}\n\n/**\n * The identifier under `offset`, or null when the offset does not sit on an identifier character.\n * An identifier character is `[A-Za-z0-9_$]`, the set TypeScript's language service treats as part\n * of a name; an offset one past the last character still counts, so a caret right after a name\n * asks about that name.\n */\nexport function identifierRangeAtOffset(text: string, offset: number): OffsetRange | null {\n const clamped = Math.max(0, Math.min(offset, text.length))\n const index = identifierIndexAtOffset(text, clamped)\n if (index === null) return null\n\n let start = index\n while (start > 0 && isIdentifierCharacter(text[start - 1] ?? '')) start -= 1\n\n let end = index + 1\n while (end < text.length && isIdentifierCharacter(text[end] ?? '')) end += 1\n\n if (end <= start) return null\n return { start, end }\n}\n\n/** The identifier at `offset`, else the single visible character there. */\nexport function hoverTargetRange(text: string, offset: number): OffsetRange {\n const identifier = identifierRangeAtOffset(text, offset)\n if (identifier) return identifier\n\n const start = Math.max(0, Math.min(offset, Math.max(0, text.length - 1)))\n return { start, end: Math.min(text.length, start + 1) }\n}\n\nconst HOVER_WINDOW_RADIUS = 256\n\n/**\n * `hoverTargetRange` over a document source, reading a window of the offset's line rather than the\n * document. The window widens only while an identifier runs into its edge.\n */\nexport function hoverTargetRangeInSource(source: TextReadSnapshot, offset: number): OffsetRange {\n const line = source.lineRange(source.lineAt(Math.min(offset, Math.max(0, source.length - 1))))\n // One past the break, so a caret on the line break targets it as the string search did.\n const lineEnd = Math.min(source.length, line.end + 1)\n for (let radius = HOVER_WINDOW_RADIUS; ; radius *= 2) {\n const from = Math.max(line.start, offset - radius)\n const to = Math.min(lineEnd, Math.max(from, offset + radius))\n const local = hoverTargetRange(source.readRange(from, to), offset - from)\n const range = { start: from + local.start, end: from + local.end }\n const clippedLeft = range.start === from && from > line.start\n const clippedRight = range.end === to && to < lineEnd\n if (!clippedLeft && !clippedRight) return range\n }\n}\n\nfunction identifierIndexAtOffset(text: string, offset: number): number | null {\n if (isIdentifierCharacter(text[offset] ?? '')) return offset\n if (offset > 0 && isIdentifierCharacter(text[offset - 1] ?? '')) return offset - 1\n return null\n}\n\nfunction isIdentifierCharacter(character: string): boolean {\n return /^[A-Za-z0-9_$]$/.test(character)\n}\n"],"mappings":";AAQA,SAAgB,gBAAgB,MAA0B,OAA6B;CACrF,OAAO,MAAM,UAAU,MAAM,SAAS,KAAK,QAAQ,MAAM;AAC3D;;AAGA,SAAgB,iBAAiB,QAAoD;CACnF,IAAI,QAA4B;CAChC,KAAK,MAAM,SAAS,QAAQ;EAC1B,IAAI,CAAC,OAAO;GACV,QAAQ;GACR;EACF;EACA,QAAQ;GAAE,OAAO,KAAK,IAAI,MAAM,OAAO,MAAM,KAAK;GAAG,KAAK,KAAK,IAAI,MAAM,KAAK,MAAM,GAAG;EAAE;CAC3F;CACA,OAAO;AACT;;;;;;;AAQA,SAAgB,wBAAwB,MAAc,QAAoC;CAExF,MAAM,QAAQ,wBAAwB,MADtB,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,KAAK,MAAM,CACZ,CAAO;CACnD,IAAI,UAAU,MAAM,OAAO;CAE3B,IAAI,QAAQ;CACZ,OAAO,QAAQ,KAAK,sBAAsB,KAAK,QAAQ,MAAM,EAAE,GAAG,SAAS;CAE3E,IAAI,MAAM,QAAQ;CAClB,OAAO,MAAM,KAAK,UAAU,sBAAsB,KAAK,QAAQ,EAAE,GAAG,OAAO;CAE3E,IAAI,OAAO,OAAO,OAAO;CACzB,OAAO;EAAE;EAAO;CAAI;AACtB;;AAGA,SAAgB,iBAAiB,MAAc,QAA6B;CAC1E,MAAM,aAAa,wBAAwB,MAAM,MAAM;CACvD,IAAI,YAAY,OAAO;CAEvB,MAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,KAAK,IAAI,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC;CACxE,OAAO;EAAE;EAAO,KAAK,KAAK,IAAI,KAAK,QAAQ,QAAQ,CAAC;CAAE;AACxD;AAEA,IAAM,sBAAsB;;;;;AAM5B,SAAgB,yBAAyB,QAA0B,QAA6B;CAC9F,MAAM,OAAO,OAAO,UAAU,OAAO,OAAO,KAAK,IAAI,QAAQ,KAAK,IAAI,GAAG,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;CAE7F,MAAM,UAAU,KAAK,IAAI,OAAO,QAAQ,KAAK,MAAM,CAAC;CACpD,KAAK,IAAI,SAAS,sBAAuB,UAAU,GAAG;EACpD,MAAM,OAAO,KAAK,IAAI,KAAK,OAAO,SAAS,MAAM;EACjD,MAAM,KAAK,KAAK,IAAI,SAAS,KAAK,IAAI,MAAM,SAAS,MAAM,CAAC;EAC5D,MAAM,QAAQ,iBAAiB,OAAO,UAAU,MAAM,EAAE,GAAG,SAAS,IAAI;EACxE,MAAM,QAAQ;GAAE,OAAO,OAAO,MAAM;GAAO,KAAK,OAAO,MAAM;EAAI;EACjE,MAAM,cAAc,MAAM,UAAU,QAAQ,OAAO,KAAK;EACxD,MAAM,eAAe,MAAM,QAAQ,MAAM,KAAK;EAC9C,IAAI,CAAC,eAAe,CAAC,cAAc,OAAO;CAC5C;AACF;AAEA,SAAS,wBAAwB,MAAc,QAA+B;CAC5E,IAAI,sBAAsB,KAAK,WAAW,EAAE,GAAG,OAAO;CACtD,IAAI,SAAS,KAAK,sBAAsB,KAAK,SAAS,MAAM,EAAE,GAAG,OAAO,SAAS;CACjF,OAAO;AACT;AAEA,SAAS,sBAAsB,WAA4B;CACzD,OAAO,kBAAkB,KAAK,SAAS;AACzC"}
@@ -0,0 +1,13 @@
1
+ export declare const HOVER_COLORS: {
2
+ readonly background: string;
3
+ readonly foreground: string;
4
+ readonly border: string;
5
+ readonly shadow: string;
6
+ readonly separator: string;
7
+ readonly secondaryForeground: string;
8
+ readonly actionSuccess: string;
9
+ readonly actionFailure: string;
10
+ };
11
+ /** The variables the hover reads, for a surface mounted outside the editor's cascade. */
12
+ export declare const HOVER_THEME_VARIABLES: readonly ["--editor-hover-background", "--editor-hover-foreground", "--editor-hover-border", "--editor-hover-shadow", "--editor-hover-separator", "--editor-hover-secondary-foreground", "--editor-hover-action-success", "--editor-hover-action-failure"];
13
+ //# sourceMappingURL=styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,YAAY;;;;;;;;;CA8Bf,CAAA;AAEV,yFAAyF;AACzF,eAAO,MAAM,qBAAqB,4PASxB,CAAA"}
package/dist/styles.js ADDED
@@ -0,0 +1,39 @@
1
+ import { editorColorReference, registerEditorColor, transparentEditorColor } from "@singapore-editor/core/rendering";
2
+ //#region src/styles.ts
3
+ var HOVER_COLORS = {
4
+ background: registerEditorColor("hover.background", {
5
+ dark: "#252526",
6
+ light: "#f3f3f3"
7
+ }),
8
+ foreground: registerEditorColor("hover.foreground", editorColorReference("foreground")),
9
+ border: registerEditorColor("hover.border", transparentEditorColor(editorColorReference("foreground"), .28)),
10
+ shadow: registerEditorColor("hover.shadow", {
11
+ dark: "#0000005c",
12
+ light: "#00000029"
13
+ }),
14
+ separator: registerEditorColor("hover.separator", transparentEditorColor(editorColorReference("foreground"), .18)),
15
+ secondaryForeground: registerEditorColor("hover.secondaryForeground", transparentEditorColor(editorColorReference("foreground"), .72)),
16
+ actionSuccess: registerEditorColor("hover.actionSuccess", {
17
+ dark: "#86efac",
18
+ light: "#15803d"
19
+ }),
20
+ actionFailure: registerEditorColor("hover.actionFailure", {
21
+ dark: "#ef4444",
22
+ light: "#dc2626"
23
+ })
24
+ };
25
+ /** The variables the hover reads, for a surface mounted outside the editor's cascade. */
26
+ var HOVER_THEME_VARIABLES = [
27
+ "--editor-hover-background",
28
+ "--editor-hover-foreground",
29
+ "--editor-hover-border",
30
+ "--editor-hover-shadow",
31
+ "--editor-hover-separator",
32
+ "--editor-hover-secondary-foreground",
33
+ "--editor-hover-action-success",
34
+ "--editor-hover-action-failure"
35
+ ];
36
+ //#endregion
37
+ export { HOVER_COLORS, HOVER_THEME_VARIABLES };
38
+
39
+ //# sourceMappingURL=styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.js","names":[],"sources":["../src/styles.ts"],"sourcesContent":["import {\n editorColorReference,\n registerEditorColor,\n transparentEditorColor,\n} from '@singapore-editor/core/rendering'\n\n/*\n * Every colour a shared surface paints with is a registered id, so a host restyles the hover\n * through the editor theme instead of forking this package.\n */\nexport const HOVER_COLORS = {\n background: registerEditorColor('hover.background', {\n dark: '#252526',\n light: '#f3f3f3',\n }),\n foreground: registerEditorColor('hover.foreground', editorColorReference('foreground')),\n border: registerEditorColor(\n 'hover.border',\n transparentEditorColor(editorColorReference('foreground'), 0.28),\n ),\n shadow: registerEditorColor('hover.shadow', {\n dark: '#0000005c',\n light: '#00000029',\n }),\n separator: registerEditorColor(\n 'hover.separator',\n transparentEditorColor(editorColorReference('foreground'), 0.18),\n ),\n secondaryForeground: registerEditorColor(\n 'hover.secondaryForeground',\n transparentEditorColor(editorColorReference('foreground'), 0.72),\n ),\n actionSuccess: registerEditorColor('hover.actionSuccess', {\n dark: '#86efac',\n light: '#15803d',\n }),\n actionFailure: registerEditorColor('hover.actionFailure', {\n dark: '#ef4444',\n light: '#dc2626',\n }),\n} as const\n\n/** The variables the hover reads, for a surface mounted outside the editor's cascade. */\nexport const HOVER_THEME_VARIABLES = [\n '--editor-hover-background',\n '--editor-hover-foreground',\n '--editor-hover-border',\n '--editor-hover-shadow',\n '--editor-hover-separator',\n '--editor-hover-secondary-foreground',\n '--editor-hover-action-success',\n '--editor-hover-action-failure',\n] as const\n"],"mappings":";;AAUA,IAAa,eAAe;CAC1B,YAAY,oBAAoB,oBAAoB;EAClD,MAAM;EACN,OAAO;CACT,CAAC;CACD,YAAY,oBAAoB,oBAAoB,qBAAqB,YAAY,CAAC;CACtF,QAAQ,oBACN,gBACA,uBAAuB,qBAAqB,YAAY,GAAG,GAAI,CACjE;CACA,QAAQ,oBAAoB,gBAAgB;EAC1C,MAAM;EACN,OAAO;CACT,CAAC;CACD,WAAW,oBACT,mBACA,uBAAuB,qBAAqB,YAAY,GAAG,GAAI,CACjE;CACA,qBAAqB,oBACnB,6BACA,uBAAuB,qBAAqB,YAAY,GAAG,GAAI,CACjE;CACA,eAAe,oBAAoB,uBAAuB;EACxD,MAAM;EACN,OAAO;CACT,CAAC;CACD,eAAe,oBAAoB,uBAAuB;EACxD,MAAM;EACN,OAAO;CACT,CAAC;AACH;;AAGA,IAAa,wBAAwB;CACnC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF"}
@@ -0,0 +1,71 @@
1
+ import type { EditorTheme } from '@singapore-editor/core/rendering';
2
+ import { type AnchoredSurfacePlacement } from './anchoredSurface';
3
+ import type { TooltipCodeTokenizer } from './codeTokens';
4
+ /** The full pointer-settle delay. Semantic requests begin halfway through it. */
5
+ export declare const HOVER_REQUEST_DEBOUNCE_MS = 300;
6
+ export declare const HOVER_ASYNC_DISPATCH_DELAY_MS: number;
7
+ export declare const HOVER_LOADING_DELAY_MS: number;
8
+ export declare const TOOLTIP_HIDE_DELAY_MS = 300;
9
+ export declare const COPY_BUTTON_RESET_DELAY_MS = 1200;
10
+ export type TooltipAction = {
11
+ readonly label: string;
12
+ readonly run: () => void | Promise<void>;
13
+ };
14
+ /** A place a note points at, opened by the host: the other half of a duplicate, a related site. */
15
+ export type TooltipNoteLink = {
16
+ /** What is clicked, such as `file.ts(12, 3): `. */
17
+ readonly label: string;
18
+ readonly text: string;
19
+ open(): void;
20
+ };
21
+ /** One line under the hover text, laid out as a VS Code marker: a diagnostic, a warning. */
22
+ export type TooltipNote = {
23
+ /** Shown as written, so a multi-line message keeps its lines. */
24
+ readonly text: string;
25
+ /** Who raised it, and its code, shown muted after the message as VS Code does. */
26
+ readonly source?: string;
27
+ readonly code?: string;
28
+ /** Makes the code a link to its documentation. */
29
+ readonly codeHref?: string;
30
+ readonly related?: readonly TooltipNoteLink[];
31
+ readonly actions?: readonly TooltipAction[];
32
+ };
33
+ /** One row group of the tooltip; shown in the order given. */
34
+ export type TooltipPart = {
35
+ readonly markdown?: string;
36
+ readonly notes?: readonly TooltipNote[];
37
+ readonly actions?: readonly TooltipAction[];
38
+ };
39
+ export type TooltipShowOptions = {
40
+ readonly anchor: DOMRect;
41
+ /** A single Markdown body, for a surface with one thing to say. */
42
+ readonly hoverText: string | null;
43
+ readonly parts?: readonly TooltipPart[];
44
+ readonly theme: EditorTheme | null;
45
+ readonly loading?: boolean;
46
+ readonly focus?: boolean;
47
+ readonly preferredPlacement?: AnchoredSurfacePlacement;
48
+ };
49
+ export type TooltipOptions = {
50
+ readonly document: Document;
51
+ readonly themeSource: HTMLElement;
52
+ readonly reentryElement: HTMLElement;
53
+ readonly markdownCodeBackground?: boolean;
54
+ readonly classNamespace?: string;
55
+ readonly codeTokenizer?: TooltipCodeTokenizer | null;
56
+ onDidHide?(): void;
57
+ onRequestEditorFocus?(): void;
58
+ };
59
+ export type TooltipController = {
60
+ show(options: TooltipShowOptions): void;
61
+ reanchor(anchor: DOMRect): void;
62
+ hide(): void;
63
+ scheduleHide(): void;
64
+ cancelHide(): void;
65
+ containsTarget(target: EventTarget | null): boolean;
66
+ /** Keeps a sticky hover only while the pointer is inside it or is still moving closer to it. */
67
+ shouldKeepForPointer(clientX: number, clientY: number): boolean;
68
+ dispose(): void;
69
+ };
70
+ export declare function createTooltipController(options: TooltipOptions): TooltipController;
71
+ //# sourceMappingURL=tooltip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../src/tooltip.ts"],"names":[],"mappings":"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"}