<template>
  <div class="snt-data-spreadsheet">
    <slot
      :navigatorErrors="navigatorErrors"
      :navigatorErrorSelected="navigatorErrorSelected"
      :navigatorErrorTo="navigatorErrorTo"
      name="header" />
    <v-sheet>
      <div class="pa-3">
        <slot
          :navigatorErrors="navigatorErrors"
          :navigatorErrorSelected="navigatorErrorSelected"
          :navigatorErrorTo="navigatorErrorTo" />
      </div>
      <div class="snt-data-spreadsheet__content">
        <div
          :id="`x-spreadsheet-${name}`"
          ref="sheetEl"
          :class="{ 'uninsert': uninsert }"
          class="snt-x-spreadsheet">
        </div>
        <Suggestion
          v-if="showSuggestion && mode === 'edit'"
          :key="`suggestion-${suggestKey}-${cellSelected.ri}`"
          :items="suggestItems"
          :callback="suggestCallback"
          :search="suggestValue"
          :top="suggestTop"
          :left="suggestLeft"
          @input="changeSuggestionItem($event)" />
      </div>
    </v-sheet>
  </div>
</template>

<script>
import { VSheet } from 'vuetify/lib'
import Spreadsheet from 'x-data-spreadsheet'
import { stringAt, indexAt } from 'x-data-spreadsheet/src/core/alphabet'
import Suggestion from './components/Suggestion.vue'

