@instructure/ui-source-code-editor 8.25.1-snapshot-19

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