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

HDS::CodeEditor with Code Mirror 6 #2573

Merged
merged 112 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
112 commits
Select commit Hold shift + click to select a range
2d7eb0d
Install `codemirror` 5
alex-ju Sep 17, 2024
86bc460
Generate `CodeEditor` showcase
alex-ju Sep 17, 2024
b796d9e
Generate `hds-code-editor` modifier
alex-ju Sep 19, 2024
e83e17e
Generate `CodeEditor` component
alex-ju Sep 19, 2024
9fce137
Switch to `codemirror` 6 via subpackages
alex-ju Sep 19, 2024
f1eea68
Theme
alex-ju Oct 1, 2024
ffb3f9b
Clean-up and lint
alex-ju Oct 22, 2024
90179ff
working on initial structure
zamoore Nov 11, 2024
c924fab
added javascript support
zamoore Nov 11, 2024
77cff8c
added some initial language support
zamoore Nov 11, 2024
a0e9d58
can add new lines in the code editor
zamoore Nov 13, 2024
896b315
added support for history
zamoore Nov 14, 2024
82b8219
rough version of fullscreen mode works
zamoore Nov 14, 2024
f2a41a1
styling code editor
zamoore Nov 15, 2024
5c60fe3
styling wip
zamoore Nov 15, 2024
5bab68d
copy button works
zamoore Nov 15, 2024
ee55642
updated highlighting
zamoore Nov 15, 2024
6b8c28c
added tab support
zamoore Nov 15, 2024
f591946
calls the update function
zamoore Nov 15, 2024
dc67285
working on showcase docs
zamoore Nov 18, 2024
ff9ce7f
writing tests and cleaning up code
zamoore Nov 18, 2024
2087a3e
added examples to the showcase
zamoore Nov 19, 2024
deac976
added examples to the showcase
zamoore Nov 19, 2024
ebb9bf2
cleanup
zamoore Nov 20, 2024
481f006
changed title and description to yielded subcomponents
zamoore Dec 4, 2024
002f134
website docs WIP
zamoore Dec 5, 2024
16dae51
adjusted styling and header composition to fit the new designs
zamoore Dec 5, 2024
ac77c98
fixed styling for differnet header combos
zamoore Dec 6, 2024
2c271e2
adding keyboard nav support
zamoore Dec 6, 2024
f723c11
fixing styling
zamoore Dec 6, 2024
82d212e
improving keybopard navigation
zamoore Dec 6, 2024
cc27ba7
updated the highlight style
zamoore Dec 6, 2024
e356dfc
added support for bracket matching
zamoore Dec 6, 2024
6a45cc2
working on dynamic package importing
zamoore Dec 10, 2024
a1d94b3
wip
zamoore Dec 10, 2024
e72598e
removed some visibility observers
zamoore Dec 10, 2024
5cbcdd9
will only load once visible
zamoore Dec 10, 2024
3933fe8
added customizable option for title tag
zamoore Dec 10, 2024
1488b06
code cleanup
zamoore Dec 10, 2024
51c1754
reduced header complexity
zamoore Dec 10, 2024
4083224
fixed header styling
zamoore Dec 10, 2024
4fb1df4
updating active line styles
zamoore Dec 11, 2024
3a29bdc
fixing color setup
zamoore Dec 11, 2024
56d992b
moved to local color definitions
zamoore Dec 11, 2024
907dee2
using local colors
zamoore Dec 11, 2024
2d6e408
cleaning up theming
zamoore Dec 11, 2024
eab17bf
added support for hcl
zamoore Dec 11, 2024
aaa2deb
added more examples in the showcase
zamoore Dec 11, 2024
7b5f594
got content selection styled
zamoore Dec 12, 2024
38b010f
got content selection styled
zamoore Dec 12, 2024
860c5e8
fixing color variables
zamoore Dec 12, 2024
0b00afd
loading state added
zamoore Dec 16, 2024
754d72d
fixing linting issues
zamoore Dec 16, 2024
059e53f
fixing linting issues
zamoore Dec 16, 2024
caa0c24
added a root margin to the loader intersection observer
zamoore Dec 16, 2024
9d372a6
fixing linting issues
zamoore Dec 16, 2024
0bbc6a5
removed website updates
zamoore Dec 16, 2024
bf44c40
cleaning up code for PR
zamoore Dec 16, 2024
1491864
fixing tests
zamoore Dec 17, 2024
aa57336
simplified html structure
zamoore Dec 17, 2024
1615858
figured out padding for custom content
zamoore Dec 17, 2024
9dad48b
passing tests
zamoore Dec 17, 2024
3118873
cleaning up tests
zamoore Dec 17, 2024
d372c94
fixed typescript error ignores
zamoore Dec 17, 2024
5c5751e
adding support for async tasks
zamoore Dec 17, 2024
0599078
added a changeset
zamoore Dec 17, 2024
4151550
fixed typo in test selector
zamoore Dec 17, 2024
04c4fc7
a11y changes
zamoore Dec 19, 2024
b9b7e14
responding to pr feedback
zamoore Dec 19, 2024
c0aafe2
added test for expand/collapse
zamoore Dec 19, 2024
7f6bbfb
cleaning up the state in the fullscreen toggle button
zamoore Dec 20, 2024
a15908f
fixed full screen button
zamoore Dec 20, 2024
10e88a0
responding to PR feedback
zamoore Dec 20, 2024
e78a00e
changed to relative path import to fix the import issue
zamoore Dec 23, 2024
21a3b3b
changed to relative path import to fix the import issue
zamoore Dec 23, 2024
670cf31
added modifier usage
zamoore Dec 23, 2024
52b8231
removing button component and applying styles to child button elements
zamoore Dec 23, 2024
e959d10
updated the copy button so that it works with an internal val
zamoore Dec 23, 2024
20a6f12
added a test for the copy button
zamoore Dec 23, 2024
5c6f760
fixed height issue in full screen mode with too much content
zamoore Dec 23, 2024
d2ba1f5
added some additional tests around copying content
zamoore Dec 24, 2024
1ee660a
fixing focus ring on action buttons
zamoore Dec 24, 2024
41cbf2e
handled escape key with a modifier that adds an ecent listener to the…
zamoore Dec 24, 2024
0e7ff2b
fixing full screen button
zamoore Dec 24, 2024
97f2e61
waiting for the component to load before taking percy screenshot
zamoore Dec 24, 2024
ab23f7c
updating theme to hit docs
zamoore Dec 24, 2024
fc49c30
added a warning
zamoore Dec 24, 2024
187de57
added exports to components file
zamoore Dec 24, 2024
4eb5d1b
added support for other langs
zamoore Dec 30, 2024
90fb272
added support for other langs
zamoore Dec 30, 2024
3a2894c
addressing PR feedback
zamoore Jan 2, 2025
c2bc05f
responding to pr feedback
zamoore Jan 6, 2025
1727972
added support for aria-label and aria-labelledby
zamoore Jan 6, 2025
ecf8501
responding to PR feedback
zamoore Jan 7, 2025
6521241
addressed some feedback on the aria-label
zamoore Jan 8, 2025
5bae2b9
updating tests after accessibility changes
zamoore Jan 9, 2025
d100dce
fixed ts errors
zamoore Jan 9, 2025
7c874b6
Refactored custom content to add a new Generic container component, s…
KristinLBradley Jan 10, 2025
97cc902
making adjustments to the aria label properties
zamoore Jan 13, 2025
4fa3d0e
making adjustments to the aria label properties
zamoore Jan 14, 2025
0c3b714
only showing active line style when the editor is focused
zamoore Jan 14, 2025
c2449a0
responding to design feedback
zamoore Jan 14, 2025
4fb8c45
updated showcase examples and fixed styles for title/gneric combo
zamoore Jan 15, 2025
4e1b815
responding to Pr feedback
zamoore Jan 15, 2025
a9577ea
added support for @isStandalone arg
zamoore Jan 15, 2025
04b2d5f
added some missing tests for the full screen button
zamoore Jan 15, 2025
bd65a96
added some missing tests for the title
zamoore Jan 15, 2025
16df6ff
handling blur event
zamoore Jan 15, 2025
928128c
fixing failing test
zamoore Jan 16, 2025
be4d817
responding to PR feedback
zamoore Jan 16, 2025
43deda4
fixing hover state on copy button
zamoore Jan 16, 2025
015c7cf
responding to pr feedback
zamoore Jan 16, 2025
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
6 changes: 6 additions & 0 deletions .changeset/long-poets-wonder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@hashicorp/design-system-components": minor
---

