@wallarm-org/design-system 1.30.0 → 1.31.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 (123) hide show
  1. package/dist/components/CodeEditor/CodeEditorContent.d.ts +17 -0
  2. package/dist/components/CodeEditor/CodeEditorContent.js +197 -0
  3. package/dist/components/CodeEditor/CodeEditorContext.d.ts +17 -0
  4. package/dist/components/CodeEditor/CodeEditorContext.js +8 -0
  5. package/dist/components/CodeEditor/CodeEditorRoot.d.ts +77 -0
  6. package/dist/components/CodeEditor/CodeEditorRoot.js +203 -0
  7. package/dist/components/CodeEditor/classes.d.ts +21 -0
  8. package/dist/components/CodeEditor/classes.js +41 -0
  9. package/dist/components/CodeEditor/engine/SearchPanel.d.ts +13 -0
  10. package/dist/components/CodeEditor/engine/SearchPanel.js +201 -0
  11. package/dist/components/CodeEditor/engine/adapterPainter.d.ts +23 -0
  12. package/dist/components/CodeEditor/engine/adapterPainter.js +110 -0
  13. package/dist/components/CodeEditor/engine/babelSyntax.d.ts +15 -0
  14. package/dist/components/CodeEditor/engine/babelSyntax.js +54 -0
  15. package/dist/components/CodeEditor/engine/completion.d.ts +17 -0
  16. package/dist/components/CodeEditor/engine/completion.js +129 -0
  17. package/dist/components/CodeEditor/engine/contentAttributes.d.ts +12 -0
  18. package/dist/components/CodeEditor/engine/contentAttributes.js +24 -0
  19. package/dist/components/CodeEditor/engine/diagnostics.d.ts +73 -0
  20. package/dist/components/CodeEditor/engine/diagnostics.js +327 -0
  21. package/dist/components/CodeEditor/engine/diff.d.ts +37 -0
  22. package/dist/components/CodeEditor/engine/diff.js +145 -0
  23. package/dist/components/CodeEditor/engine/folds.d.ts +25 -0
  24. package/dist/components/CodeEditor/engine/folds.js +458 -0
  25. package/dist/components/CodeEditor/engine/gutters.d.ts +22 -0
  26. package/dist/components/CodeEditor/engine/gutters.js +160 -0
  27. package/dist/components/CodeEditor/engine/index.d.ts +12 -0
  28. package/dist/components/CodeEditor/engine/index.js +387 -0
  29. package/dist/components/CodeEditor/engine/languages/http/index.d.ts +20 -0
  30. package/dist/components/CodeEditor/engine/languages/http/index.js +69 -0
  31. package/dist/components/CodeEditor/engine/languages/http/parser.d.ts +2 -0
  32. package/dist/components/CodeEditor/engine/languages/http/parser.js +31 -0
  33. package/dist/components/CodeEditor/engine/languages/http/parser.terms.d.ts +1 -0
  34. package/dist/components/CodeEditor/engine/languages/http/parser.terms.js +2 -0
  35. package/dist/components/CodeEditor/engine/languages/index.d.ts +8 -0
  36. package/dist/components/CodeEditor/engine/languages/index.js +41 -0
  37. package/dist/components/CodeEditor/engine/languages/json.d.ts +8 -0
  38. package/dist/components/CodeEditor/engine/languages/json.js +11 -0
  39. package/dist/components/CodeEditor/engine/languages/jsonPointers.d.ts +47 -0
  40. package/dist/components/CodeEditor/engine/languages/jsonPointers.js +125 -0
  41. package/dist/components/CodeEditor/engine/languages/yaml.d.ts +4 -0
  42. package/dist/components/CodeEditor/engine/languages/yaml.js +11 -0
  43. package/dist/components/CodeEditor/engine/lines.d.ts +22 -0
  44. package/dist/components/CodeEditor/engine/lines.js +131 -0
  45. package/dist/components/CodeEditor/engine/luaSyntax.d.ts +14 -0
  46. package/dist/components/CodeEditor/engine/luaSyntax.js +36 -0
  47. package/dist/components/CodeEditor/engine/positions.d.ts +19 -0
  48. package/dist/components/CodeEditor/engine/positions.js +22 -0
  49. package/dist/components/CodeEditor/engine/schema/complete.d.ts +12 -0
  50. package/dist/components/CodeEditor/engine/schema/complete.js +211 -0
  51. package/dist/components/CodeEditor/engine/schema/hover.d.ts +12 -0
  52. package/dist/components/CodeEditor/engine/schema/hover.js +73 -0
  53. package/dist/components/CodeEditor/engine/schema/loadSchema.d.ts +19 -0
  54. package/dist/components/CodeEditor/engine/schema/loadSchema.js +32 -0
  55. package/dist/components/CodeEditor/engine/schema/validate.d.ts +9 -0
  56. package/dist/components/CodeEditor/engine/schema/validate.js +67 -0
  57. package/dist/components/CodeEditor/engine/search.d.ts +13 -0
  58. package/dist/components/CodeEditor/engine/search.js +84 -0
  59. package/dist/components/CodeEditor/engine/searchMatches.d.ts +8 -0
  60. package/dist/components/CodeEditor/engine/searchMatches.js +15 -0
  61. package/dist/components/CodeEditor/engine/theme.d.ts +8 -0
  62. package/dist/components/CodeEditor/engine/theme.js +89 -0
  63. package/dist/components/CodeEditor/engine/types.d.ts +44 -0
  64. package/dist/components/CodeEditor/engine/types.js +0 -0
  65. package/dist/components/CodeEditor/hooks/useCodeEditor.d.ts +6 -0
  66. package/dist/components/CodeEditor/hooks/useCodeEditor.js +3 -0
  67. package/dist/components/CodeEditor/index.d.ts +6 -0
  68. package/dist/components/CodeEditor/index.js +5 -0
  69. package/dist/components/CodeEditor/lib/PortalOutlet.d.ts +11 -0
  70. package/dist/components/CodeEditor/lib/PortalOutlet.js +11 -0
  71. package/dist/components/CodeEditor/lib/httpCompletions.d.ts +7 -0
  72. package/dist/components/CodeEditor/lib/httpCompletions.js +102 -0
  73. package/dist/components/CodeEditor/lib/httpCompletionsData.d.ts +29 -0
  74. package/dist/components/CodeEditor/lib/httpCompletionsData.js +650 -0
  75. package/dist/components/CodeEditor/lib/keyboardHint.d.ts +5 -0
  76. package/dist/components/CodeEditor/lib/keyboardHint.js +2 -0
  77. package/dist/components/CodeEditor/lib/loadEngine.d.ts +7 -0
  78. package/dist/components/CodeEditor/lib/loadEngine.js +9 -0
  79. package/dist/components/CodeEditor/lib/portalRegistry.d.ts +20 -0
  80. package/dist/components/CodeEditor/lib/portalRegistry.js +47 -0
  81. package/dist/components/CodeEditor/lib/splitContentProps.d.ts +12 -0
  82. package/dist/components/CodeEditor/lib/splitContentProps.js +28 -0
  83. package/dist/components/CodeEditor/types.d.ts +72 -0
  84. package/dist/components/CodeEditor/types.js +0 -0
  85. package/dist/components/CodeSnippet/CodeSnippetCode.js +6 -23
  86. package/dist/components/CodeSnippet/CodeSnippetCopyButton.js +4 -3
  87. package/dist/components/CodeSnippet/CodeSnippetFrameContext.d.ts +25 -0
  88. package/dist/components/CodeSnippet/CodeSnippetFrameContext.js +3 -0
  89. package/dist/components/CodeSnippet/CodeSnippetFullscreenButton.js +2 -2
  90. package/dist/components/CodeSnippet/CodeSnippetRoot.d.ts +3 -5
  91. package/dist/components/CodeSnippet/CodeSnippetRoot.js +56 -50
  92. package/dist/components/CodeSnippet/CodeSnippetShowMoreButton.js +7 -5
  93. package/dist/components/CodeSnippet/CodeSnippetWrapButton.js +2 -2
  94. package/dist/components/CodeSnippet/adapters/highlightjs.js +1 -0
  95. package/dist/components/CodeSnippet/adapters/prism.js +3 -1
  96. package/dist/components/CodeSnippet/adapters/shiki.js +1 -0
  97. package/dist/components/CodeSnippet/adapters/types.d.ts +3 -3
  98. package/dist/components/CodeSnippet/classes.d.ts +3 -0
  99. package/dist/components/CodeSnippet/classes.js +14 -0
  100. package/dist/components/CodeSnippet/hooks/index.d.ts +1 -0
  101. package/dist/components/CodeSnippet/hooks/index.js +1 -0
  102. package/dist/components/CodeSnippet/hooks/useCodeSnippetFrame.d.ts +2 -0
  103. package/dist/components/CodeSnippet/hooks/useCodeSnippetFrame.js +8 -0
  104. package/dist/components/CodeSnippet/index.d.ts +2 -1
  105. package/dist/components/CodeSnippet/index.js +1 -1
  106. package/dist/components/CodeSnippet/internal/CodeSnippetFrame.d.ts +22 -0
  107. package/dist/components/CodeSnippet/internal/CodeSnippetFrame.js +81 -0
  108. package/dist/components/CodeSnippet/internal/CodeToken.d.ts +2 -1
  109. package/dist/components/CodeSnippet/internal/CodeToken.js +1 -1
  110. package/dist/components/CodeSnippet/internal/FoldSummary.d.ts +11 -0
  111. package/dist/components/CodeSnippet/internal/FoldSummary.js +27 -0
  112. package/dist/components/CodeSnippet/internal/FoldToggle.d.ts +2 -0
  113. package/dist/components/CodeSnippet/internal/FoldToggle.js +2 -1
  114. package/dist/components/CodeSnippet/internal/index.d.ts +1 -0
  115. package/dist/components/CodeSnippet/internal/index.js +1 -0
  116. package/dist/components/CodeSnippet/lib/foldUtils.d.ts +9 -2
  117. package/dist/components/CodeSnippet/lib/foldUtils.js +2 -2
  118. package/dist/components/CodeSnippet/lib/showMore.d.ts +7 -0
  119. package/dist/components/CodeSnippet/lib/showMore.js +7 -0
  120. package/dist/components/Copyable/Copyable.d.ts +5 -2
  121. package/dist/components/Copyable/Copyable.js +1 -1
  122. package/dist/metadata/components.json +1235 -5
  123. package/package.json +24 -1
