Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[UI Framework] Add isReadOnly prop to KuiCodeEditor. #14804

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions ui_framework/dist/ui_framework.css
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,10 @@ input[type="button"] {

.kuiCodeEditorWrapper {
position: relative; }
.kuiCodeEditorWrapper .ace_hidden-cursors {
opacity: 0; }
.kuiCodeEditorWrapper.kuiCodeEditorWrapper-isEditing .ace_hidden-cursors {
opacity: 1; }

.kuiCodeEditorKeyboardHint {
position: absolute;
Expand Down
15 changes: 15 additions & 0 deletions ui_framework/doc_site/src/views/code_editor/code_editor_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import {
import CodeEditor from './code_editor';
const codeEditorSource = require('!!raw-loader!./code_editor');

import ReadOnly from './read_only';
const readOnlySource = require('!!raw-loader!./read_only');

export default props => (
<GuidePage title={props.route.name}>
<GuideSection
Expand All @@ -36,5 +39,17 @@ export default props => (
<CodeEditor />
</GuideDemo>
</GuideSection>

<GuideSection
title="Read-only"
source={[{
type: GuideSectionTypes.JS,
code: readOnlySource,
}]}
>
<GuideDemo>
<ReadOnly />
</GuideDemo>
</GuideSection>
</GuidePage>
);
27 changes: 27 additions & 0 deletions ui_framework/doc_site/src/views/code_editor/read_only.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React, { Component } from 'react';

import 'brace/mode/less';
import 'brace/theme/github';

import {
KuiCodeEditor
} from '../../../../components';

export default class extends Component {
state = {
value: '<p>This code is read only</p>'
};

render() {
return (
<KuiCodeEditor
mode="less"
theme="github"
width="100%"
value={this.state.value}
setOptions={{ fontSize: '14px' }}
isReadOnly
/>
);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`KuiCodeEditor hint element should be disabled when the ui ace box gains focus 1`] = `
exports[`KuiCodeEditor behavior hint element should be disabled when the ui ace box gains focus 1`] = `
<div
className="kuiCodeEditorKeyboardHint kuiCodeEditorKeyboardHint-isInactive"
data-test-subj="codeEditorHint"
Expand All @@ -23,7 +23,7 @@ exports[`KuiCodeEditor hint element should be disabled when the ui ace box gains
</div>
`;

exports[`KuiCodeEditor hint element should be enabled when the ui ace box loses focus 1`] = `
exports[`KuiCodeEditor behavior hint element should be enabled when the ui ace box loses focus 1`] = `
<div
className="kuiCodeEditorKeyboardHint"
data-test-subj="codeEditorHint"
Expand Down Expand Up @@ -158,3 +158,99 @@ exports[`KuiCodeEditor is rendered 1`] = `
</div>
</div>
`;

exports[`KuiCodeEditor props isReadOnly doesn't render hint 1`] = `
<div
class="kuiCodeEditorWrapper"
>
<div
class=" ace_editor ace-tm"
id="brace-editor"
style="width: 500px; height: 500px;"
>
<textarea
autocapitalize="off"
autocorrect="off"
class="ace_text-input"
spellcheck="false"
style="opacity: 0;"
tabindex="-1"
wrap="off"
/>
<div
class="ace_gutter"
>
<div
class="ace_layer ace_gutter-layer ace_folding-enabled"
/>
<div
class="ace_gutter-active-line"
style="display: none;"
/>
</div>
<div
class="ace_scroller"
>
<div
class="ace_content"
>
<div
class="ace_layer ace_print-margin-layer"
>
<div
class="ace_print-margin"
style="left: 4px; visibility: visible;"
/>
</div>
<div
class="ace_layer ace_marker-layer"
/>
<div
class="ace_layer ace_text-layer"
style="padding: 0px 4px;"
/>
<div
class="ace_layer ace_marker-layer"
/>
<div
class="ace_layer ace_cursor-layer ace_hidden-cursors"
>
<div
class="ace_cursor"
/>
</div>
</div>
</div>
<div
class="ace_scrollbar ace_scrollbar-v"
style="display: none; width: 20px;"
>
<div
class="ace_scrollbar-inner"
style="width: 20px;"
/>
</div>
<div
class="ace_scrollbar ace_scrollbar-h"
style="display: none; height: 20px;"
>
<div
class="ace_scrollbar-inner"
style="height: 20px;"
/>
</div>
<div
style="height: auto; width: auto; top: 0px; left: 0px; visibility: hidden; position: absolute; white-space: pre; overflow: hidden;"
>
<div
style="height: auto; width: auto; top: 0px; left: 0px; visibility: hidden; position: absolute; white-space: pre; overflow: visible;"
/>
<div
style="height: auto; width: auto; top: 0px; left: 0px; visibility: hidden; position: absolute; white-space: pre; overflow: visible;"
>
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
</div>
</div>
</div>
</div>
`;
10 changes: 10 additions & 0 deletions ui_framework/src/components/code_editor/_code_editor.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
.kuiCodeEditorWrapper {
position: relative;

.ace_hidden-cursors {
opacity: 0;
}

&.kuiCodeEditorWrapper-isEditing {
.ace_hidden-cursors {
opacity: 1;
}
}
}

.kuiCodeEditorKeyboardHint {
Expand Down
106 changes: 82 additions & 24 deletions ui_framework/src/components/code_editor/code_editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import AceEditor from 'react-ace';
import { htmlIdGenerator, keyCodes } from '../../../services';

export class KuiCodeEditor extends Component {

state = {
isHintActive: true
isHintActive: true,
isEditing: false,
};

idGenerator = htmlIdGenerator();
Expand All @@ -30,6 +30,15 @@ export class KuiCodeEditor extends Component {
}
}

onFocusAce = (...args) => {
this.setState({
isEditing: true,
});
if (this.props.onFocus) {
this.props.onFocus(...args);
}
}

onBlurAce = (...args) => {
this.stopEditing();
if (this.props.onBlur) {
Expand All @@ -45,55 +54,97 @@ export class KuiCodeEditor extends Component {
};

startEditing = () => {
this.setState({ isHintActive: false });
this.setState({
isHintActive: false,
});
this.aceEditor.editor.textInput.focus();
}

stopEditing() {
this.setState({ isHintActive: true });
this.setState({
isHintActive: true,
isEditing: false,
});
}

render() {
const {
width,
height,
onBlur, // eslint-disable-line no-unused-vars
isReadOnly,
setOptions,
cursorStart,
...rest,
} = this.props;

const classes = classNames('kuiCodeEditorKeyboardHint', {
const classes = classNames('kuiCodeEditorWrapper', {
'kuiCodeEditorWrapper-isEditing': this.state.isEditing,
});

const promptClasses = classNames('kuiCodeEditorKeyboardHint', {
'kuiCodeEditorKeyboardHint-isInactive': !this.state.isHintActive
});

let filteredCursorStart;

const options = { ...setOptions };

if (isReadOnly) {
// Put the cursor at the beginning of the editor, so that it doesn't look like
// a prompt to begin typing.
filteredCursorStart = -1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this logic still needed now that css is used to hide the cursor?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it still makes sense to put the cursor at the beginning for people who are using the keyboard to interact with the content. I'm guessing they'd want to copy/paste it and it makes sense to me intuitively to do that from start to end rather than the reverse.


Object.assign(options, {
readOnly: true,
highlightActiveLine: false,
highlightGutterLine: false,
});
} else {
filteredCursorStart = cursorStart;
}

const activity =
isReadOnly
? 'interacting with the code'
: 'editing';

const prompt = (
<div
className={promptClasses}
id={this.idGenerator('codeEditor')}
ref={(hint) => { this.editorHint = hint; }}
tabIndex="0"
role="button"
onClick={this.startEditing}
onKeyDown={this.onKeyDownHint}
data-test-subj="codeEditorHint"
>
<p className="kuiText kuiVerticalRhythmSmall">
Press Enter to start {activity}.
</p>

<p className="kuiText kuiVerticalRhythmSmall">
When you&rsquo;re done, press Escape to stop {activity}.
</p>
</div>
);

return (
<div
className="kuiCodeEditorWrapper"
className={classes}
style={{ width, height }}
>
<div
className={classes}
id={this.idGenerator('codeEditor')}
ref={(hint) => { this.editorHint = hint; }}
tabIndex="0"
role="button"
onClick={this.startEditing}
onKeyDown={this.onKeyDownHint}
data-test-subj="codeEditorHint"
>
<p className="kuiText kuiVerticalRhythmSmall">
Press Enter to start editing.
</p>

<p className="kuiText kuiVerticalRhythmSmall">
When you&rsquo;re done, press Escape to stop editing.
</p>
</div>
{prompt}

<AceEditor
ref={this.aceEditorRef}
width={width}
height={height}
onFocus={this.onFocusAce}
onBlur={this.onBlurAce}
setOptions={options}
cursorStart={filteredCursorStart}
{...rest}
/>
</div>
Expand All @@ -105,4 +156,11 @@ KuiCodeEditor.propTypes = {
width: PropTypes.string,
height: PropTypes.string,
onBlur: PropTypes.func,
isReadOnly: PropTypes.bool,
setOptions: PropTypes.object,
cursorStart: PropTypes.number,
};

KuiCodeEditor.defaultProps = {
setOptions: {},
};
Loading