@particle-academy/fancy-code 0.16.0 → 0.17.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.
- package/CHANGELOG.md +38 -1
- package/dist/index.cjs +50 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +47 -7
- package/dist/index.d.ts +47 -7
- package/dist/index.js +50 -10
- package/dist/index.js.map +1 -1
- package/docs/CodeEditor.md +16 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -21,6 +21,11 @@ interface UseEditorEngineReturn {
|
|
|
21
21
|
themeColors: ThemeColors;
|
|
22
22
|
handleKeyDown: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void;
|
|
23
23
|
handleInput: () => void;
|
|
24
|
+
/**
|
|
25
|
+
* Ends the focus session: disarms Tab-indent so the next Tab into the editor
|
|
26
|
+
* moves focus rather than indenting. Wire to the textarea's `onBlur`.
|
|
27
|
+
*/
|
|
28
|
+
handleBlur: () => void;
|
|
24
29
|
handleScroll: () => void;
|
|
25
30
|
handleSelect: () => void;
|
|
26
31
|
/**
|
|
@@ -49,13 +54,22 @@ interface CodeEditorProps {
|
|
|
49
54
|
onLanguageChange?: (lang: string) => void;
|
|
50
55
|
/** Theme name: "light", "dark", "auto", or a custom registered name (default: "auto") */
|
|
51
56
|
theme?: string;
|
|
52
|
-
/**
|
|
57
|
+
/**
|
|
58
|
+
* Prevent editing (default: false). Read-only editors still take every
|
|
59
|
+
* navigation key, and Tab / Shift+Tab move focus out.
|
|
60
|
+
*/
|
|
53
61
|
readOnly?: boolean;
|
|
54
62
|
/** Show line numbers (default: true) */
|
|
55
63
|
lineNumbers?: boolean;
|
|
56
64
|
/** Enable word wrap (default: false) */
|
|
57
65
|
wordWrap?: boolean;
|
|
58
|
-
/**
|
|
66
|
+
/**
|
|
67
|
+
* Tab size in spaces (default: 2).
|
|
68
|
+
*
|
|
69
|
+
* Tab / Shift+Tab indent and dedent only once the user has edited in the
|
|
70
|
+
* current focus session; until then Tab moves focus like any other control,
|
|
71
|
+
* so keyboard users are never trapped (WCAG 2.1.2). Escape and blur disarm.
|
|
72
|
+
*/
|
|
59
73
|
tabSize?: number;
|
|
60
74
|
/** Placeholder shown when empty */
|
|
61
75
|
placeholder?: string;
|
|
@@ -88,7 +102,19 @@ interface CodeEditorProps {
|
|
|
88
102
|
* marks. Requires `lineNumbers`.
|
|
89
103
|
*/
|
|
90
104
|
diffBase?: string | null;
|
|
105
|
+
/**
|
|
106
|
+
* Accessible name of the editing surface. Lands on the `<textarea>` a person
|
|
107
|
+
* types into, not on a wrapper. Default "Code editor"; ignored when
|
|
108
|
+
* `aria-labelledby` is set.
|
|
109
|
+
*/
|
|
110
|
+
"aria-label"?: string;
|
|
111
|
+
/** Id(s) of the element(s) naming the editing surface. Wins over `aria-label`. */
|
|
112
|
+
"aria-labelledby"?: string;
|
|
113
|
+
/** Id(s) of the element(s) describing the editing surface. */
|
|
114
|
+
"aria-describedby"?: string;
|
|
91
115
|
}
|
|
116
|
+
/** The accessible-name props every editor forwards to its textarea. */
|
|
117
|
+
type EditorAriaProps = Pick<CodeEditorProps, "aria-label" | "aria-labelledby" | "aria-describedby">;
|
|
92
118
|
interface CodeEditorContextValue {
|
|
93
119
|
/** Get the current document text */
|
|
94
120
|
getValue: () => string;
|
|
@@ -166,6 +192,12 @@ interface CodeEditorContextValue {
|
|
|
166
192
|
_maxHeight?: number;
|
|
167
193
|
/** @internal — lines to band; see {@link CodeEditorProps.highlightLines}. */
|
|
168
194
|
_highlightLines?: readonly number[];
|
|
195
|
+
/** @internal — accessible-name attributes for the textarea. */
|
|
196
|
+
_aria?: {
|
|
197
|
+
"aria-label"?: string;
|
|
198
|
+
"aria-labelledby"?: string;
|
|
199
|
+
"aria-describedby"?: string;
|
|
200
|
+
};
|
|
169
201
|
}
|
|
170
202
|
interface CodeEditorToolbarProps {
|
|
171
203
|
children?: ReactNode;
|
|
@@ -199,7 +231,7 @@ declare namespace CodeEditorStatusBar {
|
|
|
199
231
|
var displayName: string;
|
|
200
232
|
}
|
|
201
233
|
|
|
202
|
-
declare function CodeEditorRoot({ children, className, value: valueProp, defaultValue, onChange, language: languageProp, onLanguageChange, theme, readOnly, lineNumbers: lineNumbersProp, wordWrap: wordWrapProp, tabSize: tabSizeProp, placeholder, minHeight, maxHeight, cursorLine, cursorColumn, diffBase, highlightLines, }: CodeEditorProps): react.JSX.Element;
|
|
234
|
+
declare function CodeEditorRoot({ children, className, value: valueProp, defaultValue, onChange, language: languageProp, onLanguageChange, theme, readOnly, lineNumbers: lineNumbersProp, wordWrap: wordWrapProp, tabSize: tabSizeProp, placeholder, minHeight, maxHeight, cursorLine, cursorColumn, diffBase, highlightLines, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, }: CodeEditorProps): react.JSX.Element;
|
|
203
235
|
declare namespace CodeEditorRoot {
|
|
204
236
|
var displayName: string;
|
|
205
237
|
}
|
|
@@ -214,7 +246,11 @@ declare const CodeEditor: typeof CodeEditorRoot & {
|
|
|
214
246
|
declare function useCodeEditor(): CodeEditorContextValue;
|
|
215
247
|
|
|
216
248
|
type MarkdownEditorMode = "split" | "edit" | "preview";
|
|
217
|
-
|
|
249
|
+
/**
|
|
250
|
+
* `aria-label` / `aria-labelledby` / `aria-describedby` name the editing
|
|
251
|
+
* textarea. Default name: "Markdown editor".
|
|
252
|
+
*/
|
|
253
|
+
interface MarkdownEditorProps extends EditorAriaProps {
|
|
218
254
|
/** Controlled markdown value. */
|
|
219
255
|
value?: string;
|
|
220
256
|
/** Initial value (uncontrolled). */
|
|
@@ -265,7 +301,7 @@ interface MarkdownEditorProps {
|
|
|
265
301
|
* <MarkdownEditor value={md} onValueChange={setMd} mode="split" minHeight={240} />
|
|
266
302
|
* ```
|
|
267
303
|
*/
|
|
268
|
-
declare function MarkdownEditor({ value, defaultValue, onValueChange, mode, theme, readOnly, lineNumbers, wordWrap, placeholder, minHeight, maxHeight, className, renderPreview, }: MarkdownEditorProps): react.JSX.Element;
|
|
304
|
+
declare function MarkdownEditor({ value, defaultValue, onValueChange, mode, theme, readOnly, lineNumbers, wordWrap, placeholder, minHeight, maxHeight, className, renderPreview, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, }: MarkdownEditorProps): react.JSX.Element;
|
|
269
305
|
declare namespace MarkdownEditor {
|
|
270
306
|
var displayName: string;
|
|
271
307
|
}
|
|
@@ -319,7 +355,11 @@ interface ResolveFileKindInput {
|
|
|
319
355
|
*/
|
|
320
356
|
declare function resolveFileKind({ filename, mime }: ResolveFileKindInput): FileKind;
|
|
321
357
|
|
|
322
|
-
|
|
358
|
+
/**
|
|
359
|
+
* `aria-label` / `aria-labelledby` / `aria-describedby` name the source view's
|
|
360
|
+
* textarea. Default name: the `filename`, else "File contents".
|
|
361
|
+
*/
|
|
362
|
+
interface FileViewerProps extends EditorAriaProps {
|
|
323
363
|
/**
|
|
324
364
|
* File name or path — used to detect the file kind / editor language, and as
|
|
325
365
|
* a label / alt text. Pass `mime` too when you have it (it's preferred).
|
|
@@ -405,7 +445,7 @@ interface FileViewerProps {
|
|
|
405
445
|
* <FileViewer filename="logo.png" src={url} style={{ height: 360 }} />
|
|
406
446
|
* ```
|
|
407
447
|
*/
|
|
408
|
-
declare function FileViewer({ filename, mime, src, value, onChange, readOnly, theme, fileKind, lineNumbers, wordWrap, line, column, highlightLines, minHeight, maxHeight, mediaProps, view, frameProps, document, className, style, }: FileViewerProps): react.JSX.Element;
|
|
448
|
+
declare function FileViewer({ filename, mime, src, value, onChange, readOnly, theme, fileKind, lineNumbers, wordWrap, line, column, highlightLines, minHeight, maxHeight, mediaProps, view, frameProps, document, className, style, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, }: FileViewerProps): react.JSX.Element;
|
|
409
449
|
declare namespace FileViewer {
|
|
410
450
|
var displayName: string;
|
|
411
451
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -21,6 +21,11 @@ interface UseEditorEngineReturn {
|
|
|
21
21
|
themeColors: ThemeColors;
|
|
22
22
|
handleKeyDown: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void;
|
|
23
23
|
handleInput: () => void;
|
|
24
|
+
/**
|
|
25
|
+
* Ends the focus session: disarms Tab-indent so the next Tab into the editor
|
|
26
|
+
* moves focus rather than indenting. Wire to the textarea's `onBlur`.
|
|
27
|
+
*/
|
|
28
|
+
handleBlur: () => void;
|
|
24
29
|
handleScroll: () => void;
|
|
25
30
|
handleSelect: () => void;
|
|
26
31
|
/**
|
|
@@ -49,13 +54,22 @@ interface CodeEditorProps {
|
|
|
49
54
|
onLanguageChange?: (lang: string) => void;
|
|
50
55
|
/** Theme name: "light", "dark", "auto", or a custom registered name (default: "auto") */
|
|
51
56
|
theme?: string;
|
|
52
|
-
/**
|
|
57
|
+
/**
|
|
58
|
+
* Prevent editing (default: false). Read-only editors still take every
|
|
59
|
+
* navigation key, and Tab / Shift+Tab move focus out.
|
|
60
|
+
*/
|
|
53
61
|
readOnly?: boolean;
|
|
54
62
|
/** Show line numbers (default: true) */
|
|
55
63
|
lineNumbers?: boolean;
|
|
56
64
|
/** Enable word wrap (default: false) */
|
|
57
65
|
wordWrap?: boolean;
|
|
58
|
-
/**
|
|
66
|
+
/**
|
|
67
|
+
* Tab size in spaces (default: 2).
|
|
68
|
+
*
|
|
69
|
+
* Tab / Shift+Tab indent and dedent only once the user has edited in the
|
|
70
|
+
* current focus session; until then Tab moves focus like any other control,
|
|
71
|
+
* so keyboard users are never trapped (WCAG 2.1.2). Escape and blur disarm.
|
|
72
|
+
*/
|
|
59
73
|
tabSize?: number;
|
|
60
74
|
/** Placeholder shown when empty */
|
|
61
75
|
placeholder?: string;
|
|
@@ -88,7 +102,19 @@ interface CodeEditorProps {
|
|
|
88
102
|
* marks. Requires `lineNumbers`.
|
|
89
103
|
*/
|
|
90
104
|
diffBase?: string | null;
|
|
105
|
+
/**
|
|
106
|
+
* Accessible name of the editing surface. Lands on the `<textarea>` a person
|
|
107
|
+
* types into, not on a wrapper. Default "Code editor"; ignored when
|
|
108
|
+
* `aria-labelledby` is set.
|
|
109
|
+
*/
|
|
110
|
+
"aria-label"?: string;
|
|
111
|
+
/** Id(s) of the element(s) naming the editing surface. Wins over `aria-label`. */
|
|
112
|
+
"aria-labelledby"?: string;
|
|
113
|
+
/** Id(s) of the element(s) describing the editing surface. */
|
|
114
|
+
"aria-describedby"?: string;
|
|
91
115
|
}
|
|
116
|
+
/** The accessible-name props every editor forwards to its textarea. */
|
|
117
|
+
type EditorAriaProps = Pick<CodeEditorProps, "aria-label" | "aria-labelledby" | "aria-describedby">;
|
|
92
118
|
interface CodeEditorContextValue {
|
|
93
119
|
/** Get the current document text */
|
|
94
120
|
getValue: () => string;
|
|
@@ -166,6 +192,12 @@ interface CodeEditorContextValue {
|
|
|
166
192
|
_maxHeight?: number;
|
|
167
193
|
/** @internal — lines to band; see {@link CodeEditorProps.highlightLines}. */
|
|
168
194
|
_highlightLines?: readonly number[];
|
|
195
|
+
/** @internal — accessible-name attributes for the textarea. */
|
|
196
|
+
_aria?: {
|
|
197
|
+
"aria-label"?: string;
|
|
198
|
+
"aria-labelledby"?: string;
|
|
199
|
+
"aria-describedby"?: string;
|
|
200
|
+
};
|
|
169
201
|
}
|
|
170
202
|
interface CodeEditorToolbarProps {
|
|
171
203
|
children?: ReactNode;
|
|
@@ -199,7 +231,7 @@ declare namespace CodeEditorStatusBar {
|
|
|
199
231
|
var displayName: string;
|
|
200
232
|
}
|
|
201
233
|
|
|
202
|
-
declare function CodeEditorRoot({ children, className, value: valueProp, defaultValue, onChange, language: languageProp, onLanguageChange, theme, readOnly, lineNumbers: lineNumbersProp, wordWrap: wordWrapProp, tabSize: tabSizeProp, placeholder, minHeight, maxHeight, cursorLine, cursorColumn, diffBase, highlightLines, }: CodeEditorProps): react.JSX.Element;
|
|
234
|
+
declare function CodeEditorRoot({ children, className, value: valueProp, defaultValue, onChange, language: languageProp, onLanguageChange, theme, readOnly, lineNumbers: lineNumbersProp, wordWrap: wordWrapProp, tabSize: tabSizeProp, placeholder, minHeight, maxHeight, cursorLine, cursorColumn, diffBase, highlightLines, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, }: CodeEditorProps): react.JSX.Element;
|
|
203
235
|
declare namespace CodeEditorRoot {
|
|
204
236
|
var displayName: string;
|
|
205
237
|
}
|
|
@@ -214,7 +246,11 @@ declare const CodeEditor: typeof CodeEditorRoot & {
|
|
|
214
246
|
declare function useCodeEditor(): CodeEditorContextValue;
|
|
215
247
|
|
|
216
248
|
type MarkdownEditorMode = "split" | "edit" | "preview";
|
|
217
|
-
|
|
249
|
+
/**
|
|
250
|
+
* `aria-label` / `aria-labelledby` / `aria-describedby` name the editing
|
|
251
|
+
* textarea. Default name: "Markdown editor".
|
|
252
|
+
*/
|
|
253
|
+
interface MarkdownEditorProps extends EditorAriaProps {
|
|
218
254
|
/** Controlled markdown value. */
|
|
219
255
|
value?: string;
|
|
220
256
|
/** Initial value (uncontrolled). */
|
|
@@ -265,7 +301,7 @@ interface MarkdownEditorProps {
|
|
|
265
301
|
* <MarkdownEditor value={md} onValueChange={setMd} mode="split" minHeight={240} />
|
|
266
302
|
* ```
|
|
267
303
|
*/
|
|
268
|
-
declare function MarkdownEditor({ value, defaultValue, onValueChange, mode, theme, readOnly, lineNumbers, wordWrap, placeholder, minHeight, maxHeight, className, renderPreview, }: MarkdownEditorProps): react.JSX.Element;
|
|
304
|
+
declare function MarkdownEditor({ value, defaultValue, onValueChange, mode, theme, readOnly, lineNumbers, wordWrap, placeholder, minHeight, maxHeight, className, renderPreview, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, }: MarkdownEditorProps): react.JSX.Element;
|
|
269
305
|
declare namespace MarkdownEditor {
|
|
270
306
|
var displayName: string;
|
|
271
307
|
}
|
|
@@ -319,7 +355,11 @@ interface ResolveFileKindInput {
|
|
|
319
355
|
*/
|
|
320
356
|
declare function resolveFileKind({ filename, mime }: ResolveFileKindInput): FileKind;
|
|
321
357
|
|
|
322
|
-
|
|
358
|
+
/**
|
|
359
|
+
* `aria-label` / `aria-labelledby` / `aria-describedby` name the source view's
|
|
360
|
+
* textarea. Default name: the `filename`, else "File contents".
|
|
361
|
+
*/
|
|
362
|
+
interface FileViewerProps extends EditorAriaProps {
|
|
323
363
|
/**
|
|
324
364
|
* File name or path — used to detect the file kind / editor language, and as
|
|
325
365
|
* a label / alt text. Pass `mime` too when you have it (it's preferred).
|
|
@@ -405,7 +445,7 @@ interface FileViewerProps {
|
|
|
405
445
|
* <FileViewer filename="logo.png" src={url} style={{ height: 360 }} />
|
|
406
446
|
* ```
|
|
407
447
|
*/
|
|
408
|
-
declare function FileViewer({ filename, mime, src, value, onChange, readOnly, theme, fileKind, lineNumbers, wordWrap, line, column, highlightLines, minHeight, maxHeight, mediaProps, view, frameProps, document, className, style, }: FileViewerProps): react.JSX.Element;
|
|
448
|
+
declare function FileViewer({ filename, mime, src, value, onChange, readOnly, theme, fileKind, lineNumbers, wordWrap, line, column, highlightLines, minHeight, maxHeight, mediaProps, view, frameProps, document, className, style, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, }: FileViewerProps): react.JSX.Element;
|
|
409
449
|
declare namespace FileViewer {
|
|
410
450
|
var displayName: string;
|
|
411
451
|
}
|
package/dist/index.js
CHANGED
|
@@ -41,7 +41,8 @@ function CodeEditorPanel({ className }) {
|
|
|
41
41
|
_diffAnnotations: diffAnnotations,
|
|
42
42
|
_maxHeight,
|
|
43
43
|
_minHeight,
|
|
44
|
-
_highlightLines: highlightLines
|
|
44
|
+
_highlightLines: highlightLines,
|
|
45
|
+
_aria: aria
|
|
45
46
|
} = useCodeEditor();
|
|
46
47
|
const lineNumberElements = useMemo(() => {
|
|
47
48
|
if (!engine || !lineNumbers) return null;
|
|
@@ -131,6 +132,7 @@ function CodeEditorPanel({ className }) {
|
|
|
131
132
|
themeColors,
|
|
132
133
|
handleKeyDown,
|
|
133
134
|
handleInput,
|
|
135
|
+
handleBlur,
|
|
134
136
|
handleScroll,
|
|
135
137
|
handleSelect,
|
|
136
138
|
scrollTop,
|
|
@@ -203,8 +205,12 @@ function CodeEditorPanel({ className }) {
|
|
|
203
205
|
"textarea",
|
|
204
206
|
{
|
|
205
207
|
ref: textareaRef,
|
|
208
|
+
"aria-label": aria?.["aria-label"],
|
|
209
|
+
"aria-labelledby": aria?.["aria-labelledby"],
|
|
210
|
+
"aria-describedby": aria?.["aria-describedby"],
|
|
206
211
|
className: cn(
|
|
207
|
-
"relative m-0 block resize-none border-none bg-transparent p-2.5 text-[13px] leading-[1.5] text-transparent
|
|
212
|
+
"relative m-0 block resize-none border-none bg-transparent p-2.5 text-[13px] leading-[1.5] text-transparent",
|
|
213
|
+
"focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[color:var(--fancy-focus,var(--color-blue-500))] dark:focus-visible:ring-[color:var(--fancy-focus-dark,var(--color-blue-400))]",
|
|
208
214
|
wordWrap ? "w-full" : "min-w-full"
|
|
209
215
|
),
|
|
210
216
|
style: {
|
|
@@ -221,6 +227,7 @@ function CodeEditorPanel({ className }) {
|
|
|
221
227
|
readOnly,
|
|
222
228
|
onKeyDown: handleKeyDown,
|
|
223
229
|
onInput: handleInput,
|
|
230
|
+
onBlur: handleBlur,
|
|
224
231
|
onScroll: handleScroll,
|
|
225
232
|
onSelect: handleSelect,
|
|
226
233
|
onClick: handleSelect
|
|
@@ -482,6 +489,7 @@ function useEditorEngine({
|
|
|
482
489
|
const [scrollTop, setScrollTop] = useState(0);
|
|
483
490
|
const [scrollLeft, setScrollLeft] = useState(0);
|
|
484
491
|
const [activeLine, setActiveLine] = useState(1);
|
|
492
|
+
const tabArmedRef = useRef(false);
|
|
485
493
|
const themeColors = useMemo(() => {
|
|
486
494
|
const def = getTheme(theme);
|
|
487
495
|
return def?.colors ?? DEFAULT_COLORS;
|
|
@@ -542,6 +550,7 @@ function useEditorEngine({
|
|
|
542
550
|
const handleInput = useCallback(() => {
|
|
543
551
|
const ta = textareaRef.current;
|
|
544
552
|
if (!ta) return;
|
|
553
|
+
tabArmedRef.current = true;
|
|
545
554
|
onChangeRef.current?.(ta.value);
|
|
546
555
|
autoResize();
|
|
547
556
|
updateCursorInfo();
|
|
@@ -577,14 +586,19 @@ function useEditorEngine({
|
|
|
577
586
|
},
|
|
578
587
|
[updateCursorInfo]
|
|
579
588
|
);
|
|
589
|
+
const handleBlur = useCallback(() => {
|
|
590
|
+
tabArmedRef.current = false;
|
|
591
|
+
}, []);
|
|
580
592
|
const handleKeyDown = useCallback(
|
|
581
593
|
(e) => {
|
|
582
594
|
if (readOnly) {
|
|
583
|
-
if (e.key === "c" && (e.metaKey || e.ctrlKey)) return;
|
|
584
|
-
if (e.key === "a" && (e.metaKey || e.ctrlKey)) return;
|
|
585
|
-
e.preventDefault();
|
|
586
595
|
return;
|
|
587
596
|
}
|
|
597
|
+
if (e.key === "Escape") {
|
|
598
|
+
tabArmedRef.current = false;
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
if (e.key === "Tab" && !tabArmedRef.current) return;
|
|
588
602
|
if (e.key === "Tab") {
|
|
589
603
|
e.preventDefault();
|
|
590
604
|
const ta = e.currentTarget;
|
|
@@ -633,6 +647,7 @@ function useEditorEngine({
|
|
|
633
647
|
}
|
|
634
648
|
if (e.key === "Enter") {
|
|
635
649
|
e.preventDefault();
|
|
650
|
+
tabArmedRef.current = true;
|
|
636
651
|
const ta = e.currentTarget;
|
|
637
652
|
const start = ta.selectionStart;
|
|
638
653
|
const end = ta.selectionEnd;
|
|
@@ -661,6 +676,7 @@ function useEditorEngine({
|
|
|
661
676
|
themeColors,
|
|
662
677
|
handleKeyDown,
|
|
663
678
|
handleInput,
|
|
679
|
+
handleBlur,
|
|
664
680
|
handleScroll,
|
|
665
681
|
handleSelect,
|
|
666
682
|
revealLine,
|
|
@@ -701,8 +717,19 @@ function CodeEditorRoot({
|
|
|
701
717
|
cursorLine,
|
|
702
718
|
cursorColumn,
|
|
703
719
|
diffBase,
|
|
704
|
-
highlightLines
|
|
720
|
+
highlightLines,
|
|
721
|
+
"aria-label": ariaLabel,
|
|
722
|
+
"aria-labelledby": ariaLabelledBy,
|
|
723
|
+
"aria-describedby": ariaDescribedBy
|
|
705
724
|
}) {
|
|
725
|
+
const aria = useMemo(
|
|
726
|
+
() => ({
|
|
727
|
+
"aria-label": ariaLabelledBy ? void 0 : ariaLabel ?? "Code editor",
|
|
728
|
+
"aria-labelledby": ariaLabelledBy,
|
|
729
|
+
"aria-describedby": ariaDescribedBy
|
|
730
|
+
}),
|
|
731
|
+
[ariaLabel, ariaLabelledBy, ariaDescribedBy]
|
|
732
|
+
);
|
|
706
733
|
const [currentValue, setCurrentValue] = useControllableState(valueProp, defaultValue, onChange);
|
|
707
734
|
const diffAnnotations = useMemo(
|
|
708
735
|
() => diffBase == null ? null : annotateLines(diffBase, currentValue),
|
|
@@ -795,9 +822,10 @@ function CodeEditorRoot({
|
|
|
795
822
|
_engineReturn: engineReturn,
|
|
796
823
|
_minHeight: minHeight,
|
|
797
824
|
_maxHeight: maxHeight,
|
|
798
|
-
_highlightLines: highlightLines
|
|
825
|
+
_highlightLines: highlightLines,
|
|
826
|
+
_aria: aria
|
|
799
827
|
}),
|
|
800
|
-
[engineReturn, currentValue, currentLanguage, setLanguage, resolvedTheme, readOnly, showLineNumbers, isWordWrap, tabSizeProp, cursorPosition, selectionLength, setCurrentValue, placeholder, diffAnnotations, minHeight, maxHeight, highlightLines]
|
|
828
|
+
[engineReturn, currentValue, currentLanguage, setLanguage, resolvedTheme, readOnly, showLineNumbers, isWordWrap, tabSizeProp, cursorPosition, selectionLength, setCurrentValue, placeholder, diffAnnotations, minHeight, maxHeight, highlightLines, aria]
|
|
801
829
|
);
|
|
802
830
|
return /* @__PURE__ */ jsx(CodeEditorContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
|
|
803
831
|
"div",
|
|
@@ -833,7 +861,10 @@ function MarkdownEditor({
|
|
|
833
861
|
minHeight,
|
|
834
862
|
maxHeight,
|
|
835
863
|
className,
|
|
836
|
-
renderPreview
|
|
864
|
+
renderPreview,
|
|
865
|
+
"aria-label": ariaLabel,
|
|
866
|
+
"aria-labelledby": ariaLabelledBy,
|
|
867
|
+
"aria-describedby": ariaDescribedBy
|
|
837
868
|
}) {
|
|
838
869
|
const [content, setContent] = useControllableState(value, defaultValue, onValueChange);
|
|
839
870
|
const showEditor = mode !== "preview";
|
|
@@ -858,6 +889,9 @@ function MarkdownEditor({
|
|
|
858
889
|
placeholder,
|
|
859
890
|
minHeight,
|
|
860
891
|
maxHeight,
|
|
892
|
+
"aria-label": ariaLabel ?? "Markdown editor",
|
|
893
|
+
"aria-labelledby": ariaLabelledBy,
|
|
894
|
+
"aria-describedby": ariaDescribedBy,
|
|
861
895
|
children: /* @__PURE__ */ jsx(CodeEditor.Panel, {})
|
|
862
896
|
}
|
|
863
897
|
) }),
|
|
@@ -959,7 +993,10 @@ function FileViewer({
|
|
|
959
993
|
frameProps,
|
|
960
994
|
document,
|
|
961
995
|
className,
|
|
962
|
-
style
|
|
996
|
+
style,
|
|
997
|
+
"aria-label": ariaLabel,
|
|
998
|
+
"aria-labelledby": ariaLabelledBy,
|
|
999
|
+
"aria-describedby": ariaDescribedBy
|
|
963
1000
|
}) {
|
|
964
1001
|
const resolved = fileKind ?? resolveFileKind({ filename, mime });
|
|
965
1002
|
if (resolved.kind === "document" && view === "rendered" && readOnly && line == null) {
|
|
@@ -1053,6 +1090,9 @@ function FileViewer({
|
|
|
1053
1090
|
cursorLine: line,
|
|
1054
1091
|
cursorColumn: column,
|
|
1055
1092
|
highlightLines: highlightLines ?? (line != null ? [line] : void 0),
|
|
1093
|
+
"aria-label": ariaLabel ?? filename ?? "File contents",
|
|
1094
|
+
"aria-labelledby": ariaLabelledBy,
|
|
1095
|
+
"aria-describedby": ariaDescribedBy,
|
|
1056
1096
|
children: /* @__PURE__ */ jsx(CodeEditor.Panel, {})
|
|
1057
1097
|
}
|
|
1058
1098
|
)
|