@instructure/ui-source-code-editor 11.6.0 → 11.6.1-snapshot-129

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 (78) hide show
  1. package/CHANGELOG.md +40 -293
  2. package/es/SourceCodeEditor/{SearchPanel.js → v1/SearchPanel.js} +2 -2
  3. package/es/SourceCodeEditor/{index.js → v1/index.js} +1 -1
  4. package/es/SourceCodeEditor/v2/SearchPanel.js +118 -0
  5. package/es/SourceCodeEditor/v2/customKeybinding.js +100 -0
  6. package/es/SourceCodeEditor/v2/index.js +535 -0
  7. package/es/SourceCodeEditor/v2/props.js +28 -0
  8. package/es/SourceCodeEditor/v2/styles.js +228 -0
  9. package/es/{index.js → exports/a.js} +1 -1
  10. package/{src/index.ts → es/exports/b.js} +1 -2
  11. package/lib/SourceCodeEditor/{SearchPanel.js → v1/SearchPanel.js} +8 -8
  12. package/lib/SourceCodeEditor/{index.js → v1/index.js} +1 -1
  13. package/lib/SourceCodeEditor/v2/SearchPanel.js +126 -0
  14. package/lib/SourceCodeEditor/v2/customKeybinding.js +105 -0
  15. package/lib/SourceCodeEditor/v2/index.js +541 -0
  16. package/lib/SourceCodeEditor/v2/props.js +33 -0
  17. package/lib/SourceCodeEditor/v2/styles.js +234 -0
  18. package/lib/{index.js → exports/a.js} +2 -2
  19. package/lib/exports/b.js +12 -0
  20. package/package.json +42 -20
  21. package/src/SourceCodeEditor/{SearchPanel.tsx → v1/SearchPanel.tsx} +2 -2
  22. package/src/SourceCodeEditor/{index.tsx → v1/index.tsx} +1 -1
  23. package/src/SourceCodeEditor/v2/README.md +799 -0
  24. package/src/SourceCodeEditor/v2/SearchPanel.tsx +150 -0
  25. package/src/SourceCodeEditor/v2/customKeybinding.ts +125 -0
  26. package/src/SourceCodeEditor/v2/index.tsx +685 -0
  27. package/src/SourceCodeEditor/v2/props.ts +263 -0
  28. package/src/SourceCodeEditor/v2/styles.ts +239 -0
  29. package/src/exports/a.ts +25 -0
  30. package/src/exports/b.ts +25 -0
  31. package/tsconfig.build.tsbuildinfo +1 -1
  32. package/types/SourceCodeEditor/v1/SearchPanel.d.ts.map +1 -0
  33. package/types/SourceCodeEditor/v1/customKeybinding.d.ts.map +1 -0
  34. package/types/SourceCodeEditor/v1/index.d.ts.map +1 -0
  35. package/types/SourceCodeEditor/v1/props.d.ts.map +1 -0
  36. package/types/SourceCodeEditor/v1/styles.d.ts.map +1 -0
  37. package/types/SourceCodeEditor/v1/theme.d.ts.map +1 -0
  38. package/types/SourceCodeEditor/v2/SearchPanel.d.ts +7 -0
  39. package/types/SourceCodeEditor/v2/SearchPanel.d.ts.map +1 -0
  40. package/types/SourceCodeEditor/v2/customKeybinding.d.ts +4 -0
  41. package/types/SourceCodeEditor/v2/customKeybinding.d.ts.map +1 -0
  42. package/types/SourceCodeEditor/v2/index.d.ts +103 -0
  43. package/types/SourceCodeEditor/v2/index.d.ts.map +1 -0
  44. package/types/SourceCodeEditor/v2/props.d.ts +142 -0
  45. package/types/SourceCodeEditor/v2/props.d.ts.map +1 -0
  46. package/types/SourceCodeEditor/v2/styles.d.ts +14 -0
  47. package/types/SourceCodeEditor/v2/styles.d.ts.map +1 -0
  48. package/types/exports/a.d.ts +3 -0
  49. package/types/exports/a.d.ts.map +1 -0
  50. package/types/exports/b.d.ts +3 -0
  51. package/types/exports/b.d.ts.map +1 -0
  52. package/types/SourceCodeEditor/SearchPanel.d.ts.map +0 -1
  53. package/types/SourceCodeEditor/customKeybinding.d.ts.map +0 -1
  54. package/types/SourceCodeEditor/index.d.ts.map +0 -1
  55. package/types/SourceCodeEditor/props.d.ts.map +0 -1
  56. package/types/SourceCodeEditor/styles.d.ts.map +0 -1
  57. package/types/SourceCodeEditor/theme.d.ts.map +0 -1
  58. package/types/index.d.ts +0 -3
  59. package/types/index.d.ts.map +0 -1
  60. /package/es/SourceCodeEditor/{customKeybinding.js → v1/customKeybinding.js} +0 -0
  61. /package/es/SourceCodeEditor/{props.js → v1/props.js} +0 -0
  62. /package/es/SourceCodeEditor/{styles.js → v1/styles.js} +0 -0
  63. /package/es/SourceCodeEditor/{theme.js → v1/theme.js} +0 -0
  64. /package/lib/SourceCodeEditor/{customKeybinding.js → v1/customKeybinding.js} +0 -0
  65. /package/lib/SourceCodeEditor/{props.js → v1/props.js} +0 -0
  66. /package/lib/SourceCodeEditor/{styles.js → v1/styles.js} +0 -0
  67. /package/lib/SourceCodeEditor/{theme.js → v1/theme.js} +0 -0
  68. /package/src/SourceCodeEditor/{README.md → v1/README.md} +0 -0
  69. /package/src/SourceCodeEditor/{customKeybinding.ts → v1/customKeybinding.ts} +0 -0
  70. /package/src/SourceCodeEditor/{props.ts → v1/props.ts} +0 -0
  71. /package/src/SourceCodeEditor/{styles.ts → v1/styles.ts} +0 -0
  72. /package/src/SourceCodeEditor/{theme.ts → v1/theme.ts} +0 -0
  73. /package/types/SourceCodeEditor/{SearchPanel.d.ts → v1/SearchPanel.d.ts} +0 -0
  74. /package/types/SourceCodeEditor/{customKeybinding.d.ts → v1/customKeybinding.d.ts} +0 -0
  75. /package/types/SourceCodeEditor/{index.d.ts → v1/index.d.ts} +0 -0
  76. /package/types/SourceCodeEditor/{props.d.ts → v1/props.d.ts} +0 -0
  77. /package/types/SourceCodeEditor/{styles.d.ts → v1/styles.d.ts} +0 -0
  78. /package/types/SourceCodeEditor/{theme.d.ts → v1/theme.d.ts} +0 -0
