@codemirror/state#Compartment TypeScript Examples

The following examples show how to use @codemirror/state#Compartment. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: editor.ts    From starboard-notebook with Mozilla Public License 2.0 4 votes vote down vote up
export function createCodeMirrorEditor(
  element: HTMLElement,
  cell: Cell,
  opts: {
    language?: string;
    wordWrap?: "off" | "on" | "wordWrapColumn" | "bounded";
  },
  runtime: Runtime
) {
  const listen = EditorView.updateListener.of((update) => {
    if (update.docChanged) {
      cell.textContent = update.state.doc.toString();
    }
  });

  const readOnlyCompartment = new Compartment();
  const readOnlyExtension = EditorView.editable.of(!cell.metadata.properties.locked);

  const cellSwitchExtension = keymap.of([
    {
      key: "ArrowUp",
      run: (target) => {
        if (target.state.selection.ranges.length === 1 && target.state.selection.ranges[0].empty) {
          const firstLine = target.state.doc.line(1);
          const cursorPosition = target.state.selection.ranges[0].head;
          if (firstLine.from <= cursorPosition && cursorPosition <= firstLine.to) {
            runtime.controls.focusCell({ id: cell.id, focusTarget: "previous" });
            return true;
          }
        }
        return false;
      },
    },
    {
      key: "ArrowDown",
      run: (target) => {
        if (target.state.selection.ranges.length === 1 && target.state.selection.ranges[0].empty) {
          const lastline = target.state.doc.line(target.state.doc.lines);
          const cursorPosition = target.state.selection.ranges[0].head;
          if (lastline.from <= cursorPosition && cursorPosition <= lastline.to) {
            runtime.controls.focusCell({ id: cell.id, focusTarget: "next" });
            return true;
          }
        }
        return false;
      },
    },
  ]);

  const languageExtension = getCodemirrorLanguageExtension(opts.language);
  const editorView = new EditorView({
    state: EditorState.create({
      doc: cell.textContent.length === 0 ? undefined : cell.textContent,
      extensions: [
        cellSwitchExtension,
        ...commonExtensions,
        ...(languageExtension ? [languageExtension] : []),
        ...(opts.wordWrap === "on" ? [EditorView.lineWrapping] : []),
        readOnlyCompartment.of(readOnlyExtension),
        listen,
      ],
    }),
  });

  const setEditable = (editor: EditorView, locked: boolean | undefined) => {
    editor.dispatch({
      effects: readOnlyCompartment.reconfigure(EditorView.editable.of(!locked)),
    });
  };

  let isLocked: boolean | undefined = cell.metadata.properties.locked;
  runtime.controls.subscribeToCellChanges(cell.id, () => {
    // Note this function will be called on ALL text changes, so any letter typed,
    // it's probably better for performance to only ask cm to change it's editable state if it actually changed.
    if (isLocked === cell.metadata.properties.locked) return;
    isLocked = cell.metadata.properties.locked;
    setEditable(editorView, isLocked);
  });

  element.appendChild(editorView.dom);
  return editorView;
}