export default {
  components: {
    VSheet,
    Suggestion
  },
  props: {
    name: {
      type: String,
      required: true
    },
    mode: {
      type: String,
      default: 'edit'
    },
    headers: {
      type: [Array],
      default: () => ([])
    },
    items: {
      type: [Array],
      default: () => ([])
    },
    rowLen: {
      type: [Number],
      default: 250
    },
    colLen: {
      type: [Number],
      default: 26
    },
    selected: {
      type: [Array],
      default: () => ([0, 0])
    },
    showPlaceholder: Boolean,
    uninsert: Boolean
  },
  data () {
    return {
      xs: null,
      errors: {},
      imgError: null,
      imgSuggest: null,
      styles: [
        {
          font: {
            size: 10,
            name: 'prompt',
            bold: true
          },
          bgcolor: '#ffffff',
          color: '#6C6C6C'
        },
        {
          font: {
            size: 10,
            name: 'prompt',
            bold: true
          },
          bgcolor: '#1aa4e033',
          color: '#6C6C6C'
        },
        {
          font: {
            size: 10,
            name: 'prompt',
            bold: false
          },
          bgcolor: '#ffffff',
          color: '#6C6C6C'
        },
        {
          font: {
            size: 10,
            name: 'prompt',
            bold: false
          },
          bgcolor: '#ffffff',
          color: '#B5B5B5'
        },
        {
          font: {
            size: 10,
            name: 'prompt',
            bold: false
          },
          bgcolor: '#de6b4f33',
          color: '#6C6C6C'
        }
      ],
      cols: {},
      rows: {},
      cellSelected: {
        ri: null,
        ci: null,
        rect: {
          bottom: null,
          height: null,
          left: null,
          right: null,
          top: null,
          width: null,
          x: null,
          y: null
        }
      },
      navigatorErrorSelected: null,
      navigatorErrors: [],
      oldStyles: [
        {
          font: {
            size: 10,
            name: 'prompt',
            bold: true
          },
          bgcolor: '#ffffff',
          color: '#6C6C6C'
        },
        {
          font: {
            size: 10,
            name: 'prompt',
            bold: true
          },
          bgcolor: '#1aa4e033',
          color: '#6C6C6C'
        },
        {
          font: {
            size: 10,
            name: 'prompt',
            bold: false
          },
          bgcolor: '#ffffff',
          color: '#6C6C6C'
        },
        {
          font: {
            size: 10,
            name: 'prompt',
            bold: false
          },
          bgcolor: '#ffffff',
          color: '#B5B5B5'
        },
        {
          font: {
            size: 10,
            name: 'prompt',
            bold: false
          },
          bgcolor: '#de6b4f33',
          color: '#6C6C6C'
        }
      ],
      suggested: false
    }
  },
  computed: {
    suggestKey () {
      return this.cellSelected.ri > 0 ? this.headers[this.cellSelected.ci].value || null : null
    },
    suggestValue () {
      const item = this.items[this.cellSelected.ri - 1] || {}
      return item[this.suggestKey] || ''
    },
    suggestCallback () {
      return this.cellSelected.ri > 0 ? this.headers[this.cellSelected.ci]?.suggestCallback || null : null
    },
    suggestItems () {
      if (this.cellSelected.ri > 0) {
        let suggestItems
        if (typeof this.headers[this.cellSelected.ci]?.suggestItems === 'function') {
          suggestItems = this.headers[this.cellSelected.ci]?.suggestItems(this.suggestValue, this.cellSelected.ri - 1)
        } else {
          suggestItems = this.headers[this.cellSelected.ci]?.suggestItems
        }
        return suggestItems || null
      }
      return null
    },
    showSuggestion () {
      const items = this.suggestItems || this.suggestCallback || []
      return !this.suggested && items.length
    },
    suggestTop () {
      const sheetRect = this.xs.sheet.el.el.getBoundingClientRect()
      const top = this.cellSelected.rect.top + this.cellSelected.rect.height - sheetRect.y
      return this.$_.max([top, 0])
    },
    suggestLeft () {
      const sheetRect = this.xs.sheet.el.el.getBoundingClientRect()
      const left = this.cellSelected.rect.left - sheetRect.x
      return this.$_.max([left, 0])
    },
    beforeValueChanges () {
      return this.cellSelected.ri > 0 ? this.headers[this.cellSelected.ci]?.beforeValueChanges || null : null
    }
  },
  watch: {
    selected (newValue, oldValue) {
      if (
        !!newValue
        && !this.$_.isUndefined(newValue[0])
        && !this.$_.isUndefined(newValue[1])
        && (!oldValue || (newValue[0] !== oldValue[0] || newValue[1] !== oldValue[1]))
        && (newValue[0] !== this.cellSelected.ri || newValue[1] !== this.cellSelected.ci)
      ) {
        this.moveTo(newValue[0], newValue[1])
      }
    },
    showPlaceholder (newValue, oldValue) {
      if (newValue !== oldValue) {
        this.xs.reRender()
        // this.renderFixedHeaders(this.errors)
        // this.renderPlaceholder()
      }
    }
  },
  beforeDestroy () {
    window.removeEventListener('keydown', this.handleKeydown)
  },
  created () {
    const b64Start = 'data:image/svg+xml;base64,'
    this.imgError = document.createElement('img')
    this.imgError.src = b64Start + btoa(`
      <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="16" height="16" viewBox="0 0 24 24" fill="#de6b4f">
        <path d="
          M11,15H13V17H11V15M11,7H13V13H11V7M12,2C6.47,2 2,6.5 2,12A10,10 0 0,0 12,22A10,10 0 0,
          0 22,12A10,10 0 0,0 12,2M12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4A8,8 0 0,1 20,12A8,8 0 0,
          1 12,20Z" />
      </svg>
    `)
    this.imgSuggest = document.createElement('img')
    this.validateThrottle = this.$_.throttle(this.validate, 250)
    this.changeDebounce = this.$_.debounce(this.change, 250)
  },
  mounted () {
    this.reinit(true)
  },
  methods: {
    reinit (init = false) {
      this.xs = null
      this.cols = {}
      this.rows = {}
      this.styles = this.$_.cloneDeep(this.oldStyles)
      setTimeout(() => {
        this.loadHeaders()
        this.loadItems()
        this.loadSheet()
        const { ri, ci } = this.cellSelected
        this.xs.sheet.selector.set(Number(ri), Number(ci))
        if (init) {
          this.preventMousewheelHorizontal()
        }
      }, 100)
    },
    preventMousewheelHorizontal () {
      const element = this.xs.sheet.horizontalScrollbar.el.el
      // Detect browsers
      const isChrome = navigator.userAgent.indexOf('Chrome') > -1
      const isSafari = navigator.userAgent.indexOf('Safari') > -1
      const isFirefox = navigator.userAgent.indexOf('Firefox') > -1

      // Handle scroll events in Chrome, Safari, and Firefox
      if (isChrome || isSafari || isFirefox) {
        // scrolling left without raising your fingers from the scroll position.
        element.addEventListener('mousewheel', (e) => {
          const preventLeft = e.deltaY < 0 && e.target.scrollLeft <= 0
          if (preventLeft) {
            e.preventDefault()
          }
        })
      }
    },
    loadItems () {
      this.items.forEach((item, i) => {
        this.rows[i + 1] = {
          cells: {}
        }
        this.headers.forEach((head, j) => {
          this.rows[i + 1].cells[j] = {
            text: this.$_.toString(item[head.value]),
            value: item[head.value],
            style: head.bodyStyle,
            editable: this.$_.isUndefined(head.editable) ? true : head.editable
          }
        })
      })
    },
    loadHeaders () {
      this.rows[0] = {
        cells: {}
      }
      this.$_.times(this.colLen, (i) => {
        const value = this.headers[i]
        if (value) {
          this.rows[0].cells[i] = {
            ...value,
            text: value.text,
            value: value.value,
            width: value.width,
            style: value.style,
            editable: false
          }
          this.cols[i] = {
            width: value.width,
            placeholder: value.placeholder
          }
        } else {
          this.rows[0].cells[i] = {
            text: '',
            editable: false
          }
        }
      })
    },
    loadSheet () {
      const element = this.$refs.sheetEl
      element.innerHTML = ''
      const options = {
        mode: this.mode,
        showToolbar: false,
        showGrid: true,
        showContextmenu: true,
        showBottomBar: false,
        row: {
          height: 30,
          len: this.rowLen
        },
        col: {
          len: this.colLen
        },
        view: {
          height () {
            return 450
          },
          width: () => (element && element.clientWidth)
            || document.documentElement.clientWidth
        },
        style: {
          bgcolor: '#ffffff',
          align: 'left',
          valign: 'middle',
          textwrap: false,
          strike: false,
          underline: false,
          color: '#0a0a0a',
          font: {
            name: 'prompt',
            size: 10,
            bold: false,
            italic: false
          }
        }
      }
      this.xs = new Spreadsheet(element, options).loadData({
        styles: this.styles,
        cols: this.cols,
        rows: this.rows
      })
      if (this.xs) {
        if (
          !!this.selected
          && !this.$_.isUndefined(this.selected[0])
          && !this.$_.isUndefined(this.selected[1])) {
          this.moveTo(this.selected[0], this.selected[1])
        }

        this.onChange()
        this.validate()
        this.onCellSelected()
        this.onCellsSelected()
        this.onClick()
        this.onEditor()
        this.onVerticalScroll()
        this.onHorizontalScroll()
        this.xs.reRender()
        // this.renderFixedHeaders(this.errors)
        // this.renderPlaceholder()
        // // fix style none init render
        if (!this.items.length) {
          setTimeout(() => {
            this.xs.reRender()
            // this.renderFixedHeaders(this.errors)
            // this.renderPlaceholder()
          }, 100)
        }
      }
    },
    handleKeydown (evt) {
      if (!this.xs.sheet.focusing) return
      const keyCode = evt.keyCode || evt.which
      if ((keyCode >= 65 && keyCode <= 90)
        || (keyCode >= 48 && keyCode <= 57)
        || (keyCode >= 96 && keyCode <= 105)
        || evt.key === '='
      ) {
        const { ci } = this.cellSelected
        const column = this.headers[ci]
        if (column && column.editable === false) {
          this.$emit('re-render')
        }
      }
    },
    onEditor () {
      window.addEventListener('keydown', this.handleKeydown)
    },
    change (sheet) {
      const rows = []
      const len = this.$_.max(this.$_.map(sheet.rows, (val, key) => Number(key)))
      for (let i = 1; i <= len; i++) {
        const row = sheet.rows[i] || {}
        const cols = {}
        if (row.cells) {
          this.$_.forEach(row.cells, (cell, j) => {
            const column = this.headers[j]
            if (column) {
              if (column.editable !== false) {
                cols[column.value] = cell?.text || ''
              } else {
                cols[column.value] = !this.$_.isUndefined(cell?.value) ? cell?.value : ''
              }
            }
          })
        }
        rows.push(cols)
      }
      this.$emit('update:items', rows)
      this.validate()
      this.xs.reRender()
      this.renderFixedHeaders(this.errors)
      this.renderPlaceholder()
      if (!sheet.rows[0]) {
        this.$emit('re-render')
      }
    },
    onChange () {
      this.xs.change(this.changeDebounce)
    },
    onHorizontalScroll () {
      const horizontalMoveFn = this.xs.sheet.horizontalScrollbar.moveFn
      this.xs.sheet.horizontalScrollbar.moveFn = (distance, evt) => {
        horizontalMoveFn(distance, evt)
        this.cellSelected.rect = this.xs.sheet.selector.br.areaEl.el.getBoundingClientRect()
      }
    },
    onVerticalScroll () {
      const verticalMoveFn = this.xs.sheet.verticalScrollbar.moveFn
      this.xs.sheet.verticalScrollbar.moveFn = (distance, evt) => {
        verticalMoveFn(distance, evt)
        this.cellSelected.rect = this.xs.sheet.selector.br.areaEl.el.getBoundingClientRect()
      }
    },
    onClick () {
      const render = this.xs.sheet.table.render
      setTimeout(() => {
        this.xs.sheet.overlayerEl.on('mousewheel.stop', (evt) => {
          evt.preventDefault()
        })
      })
      this.xs.sheet.table.draw.frozen = () => {}
      this.xs.sheet.table.render = () => {
        render.call(this.xs.sheet.table)
        this.renderFixedHeaders(this.errors)
        this.renderPlaceholder()
      }
      this.xs.sheet.el.on('mousedown', () => {

      })
      this.xs.sheet.el.on('mouseup', () => {

      })
    },
    onCellSelected () {
      this.xs.sheet.on('cell-selected', (cell, ri, ci) => {
        // ปลดออกเหมือนจะไม่จำเป็นต้องใช้แล้ว
        // this.validateThrottle()
        this.setValidate(ri, ci)
        this.cellSelected = {
          ri,
          ci,
          rect: this.xs.sheet.selector.br.areaEl.el.getBoundingClientRect()
        }
        this.suggested = false
        this.$emit('update:selected', [ri, ci])
        const header = this.headers[ci] || {}
        const editable = this.$_.isUndefined(header.editable) ? true : header.editable
        if (ri > 0 && editable) {
          this.xs.sheet.editor.areaEl.el.style.display = 'block'
        } else {
          this.xs.sheet.editor.areaEl.el.style.display = 'none'
        }
      })
    },
    onCellsSelected () {
      this.xs.sheet.on('cells-selected', () => {

      })
    },
    changeSuggestionItem (value) {
      const { ri, ci } = this.cellSelected
      const row = ri - 1
      const header = this.headers[ci]
      if (!header) return
      const items = this.$_.cloneDeep(this.items)
      let newValue = value
      if (this.beforeValueChanges) {
        const itemRow = items[row] || {}
        const oldValue = itemRow[header.value]
        newValue = this.beforeValueChanges(newValue, oldValue)
      }
      for (let i = 0; i <= row; i++) {
        if (!items[i]) {
          items[i] = {}
        }
        if (row === i) {
          items[i][header.value] = newValue
        }
      }
      this.suggested = true
      this.$emit('update:items', items)
      this.$emit('suggest-selected', newValue)
    },
    validate () {
      this.errors = {}
      this.xs.sheet.table.data.rows.each((ri) => {
        this.headers.forEach((header, ci) => {
          const errors = this.getErrors(ri, ci)
          if (errors.length) {
            this.xs.sheet.table.data.rows.setCell(ri, ci, {
              style: 4
            }, 'format')
            this.setError(ri, ci, errors[0])
          } else {
            this.xs.sheet.table.data.rows.setCell(ri, ci, {
              style: ri > 0 ? this.headers[ci].bodyStyle : this.headers[ci].style
            }, 'format')
          }
        })
      })
      const navigator = this.$_.map(this.errors,
        ((row, ri) => this.$_.map(row.cells,
          ((cell, ci) => ({
            ri,
            ci,
            at: cell.at,
            error: cell.error
          })
          ))
        )).flat()
      this.navigatorErrors = this.$_.cloneDeep(navigator)
      if (navigator.length) {
        const error = this.$_.head(navigator)
        this.navigatorErrorSelected = {
          ...error,
          seq: 1
        }
      } else {
        this.navigatorErrorSelected = null
      }
      this.$emit('validate', navigator)
    },
    setError (ri, ci, error) {
      this.errors = this.$_.defaultsDeep({
        [ri]: {
          cells: {
            [ci]: {
              at: stringAt(ci) + (Number(ri) + 1),
              error
            }
          }
        }
      }, this.errors)
    },
    setValidate (ri, ci) {
      const errors = this.getErrors(ri, ci)
      const row = this.xs.sheet.table.data.rows.get(ri)
      if (row && errors.length) {
        const width = this.xs.sheet.selector.br.hideInputDiv.el.clientWidth
        const left = width + 15
        const tooltip = `
          <div class="tooltip-error" style="left: ${ left }px; }">
            <div class="tooltip-error__text"> ${ errors[0] } </div>
          </div>
        `
        this.xs.sheet.selector.br.hideInputDiv.el.innerHTML = tooltip
      } else {
        this.xs.sheet.selector.br.hideInputDiv.el.innerHTML = ''
      }
    },
    getErrors (ri, ci) {
      const index = ri - 1
      const col = this.headers[ci]
      const errors = []
      if (col && col.rules && ri > 0) {
        const cell = this.xs.sheet.table.data.getCell(ri, ci)
        const value = cell?.text || ''
        col.rules.forEach((rule) => {
          const valid = typeof rule === 'function' ? rule(value, index) : rule
          if (valid === false || typeof valid === 'string') {
            errors.push(valid || '')
          } else if (typeof valid !== 'boolean') {
            console.error(`Rules should return a string or boolean, received '${typeof valid}' instead`)
          }
        })
      }
      return errors
    },
    navigatorErrorTo (navigator) {
      this.navigatorErrorSelected = navigator
      this.moveTo(navigator.ri, navigator.ci)
    },
    moveTo (ri, ci) {
      const col = ci - 5
      const colWidth = 100
      const row = ri - 5
      const rowHeight = 30
      this.xs.sheet.selector.set(Number(ri), Number(ci))
      this.setValidate(ri, ci)
      this.xs.sheet.verticalScrollbar.move({
        top: (rowHeight * (row)) || 0,
        behavior: 'smooth'
      })
      this.xs.sheet.horizontalScrollbar.move({
        left: (colWidth * (col)) || 0,
        behavior: 'smooth'
      })
    },
    renderFixedHeaders (errors) {
      // this.xs.sheet.table.draw.ctx.restore()
      const viewRange = this.xs.sheet.table.data.viewRange()
      const headerHeight = 30
      const headerWidth = 45
      this.xs.sheet.table.draw.ctx.scale(this.dpr(), this.dpr())
      this.xs.sheet.table.draw.ctx.restore()
      this.xs.sheet.table.data.rowEach(viewRange.sri, viewRange.eri, (ri, y1, rowHeight) => {
        const y = headerHeight + y1 + (rowHeight / 2) - 10
        if (errors[ri]) {
          this.xs.sheet.table.draw.ctx.drawImage(this.imgError, 6, y)
        }
        this.xs.sheet.table.data.colEach(viewRange.sci, viewRange.eri, (ci, x1, colWidth) => {
          const x = headerWidth + x1 + colWidth - 10
          const header = this.headers[ci] || {}
          if (ri > 0) {
            if (header.suggestCallback || header.suggestItems) {
              const base64 = `data:image/svg+xml;base64, ${ btoa(`
                <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                  <rect width="16" height="16" rx="3" fill="#E9E9E9"/>
                  <path 
                    d="M5.80703 7.80602L7.53369 9.53268C7.79369 9.79268 8.21369 9.79268 8.47369 9.53268L10.2004 7.80602C10.6204 
                    7.38602 10.3204 6.66602 9.72703 6.66602H6.27369C5.68036 6.66602 5.38703 7.38602 5.80703 7.80602Z" 
                    fill="#6C6C6C" />
                </svg>
              `)}`
              const imgSuggest = document.createElement('img')
              imgSuggest.src = header.suggestIcon || base64
              this.xs.sheet.table.draw.ctx.drawImage(imgSuggest, x, y)
            }
          }
        })
      })
      this.xs.sheet.table.draw.ctx.save()
    },
    renderPlaceholder () {
      if (!this.showPlaceholder) return
      const viewRange = this.xs.sheet.table.data.viewRange()

      const ny1 = 33 // fixed margin top
      const nx1 = 66 // fixed margin left
      const example = 2
      let renderExample = 0
      this.xs.sheet.table.draw.ctx.scale(this.dpr(), this.dpr())
      this.xs.sheet.table.draw.ctx.restore()
      this.xs.sheet.table.draw.ctx.font = '12px prompt'
      this.xs.sheet.table.draw.ctx.fillStyle = '#B5B5B5'
      this.xs.sheet.table.data.rowEach(viewRange.sri, viewRange.eri, (ri, y1, rowHeight) => {
        this.xs.sheet.table.data.colEach(viewRange.sci, viewRange.eci, (ci, x1) => {
          const cell = this.xs.sheet.table.data.getCell(ri, ci)
          if ((cell && !cell.text && ri <= example) || (!cell && ri <= example)) {
            const col = this.xs.sheet.table.data.cols._[ci]
            if (col && col.placeholder) {
              const placeholder = this.$_.isArray(col.placeholder)
                ? col.placeholder[renderExample] || col.placeholder[col.placeholder.length - 1]
                : col.placeholder
              this.xs.sheet.table.draw.ctx.fillText(placeholder, nx1 + x1, ny1 + y1 + (rowHeight / 2))
            }
          }
        })
        if (ri !== 0) {
          renderExample++
        }
      })
      this.xs.sheet.table.draw.ctx.save()
    },
    dpr () {
      return window.devicePixelRatio || 1
    },
    stringAt,
    indexAt
  }

}
</script>
<style lang="scss">
  .snt-data-spreadsheet {
    &__content {
      position: relative;
    }
  }
  .snt-x-spreadsheet {
    position: relative;
    z-index: 1;
    ::-webkit-scrollbar {
      width: 12px;
      height: 12px;
    }
    ::-webkit-scrollbar-button:single-button {
      background-color: #f1f1f1;

      display: block;
      background-size: 8px;
      background-repeat: no-repeat;
    }
    // /* Up */
    // ::-webkit-scrollbar-button:single-button:vertical:decrement {
    //     height: 12px;
    //     width: 16px;
    //     background-position: center 4px;
    //     background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='rgb(96, 96, 96)'><polygon points='50,00 0,50 100,50'/></svg>");
    // }

    // ::-webkit-scrollbar-button:single-button:vertical:decrement:hover {
    //     background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='rgb(112, 112, 112)'><polygon points='50,00 0,50 100,50'/></svg>");
    // }

    // ::-webkit-scrollbar-button:single-button:vertical:decrement:active {
    //     background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='rgb(128, 128, 128)'><polygon points='50,00 0,50 100,50'/></svg>");
    // }

    // /* Down */
    // ::-webkit-scrollbar-button:single-button:vertical:increment {
    //     height: 12px;
    //     width: 16px;
    //     background-position: center 2px;
    //     background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='rgb(96, 96, 96)'><polygon points='0,0 100,0 50,50'/></svg>");
    // }

    // ::-webkit-scrollbar-button:single-button:vertical:increment:hover {
    //     background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='rgb(112, 112, 112)'><polygon points='0,0 100,0 50,50'/></svg>");
    // }

    // ::-webkit-scrollbar-button:single-button:vertical:increment:active {
    //     background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='rgb(128, 128, 128)'><polygon points='0,0 100,0 50,50'/></svg>");
    // }
    /* Left */
    ::-webkit-scrollbar-button:single-button:horizontal:decrement {
      height: 12px;
      width: 12px;
      background-position: 3px 2px;
      background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='rgb(96, 96, 96)'><polygon points='0,50 50,100 50,0'/></svg>");
    }
    ::-webkit-scrollbar-button:single-button:horizontal:decrement:hover {
      background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='rgb(112, 112, 112)'><polygon points='0,50 50,100 50,0'/></svg>");
    }
    ::-webkit-scrollbar-button:single-button:horizontal:decrement:active {
      background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='rgb(128, 128, 128)'><polygon points='0,50 50,100 50,0'/></svg>");
    }
    /* Right */
    ::-webkit-scrollbar-button:single-button:horizontal:increment {
        height: 12px;
        width: 12px;
        background-position: 3px 2px;
        background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='rgb(96, 96, 96)'><polygon points='0,0 0,100 50,50'/></svg>");
    }
    ::-webkit-scrollbar-button:single-button:horizontal:increment:hover {
      background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='rgb(112, 112, 112)'><polygon points='0,0 0,100 50,50'/></svg>");
    }
    ::-webkit-scrollbar-button:single-button:horizontal:increment:active {
      background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='rgb(128, 128, 128)'><polygon points='0,0 0,100 50,50'/></svg>");
    }
    ::-webkit-scrollbar-thumb {
      border-radius: 4px;
    }
    .x-spreadsheet-editor {
      z-index: 40;
      textarea {
        background-color: rgb(255, 255, 255);
        color: #000;
      }
    }
    .x-spreadsheet-contextmenu {
      .x-spreadsheet-item:nth-child(2),
      .x-spreadsheet-item:nth-child(4),
      .x-spreadsheet-item:nth-child(5),
      .x-spreadsheet-item:nth-child(8),
      .x-spreadsheet-item:nth-child(9),
      .x-spreadsheet-item:nth-child(11),
      .x-spreadsheet-item:nth-child(12),
      .x-spreadsheet-item:nth-child(13),
      .x-spreadsheet-item:nth-child(14),
      .x-spreadsheet-item:nth-child(15),
      .x-spreadsheet-item:nth-child(16),
      .x-spreadsheet-item:nth-child(17),
      .x-spreadsheet-item:nth-child(18),
      .x-spreadsheet-item:nth-child(19),
      .x-spreadsheet-item:nth-child(20),
      .x-spreadsheet-item:nth-child(21) {
        display: none !important;
      }
    }
    &.uninsert {
      .x-spreadsheet-contextmenu {
        .x-spreadsheet-item:nth-child(1),
        .x-spreadsheet-item:nth-child(3),
        .x-spreadsheet-item:nth-child(6),
        .x-spreadsheet-item:nth-child(7) {
          display: none !important;
        }
      }
    }
    .x-spreadsheet-overlayer {
      .x-spreadsheet-suggest {
        height: 300px;
        overflow-y: auto;
      }
    }
    .tooltip-error {
      position: absolute;
      background: #000000a6;
      border: 1px solid #6c6c6c;
      border-radius: 4px;
      width: 150px;
      z-index: 40;
      &__text {
        color: #ffffff;
        padding: 8px 12px;
      }
    }
  }
</style>
<style lang="scss" scoped>

</style>