@@ -0,0 +1,799 @@
1
+ ---
2
+ describes: CodeEditor
3
+ ---
4
+
5
+ A wrapper around the popular [CodeMirror](https://codemirror.net/) code editor component. CodeMirror provides a text input field with features like line gutters, syntax highlighting, and autocompletion.
6
+
7
+ ### Built-in features
8
+
9
+ SourceCodeEditor has a lot of built-in features that makes editing code easier.
10
+
11
+ ##### Command keybinding
12
+
13
+ The editor has a lot of handy key bindings for commands like copying and deleting lines, moving lines up and down, selection and indentation, etc. See the keymaps here: [defaultKeymap](https://codemirror.net/docs/ref/#commands.defaultKeymap), [closeBracketsKeymap](https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap), [historyKeymap](https://codemirror.net/docs/ref/#commands.historyKeymap), [foldKeymap](https://codemirror.net/docs/ref/#language.foldKeymap), [completionKeymap](https://codemirror.net/docs/ref/#autocomplete.completionKeymap), [lintKeymap](https://codemirror.net/docs/ref/#lint.lintKeymap).
14
+
15
+ ##### History
16
+
17
+ The history feature remembers the steps of the code editing and selections, and lets you undo and redo them.
18
+
19
+ ##### Cursor and selection
20
+
21
+ Instead of using the browser's native selection and cursor, SourceCodeEditor uses its own system. This allows the editor to display secondary selection ranges, and tends to produce a type of selection more in line with that users expect in a text editor.
22
+
23
+ It also allows **multiple** cursors to be placed (`Cmd/Ctrl` + click), multiple ranges to be selected and edited at the same time.
24
+
25
+ **Rectangular selections:** by default, it will react to left mouse drag with the `Option/Alt` key held down. When such a selection occurs, the text within the rectangle that was dragged over will be selected, as one selection range per line.
26
+
27
+ The editor highlights text that matches the current selection.
28
+
29
+ ##### Bracket matching and closing
30
+
31
+ Whenever the cursor is next to a bracket, that bracket and the one it matches are highlighted. Or, when no matching bracket is found, another highlighting style is used to indicate this.
32
+
33
+ When a closeable bracket is typed, its closing bracket is immediately inserted after the cursor.
34
+
35
+ ### Language support
36
+
37
+ Setting the correct language adds **syntax highlighting** and other helpful features to the editor, like **code folding**, **auto-indentation**, **syntax-aware selection** and **autocompletion** features.
38
+
39
+ **Note:** In case you need support for additional languages, please contact us on [GitHub](https://github.com/instructure/instructure-ui)!
40
+
41
+ ```js
42
+ ---
43
+ type: example
44
+ ---
45
+ const languages = {
46
+ json: `{
47
+ "name": "@instructure/ui-source-code-editor",
48
+ "version": "8.24.2",
49
+ "description": "A UI component library made by Instructure Inc.",
50
+ "author": "Instructure, Inc. Engineering and Product Design",
51
+ "module": "./es/index.js",
52
+ "main": "./lib/index.js",
53
+ "types": "./types/index.d.ts",
54
+ "repository": {
55
+ "type": "git",
56
+ "url": "https://github.com/instructure/instructure-ui.git"
57
+ },
58
+ }`,
59
+ javascript: `const fruit: string = "apple"
60
+
61
+ const re = new RegExp('ab+c')
62
+
63
+ function exampleMethod(props: Props) {
64
+ return props ? props.value : null
65
+ }
66
+
67
+ /**
68
+ * This is an example
69
+ * @param {Object} props
70
+ */
71
+ const Example = () => {
72
+ return (
73
+ <View as="div" padding={'large'}>
74
+ <Position
75
+ renderTarget={<GoodComponent />}
76
+ placement='end center'
77
+ offsetX='20px'
78
+ >
79
+ <span style={{ padding: '8px', background: 'white' }}>
80
+ Positioned content
81
+ </span>
82
+ </Position>
83
+ </View>
84
+ )
85
+ }
86
+
87
+ render(<Example />)`,
88
+
89
+ html: `<!DOCTYPE html>
90
+ <html lang="en">
91
+ <head>
92
+ <meta charset="UTF-8" />
93
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
94
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
95
+ <title>Example app</title>
96
+ </head>
97
+ <body>
98
+ <div id="app">
99
+ <button onclick="myFunction()">Click me</button>
100
+ </div>
101
+
102
+ <script src="script.js"></script>
103
+ </body>
104
+ </html>`,
105
+ css: `a {
106
+ text-decoration: none;
107
+
108
+ &:hover { text-decoration: underline; }
109
+ }
110
+
111
+ a:link, a:visited, a:hover, a:active {
112
+ background-color: green;
113
+ color: white;
114
+ padding: 10px 25px;
115
+ text-align: center;
116
+ text-decoration: none;
117
+ display: inline-block;
118
+ }
119
+
120
+ .centertext { text-align: center; }
121
+
122
+ img { opacity: 0.5; filter: alpha(opacity=50); }`,
123
+ markdown: `#### The quarterly results look great!
124
+
125
+ > - Revenue was off the chart.
126
+ > - Profits were higher than ever.
127
+
128
+ *Everything* is going according to **plan**.
129
+
130
+ ---
131
+ type: example
132
+ ---`,
133
+ shell: `#!/bin/bash
134
+
135
+ # example of using arguments to a script
136
+ echo "My first name is $1"
137
+ echo "My surname is $2"
138
+ echo "Total number of arguments is $#"
139
+
140
+ ________________________________________
141
+
142
+ $ chmod a+x name.sh
143
+ $ ./name.sh Hans-Wolfgang Loidl
144
+ My first name is Hans-Wolfgang
145
+ My surname is Loidl
146
+ Total number of arguments is 2`,
147
+ yml: `---
148
+ doe: "a deer, a female deer"
149
+ ray: "a drop of golden sun"
150
+ pi: 3.14159
151
+ xmas: true
152
+ french-hens: 3
153
+ calling-birds:
154
+ - huey
155
+ - dewey
156
+ - louie
157
+ - fred
158
+ xmas-fifth-day:
159
+ calling-birds: four
160
+ french-hens: 3
161
+ golden-rings: 5
162
+ partridges:
163
+ count: 1
164
+ location: "a pear tree"
165
+ turtle-doves: two`
166
+ }
167
+
168
+ const languageMap = {
169
+ json: languages.json,
170
+ js: languages.javascript,
171
+ jsx: languages.javascript,
172
+ javascript: languages.javascript,
173
+ html: languages.html,
174
+ css: languages.css,
175
+ markdown: languages.markdown,
176
+ sh: languages.shell,
177
+ shell: languages.shell,
178
+ bash: languages.shell,
179
+ yml: languages.yml,
180
+ yaml: languages.yml
181
+ }
182
+
183
+ const LanguageExamples = () => {
184
+ const [currentLanguage, setCurrentLanguage] = useState('javascript')
185
+ const [currentValue, setCurrentValue] = useState(languageMap.javascript)
186
+
187
+ const languageKeys = Object.keys(languageMap)
188
+
189
+ return (
190
+ <Flex alignItems="start">
191
+ <Flex.Item>
192
+ <RadioInputGroup
193
+ name="languageOptions"
194
+ value={currentLanguage}
195
+ description="Language"
196
+ onChange={(e, newLanguage) => {
197
+ setCurrentLanguage(newLanguage)
198
+ setCurrentValue(languageMap[newLanguage])
199
+ }}
200
+ >
201
+ {languageKeys.map((language) => (
202
+ <RadioInput key={language} label={language} value={language} />
203
+ ))}
204
+ </RadioInputGroup>
205
+ </Flex.Item>
206
+
207
+ <Flex.Item padding="0 0 0 large" shouldGrow shouldShrink>
208
+ <FormField label="SourceCodeEditor with syntax highlight">
209
+ <SourceCodeEditor
210
+ label={`${currentLanguage} SourceCodeEditor with syntax highlight`}
211
+ language={currentLanguage}
212
+ value={currentValue}
213
+ onChange={(value) => {
214
+ setCurrentValue(value)
215
+ }}
216
+ lineNumbers
217
+ lineWrapping
218
+ highlightActiveLine
219
+ highlightActiveLineGutter
220
+ />
221
+ </FormField>
222
+ </Flex.Item>
223
+ </Flex>
224
+ )
225
+ }
226
+
227
+ render(<LanguageExamples />)
228
+ ```
229
+
230
+ ### Controlled mode
231
+
232
+ SourceCodeEditor works best as an uncontrolled component (with the `defaultValue` prop), and that is how we recommend it to be used. As an uncontrolled component, the underlying CodeMirror component can take care of all interactions.
233
+
234
+ We've implemented the "controlled" usage, but please let us know if you run into any performance issues or bugs.
235
+
236
+ ```js
237
+ ---
238
+ type: example
239
+ ---
240
+ const ControlledExample = () => {
241
+ const [value, setValue] = useState(`const fruit: string = "apple"
242
+
243
+ function exampleMethod(props: Props) {
244
+ return props ? props.value : null
245
+ }`)
246
+
247
+ const textAreaRef = useRef(null)
248
+
249
+ return (
250
+ <View display="block" background="primary">
251
+ <Flex alignItems="start">
252
+ <Flex.Item shouldGrow shouldShrink padding="0 large 0 0">
253
+ <FormField
254
+ label="Controlled code editor"
255
+ id="controlledCodeEditor"
256
+ messages={[
257
+ {
258
+ type: 'hint',
259
+ text: 'Type in the editor or set the value from the textarea.'
260
+ }
261
+ ]}
262
+ >
263
+ <SourceCodeEditor
264
+ label="controlled code editor"
265
+ value={value}
266
+ onChange={(newValue) => setValue(newValue)}
267
+ highlightActiveLine
268
+ highlightActiveLineGutter
269
+ lineWrapping
270
+ lineNumbers
271
+ foldGutter
272
+ spellcheck
273
+ />
274
+ </FormField>
275
+ </Flex.Item>
276
+ <Flex.Item size="50%" padding="0 0 0 large">
277
+ <FormFieldGroup
278
+ description="Set value from the outside"
279
+ name="setValue"
280
+ >
281
+ <TextArea
282
+ label={<ScreenReaderContent>Change value</ScreenReaderContent>}
283
+ textareaRef={(e) => {
284
+ textAreaRef.current = e
285
+ }}
286
+ defaultValue={value}
287
+ />
288
+ <Button
289
+ color="primary"
290
+ onClick={() => {
291
+ if (textAreaRef.current) {
292
+ setValue(textAreaRef.current.value)
293
+ }
294
+ }}
295
+ >
296
+ Update value
297
+ </Button>
298
+ </FormFieldGroup>
299
+ </Flex.Item>
300
+ </Flex>
301
+ </View>
302
+ )
303
+ }
304
+ render(<ControlledExample />)
305
+ ```
306
+
307
+ ### Editable and readOnly
308
+
309
+ The editability of the content can be set with the combination of the `editable` and `readOnly` props.
310
+
311
+ The `readOnly` prop works like a "preventDefault" and disables any interaction by the user or API calls (e.g. copy-paste).
312
+ If the `editable` prop is set to `false`, the editor is also not focusable, and the `contenteditable="false"` is set on the content.
313
+
314
+ ```js
315
+ ---
316
+ type: example
317
+ ---
318
+ const EditableExample = () => {
319
+ const [settings, setSettings] = useState({
320
+ editable: true,
321
+ readOnly: false
322
+ })
323
+
324
+ return (
325
+ <View display="block" padding="medium medium small" background="primary">
326
+ <View display="block" margin="small none large">
327
+ <FormFieldGroup description="Settings" rowSpacing="small">
328
+ {Object.keys(settings).map((prop) => (
329
+ <Checkbox
330
+ label={prop}
331
+ key={prop}
332
+ defaultChecked={settings[prop]}
333
+ onChange={() =>
334
+ setSettings((prevState) => ({
335
+ ...prevState,
336
+ [prop]: !prevState[prop]
337
+ }))
338
+ }
339
+ />
340
+ ))}
341
+ </FormFieldGroup>
342
+ </View>
343
+
344
+ <SourceCodeEditor
345
+ label="editable code editor"
346
+ language="jsx"
347
+ editable={settings.editable}
348
+ readOnly={settings.readOnly}
349
+ defaultValue={`function example() {
350
+ console.log('example')
351
+ }`}
352
+ />
353
+ </View>
354
+ )
355
+ }
356
+ render(<EditableExample />)
357
+ ```
358
+
359
+ ### Gutter settings
360
+
361
+ The `lineNumbers` prop displays the line numbers in the side gutter, and the `foldGutter` prop displays the toggleable fold icon next to foldable code blocks.
362
+
363
+ If any of these two props are active, the gutter is displayed, and the `highlightActiveLineGutter` highlights the active line in the gutter. (The `highlightActiveLine` prop highlights the line itself.)
364
+
365
+ ```js
366
+ ---
367
+ type: example
368
+ ---
369
+ const GutterExample = () => {
370
+ const [settings, setSettings] = useState({
371
+ lineNumbers: true,
372
+ foldGutter: true,
373
+ highlightActiveLineGutter: true,
374
+ highlightActiveLine: true
375
+ })
376
+
377
+ return (
378
+ <View display="block" padding="medium medium small" background="primary">
379
+ <View display="block" margin="small none large">
380
+ <FormFieldGroup description="Settings" rowSpacing="small">
381
+ {[
382
+ 'lineNumbers',
383
+ 'foldGutter',
384
+ 'highlightActiveLineGutter',
385
+ 'highlightActiveLine'
386
+ ].map((prop) => (
387
+ <Checkbox
388
+ label={prop}
389
+ key={prop}
390
+ defaultChecked={settings[prop]}
391
+ onChange={() => {
392
+ setSettings((prevSettings) => ({
393
+ ...prevSettings,
394
+ [prop]: !prevSettings[prop]
395
+ }))
396
+ }}
397
+ />
398
+ ))}
399
+ </FormFieldGroup>
400
+ </View>
401
+
402
+ <SourceCodeEditor
403
+ label="gutter example"
404
+ language="jsx"
405
+ lineNumbers={settings.lineNumbers}
406
+ foldGutter={settings.foldGutter}
407
+ highlightActiveLineGutter={settings.highlightActiveLineGutter}
408
+ highlightActiveLine={settings.highlightActiveLine}
409
+ defaultValue={`const fruit: string = "apple"
410
+
411
+ function exampleMethod(props: Props) {
412
+ return props ? props.value : null
413
+ }
414
+
415
+ /**
416
+ * This is an example
417
+ * @param {Object} props
418
+ */
419
+ const Example = () => {
420
+ return (
421
+ <View as="div" padding={'large'}>
422
+ <Position
423
+ renderTarget={<GoodComponent />}
424
+ placement='end center'
425
+ offsetX='20px'
426
+ >
427
+ <span style={{ padding: '8px', background: 'white' }}>
428
+ Positioned content
429
+ </span>
430
+ </Position>
431
+ </View>
432
+ )
433
+ }
434
+
435
+ render(<Example />)`}
436
+ />
437
+ </View>
438
+ )
439
+ }
440
+ render(<GutterExample />)
441
+ ```
442
+
443
+ ### Indentation
444
+
445
+ ##### auto-indent
446
+
447
+ The editor automatically indents the lines on input. The `indentOnLoad` prop indents the code on the initial load and when the `value` prop is updated.
448
+
449
+ ##### indent with tab
450
+
451
+ When the `indentWithTab` feature is turned on, Tab and Shift-Tab will indent the code.
452
+ By default, it is turned off, and tabbing will focus the next element in the tab order.
453
+
454
+ **Accessibility note**: Even if `indentWithTab` is on, pressing Escape before tabbing will not handle indentation and will handle focus instead. When using this feature, it is recommended to add info about this behaviour in your documentation.
455
+
456
+ ##### indent unit
457
+
458
+ You can also override the unit by which indentation happens (defaults to 2 spaces).
459
+ The `indentUnitCount` prop should be a string consisting either entirely of spaces or entirely of tabs.
460
+
461
+ ##### manual re-indent
462
+
463
+ Another useful feature is the `indentAll` public method on the `SourceCodeEditor` component that can be called anytime to trigger a re-indent on the content.
464
+
465
+ ```js
466
+ ---
467
+ type: example
468
+ ---
469
+ const IndentExample = () => {
470
+ const [indentWithTab, setIndentWithTab] = useState(true)
471
+ const [indentUnitCount, setIndentUnitCount] = useState('2')
472
+
473
+ const editorRef = useRef(null)
474
+
475
+ const indentUnit = Array(parseInt(indentUnitCount)).fill(' ').join('')
476
+
477
+ const reIndent = () => {
478
+ if (editorRef.current) {
479
+ editorRef.current.indentAll()
480
+ }
481
+ }
482
+
483
+ const indentCurrentSelection = () => {
484
+ if (editorRef.current) {
485
+ editorRef.current.indentCurrentSelection()
486
+ }
487
+ }
488
+
489
+ return (
490
+ <View display="block" padding="medium medium small" background="primary">
491
+ <View display="block" margin="small none large">
492
+ <FormFieldGroup description="Settings">
493
+ <Checkbox
494
+ label="indentWithTab"
495
+ defaultChecked={indentWithTab}
496
+ onChange={() => setIndentWithTab(!indentWithTab)}
497
+ />
498
+ <RadioInputGroup
499
+ name="indentUnitCount"
500
+ value={indentUnitCount}
501
+ description="indent space count"
502
+ onChange={(e, value) => {
503
+ setIndentUnitCount(value)
504
+ reIndent()
505
+ }}
506
+ >
507
+ {['2', '4', '8'].map((count) => (
508
+ <RadioInput key={count} label={count} value={count} />
509
+ ))}
510
+ </RadioInputGroup>
511
+ <Button onClick={reIndent}>Re-indent code</Button>
512
+ <Button onClick={indentCurrentSelection}>
513
+ Indent current selection
514
+ </Button>
515
+ </FormFieldGroup>
516
+ </View>
517
+
518
+ <SourceCodeEditor
519
+ label="indent example"
520
+ ref={editorRef}
521
+ language="jsx"
522
+ indentWithTab={indentWithTab}
523
+ indentUnit={indentUnit}
524
+ defaultValue={`const fruit: string = "apple"
525
+
526
+ function exampleMethod(props: Props) {
527
+ return props ? props.value : null
528
+ }
529
+
530
+ /**
531
+ * This is an example
532
+ * @param {Object} props
533
+ */
534
+ const Example = () => {
535
+ return (
536
+ <View as="div" padding={'large'}>
537
+ <Position
538
+ renderTarget={<GoodComponent />}
539
+ placement='end center'
540
+ offsetX='20px'
541
+ >
542
+ <span style={{ padding: '8px', background: 'white' }}>
543
+ Positioned content
544
+ </span>
545
+ </Position>
546
+ </View>
547
+ )
548
+ }
549
+
550
+ render(<Example />)`}
551
+ />
552
+ </View>
553
+ )
554
+ }
555
+
556
+ render(<IndentExample />)
557
+ ```
558
+
559
+ ### Direction
560
+
561
+ SourceCodeEditor is a bidirectional component. It will inherit the text-direction from the context, and can be set directly on the component with the `direction` prop. The `rtl` mode will flip the overall layout and selects base paragraph direction to RTL.
562
+
563
+ The `rtlMoveVisually` prop controls the cursor movement in RTL mode, whether it should be **visual** (pressing the left arrow moves the cursor left) or **logical** (pressing the left arrow moves to the next lower index in the string, which is visually right in RTL text).
564
+
565
+ ```js
566
+ ---
567
+ type: example
568
+ ---
569
+ const DirectionExample = () => {
570
+ const [settings, setSettings] = useState({
571
+ contextDir: 'unset',
572
+ editorDir: 'unset',
573
+ rtlMoveVisually: true
574
+ })
575
+
576
+ return (
577
+ <InstUISettingsProvider
578
+ dir={settings.contextDir !== 'unset' ? settings.contextDir : undefined}
579
+ >
580
+ <View
581
+ display="block"
582
+ padding="medium medium small"
583
+ background="primary"
584
+ >
585
+ <View display="block" margin="small none large">
586
+ <FormFieldGroup
587
+ description="Settings"
588
+ layout="columns"
589
+ vAlign="top"
590
+ >
591
+ <RadioInputGroup
592
+ name="contextDir"
593
+ value={settings.contextDir}
594
+ description="context direction"
595
+ onChange={(e, contextDir) => {
596
+ setSettings((prevSettings) => ({
597
+ ...prevSettings,
598
+ contextDir
599
+ }))
600
+ }}
601
+ >
602
+ {['unset', 'ltr', 'rtl'].map((dir) => (
603
+ <RadioInput key={dir} label={dir} value={dir} />
604
+ ))}
605
+ </RadioInputGroup>
606
+ <RadioInputGroup
607
+ name="editorDir"
608
+ value={settings.editorDir}
609
+ description="editor direction"
610
+ onChange={(e, editorDir) => {
611
+ setSettings((prevSettings) => ({
612
+ ...prevSettings,
613
+ editorDir
614
+ }))
615
+ }}
616
+ >
617
+ {['unset', 'ltr', 'rtl'].map((dir) => (
618
+ <RadioInput key={dir} label={dir} value={dir} />
619
+ ))}
620
+ </RadioInputGroup>
621
+ <Checkbox
622
+ label="rtlMoveVisually"
623
+ defaultChecked={settings.rtlMoveVisually}
624
+ onChange={() => {
625
+ setSettings((prevSettings) => ({
626
+ ...prevSettings,
627
+ rtlMoveVisually: !prevSettings.rtlMoveVisually
628
+ }))
629
+ }}
630
+ />
631
+ </FormFieldGroup>
632
+ </View>
633
+
634
+ <SourceCodeEditor
635
+ label="editable code editor"
636
+ language="jsx"
637
+ direction={
638
+ settings.editorDir !== 'unset' ? settings.editorDir : undefined
639
+ }
640
+ rtlMoveVisually={settings.rtlMoveVisually}
641
+ defaultValue={`function directionExample(dir?: 'ltr' | 'rtl') {
642
+ console.log(dir)
643
+ }`}
644
+ />
645
+ </View>
646
+ </InstUISettingsProvider>
647
+ )
648
+ }
649
+
650
+ render(<DirectionExample />)
651
+ ```
652
+
653
+ ### Focus management
654
+
655
+ By default, SourceCodeEditor is tabbable/focusable, and once it is in focus, tabbing will move the focus on the page. These behaviours can be changed with the [editable](/#SourceCodeEditor/#editable-and-readonly) and [indentWithTab](/#SourceCodeEditor/#indentation-indent-with-tab) props.
656
+
657
+ The `autofocus` prop will automatically focus the editor on the initial render.
658
+
659
+ You can also manually focus the editor with its public `focus` method (the `hasFocus` getter is also available).
660
+
661
+ ```js
662
+ ---
663
+ type: example
664
+ ---
665
+ const FocusExample = () => {
666
+ const [indentWithTab, setIndentWithTab] = useState(true)
667
+ const [indentUnitCount, setIndentUnitCount] = useState('2')
668
+
669
+ const editorRef = useRef(null)
670
+
671
+ return (
672
+ <View display="block" padding="medium medium small" background="primary">
673
+ <View display="block" margin="small none large">
674
+ <Button
675
+ onClick={() => {
676
+ console.log('manual focus')
677
+ editorRef.current.focus()
678
+ }}
679
+ >
680
+ Focus editor
681
+ </Button>
682
+ </View>
683
+
684
+ <SourceCodeEditor
685
+ label="focus example"
686
+ ref={editorRef}
687
+ language="jsx"
688
+ onFocus={() => {
689
+ console.log('onFocus')
690
+ console.log({ hasFocus: editorRef.current.hasFocus })
691
+ }}
692
+ onBlur={() => {
693
+ console.log('onBlur')
694
+ console.log({ hasFocus: editorRef.current.hasFocus })
695
+ }}
696
+ defaultValue={`function exampleMethod(props: Props) {
697
+ return props ? props.value : null
698
+ }`}
699
+ />
700
+ </View>
701
+ )
702
+ }
703
+
704
+ render(<FocusExample />)
705
+ ```
706
+
707
+ ### Attachment
708
+
709
+ The `attachment` prop removes the top/bottom border-radius and margin of the editor, so it can be attached to the top or bottom of another element.
710
+
711
+ ```js
712
+ ---
713
+ type: example
714
+ ---
715
+ const AttachmentExample = () => {
716
+ const [attachment, setAttachment] = useState('none')
717
+
718
+ const viewProps = {
719
+ as: 'div',
720
+ background: 'primary-inverse',
721
+ padding: 'small'
722
+ }
723
+
724
+ return (
725
+ <View display="block" padding="medium medium small" background="primary">
726
+ <View display="block" margin="small none large">
727
+ <RadioInputGroup
728
+ name="attachmentExample"
729
+ value={attachment}
730
+ description="attachment"
731
+ onChange={(e, attachment) => {
732
+ setAttachment(attachment)
733
+ }}
734
+ >
735
+ {['none', 'top', 'bottom'].map((attachment) => (
736
+ <RadioInput
737
+ key={attachment}
738
+ label={attachment}
739
+ value={attachment}
740
+ />
741
+ ))}
742
+ </RadioInputGroup>
743
+ </View>
744
+
745
+ {attachment === 'bottom' && (
746
+ <View {...viewProps}>
747
+ CodeEditor is attached to the bottom of this element
748
+ </View>
749
+ )}
750
+ <SourceCodeEditor
751
+ label="attachment example"
752
+ language="jsx"
753
+ attachment={attachment === 'none' ? undefined : attachment}
754
+ defaultValue={`const fruit: string = "apple"
755
+
756
+ function exampleMethod(props: Props) {
757
+ return props ? props.value : null
758
+ }`}
759
+ />
760
+ {attachment === 'top' && (
761
+ <View {...viewProps}>
762
+ CodeEditor is attached to the top of this element
763
+ </View>
764
+ )}
765
+ </View>
766
+ )
767
+ }
768
+
769
+ render(<AttachmentExample />)
770
+ ```
771
+
772
+ ### Search
773
+
774
+ To enable the search panel use the `searchConfig` prop.
775
+
776
+ You can open the search panel in the code editor by pressing `cmd/ctrl+f` when the editor is in focus (otherwise the browser's search will open). The reason you would use this instead of the browser native search is because it will miss results that are far out of view in the text rendered by the editor. This is the limitation of the underlying CodeMirror component.
777
+
778
+ Hitting `Enter` jumps to the next result and `Shift+Enter` to the previous. Alternatively you can use the up and down buttons to the right of the input field.
779
+
780
+ Placement: the search panel will open at the bottom of the editor. This cannot be changed unfortunately due to a limitation in CodeMirror.
781
+
782
+ ```js
783
+ ---
784
+ type: example
785
+ ---
786
+ <SourceCodeEditor
787
+ label="lorem"
788
+ language="markdown"
789
+ defaultValue={`Lorem ipsum dolor sit amet, officia excepteur ex fugiat reprehenderit
790
+ enim labore culpa sint ad nisi Lorem pariatur mollit ex esse exercitation amet.
791
+ Nisi anim cupidatat excepteur officia.
792
+ `}
793
+ searchConfig={{
794
+ placeholder: 'Find in code...',
795
+ nextResultLabel: 'Next result',
796
+ prevResultLabel: 'Previouse result',
797
+ }}
798
+ />
799
+ ```