@@ -0,0 +1,17 @@
1
+ import type { FC, HTMLAttributes, Ref } from 'react';
2
+ import { type TestableProps } from '../../utils/testId';
3
+ type CodeEditorContentNativeProps = Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'onChange' | 'contentEditable' | 'role' | 'defaultValue'>;
4
+ export interface CodeEditorContentProps extends CodeEditorContentNativeProps, TestableProps {
5
+ /** Content wrapper element */
6
+ ref?: Ref<HTMLDivElement>;
7
+ /** Show the line-number gutter (CodeSnippet's `<CodeSnippetLineNumbers />` equivalent) */
8
+ lineNumbers?: boolean;
9
+ }
10
+ /**
11
+ * Editing surface of `CodeEditorRoot`. Loads the CodeMirror engine on mount and
12
+ * shows the value as static text until it is ready. `data-*`, `aria-*`, `id`,
13
+ * `title` and `tabIndex` land on the typing surface; `className`, `style`, `ref`
14
+ * and event handlers stay on this wrapper (events from the editor bubble to it).
15
+ */
16
+ export declare const CodeEditorContent: FC<CodeEditorContentProps>;
17
+ export {};
@@ -0,0 +1,197 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useMemo, useRef, useState } from "react";
3
+ import { flushSync } from "react-dom";
4
+ import { cn } from "../../utils/cn.js";
5
+ import { useTestId } from "../../utils/testId.js";
6
+ import { useCodeSnippetFrame } from "../CodeSnippet/hooks/index.js";
7
+ import { useCodeEditorContext } from "./CodeEditorContext.js";
8
+ import { codeEditorContentVariants, codeEditorFallbackCodeVariants, codeEditorFallbackGutterVariants, codeEditorFallbackGuttersVariants, codeEditorFallbackLineVariants, codeEditorFallbackVariants, codeEditorHostVariants } from "./classes.js";
9
+ import { loadEngine } from "./lib/loadEngine.js";
10
+ import { PortalOutlet } from "./lib/PortalOutlet.js";
11
+ import { createPortalRegistry } from "./lib/portalRegistry.js";
12
+ import { splitContentProps } from "./lib/splitContentProps.js";
13
+ const ROW_HEIGHT = 20;
14
+ const VERTICAL_PADDING = 16;
15
+ const fallbackGuttersFor = (options)=>{
16
+ const configs = Object.values(options.lines);
17
+ const diff = void 0 !== options.original;
18
+ const { folds } = options;
19
+ return {
20
+ stick: diff || configs.some((line)=>null != line.color),
21
+ folds: void 0 !== folds && !(Array.isArray(folds) && 0 === folds.length),
22
+ prefix: diff || configs.some((line)=>null != line.prefix)
23
+ };
24
+ };
25
+ const buildFallbackRows = (value, startingLineNumber, maxHeight)=>{
26
+ const lines = value.split('\n');
27
+ const visible = null === maxHeight ? lines : lines.slice(0, Math.max(0, Math.round((maxHeight - VERTICAL_PADDING) / ROW_HEIGHT)));
28
+ return visible.map((text, index)=>({
29
+ number: startingLineNumber + index,
30
+ text
31
+ }));
32
+ };
33
+ const CodeEditorContent = ({ ref, lineNumbers = false, className, 'data-testid': testIdProp, ...props })=>{
34
+ const testId = useTestId('content', testIdProp);
35
+ const fallbackTestId = useTestId('fallback');
36
+ const fallbackGuttersTestId = useTestId('fallback-gutters');
37
+ const { options, callbacks, setHandle } = useCodeEditorContext();
38
+ const { isFullscreen } = useCodeSnippetFrame();
39
+ const [registry] = useState(createPortalRegistry);
40
+ const [handle, setLocalHandle] = useState(null);
41
+ const [loadFailed, setLoadFailed] = useState(false);
42
+ const hostRef = useRef(null);
43
+ const { contentAttributes: routedAttributes, wrapperProps } = splitContentProps(props);
44
+ const attributesKey = JSON.stringify(routedAttributes);
45
+ const contentAttributes = useMemo(()=>JSON.parse(attributesKey), [
46
+ attributesKey
47
+ ]);
48
+ const engineOptions = useMemo(()=>({
49
+ ...options,
50
+ lineNumbers,
51
+ contentAttributes
52
+ }), [
53
+ options,
54
+ lineNumbers,
55
+ contentAttributes
56
+ ]);
57
+ const optionsRef = useRef(engineOptions);
58
+ useEffect(()=>{
59
+ optionsRef.current = engineOptions;
60
+ }, [
61
+ engineOptions
62
+ ]);
63
+ useEffect(()=>{
64
+ const host = hostRef.current;
65
+ if (!host) return;
66
+ let cancelled = false;
67
+ let created = null;
68
+ loadEngine().then((engine)=>{
69
+ if (cancelled) return;
70
+ created = engine.createEditor(host, optionsRef.current, {
71
+ ...callbacks,
72
+ portals: registry
73
+ });
74
+ const mounted = created;
75
+ flushSync(()=>{
76
+ setHandle(mounted);
77
+ setLocalHandle(mounted);
78
+ });
79
+ }, (error)=>{
80
+ if (cancelled) return;
81
+ console.error('[CodeEditor] Failed to load the editor engine; showing read-only text.', error);
82
+ setLoadFailed(true);
83
+ });
84
+ return ()=>{
85
+ cancelled = true;
86
+ if (created) {
87
+ created.destroy();
88
+ setHandle(null);
89
+ }
90
+ setLocalHandle(null);
91
+ };
92
+ }, [
93
+ callbacks,
94
+ registry,
95
+ setHandle
96
+ ]);
97
+ useEffect(()=>{
98
+ handle?.update(engineOptions);
99
+ }, [
100
+ handle,
101
+ engineOptions
102
+ ]);
103
+ useEffect(()=>{
104
+ handle?.view.requestMeasure();
105
+ }, [
106
+ handle,
107
+ isFullscreen
108
+ ]);
109
+ const hasAccessibleName = void 0 !== contentAttributes['aria-label'] || void 0 !== contentAttributes['aria-labelledby'];
110
+ useEffect(()=>{
111
+ if ('production' !== process.env.NODE_ENV && !hasAccessibleName) console.warn('[CodeEditor] CodeEditorContent has no accessible name. Pass `aria-label` or `aria-labelledby`.');
112
+ }, [
113
+ hasAccessibleName
114
+ ]);
115
+ const fallbackRows = null === handle ? buildFallbackRows(options.value, options.startingLineNumber, options.maxHeight) : null;
116
+ const fallbackGutters = fallbackGuttersFor(options);
117
+ const hasGutter = lineNumbers || fallbackGutters.stick || fallbackGutters.folds || fallbackGutters.prefix;
118
+ const isDiff = void 0 !== options.original;
119
+ return /*#__PURE__*/ jsxs("div", {
120
+ ...wrapperProps,
121
+ ref: ref,
122
+ "data-slot": "code-editor-content",
123
+ "data-testid": testId,
124
+ "data-ds-suppress-parent-click": "",
125
+ className: cn(codeEditorContentVariants(), className),
126
+ children: [
127
+ fallbackRows && /*#__PURE__*/ jsxs("pre", {
128
+ "data-testid": fallbackTestId,
129
+ "aria-busy": loadFailed ? 'false' : 'true',
130
+ className: codeEditorFallbackVariants(),
131
+ children: [
132
+ hasGutter && /*#__PURE__*/ jsxs("span", {
133
+ "aria-hidden": "true",
134
+ "data-testid": fallbackGuttersTestId,
135
+ className: codeEditorFallbackGuttersVariants(),
136
+ children: [
137
+ fallbackGutters.stick && /*#__PURE__*/ jsx("span", {
138
+ className: codeEditorFallbackGutterVariants({
139
+ column: 'stick'
140
+ })
141
+ }),
142
+ lineNumbers && /*#__PURE__*/ jsx("span", {
143
+ className: codeEditorFallbackGutterVariants({
144
+ column: 'lineNumbers'
145
+ }),
146
+ children: fallbackRows.map((row)=>/*#__PURE__*/ jsx("span", {
147
+ className: codeEditorFallbackLineVariants(),
148
+ children: row.number
149
+ }, row.number))
150
+ }),
151
+ fallbackGutters.folds && /*#__PURE__*/ jsx("span", {
152
+ className: codeEditorFallbackGutterVariants({
153
+ column: 'folds'
154
+ })
155
+ }),
156
+ fallbackGutters.prefix && /*#__PURE__*/ jsxs("span", {
157
+ className: codeEditorFallbackGutterVariants({
158
+ column: 'prefix'
159
+ }),
160
+ children: [
161
+ fallbackRows.map((row)=>/*#__PURE__*/ jsx("span", {
162
+ className: codeEditorFallbackLineVariants(),
163
+ children: isDiff ? null : options.lines[row.number]?.prefix
164
+ }, row.number)),
165
+ isDiff && /*#__PURE__*/ jsx("span", {
166
+ className: "invisible h-0 overflow-hidden",
167
+ children: "+"
168
+ })
169
+ ]
170
+ })
171
+ ]
172
+ }),
173
+ /*#__PURE__*/ jsx("code", {
174
+ className: codeEditorFallbackCodeVariants({
175
+ hasGutter
176
+ }),
177
+ children: fallbackRows.map((row)=>/*#__PURE__*/ jsx("span", {
178
+ className: codeEditorFallbackLineVariants({
179
+ wrapLines: options.wrapLines
180
+ }),
181
+ children: row.text
182
+ }, row.number))
183
+ })
184
+ ]
185
+ }),
186
+ /*#__PURE__*/ jsx("div", {
187
+ ref: hostRef,
188
+ className: codeEditorHostVariants()
189
+ }),
190
+ /*#__PURE__*/ jsx(PortalOutlet, {
191
+ registry: registry
192
+ })
193
+ ]
194
+ });
195
+ };
196
+ CodeEditorContent.displayName = 'CodeEditorContent';
197
+ export { CodeEditorContent };
@@ -0,0 +1,17 @@
1
+ import type { EditorHandle, EngineCallbacks, EngineOptions } from './engine/types';
2
+ import type { CodeEditorApi } from './types';
3
+ /** Internal bridge between `CodeEditorRoot` (state owner) and `CodeEditorContent` (engine host). */
4
+ export interface CodeEditorContextValue {
5
+ /** Engine options owned by Root; Content adds `lineNumbers` and `contentAttributes` */
6
+ options: Omit<EngineOptions, 'lineNumbers' | 'contentAttributes' | 'maxHeight'> & {
7
+ maxHeight: number | null;
8
+ };
9
+ /** Stable callbacks (same identity for the Root's lifetime) */
10
+ callbacks: Omit<EngineCallbacks, 'portals'>;
11
+ /** Content registers the live handle after `createEditor()` and clears it on destroy */
12
+ setHandle: (handle: EditorHandle | null) => void;
13
+ /** Stable object delegating to the current handle (no-ops before the engine loads) */
14
+ api: CodeEditorApi;
15
+ }
16
+ export declare const CodeEditorContext: import("react").Context<CodeEditorContextValue | null>;
17
+ export declare const useCodeEditorContext: () => CodeEditorContextValue;
@@ -0,0 +1,8 @@
1
+ import { createContext, useContext } from "react";
2
+ const CodeEditorContext = createContext(null);
3
+ const useCodeEditorContext = ()=>{
4
+ const context = useContext(CodeEditorContext);
5
+ if (!context) throw new Error('CodeEditor components must be used within CodeEditorRoot');
6
+ return context;
7
+ };
8
+ export { CodeEditorContext, useCodeEditorContext };
@@ -0,0 +1,77 @@
1
+ import type { HTMLAttributes, ReactNode, Ref } from 'react';
2
+ import type { VariantProps } from 'class-variance-authority';
3
+ import { type TestableProps } from '../../utils/testId';
4
+ import type { LineConfig } from '../CodeSnippet/CodeSnippetContext';
5
+ import { codeSnippetRootVariants } from '../CodeSnippet/classes';
6
+ import type { CodeEditorApi, CodeEditorCompletionSource, CodeEditorDiagnostic, CodeEditorFolds, CodeEditorLanguage, JsonSchema } from './types';
7
+ type CodeEditorRootNativeProps = Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'onChange' | 'defaultValue' | 'onCopy'>;
8
+ export interface CodeEditorRootProps extends CodeEditorRootNativeProps, TestableProps, VariantProps<typeof codeSnippetRootVariants> {
9
+ /** Root element, including in fullscreen */
10
+ ref?: Ref<HTMLDivElement>;
11
+ /** Controlled document */
12
+ value?: string;
13
+ /** Uncontrolled initial document (controlled vs uncontrolled is locked on first render) */
14
+ defaultValue?: string;
15
+ /** Fired for user edits only, never for external `value` syncs */
16
+ onChange?: (value: string) => void;
17
+ /** Passed verbatim to the syntax adapter; selects the structural parser */
18
+ language?: CodeEditorLanguage;
19
+ /**
20
+ * Document identity: changing it swaps to that document's cached state (undo history,
21
+ * selection, folds). Requires a controlled `value`: when the id changes, `value` must already
22
+ * hold that document's text (an uncached id starts from `value`). In uncontrolled mode the new
23
+ * document would be seeded with the previous document's text.
24
+ */
25
+ documentId?: string;
26
+ /** Focusable, selectable, searchable, copyable — but not editable by the user */
27
+ readOnly?: boolean;
28
+ /** Offsets gutter numbers; `lines`, `folds`, `diagnostics` use absolute numbers */
29
+ startingLineNumber?: number;
30
+ /**
31
+ * Per-line configuration keyed by absolute line number (static, see spec D6).
32
+ * Compared by identity: memoise it (or hoist it to a constant) — a new object
33
+ * every render reconfigures the lines and gutters on every render.
34
+ */
35
+ lines?: Record<number, LineConfig>;
36
+ /**
37
+ * Fold regions, or a function re-run after edits; collapsed state is kept by `id`.
38
+ * Compared by identity: memoise the array or pass a stable function (e.g. `getHttpFolds`) —
39
+ * an inline array/arrow reconfigures folds on every render and bypasses the re-run debounce.
40
+ */
41
+ folds?: CodeEditorFolds;
42
+ /** Controlled line wrapping */
43
+ wrapLines?: boolean;
44
+ /** Uncontrolled initial line wrapping */
45
+ defaultWrapLines?: boolean;
46
+ /** Fired when the wrap button toggles wrapping */
47
+ onWrapLinesChange?: (wrap: boolean) => void;
48
+ /** Height clamp in rows; auto-renders `CodeSnippetShowMoreButton` unless one is a direct child */
49
+ maxLines?: number;
50
+ /** Enables diff mode against this text */
51
+ original?: string;
52
+ /** JSON Schema for the document (`json`) or the JSON body (`http`) */
53
+ schema?: JsonSchema;
54
+ /**
55
+ * Consumer completion sources, added after the built-in ones. Compared by identity: a new
56
+ * array reconfigures autocomplete and closes an open list, so keep it stable (module constant
57
+ * or `useMemo`).
58
+ */
59
+ completions?: CodeEditorCompletionSource[];
60
+ /** External diagnostics, merged with syntax and schema ones */
61
+ diagnostics?: CodeEditorDiagnostic[];
62
+ /** Fired when the merged diagnostics change */
63
+ onDiagnosticsChange?: (diagnostics: CodeEditorDiagnostic[]) => void;
64
+ /** Imperative handle */
65
+ apiRef?: Ref<CodeEditorApi>;
66
+ /** Nonce for the style tags the editor injects */
67
+ cspNonce?: string;
68
+ /** Fired by `CodeSnippetCopyButton` after a copy, with the current document */
69
+ onCopy?: (value: string) => void;
70
+ /** Chrome (header, floating actions, show more) and `CodeEditorContent` */
71
+ children?: ReactNode;
72
+ }
73
+ export declare function CodeEditorRoot({ ref, value: valueProp, defaultValue, onChange, language, documentId, size, readOnly, startingLineNumber, lines, folds, wrapLines: wrapLinesProp, defaultWrapLines, onWrapLinesChange, maxLines, original, schema, completions, diagnostics, onDiagnosticsChange, apiRef, cspNonce, onCopy, className, children, 'data-testid': testId, ...props }: CodeEditorRootProps): import("react").JSX.Element;
74
+ export declare namespace CodeEditorRoot {
75
+ var displayName: string;
76
+ }
77
+ export {};
@@ -0,0 +1,203 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
3
+ import { useControlled } from "../../hooks/useControlled.js";
4
+ import { cn } from "../../utils/cn.js";
5
+ import { TestIdProvider } from "../../utils/testId.js";
6
+ import { plainAdapter } from "../CodeSnippet/adapters/plain.js";
7
+ import { CodeSnippetFrameContext } from "../CodeSnippet/CodeSnippetFrameContext.js";
8
+ import { CodeSnippetShowMoreButton } from "../CodeSnippet/CodeSnippetShowMoreButton.js";
9
+ import { codeSnippetRootVariants } from "../CodeSnippet/classes.js";
10
+ import { useAdapter } from "../CodeSnippet/hooks/index.js";
11
+ import { CodeSnippetFrame } from "../CodeSnippet/internal/CodeSnippetFrame.js";
12
+ import { getHiddenLineCount, hasExplicitShowMoreButton, isClamped } from "../CodeSnippet/lib/showMore.js";
13
+ import { CodeEditorContext } from "./CodeEditorContext.js";
14
+ const EMPTY_LINES = {};
15
+ const EMPTY_COMPLETIONS = [];
16
+ const EMPTY_DIAGNOSTICS = [];
17
+ const ROW_HEIGHT = 20;
18
+ const VERTICAL_PADDING = 16;
19
+ const countLines = (value)=>{
20
+ let count = 1;
21
+ for(let index = value.indexOf('\n'); -1 !== index; index = value.indexOf('\n', index + 1))count += 1;
22
+ return count;
23
+ };
24
+ const CodeEditorRoot = ({ ref, value: valueProp, defaultValue = '', onChange, language = 'text', documentId, size = 'sm', readOnly = false, startingLineNumber = 1, lines = EMPTY_LINES, folds, wrapLines: wrapLinesProp, defaultWrapLines = false, onWrapLinesChange, maxLines = 0, original, schema, completions = EMPTY_COMPLETIONS, diagnostics = EMPTY_DIAGNOSTICS, onDiagnosticsChange, apiRef, cspNonce, onCopy, className, children, 'data-testid': testId, ...props })=>{
25
+ const adapterContext = useAdapter();
26
+ const adapter = adapterContext?.adapter ?? plainAdapter;
27
+ const [valueState, setValue] = useControlled({
28
+ controlled: valueProp,
29
+ default: defaultValue
30
+ });
31
+ const value = valueState ?? '';
32
+ const [wrapState, setWrapState] = useControlled({
33
+ controlled: wrapLinesProp,
34
+ default: defaultWrapLines
35
+ });
36
+ const wrapLines = wrapState ?? false;
37
+ const [isExpanded, setIsExpanded] = useState(false);
38
+ const [isFullscreen, setIsFullscreen] = useState(false);
39
+ const [engineRows, setEngineRows] = useState(null);
40
+ const latest = useRef({
41
+ value,
42
+ onChange,
43
+ onDiagnosticsChange,
44
+ onWrapLinesChange,
45
+ onCopy
46
+ });
47
+ useEffect(()=>{
48
+ latest.current = {
49
+ value,
50
+ onChange,
51
+ onDiagnosticsChange,
52
+ onWrapLinesChange,
53
+ onCopy
54
+ };
55
+ });
56
+ const documentIdWithoutValue = void 0 !== documentId && void 0 === valueProp;
57
+ const warnedDocumentId = useRef(false);
58
+ useEffect(()=>{
59
+ if ('production' === process.env.NODE_ENV) return;
60
+ if (!documentIdWithoutValue || warnedDocumentId.current) return;
61
+ warnedDocumentId.current = true;
62
+ console.warn("[CodeEditor] `documentId` requires a controlled `value`: in uncontrolled mode a new document starts from the previous document's text.");
63
+ }, [
64
+ documentIdWithoutValue
65
+ ]);
66
+ const handleRef = useRef(null);
67
+ const [api] = useState(()=>({
68
+ focus: ()=>handleRef.current?.api.focus(),
69
+ getValue: ()=>handleRef.current?.api.getValue() ?? latest.current.value,
70
+ insertText: (text)=>handleRef.current?.api.insertText(text),
71
+ openSearch: ()=>handleRef.current?.api.openSearch(),
72
+ foldAll: ()=>handleRef.current?.api.foldAll(),
73
+ unfoldAll: ()=>handleRef.current?.api.unfoldAll()
74
+ }));
75
+ useImperativeHandle(apiRef, ()=>api, [
76
+ api
77
+ ]);
78
+ const [callbacks] = useState(()=>({
79
+ onChange: (next)=>{
80
+ setValue(next);
81
+ latest.current.onChange?.(next);
82
+ },
83
+ onDiagnosticsChange: (next)=>latest.current.onDiagnosticsChange?.(next),
84
+ onVisibleRowCountChange: (rows)=>setEngineRows(rows)
85
+ }));
86
+ const setHandle = useCallback((handle)=>{
87
+ handleRef.current = handle;
88
+ if (null === handle) setEngineRows(null);
89
+ }, []);
90
+ const setWrapLines = useCallback((wrap)=>{
91
+ setWrapState(wrap);
92
+ latest.current.onWrapLinesChange?.(wrap);
93
+ }, [
94
+ setWrapState
95
+ ]);
96
+ const getCode = useCallback(()=>api.getValue(), [
97
+ api
98
+ ]);
99
+ const notifyCopied = useCallback(()=>latest.current.onCopy?.(api.getValue()), [
100
+ api
101
+ ]);
102
+ const lineCount = useMemo(()=>countLines(value), [
103
+ value
104
+ ]);
105
+ const hiddenLineCount = getHiddenLineCount(engineRows ?? lineCount, maxLines);
106
+ const maxHeight = isClamped(hiddenLineCount, isExpanded) ? maxLines * ROW_HEIGHT + VERTICAL_PADDING : null;
107
+ const resolvedSize = size ?? 'sm';
108
+ const frameValue = useMemo(()=>({
109
+ size: resolvedSize,
110
+ getCode,
111
+ notifyCopied,
112
+ wrapLines,
113
+ setWrapLines,
114
+ isFullscreen,
115
+ setIsFullscreen,
116
+ maxLines,
117
+ isExpanded,
118
+ setIsExpanded,
119
+ hiddenLineCount
120
+ }), [
121
+ resolvedSize,
122
+ getCode,
123
+ notifyCopied,
124
+ wrapLines,
125
+ setWrapLines,
126
+ isFullscreen,
127
+ maxLines,
128
+ isExpanded,
129
+ hiddenLineCount
130
+ ]);
131
+ const options = useMemo(()=>({
132
+ value,
133
+ documentId,
134
+ language,
135
+ readOnly,
136
+ wrapLines,
137
+ startingLineNumber,
138
+ lines,
139
+ folds,
140
+ adapter,
141
+ original,
142
+ schema,
143
+ completions,
144
+ diagnostics,
145
+ testId,
146
+ cspNonce,
147
+ maxHeight
148
+ }), [
149
+ value,
150
+ documentId,
151
+ language,
152
+ readOnly,
153
+ wrapLines,
154
+ startingLineNumber,
155
+ lines,
156
+ folds,
157
+ adapter,
158
+ original,
159
+ schema,
160
+ completions,
161
+ diagnostics,
162
+ testId,
163
+ cspNonce,
164
+ maxHeight
165
+ ]);
166
+ const editorContext = useMemo(()=>({
167
+ options,
168
+ callbacks,
169
+ setHandle,
170
+ api
171
+ }), [
172
+ options,
173
+ callbacks,
174
+ setHandle,
175
+ api
176
+ ]);
177
+ return /*#__PURE__*/ jsx(TestIdProvider, {
178
+ value: testId,
179
+ children: /*#__PURE__*/ jsx(CodeSnippetFrameContext.Provider, {
180
+ value: frameValue,
181
+ children: /*#__PURE__*/ jsx(CodeEditorContext.Provider, {
182
+ value: editorContext,
183
+ children: /*#__PURE__*/ jsxs(CodeSnippetFrame, {
184
+ ...props,
185
+ ref: ref,
186
+ "data-slot": "code-editor",
187
+ "data-testid": testId,
188
+ className: cn(codeSnippetRootVariants({
189
+ size
190
+ }), 'focus-within:ring-focus-primary focus-within:ring-2', className),
191
+ isFullscreen: isFullscreen,
192
+ setIsFullscreen: setIsFullscreen,
193
+ children: [
194
+ children,
195
+ maxLines > 0 && !hasExplicitShowMoreButton(children) && /*#__PURE__*/ jsx(CodeSnippetShowMoreButton, {})
196
+ ]
197
+ })
198
+ })
199
+ })
200
+ });
201
+ };
202
+ CodeEditorRoot.displayName = 'CodeEditorRoot';
203
+ export { CodeEditorRoot };
@@ -0,0 +1,21 @@
1
+ /** `CodeEditorContent` wrapper: fills the root's flex column (fullscreen) and clips by height. */
2
+ export declare const codeEditorContentVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
3
+ /** Element CodeMirror mounts into; `.cm-editor` fills it in the fullscreen column. */
4
+ export declare const codeEditorHostVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
5
+ /** Static text shown until the engine chunk resolves: CodeSnippet's 20px rows and `py-8`. */
6
+ export declare const codeEditorFallbackVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
7
+ /** Gutter group of the fallback: the columns below, then the 8px gap the editor leaves. */
8
+ export declare const codeEditorFallbackGuttersVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
9
+ /**
10
+ * Fallback gutter columns, same widths as the engine gutters so nothing shifts when the editor
11
+ * mounts (spec §7.2): colour stick, line numbers, fold toggles (16px + 4px padding), prefixes.
12
+ */
13
+ export declare const codeEditorFallbackGutterVariants: (props?: ({
14
+ column?: "folds" | "lineNumbers" | "prefix" | "stick" | null | undefined;
15
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
16
+ export declare const codeEditorFallbackCodeVariants: (props?: ({
17
+ hasGutter?: boolean | null | undefined;
18
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
19
+ export declare const codeEditorFallbackLineVariants: (props?: ({
20
+ wrapLines?: boolean | null | undefined;
21
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
@@ -0,0 +1,41 @@
1
+ import { cva } from "class-variance-authority";
2
+ const codeEditorContentVariants = cva('relative flex-1 min-h-0');
3
+ const codeEditorHostVariants = cva('h-full [&>.cm-editor]:h-full');
4
+ const codeEditorFallbackVariants = cva('m-0 flex overflow-hidden py-8 font-mono');
5
+ const codeEditorFallbackGuttersVariants = cva('mr-8 flex shrink-0 select-none');
6
+ const codeEditorFallbackGutterVariants = cva('flex shrink-0 flex-col', {
7
+ variants: {
8
+ column: {
9
+ stick: 'border-l-2 border-transparent pl-12',
10
+ lineNumbers: 'px-8 text-right text-text-secondary',
11
+ folds: 'w-24',
12
+ prefix: 'px-8 text-center'
13
+ }
14
+ },
15
+ defaultVariants: {
16
+ column: 'lineNumbers'
17
+ }
18
+ });
19
+ const codeEditorFallbackCodeVariants = cva('flex min-w-0 flex-1 flex-col pr-12', {
20
+ variants: {
21
+ hasGutter: {
22
+ true: '',
23
+ false: 'pl-12'
24
+ }
25
+ },
26
+ defaultVariants: {
27
+ hasGutter: false
28
+ }
29
+ });
30
+ const codeEditorFallbackLineVariants = cva('block min-h-lh leading-sm', {
31
+ variants: {
32
+ wrapLines: {
33
+ true: 'whitespace-pre-wrap break-all',
34
+ false: 'whitespace-pre'
35
+ }
36
+ },
37
+ defaultVariants: {
38
+ wrapLines: false
39
+ }
40
+ });
41
+ export { codeEditorContentVariants, codeEditorFallbackCodeVariants, codeEditorFallbackGutterVariants, codeEditorFallbackGuttersVariants, codeEditorFallbackLineVariants, codeEditorFallbackVariants, codeEditorHostVariants };
@@ -0,0 +1,13 @@
1
+ import { type FC } from 'react';
2
+ import { SearchQuery } from '@codemirror/search';
3
+ import { EditorView } from '@codemirror/view';
4
+ export interface SearchPanelProps {
5
+ view: EditorView;
6
+ query: SearchQuery;
7
+ /** `null` while the query is empty or an invalid regular expression. */
8
+ matchCount: number | null;
9
+ readOnly: boolean;
10
+ testId: string | undefined;
11
+ }
12
+ /** Internal: rendered by `searchExtension` into CodeMirror's top panel through the portal registry. */
13
+ export declare const SearchPanel: FC<SearchPanelProps>;