mirror of https://github.com/fantasticit/think.git
improve table cell
parent
922ecdf98f
commit
c6abfab7c8
|
@ -1,13 +1,18 @@
|
||||||
|
import { IconPlus } from '@douyinfe/semi-icons';
|
||||||
import { mergeAttributes, Node } from '@tiptap/core';
|
import { mergeAttributes, Node } from '@tiptap/core';
|
||||||
import { Plugin } from 'prosemirror-state';
|
import { Tooltip } from 'components/tooltip';
|
||||||
|
import { Plugin, PluginKey } from 'prosemirror-state';
|
||||||
|
import { addRowAfter } from 'prosemirror-tables';
|
||||||
import { Decoration, DecorationSet } from 'prosemirror-view';
|
import { Decoration, DecorationSet } from 'prosemirror-view';
|
||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
import { getCellsInColumn, isRowSelected, isTableSelected, selectRow, selectTable } from 'tiptap/prose-utils';
|
import { getCellsInColumn, isRowSelected, isTableSelected, selectRow, selectTable } from 'tiptap/prose-utils';
|
||||||
|
|
||||||
export interface TableCellOptions {
|
export interface TableCellOptions {
|
||||||
HTMLAttributes: Record<string, any>;
|
HTMLAttributes: Record<string, any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TableCell = Node.create<TableCellOptions>({
|
export const TableCell = Node.create<TableCellOptions, { clearCallbacks: Array<() => void> }>({
|
||||||
name: 'tableCell',
|
name: 'tableCell',
|
||||||
content: 'block+',
|
content: 'block+',
|
||||||
tableRole: 'cell',
|
tableRole: 'cell',
|
||||||
|
@ -19,14 +24,6 @@ export const TableCell = Node.create<TableCellOptions>({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
parseHTML() {
|
|
||||||
return [{ tag: 'td' }];
|
|
||||||
},
|
|
||||||
|
|
||||||
renderHTML({ HTMLAttributes }) {
|
|
||||||
return ['td', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];
|
|
||||||
},
|
|
||||||
|
|
||||||
addAttributes() {
|
addAttributes() {
|
||||||
return {
|
return {
|
||||||
colspan: {
|
colspan: {
|
||||||
|
@ -46,7 +43,7 @@ export const TableCell = Node.create<TableCellOptions>({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
colwidth: {
|
colwidth: {
|
||||||
default: [150],
|
default: [100],
|
||||||
parseHTML: (element) => {
|
parseHTML: (element) => {
|
||||||
const colwidth = element.getAttribute('colwidth');
|
const colwidth = element.getAttribute('colwidth');
|
||||||
const value = colwidth ? [parseInt(colwidth, 10)] : null;
|
const value = colwidth ? [parseInt(colwidth, 10)] : null;
|
||||||
|
@ -59,22 +56,44 @@ export const TableCell = Node.create<TableCellOptions>({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
parseHTML() {
|
||||||
|
return [{ tag: 'td' }];
|
||||||
|
},
|
||||||
|
|
||||||
|
renderHTML({ HTMLAttributes }) {
|
||||||
|
return ['td', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];
|
||||||
|
},
|
||||||
|
|
||||||
|
addStorage() {
|
||||||
|
return {
|
||||||
|
clearCallbacks: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
onDestroy() {
|
||||||
|
this.storage.clearCallbacks.forEach((cb) => cb());
|
||||||
|
this.storage.clearCallbacks.length = 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
addProseMirrorPlugins() {
|
addProseMirrorPlugins() {
|
||||||
const { isEditable } = this.editor;
|
const { isEditable } = this.editor;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
new Plugin({
|
new Plugin({
|
||||||
|
key: new PluginKey('table-cell-control'),
|
||||||
props: {
|
props: {
|
||||||
decorations: (state) => {
|
decorations: (state) => {
|
||||||
if (!isEditable) {
|
if (!isEditable) {
|
||||||
return DecorationSet.empty;
|
return DecorationSet.empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { doc, selection } = state;
|
const { doc, selection } = state;
|
||||||
const decorations: Decoration[] = [];
|
const decorations: Decoration[] = [];
|
||||||
const cells = getCellsInColumn(0)(selection);
|
const cells = getCellsInColumn(0)(selection);
|
||||||
|
|
||||||
if (cells) {
|
if (cells) {
|
||||||
|
this.storage.clearCallbacks.forEach((cb) => cb());
|
||||||
|
this.storage.clearCallbacks.length = 0;
|
||||||
|
|
||||||
cells.forEach(({ pos }, index) => {
|
cells.forEach(({ pos }, index) => {
|
||||||
if (index === 0) {
|
if (index === 0) {
|
||||||
decorations.push(
|
decorations.push(
|
||||||
|
@ -89,8 +108,10 @@ export const TableCell = Node.create<TableCellOptions>({
|
||||||
grip.addEventListener('mousedown', (event) => {
|
grip.addEventListener('mousedown', (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopImmediatePropagation();
|
event.stopImmediatePropagation();
|
||||||
this.editor.view.dispatch(selectTable(this.editor.state.tr));
|
this.editor.view.dispatch(
|
||||||
// this.options.onSelectTable(state);
|
// @ts-ignore
|
||||||
|
selectTable(this.editor.state.tr)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
return grip;
|
return grip;
|
||||||
})
|
})
|
||||||
|
@ -99,7 +120,6 @@ export const TableCell = Node.create<TableCellOptions>({
|
||||||
decorations.push(
|
decorations.push(
|
||||||
Decoration.widget(pos + 1, () => {
|
Decoration.widget(pos + 1, () => {
|
||||||
const rowSelected = isRowSelected(index)(selection);
|
const rowSelected = isRowSelected(index)(selection);
|
||||||
|
|
||||||
let className = 'grip-row';
|
let className = 'grip-row';
|
||||||
if (rowSelected) {
|
if (rowSelected) {
|
||||||
className += ' selected';
|
className += ' selected';
|
||||||
|
@ -111,18 +131,41 @@ export const TableCell = Node.create<TableCellOptions>({
|
||||||
className += ' last';
|
className += ' last';
|
||||||
}
|
}
|
||||||
const grip = document.createElement('a');
|
const grip = document.createElement('a');
|
||||||
grip.className = className;
|
|
||||||
grip.addEventListener('mousedown', (event) => {
|
ReactDOM.render(
|
||||||
event.preventDefault();
|
<Tooltip content="向后增加一行">
|
||||||
event.stopImmediatePropagation();
|
<IconPlus />
|
||||||
this.editor.view.dispatch(selectRow(index)(this.editor.state.tr));
|
</Tooltip>,
|
||||||
|
grip
|
||||||
|
);
|
||||||
|
|
||||||
|
this.storage.clearCallbacks.push(() => {
|
||||||
|
ReactDOM.unmountComponentAtNode(grip);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
grip.className = className;
|
||||||
|
grip.addEventListener(
|
||||||
|
'mousedown',
|
||||||
|
(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopImmediatePropagation();
|
||||||
|
|
||||||
|
this.editor.view.dispatch(
|
||||||
|
// @ts-ignore
|
||||||
|
selectRow(index)(this.editor.state.tr)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (event.target !== grip) {
|
||||||
|
addRowAfter(this.editor.state, this.editor.view.dispatch);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
return grip;
|
return grip;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return DecorationSet.create(doc, decorations);
|
return DecorationSet.create(doc, decorations);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,9 +1,29 @@
|
||||||
import { TableHeader as BuiltInTableHeader } from '@tiptap/extension-table-header';
|
import { IconPlus } from '@douyinfe/semi-icons';
|
||||||
import { Plugin } from 'prosemirror-state';
|
import { mergeAttributes, Node } from '@tiptap/core';
|
||||||
|
import { Tooltip } from 'components/tooltip';
|
||||||
|
import { Plugin, PluginKey } from 'prosemirror-state';
|
||||||
|
import { addColumnAfter } from 'prosemirror-tables';
|
||||||
import { Decoration, DecorationSet } from 'prosemirror-view';
|
import { Decoration, DecorationSet } from 'prosemirror-view';
|
||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
import { getCellsInRow, isColumnSelected, selectColumn } from 'tiptap/prose-utils';
|
import { getCellsInRow, isColumnSelected, selectColumn } from 'tiptap/prose-utils';
|
||||||
|
|
||||||
export const TableHeader = BuiltInTableHeader.extend({
|
export interface TableHeaderOptions {
|
||||||
|
HTMLAttributes: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TableHeader = Node.create<TableHeaderOptions, { clearCallbacks: Array<() => void> }>({
|
||||||
|
name: 'tableHeader',
|
||||||
|
content: 'block+',
|
||||||
|
tableRole: 'header_cell',
|
||||||
|
isolating: true,
|
||||||
|
|
||||||
|
addOptions() {
|
||||||
|
return {
|
||||||
|
HTMLAttributes: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
addAttributes() {
|
addAttributes() {
|
||||||
return {
|
return {
|
||||||
colspan: {
|
colspan: {
|
||||||
|
@ -13,10 +33,10 @@ export const TableHeader = BuiltInTableHeader.extend({
|
||||||
default: 1,
|
default: 1,
|
||||||
},
|
},
|
||||||
colwidth: {
|
colwidth: {
|
||||||
default: [150],
|
default: [100],
|
||||||
parseHTML: (element) => {
|
parseHTML: (element) => {
|
||||||
const colwidth = element.getAttribute('colwidth');
|
const colwidth = element.getAttribute('colwidth');
|
||||||
const value = colwidth ? colwidth.split(',').map((item) => parseInt(item, 10)) : null;
|
const value = colwidth ? [parseInt(colwidth, 10)] : null;
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
},
|
},
|
||||||
|
@ -27,22 +47,44 @@ export const TableHeader = BuiltInTableHeader.extend({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
parseHTML() {
|
||||||
|
return [{ tag: 'th' }];
|
||||||
|
},
|
||||||
|
|
||||||
|
renderHTML({ HTMLAttributes }) {
|
||||||
|
return ['th', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];
|
||||||
|
},
|
||||||
|
|
||||||
|
addStorage() {
|
||||||
|
return {
|
||||||
|
clearCallbacks: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
onDestroy() {
|
||||||
|
this.storage.clearCallbacks.forEach((cb) => cb());
|
||||||
|
this.storage.clearCallbacks.length = 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
addProseMirrorPlugins() {
|
addProseMirrorPlugins() {
|
||||||
const { isEditable } = this.editor;
|
const { isEditable } = this.editor;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
new Plugin({
|
new Plugin({
|
||||||
|
key: new PluginKey('table-header-control'),
|
||||||
props: {
|
props: {
|
||||||
decorations: (state) => {
|
decorations: (state) => {
|
||||||
if (!isEditable) {
|
if (!isEditable) {
|
||||||
return DecorationSet.empty;
|
return DecorationSet.empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { doc, selection } = state;
|
const { doc, selection } = state;
|
||||||
const decorations: Decoration[] = [];
|
const decorations: Decoration[] = [];
|
||||||
const cells = getCellsInRow(0)(selection);
|
const cells = getCellsInRow(0)(selection);
|
||||||
|
|
||||||
if (cells) {
|
if (cells) {
|
||||||
|
this.storage.clearCallbacks.forEach((cb) => cb());
|
||||||
|
this.storage.clearCallbacks.length = 0;
|
||||||
|
|
||||||
cells.forEach(({ pos }, index) => {
|
cells.forEach(({ pos }, index) => {
|
||||||
decorations.push(
|
decorations.push(
|
||||||
Decoration.widget(pos + 1, () => {
|
Decoration.widget(pos + 1, () => {
|
||||||
|
@ -58,17 +100,33 @@ export const TableHeader = BuiltInTableHeader.extend({
|
||||||
}
|
}
|
||||||
const grip = document.createElement('a');
|
const grip = document.createElement('a');
|
||||||
grip.className = className;
|
grip.className = className;
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<Tooltip content="向后增加一列">
|
||||||
|
<IconPlus />
|
||||||
|
</Tooltip>,
|
||||||
|
grip
|
||||||
|
);
|
||||||
|
|
||||||
|
this.storage.clearCallbacks.push(() => {
|
||||||
|
ReactDOM.unmountComponentAtNode(grip);
|
||||||
|
});
|
||||||
|
|
||||||
grip.addEventListener('mousedown', (event) => {
|
grip.addEventListener('mousedown', (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopImmediatePropagation();
|
event.stopImmediatePropagation();
|
||||||
|
|
||||||
this.editor.view.dispatch(selectColumn(index)(this.editor.state.tr));
|
this.editor.view.dispatch(selectColumn(index)(this.editor.state.tr));
|
||||||
|
|
||||||
|
if (event.target !== grip) {
|
||||||
|
addColumnAfter(this.editor.state, this.editor.view.dispatch);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return grip;
|
return grip;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return DecorationSet.create(doc, decorations);
|
return DecorationSet.create(doc, decorations);
|
||||||
},
|
},
|
||||||
},
|
},
|
|
@ -1,5 +1,7 @@
|
||||||
import BuiltInTable from '@tiptap/extension-table';
|
import BuiltInTable from '@tiptap/extension-table';
|
||||||
import { Node as ProseMirrorNode } from 'prosemirror-model';
|
import { Node as ProseMirrorNode } from 'prosemirror-model';
|
||||||
|
import { Plugin, PluginKey } from 'prosemirror-state';
|
||||||
|
import { tableNodeTypes } from 'prosemirror-tables';
|
||||||
import { NodeView } from 'prosemirror-view';
|
import { NodeView } from 'prosemirror-view';
|
||||||
|
|
||||||
function updateColumns(
|
function updateColumns(
|
||||||
|
@ -105,6 +107,26 @@ class TableView implements NodeView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function readonlyTableView({ cellMinWidth = 25, View = TableView } = {}) {
|
||||||
|
const plugin = new Plugin({
|
||||||
|
key: new PluginKey('readonlyTableView'),
|
||||||
|
state: {
|
||||||
|
init(_, state) {
|
||||||
|
this.spec.props.nodeViews[tableNodeTypes(state.schema).table.name] = (node, view) =>
|
||||||
|
new View(node, cellMinWidth);
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
apply(tr, prev) {
|
||||||
|
return prev;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
nodeViews: {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return plugin;
|
||||||
|
}
|
||||||
|
|
||||||
export const Table = BuiltInTable.extend({
|
export const Table = BuiltInTable.extend({
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
addOptions() {
|
addOptions() {
|
||||||
|
@ -118,4 +140,8 @@ export const Table = BuiltInTable.extend({
|
||||||
allowTableNodeSelection: false,
|
allowTableNodeSelection: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
addProseMirrorPlugins() {
|
||||||
|
return [...this.parent(), !this.editor.isEditable && readonlyTableView()].filter(Boolean);
|
||||||
|
},
|
||||||
}).configure({ resizable: true });
|
}).configure({ resizable: true });
|
||||||
|
|
|
@ -25,13 +25,14 @@ export const TableBubbleMenu = ({ editor }) => {
|
||||||
const shouldShow = useCallback(() => {
|
const shouldShow = useCallback(() => {
|
||||||
return editor.isActive(Table.name);
|
return editor.isActive(Table.name);
|
||||||
}, [editor]);
|
}, [editor]);
|
||||||
|
|
||||||
const getRenderContainer = useCallback((node) => {
|
const getRenderContainer = useCallback((node) => {
|
||||||
let container = node;
|
let container = node;
|
||||||
// 文本节点
|
// 文本节点
|
||||||
if (container && !container.tag) {
|
if (container && !container.tag) {
|
||||||
container = node.parentElement;
|
container = node.parentElement;
|
||||||
}
|
}
|
||||||
while (container && container.tagName !== 'TABLE') {
|
while (container && !container.classList.contains('tableWrapper')) {
|
||||||
container = container.parentElement;
|
container = container.parentElement;
|
||||||
}
|
}
|
||||||
return container;
|
return container;
|
||||||
|
@ -40,6 +41,7 @@ export const TableBubbleMenu = ({ editor }) => {
|
||||||
const deleteMe = useCallback(() => {
|
const deleteMe = useCallback(() => {
|
||||||
deleteNode(Table.name, editor);
|
deleteNode(Table.name, editor);
|
||||||
}, [editor]);
|
}, [editor]);
|
||||||
|
|
||||||
const addColumnBefore = useCallback(() => editor.chain().focus().addColumnBefore().run(), [editor]);
|
const addColumnBefore = useCallback(() => editor.chain().focus().addColumnBefore().run(), [editor]);
|
||||||
const addColumnAfter = useCallback(() => editor.chain().focus().addColumnAfter().run(), [editor]);
|
const addColumnAfter = useCallback(() => editor.chain().focus().addColumnAfter().run(), [editor]);
|
||||||
const deleteColumn = useCallback(() => editor.chain().focus().deleteColumn().run(), [editor]);
|
const deleteColumn = useCallback(() => editor.chain().focus().deleteColumn().run(), [editor]);
|
||||||
|
@ -59,7 +61,6 @@ export const TableBubbleMenu = ({ editor }) => {
|
||||||
pluginKey="table-bubble-menu"
|
pluginKey="table-bubble-menu"
|
||||||
tippyOptions={{
|
tippyOptions={{
|
||||||
maxWidth: 'calc(100vw - 100px)',
|
maxWidth: 'calc(100vw - 100px)',
|
||||||
placement: 'bottom',
|
|
||||||
}}
|
}}
|
||||||
shouldShow={shouldShow}
|
shouldShow={shouldShow}
|
||||||
getRenderContainer={getRenderContainer}
|
getRenderContainer={getRenderContainer}
|
||||||
|
|
|
@ -9,8 +9,8 @@ export const Table: React.FC<{ editor: Editor }> = ({ editor }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TableBubbleMenu editor={editor} />
|
<TableBubbleMenu editor={editor} />
|
||||||
<TableRowBubbleMenu editor={editor} />
|
{/* <TableRowBubbleMenu editor={editor} /> */}
|
||||||
<TableColBubbleMenu editor={editor} />
|
{/* <TableColBubbleMenu editor={editor} /> */}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,160 +1,282 @@
|
||||||
.ProseMirror {
|
/* stylelint-disable */
|
||||||
.node-table {
|
$tableBorderColor: var(--semi-color-border);
|
||||||
position: relative;
|
$tableHeaderBgColor: var(--semi-color-fill-0);
|
||||||
margin-top: 0.75em;
|
$tableSelectedBorderColor: rgb(0 101 255);
|
||||||
scrollbar-width: thin;
|
$tableSelectedCellBgColor: transparent;
|
||||||
scrollbar-color: transparent transparent;
|
$tableSelectedControlBgColor: #2584ff;
|
||||||
}
|
$tableResizeHandleBgColor: #adf;
|
||||||
|
|
||||||
.scrollable {
|
.tableWrapper {
|
||||||
padding-left: 1em;
|
position: relative;
|
||||||
margin-left: -1em;
|
margin: 0.5em 0px;
|
||||||
overflow: auto hidden;
|
|
||||||
border-left: 1px solid transparent;
|
|
||||||
border-right: 1px solid transparent;
|
|
||||||
transition: border 250ms ease-in-out 0s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scrollable-shadow {
|
&.has-focus {
|
||||||
position: absolute;
|
.scrollWrapper {
|
||||||
top: 0;
|
margin-top: -20px;
|
||||||
bottom: 0;
|
|
||||||
left: -1em;
|
|
||||||
width: 16px;
|
|
||||||
transition: box-shadow 250ms ease-in-out 0s;
|
|
||||||
border-width: 0 0 0 1em;
|
|
||||||
border-style: solid;
|
|
||||||
border-color: transparent;
|
|
||||||
border-image: initial;
|
|
||||||
pointer-events: none;
|
|
||||||
|
|
||||||
&.left {
|
|
||||||
box-shadow: 16px 0 16px -16px inset rgb(0 0 0 / 25%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.right {
|
|
||||||
right: 0;
|
|
||||||
left: auto;
|
|
||||||
box-shadow: rgb(0 0 0 / 25%) -16px 0 16px -16px inset;
|
|
||||||
|
|
||||||
&.is-editable {
|
|
||||||
&::after {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
width: 1em;
|
|
||||||
height: 1em;
|
|
||||||
background-color: var(--semi-color-nav-bg);
|
|
||||||
content: '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
table {
|
.scrollWrapper {
|
||||||
width: 100%;
|
overflow-y: hidden;
|
||||||
margin-top: 1em;
|
overflow-x: auto;
|
||||||
border-radius: 4px;
|
padding-left: 28px;
|
||||||
border-collapse: collapse;
|
padding-top: 28px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
margin-left: -28px;
|
||||||
|
margin-top: -20px;
|
||||||
|
margin-bottom: -8px;
|
||||||
|
border-left: 1px solid transparent;
|
||||||
|
border-right: 1px solid transparent;
|
||||||
|
-webkit-transition: border 250ms ease-in-out 0s;
|
||||||
|
transition: border 250ms ease-in-out 0s;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-color: var(--semi-color-fill-2);
|
}
|
||||||
|
|
||||||
&.is-readonly {
|
tr {
|
||||||
margin-top: 0;
|
position: relative;
|
||||||
}
|
border-bottom: 1px solid $tableBorderColor;
|
||||||
|
}
|
||||||
|
|
||||||
td,
|
th {
|
||||||
th {
|
background: $tableHeaderBgColor;
|
||||||
position: relative;
|
}
|
||||||
min-width: 100px;
|
|
||||||
padding: 4px 8px;
|
|
||||||
text-align: left;
|
|
||||||
vertical-align: top;
|
|
||||||
border: 1px solid rgb(232 235 237);
|
|
||||||
border-color: var(--semi-color-fill-2);
|
|
||||||
|
|
||||||
:not(a) {
|
td,
|
||||||
&:first-of-type {
|
th {
|
||||||
margin-top: 0;
|
position: relative;
|
||||||
}
|
vertical-align: top;
|
||||||
}
|
border: 1px solid $tableBorderColor;
|
||||||
}
|
position: relative;
|
||||||
|
padding: 4px 8px;
|
||||||
|
text-align: left;
|
||||||
|
min-width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
th {
|
.selectedCell {
|
||||||
font-weight: bold;
|
position: relative;
|
||||||
background-color: var(--semi-color-fill-0);
|
border: 1px solid $tableSelectedBorderColor;
|
||||||
}
|
background-color: $tableSelectedCellBgColor;
|
||||||
|
|
||||||
.selectedCell {
|
&::after {
|
||||||
border-style: double;
|
box-sizing: content-box;
|
||||||
border-color: rgb(0 101 255);
|
|
||||||
background: var(--semi-color-info-light-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
.grip-column {
|
|
||||||
position: absolute;
|
|
||||||
top: -1em;
|
|
||||||
left: 0;
|
|
||||||
z-index: 10;
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
height: 0.7em;
|
|
||||||
margin-bottom: 3px;
|
|
||||||
cursor: pointer;
|
|
||||||
background: #ced4da;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&.selected {
|
|
||||||
background: var(--semi-color-info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.grip-row {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: -1em;
|
|
||||||
z-index: 10;
|
|
||||||
display: block;
|
|
||||||
width: 0.7em;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin-right: 3px;
|
width: 100%;
|
||||||
cursor: pointer;
|
border: 1px solid $tableSelectedBorderColor;
|
||||||
background: #ced4da;
|
content: '';
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&.selected {
|
|
||||||
background: var(--semi-color-info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.grip-table {
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -1em;
|
left: -1px;
|
||||||
left: -1em;
|
top: -1px;
|
||||||
z-index: 10;
|
bottom: 0px;
|
||||||
display: block;
|
z-index: 12;
|
||||||
width: 0.8em;
|
display: inline-block;
|
||||||
height: 0.8em;
|
pointer-events: none;
|
||||||
cursor: pointer;
|
}
|
||||||
background: #ced4da;
|
}
|
||||||
border-radius: 50%;
|
|
||||||
|
|
||||||
&:hover,
|
.grip-column {
|
||||||
&.selected {
|
position: absolute;
|
||||||
background: var(--semi-color-info);
|
top: -12px;
|
||||||
|
left: -1px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
> span {
|
||||||
|
position: absolute;
|
||||||
|
top: -18px;
|
||||||
|
left: 100%;
|
||||||
|
transform: translateX(-8px);
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
|
||||||
|
font-size: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.semi-icon-default {
|
||||||
|
font-size: inherit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.column-resize-handle {
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 100%;
|
||||||
|
bottom: 4px;
|
||||||
|
transform: translateX(-1px);
|
||||||
|
|
||||||
|
width: 4px;
|
||||||
|
height: 4px;
|
||||||
|
background-color: $tableBorderColor;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
box-sizing: content-box;
|
||||||
|
content: '';
|
||||||
|
cursor: pointer;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: -2px;
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 10px;
|
||||||
|
background: $tableHeaderBgColor;
|
||||||
|
border: 1px solid $tableBorderColor;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $tableSelectedBorderColor;
|
||||||
|
|
||||||
|
> span {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
background: $tableSelectedControlBgColor;
|
||||||
|
border-color: $tableSelectedControlBgColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.last::after {
|
||||||
|
border-top-right-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected::after {
|
||||||
|
background: $tableSelectedControlBgColor;
|
||||||
|
border-color: $tableSelectedControlBgColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.grip-row {
|
||||||
|
position: absolute;
|
||||||
|
left: -12px;
|
||||||
|
top: -1px;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
> span {
|
||||||
|
transform: translateY(8px);
|
||||||
|
position: absolute;
|
||||||
|
left: -16px;
|
||||||
|
bottom: 4px;
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
|
||||||
|
font-size: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.semi-icon-default {
|
||||||
|
font-size: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: -10px;
|
||||||
bottom: -2px;
|
bottom: -2px;
|
||||||
width: 4px;
|
width: 4px;
|
||||||
pointer-events: none;
|
height: 4px;
|
||||||
background-color: #adf;
|
background-color: $tableBorderColor;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
box-sizing: content-box;
|
||||||
|
content: '';
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 10px;
|
||||||
|
background: $tableHeaderBgColor;
|
||||||
|
border: 1px solid $tableBorderColor;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $tableSelectedBorderColor;
|
||||||
|
|
||||||
|
> span {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
background: $tableSelectedControlBgColor;
|
||||||
|
border-color: $tableSelectedBorderColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.last::after {
|
||||||
|
border-bottom-left-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected::after {
|
||||||
|
background: $tableSelectedControlBgColor;
|
||||||
|
border-color: $tableSelectedBorderColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.grip-table {
|
||||||
|
&::after {
|
||||||
|
box-sizing: content-box;
|
||||||
|
content: '';
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
top: -12px;
|
||||||
|
left: -12px;
|
||||||
|
display: block;
|
||||||
|
background: $tableHeaderBgColor;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border: 1px solid $tableBorderColor;
|
||||||
|
border-top-left-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover::after {
|
||||||
|
background: $tableSelectedControlBgColor;
|
||||||
|
border-color: $tableSelectedBorderColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected::after {
|
||||||
|
background: $tableSelectedControlBgColor;
|
||||||
|
border-color: $tableSelectedBorderColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-resize-handle {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: -2px;
|
||||||
|
bottom: -2px;
|
||||||
|
width: 4px;
|
||||||
|
pointer-events: none;
|
||||||
|
background-color: $tableResizeHandleBgColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
.resize-cursor {
|
.resize-cursor {
|
||||||
|
|
Loading…
Reference in New Issue