@adecore/editor-react 0.22.1 → 0.23.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/dist/CallHierarchyPanel.d.ts +6 -0
  2. package/dist/CallHierarchyPanel.js +92 -0
  3. package/dist/CompletionPopup.js +11 -3
  4. package/dist/DiffView.d.ts +22 -0
  5. package/dist/DiffView.js +203 -0
  6. package/dist/EditorContextMenu.js +1 -0
  7. package/dist/EditorView.js +18 -1
  8. package/dist/FindReplace.d.ts +1 -1
  9. package/dist/FindReplace.js +41 -11
  10. package/dist/HoverCard.js +2 -2
  11. package/dist/LanguagePopups.js +4 -1
  12. package/dist/Markdown.d.ts +2 -1
  13. package/dist/Markdown.js +8 -4
  14. package/dist/PanelResizeHandle.d.ts +8 -0
  15. package/dist/PanelResizeHandle.js +71 -0
  16. package/dist/PeekPanel.d.ts +3 -0
  17. package/dist/PeekPanel.js +7 -4
  18. package/dist/PickPopup.js +15 -2
  19. package/dist/RenameCard.js +10 -5
  20. package/dist/RenderedDocs.d.ts +9 -0
  21. package/dist/RenderedDocs.js +84 -0
  22. package/dist/SplitDiffView.d.ts +9 -0
  23. package/dist/SplitDiffView.js +276 -0
  24. package/dist/SymbolPicker.d.ts +3 -0
  25. package/dist/SymbolPicker.js +4 -3
  26. package/dist/call-hierarchy-model.d.ts +52 -0
  27. package/dist/call-hierarchy-model.js +93 -0
  28. package/dist/call-hierarchy.d.ts +42 -0
  29. package/dist/call-hierarchy.js +398 -0
  30. package/dist/code-actions-model.d.ts +2 -0
  31. package/dist/code-actions-model.js +12 -10
  32. package/dist/code-actions.js +3 -1
  33. package/dist/completion-model.d.ts +14 -4
  34. package/dist/completion-model.js +40 -33
  35. package/dist/completion.d.ts +4 -0
  36. package/dist/completion.js +257 -42
  37. package/dist/diagnostics.js +8 -6
  38. package/dist/diff-expansion.d.ts +9 -0
  39. package/dist/diff-expansion.js +41 -0
  40. package/dist/diff-overlays.d.ts +15 -0
  41. package/dist/diff-overlays.js +28 -0
  42. package/dist/diff-syntax.d.ts +16 -0
  43. package/dist/diff-syntax.js +49 -0
  44. package/dist/diff-wordmarks.d.ts +5 -0
  45. package/dist/diff-wordmarks.js +26 -0
  46. package/dist/doc-comment-model.d.ts +23 -0
  47. package/dist/doc-comment-model.js +291 -0
  48. package/dist/editor-language.d.ts +13 -1
  49. package/dist/editor-language.js +15 -5
  50. package/dist/editor-react.css +79 -0
  51. package/dist/format-on-type.d.ts +14 -0
  52. package/dist/format-on-type.js +96 -0
  53. package/dist/host-types.d.ts +19 -0
  54. package/dist/hover.d.ts +4 -0
  55. package/dist/hover.js +15 -2
  56. package/dist/index.d.ts +19 -5
  57. package/dist/index.js +9 -1
  58. package/dist/inlay-hints.d.ts +47 -2
  59. package/dist/inlay-hints.js +353 -16
  60. package/dist/language-ids.js +4 -2
  61. package/dist/locales/en.json +117 -3
  62. package/dist/locales/nl.json +117 -3
  63. package/dist/models.d.ts +6 -2
  64. package/dist/models.js +5 -1
  65. package/dist/panel-size.d.ts +6 -0
  66. package/dist/panel-size.js +25 -0
  67. package/dist/patch-decorations.d.ts +27 -0
  68. package/dist/patch-decorations.js +182 -0
  69. package/dist/patch-layout.d.ts +40 -0
  70. package/dist/patch-layout.js +304 -0
  71. package/dist/peek.d.ts +3 -1
  72. package/dist/peek.js +6 -1
  73. package/dist/pick.d.ts +1 -0
  74. package/dist/pick.js +11 -1
  75. package/dist/popups.d.ts +17 -0
  76. package/dist/popups.js +1 -0
  77. package/dist/project-language.d.ts +12 -0
  78. package/dist/project-language.js +52 -2
  79. package/dist/refresher.d.ts +1 -0
  80. package/dist/refresher.js +5 -0
  81. package/dist/rename-model.d.ts +1 -1
  82. package/dist/rename-model.js +3 -7
  83. package/dist/rename.js +5 -8
  84. package/dist/rendered-docs.d.ts +64 -0
  85. package/dist/rendered-docs.js +374 -0
  86. package/dist/row-host.d.ts +2 -0
  87. package/dist/row-host.js +11 -3
  88. package/dist/semantic-delta.d.ts +2 -0
  89. package/dist/semantic-delta.js +27 -0
  90. package/dist/semantic-model.js +16 -0
  91. package/dist/semantic-tokens.d.ts +26 -1
  92. package/dist/semantic-tokens.js +174 -14
  93. package/dist/shortcut-keys.d.ts +2 -0
  94. package/dist/shortcut-keys.js +6 -2
  95. package/dist/signature.js +1 -1
  96. package/dist/snippet-field-transforms.d.ts +30 -0
  97. package/dist/snippet-field-transforms.js +116 -0
  98. package/dist/snippet-indent.d.ts +2 -0
  99. package/dist/snippet-indent.js +49 -0
  100. package/dist/snippet-range-order.d.ts +3 -0
  101. package/dist/snippet-range-order.js +19 -0
  102. package/dist/snippet-session.d.ts +42 -6
  103. package/dist/snippet-session.js +650 -53
  104. package/dist/snippet-transform-client.d.ts +19 -0
  105. package/dist/snippet-transform-client.js +66 -0
  106. package/dist/snippet-transform-format.d.ts +15 -0
  107. package/dist/snippet-transform-format.js +302 -0
  108. package/dist/snippet-transform-protocol.d.ts +45 -0
  109. package/dist/snippet-transform-protocol.js +8 -0
  110. package/dist/snippet-transform-queue.d.ts +32 -0
  111. package/dist/snippet-transform-queue.js +173 -0
  112. package/dist/snippet-transform-worker.d.ts +10 -0
  113. package/dist/snippet-transform-worker.js +41 -0
  114. package/dist/snippet-variable-names.d.ts +1 -0
  115. package/dist/snippet-variable-names.js +36 -0
  116. package/dist/snippet-variables.d.ts +7 -0
  117. package/dist/snippet-variables.js +66 -0
  118. package/dist/snippet.d.ts +30 -3
  119. package/dist/snippet.js +402 -87
  120. package/dist/split-alignment.d.ts +6 -0
  121. package/dist/split-alignment.js +38 -0
  122. package/dist/split-scroll.d.ts +14 -0
  123. package/dist/split-scroll.js +45 -0
  124. package/dist/symbols.d.ts +2 -1
  125. package/dist/symbols.js +39 -7
  126. package/dist/testing.d.ts +5 -1
  127. package/dist/testing.js +12 -0
  128. package/dist/timers.d.ts +1 -0
  129. package/dist/timers.js +4 -0
  130. package/dist/use-panel-body.d.ts +6 -0
  131. package/dist/use-panel-body.js +13 -0
  132. package/dist/workspace-edit.d.ts +25 -3
  133. package/dist/workspace-edit.js +282 -143
  134. package/package.json +10 -5
  135. package/src/CallHierarchyPanel.tsx +244 -0
  136. package/src/CompletionPopup.tsx +12 -1
  137. package/src/DiffView.tsx +262 -0
  138. package/src/EditorContextMenu.tsx +1 -0
  139. package/src/EditorView.tsx +21 -2
  140. package/src/FindReplace.tsx +51 -13
  141. package/src/HoverCard.tsx +23 -21
  142. package/src/LanguagePopups.tsx +5 -0
  143. package/src/Markdown.tsx +10 -3
  144. package/src/PanelResizeHandle.tsx +104 -0
  145. package/src/PeekPanel.tsx +11 -6
  146. package/src/PickPopup.tsx +18 -2
  147. package/src/RenameCard.tsx +18 -0
  148. package/src/RenderedDocs.tsx +155 -0
  149. package/src/SplitDiffView.tsx +337 -0
  150. package/src/SymbolPicker.tsx +4 -3
  151. package/src/call-hierarchy-model.ts +151 -0
  152. package/src/call-hierarchy.ts +440 -0
  153. package/src/code-actions-model.ts +17 -11
  154. package/src/code-actions.ts +3 -1
  155. package/src/completion-model.ts +61 -35
  156. package/src/completion.ts +302 -42
  157. package/src/diagnostics.ts +8 -6
  158. package/src/diff-expansion.ts +49 -0
  159. package/src/diff-overlays.tsx +69 -0
  160. package/src/diff-syntax.ts +67 -0
  161. package/src/diff-wordmarks.ts +31 -0
  162. package/src/doc-comment-model.ts +336 -0
  163. package/src/editor-language.ts +22 -6
  164. package/src/editor-react.css +79 -0
  165. package/src/format-on-type.ts +111 -0
  166. package/src/host-types.ts +23 -0
  167. package/src/hover.ts +18 -3
  168. package/src/index.ts +27 -4
  169. package/src/inlay-hints.ts +394 -18
  170. package/src/language-ids.ts +4 -2
  171. package/src/locales/en.json +117 -3
  172. package/src/locales/nl.json +117 -3
  173. package/src/models.ts +40 -1
  174. package/src/panel-size.ts +28 -0
  175. package/src/patch-decorations.ts +224 -0
  176. package/src/patch-layout.ts +388 -0
  177. package/src/peek.ts +6 -1
  178. package/src/pick.ts +12 -1
  179. package/src/popups.ts +24 -0
  180. package/src/project-language.ts +63 -2
  181. package/src/refresher.ts +6 -0
  182. package/src/rename-model.ts +4 -8
  183. package/src/rename.ts +5 -8
  184. package/src/rendered-docs.ts +430 -0
  185. package/src/row-host.ts +12 -3
  186. package/src/semantic-delta.ts +29 -0
  187. package/src/semantic-model.ts +17 -0
  188. package/src/semantic-tokens.ts +202 -19
  189. package/src/shortcut-keys.ts +6 -2
  190. package/src/signature.ts +1 -1
  191. package/src/snippet-field-transforms.ts +144 -0
  192. package/src/snippet-indent.ts +53 -0
  193. package/src/snippet-range-order.ts +19 -0
  194. package/src/snippet-session.ts +797 -56
  195. package/src/snippet-transform-client.ts +84 -0
  196. package/src/snippet-transform-format.ts +325 -0
  197. package/src/snippet-transform-protocol.ts +24 -0
  198. package/src/snippet-transform-queue.ts +199 -0
  199. package/src/snippet-transform-worker.ts +58 -0
  200. package/src/snippet-variable-names.ts +36 -0
  201. package/src/snippet-variables.ts +74 -0
  202. package/src/snippet.ts +452 -89
  203. package/src/split-alignment.ts +45 -0
  204. package/src/split-scroll.ts +54 -0
  205. package/src/symbols.ts +43 -7
  206. package/src/testing.ts +25 -0
  207. package/src/timers.ts +5 -0
  208. package/src/use-panel-body.ts +17 -0
  209. package/src/workspace-edit.ts +347 -169
