Skip to content

json‐editor for web component

redgoose.eth edited this page Aug 28, 2023 · 1 revision

JSON Editor 에디터를 웹 컴포넌트로 만들어서 사용할 수 있습니다.
에디터 라이브러리를 웹 컴포넌트 클래스 속에 집어넣고 사용하는 것이죠. 웹 컴포넌트로 사용하면 스타일시트를 격리화 시킬 수 있습니다.

파일 하나로 출력하여 사용할 수 있다는점이 매력적이죠.

Web component source

web-component.js

import JsonEditorCore from '@redgoose/json-editor'
import css from '@redgoose/json-editor/css?inline'

class JsonEditor extends HTMLElement {

  constructor()
  {
    super()
    this.attachShadow({ mode: 'open' })
    const template = document.createElement('template')
    template.innerHTML = `<div id="json-editor"></div>`
    const style = new CSSStyleSheet()
    style.replaceSync(css)
    this.shadowRoot.appendChild(template.content.cloneNode(true))
    this.shadowRoot.adoptedStyleSheets = [ style ]
    this.root = this.shadowRoot.childNodes[0]
    this.ready = false
    this.options = {
      live: false,
      theme: 'system', // system,light,dark
    }
  }

  static get observedAttributes()
  {
    return [ 'src', 'theme', 'live' ]
  }

  get props()
  {
    return {
      src: this.getAttribute('src'),
      theme: this.getAttribute('theme'),
      live: this.getAttribute('live'),
    }
  }

  /**
   * change attributes
   */
  attributeChangedCallback(name, oldValue, newValue)
  {
    if (oldValue === newValue) return
    switch (name)
    {
      case 'theme':
        this.options.theme = newValue
        if (this.core) this.core.options.theme = this.options.theme
        break
      case 'live':
        this.options.live = [ 'true', '1' ].includes(newValue)
        if (this.core) this.core.options.live = this.options.live
        break
    }
  }

  /**
   * mounted component
   */
  connectedCallback()
  {
    this.core = new JsonEditorCore(this.root, this.options)
    this.core.replace(JSON.parse(this.props.src), false)
    this.root.addEventListener('update', this.#onUpdate.bind(this))
    this.root.addEventListener('context', this.#onContext.bind(this))
  }

  /**
   * unmounted component
   */
  disconnectedCallback()
  {
    // destroy core
    if (!this.core) return
    this.core.destroy()
    delete this.core
    // clear source
    this.root.innerHTML = ''
  }

  #event(name, src)
  {
    this.dispatchEvent(new CustomEvent(name, {
      detail: src,
    }))
  }

  #onUpdate({ detail })
  {
    this.setAttribute('src', JSON.stringify(detail))
    this.#event('update', detail)
  }

  #onContext({ detail: { body, node, type, isRoot, $ } })
  {
    this.#event('context', { body, node, type, isRoot, $ })
  }

  /**
   * change src
   * @param {object|array} src
   */
  change(src)
  {
    this.setAttribute('src', JSON.stringify(src))
    this.core.replace(src, true)
  }

}

export default JsonEditor

먼저 에디터 라이브러리와 스타일시트를 불러온 웹 컴포넌트 클래스를 작성해둡니다.
이 코드로 저장된 파일이 진짜 웹 컴포넌트이며 이것을 불러와서 사용하면 됩니다.

Usage

사용 환경은 vite인점을 알려드립니다.

먼저 패키지를 설치합니다.

npm install @redgoose/json-editor

설치한 후에 html 코드에서 다음과 같이 엘리먼트를 추가해줍니다.

<json-editor id="editor" theme="light" live="true"></json-editor>

기초적으로 웹 컴포넌트를 정의하는 방법은 다음과 같습니다.

import JsonEditor from './web-component.js'

// define component
customElements.define('json-editor', JsonEditor)

만약 자바스크립트로 엘리먼트를 삽입한다면 다음과 같이 코드를 작성하여 사용합니다.

const jsonEditor = document.createElement('json-editor')
jsonEditor.setAttribute('src', '{"foo": "bar"}')
jsonEditor.setAttribute('theme', 'system')
jsonEditor.setAttribute('live', 'true')
document.getElementById('target').append(jsonEditor)

Attribute

  • src: JSON.stringify 형태의 데이터 값 (마운트 하는 시점에만 사용합니다!)
  • theme: 다크모드에 대한 값
  • live: 데이터가 업데이트 될때마다 update이벤트를 실행할지에 대한 여부

src 속성값과 에디터의 내용은 서로 분리되어 있기 때문에 src 값이 변한다고 에디터에 자동으로 업데이트 되지 않습니다.
에디터의 내용은 그대로 두고 외부에서 에디터의 내용을 변경하려면 change()메서드를 사용하거나 라이브러리 메서드를 이용하는것을 권장드립니다.

Methods

change

데이터 내용을 변경합니다.
속성과 에디터의 내용을 강제로 변경하기 때문에 주의해주세요.

jsonEditor.change({ foo: 'bar' })

Events

update

에디터 내용이 업데이트 되면 호출되는 이벤트

editor.addEventListener('update', (e) => {
  console.log('update', e.detail)
})

context

컨텍스트 메뉴가 열릴때 호출되는 이벤트

jsonEditor.addEventListener('context', (e) => {
  const { body, node, type, isRoot, $ } = e.detail
  console.log('context', node)
})

Access core instance

에디터 코어 메서드나 요소에 접근하여 기능을 사용할 수 있습니다.

const element = document.querySelector('json-editor')
const data = element.core.export(true, 2)
console.log('export data', data)

demo code

마지막으로 테스트로 작성한 웹 컴포넌트를 불러오는 데모코드와 프로젝트 디렉토리 압축파일을 첨부로 남겨둡니다.

main.js

import JsonEditor from './web-component.js'

// define component
customElements.define('json-editor', JsonEditor)

const editor = document.getElementById('editor')
editor.core.replace({
  foo: 'bar',
  apple: 'red',
  null: null,
  bool: false,
})

// event - update
editor.addEventListener('update', ({ detail }) => {
  console.log('update', detail)
})

// event - context
editor.addEventListener('context', ({ detail }) => {
  const { body, node, type, isRoot, $ } = detail
  console.log('context', node)
})

// export
const exportButton = document.getElementById('action-export')
exportButton.addEventListener('click', () => {
  const src = editor.core.export(undefined, false)
  console.log('export', src)
})

project file

web-component-demo.zip

Clone this wiki locally