Skip to content

Commit

Permalink
fix: Editor's state should not be shared between tabs (#52)
Browse files Browse the repository at this point in the history
  • Loading branch information
YossiSaadi authored Apr 3, 2024
1 parent 7030ca6 commit 50fe86f
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 9 deletions.
39 changes: 34 additions & 5 deletions src/components/Addons/Panel.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { Suspense, useCallback, useMemo } from "react";
import React, { Suspense, useCallback, useMemo, useRef } from "react";
import { Editor, EditorTabs, EditorToolbar } from "../Editor";
import {
useInitialCode,
Expand All @@ -9,12 +9,13 @@ import {
} from "@/hooks";
import { AddonPanel } from "@storybook/components";
import { Addon_RenderOptions } from "@storybook/types";
import { Extension, keymap } from "@uiw/react-codemirror";
import { Extension, keymap, ReactCodeMirrorRef } from "@uiw/react-codemirror";
import { useAddonState, useParameter } from "@storybook/manager-api";
import {
ADDON_ID_FOR_PARAMETERS,
DEFAULT_ADDON_PARAMETERS,
DEFAULT_ADDON_STATE,
EDITOR_STATE_FIELDS,
PANEL_ID,
} from "@/consts";
import { PlaygroundParameters, PlaygroundState, Tab } from "@/types";
Expand All @@ -24,6 +25,8 @@ import { autocomplete as playgroundAutocompletion } from "@/codemirror/extension
import playgroundKeymaps from "@/codemirror/keymaps";

const Panel: React.FC<Addon_RenderOptions> = ({ active }) => {
const editorRef = useRef<ReactCodeMirrorRef>(null);

useInitialCode();
useBroadcastEditorChanges();
useAutoOpenPlayground();
Expand All @@ -38,7 +41,7 @@ const Panel: React.FC<Addon_RenderOptions> = ({ active }) => {
DEFAULT_ADDON_STATE
);

const extensions: { jsx: Extension[]; css: Extension[] } = useMemo(
const extensions = useMemo<Record<Tab, Extension[]>>(
() => ({
jsx: [
langs.html(),
Expand All @@ -51,15 +54,38 @@ const Panel: React.FC<Addon_RenderOptions> = ({ active }) => {
[autocompletions]
);

const { code, selectedTab, fontSize, hasInitialCodeLoaded } = state;
const { code, selectedTab, fontSize, hasInitialCodeLoaded, editorState } =
state;

const onTabChange = useCallback(
(newTab: Tab) => {
setState((state) => ({ ...state, selectedTab: newTab }));
setState((prev) => {
const updates = {
...prev,
selectedTab: newTab,
};
const editorStateJson =
editorRef.current?.view?.state?.toJSON?.(EDITOR_STATE_FIELDS);
if (editorStateJson) {
updates.editorState = {
...prev.editorState,
[prev.selectedTab]: editorStateJson,
};
}
return updates;
});
},
[setState]
);

const editorInitialState = useMemo(
() => ({
json: editorState[selectedTab],
fields: EDITOR_STATE_FIELDS,
}),
[editorState, selectedTab]
);

return (
<AddonPanel active={active}>
<div className={styles.panel}>
Expand All @@ -69,13 +95,16 @@ const Panel: React.FC<Addon_RenderOptions> = ({ active }) => {
<div className={styles.editor}>
<Suspense fallback={"Loading Editor..."}>
<Editor
key={selectedTab}
ref={editorRef}
loading={!hasInitialCodeLoaded}
placeholder={`Insert your ${selectedTab.toUpperCase()} code here`}
code={code[selectedTab]}
theme={theme}
extensions={extensions[selectedTab]}
style={{ fontSize }}
onChange={updateCode}
initialState={editorInitialState}
/>
</Suspense>
</div>
Expand Down
4 changes: 4 additions & 0 deletions src/components/Editor/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
import { Loader } from "@storybook/components";
const CodeMirror = lazy(() => import("@uiw/react-codemirror"));
import "./Editor.module.css";
import { EditorInitialState } from "@/types";

interface EditorProps {
code: string;
Expand All @@ -17,6 +18,7 @@ interface EditorProps {
style?: React.CSSProperties;
extensions?: Extension[];
setup?: BasicSetupOptions;
initialState?: EditorInitialState;
}

type EditorComponent = React.ForwardRefExoticComponent<
Expand All @@ -34,6 +36,7 @@ const Editor: EditorComponent = forwardRef(
style,
extensions,
setup,
initialState,
},
ref
) => {
Expand All @@ -51,6 +54,7 @@ const Editor: EditorComponent = forwardRef(
onChange={onChange}
placeholder={placeholder}
basicSetup={setup}
initialState={initialState?.json && initialState}
/>
)}
</>
Expand Down
4 changes: 4 additions & 0 deletions src/consts/editor-consts.ts
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
import { historyField } from "@codemirror/commands";

export const SNIPPET_SHARE_QUERY_ID = "snippet";

export const EDITOR_STATE_FIELDS = { history: historyField };
4 changes: 4 additions & 0 deletions src/consts/state-consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ export const DEFAULT_ADDON_STATE: PlaygroundState = {
code: { jsx: "", css: "" },
fontSize: 13,
selectedTab: "jsx",
editorState: {
jsx: null,
css: null,
},
};
24 changes: 20 additions & 4 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React from "react";
import { Extension } from "@uiw/react-codemirror";
import { EditorStateConfig } from "@codemirror/state";
import { EDITOR_STATE_FIELDS } from "@/consts";

export interface PlaygroundParameters {
storyId: string;
Expand Down Expand Up @@ -31,13 +33,27 @@ export interface PlaygroundArgs {

export interface PlaygroundState {
hasInitialCodeLoaded?: boolean;
fontSize: number;
fontSize?: number;
code?: Code;
selectedTab: Tab;
selectedTab?: Tab;
editorState?: Record<Tab, EditorStateJson>;
}

export type Code = { jsx: string; css: string };
type EditorStateFields = typeof EDITOR_STATE_FIELDS;

export type Tab = "jsx" | "css";
export interface EditorInitialState {
fields: EditorStateFields;
json: EditorStateJson;
}

type EditorStateJson = Partial<EditorStateConfig> & {
[K in keyof EditorStateFields]: unknown;
};

export type Code = Record<SupportedLanguages, string>;

export type Tab = SupportedLanguages;

type SupportedLanguages = "jsx" | "css";

export type EditorTheme = "light" | "dark" | Extension;

0 comments on commit 50fe86f

Please sign in to comment.