`Hds::CodeEditor` - Added new CodeMirror 6 supported code editor component
`hds-code-editor` modifier - Added new code editor modifier which converts the element it is applied to into a CodeMirror 6 code editor
3 changes: 2 additions & 1 deletion packages/components/babel.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
],
["@babel/plugin-proposal-decorators", { "legacy": true }],
"@babel/plugin-transform-class-properties",
"@babel/plugin-transform-private-methods"
"@babel/plugin-transform-private-methods",
"ember-concurrency/async-arrow-task-transform"
]
}
20 changes: 20 additions & 0 deletions packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@
"lint:js:fix": "eslint . --fix"
},
"dependencies": {
"@codemirror/commands": "^6.8.0",
"@codemirror/lang-go": "^6.0.1",
"@codemirror/lang-json": "^6.0.1",
"@codemirror/lang-sql": "^6.8.0",
"@codemirror/lang-yaml": "^6.1.2",
"@codemirror/language": "^6.10.3",
"@codemirror/legacy-modes": "^6.4.2",
"@codemirror/state": "^6.5.0",
"@codemirror/view": "^6.36.2",
"@ember/render-modifiers": "^2.1.0",
"@ember/string": "^3.1.1",
"@ember/test-waiters": "^3.1.0",
Expand All @@ -43,6 +52,7 @@
"@hashicorp/design-system-tokens": "^2.2.2",
"@hashicorp/flight-icons": "^3.8.0",
"clipboard-polyfill": "^4.1.1",
"codemirror-lang-hcl": "^0.0.0-beta.2",
"decorator-transforms": "^1.2.1",
"ember-a11y-refocus": "^4.1.4",
"ember-cli-sass": "^11.0.1",
Expand Down Expand Up @@ -155,6 +165,11 @@
"./components/hds/code-block/description.js": "./dist/_app_/components/hds/code-block/description.js",
"./components/hds/code-block/index.js": "./dist/_app_/components/hds/code-block/index.js",
"./components/hds/code-block/title.js": "./dist/_app_/components/hds/code-block/title.js",
"./components/hds/code-editor/description.js": "./dist/_app_/components/hds/code-editor/description.js",
"./components/hds/code-editor/full-screen-button.js": "./dist/_app_/components/hds/code-editor/full-screen-button.js",
"./components/hds/code-editor/generic.js": "./dist/_app_/components/hds/code-editor/generic.js",
"./components/hds/code-editor/index.js": "./dist/_app_/components/hds/code-editor/index.js",
"./components/hds/code-editor/title.js": "./dist/_app_/components/hds/code-editor/title.js",
"./components/hds/copy/button/index.js": "./dist/_app_/components/hds/copy/button/index.js",
"./components/hds/copy/snippet/index.js": "./dist/_app_/components/hds/copy/snippet/index.js",
"./components/hds/dialog-primitive/body.js": "./dist/_app_/components/hds/dialog-primitive/body.js",
Expand Down Expand Up @@ -300,6 +315,11 @@
"./instance-initializers/load-sprite.js": "./dist/_app_/instance-initializers/load-sprite.js",
"./modifiers/hds-anchored-position.js": "./dist/_app_/modifiers/hds-anchored-position.js",
"./modifiers/hds-clipboard.js": "./dist/_app_/modifiers/hds-clipboard.js",
"./modifiers/hds-code-editor.js": "./dist/_app_/modifiers/hds-code-editor.js",
"./modifiers/hds-code-editor/highlight-styles/hds-dark-highlight-style.js": "./dist/_app_/modifiers/hds-code-editor/highlight-styles/hds-dark-highlight-style.js",
"./modifiers/hds-code-editor/palettes/hds-dark-palette.js": "./dist/_app_/modifiers/hds-code-editor/palettes/hds-dark-palette.js",
"./modifiers/hds-code-editor/themes/hds-dark-theme.js": "./dist/_app_/modifiers/hds-code-editor/themes/hds-dark-theme.js",
"./modifiers/hds-code-editor/types.js": "./dist/_app_/modifiers/hds-code-editor/types.js",
"./modifiers/hds-register-event.js": "./dist/_app_/modifiers/hds-register-event.js",
"./modifiers/hds-tooltip.js": "./dist/_app_/modifiers/hds-tooltip.js",
"./services/hds-time.js": "./dist/_app_/services/hds-time.js"
Expand Down
6 changes: 6 additions & 0 deletions packages/components/src/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ export { default as HdsCodeBlockDescription } from './components/hds/code-block/
export { default as HdsCodeBlockTitle } from './components/hds/code-block/title.ts';
export * from './components/hds/code-block/types.ts';

// CodeEditor
export { default as HdsCodeEditor } from './components/hds/code-editor/index.ts';
export { default as HdsCodeEditorDescription } from './components/hds/code-editor/description.ts';
export { default as HdsCodeEditorTitle } from './components/hds/code-editor/title.ts';
export { default as HdsCodeEditorFullScreenButton } from './components/hds/code-editor/full-screen-button.ts';

// CopyButton
export { default as HdsCopyButton } from './components/hds/copy/button/index.ts';
export * from './components/hds/copy/button/types.ts';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<Hds::Text::Body class="hds-code-editor__description" @tag="p" @size="100" ...attributes>
{{yield}}
</Hds::Text::Body>
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/

import TemplateOnlyComponent from '@ember/component/template-only';

import type { HdsTextBodySignature } from '../text/body';

export interface HdsCodeEditorDescriptionSignature {
Blocks: {
default: [];
};
Element: HdsTextBodySignature['Element'];
}

const HdsCodeEditorDescription =
TemplateOnlyComponent<HdsCodeEditorDescriptionSignature>();

export default HdsCodeEditorDescription;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Hds::Button
class={{this.className}}
aria-pressed={{@isFullScreen}}
@isIconOnly={{true}}
@color="secondary"
@size="small"
@icon={{this.state}}
@text="Toggle full screen view"
{{on "click" @onToggleFullScreen}}
...attributes
/>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/

import Component from '@glimmer/component';

import type { HdsButtonSignature } from '../button';

export interface HdsCodeEditorFullScreenButtonSignature {
Args: {
isFullScreen: boolean;
onToggleFullScreen: () => void;
};
Element: HdsButtonSignature['Element'];
}

export default class HdsCodeEditorFullScreenButton extends Component<HdsCodeEditorFullScreenButtonSignature> {
get state(): 'minimize' | 'maximize' {
return this.args.isFullScreen ? 'minimize' : 'maximize';
}

get className(): string {
const classes = [
'hds-code-editor__full-screen-button',
'hds-code-editor__button',
];

const stateClass = `hds-code-editor__full-screen-button--${this.state}`;

classes.push(stateClass);

return classes.join(' ');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: MPL-2.0
}}
<div class="hds-code-editor__header-generic" ...attributes>
{{yield}}
</div>
18 changes: 18 additions & 0 deletions packages/components/src/components/hds/code-editor/generic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/

import TemplateOnlyComponent from '@ember/component/template-only';

export interface HdsCodeEditorGenericSignature {
Blocks: {
default: [];
};
Element: HTMLDivElement;
}

const HdsCodeEditorGeneric =
TemplateOnlyComponent<HdsCodeEditorGenericSignature>();

export default HdsCodeEditorGeneric;
70 changes: 70 additions & 0 deletions packages/components/src/components/hds/code-editor/index.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: MPL-2.0
}}