@@ -0,0 +1,71 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from 'react';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { PANEL_BODY_MIN, PANEL_KEY_STEP, availableHeightOf, clampPanelBody, panelBodyMax } from './panel-size.js';
5
+ import { realTimers, revealRow } from './timers.js';
6
+ /* The bottom edge of a panel: a drag, or the arrow keys, change the height of its body. */
7
+ export function PanelResizeHandle({ container, height, onHeight, onCommit }) {
8
+ const { t } = useTranslation('editor');
9
+ const drag = useRef(null);
10
+ const [dragging, setDragging] = useState(false);
11
+ const [max, setMax] = useState(() => panelBodyMax(availableHeightOf(container)));
12
+ useEffect(() => {
13
+ const viewport = container.closest('.se-viewport');
14
+ const Observer = viewport?.ownerDocument.defaultView?.ResizeObserver;
15
+ if (viewport === null || viewport === undefined || Observer === undefined) {
16
+ return;
17
+ }
18
+ const observer = new Observer(() => setMax(panelBodyMax(availableHeightOf(container))));
19
+ observer.observe(viewport);
20
+ return () => observer.disconnect();
21
+ }, [container]);
22
+ function settle(value, from) {
23
+ const next = clampPanelBody(value, availableHeightOf(container));
24
+ onHeight(next);
25
+ if (next !== from) {
26
+ onCommit(next);
27
+ revealRow(realTimers, container);
28
+ }
29
+ }
30
+ function heightAt(clientY) {
31
+ return clampPanelBody(drag.current.startHeight + clientY - drag.current.startY, availableHeightOf(container));
32
+ }
33
+ function down(event) {
34
+ if (event.button !== 0) {
35
+ return;
36
+ }
37
+ event.currentTarget.setPointerCapture(event.pointerId);
38
+ drag.current = { startY: event.clientY, startHeight: height, lastY: event.clientY };
39
+ setDragging(true);
40
+ }
41
+ function move(event) {
42
+ if (drag.current !== null) {
43
+ drag.current.lastY = event.clientY;
44
+ onHeight(heightAt(event.clientY));
45
+ }
46
+ }
47
+ // Also the end of a drag whose capture was lost, such as a container that was replaced under the pointer.
48
+ function end(event) {
49
+ if (drag.current === null) {
50
+ return;
51
+ }
52
+ const { startHeight } = drag.current;
53
+ const next = heightAt(drag.current.lastY);
54
+ drag.current = null;
55
+ setDragging(false);
56
+ event.currentTarget.releasePointerCapture?.(event.pointerId);
57
+ settle(next, startHeight);
58
+ }
59
+ function key(event) {
60
+ const step = event.shiftKey ? PANEL_KEY_STEP * 4 : PANEL_KEY_STEP;
61
+ const end = panelBodyMax(availableHeightOf(container));
62
+ const target = { ArrowUp: height - step, ArrowDown: height + step, Home: PANEL_BODY_MIN, End: end }[event.key];
63
+ if (target === undefined) {
64
+ return;
65
+ }
66
+ event.preventDefault();
67
+ event.stopPropagation();
68
+ settle(target, height);
69
+ }
70
+ return (_jsx("div", { role: "separator", "aria-orientation": "horizontal", "aria-label": t('language.panel.resize'), "aria-valuemin": PANEL_BODY_MIN, "aria-valuemax": max, "aria-valuenow": height, tabIndex: 0, "data-dragging": dragging, className: "absolute inset-x-0 bottom-0 z-10 h-1 cursor-row-resize touch-none outline-none hover:bg-accent-soft focus-visible:bg-accent-soft data-[dragging=true]:bg-accent-soft", onPointerDown: down, onPointerMove: move, onPointerUp: end, onPointerCancel: end, onLostPointerCapture: end, onKeyDown: key }));
71
+ }
@@ -1,5 +1,8 @@
1
1
  import type { EditorLanguage } from './editor-language.ts';
