* feat: 🎸 Add code-editor component (#1207)
* feat: 🎸 Add code-editor component Added code editor component which was taken from HCP, tweaked styles and imports to use boundary assets ✅ Closes: ICU-5167
This commit is contained in:
1 parent
40184006cd
commit
b722fa361b
22 files changed
+637
-37
No files matched your search
@@ -0,0 +1,6 @@
|
||||
<div
|
||||
data-test-code-editor-field-editor
|
||||
...attributes
|
||||
class='{{@classNames}} rose-codemirror-container'
|
||||
{{code-mirror value=@value onInput=@onInput options=@options}}
|
||||
></div>
|
||||
@@ -0,0 +1,8 @@
|
||||
<div data-test-code-editor>
|
||||
{{yield
|
||||
(hash
|
||||
fieldEditor=(component 'rose/code-editor/field-editor' value=@codeValue)
|
||||
toolbar=(component 'rose/code-editor/toolbar' copyText=@codeValue)
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
@@ -0,0 +1,90 @@
|
||||
import { Meta, Story, Preview } from '@storybook/addon-docs/blocks';
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
|
||||
<Meta title="Rose|Code Editor" component="CodeEditor" />
|
||||
|
||||
# Code Editor
|
||||
|
||||
`CodeEditor` is a component that yields two presentational components which together provide an IDE-like UX.
|
||||
CodeEditor::fieldEditor is where the provided code is displayed with syntax highlighting.
|
||||
CodeEditor::toolbar is intended to go on top of the fieldEditor and provides a 'Copy code' button as well as other optional user-provided actions.
|
||||
|
||||
```html
|
||||
<CodeEditor @codeValue="{{this.codeIWantToSee}}" as |c|>
|
||||
<c.toolbar />
|
||||
<c.fieldEditor />
|
||||
</CodeEditor>
|
||||
```
|
||||
|
||||
<!-- mdx seems to not be able to handle template literals -->
|
||||
|
||||
export const codeValue =
|
||||
'hcp_boundary_cluster_id = "<cluster-id>"\n\n' +
|
||||
'listener "tcp" {\n' +
|
||||
' address = "0.0.0.0:9202"\n' +
|
||||
' purpose = "proxy"\n' +
|
||||
'}\n\n' +
|
||||
'worker {\n' +
|
||||
' public_addr = "107.22.128.152"\n' +
|
||||
' auth_storage_path = "/home/ubuntu/boundary/worker1"\n' +
|
||||
' tags {\n' +
|
||||
' type = ["dev-worker", "ubuntu"]\n' +
|
||||
' }\n' +
|
||||
'}';
|
||||
|
||||
<Preview>
|
||||
<Story name="Readonly">
|
||||
{{
|
||||
template: hbs`
|
||||
<Rose::CodeEditor @codeValue={{codeValue}} as |c|>
|
||||
<c.toolbar />
|
||||
<c.fieldEditor @options={{options}} />
|
||||
</Rose::CodeEditor>`,
|
||||
context: {
|
||||
codeValue: codeValue,
|
||||
options: {
|
||||
mode: 'hcl',
|
||||
readOnly: true,
|
||||
},
|
||||
},
|
||||
}}
|
||||
</Story>
|
||||
</Preview>
|
||||
|
||||
<Preview>
|
||||
<Story name="CodeEditorShell">
|
||||
{{
|
||||
template: hbs`
|
||||
<Rose::CodeEditor @codeValue={{codeValue}} as |c|>
|
||||
<c.toolbar />
|
||||
<c.fieldEditor @classNames='rose-autosize' @options={{options}} />
|
||||
</Rose::CodeEditor>`,
|
||||
context: {
|
||||
codeValue: 'mkdir /home/ubuntu/boundary/',
|
||||
options: {
|
||||
mode: 'shell',
|
||||
readOnly: true,
|
||||
},
|
||||
},
|
||||
}}
|
||||
</Story>
|
||||
</Preview>
|
||||
|
||||
<Preview>
|
||||
<Story name="CodeEditorShellEditable">
|
||||
{{
|
||||
template: hbs`
|
||||
<Rose::CodeEditor @codeValue={{codeValue}} as |c|>
|
||||
<c.toolbar />
|
||||
<c.fieldEditor @classNames='autosize' @options={{options}} />
|
||||
</Rose::CodeEditor>`,
|
||||
context: {
|
||||
codeValue: 'mkdir /home/ubuntu/boundary/',
|
||||
options: {
|
||||
mode: 'shell',
|
||||
readOnly: false,
|
||||
},
|
||||
},
|
||||
}}
|
||||
</Story>
|
||||
</Preview>
|
||||
@@ -0,0 +1,29 @@
|
||||
<div class='rose-code-editor-toolbar' data-test-code-editor-toolbar>
|
||||
<div data-test-code-editor-toolbar-action class='code-editor-toolbar__action'>
|
||||
{{yield to='action'}}
|
||||
</div>
|
||||
|
||||
<div class='rose-code-editor-toolbar__right-aligned'>
|
||||
{{#if (has-block 'menu')}}
|
||||
<div
|
||||
data-test-code-editor-toolbar-menu
|
||||
class='rose-code-editor-toolbar__menu'
|
||||
>
|
||||
{{yield to='menu'}}
|
||||
</div>
|
||||
<div
|
||||
class='rose-code-editor-toolbar__menu-divider'
|
||||
data-test-code-editor-toolbar-menu-divider
|
||||
></div>
|
||||
{{/if}}
|
||||
<CopyButton
|
||||
@clipboardText={{@copyText}}
|
||||
@success={{this.copied}}
|
||||
class='rose-code-editor-toolbar__copy-button'
|
||||
data-test-code-editor-toolbar-copy-button
|
||||
>
|
||||
<Rose::Icon @name={{this.copyIconType}} @size='medium' />
|
||||
Copy code
|
||||
</CopyButton>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,25 @@
|
||||
import Component from '@glimmer/component';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { action } from '@ember/object';
|
||||
import { later } from '@ember/runloop';
|
||||
|
||||
export const COPY_ICON_TYPE = 'flight-icons/svg/clipboard-copy-16';
|
||||
export const COPIED_ICON_TYPE = 'flight-icons/svg/clipboard-checked-16';
|
||||
|
||||
export default class RoseCodeEditorToolbarComponent extends Component {
|
||||
@tracked copyIconType = COPY_ICON_TYPE;
|
||||
|
||||
@action
|
||||
copied() {
|
||||
let { onCopy } = this.args;
|
||||
let originalIconType = this.copyIconType;
|
||||
|
||||
this.copyIconType = COPIED_ICON_TYPE;
|
||||
|
||||
if (onCopy) {
|
||||
onCopy();
|
||||
}
|
||||
|
||||
later(() => (this.copyIconType = originalIconType), 1000);
|
||||
}
|
||||
}
|
||||
@@ -10,14 +10,16 @@ import { text, boolean, select } from '@storybook/addon-knobs';
|
||||
Proxies the built-in `LinkTo` component, applying a class `rose-nav-link`.
|
||||
|
||||
```html
|
||||
<Rose::Nav::Link @route='index'>Text</nav.link>
|
||||
<Rose::Nav::Link @route="index">Text</Rose::Nav::Link>
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Story name="Basic Nav Link">{{
|
||||
template: hbs`
|
||||
<Rose::Nav::Link @route='index'>Text</nav.link>
|
||||
<Story name="Basic Nav Link">
|
||||
{{
|
||||
template: hbs`
|
||||
<Rose::Nav::Link @route='index'>Text</Rose::Nav::Link>
|
||||
`,
|
||||
context: {},
|
||||
}}</Story>
|
||||
context: {},
|
||||
}}
|
||||
</Story>
|
||||
</Preview>
|
||||
@@ -0,0 +1,88 @@
|
||||
import Modifier from 'ember-modifier';
|
||||
import codemirror from 'codemirror';
|
||||
|
||||
import '../utilities/register-codemirror-hcl';
|
||||
import 'codemirror/mode/go/go';
|
||||
import 'codemirror/mode/javascript/javascript';
|
||||
import 'codemirror/mode/shell/shell';
|
||||
import 'codemirror/addon/edit/matchbrackets';
|
||||
import 'codemirror/addon/edit/closebrackets';
|
||||
import 'codemirror/addon/selection/active-line';
|
||||
|
||||
// Here we define default options for the editor.
|
||||
// These should follow the codemirror configuration types
|
||||
//
|
||||
const _PRESET_DEFAULTS = {
|
||||
theme: 'monokai',
|
||||
lineNumbers: true,
|
||||
cursorBlinkRate: 500,
|
||||
matchBrackets: true,
|
||||
autoCloseBrackets: true,
|
||||
styleActiveLine: true,
|
||||
mode: 'hcl',
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* `CodeMirror` implements a modifier that creates a CodeMirror instance on the provided element.
|
||||
*
|
||||
* The supported modes for the editor are currently: hcl, shell, go, javascript
|
||||
* The supported themes are: monokai
|
||||
*
|
||||
* Sample usage:
|
||||
* ```
|
||||
* <div
|
||||
* {{code-mirror value=@value onInput=@onInput options=@options}}
|
||||
* />
|
||||
* ```
|
||||
*
|
||||
* @class CodeMirror
|
||||
*
|
||||
*/
|
||||
export default class CodeMirrorModifier extends Modifier {
|
||||
_editor;
|
||||
|
||||
didInstall() {
|
||||
this._setup();
|
||||
}
|
||||
|
||||
didUpdateArguments() {
|
||||
if (this._editor?.getValue() !== this.args.named.value) {
|
||||
this._editor?.setValue(this.args.named.value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when editor contents change.
|
||||
* @method CodeMirror#_onChange
|
||||
* See documentation for the CodeMirror editor events, specifically 'change' event here https://codemirror.net/doc/manual.html#events.
|
||||
*/
|
||||
_onChange(editor) {
|
||||
const { onInput } = this.args.named;
|
||||
const newVal = editor.getValue();
|
||||
onInput && onInput(newVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the editor with default configuration merged with consumer-provided configuration.
|
||||
* Also registers a 'change' event on the editor.
|
||||
* @method CodeMirror#_setup
|
||||
*/
|
||||
_setup() {
|
||||
if (!this.element) {
|
||||
throw new Error('CodeMirror modifier has no element');
|
||||
}
|
||||
|
||||
const editor = codemirror(this.element, {
|
||||
..._PRESET_DEFAULTS,
|
||||
...(this.args.named.options || {}),
|
||||
value: this.args.named.value,
|
||||
});
|
||||
|
||||
editor.on('change', (editor) => {
|
||||
this._onChange(editor);
|
||||
});
|
||||
|
||||
this._editor = editor;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { modifier } from 'ember-modifier';
|
||||
|
||||
/**
|
||||
* Used to detect clicks occuring _inside_ the modified element.
|
||||
* Used to detect clicks occurring _inside_ the modified element.
|
||||
* This is useful especially for dropdowns to toggle content visibility
|
||||
* when the user clicks an item.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { modifier } from 'ember-modifier';
|
||||
|
||||
/**
|
||||
* Used to detect clicks occuring _outside_ of the modified element.
|
||||
* Used to detect clicks occurring _outside_ of the modified element.
|
||||
* This is useful especially for dropdowns to toggle content visibility
|
||||
* when the user clicks away.
|
||||
*/
|
||||
|
||||
@@ -19,3 +19,4 @@
|
||||
@import 'link-button';
|
||||
@import 'badge';
|
||||
@import 'toolbar';
|
||||
@import 'code-editor';
|
||||
@@ -0,0 +1,80 @@
|
||||
@use '../../variables/sizing';
|
||||
|
||||
// Codemirror overrides
|
||||
.rose-codemirror-container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.CodeMirror {
|
||||
max-width: 100%;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
font-family: ui-monospace, 'Menlo', monospace;
|
||||
}
|
||||
|
||||
.rose-autosize {
|
||||
.CodeMirror {
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.CodeMirror-scroll {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.CodeMirror-sizer {
|
||||
border-right-width: 0px !important;
|
||||
}
|
||||
|
||||
// Toolbar
|
||||
.rose-code-editor-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: var(--ui-gray-subtler-6);
|
||||
border-top: 1px solid var(--ui-gray-subtler-3);
|
||||
border-bottom: 1px solid var(--ui-gray-subtler-3);
|
||||
height: 2.75rem;
|
||||
|
||||
&__action {
|
||||
margin-left: sizing.rems(s);
|
||||
}
|
||||
|
||||
&__right-aligned {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__menu {
|
||||
margin-right: sizing.rems(s);
|
||||
|
||||
.pds-dropdownTrigger {
|
||||
box-shadow: none;
|
||||
|
||||
&__layoutWrapper {
|
||||
padding-left: sizing.rems(s);
|
||||
padding-right: sizing.rems(s);
|
||||
}
|
||||
}
|
||||
|
||||
&-divider {
|
||||
border-right: 1px solid var(--ui-gray-subtler-3);
|
||||
height: sizing.rems(xl);
|
||||
}
|
||||
}
|
||||
|
||||
&__copy-button {
|
||||
border: none;
|
||||
background-color: inherit;
|
||||
cursor: pointer;
|
||||
color: var(--ui-gray-starker-2);
|
||||
margin-right: sizing.rems(xs);
|
||||
margin-left: sizing.rems(s);
|
||||
height: sizing.rems(xl);
|
||||
|
||||
&-icon {
|
||||
margin-right: sizing.rems(xs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import codemirror from 'codemirror';
|
||||
import 'codemirror/addon/mode/simple';
|
||||
|
||||
// This utility defines 'hcl' mode for a codemirror editor and enables correct syntax highlighting.
|
||||
// Importing this file in the codemirror modifier will allow 'hcl' to be selected as a mode:
|
||||
// import 'cloud-ui-core/utils/register-codemirror-hcl'
|
||||
codemirror.defineSimpleMode('hcl', {
|
||||
start: [
|
||||
{ regex: /"(?:[^\\]|\\.)*?(?:"|$)/, token: 'string' }, // strings
|
||||
{ regex: /(\w+)(\s+)(=)/, token: ['keyword', 'null', 'null'] }, // assignment of variables
|
||||
{
|
||||
regex: /(build|deploy|release|hook|registry|type|runner|url)( )({)/,
|
||||
token: ['keyword', 'null', 'null'],
|
||||
}, // top level keywords
|
||||
{ regex: /(variable)\b/, token: 'keyword' }, // input variable keyword
|
||||
{ regex: /true|false|null|undefined/, token: 'atom' }, // bool keywords
|
||||
{
|
||||
regex: /0x[a-f\d]+|[-+]?(?:\.\d+|\d+\.?\d*)(?:e[-+]?\d+)?/i,
|
||||
token: 'number',
|
||||
}, // numbers
|
||||
{ regex: /(#|\/\/)(\s*\S*)/, token: 'comment' }, // single line comments
|
||||
{ regex: /(path)(.)/, token: ['variable-2', 'null'] }, // path variables
|
||||
{ regex: /(workspace)(.)(\S*)/, token: ['string', 'null', 'string'] }, // workspace variables
|
||||
{ regex: /\/\*/, token: 'comment', next: 'comment' }, // multi-line comment
|
||||
{ regex: /[-+/*=<>!]+/, token: 'operator' }, // operators
|
||||
{ regex: /[{[(]/, indent: true }, // for auto indent
|
||||
{ regex: /[}\])]/, dedent: true },
|
||||
],
|
||||
// The multi-line comment state.
|
||||
comment: [
|
||||
{ regex: /.*?\*\//, token: 'comment', next: 'start' },
|
||||
{ regex: /.*/, token: 'comment' },
|
||||
],
|
||||
meta: {
|
||||
dontIndentStates: ['comment'],
|
||||
lineComment: '#',
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from 'rose/components/rose/code-editor';
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from 'rose/components/rose/code-editor/field-editor';
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from 'rose/components/rose/code-editor/toolbar';
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from 'rose/modifiers/code-mirror';
|
||||
@@ -7,6 +7,9 @@ module.exports = function (defaults) {
|
||||
// Add options here
|
||||
});
|
||||
|
||||
app.import('node_modules/codemirror/lib/codemirror.css');
|
||||
app.import('node_modules/codemirror/theme/monokai.css');
|
||||
|
||||
/*
|
||||
This build file specifies the options for the dummy test app of this
|
||||
addon, located in `/tests/dummy`
|
||||
|
||||
@@ -31,8 +31,10 @@
|
||||
"doc:toc": "doctoc README.md"
|
||||
},
|
||||
"dependencies": {
|
||||
"codemirror": "5.65.7",
|
||||
"ember-auto-import": "^2.4.2",
|
||||
"ember-cli-babel": "^7.26.8",
|
||||
"ember-cli-clipboard": "^0.16.0",
|
||||
"ember-cli-htmlbars": "^5.7.1",
|
||||
"ember-composable-helpers": "^5.0.0",
|
||||
"ember-focus-trap": "^0.7.0",
|
||||
@@ -112,6 +114,6 @@
|
||||
"lint-staged": {
|
||||
"*.js": "eslint --fix",
|
||||
"*.hbs": "ember-template-lint --fix",
|
||||
"*.{js,scss}": "prettier --write"
|
||||
"*.{js,scss,mdx}": "prettier --write"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'ember-qunit';
|
||||
import { render } from '@ember/test-helpers';
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
|
||||
module('Integration | Component | rose/code-editor', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test('it renders', async function (assert) {
|
||||
const codeValue = 'export HCP_CLIENT_ID = {place your client_id here}';
|
||||
this.set('codeValue', codeValue);
|
||||
|
||||
await render(hbs`
|
||||
<Rose::CodeEditor
|
||||
@codeValue={{this.codeValue}}
|
||||
as |c|
|
||||
>
|
||||
<c.toolbar />
|
||||
<c.fieldEditor />
|
||||
</Rose::CodeEditor>
|
||||
`);
|
||||
assert.dom('[data-test-code-editor]').isVisible();
|
||||
assert.dom('[data-test-code-editor-toolbar]').isVisible();
|
||||
assert.dom('[data-test-code-editor-field-editor]').isVisible();
|
||||
assert.dom('[data-test-code-editor-field-editor]').includesText(codeValue);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'ember-qunit';
|
||||
import { typeIn, render, waitUntil } from '@ember/test-helpers';
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
|
||||
module(
|
||||
'Integration | Component | rose/code-editor/field-editor',
|
||||
function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
const editorSelector = '[data-test-code-editor-field-editor]';
|
||||
|
||||
test('it renders', async function (assert) {
|
||||
const codeValue = `export HCP_CLIENT_ID = {place your client_id here}`;
|
||||
this.set('codeValue', codeValue);
|
||||
await render(hbs`
|
||||
<Rose::CodeEditor::FieldEditor @value={{this.codeValue}} />
|
||||
`);
|
||||
assert.dom(editorSelector).isVisible();
|
||||
assert.dom(editorSelector).includesText(codeValue);
|
||||
|
||||
const myNewCode = 'NEW CODE';
|
||||
await typeIn(`${editorSelector} textarea`, myNewCode);
|
||||
assert.dom(editorSelector).includesText(myNewCode);
|
||||
});
|
||||
|
||||
test('it renders readonly', async function (assert) {
|
||||
const codeValue = `export HCP_CLIENT_ID = {place your client_id here}`;
|
||||
this.set('codeValue', codeValue);
|
||||
this.set('options', {
|
||||
readOnly: true,
|
||||
});
|
||||
await render(hbs`
|
||||
<Rose::CodeEditor::FieldEditor @value={{this.codeValue}} @options={{this.options}} />
|
||||
`);
|
||||
assert.dom(editorSelector).isVisible();
|
||||
assert.dom(editorSelector).includesText(codeValue);
|
||||
|
||||
const myNewCode = 'NEW CODE';
|
||||
waitUntil(async () => {
|
||||
try {
|
||||
// This should fail if the textarea is readonly
|
||||
await typeIn(`${editorSelector} textarea`, myNewCode);
|
||||
} catch {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
assert.dom(editorSelector).doesNotIncludeText(myNewCode);
|
||||
});
|
||||
|
||||
test('it calls onInput on change', async function (assert) {
|
||||
const codeValue = `export HCP_CLIENT_ID = {place your client_id here}`;
|
||||
const onInput = () => {
|
||||
this.set('called', true);
|
||||
};
|
||||
this.set('codeValue', codeValue);
|
||||
this.set('onInput', onInput);
|
||||
await render(hbs`
|
||||
<Rose::CodeEditor::FieldEditor @value={{this.codeValue}} @onInput={{this.onInput}} />
|
||||
`);
|
||||
assert.dom(editorSelector).isVisible();
|
||||
assert.dom(editorSelector).includesText(codeValue);
|
||||
|
||||
const myNewCode = 'NEW CODE';
|
||||
await typeIn(`${editorSelector} textarea`, myNewCode);
|
||||
assert.dom(editorSelector).includesText(myNewCode);
|
||||
assert.true(this.called);
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,55 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'ember-qunit';
|
||||
import { click, render } from '@ember/test-helpers';
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
|
||||
module('Integration | Component | rose/code-editor/toolbar', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
const toolbarSelector = '[data-test-code-editor-toolbar]';
|
||||
const copyButtonSelector = '[data-test-code-editor-toolbar-copy-button]';
|
||||
const menuDividerSelector = '[data-test-code-editor-toolbar-menu-divider]';
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
const copyText = 'copyText';
|
||||
this.set('copyText', copyText);
|
||||
});
|
||||
|
||||
test('it renders', async function (assert) {
|
||||
await render(hbs`
|
||||
<Rose::CodeEditor::Toolbar @copyText={{this.copyText}} />
|
||||
`);
|
||||
assert.dom(toolbarSelector).isVisible();
|
||||
assert.dom(copyButtonSelector).isVisible();
|
||||
assert.dom(menuDividerSelector).doesNotExist();
|
||||
});
|
||||
|
||||
test('it displays action', async function (assert) {
|
||||
await render(hbs`
|
||||
<Rose::CodeEditor::Toolbar @onCopy={{this.copyText}}>
|
||||
<:action>
|
||||
<div data-test-my-action>Hello</div>
|
||||
</:action>
|
||||
</Rose::CodeEditor::Toolbar>
|
||||
`);
|
||||
assert.dom(toolbarSelector).isVisible();
|
||||
assert.dom(copyButtonSelector).isVisible();
|
||||
assert.dom(menuDividerSelector).doesNotExist();
|
||||
assert.dom('[data-test-my-action]').isVisible();
|
||||
});
|
||||
|
||||
test('it calls onCopy callback', async function (assert) {
|
||||
const onCopy = () => {
|
||||
this.set('called', true);
|
||||
};
|
||||
this.set('onCopy', onCopy);
|
||||
await render(hbs`
|
||||
<Rose::CodeEditor::Toolbar @copyText={{this.copyText}} @onCopy={{this.onCopy}} />
|
||||
`);
|
||||
assert.dom(toolbarSelector).isVisible();
|
||||
assert.dom(copyButtonSelector).isVisible();
|
||||
assert.dom(menuDividerSelector).doesNotExist();
|
||||
|
||||
await click(copyButtonSelector);
|
||||
assert.true(this.called);
|
||||
});
|
||||
});
|
||||
@@ -3869,7 +3869,7 @@
|
||||
ember-cli-babel "^7.22.1"
|
||||
ember-compatibility-helpers "^1.1.1"
|
||||
|
||||
"@ember/render-modifiers@^2.0.4":
|
||||
"@ember/render-modifiers@^1.0.2 || ^2.0.0", "@ember/render-modifiers@^2.0.4":
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@ember/render-modifiers/-/render-modifiers-2.0.4.tgz#0ac7af647cb736076dbfcd54ca71e090cd329d71"
|
||||
integrity sha512-Zh/fo5VUmVzYHkHVvzWVjJ1RjFUxA2jH0zCp2+DQa80Bf3DUXauiEByxU22UkN4LFT55DBFttC0xCQSJG3WTsg==
|
||||
@@ -9420,13 +9420,13 @@ browserify-zlib@^0.2.0:
|
||||
pako "~1.0.5"
|
||||
|
||||
browserslist@4.14.2, browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.16.5, browserslist@^4.16.6, browserslist@^4.16.7, browserslist@^4.17.3, browserslist@^4.17.5, browserslist@^4.19.1, browserslist@^4.20.2, browserslist@^4.21.0:
|
||||
version "4.21.1"
|
||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.1.tgz#c9b9b0a54c7607e8dc3e01a0d311727188011a00"
|
||||
integrity sha512-Nq8MFCSrnJXSc88yliwlzQe3qNe3VntIjhsArW9IJOEPSHNx23FalwApUVbzAWABLhYJJ7y8AynWI/XM8OdfjQ==
|
||||
version "4.21.2"
|
||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.2.tgz#59a400757465535954946a400b841ed37e2b4ecf"
|
||||
integrity sha512-MonuOgAtUB46uP5CezYbRaYKBNt2LxP0yX+Pmj4LkcDFGkn9Cbpi83d9sCjwQDErXsIJSzY5oKGDbgOlF/LPAA==
|
||||
dependencies:
|
||||
caniuse-lite "^1.0.30001359"
|
||||
electron-to-chromium "^1.4.172"
|
||||
node-releases "^2.0.5"
|
||||
caniuse-lite "^1.0.30001366"
|
||||
electron-to-chromium "^1.4.188"
|
||||
node-releases "^2.0.6"
|
||||
update-browserslist-db "^1.0.4"
|
||||
|
||||
bser@2.1.1:
|
||||
@@ -9758,10 +9758,10 @@ caniuse-api@^3.0.0:
|
||||
lodash.memoize "^4.1.2"
|
||||
lodash.uniq "^4.5.0"
|
||||
|
||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001157, caniuse-lite@^1.0.30001359:
|
||||
version "1.0.30001364"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001364.tgz#1e118f0e933ed2b79f8d461796b8ce45398014a0"
|
||||
integrity sha512-9O0xzV3wVyX0SlegIQ6knz+okhBB5pE0PC40MNdwcipjwpxoUEHL24uJ+gG42cgklPjfO5ZjZPme9FTSN3QT2Q==
|
||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001157, caniuse-lite@^1.0.30001366:
|
||||
version "1.0.30001367"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001367.tgz#2b97fe472e8fa29c78c5970615d7cd2ee414108a"
|
||||
integrity sha512-XDgbeOHfifWV3GEES2B8rtsrADx4Jf+juKX2SICJcaUhjYBO3bR96kvEIHa15VU6ohtOhBZuPGGYGbXMRn0NCw==
|
||||
|
||||
capture-exit@^2.0.0:
|
||||
version "2.0.0"
|
||||
@@ -10155,6 +10155,15 @@ cli-width@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
|
||||
integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
|
||||
|
||||
clipboard@^2.0.6:
|
||||
version "2.0.11"
|
||||
resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.11.tgz#62180360b97dd668b6b3a84ec226975762a70be5"
|
||||
integrity sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==
|
||||
dependencies:
|
||||
good-listener "^1.2.2"
|
||||
select "^1.1.2"
|
||||
tiny-emitter "^2.0.0"
|
||||
|
||||
clipboard@^2.0.8:
|
||||
version "2.0.8"
|
||||
resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.8.tgz#ffc6c103dd2967a83005f3f61976aa4655a4cdba"
|
||||
@@ -10251,6 +10260,11 @@ code-point-at@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
|
||||
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
|
||||
|
||||
codemirror@5.65.7:
|
||||
version "5.65.7"
|
||||
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.65.7.tgz#29af41ce5f4c2b8f1c1e16f4e645ff392823716a"
|
||||
integrity sha512-zb67cXzgugIQmb6tfD4G11ILjYoMfTjwcjn+cWsa4GewlI2adhR/h3kolkoCQTm1msD/1BuqVTKuO09ELsS++A==
|
||||
|
||||
collapse-white-space@^1.0.2:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287"
|
||||
@@ -11757,10 +11771,10 @@ electron-rebuild@^3.2.6:
|
||||
tar "^6.0.5"
|
||||
yargs "^17.0.1"
|
||||
|
||||
electron-to-chromium@^1.4.172:
|
||||
version "1.4.182"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.182.tgz#5d59214ebfe90b36f23e81cd226a42732cd8c677"
|
||||
integrity sha512-OpEjTADzGoXABjqobGhpy0D2YsTncAax7IkER68ycc4adaq0dqEG9//9aenKPy7BGA90bqQdLac0dPp6uMkcSg==
|
||||
electron-to-chromium@^1.4.188:
|
||||
version "1.4.195"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.195.tgz#139b2d95a42a3f17df217589723a1deac71d1473"
|
||||
integrity sha512-vefjEh0sk871xNmR5whJf9TEngX+KTKS3hOHpjoMpauKkwlGwtMz1H8IaIjAT/GNnX0TbGwAdmVoXCAzXf+PPg==
|
||||
|
||||
element-resize-detector@^1.2.2:
|
||||
version "1.2.3"
|
||||
@@ -11836,6 +11850,41 @@ ember-auto-import@^1.10.1, ember-auto-import@^1.11.2, ember-auto-import@^1.2.15,
|
||||
walk-sync "^0.3.3"
|
||||
webpack "^4.43.0"
|
||||
|
||||
ember-auto-import@^1.11.3:
|
||||
version "1.12.2"
|
||||
resolved "https://registry.yarnpkg.com/ember-auto-import/-/ember-auto-import-1.12.2.tgz#cc7298ee5c0654b0249267de68fb27a2861c3579"
|
||||
integrity sha512-gLqML2k77AuUiXxWNon1FSzuG1DV7PEPpCLCU5aJvf6fdL6rmFfElsZRh+8ELEB/qP9dT+LHjNEunVzd2dYc8A==
|
||||
dependencies:
|
||||
"@babel/core" "^7.1.6"
|
||||
"@babel/preset-env" "^7.10.2"
|
||||
"@babel/traverse" "^7.1.6"
|
||||
"@babel/types" "^7.1.6"
|
||||
"@embroider/shared-internals" "^1.0.0"
|
||||
babel-core "^6.26.3"
|
||||
babel-loader "^8.0.6"
|
||||
babel-plugin-syntax-dynamic-import "^6.18.0"
|
||||
babylon "^6.18.0"
|
||||
broccoli-debug "^0.6.4"
|
||||
broccoli-node-api "^1.7.0"
|
||||
broccoli-plugin "^4.0.0"
|
||||
broccoli-source "^3.0.0"
|
||||
debug "^3.1.0"
|
||||
ember-cli-babel "^7.0.0"
|
||||
enhanced-resolve "^4.0.0"
|
||||
fs-extra "^6.0.1"
|
||||
fs-tree-diff "^2.0.0"
|
||||
handlebars "^4.3.1"
|
||||
js-string-escape "^1.0.1"
|
||||
lodash "^4.17.19"
|
||||
mkdirp "^0.5.1"
|
||||
resolve-package-path "^3.1.0"
|
||||
rimraf "^2.6.2"
|
||||
semver "^7.3.4"
|
||||
symlink-or-copy "^1.2.0"
|
||||
typescript-memoize "^1.0.0-alpha.3"
|
||||
walk-sync "^0.3.3"
|
||||
webpack "^4.43.0"
|
||||
|
||||
ember-auto-import@^2.4.2:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/ember-auto-import/-/ember-auto-import-2.4.2.tgz#d4d3bc6885a11cf124f606f5c37169bdf76e37ae"
|
||||
@@ -11961,6 +12010,17 @@ ember-cli-babel@^6.16.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.1, ember-c
|
||||
rimraf "^3.0.1"
|
||||
semver "^5.5.0"
|
||||
|
||||
ember-cli-clipboard@^0.16.0:
|
||||
version "0.16.0"
|
||||
resolved "https://registry.yarnpkg.com/ember-cli-clipboard/-/ember-cli-clipboard-0.16.0.tgz#f4878cbbfbc56e0bc6d2a65ccf5a334c47b0f614"
|
||||
integrity sha512-l9iDVjcJLkbgpdbJe+bN29q2ibZmEpEV6bXstIG9q4HPvaqbXw0PbSFhaNeQWpJKNkd5dFKSNdgEfli6heJSFw==
|
||||
dependencies:
|
||||
"@ember/render-modifiers" "^1.0.2 || ^2.0.0"
|
||||
clipboard "^2.0.6"
|
||||
ember-auto-import "^1.11.3"
|
||||
ember-cli-babel "^7.26.6"
|
||||
ember-cli-htmlbars "^5.7.1"
|
||||
|
||||
ember-cli-code-coverage@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/ember-cli-code-coverage/-/ember-cli-code-coverage-1.0.3.tgz#9a6e5e6350d70761eba749d68ebe2e0d9aa3492f"
|
||||
@@ -16417,6 +16477,11 @@ ip@1.1.5, ip@^1.1.5:
|
||||
resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
|
||||
integrity sha512-rBtCAQAJm8A110nbwn6YdveUnuZH3WrC36IwkRXxDnq53JvXA2NVQvB7IHyKomxK1MJ4VDNw3UtFDdXQ+AvLYA==
|
||||
|
||||
ip@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
|
||||
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
|
||||
|
||||
ipaddr.js@1.9.1:
|
||||
version "1.9.1"
|
||||
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
|
||||
@@ -20115,10 +20180,10 @@ node-notifier@^10.0.0, node-notifier@^8.0.1:
|
||||
uuid "^8.3.0"
|
||||
which "^2.0.2"
|
||||
|
||||
node-releases@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.5.tgz#280ed5bc3eba0d96ce44897d8aee478bfb3d9666"
|
||||
integrity sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==
|
||||
node-releases@^2.0.6:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503"
|
||||
integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==
|
||||
|
||||
node-uuid@~1.4.7:
|
||||
version "1.4.8"
|
||||
@@ -21425,12 +21490,12 @@ playwright@^1.15.0:
|
||||
yazl "^2.5.1"
|
||||
|
||||
plist@^3.0.0, plist@^3.0.1, plist@^3.0.4, plist@^3.0.5:
|
||||
version "3.0.5"
|
||||
resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.5.tgz#2cbeb52d10e3cdccccf0c11a63a85d830970a987"
|
||||
integrity sha512-83vX4eYdQp3vP9SxuYgEM/G/pJQqLUz/V/xzPrzruLs7fz7jxGQ1msZ/mg1nwZxUSuOp4sb+/bEIbRrbzZRxDA==
|
||||
version "3.0.6"
|
||||
resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.6.tgz#7cfb68a856a7834bca6dbfe3218eb9c7740145d3"
|
||||
integrity sha512-WiIVYyrp8TD4w8yCvyeIr+lkmrGRd5u0VbRnU+tP/aRLxP/YadJUYOMZJ/6hIa3oUyVCsycXvtNRgd5XBJIbiA==
|
||||
dependencies:
|
||||
base64-js "^1.5.1"
|
||||
xmlbuilder "^9.0.7"
|
||||
xmlbuilder "^15.1.1"
|
||||
|
||||
pluralize@^1.2.1:
|
||||
version "1.2.1"
|
||||
@@ -23986,7 +24051,15 @@ socks-proxy-agent@^6.0.0:
|
||||
debug "^4.3.3"
|
||||
socks "^2.6.2"
|
||||
|
||||
socks@^2.3.3, socks@^2.6.2:
|
||||
socks@^2.3.3:
|
||||
version "2.7.0"
|
||||
resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.0.tgz#f9225acdb841e874dca25f870e9130990f3913d0"
|
||||
integrity sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==
|
||||
dependencies:
|
||||
ip "^2.0.0"
|
||||
smart-buffer "^4.2.0"
|
||||
|
||||
socks@^2.6.2:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.2.tgz#ec042d7960073d40d94268ff3bb727dc685f111a"
|
||||
integrity sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==
|
||||
@@ -26711,10 +26784,10 @@ xml-name-validator@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"
|
||||
integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==
|
||||
|
||||
xmlbuilder@^9.0.7:
|
||||
version "9.0.7"
|
||||
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d"
|
||||
integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=
|
||||
xmlbuilder@^15.1.1:
|
||||
version "15.1.1"
|
||||
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5"
|
||||
integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==
|
||||
|
||||
xmlchars@^2.2.0:
|
||||
version "2.2.0"
|
||||
|
||||
Reference in new issue
Block a user