<div
id={{this._id}}
class={{this.classNames}}
{{! @glint-expect-error - https://github.com/josemarluedke/ember-focus-trap/issues/86 }}
{{focus-trap isActive=this._isFullScreen}}
{{this._handleEscape}}
...attributes
>
{{! header }}
{{#if (or this.hasActions (has-block))}}
<div class="hds-code-editor__header">
<div class="hds-code-editor__header-content">
{{yield
(hash
Title=(component "hds/code-editor/title" editorId=this._id onInsert=this.registerTitleElement)
Description=(component "hds/code-editor/description")
Generic=(component "hds/code-editor/generic")
)
}}
</div>

{{#if this.hasActions}}
<div class="hds-code-editor__header-actions">
{{#if @hasCopyButton}}
<Hds::Copy::Button
class="hds-code-editor__button hds-code-editor__copy-button"
@isIconOnly={{true}}
@size="small"
@text="Copy"
@textToCopy={{this._value}}
/>
{{/if}}
{{#if @hasFullScreenButton}}
<Hds::CodeEditor::FullScreenButton
@isFullScreen={{this._isFullScreen}}
@onToggleFullScreen={{this.toggleFullScreen}}
/>
{{/if}}
</div>
{{/if}}
</div>
{{/if}}

{{! editor }}
<div
class="hds-code-editor__editor"
{{hds-code-editor
ariaLabel=@ariaLabel
ariaLabelledBy=this.ariaLabelledBy
value=@value
language=@language
onBlur=@onBlur
onInput=this.onInput
onSetup=this.onSetup
}}
/>

{{! loader }}
{{#unless this._isSetupComplete}}
<div class="hds-code-editor__loader" aria-live="polite" role="status">
<Hds::Icon @name="loading" @size="24" />
<span class="sr-only">Loading</span>
</div>
{{/unless}}
</div>
136 changes: 136 additions & 0 deletions packages/components/src/components/hds/code-editor/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/

import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { modifier } from 'ember-modifier';

import type { ComponentLike } from '@glint/template';
import type { HdsCodeEditorSignature as HdsCodeEditorModifierSignature } from 'src/modifiers/hds-code-editor';
import type { HdsCodeEditorDescriptionSignature } from './description';
import type { HdsCodeEditorTitleSignature } from './title';
import type { HdsCodeEditorGenericSignature } from './generic';
import type { EditorView } from '@codemirror/view';
import { guidFor } from '@ember/object/internals';

export interface HdsCodeEditorSignature {
Args: {
ariaLabel?: string;
ariaLabelledBy?: string;
hasCopyButton?: boolean;
hasFullScreenButton?: boolean;
isStandalone?: boolean;
language?: HdsCodeEditorModifierSignature['Args']['Named']['language'];
value?: HdsCodeEditorModifierSignature['Args']['Named']['value'];
onBlur?: HdsCodeEditorModifierSignature['Args']['Named']['onBlur'];
onInput?: HdsCodeEditorModifierSignature['Args']['Named']['onInput'];
onSetup?: HdsCodeEditorModifierSignature['Args']['Named']['onSetup'];
};
Blocks: {
default: [
{
Title?: ComponentLike<HdsCodeEditorTitleSignature>;
Description?: ComponentLike<HdsCodeEditorDescriptionSignature>;
Generic?: ComponentLike<HdsCodeEditorGenericSignature>;
},
];
};
Element: HTMLDivElement;
}

export default class HdsCodeEditor extends Component<HdsCodeEditorSignature> {
@tracked private _isFullScreen = false;
@tracked private _isSetupComplete = false;
@tracked private _value;
@tracked private _titleId: string | undefined;

private _id = guidFor(this);

private _handleEscape = modifier(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key !== 'Escape' || !this._isFullScreen) {
return;
}

this.toggleFullScreen();
};

document.addEventListener('keydown', handleKeyDown);

return () => {
document.removeEventListener('keydown', handleKeyDown);
};
});

constructor(owner: unknown, args: HdsCodeEditorSignature['Args']) {
super(owner, args);

if (args.value) {
this._value = args.value;
}
}

get ariaLabelledBy(): string | undefined {
if (this.args.ariaLabel !== undefined) {
return;
}

return this.args.ariaLabelledBy ?? this._titleId;
}

get hasActions(): boolean {
return (this.args.hasCopyButton || this.args.hasFullScreenButton) ?? false;
}

get isStandalone(): boolean {
return this.args.isStandalone ?? true;
}

get classNames(): string {
// Currently there is only one theme so the class name is hard-coded.
// In the future, additional themes such as a "light" theme could be added.
const classes = ['hds-code-editor', 'hds-code-editor--theme-dark'];

if (this._isFullScreen) {
classes.push('hds-code-editor--is-full-screen');
}

if (this.isStandalone) {
classes.push('hds-code-editor--is-standalone');
}

return classes.join(' ');
}

@action
registerTitleElement(element: HdsCodeEditorTitleSignature['Element']): void {
this._titleId = element.id;
}

@action
toggleFullScreen(): void {
this._isFullScreen = !this._isFullScreen;
}

@action
onInput(newValue: string): void {
this._value = newValue;
this.args.onInput?.(newValue);
}

@action
onKeyDown(event: KeyboardEvent): void {
if (event.key === 'Escape' && this._isFullScreen) {
this.toggleFullScreen();
}
}

@action
onSetup(editorView: EditorView): void {
this._isSetupComplete = true;
this.args.onSetup?.(editorView);
}
}
Loading
Loading