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>
<td
<div
ref="rootEl"
class="mk_grid_td"
:class="$style.cell"
:style="{ maxWidth: cellWidth, minWidth: cellWidth }"
:tabindex="-1"
data-grid-cell
:data-grid-cell-row="cell.row.index"
:data-grid-cell-col="cell.column.index"
@keydown="onCellKeyDown"
@dblclick.prevent="onCellDoubleClick"
>
@ -77,7 +81,7 @@ SPDX-License-Identifier: AGPL-3.0-only
/>
</div>
</div>
</td>
</div>
</template>
<script setup lang="ts">
@ -143,7 +147,7 @@ function onCellDoubleClick(ev: MouseEvent) {
function onOutsideMouseDown(ev: MouseEvent) {
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);
}
}
@ -352,9 +356,9 @@ $cellHeight: 28px;
width: 100%;
max-width: 100%;
box-sizing: border-box;
min-height: $cellHeight;
max-height: $cellHeight;
height: $cellHeight + 4px;
min-height: $cellHeight - 2;
max-height: $cellHeight - 2;
height: $cellHeight - 2;
outline: none;
border: none;
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>
<tr
<div
class="mk_grid_tr"
:class="[
$style.row,
row.ranged ? $style.ranged : {},
@ -13,6 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:style="[
...(row.additionalStyles ?? []).map(it => it.style ?? {}),
]"
:data-grid-row="row.index"
>
<MkNumberCell
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:contentSize="(sender, newSize) => emit('change:contentSize', sender, newSize)"
/>
</tr>
</div>
</template>
<script setup lang="ts">
@ -58,6 +60,10 @@ defineProps<{
<style module lang="scss">
.row {
display: flex;
flex-direction: row;
align-items: center;
&.ranged {
background-color: var(--accentedBg);
}

View File

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

View File

@ -4,16 +4,20 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<th
<div
ref="rootEl"
class="mk_grid_th"
:class="$style.cell"
: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.left"/>
<div :class="$style.wrapper">
<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>
</div>
</div>
@ -23,7 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only
@dblclick="onHandleDoubleClick"
/>
</div>
</th>
</div>
</template>
<script setup lang="ts">
@ -161,6 +165,7 @@ onUnmounted(() => {
<style module lang="scss">
$handleWidth: 5px;
$cellHeight: 28px;
.cell {
cursor: pointer;
@ -169,7 +174,9 @@ $handleWidth: 5px;
.root {
display: flex;
flex-direction: row;
height: 100%;
height: $cellHeight;
max-height: $cellHeight;
min-height: $cellHeight;
.wrapper {
flex: 1;

View File

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

View File

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