From 2c80d20fb846837e4c0d3031c88b6d8c08e79ef4 Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Tue, 21 Jun 2022 20:01:51 +0500 Subject: [PATCH] add table resize --- .eslintrc.js | 8 ++- src/components/table/Table.ts | 12 ++++ src/components/table/table.functions.ts | 0 src/components/table/table.resize.ts | 77 +++++++++++++++++++++++++ src/components/table/table.template.ts | 29 ++++++---- src/core/dom.ts | 22 +++++++ src/styles/_variables.scss | 3 +- tsconfig.json | 2 +- 8 files changed, 138 insertions(+), 15 deletions(-) create mode 100644 src/components/table/table.functions.ts create mode 100644 src/components/table/table.resize.ts diff --git a/.eslintrc.js b/.eslintrc.js index 4ff7eb6..91d753b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -13,18 +13,20 @@ module.exports = { project: './tsconfig.json' }, rules: { + "@typescript-eslint/ban-ts-comment": "off", + "@typescript-eslint/lines-between-class-members": "off", "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-unnecessary-type-assertion": "off", "@typescript-eslint/no-unsafe-argument": "off", "@typescript-eslint/no-unsafe-assignment": "off", "@typescript-eslint/no-unsafe-call": "off", "@typescript-eslint/no-unsafe-member-access": "off", - "@typescript-eslint/restrict-template-expressions": "off", - "@typescript-eslint/lines-between-class-members": "off", "@typescript-eslint/no-unsafe-return": "off", "@typescript-eslint/no-use-before-define": "off", - "@typescript-eslint/ban-ts-comment": "off", + "@typescript-eslint/restrict-template-expressions": "off", "arrow-parens": "off", "class-methods-use-this": "off", + "func-names": "off", "import/prefer-default-export": "off", "no-console": "off", "no-plusplus": "off", diff --git a/src/components/table/Table.ts b/src/components/table/Table.ts index 78a0e17..e081cab 100644 --- a/src/components/table/Table.ts +++ b/src/components/table/Table.ts @@ -1,10 +1,22 @@ import { ExcelComponent } from '../../core/ExcelComponent'; import { createTable } from './table.template'; +import { resizeHandler } from './table.resize'; export class Table extends ExcelComponent { static className = 'excel__table'; + constructor($root: any) { + super($root, { + name: 'Table', + listeners: ['mousedown'], + }); + } + toHTML(): string { return createTable(50, 24); } + + onMousedown(event: MouseEvent) { + resizeHandler(this.$root, event); + } } diff --git a/src/components/table/table.functions.ts b/src/components/table/table.functions.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/components/table/table.resize.ts b/src/components/table/table.resize.ts new file mode 100644 index 0000000..0e6abb9 --- /dev/null +++ b/src/components/table/table.resize.ts @@ -0,0 +1,77 @@ +import { $, Dom } from '../../core/dom'; + +type CustomElementType = Element & { css: any }; + +export function resizeHandler($root: Dom, event: MouseEvent) { + const { target } = event; + if (!(target as HTMLElement).dataset.resize) return; + + const $resizer = $(target as HTMLElement); + const $parent = $resizer.closest('[data-type="resizable"]'); + const coords = $parent.getCoords(); + const type = $resizer.data.resize; + + const allCols = $root.findAll(`[data-col="${$parent.data.col}"]`); + + let delta: number; + + (Element.prototype as CustomElementType).css = function (styles: any) { + Object.keys(styles).forEach((key: any) => { + this.style[key] = styles[key]; + }); + }; + + $resizer.css({ opacity: 1 }); + + document.onmousemove = e => { + document.body.style.userSelect = 'none'; + + switch (type) { + case 'col': { + delta = e.pageX - coords.right; + $resizer.css({ + right: `${-delta}px`, + bottom: '-100vh', + }); + + break; + } + + case 'row': { + delta = e.pageY - coords.bottom; + + $resizer.css({ + bottom: `${-delta}px`, + right: '-100vw', + }); + + break; + } + + default: break; + } + }; + + document.onmouseup = () => { + document.onmousemove = null; + document.onmouseup = null; + document.body.style.userSelect = null; + + switch (type) { + case 'col': { + $parent.css({ width: `${coords.width + delta}px` }); + allCols.forEach((el: CustomElementType) => el.css({ width: `${coords.width + delta}px` })); + break; + } + + case 'row': { + $parent.css({ height: `${coords.height + (delta)}px` }); + break; + } + + default: break; + } + + $resizer.css({ opacity: 0, bottom: 0, right: 0 }); + }; +} diff --git a/src/components/table/table.template.ts b/src/components/table/table.template.ts index 153f713..a2418a7 100644 --- a/src/components/table/table.template.ts +++ b/src/components/table/table.template.ts @@ -3,22 +3,28 @@ const CODES = { Z: 90, }; -function createCell(cellContent = '') { +function createCell(cellContent = '', index = 1) { return ` -
${cellContent}
+
${cellContent}
`; } -function createCol(columnContent = '') { +function createCol(columnContent = '', index = 1) { return ` -
${columnContent}
+
+ ${columnContent} +
+
`; } -function createRow(dataContent = '', infoContent = '') { +function createRow(dataContent = '', infoContent = '', needResize = true) { return ` -
-
${infoContent}
+
+
+ ${infoContent} + ${needResize ? '
' : ''} +
${dataContent}
`; @@ -31,13 +37,16 @@ export function createTable(rowsCount = 10, columnCount = 10) { const cols = new Array(colsCount) .fill('') .map((el, index) => String.fromCharCode(CODES.A + index)) - .map((el) => createCol(el)) + .map((el, index) => createCol(el, index)) .join(''); - rows.push(createRow(cols)); + rows.push(createRow(cols, '', false)); for (let i = 0; i < rowsCount; i++) { - const cells = new Array(colsCount).fill(createCell()).join(''); + const cells = new Array(colsCount) + .fill('') + .map((el, index) => createCell('', index)) + .join(''); rows.push(createRow(cells, `${i + 1}`)); } diff --git a/src/core/dom.ts b/src/core/dom.ts index c1499a8..e8f4807 100644 --- a/src/core/dom.ts +++ b/src/core/dom.ts @@ -52,6 +52,28 @@ export class Dom implements DomClass { off(eventType: string, callback: any) { this.$el.removeEventListener(eventType, callback); } + + get data() { + return this.$el.dataset; + } + + closest(selector: string) { + return $(this.$el.closest(selector) as HTMLElement); + } + + getCoords() { + return this.$el.getBoundingClientRect(); + } + + findAll(selector: string) { + return this.$el.querySelectorAll(selector); + } + + css(styles: any) { + Object.keys(styles).forEach((key: any) => { + this.$el.style[key] = styles[key]; + }); + } } export function $(selector: SelectorType) { diff --git a/src/styles/_variables.scss b/src/styles/_variables.scss index 213cf33..b1bb2b7 100644 --- a/src/styles/_variables.scss +++ b/src/styles/_variables.scss @@ -5,4 +5,5 @@ $formula-height: 24px; $header-height: 34px; $info-cell-width: 40px; $row-height: 25px; -$toolbar-height: 40px; \ No newline at end of file +$toolbar-height: 40px; +$primary-color: #3c74ff; diff --git a/tsconfig.json b/tsconfig.json index 61ee365..2dc5eaa 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "./dist/", "noImplicitAny": true, - "target": "es3", + "target": "es5", "allowJs": true, "moduleResolution": "node", "esModuleInterop": true,