2
2
  import type { PeekView } from './popups.ts';
3
+ export declare function Preview({ preview }: {
4
+ preview: PeekView['preview'];
5
+ }): import("react").JSX.Element;
3
6
  export declare function PeekPanel({ language, view }: {
4
7
  language: EditorLanguage;
5
8
  view: PeekView;
package/dist/PeekPanel.js CHANGED
@@ -9,16 +9,18 @@ import { formatNumber } from '@adecore/ui/format';
9
9
  import { basenameOf, relativeTo } from './paths.js';
10
10
  import { shikiLanguageOfPath } from './language-ids.js';
11
11
  import { PathText } from './PathText.js';
12
+ import { PanelResizeHandle } from './PanelResizeHandle.js';
13
+ import { usePanelBody } from './use-panel-body.js';
14
+ import { PANEL_BODY_HEIGHT } from './panel-size.js';
12
15
  import { PEEK_HEIGHT } from './peek.js';
13
16
  import { distinguishingFolders, visualColumnOf } from './peek-model.js';
14
17
  import { useEditorRendering } from './rendering-context.js';
15
18
  const TAB_SIZE = 4;
16
19
  const CODE = 'font-mono text-(length:--code-font-size) [tab-size:4] [&_.line]:block [&_.line]:h-(--code-line-height) [&_.line]:leading-(--code-line-height) [&_pre]:m-0 [&_pre]:bg-transparent! [&_pre]:p-0 [&_pre]:whitespace-pre [&_code]:font-mono';
17
20
  /* The code around the active reference, drawn like the editor's own rows: its gutter, the line the reference is on and the name marked. */
18
- function Preview({ view }) {
21
+ export function Preview({ preview }) {
19
22
  const { theme, highlight } = useEditorRendering();
20
23
  const scroller = useRef(null);
21
- const { preview } = view;
22
24
  const [html, setHtml] = useState(null);
23
25
  const path = preview === null ? null : fileUriToPath(preview.uri);
24
26
  const key = preview === null ? '' : `${theme}\0${path}\0${preview.text}`;
@@ -94,11 +96,12 @@ export function PeekPanel({ language, view }) {
94
96
  const path = active === undefined ? null : fileUriToPath(active.location.uri);
95
97
  const folder = language.project.folder;
96
98
  const shown = path === null ? '' : folderOf(relativeTo(path, folder));
99
+ const body = usePanelBody(language);
97
100
  if (view.container === null) {
98
101
  return null;
99
102
  }
100
- return createPortal(_jsxs("div", { className: "flex flex-col bg-surface pt-[2px] font-sans text-xs text-text", style: { height: PEEK_HEIGHT }, onPointerDown: (event) => event.preventDefault(), children: [_jsx("div", { className: "peek-hatch h-[14px]" }), _jsxs("div", { className: "flex h-[31px] shrink-0 items-center gap-2 border-b border-border pr-2 pl-3 text-sm", children: [_jsx("span", { className: "shrink-0 font-medium", children: path === null ? '' : basenameOf(path) }), _jsx(PathText, { path: shown, className: "text-text-muted" }), _jsxs("div", { className: "ml-auto flex shrink-0 items-center gap-1", children: [_jsx("span", { className: "text-text-muted", children: t(view.kind === 'definitions' ? 'language.peek.definitions' : 'language.peek.references', {
103
+ return createPortal(_jsxs("div", { className: "flex flex-col bg-surface pt-[2px] font-sans text-xs text-text", style: { height: PEEK_HEIGHT - PANEL_BODY_HEIGHT + body.height }, onPointerDown: (event) => event.preventDefault(), children: [_jsx("div", { className: "peek-hatch h-[14px]" }), _jsxs("div", { className: "flex h-[31px] shrink-0 items-center gap-2 border-b border-border pr-2 pl-3 text-sm", children: [_jsx("span", { className: "shrink-0 font-medium", children: path === null ? '' : basenameOf(path) }), _jsx(PathText, { path: shown, className: "text-text-muted" }), _jsxs("div", { className: "ml-auto flex shrink-0 items-center gap-1", children: [_jsx("span", { className: "text-text-muted", children: t(view.kind === 'definitions' ? 'language.peek.definitions' : 'language.peek.references', {
101
104
  count: view.count,
102
105
  formatted: formatNumber(view.count)
103
- }) }), _jsx(IconButton, { icon: X, size: "xs", label: t('language.peek.close'), onClick: () => language.peek.close() })] })] }), _jsxs("div", { className: "flex h-[180px] shrink-0", children: [_jsx(Preview, { view: view }), _jsx(Places, { language: language, view: view })] }), _jsx("div", { className: "peek-hatch h-[14px]" })] }), view.container);
106
+ }) }), _jsx(IconButton, { icon: X, size: "xs", label: t('language.peek.close'), onClick: () => language.peek.close() })] })] }), _jsxs("div", { className: "flex shrink-0", style: { height: body.height }, children: [_jsx(Preview, { preview: view.preview }), _jsx(Places, { language: language, view: view })] }), _jsx("div", { className: "peek-hatch relative h-[14px]", children: _jsx(PanelResizeHandle, { container: view.container, height: body.height, onHeight: body.set, onCommit: body.commit }) })] }), view.container);
104
107
  }
package/dist/PickPopup.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useLayoutEffect, useRef } from 'react';
2
+ import { useId, useLayoutEffect, useRef } from 'react';
3
3
  import { createPortal } from 'react-dom';
4
4
  import { PathText } from './PathText.js';
5
5
  import { placePopup } from './popup-placement.js';
@@ -12,6 +12,7 @@ function PreviewLines({ preview }) {
12
12
  * the focus from the editor, so the keys keep going to it while the list is open.
13
13
  */
14
14
  export function PickPopup({ language, view, rect }) {
15
+ const listId = useId();
15
16
  const card = useRef(null);
16
17
  const activeRow = useRef(null);
17
18
  // Every render: the character moves with the scroll, and the list changes size with its preview.
@@ -29,5 +30,17 @@ export function PickPopup({ language, view, rect }) {
29
30
  useLayoutEffect(() => {
30
31
  activeRow.current?.scrollIntoView({ block: 'nearest' });
31
32
  }, [view.active]);
32
- return createPortal(_jsxs("div", { ref: card, className: CARD, style: { visibility: 'hidden' }, onPointerDown: (event) => event.preventDefault(), children: [view.title !== null && _jsx("div", { className: "border-b border-border px-3 py-1.5 text-xs text-text-muted", children: view.title }), _jsx("div", { role: "listbox", className: "min-h-0 flex-1 overflow-y-auto p-1", children: view.groups.map((group, groupIndex) => (_jsxs("div", { role: "group", className: "flex flex-col", children: [group.title !== null && _jsx("div", { className: "px-2 pt-1.5 pb-0.5 text-xs font-medium text-text-faint", children: group.title }), group.rows.map((row) => (_jsxs("button", { ref: row.id === view.active ? activeRow : undefined, type: "button", role: "option", "aria-selected": row.id === view.active, "data-active": row.id === view.active, className: "flex h-7 w-full items-center gap-2 rounded-md px-2 text-left text-xs cursor-row", onClick: () => language.pick.choose(row.id), children: [_jsx("span", { className: row.path ? 'shrink-0' : 'min-w-0 truncate', children: row.label }), row.path ? (_jsx(PathText, { path: row.detail, className: "ml-auto font-mono text-text-faint" })) : (_jsx("span", { className: "ml-auto shrink-0 font-mono text-text-faint", children: row.id === view.active && row.detail === '' ? '↵' : row.detail }))] }, row.id)))] }, group.title ?? groupIndex))) }), view.preview !== null && _jsx(PreviewLines, { preview: view.preview })] }), document.body);
33
+ const optionIds = new Map();
34
+ for (const group of view.groups) {
35
+ for (const row of group.rows) {
36
+ optionIds.set(row.id, `${listId}-option-${optionIds.size}`);
37
+ }
38
+ }
39
+ const activeId = optionIds.get(view.active);
40
+ // The focus stays in the text, so the input is what names the list and its active option.
41
+ useLayoutEffect(() => {
42
+ language.editor.setInputPopup({ controls: listId, activeDescendant: activeId });
43
+ return () => language.editor.setInputPopup(null);
44
+ }, [language, listId, activeId]);
45
+ return createPortal(_jsxs("div", { ref: card, className: CARD, style: { visibility: 'hidden' }, onPointerDown: (event) => event.preventDefault(), children: [view.title !== null && _jsx("div", { className: "border-b border-border px-3 py-1.5 text-xs text-text-muted", children: view.title }), _jsx("div", { id: listId, role: "listbox", className: "min-h-0 flex-1 overflow-y-auto p-1", children: view.groups.map((group, groupIndex) => (_jsxs("div", { role: "group", className: "flex flex-col", children: [group.title !== null && _jsx("div", { className: "px-2 pt-1.5 pb-0.5 text-xs font-medium text-text-faint", children: group.title }), group.rows.map((row) => (_jsxs("button", { id: optionIds.get(row.id), ref: row.id === view.active ? activeRow : undefined, type: "button", role: "option", "aria-selected": row.id === view.active, "data-active": row.id === view.active, className: "flex h-7 w-full items-center gap-2 rounded-md px-2 text-left text-xs cursor-row", onClick: () => language.pick.choose(row.id), children: [_jsx("span", { className: row.path ? 'shrink-0' : 'min-w-0 truncate', children: row.label }), row.path ? (_jsx(PathText, { path: row.detail, className: "ml-auto font-mono text-text-faint" })) : (_jsx("span", { className: "ml-auto shrink-0 font-mono text-text-faint", children: row.id === view.active && row.detail === '' ? '↵' : row.detail }))] }, row.id)))] }, group.title ?? groupIndex))) }), view.preview !== null && _jsx(PreviewLines, { preview: view.preview })] }), document.body);
33
46
  }
@@ -35,11 +35,16 @@ function Hints({ view, active, onPick }) {
35
35
  function Preview({ language, view }) {
36
36
  const { t } = useTranslation('editor');
37
37
  const folder = language.project.folder;
38
- return (_jsxs("div", { className: "flex w-[520px] max-w-full flex-col", onPointerDown: (event) => event.preventDefault(), children: [_jsx("div", { className: "max-h-[320px] overflow-y-auto", children: view.files.map((file) => {
39
- const path = fileUriToPath(file.uri);
40
- const shown = path === null ? file.uri : relativeTo(path, folder);
41
- return (_jsxs("div", { className: "border-b border-border last:border-b-0", children: [_jsxs("div", { className: "flex items-center gap-2 px-3 py-1.5 text-xs", children: [_jsx("span", { className: "font-medium", children: path === null ? shown : basenameOf(path) }), _jsx("span", { className: "min-w-0 truncate text-text-faint", children: shown })] }), _jsx("div", { className: "flex flex-col gap-px px-1 pb-1.5 font-mono text-code", children: file.rows.map((row) => (_jsxs("div", { className: "flex flex-col gap-px", children: [_jsxs("div", { className: "flex gap-2 rounded-sm bg-status-error/10 px-1.5 whitespace-pre", children: [_jsx("span", { className: "w-8 shrink-0 text-right text-text-faint", children: row.line }), _jsx("span", { className: "min-w-0 truncate", children: row.before })] }), _jsxs("div", { className: "flex gap-2 rounded-sm bg-status-idle/10 px-1.5 whitespace-pre", children: [_jsx("span", { className: "w-8 shrink-0" }), _jsx("span", { className: "min-w-0 truncate", children: row.after })] })] }, row.line))) })] }, file.uri));
42
- }) }), _jsxs("div", { className: "flex items-center justify-end gap-2 border-t border-border p-2", children: [_jsx(Button, { size: "xs", variant: "ghost", onClick: () => language.rename.cancel(), children: t('language.rename.cancel') }), _jsx(Button, { size: "xs", variant: "primary", onClick: () => void language.rename.confirm(), children: t('language.rename.apply') })] })] }));
38
+ const operations = view.operations ?? [];
39
+ const shownPath = (uri) => {
40
+ const path = fileUriToPath(uri);
41
+ return path === null ? uri : relativeTo(path, folder);
42
+ };
43
+ return (_jsxs("div", { className: "flex w-[520px] max-w-full flex-col", onPointerDown: (event) => event.preventDefault(), children: [_jsxs("div", { className: "max-h-[320px] overflow-y-auto", children: [view.files.map((file) => {
44
+ const path = fileUriToPath(file.uri);
45
+ const shown = path === null ? file.uri : relativeTo(path, folder);
46
+ return (_jsxs("div", { className: "border-b border-border last:border-b-0", children: [_jsxs("div", { className: "flex items-center gap-2 px-3 py-1.5 text-xs", children: [_jsx("span", { className: "font-medium", children: path === null ? shown : basenameOf(path) }), _jsx("span", { className: "min-w-0 truncate text-text-faint", children: shown })] }), _jsx("div", { className: "flex flex-col gap-px px-1 pb-1.5 font-mono text-code", children: file.rows.map((row) => (_jsxs("div", { className: "flex flex-col gap-px", children: [_jsxs("div", { className: "flex gap-2 rounded-sm bg-status-error/10 px-1.5 whitespace-pre", children: [_jsx("span", { className: "w-8 shrink-0 text-right text-text-faint", children: row.line }), _jsx("span", { className: "min-w-0 truncate", children: row.before })] }), _jsxs("div", { className: "flex gap-2 rounded-sm bg-status-idle/10 px-1.5 whitespace-pre", children: [_jsx("span", { className: "w-8 shrink-0" }), _jsx("span", { className: "min-w-0 truncate", children: row.after })] })] }, row.line))) })] }, file.uri));
47
+ }), operations.length > 0 && (_jsx("div", { className: "flex flex-col gap-px border-b border-border px-3 py-1.5 text-xs last:border-b-0", children: operations.map((operation, index) => (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "shrink-0 font-medium", children: t(`language.rename.operations.${operation.kind}`) }), _jsxs("span", { className: "min-w-0 truncate text-text-faint", children: [shownPath(operation.uri), operation.newUri === undefined ? '' : ` \u2192 ${shownPath(operation.newUri)}`] })] }, `${operation.kind}:${operation.uri}:${index}`))) }))] }), _jsxs("div", { className: "flex items-center justify-end gap-2 border-t border-border p-2", children: [_jsx(Button, { size: "xs", variant: "ghost", onClick: () => language.rename.cancel(), children: t('language.rename.cancel') }), _jsx(Button, { size: "xs", variant: "primary", onClick: () => void language.rename.confirm(), children: t('language.rename.apply') })] })] }));
43
48
  }
44
49
  /*
45
50
  * The rename of a symbol: an input over the symbol itself, and under it either the count of its places with
@@ -0,0 +1,9 @@
1
+ import type { EditorLanguage } from './editor-language.ts';
2
+ import type { RenderedDocEntry } from './rendered-docs.ts';
3
+ export declare function RenderedDocBlock({ language, entry }: {
4
+ language: EditorLanguage;
5
+ entry: RenderedDocEntry;
6
+ }): import("react").JSX.Element;
7
+ export declare function RenderedDocs({ language }: {
8
+ language: EditorLanguage;
9
+ }): import("react").JSX.Element;
@@ -0,0 +1,84 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { createPortal } from 'react-dom';
3
+ import { useSyncExternalStore } from 'react';
4
+ import { useTranslation } from 'react-i18next';
5
+ import { DOC_LINK_PREFIX, sectionsOf } from './doc-comment-model.js';
6
+ import { markdownParts } from './hover-content.js';
7
+ import { Signature } from './HoverSections.js';
8
+ import { shikiLanguageOf } from './language-ids.js';
9
+ import { Markdown } from './Markdown.js';
10
+ const LINK = /\[([^\]]*)\]\(#doc-link:[^)]*\)/g;
11
+ const KNOWN = new Set([
12
+ 'deprecated',
13
+ 'template',
14
+ 'param',
15
+ 'property',
16
+ 'type',
17
+ 'var',
18
+ 'return',
19
+ 'yield',
20
+ 'throws',
21
+ 'see',
22
+ 'example',
23
+ 'since',
24
+ 'version',
25
+ 'author'
26
+ ]);
27
+ /* Code in the editor's face, with a type fainter than a name. */
28
+ function Code({ children, faint = false }) {
29
+ return _jsx("code", { className: `font-mono text-code break-words ${faint ? 'text-text-faint' : 'text-text'}`, children: children });
30
+ }
31
+ /* Markdown prose and fenced code as the hover draws them: the blocks in the code face, the rest muted. */
32
+ function Prose({ text, language, linkable, compact = false }) {
33
+ const plain = linkable ? text : text.replace(LINK, '$1');
34
+ return (_jsx(_Fragment, { children: markdownParts(plain).map((part, index) => part.kind === 'code' ? (_jsx("div", { className: "rounded-md bg-surface-sunken px-2 py-1.5", children: _jsx(Signature, { code: part.block.code, language: part.block.language === 'text' ? language : part.block.language }) }, index)) : (_jsx("div", { className: `[&_.adecore-editor-markdown]:text-xs ${compact ? '[&_p]:my-0' : '[&_p]:my-1'}`, children: _jsx(Markdown, { text: part.text, images: false }) }, index))) }));
35
+ }
36
+ /* A value of a tag, in the second column of the table; `spaced` opens a new section with more room above. */
37
+ function TagRow({ tag, language, linkable, spaced }) {
38
+ const target = tag.name === 'see' && tag.subject !== null ? tag.subject : null;
39
+ const link = target === null ? null : /^https?:\/\//i.test(target) ? `[${target}](${target})` : `[\`${target}\`](${DOC_LINK_PREFIX}${encodeURIComponent(target)})`;
40
+ return (_jsx("dd", { className: `col-start-2 m-0 flex min-w-0 flex-wrap items-baseline gap-x-2 ${spaced ? 'mt-1' : ''}`, children: tag.name === 'example' ? (_jsx("div", { className: "w-full rounded-md bg-surface-sunken px-2 py-1.5", children: _jsx(Signature, { code: tag.text, language: language }) })) : (_jsxs(_Fragment, { children: [tag.subject !== null && target === null && _jsx(Code, { children: tag.subject }), tag.type !== null && _jsx(Code, { faint: true, children: tag.type }), (link !== null || tag.text !== '') && (_jsx("div", { className: "min-w-0 grow basis-48 text-text", children: _jsx(Prose, { text: [link, tag.text].filter((part) => part !== null && part !== '').join(' '), language: language, linkable: linkable, compact: true }) }))] })) }));
41
+ }
42
+ export function RenderedDocBlock({ language, entry }) {
43
+ const { t } = useTranslation('editor');
44
+ const feature = language.renderedDocs;
45
+ const { description, tags } = entry.parsed;
46
+ const highlighter = shikiLanguageOf(language.languageId);
47
+ const linkable = feature.canFollow;
48
+ const sections = sectionsOf(tags);
49
+ const deprecated = sections.find((section) => section.name === 'deprecated');
50
+ const shown = sections.filter((section) => section.name !== 'deprecated');
51
+ // One handler for every link, since the links are made by the Markdown renderer and not by us.
52
+ const follow = (event) => {
53
+ const anchor = event.target.closest('a');
54
+ if (anchor === null) {
55
+ return;
56
+ }
57
+ event.preventDefault();
58
+ const mod = language.apple ? event.metaKey : event.ctrlKey;
59
+ const href = anchor.getAttribute('href') ?? '';
60
+ if (!mod) {
61
+ return;
62
+ }
63
+ if (href.startsWith(DOC_LINK_PREFIX)) {
64
+ feature.follow(decodeURIComponent(href.slice(DOC_LINK_PREFIX.length)), entry.comment);
65
+ }
66
+ else if (/^(https?:|mailto:)/i.test(href)) {
67
+ window.open(href, '_blank', 'noopener,noreferrer');
68
+ }
69
+ };
70
+ return (_jsxs("div", { className: "adecore-rendered-doc flex max-w-[520px] flex-col gap-1.5 py-1 font-sans text-xs/[18px] text-text select-text", onClick: follow, children: [deprecated !== undefined && (_jsxs("div", { className: "border-l-2 border-status-error pl-2 text-text-muted", children: [_jsx("span", { className: "font-medium text-status-error", children: t('language.docs.deprecated') }), deprecated.tags.some((tag) => tag.text !== '') && (_jsx(Prose, { text: deprecated.tags.map((tag) => tag.text).join(' '), language: highlighter, linkable: linkable }))] })), description !== '' && (_jsx("div", { className: "text-text", children: _jsx(Prose, { text: description, language: highlighter, linkable: linkable }) })), shown.length > 0 && (_jsx("dl", { className: "m-0 grid grid-cols-[max-content_minmax(0,1fr)] items-baseline gap-x-3 gap-y-0.5", children: shown.map((section, row) => [
71
+ _jsx("dt", { className: `col-start-1 font-medium text-text-muted ${row > 0 ? 'mt-1' : ''}`, children: KNOWN.has(section.name) ? t(`language.docs.tags.${section.name}`) : `${section.name}:` }, `${section.name}:label`),
72
+ ...section.tags.map((tag, index) => (_jsx(TagRow, { tag: tag, language: highlighter, linkable: linkable, spaced: row > 0 && index === 0 }, `${section.name}:${index}`)))
73
+ ]) }))] }));
74
+ }
75
+ /*
76
+ * The documentation comments the editor drew as rows, filled with their formatted text. It portals into
77
+ * the element the editor made for each row, so the editor decides what is in view; a comment is parsed
78
+ * only once its row is. Links in the text are followed with Cmd (Ctrl elsewhere) held, as definitions are.
79
+ */
80
+ export function RenderedDocs({ language }) {
81
+ const feature = language.renderedDocs;
82
+ useSyncExternalStore(feature.subscribe, feature.getVersion, feature.getVersion);
83
+ return _jsx(_Fragment, { children: feature.entries().map((entry) => createPortal(_jsx(RenderedDocBlock, { language: language, entry: entry }), entry.container, entry.id)) });
84
+ }
@@ -0,0 +1,9 @@
1
+ import type { DiffSplit } from '@adecore/merge';
2
+ import type { DiffViewProps } from './DiffView.tsx';
3
+ interface SplitViewProps extends DiffViewProps {
4
+ display: DiffSplit;
5
+ unfold(id: number): void;
6
+ blocked: ReadonlySet<number>;
7
+ }
8
+ export declare function SplitDiffView({ engine, document, display, unfold, blocked, theme, tokens, wrap, fill, maxHeight, label, className, ref, onMount }: SplitViewProps): import("react").JSX.Element;
9
+ export {};
@@ -0,0 +1,276 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useLayoutEffect, useMemo, useRef, useState } from 'react';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { parseChord } from '@adecore/editor/keymap';
5
+ import { DiffOverlays } from './diff-overlays.js';
6
+ import { wordMarks } from './diff-wordmarks.js';
7
+ import { RowHost, LineActionHost } from './row-host.js';
8
+ import { splitAlignment } from './split-alignment.js';
9
+ import { SplitScroll } from './split-scroll.js';
10
+ const SIDES = ['old', 'new'];
11
+ export function SplitDiffView({ engine, document, display, unfold, blocked, theme, tokens, wrap = true, fill = false, maxHeight, label, className, ref, onMount }) {
12
+ const { t } = useTranslation('editor');
13
+ const emphasis = useMemo(() => wordMarks(document), [document]);
14
+ const oldElement = useRef(null);
15
+ const newElement = useRef(null);
16
+ const current = useRef({ display, tokens, theme, wrap, label });
17
+ const applied = useRef({ theme, wrap, label });
18
+ const [failure, setFailure] = useState(null);
19
+ const [mounted, setMounted] = useState(null);
20
+ const [height, setHeight] = useState(0);
21
+ useLayoutEffect(() => {
22
+ current.current = { display, tokens, theme, wrap, label };
23
+ });
24
+ useLayoutEffect(() => {
25
+ const oldHost = oldElement.current;
26
+ const newHost = newElement.current;
27
+ if (oldHost === null || newHost === null) {
28
+ return;
29
+ }
30
+ const initial = current.current;
31
+ applied.current = { theme: initial.theme, wrap: initial.wrap, label: initial.label };
32
+ const mount = (side, host) => {
33
+ const initial = current.current;
34
+ const editor = engine.mount(host, {
35
+ text: initial.display[side].text,
36
+ theme: initial.theme,
37
+ wrap: initial.wrap,
38
+ label: initial.label,
39
+ readOnly: true,
40
+ guides: false,
41
+ folding: false,
42
+ foldOutline: 'off',
43
+ handBack: [parseChord('Mod+Enter')]
44
+ });
45
+ editor.setBlocks([]);
46
+ editor.setLineTokens((line) => {
47
+ const row = current.current.display[side].rows[line];
48
+ return row === undefined ? null : current.current.tokens?.get(side, row[side].index);
49
+ });
50
+ return { engine, editor, rows: new RowHost(editor, 'diff-alignment'), actions: new LineActionHost(editor, 'diff-status') };
51
+ };
52
+ const old = mount('old', oldHost);
53
+ let fresh;
54
+ try {
55
+ fresh = mount('new', newHost);
56
+ }
57
+ catch (error) {
58
+ old.editor.dispose();
59
+ throw error;
60
+ }
61
+ const sides = { old, new: fresh };
62
+ let stopped = false;
63
+ let pending = false;
64
+ let failed = false;
65
+ const scroll = new SplitScroll({ old: old.editor, new: fresh.editor });
66
+ let aligning = false;
67
+ let updating = false;
68
+ const fail = (error) => {
69
+ failed = true;
70
+ setFailure({ error });
71
+ };
72
+ const measure = () => setHeight(Math.max(sides.old.editor.getContentHeight(), sides.new.editor.getContentHeight()));
73
+ const align = () => {
74
+ if (pending || stopped || failed) {
75
+ return;
76
+ }
77
+ pending = true;
78
+ // Intrinsic measurements arrive after each render; align both editors before the next paint.
79
+ queueMicrotask(() => {
80
+ pending = false;
81
+ if (stopped || failed) {
82
+ return;
83
+ }
84
+ aligning = true;
85
+ try {
86
+ const rows = splitAlignment(current.current.display.aligned, (line) => sides.old.editor.getLineHeight(line), (line) => sides.new.editor.getLineHeight(line));
87
+ sides.old.rows.set(rows.old);
88
+ sides.new.rows.set(rows.new);
89
+ }
90
+ catch (error) {
91
+ fail(error);
92
+ return;
93
+ }
94
+ finally {
95
+ aligning = false;
96
+ }
97
+ try {
98
+ measure();
99
+ scroll.sync();
100
+ }
101
+ catch (error) {
102
+ fail(error);
103
+ }
104
+ });
105
+ };
106
+ const update = (run) => {
107
+ updating = true;
108
+ try {
109
+ run();
110
+ }
111
+ finally {
112
+ updating = false;
113
+ }
114
+ align();
115
+ };
116
+ const stops = SIDES.flatMap((side) => [
117
+ sides[side].editor.onLineHeights(align),
118
+ sides[side].editor.onViewChange(() => {
119
+ if (stopped || failed || aligning || updating) {
120
+ return;
121
+ }
122
+ try {
123
+ measure();
124
+ scroll.changed(side);
125
+ }
126
+ catch (error) {
127
+ fail(error);
128
+ }
129
+ })
130
+ ]);
131
+ setMounted({ old: sides.old, new: sides.new, align, update, drive: (side) => scroll.drive(side) });
132
+ measure();
133
+ return () => {
134
+ stopped = true;
135
+ for (const stop of stops) {
136
+ stop();
137
+ }
138
+ for (const side of SIDES) {
139
+ sides[side].editor.dispose();
140
+ }
141
+ };
142
+ }, [engine]);
143
+ useLayoutEffect(() => {
144
+ if (mounted === null || mounted.old.engine !== engine) {
145
+ return;
146
+ }
147
+ mounted.update(() => {
148
+ for (const side of SIDES) {
149
+ const { editor, actions } = mounted[side];
150
+ editor.setText(display[side].text);
151
+ editor.setLineNumbers((line) => {
152
+ const row = current.current.display[side].rows[line];
153
+ return row === undefined ? null : String(row[side].number);
154
+ });
155
+ const highlights = [];
156
+ for (const [index, row] of display[side].rows.entries()) {
157
+ if (row.change === 'context') {
158
+ continue;
159
+ }
160
+ highlights.push({
161
+ startLine: index + 1,
162
+ endLine: index + 1,
163
+ color: side === 'old' ? '--editor-deleted' : '--editor-added',
164
+ bar: side === 'old' ? 'hatched' : 'solid',
165
+ emphasis: [emphasis[side].get(row[side].index) ?? []]
166
+ });
167
+ }
168
+ editor.setLineHighlights(highlights);
169
+ editor.setChangeMarks(highlights.map((highlight) => ({ startLine: highlight.startLine, endLine: highlight.endLine, kind: side === 'old' ? 'deleted' : 'added' })));
170
+ actions.set(display[side].rows.flatMap((row, line) => (row.noNewline === undefined ? [] : [{ id: `no-newline-${line}`, line }])));
171
+ }
172
+ });
173
+ }, [mounted, engine, display, emphasis]);
174
+ useLayoutEffect(() => {
175
+ if (mounted === null || mounted.old.engine !== engine) {
176
+ return;
177
+ }
178
+ for (const side of SIDES) {
179
+ mounted[side].editor.setLineLabels((line) => {
180
+ const row = display[side].rows[line];
181
+ if (row === undefined || row.change === 'context') {
182
+ return null;
183
+ }
184
+ return t(side === 'old' ? 'diff.removed' : 'diff.added', { number: row[side].number });
185
+ });
186
+ }
187
+ }, [mounted, engine, display, t]);
188
+ useLayoutEffect(() => {
189
+ if (mounted === null || mounted.old.engine !== engine) {
190
+ return;
191
+ }
192
+ mounted.update(() => {
193
+ for (const side of SIDES) {
194
+ const previous = applied.current;
195
+ if (previous.theme !== theme) {
196
+ mounted[side].editor.setTheme(theme);
197
+ }
198
+ if (previous.wrap !== wrap) {
199
+ mounted[side].editor.setWrap(wrap);
200
+ }
201
+ if (previous.label !== label) {
202
+ mounted[side].editor.setLabel(label);
203
+ }
204
+ }
205
+ });
206
+ applied.current = { theme, wrap, label };
207
+ }, [mounted, engine, theme, wrap, label]);
208
+ useLayoutEffect(() => {
209
+ if (mounted === null || mounted.old.engine !== engine) {
210
+ return;
211
+ }
212
+ const refresh = () => {
213
+ for (const side of SIDES) {
214
+ mounted[side].editor.setLineTokens((line) => {
215
+ const row = current.current.display[side].rows[line];
216
+ return row === undefined ? null : current.current.tokens?.get(side, row[side].index);
217
+ });
218
+ }
219
+ };
220
+ refresh();
221
+ const ownerWindow = oldElement.current?.ownerDocument.defaultView;
222
+ let frame;
223
+ let pending = false;
224
+ let stopped = false;
225
+ const schedule = () => {
226
+ if (pending) {
227
+ return;
228
+ }
229
+ pending = true;
230
+ const paint = () => {
231
+ pending = false;
232
+ if (!stopped) {
233
+ refresh();
234
+ }
235
+ };
236
+ if (ownerWindow?.requestAnimationFrame !== undefined) {
237
+ frame = ownerWindow.requestAnimationFrame(paint);
238
+ }
239
+ else {
240
+ queueMicrotask(paint);
241
+ }
242
+ };
243
+ const stop = tokens?.subscribe(schedule);
244
+ return () => {
245
+ stopped = true;
246
+ stop?.();
247
+ if (frame !== undefined) {
248
+ ownerWindow?.cancelAnimationFrame?.(frame);
249
+ }
250
+ };
251
+ }, [mounted, engine, display, tokens]);
252
+ useLayoutEffect(() => {
253
+ if (mounted === null || mounted.old.engine !== engine) {
254
+ return;
255
+ }
256
+ const stops = SIDES.map((side) => onMount?.(mounted[side].editor, side));
257
+ return () => {
258
+ for (const stop of stops) {
259
+ stop?.();
260
+ }
261
+ };
262
+ }, [mounted, engine, onMount]);
263
+ const limit = maxHeight !== undefined && Number.isFinite(maxHeight) && maxHeight > 0 ? maxHeight : Infinity;
264
+ if (failure !== null) {
265
+ throw failure.error;
266
+ }
267
+ return (_jsx("div", { className: `adecore-editor-diff adecore-editor-diff-split ${className ?? ''}`, ref: ref, role: "group", "aria-label": label, "data-scroll": fill || height > limit, style: { height: fill ? '100%' : Math.min(height, limit) }, children: SIDES.map((side) => (_jsxs("div", { className: "adecore-editor-diff-side", "data-side": side, role: "group", "aria-label": t(`diff.${side}Side`), onWheelCapture: () => {
268
+ mounted?.drive(side);
269
+ }, onFocusCapture: () => {
270
+ mounted?.drive(side);
271
+ }, onPointerDownCapture: () => {
272
+ mounted?.drive(side);
273
+ }, onKeyDownCapture: () => {
274
+ mounted?.drive(side);
275
+ }, children: [_jsx("div", { ref: side === 'old' ? oldElement : newElement, className: "adecore-editor-diff-surface" }), mounted !== null && mounted[side].engine === engine && (_jsx(DiffOverlays, { mounted: mounted[side], display: display[side], unfold: unfold, blocked: blocked }))] }, side))) }));
276
+ }
@@ -1,5 +1,8 @@
1
1
  import type { EditorLanguage } from './editor-language.ts';
