Skip to content

Commit

Permalink
Mock up horizontal table scroll implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
etrepum committed Nov 5, 2024
1 parent f9b537a commit 629d934
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 13 deletions.
2 changes: 2 additions & 0 deletions packages/lexical-playground/src/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export default function Editor(): JSX.Element {
shouldPreserveNewLinesInMarkdown,
tableCellMerge,
tableCellBackgroundColor,
tableHorizontalScroll,
},
} = useSettings();
const isEditable = useLexicalEditable();
Expand Down Expand Up @@ -182,6 +183,7 @@ export default function Editor(): JSX.Element {
<TablePlugin
hasCellMerge={tableCellMerge}
hasCellBackgroundColor={tableCellBackgroundColor}
hasHorizontalScroll={tableHorizontalScroll}
/>
<TableCellResizer />
<ImagesPlugin />
Expand Down
8 changes: 8 additions & 0 deletions packages/lexical-playground/src/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export default function Settings(): JSX.Element {
showTableOfContents,
shouldUseLexicalContextMenu,
shouldPreserveNewLinesInMarkdown,
tableHorizontalScroll,
},
} = useSettings();
useEffect(() => {
Expand Down Expand Up @@ -167,6 +168,13 @@ export default function Settings(): JSX.Element {
checked={shouldPreserveNewLinesInMarkdown}
text="Preserve newlines in Markdown"
/>
<Switch
onClick={() => {
setOption('tableHorizontalScroll', !tableHorizontalScroll);
}}
checked={tableHorizontalScroll}
text="Tables have horizontal scroll"
/>
</div>
) : null}
</>
Expand Down
1 change: 1 addition & 0 deletions packages/lexical-playground/src/appSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const DEFAULT_SETTINGS = {
showTreeView: true,
tableCellBackgroundColor: true,
tableCellMerge: true,
tableHorizontalScroll: false,
} as const;

// These are mutated in setupEnv
Expand Down
3 changes: 2 additions & 1 deletion packages/lexical-playground/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -74,17 +74,18 @@ header h1 {

.editor-scroller {
min-height: 150px;
max-width: 100%;
border: 0;
display: flex;
position: relative;
outline: 0;
z-index: 0;
overflow: auto;
resize: vertical;
}

.editor {
flex: auto;
max-width: 100%;
position: relative;
resize: vertical;
z-index: -1;
Expand Down
7 changes: 7 additions & 0 deletions packages/lexical-react/src/LexicalTablePlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
$isTableRowNode,
applyTableHandlers,
INSERT_TABLE_COMMAND,
setScrollableTablesActive,
TableCellNode,
TableNode,
TableRowNode,
Expand All @@ -47,13 +48,19 @@ export function TablePlugin({
hasCellMerge = true,
hasCellBackgroundColor = true,
hasTabHandler = true,
hasHorizontalScroll = false,
}: {
hasCellMerge?: boolean;
hasCellBackgroundColor?: boolean;
hasTabHandler?: boolean;
hasHorizontalScroll?: boolean;
}): JSX.Element | null {
const [editor] = useLexicalComposerContext();

useEffect(() => {
setScrollableTablesActive(editor, hasHorizontalScroll);
}, [editor, hasHorizontalScroll]);

useEffect(() => {
if (!editor.hasNodes([TableNode, TableCellNode, TableRowNode])) {
invariant(
Expand Down
68 changes: 56 additions & 12 deletions packages/lexical-table/src/LexicalTableNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,27 @@
*
*/

import type {
DOMConversionMap,
DOMConversionOutput,
DOMExportOutput,
EditorConfig,
LexicalEditor,
LexicalNode,
NodeKey,
SerializedElementNode,
Spread,
} from 'lexical';

import {
addClassNamesToElement,
isHTMLElement,
removeClassNamesFromElement,
} from '@lexical/utils';
import {
$applyNodeReplacement,
$getEditor,
$getNearestNodeFromDOMNode,
DOMConversionMap,
DOMConversionOutput,
DOMExportOutput,
EditorConfig,
ElementDOMSlot,
ElementNode,
LexicalEditor,
LexicalNode,
NodeKey,
SerializedElementNode,
setDOMUnmanaged,
Spread,
} from 'lexical';

import {PIXEL_VALUE_REG_EXP} from './constants';
Expand Down Expand Up @@ -79,6 +79,25 @@ function setRowStriping(
}
}

const scrollableEditors = new WeakSet<LexicalEditor>();

export function $isScrollableTablesActive(
editor: LexicalEditor = $getEditor(),
): boolean {
return scrollableEditors.has(editor);
}

export function setScrollableTablesActive(
editor: LexicalEditor,
active: boolean,
) {
if (active) {
scrollableEditors.add(editor);
} else {
scrollableEditors.delete(editor);
}
}

/** @noInheritDoc */
export class TableNode extends ElementNode {
/** @internal */
Expand Down Expand Up @@ -142,6 +161,16 @@ export class TableNode extends ElementNode {
};
}

getDOMSlot(element: HTMLElement): ElementDOMSlot {
const tableElement =
element.dataset.lexicalScrollable === 'true'
? element.querySelector('table') || element
: element;
return super
.getDOMSlot(tableElement)
.withAfter(tableElement.querySelector('colgroup'));
}

createDOM(config: EditorConfig, editor?: LexicalEditor): HTMLElement {
const tableElement = document.createElement('table');
const colGroup = document.createElement('colgroup');
Expand All @@ -152,11 +181,19 @@ export class TableNode extends ElementNode {
this.getColumnCount(),
this.getColWidths(),
);
setDOMUnmanaged(colGroup);

addClassNamesToElement(tableElement, config.theme.table);
if (this.__rowStriping) {
setRowStriping(tableElement, config, true);
}
if ($isScrollableTablesActive()) {
const wrapperElement = document.createElement('div');
wrapperElement.dataset.lexicalScrollable = 'true';
wrapperElement.style.overflowX = 'auto';
wrapperElement.appendChild(tableElement);
return wrapperElement;
}

return tableElement;
}
Expand All @@ -177,6 +214,13 @@ export class TableNode extends ElementNode {
return {
...super.exportDOM(editor),
after: (tableElement) => {
if (
tableElement &&
isHTMLElement(tableElement) &&
tableElement.dataset.lexicalScrollable === 'true'
) {
tableElement = tableElement.querySelector('table');
}
if (tableElement) {
const newElement = tableElement.cloneNode() as ParentNode;
const colGroup = document.createElement('colgroup');
Expand Down
2 changes: 2 additions & 0 deletions packages/lexical-table/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ export type {SerializedTableNode} from './LexicalTableNode';
export {
$createTableNode,
$getElementForTableNode,
$isScrollableTablesActive,
$isTableNode,
setScrollableTablesActive,
TableNode,
} from './LexicalTableNode';
export type {TableDOMCell} from './LexicalTableObserver';
Expand Down

0 comments on commit 629d934

Please sign in to comment.