tableタグやめる

This commit is contained in:
samunohito 2024-07-07 17:10:10 +09:00
parent 1cefedb6ac
commit 20bcf4af4f
7 changed files with 111 additions and 60 deletions

View File

@ -4,11 +4,15 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<td <div
ref="rootEl" ref="rootEl"
class="mk_grid_td"
:class="$style.cell" :class="$style.cell"
:style="{ maxWidth: cellWidth, minWidth: cellWidth }" :style="{ maxWidth: cellWidth, minWidth: cellWidth }"
:tabindex="-1" :tabindex="-1"
data-grid-cell
:data-grid-cell-row="cell.row.index"
:data-grid-cell-col="cell.column.index"
@keydown="onCellKeyDown" @keydown="onCellKeyDown"
@dblclick.prevent="onCellDoubleClick" @dblclick.prevent="onCellDoubleClick"
> >
@ -77,7 +81,7 @@ SPDX-License-Identifier: AGPL-3.0-only
/> />
</div> </div>
</div> </div>
</td> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -143,7 +147,7 @@ function onCellDoubleClick(ev: MouseEvent) {
function onOutsideMouseDown(ev: MouseEvent) { function onOutsideMouseDown(ev: MouseEvent) {
const isOutside = ev.target instanceof Node && !rootEl.value?.contains(ev.target); const isOutside = ev.target instanceof Node && !rootEl.value?.contains(ev.target);
if (isOutside || !equalCellAddress(cell.value.address, getCellAddress(ev.target as HTMLElement, rowSetting.value))) { if (isOutside || !equalCellAddress(cell.value.address, getCellAddress(ev.target as HTMLElement))) {
endEditing(true); endEditing(true);
} }
} }
@ -352,9 +356,9 @@ $cellHeight: 28px;
width: 100%; width: 100%;
max-width: 100%; max-width: 100%;
box-sizing: border-box; box-sizing: border-box;
min-height: $cellHeight; min-height: $cellHeight - 2;
max-height: $cellHeight; max-height: $cellHeight - 2;
height: $cellHeight + 4px; height: $cellHeight - 2;
outline: none; outline: none;
border: none; border: none;
font-family: 'Hiragino Maru Gothic Pro', "BIZ UDGothic", Roboto, HelveticaNeue, Arial, sans-serif; font-family: 'Hiragino Maru Gothic Pro', "BIZ UDGothic", Roboto, HelveticaNeue, Arial, sans-serif;

View File

@ -4,7 +4,8 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<tr <div
class="mk_grid_tr"
:class="[ :class="[
$style.row, $style.row,
row.ranged ? $style.ranged : {}, row.ranged ? $style.ranged : {},
@ -13,6 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:style="[ :style="[
...(row.additionalStyles ?? []).map(it => it.style ?? {}), ...(row.additionalStyles ?? []).map(it => it.style ?? {}),
]" ]"
:data-grid-row="row.index"
> >
<MkNumberCell <MkNumberCell
v-if="setting.showNumber" v-if="setting.showNumber"
@ -31,7 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only
@change:value="(sender, newValue) => emit('change:value', sender, newValue)" @change:value="(sender, newValue) => emit('change:value', sender, newValue)"
@change:contentSize="(sender, newSize) => emit('change:contentSize', sender, newSize)" @change:contentSize="(sender, newSize) => emit('change:contentSize', sender, newSize)"
/> />
</tr> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -58,6 +60,10 @@ defineProps<{
<style module lang="scss"> <style module lang="scss">
.row { .row {
display: flex;
flex-direction: row;
align-items: center;
&.ranged { &.ranged {
background-color: var(--accentedBg); background-color: var(--accentedBg);
} }

View File

@ -4,14 +4,15 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<table <div
ref="rootEl" ref="rootEl"
:class="[$style.grid, $style.border]" class="mk_grid_border"
:class="[$style.grid]"
@mousedown.prevent="onMouseDown" @mousedown.prevent="onMouseDown"
@keydown="onKeyDown" @keydown="onKeyDown"
@contextmenu.prevent.stop="onContextMenu" @contextmenu.prevent.stop="onContextMenu"
> >
<thead> <div class="mk_grid_thead">
<MkHeaderRow <MkHeaderRow
:columns="columns" :columns="columns"
:gridSetting="rowSetting" :gridSetting="rowSetting"
@ -22,8 +23,8 @@ SPDX-License-Identifier: AGPL-3.0-only
@change:width="onHeaderCellChangeWidth" @change:width="onHeaderCellChangeWidth"
@change:contentSize="onHeaderCellChangeContentSize" @change:contentSize="onHeaderCellChangeContentSize"
/> />
</thead> </div>
<tbody> <div class="mk_grid_tbody">
<MkDataRow <MkDataRow
v-for="row in rows" v-for="row in rows"
v-show="row.using" v-show="row.using"
@ -39,8 +40,8 @@ SPDX-License-Identifier: AGPL-3.0-only
@change:value="onChangeCellValue" @change:value="onChangeCellValue"
@change:contentSize="onChangeCellContentSize" @change:contentSize="onChangeCellContentSize"
/> />
</tbody> </div>
</table> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -81,14 +82,14 @@ const props = defineProps<{
}>(); }>();
// non-reactive // non-reactive
// eslint-disable-next-line vue/no-setup-props-destructure
const rowSetting: Required<GridRowSetting> = { const rowSetting: Required<GridRowSetting> = {
...defaultGridRowSetting, ...defaultGridRowSetting,
...props.settings.row, ...props.settings.row,
}; };
// non-reactive // non-reactive
// eslint-disable-next-line vue/no-setup-props-destructure
const columnSettings = props.settings.cols; const columnSettings = props.settings.cols;
// non-reactive // non-reactive
@ -448,7 +449,7 @@ function onMouseDown(ev: MouseEvent) {
} }
function onLeftMouseDown(ev: MouseEvent) { function onLeftMouseDown(ev: MouseEvent) {
const cellAddress = getCellAddress(ev.target as HTMLElement, rowSetting); const cellAddress = getCellAddress(ev.target as HTMLElement);
if (_DEV_) { if (_DEV_) {
console.log(`[grid][mouse-left] state:${state.value}, button: ${ev.button}, cell: ${cellAddress.row}x${cellAddress.col}`); console.log(`[grid][mouse-left] state:${state.value}, button: ${ev.button}, cell: ${cellAddress.row}x${cellAddress.col}`);
} }
@ -582,7 +583,7 @@ function onLeftMouseDown(ev: MouseEvent) {
} }
function onRightMouseDown(ev: MouseEvent) { function onRightMouseDown(ev: MouseEvent) {
const cellAddress = getCellAddress(ev.target as HTMLElement, rowSetting); const cellAddress = getCellAddress(ev.target as HTMLElement);
if (_DEV_) { if (_DEV_) {
console.log(`[grid][mouse-right] button: ${ev.button}, cell: ${cellAddress.row}x${cellAddress.col}`); console.log(`[grid][mouse-right] button: ${ev.button}, cell: ${cellAddress.row}x${cellAddress.col}`);
} }
@ -607,7 +608,7 @@ function onRightMouseDown(ev: MouseEvent) {
function onMouseMove(ev: MouseEvent) { function onMouseMove(ev: MouseEvent) {
ev.preventDefault(); ev.preventDefault();
const targetCellAddress = getCellAddress(ev.target as HTMLElement, rowSetting); const targetCellAddress = getCellAddress(ev.target as HTMLElement);
if (equalCellAddress(previousCellAddress.value, targetCellAddress)) { if (equalCellAddress(previousCellAddress.value, targetCellAddress)) {
// //
return; return;
@ -718,7 +719,7 @@ function onMouseUp(ev: MouseEvent) {
} }
function onContextMenu(ev: MouseEvent) { function onContextMenu(ev: MouseEvent) {
const cellAddress = getCellAddress(ev.target as HTMLElement, rowSetting); const cellAddress = getCellAddress(ev.target as HTMLElement);
if (_DEV_) { if (_DEV_) {
console.log(`[grid][context-menu] button: ${ev.button}, cell: ${cellAddress.row}x${cellAddress.col}`); console.log(`[grid][context-menu] button: ${ev.button}, cell: ${cellAddress.row}x${cellAddress.col}`);
} }
@ -1270,22 +1271,22 @@ onMounted(() => {
</script> </script>
<style module lang="scss"> <style module lang="scss">
.grid {
font-size: 90%;
}
</style>
<style lang="scss">
$borderSetting: solid 0.5px var(--divider); $borderSetting: solid 0.5px var(--divider);
$borderRadius: var(--radius); $borderRadius: var(--radius);
.grid { // scopedmodule使
overflow: scroll; .mk_grid_border {
table-layout: fixed;
user-select: none;
font-size: 90%;
}
.border {
border-spacing: 0; border-spacing: 0;
thead { .mk_grid_thead {
tr { .mk_grid_tr {
th { .mk_grid_th {
border-left: $borderSetting; border-left: $borderSetting;
border-top: $borderSetting; border-top: $borderSetting;
@ -1303,9 +1304,9 @@ $borderRadius: var(--radius);
} }
} }
tbody { .mk_grid_tbody {
tr { .mk_grid_tr {
td, th { .mk_grid_td, .mk_grid_th {
border-left: $borderSetting; border-left: $borderSetting;
border-top: $borderSetting; border-top: $borderSetting;
@ -1316,7 +1317,7 @@ $borderRadius: var(--radius);
} }
&.lastLine { &.lastLine {
td, th { .mk_grid_td, .mk_grid_th {
// //
border-bottom: $borderSetting; border-bottom: $borderSetting;

View File

@ -4,16 +4,20 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<th <div
ref="rootEl" ref="rootEl"
class="mk_grid_th"
:class="$style.cell" :class="$style.cell"
:style="[{ maxWidth: column.width, minWidth: column.width, width: column.width }]" :style="[{ maxWidth: column.width, minWidth: column.width, width: column.width }]"
data-grid-cell
:data-grid-cell-row="-1"
:data-grid-cell-col="column.index"
> >
<div :class="$style.root"> <div :class="$style.root">
<div :class="$style.left"/> <div :class="$style.left"/>
<div :class="$style.wrapper"> <div :class="$style.wrapper">
<div ref="contentEl" :class="$style.contentArea"> <div ref="contentEl" :class="$style.contentArea">
<span v-if="column.setting.icon" class="ti" :class="column.setting.icon"/> <span v-if="column.setting.icon" class="ti" :class="column.setting.icon" style="line-height: normal"/>
<span v-else>{{ text }}</span> <span v-else>{{ text }}</span>
</div> </div>
</div> </div>
@ -23,7 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only
@dblclick="onHandleDoubleClick" @dblclick="onHandleDoubleClick"
/> />
</div> </div>
</th> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -161,6 +165,7 @@ onUnmounted(() => {
<style module lang="scss"> <style module lang="scss">
$handleWidth: 5px; $handleWidth: 5px;
$cellHeight: 28px;
.cell { .cell {
cursor: pointer; cursor: pointer;
@ -169,7 +174,9 @@ $handleWidth: 5px;
.root { .root {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
height: 100%; height: $cellHeight;
max-height: $cellHeight;
min-height: $cellHeight;
.wrapper { .wrapper {
flex: 1; flex: 1;

View File

@ -4,7 +4,11 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<tr> <div
class="mk_grid_tr"
:class="$style.root"
:data-grid-row="-1"
>
<MkNumberCell <MkNumberCell
v-if="gridSetting.showNumber" v-if="gridSetting.showNumber"
content="#" content="#"
@ -21,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only
@change:width="(sender, width) => emit('change:width', sender, width)" @change:width="(sender, width) => emit('change:width', sender, width)"
@change:contentSize="(sender, newSize) => emit('change:contentSize', sender, newSize)" @change:contentSize="(sender, newSize) => emit('change:contentSize', sender, newSize)"
/> />
</tr> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -46,3 +50,11 @@ defineProps<{
bus: GridEventEmitter, bus: GridEventEmitter,
}>(); }>();
</script> </script>
<style module lang="scss">
.root {
display: flex;
flex-direction: row;
align-items: center;
}
</style>

View File

@ -4,11 +4,18 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<th :class="[$style.cell]" tabindex="-1"> <div
class="mk_grid_th"
:class="[$style.cell]"
:tabindex="-1"
data-grid-cell
:data-grid-cell-row="row?.index ?? -1"
:data-grid-cell-col="-1"
>
<div :class="[$style.root]"> <div :class="[$style.root]">
{{ content }} {{ content }}
</div> </div>
</th> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">

View File

@ -6,17 +6,17 @@
import { isRef, Ref } from 'vue'; import { isRef, Ref } from 'vue';
import { DataSource, SizeStyle } from '@/components/grid/grid.js'; import { DataSource, SizeStyle } from '@/components/grid/grid.js';
import { CELL_ADDRESS_NONE, CellAddress, CellValue, GridCell } from '@/components/grid/cell.js'; import { CELL_ADDRESS_NONE, CellAddress, CellValue, GridCell } from '@/components/grid/cell.js';
import { GridRow, GridRowSetting } from '@/components/grid/row.js'; import { GridRow } from '@/components/grid/row.js';
import { GridContext } from '@/components/grid/grid-event.js'; import { GridContext } from '@/components/grid/grid-event.js';
import copyToClipboard from '@/scripts/copy-to-clipboard.js'; import copyToClipboard from '@/scripts/copy-to-clipboard.js';
import { GridColumn, GridColumnSetting } from '@/components/grid/column.js'; import { GridColumn, GridColumnSetting } from '@/components/grid/column.js';
export function isCellElement(elem: any): elem is HTMLTableCellElement { export function isCellElement(elem: HTMLElement): boolean {
return elem instanceof HTMLTableCellElement; return elem.hasAttribute('data-grid-cell');
} }
export function isRowElement(elem: any): elem is HTMLTableRowElement { export function isRowElement(elem: HTMLElement): boolean {
return elem instanceof HTMLTableRowElement; return elem.hasAttribute('data-grid-row');
} }
export function calcCellWidth(widthSetting: SizeStyle): string { export function calcCellWidth(widthSetting: SizeStyle): string {
@ -31,29 +31,43 @@ export function calcCellWidth(widthSetting: SizeStyle): string {
} }
} }
export function getCellAddress(elem: HTMLElement, gridSetting: GridRowSetting, parentNodeCount = 10): CellAddress { function getCellRowByAttribute(elem: HTMLElement): number {
let node = elem; const row = elem.getAttribute('data-grid-cell-row');
for (let i = 0; i < parentNodeCount; i++) { if (row === null) {
if (isCellElement(node) && isRowElement(node.parentElement)) { throw new Error('data-grid-cell-row attribute not found');
return { }
// ヘッダ行ぶんを除く return Number(row);
row: node.parentElement.rowIndex - 1,
// 数値列ぶんを除く
col: gridSetting.showNumber ? node.cellIndex - 1 : node.cellIndex,
};
} }
function getCellColByAttribute(elem: HTMLElement): number {
const col = elem.getAttribute('data-grid-cell-col');
if (col === null) {
throw new Error('data-grid-cell-col attribute not found');
}
return Number(col);
}
export function getCellAddress(elem: HTMLElement, parentNodeCount = 10): CellAddress {
let node = elem;
for (let i = 0; i < parentNodeCount; i++) {
if (!node.parentElement) { if (!node.parentElement) {
break; break;
} }
if (isCellElement(node) && isRowElement(node.parentElement)) {
const row = getCellRowByAttribute(node);
const col = getCellColByAttribute(node);
return { row, col };
}
node = node.parentElement; node = node.parentElement;
} }
return CELL_ADDRESS_NONE; return CELL_ADDRESS_NONE;
} }
export function getCellElement(elem: HTMLElement, parentNodeCount = 10): HTMLTableCellElement | null { export function getCellElement(elem: HTMLElement, parentNodeCount = 10): HTMLElement | null {
let node = elem; let node = elem;
for (let i = 0; i < parentNodeCount; i++) { for (let i = 0; i < parentNodeCount; i++) {
if (isCellElement(node)) { if (isCellElement(node)) {