2
2
  import type { SymbolsView } from './popups.ts';
3
+ export declare function SymbolBadge({ kind }: {
4
+ kind: number;
5
+ }): import("react").JSX.Element;
3
6
  export declare function SymbolPicker({ language, view }: {
4
7
  language: EditorLanguage;
5
8
  view: SymbolsView;
@@ -15,7 +15,8 @@ const TONES = {
15
15
  other: 'bg-surface-hover text-text-muted'
16
16
  };
17
17
  const SEARCH_DELAY_MS = 200;
18
- function Badge({ kind }) {
18
+ /* The letter badge of a symbol kind, tinted by what the symbol is. */
19
+ export function SymbolBadge({ kind }) {
19
20
  return (_jsx("span", { className: `grid size-4 shrink-0 place-items-center rounded-sm font-mono text-xs font-semibold ${TONES[toneOfKind(kind)]}`, children: letterOfKind(kind) }));
20
21
  }
21
22
  /*
@@ -94,14 +95,14 @@ export function SymbolPicker({ language, view }) {
94
95
  }, onKeyDown: onKeyDown, onBlur: () => language.symbolPicker.close() }), _jsx("span", { className: "shrink-0 text-xs text-text-faint", children: language.shortcuts.goToSymbol === null ? '' : formatShortcut(language.shortcuts.goToSymbol, language.apple) })] }), _jsxs("div", { role: "listbox", className: "max-h-[320px] overflow-y-auto p-1", children: [mode.mode === 'line' && (_jsx("div", { className: "px-2 py-1.5 text-xs text-text-muted", children: mode.line === null ? t('language.symbols.lineHint') : t('language.symbols.goToLine', { line: formatNumber(mode.line) }) })), mode.mode === 'workspace' &&
95
96
  places.map((place, index) => {
96
97
  const path = fileUriToPath(place.uri);
97
- return (_jsxs("button", { ref: index === active ? activeRow : undefined, type: "button", role: "option", "aria-selected": index === active, "data-active": index === active, className: "flex h-7 w-full items-center gap-2 rounded-md px-2 text-left text-xs cursor-row", onClick: () => choose(index), children: [_jsx(Badge, { kind: place.kind }), _jsx("span", { className: "shrink-0", children: place.name }), _jsx("span", { className: "min-w-0 truncate font-mono text-text-faint", children: place.container }), _jsxs("span", { className: "ml-auto shrink-0 font-mono text-text-faint", children: [path === null ? '' : basenameOf(path), ":", formatNumber(place.line + 1)] })] }, place.id));
98
+ return (_jsxs("button", { ref: index === active ? activeRow : undefined, type: "button", role: "option", "aria-selected": index === active, "data-active": index === active, className: "flex h-7 w-full items-center gap-2 rounded-md px-2 text-left text-xs cursor-row", onClick: () => choose(index), children: [_jsx(SymbolBadge, { kind: place.kind }), _jsx("span", { className: "shrink-0", children: place.name }), _jsx("span", { className: "min-w-0 truncate font-mono text-text-faint", children: place.container }), _jsxs("span", { className: "ml-auto shrink-0 font-mono text-text-faint", children: [path === null ? '' : basenameOf(path), ":", formatNumber(place.line + 1)] })] }, place.id));
98
99
  }), mode.mode === 'symbol' &&
99
100
  groups.map((group) => {
100
101
  const start = offset;
101
102
  offset += group.entries.length;
102
103
  return (_jsxs("div", { role: "group", children: [_jsx("div", { className: "px-2 pt-1.5 pb-0.5 text-xs font-medium text-text-faint", children: t(`language.symbols.groups.${group.group}`) }), group.entries.map((entry, index) => {
103
104
  const position = start + index;
104
- return (_jsxs("button", { ref: position === active ? activeRow : undefined, type: "button", role: "option", "aria-selected": position === active, "data-active": position === active, className: "flex h-7 w-full items-center gap-2 rounded-md px-2 text-left text-xs cursor-row", onClick: () => choose(position), children: [_jsx(Badge, { kind: entry.kind }), _jsx("span", { className: "shrink-0", children: entry.name }), _jsx("span", { className: "min-w-0 truncate font-mono text-text-faint", children: entry.detail }), entry.container !== '' && _jsx("span", { className: "min-w-0 truncate text-text-faint", children: entry.container }), _jsx("span", { className: "ml-auto shrink-0 font-mono text-text-faint", children: formatNumber(entry.line + 1) })] }, entry.id));
105
+ return (_jsxs("button", { ref: position === active ? activeRow : undefined, type: "button", role: "option", "aria-selected": position === active, "data-active": position === active, className: "flex h-7 w-full items-center gap-2 rounded-md px-2 text-left text-xs cursor-row", onClick: () => choose(position), children: [_jsx(SymbolBadge, { kind: entry.kind }), _jsx("span", { className: "shrink-0", children: entry.name }), _jsx("span", { className: "min-w-0 truncate font-mono text-text-faint", children: entry.detail }), entry.container !== '' && _jsx("span", { className: "min-w-0 truncate text-text-faint", children: entry.container }), _jsx("span", { className: "ml-auto shrink-0 font-mono text-text-faint", children: formatNumber(entry.line + 1) })] }, entry.id));
105
106
  })] }, group.group));
106
107
  }), mode.mode === 'symbol' && flat.length === 0 && (_jsx("div", { className: "px-2 py-3 text-center text-xs text-text-muted", children: t('language.symbols.none') })), mode.mode === 'workspace' && places.length === 0 && (_jsx("div", { className: "px-2 py-3 text-center text-xs text-text-muted", children: mode.text === '' ? t('language.symbols.workspaceHint') : t('language.symbols.none') }))] }), _jsxs("div", { className: "flex items-center gap-3 border-t border-border px-3 py-1.5 text-xs whitespace-nowrap text-text-faint", children: [_jsxs("span", { children: ["\u2191\u2193 ", t('language.symbols.navigate')] }), _jsxs("span", { children: ["\u21B5 ", t('language.symbols.open')] }), _jsxs("button", { type: "button", className: "ml-auto hover:text-text", onClick: () => setInput('#'), children: ["# ", t('language.symbols.workspace')] }), _jsxs("button", { type: "button", className: "hover:text-text", onClick: () => setInput(':'), children: [": ", t('language.symbols.line')] })] })] }), document.body);
107
108
  }