headless WYSIWYG 편집기'tiptap'열풍

24688 단어 TypeScripttech
이 글은 GAOGO Advent Calendaar 2021도 GAOGO 축제입니다. 16일째 되는 글이다.

개시하다


안녕하세요.
평소 업무 중 EC시스템 개발 활용에 종사하는 것은 인연이 없는데, 이번에는 타입 스크립트제의 풍부한 텍스트 편집기를 소개하고 손쉽게 수정했다.

WYSIWYG 편집기


WYSIWYG는 What You See Is What You Get의 머리글자를 딴 줄임말이다.
일본어로 바꾸면'보고 있으면 얻을 수 있다'로 바뀔 것 같다.
WYSIWYG 편집기는 모니터의 편집 화면과 출력(웹 페이지 또는 인쇄 결과)이 표시되는 편집기입니다.
절실한 예가 바로 마이크로소프트 워드다.
또 현재 워드프레스를 비롯한 CMS가 많은 사회 사이트를 차지하고 있으며, 워드프레스의 보도 제작 화면은 넓은 의미에서 WYSIWYG 편집기라고도 할 수 있다.
이렇게 되면 "WYSIWYG 편집기가 아니면 뭐야!"그러나 Mardown은 전형적인 예이다.[Googleページ](https://google.com)에 링크가 기재되어 있지만 Word처럼 입력할 때 인쇄면을 직접 표시하는 것은 아니다.
(요즘도 이런md편집기가 있는데 손이 간지러운 곳에 닿는다.)

웹 시스템의 WYSIWYG 편집기


웹 시스템, 특히 웹 페이지의 WYSIWYG 편집기 중 하나up-tri.
TinyMCE의 WordPress는 v5입니다.0 가져오기TinyMCE까지 표준 편집기로 묶입니다.이와 함께 자바스크립트가 생산한 WYSIWYG 편집기는 오랫동안 TinyMCE의 강점이었다.
물론 타이니MCE는 Vuejs, React, Anglar 등 현대 프레임워크가 웹 서비스계를 제어하는 것보다 오래전부터 존재했기 때문에 UI와 논리가 밀접하게 결합하고 현대 프레임워크와의 호환성도 완벽하지 않다.
이런 배경을 보면 최근 후발 WYSIWYG 편집기가 많이 등장했는데 그중 가장 특이한 것은Gutenberg이었다.
(이제까지)

tiptap 소개


tiptap
https://tiptap.dev/
MIT 라이센스로 릴리즈되었습니다v2.0 beta版.
https://github.com/ueberdosis/tiptap에서 보듯이 Vue와 React뿐만 아니라 Svelte 등 최신 프레임워크의 사용도 구상했다.
(물론 예전처럼 CDN을 통해서도 쓸 수 있지!)

tiptapp군의 장점


1.headless


tiptapapp의 가장 큰 장점은 제목과 같이headless이다.
WYSIWYG 편집기의 논리에만 집중하겠다는 것이다.
이전의 편집기는 기본적으로 표준 스타일을 사용했는데 도구 단추 그룹뿐만 아니라 View 부분의 맞춤형 제작에도 기교가 필요하다.
tiptapp에는 UI 설치가 정말 없어 처음부터 버튼 등을 만드는 게 번거롭지만, 가져오기 시스템에 맞는 UI/UX를 제공할 수 있다.

2. 실시간 동시 편집 지원


나는 개인적으로 대단하다고 생각하지만, 팁 앱은 기본적으로 (MIT 허가증 아래의 OSS) 여러 사람을 동시에 편집할 수 있다.
전언에 등장한 티니MCE도 기능으로 존재하지만, 라이선스식&전용 서비스로 사용해야 해 비용 측면과 유연성에 과제가 있다.
지금은 WebRTC와 WebSocket을 지원하는 것 같습니다.
installation

3. Type Script 지원


최근에는 Type Script가 웹 서비스 개발을 위한 모범 사례가 되었습니다.무형의 소JS는 이미 건드리기 싫겠지.
이전의 편집기 프로그램 라이브러리는 역사가 유구하기 때문에 TS가 지원하지 않고 일부 FW와 적합하지 않기 때문에 정식 TS가 대응하는 것은 매우 즐겁다.

기타


아주 작은 기능이지만 https://tiptap.dev/guide/collaborative-editing도 표준으로 대응할 수 있다.
문법 하이라이트와 조합.
하이라이트 CSS 자체 쓰기도 병목...

살살


1. Nextjs 설정


❯ npx create-next-app hirame-admin-front --template typescript
그대로 유지되면 프로젝트 경로에 pages 디렉토리가 있으므로 src가 아래로 이동합니다.
lowlight

2. 편집기 바디 설치


누름단추

H1, H2와 같은 스타일리시한 버튼의 점화용은 온클릭을 통해 사용할 수 있다.
src/components/organisms/AppEditorButton/index.tsx
import React, { MouseEventHandler } from "react";
import styles from "./style.module.scss";

export type AppEditorButtonProps = {
  isActive: boolean;
  onClick?: MouseEventHandler<HTMLButtonElement>;
};

export const AppEditorButton: React.FC<AppEditorButtonProps> = ({
  isActive,
  onClick,
  children,
}) => {
  const className = [styles.AppEditorButton];
  if (isActive) {
    className.push(styles["AppEditorButton--active"]);
  }

  return (
    <button onClick={onClick} className={className.join(" ")}>
      {children}
    </button>
  );
};
효과 ON 상태의 버튼에 --activesuffix가 첨부되어 있어 스타일을 선택할 수 있습니다.
src/components/organisms/AppEditorButton/style.module.scss
.AppEditorButton {
  display: inline-block;
  margin: 0 3px;
  border: 1px solid #555;
  border-radius: 2px;
  padding: 1px 10px;
  background-color: #fff;
  color: #000;
  cursor: pointer;

  &:hover {
    background-color: #555;
    color: #fff;
  }
}

.AppEditorButton--active {
  background-color: #555;
  color: #fff;
}

편집기 바디


src/components/organisms/AppEditor/index.tsx
import { EditorContent, useEditor } from "@tiptap/react"
import StarterKit from "@tiptap/starter-kit"
import { AppEditorButton } from "../AppEditorButton"
import styles from "./style.module.scss"

export const AppEditor = () => {
  const editor = useEditor({
    extensions: [
      StarterKit
    ],
    content: "<p>Hello!</p>"
  })
  if (!editor) {
    return null
  }

  return (
    <>
      <AppEditorButton
        onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}
        isActive={editor.isActive("heading", { level: 1 })}
      >H1</AppEditorButton>
      <AppEditorButton
        onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}
        isActive={editor.isActive("heading", { level: 1 })}
      >H2</AppEditorButton>
      <AppEditorButton
        onClick={() => editor.chain().focus().toggleBold().run()}
        isActive={editor.isActive("bold")}
      >B</AppEditorButton>
      <AppEditorButton
        onClick={() => editor.chain().focus().toggleItalic().run()}
        isActive={editor.isActive("italic")}
      >I</AppEditorButton>
      <EditorContent className={styles.AppEditor} editor={editor} />
    </>
  )
}
이쪽도 최소한의 스타일로 입어주세요.
편집기 DOM의 한 안쪽에 실제 내용 입력 영역을 생성하는 것이 비결이다. focus(a11y의 관점outline: none;으로 회피가 대체되었지만, 편집기 입력 상자는outline이 필요하지 않을 것 같습니다.이 가능하다, ~할 수 있다,...
src/components/organisms/AppEditor/style.module.scss
.AppEditor {
  margin: 0;
  border: 1px solid #000;
  padding: 5px;

  >:hover,
  >:focus,
  >:focus-visible {
    outline: none;
  }
}

시동 걸어봐.


넥스트js를 시작합시다.
起動イメージ
여기까지는 30분도 안 걸려요.
여기서부터 각 시스템 서비스에 따라 편집기 디자인을 할 수 있을 것 같아요!

소스 코드 여기 있습니다.


https://nextjs.org/docs/advanced-features/src-directory

최후


예전 기사↓와 조합해 k8s 환경을 만들면서 편집기를 편집하려고 했지만 순조롭게 진행될 시간이 없었다.
Redis를 사용하여 k8s 환경에서도 WebSocket 확장을 수행할 수 있습니다.관심 있으면 읽어보세요.
https://github.com/up-tri/hirame-admin-front/tree/e8972a69392f96e1fdadc39fb2836ff8815949e0
12월은 눈 깜짝할 사이에 지나갔다.여러분은 반드시 계획적으로 advent 달력을 써 주십시오.

참고 문장


https://zenn.dev/up_tri/articles/730e56443d1893

좋은 웹페이지 즐겨찾기