Skip to content

Commit

Permalink
feat: codemirror extension to automatically insert self closing tag o…
Browse files Browse the repository at this point in the history
…nce closed

e.g. `<Button /` would result in `<Button />`
  • Loading branch information
YossiSaadi committed Mar 17, 2024
1 parent 66350be commit 36696d2
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/codemirror/keymaps/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { KeyBinding } from "@uiw/react-codemirror";
import selfClosingTag from "./self-closing-tag";

export default [{ key: "/", run: selfClosingTag }] satisfies KeyBinding[];
52 changes: 52 additions & 0 deletions src/codemirror/keymaps/self-closing-tag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { EditorSelection, EditorView } from "@uiw/react-codemirror";
import {
getEditorStateInfo,
parseTagFromLineText,
} from "../utils/extensions-utils";

function insertSelfClosingTagCommand(view: EditorView): boolean {
const { state, dispatch } = view;
const { cursorPos, lineTextUpToCursor, lineTextAfterCursor } =
getEditorStateInfo(state);

const tagName = parseTagFromLineText(lineTextUpToCursor);

if (!tagName) {
return false;
}

if (!isInsideOpenTag(lineTextUpToCursor)) {
return false;
}

if (isFollowedByCloseTag(lineTextAfterCursor)) {
return false;
}

// +2 to move in after the inserted self-closing bracket
const newCursorPos = EditorSelection.cursor(cursorPos + 2);

// insert self-closing tag syntax ('/>') and adjust the cursor position
dispatch(
state.update({
changes: { from: cursorPos, insert: "/>" },
selection: newCursorPos,
})
);

return true;
}

function isInsideOpenTag(lineTextUpToCursor: string): boolean {
// Checks if the cursor is within an open tag (e.g., after "<Button" or "<Button prop").
return /<\w+[^>]*$/.test(lineTextUpToCursor);
}

function isFollowedByCloseTag(lineTextAfterCursor: string): boolean {
// Checks if the cursor's position in the document is followed by a closing part of a tag or self-closing syntax.
return (
/<\/?\w+>/.test(lineTextAfterCursor) || /\/>/.test(lineTextAfterCursor)
);
}

export default insertSelfClosingTagCommand;
4 changes: 3 additions & 1 deletion src/components/Addons/Panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from "@/hooks";
import { AddonPanel } from "@storybook/components";
import { Addon_RenderOptions } from "@storybook/types";
import { Extension } from "@uiw/react-codemirror";
import { Extension, keymap } from "@uiw/react-codemirror";
import { useAddonState, useParameter } from "@storybook/manager-api";
import {
ADDON_ID_FOR_PARAMETERS,
Expand All @@ -21,6 +21,7 @@ import { PlaygroundParameters, PlaygroundState, Tab } from "@/types";
import { langs } from "@uiw/codemirror-extensions-langs";
import styles from "./Panel.module.css";
import { autocomplete as playgroundAutocompletion } from "@/codemirror/extensions";
import playgroundKeymaps from "@/codemirror/keymaps";

const Panel: React.FC<Addon_RenderOptions> = ({ active }) => {
useInitialCode();
Expand All @@ -43,6 +44,7 @@ const Panel: React.FC<Addon_RenderOptions> = ({ active }) => {
langs.html(),
langs.javascript(),
playgroundAutocompletion(autocompletions),
keymap.of(playgroundKeymaps),
],
css: [langs.css()],
}),
Expand Down
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"paths": {
"@/components/*": ["src/components/*"],
"@/codemirror/extensions": ["src/codemirror/extensions"],
"@/codemirror/keymaps": ["src/codemirror/keymaps"],
"@/consts": ["src/consts"],
"@/hooks": ["src/hooks"],
"@/utils": ["src/utils"],
Expand Down

0 comments on commit 36696d2

Please sign in to comment.