mirror of
https://github.com/BookStackApp/BookStack.git
synced 2026-07-15 21:31:36 +03:00
Lexical: Added missing table header row toggle button
Also updated DOM converstion, and CSS, to make lexical format (th inside tbody) somewhat compatible/convertible with the tinymce format (td inside thead).
This commit is contained in:
1
resources/icons/editor/table-header.svg
Normal file
1
resources/icons/editor/table-header.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200q-33 0-56.5-23.5T120-200m293-240h134v-160H413Zm0 240h134v-160H413ZM200-440h133v-160H200Zm427 0h133v-160H627ZM200-200h133v-160H200Zm427 0h133v-160H627Z"/></svg>
|
||||
|
After Width: | Height: | Size: 327 B |
@@ -334,10 +334,13 @@ export function $convertTableCellNodeElement(
|
||||
width = parseFloat(domNode_.style.width);
|
||||
}
|
||||
|
||||
let isHeader = nodeName === 'th';
|
||||
if (domNode instanceof HTMLElement && domNode.closest('thead')) {
|
||||
isHeader = true;
|
||||
}
|
||||
|
||||
const tableCellNode = $createTableCellNode(
|
||||
nodeName === 'th'
|
||||
? TableCellHeaderStates.ROW
|
||||
: TableCellHeaderStates.NO_STATUS,
|
||||
isHeader ? TableCellHeaderStates.ROW : TableCellHeaderStates.NO_STATUS,
|
||||
domNode_.colSpan,
|
||||
width,
|
||||
);
|
||||
|
||||
@@ -7,6 +7,7 @@ import insertColumnAfterIcon from "@icons/editor/table-insert-column-after.svg";
|
||||
import insertColumnBeforeIcon from "@icons/editor/table-insert-column-before.svg";
|
||||
import insertRowAboveIcon from "@icons/editor/table-insert-row-above.svg";
|
||||
import insertRowBelowIcon from "@icons/editor/table-insert-row-below.svg";
|
||||
import tableHeaderIcon from "@icons/editor/table-header.svg";
|
||||
import {EditorUiContext} from "../../framework/core";
|
||||
import {$getSelection, BaseSelection} from "lexical";
|
||||
import {
|
||||
@@ -14,7 +15,7 @@ import {
|
||||
$deleteTableRow__EXPERIMENTAL,
|
||||
$insertTableColumn__EXPERIMENTAL,
|
||||
$insertTableRow__EXPERIMENTAL, $isTableCellNode,
|
||||
$isTableNode, $isTableRowNode, $isTableSelection, $unmergeCell, TableCellNode,
|
||||
$isTableNode, $isTableRowNode, $isTableSelection, $unmergeCell, TableCellHeaderStates, TableCellNode,
|
||||
} from "@lexical/table";
|
||||
import {$getNodeFromSelection, $selectionContainsNodeType} from "../../../utils/selection";
|
||||
import {$getParentOfType} from "../../../utils/nodes";
|
||||
@@ -23,7 +24,7 @@ import {
|
||||
$clearTableFormatting,
|
||||
$clearTableSizes, $getTableFromSelection,
|
||||
$getTableRowsFromSelection,
|
||||
$mergeTableCellsInSelection
|
||||
$mergeTableCellsInSelection, $toggleRowCellHeaderState
|
||||
} from "../../../utils/tables";
|
||||
import {
|
||||
$copySelectedColumnsToClipboard,
|
||||
@@ -239,6 +240,28 @@ export const pasteRowAfter: EditorButtonDefinition = {
|
||||
isDisabled: (selection) => cellNotSelected(selection) || isRowClipboardEmpty(),
|
||||
};
|
||||
|
||||
export const toggleRowHeaders: EditorButtonDefinition = {
|
||||
label: 'Row header',
|
||||
format: 'small',
|
||||
icon: tableHeaderIcon,
|
||||
action(context: EditorUiContext, button) {
|
||||
context.editor.update(() => {
|
||||
const row = $getNodeFromSelection($getSelection(), $isTableCellNode)?.getParent();
|
||||
if (!$isTableRowNode(row)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isNowHeader = $toggleRowCellHeaderState(row);
|
||||
button.setActiveState(isNowHeader);
|
||||
});
|
||||
},
|
||||
isActive: (selection) => {
|
||||
return $selectionContainsNodeType(selection, (node) => {
|
||||
return $isTableCellNode(node) && node.getHeaderStyles() !== TableCellHeaderStates.NO_STATUS;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const cutColumn: EditorButtonDefinition = {
|
||||
label: 'Cut column',
|
||||
format: 'long',
|
||||
|
||||
@@ -28,7 +28,7 @@ import {
|
||||
pasteRowBefore, resizeTableToContents,
|
||||
rowProperties,
|
||||
splitCell,
|
||||
table, tableProperties
|
||||
table, tableProperties, toggleRowHeaders
|
||||
} from "./buttons/tables";
|
||||
import {about, fullscreen, redo, source, undo} from "./buttons/controls";
|
||||
import {
|
||||
@@ -284,6 +284,19 @@ export const contextToolbars: Record<string, EditorContextToolbarDefinition> = {
|
||||
return originalTarget.closest('table') as HTMLTableElement;
|
||||
}
|
||||
},
|
||||
table_header: {
|
||||
selector: 'table tr:first-of-type td, table tr:first-of-type th',
|
||||
content() {
|
||||
return [
|
||||
new EditorOverflowContainer('table_headers', 1, [
|
||||
new EditorButton(toggleRowHeaders),
|
||||
]),
|
||||
];
|
||||
},
|
||||
displayTargetLocator(originalTarget: HTMLElement): HTMLElement {
|
||||
return originalTarget.closest('table') as HTMLTableElement;
|
||||
}
|
||||
},
|
||||
details: {
|
||||
selector: 'details',
|
||||
content() {
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
$isTableCellNode,
|
||||
$isTableNode,
|
||||
$isTableRowNode,
|
||||
$isTableSelection, TableCellNode, TableNode,
|
||||
$isTableSelection, TableCellHeaderStates, TableCellNode, TableNode,
|
||||
TableRowNode,
|
||||
TableSelection,
|
||||
} from "@lexical/table";
|
||||
@@ -328,9 +328,21 @@ export function $getCellPaddingForTable(table: TableNode): string {
|
||||
return padding || '';
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Toggle the header state of the cells in the provided row.
|
||||
* Returns a boolean to indicate if the new state of the cells is as headers.
|
||||
*/
|
||||
export function $toggleRowCellHeaderState(row: TableRowNode): boolean {
|
||||
const firstCell = row.getFirstChild();
|
||||
const isHeader = $isTableCellNode(firstCell) ? firstCell.getHeaderStyles() !== TableCellHeaderStates.NO_STATUS : false;
|
||||
const cells = row.getChildren();
|
||||
for (const cell of cells) {
|
||||
if ($isTableCellNode(cell)) {
|
||||
cell.setHeaderStyles(isHeader ? TableCellHeaderStates.NO_STATUS : TableCellHeaderStates.ROW);
|
||||
}
|
||||
}
|
||||
return !isHeader;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -4,10 +4,6 @@
|
||||
table {
|
||||
min-width: 100px;
|
||||
max-width: 100%;
|
||||
thead {
|
||||
@include mixins.lightDark(background-color, #f8f8f8, #333);
|
||||
font-weight: 500;
|
||||
}
|
||||
td, th {
|
||||
min-width: 10px;
|
||||
padding: 6px 8px;
|
||||
@@ -22,6 +18,15 @@ table {
|
||||
}
|
||||
}
|
||||
|
||||
// Table Header styles.
|
||||
// Initial selector for in-body th cells, intended to (somewhat) not conflict with
|
||||
// previous approach (second selector) to table headers where
|
||||
// we would target the thead specifically.
|
||||
table:not(:has(thead)) th, table thead {
|
||||
@include mixins.lightDark(background-color, #f8f8f8, #333);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
table.table {
|
||||
width: 100%;
|
||||
tr td, tr th {
|
||||
|
||||
Reference in New Issue
Block a user