@crystallize/design-system 1.6.1 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/index.css +53 -332
- package/dist/index.d.ts +15 -8
- package/dist/index.js +1736 -4555
- package/dist/index.mjs +1655 -2339
- package/package.json +1 -1
- package/src/action-menu/action-item-separator.tsx +14 -0
- package/src/action-menu/action-item.tsx +2 -2
- package/src/action-menu/action-menu.css +8 -0
- package/src/action-menu/action-menu.tsx +2 -1
- package/src/dropdown-menu/dropdown-menu-root.tsx +3 -1
- package/src/dropdown-menu/index.ts +5 -2
- package/src/iconography/subscription-contracts.tsx +4 -4
- package/src/iconography/subscription-plans.tsx +5 -5
- package/src/rich-text-editor/model/crystallize-to-lexical.ts +12 -1
- package/src/rich-text-editor/model/lexical-to-crystallize.ts +38 -38
- package/src/rich-text-editor/nodes/BaseNodes.ts +0 -7
- package/src/rich-text-editor/nodes/TableCellNodes.ts +0 -7
- package/src/rich-text-editor/plugins/ActionsPlugin/index.tsx +13 -2
- package/src/rich-text-editor/plugins/CodeActionMenuPlugin/components/CopyButton/index.tsx +3 -2
- package/src/rich-text-editor/plugins/CodeActionMenuPlugin/components/PrettierButton/index.tsx +0 -1
- package/src/rich-text-editor/plugins/FloatingTextFormatToolbarPlugin/index.css +17 -17
- package/src/rich-text-editor/plugins/FloatingTextFormatToolbarPlugin/index.tsx +1 -1
- package/src/rich-text-editor/plugins/MaxLengthPlugin/index.tsx +2 -7
- package/src/rich-text-editor/plugins/TableActionMenuPlugin/index.tsx +80 -149
- package/src/rich-text-editor/plugins/ToolbarPlugin/index.tsx +2 -2
- package/src/rich-text-editor/plugins/ToolbarPlugin/insert-table.tsx +55 -0
- package/src/rich-text-editor/rich-text-editor.css +10 -322
- package/src/rich-text-editor/rich-text-editor.stories.tsx +35 -5
- package/src/rich-text-editor/rich-text-editor.tsx +6 -39
- package/src/rich-text-editor/tests/rich-text-editor-code.test.tsx +10 -6
- package/src/rich-text-editor/tests/rich-text-editor-model-conversions.test.tsx +19 -7
- package/src/rich-text-editor/themes/CrystallizeRTEditorTheme.css +3 -11
- package/dist/TableComponent-I2YOOYOU.css +0 -281
- package/dist/TableComponent-QINOO453.mjs +0 -1377
- package/dist/chevron-down-3FRWSIKS.svg +0 -1
- package/dist/chunk-VUXQZRSP.mjs +0 -737
- package/dist/markdown-4BGQNLLT.svg +0 -1
- package/src/rich-text-editor/nodes/KeywordNode.ts +0 -73
- package/src/rich-text-editor/nodes/TableComponent.tsx +0 -1547
- package/src/rich-text-editor/nodes/TableNode.tsx +0 -398
- package/src/rich-text-editor/plugins/ComponentPickerPlugin/index.tsx +0 -320
- package/src/rich-text-editor/plugins/DragDropPastePlugin/index.ts +0 -40
- package/src/rich-text-editor/plugins/MarkdownShortcutPlugin/index.tsx +0 -16
- package/src/rich-text-editor/plugins/MarkdownTransformers/index.ts +0 -195
- package/src/rich-text-editor/plugins/SpeechToTextPlugin/index.ts +0 -113
- package/src/rich-text-editor/plugins/TableCellResizer/index.css +0 -12
- package/src/rich-text-editor/plugins/TableCellResizer/index.tsx +0 -386
- package/src/rich-text-editor/plugins/TablePlugin.tsx +0 -190
- package/src/rich-text-editor/plugins/TreeViewPlugin/index.tsx +0 -25
- package/src/rich-text-editor/plugins/TypingPerfPlugin/index.ts +0 -117
|
@@ -1,386 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the MIT license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*
|
|
7
|
-
*/
|
|
8
|
-
import type {Cell} from '@lexical/table';
|
|
9
|
-
import type {LexicalEditor} from 'lexical';
|
|
10
|
-
|
|
11
|
-
import './index.css';
|
|
12
|
-
|
|
13
|
-
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
|
|
14
|
-
import useLexicalEditable from '@lexical/react/useLexicalEditable';
|
|
15
|
-
import {
|
|
16
|
-
$getTableColumnIndexFromTableCellNode,
|
|
17
|
-
$getTableNodeFromLexicalNodeOrThrow,
|
|
18
|
-
$getTableRowIndexFromTableCellNode,
|
|
19
|
-
$isTableCellNode,
|
|
20
|
-
$isTableRowNode,
|
|
21
|
-
getCellFromTarget,
|
|
22
|
-
} from '@lexical/table';
|
|
23
|
-
import {
|
|
24
|
-
$getNearestNodeFromDOMNode,
|
|
25
|
-
$getSelection,
|
|
26
|
-
COMMAND_PRIORITY_HIGH,
|
|
27
|
-
DEPRECATED_$isGridSelection,
|
|
28
|
-
SELECTION_CHANGE_COMMAND,
|
|
29
|
-
} from 'lexical';
|
|
30
|
-
import * as React from 'react';
|
|
31
|
-
import {
|
|
32
|
-
MouseEventHandler,
|
|
33
|
-
ReactPortal,
|
|
34
|
-
useCallback,
|
|
35
|
-
useEffect,
|
|
36
|
-
useMemo,
|
|
37
|
-
useRef,
|
|
38
|
-
useState,
|
|
39
|
-
} from 'react';
|
|
40
|
-
import {createPortal} from 'react-dom';
|
|
41
|
-
|
|
42
|
-
type MousePosition = {
|
|
43
|
-
x: number;
|
|
44
|
-
y: number;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
type MouseDraggingDirection = 'right' | 'bottom';
|
|
48
|
-
|
|
49
|
-
const MIN_ROW_HEIGHT = 33;
|
|
50
|
-
const MIN_COLUMN_WIDTH = 50;
|
|
51
|
-
|
|
52
|
-
function TableCellResizer({editor}: {editor: LexicalEditor}): JSX.Element {
|
|
53
|
-
const targetRef = useRef<HTMLElement | null>(null);
|
|
54
|
-
const resizerRef = useRef<HTMLDivElement | null>(null);
|
|
55
|
-
const tableRectRef = useRef<ClientRect | null>(null);
|
|
56
|
-
|
|
57
|
-
const mouseStartPosRef = useRef<MousePosition | null>(null);
|
|
58
|
-
const [mouseCurrentPos, updateMouseCurrentPos] =
|
|
59
|
-
useState<MousePosition | null>(null);
|
|
60
|
-
|
|
61
|
-
const [activeCell, updateActiveCell] = useState<Cell | null>(null);
|
|
62
|
-
const [isSelectingGrid, updateIsSelectingGrid] = useState<boolean>(false);
|
|
63
|
-
const [draggingDirection, updateDraggingDirection] =
|
|
64
|
-
useState<MouseDraggingDirection | null>(null);
|
|
65
|
-
|
|
66
|
-
useEffect(() => {
|
|
67
|
-
return editor.registerCommand(
|
|
68
|
-
SELECTION_CHANGE_COMMAND,
|
|
69
|
-
(payload) => {
|
|
70
|
-
const selection = $getSelection();
|
|
71
|
-
const isGridSelection = DEPRECATED_$isGridSelection(selection);
|
|
72
|
-
|
|
73
|
-
if (isSelectingGrid !== isGridSelection) {
|
|
74
|
-
updateIsSelectingGrid(isGridSelection);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return false;
|
|
78
|
-
},
|
|
79
|
-
COMMAND_PRIORITY_HIGH,
|
|
80
|
-
);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
const resetState = useCallback(() => {
|
|
84
|
-
updateActiveCell(null);
|
|
85
|
-
targetRef.current = null;
|
|
86
|
-
updateDraggingDirection(null);
|
|
87
|
-
mouseStartPosRef.current = null;
|
|
88
|
-
tableRectRef.current = null;
|
|
89
|
-
}, []);
|
|
90
|
-
|
|
91
|
-
useEffect(() => {
|
|
92
|
-
const onMouseMove = (event: MouseEvent) => {
|
|
93
|
-
setTimeout(() => {
|
|
94
|
-
const target = event.target;
|
|
95
|
-
|
|
96
|
-
if (draggingDirection) {
|
|
97
|
-
updateMouseCurrentPos({
|
|
98
|
-
x: event.clientX,
|
|
99
|
-
y: event.clientY,
|
|
100
|
-
});
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (resizerRef.current && resizerRef.current.contains(target as Node)) {
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (targetRef.current !== target) {
|
|
109
|
-
targetRef.current = target as HTMLElement;
|
|
110
|
-
const cell = getCellFromTarget(target as HTMLElement);
|
|
111
|
-
|
|
112
|
-
if (cell && activeCell !== cell) {
|
|
113
|
-
editor.update(() => {
|
|
114
|
-
const tableCellNode = $getNearestNodeFromDOMNode(cell.elem);
|
|
115
|
-
if (!tableCellNode) {
|
|
116
|
-
throw new Error('TableCellResizer: Table cell node not found.');
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const tableNode =
|
|
120
|
-
$getTableNodeFromLexicalNodeOrThrow(tableCellNode);
|
|
121
|
-
const tableElement = editor.getElementByKey(tableNode.getKey());
|
|
122
|
-
|
|
123
|
-
if (!tableElement) {
|
|
124
|
-
throw new Error('TableCellResizer: Table element not found.');
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
targetRef.current = target as HTMLElement;
|
|
128
|
-
tableRectRef.current = tableElement.getBoundingClientRect();
|
|
129
|
-
updateActiveCell(cell);
|
|
130
|
-
});
|
|
131
|
-
} else if (cell == null) {
|
|
132
|
-
resetState();
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}, 0);
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
document.addEventListener('mousemove', onMouseMove);
|
|
139
|
-
|
|
140
|
-
return () => {
|
|
141
|
-
document.removeEventListener('mousemove', onMouseMove);
|
|
142
|
-
};
|
|
143
|
-
}, [activeCell, draggingDirection, editor, resetState]);
|
|
144
|
-
|
|
145
|
-
const isHeightChanging = (direction: MouseDraggingDirection) => {
|
|
146
|
-
if (direction === 'bottom') return true;
|
|
147
|
-
return false;
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
const updateRowHeight = useCallback(
|
|
151
|
-
(newHeight: number) => {
|
|
152
|
-
if (!activeCell) {
|
|
153
|
-
throw new Error('TableCellResizer: Expected active cell.');
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
editor.update(() => {
|
|
157
|
-
const tableCellNode = $getNearestNodeFromDOMNode(activeCell.elem);
|
|
158
|
-
if (!$isTableCellNode(tableCellNode)) {
|
|
159
|
-
throw new Error('TableCellResizer: Table cell node not found.');
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
|
|
163
|
-
|
|
164
|
-
const tableRowIndex = $getTableRowIndexFromTableCellNode(tableCellNode);
|
|
165
|
-
|
|
166
|
-
const tableRows = tableNode.getChildren();
|
|
167
|
-
|
|
168
|
-
if (tableRowIndex >= tableRows.length || tableRowIndex < 0) {
|
|
169
|
-
throw new Error('Expected table cell to be inside of table row.');
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const tableRow = tableRows[tableRowIndex];
|
|
173
|
-
|
|
174
|
-
if (!$isTableRowNode(tableRow)) {
|
|
175
|
-
throw new Error('Expected table row');
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
tableRow.setHeight(newHeight);
|
|
179
|
-
});
|
|
180
|
-
},
|
|
181
|
-
[activeCell, editor],
|
|
182
|
-
);
|
|
183
|
-
|
|
184
|
-
const updateColumnWidth = useCallback(
|
|
185
|
-
(newWidth: number) => {
|
|
186
|
-
if (!activeCell) {
|
|
187
|
-
throw new Error('TableCellResizer: Expected active cell.');
|
|
188
|
-
}
|
|
189
|
-
editor.update(() => {
|
|
190
|
-
const tableCellNode = $getNearestNodeFromDOMNode(activeCell.elem);
|
|
191
|
-
if (!$isTableCellNode(tableCellNode)) {
|
|
192
|
-
throw new Error('TableCellResizer: Table cell node not found.');
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
|
|
196
|
-
|
|
197
|
-
const tableColumnIndex =
|
|
198
|
-
$getTableColumnIndexFromTableCellNode(tableCellNode);
|
|
199
|
-
|
|
200
|
-
const tableRows = tableNode.getChildren();
|
|
201
|
-
|
|
202
|
-
for (let r = 0; r < tableRows.length; r++) {
|
|
203
|
-
const tableRow = tableRows[r];
|
|
204
|
-
|
|
205
|
-
if (!$isTableRowNode(tableRow)) {
|
|
206
|
-
throw new Error('Expected table row');
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
const tableCells = tableRow.getChildren();
|
|
210
|
-
|
|
211
|
-
if (tableColumnIndex >= tableCells.length || tableColumnIndex < 0) {
|
|
212
|
-
throw new Error('Expected table cell to be inside of table row.');
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
const tableCell = tableCells[tableColumnIndex];
|
|
216
|
-
|
|
217
|
-
if (!$isTableCellNode(tableCell)) {
|
|
218
|
-
throw new Error('Expected table cell');
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
tableCell.setWidth(newWidth);
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
},
|
|
225
|
-
[activeCell, editor],
|
|
226
|
-
);
|
|
227
|
-
|
|
228
|
-
const toggleResize = useCallback(
|
|
229
|
-
(direction: MouseDraggingDirection): MouseEventHandler<HTMLDivElement> =>
|
|
230
|
-
(event) => {
|
|
231
|
-
event.preventDefault();
|
|
232
|
-
event.stopPropagation();
|
|
233
|
-
|
|
234
|
-
if (!activeCell) {
|
|
235
|
-
throw new Error('TableCellResizer: Expected active cell.');
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
if (draggingDirection === direction && mouseStartPosRef.current) {
|
|
239
|
-
const {x, y} = mouseStartPosRef.current;
|
|
240
|
-
|
|
241
|
-
if (activeCell === null) {
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
const {height, width} = activeCell.elem.getBoundingClientRect();
|
|
246
|
-
|
|
247
|
-
if (isHeightChanging(direction)) {
|
|
248
|
-
const heightChange = Math.abs(event.clientY - y);
|
|
249
|
-
|
|
250
|
-
const isShrinking = direction === 'bottom' && y > event.clientY;
|
|
251
|
-
|
|
252
|
-
updateRowHeight(
|
|
253
|
-
Math.max(
|
|
254
|
-
isShrinking ? height - heightChange : heightChange + height,
|
|
255
|
-
MIN_ROW_HEIGHT,
|
|
256
|
-
),
|
|
257
|
-
);
|
|
258
|
-
} else {
|
|
259
|
-
const widthChange = Math.abs(event.clientX - x);
|
|
260
|
-
|
|
261
|
-
const isShrinking = direction === 'right' && x > event.clientX;
|
|
262
|
-
|
|
263
|
-
updateColumnWidth(
|
|
264
|
-
Math.max(
|
|
265
|
-
isShrinking ? width - widthChange : widthChange + width,
|
|
266
|
-
MIN_COLUMN_WIDTH,
|
|
267
|
-
),
|
|
268
|
-
);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
resetState();
|
|
272
|
-
} else {
|
|
273
|
-
mouseStartPosRef.current = {
|
|
274
|
-
x: event.clientX,
|
|
275
|
-
y: event.clientY,
|
|
276
|
-
};
|
|
277
|
-
updateMouseCurrentPos(mouseStartPosRef.current);
|
|
278
|
-
updateDraggingDirection(direction);
|
|
279
|
-
}
|
|
280
|
-
},
|
|
281
|
-
[
|
|
282
|
-
activeCell,
|
|
283
|
-
draggingDirection,
|
|
284
|
-
resetState,
|
|
285
|
-
updateColumnWidth,
|
|
286
|
-
updateRowHeight,
|
|
287
|
-
],
|
|
288
|
-
);
|
|
289
|
-
|
|
290
|
-
const getResizers = useCallback(() => {
|
|
291
|
-
if (activeCell) {
|
|
292
|
-
const {height, width, top, left} =
|
|
293
|
-
activeCell.elem.getBoundingClientRect();
|
|
294
|
-
|
|
295
|
-
const styles = {
|
|
296
|
-
bottom: {
|
|
297
|
-
backgroundColor: 'none',
|
|
298
|
-
cursor: 'row-resize',
|
|
299
|
-
height: '10px',
|
|
300
|
-
left: `${window.pageXOffset + left}px`,
|
|
301
|
-
top: `${window.pageYOffset + top + height}px`,
|
|
302
|
-
width: `${width}px`,
|
|
303
|
-
},
|
|
304
|
-
right: {
|
|
305
|
-
backgroundColor: 'none',
|
|
306
|
-
cursor: 'col-resize',
|
|
307
|
-
height: `${height}px`,
|
|
308
|
-
left: `${window.pageXOffset + left + width}px`,
|
|
309
|
-
top: `${window.pageYOffset + top}px`,
|
|
310
|
-
width: '10px',
|
|
311
|
-
},
|
|
312
|
-
};
|
|
313
|
-
|
|
314
|
-
const tableRect = tableRectRef.current;
|
|
315
|
-
|
|
316
|
-
if (draggingDirection && mouseCurrentPos && tableRect) {
|
|
317
|
-
if (isHeightChanging(draggingDirection)) {
|
|
318
|
-
styles[draggingDirection].left = `${
|
|
319
|
-
window.pageXOffset + tableRect.left
|
|
320
|
-
}px`;
|
|
321
|
-
styles[draggingDirection].top = `${
|
|
322
|
-
window.pageYOffset + mouseCurrentPos.y
|
|
323
|
-
}px`;
|
|
324
|
-
styles[draggingDirection].height = '3px';
|
|
325
|
-
styles[draggingDirection].width = `${tableRect.width}px`;
|
|
326
|
-
} else {
|
|
327
|
-
styles[draggingDirection].top = `${
|
|
328
|
-
window.pageYOffset + tableRect.top
|
|
329
|
-
}px`;
|
|
330
|
-
styles[draggingDirection].left = `${
|
|
331
|
-
window.pageXOffset + mouseCurrentPos.x
|
|
332
|
-
}px`;
|
|
333
|
-
styles[draggingDirection].width = '3px';
|
|
334
|
-
styles[draggingDirection].height = `${tableRect.height}px`;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
styles[draggingDirection].backgroundColor = '#adf';
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
return styles;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
return {
|
|
344
|
-
bottom: null,
|
|
345
|
-
left: null,
|
|
346
|
-
right: null,
|
|
347
|
-
top: null,
|
|
348
|
-
};
|
|
349
|
-
}, [activeCell, draggingDirection, mouseCurrentPos]);
|
|
350
|
-
|
|
351
|
-
const resizerStyles = getResizers();
|
|
352
|
-
|
|
353
|
-
return (
|
|
354
|
-
<div ref={resizerRef}>
|
|
355
|
-
{activeCell != null && !isSelectingGrid && (
|
|
356
|
-
<>
|
|
357
|
-
<div
|
|
358
|
-
className="TableCellResizer__resizer TableCellResizer__ui"
|
|
359
|
-
style={resizerStyles.right || undefined}
|
|
360
|
-
onMouseDown={toggleResize('right')}
|
|
361
|
-
onMouseUp={toggleResize('right')}
|
|
362
|
-
/>
|
|
363
|
-
<div
|
|
364
|
-
className="TableCellResizer__resizer TableCellResizer__ui"
|
|
365
|
-
style={resizerStyles.bottom || undefined}
|
|
366
|
-
onMouseDown={toggleResize('bottom')}
|
|
367
|
-
onMouseUp={toggleResize('bottom')}
|
|
368
|
-
/>
|
|
369
|
-
</>
|
|
370
|
-
)}
|
|
371
|
-
</div>
|
|
372
|
-
);
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
export default function TableCellResizerPlugin(): null | ReactPortal {
|
|
376
|
-
const [editor] = useLexicalComposerContext();
|
|
377
|
-
const isEditable = useLexicalEditable();
|
|
378
|
-
|
|
379
|
-
return useMemo(
|
|
380
|
-
() =>
|
|
381
|
-
isEditable
|
|
382
|
-
? createPortal(<TableCellResizer editor={editor} />, document.body)
|
|
383
|
-
: null,
|
|
384
|
-
[editor, isEditable],
|
|
385
|
-
);
|
|
386
|
-
}
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the MIT license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { createContext, useContext, useEffect, useMemo, useState } from 'react';
|
|
10
|
-
import * as React from 'react';
|
|
11
|
-
import {
|
|
12
|
-
$createNodeSelection,
|
|
13
|
-
$createParagraphNode,
|
|
14
|
-
$getSelection,
|
|
15
|
-
$isRangeSelection,
|
|
16
|
-
$isRootOrShadowRoot,
|
|
17
|
-
$setSelection,
|
|
18
|
-
COMMAND_PRIORITY_EDITOR,
|
|
19
|
-
createCommand,
|
|
20
|
-
EditorThemeClasses,
|
|
21
|
-
Klass,
|
|
22
|
-
LexicalCommand,
|
|
23
|
-
LexicalEditor,
|
|
24
|
-
LexicalNode,
|
|
25
|
-
} from 'lexical';
|
|
26
|
-
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
27
|
-
|
|
28
|
-
import { Button } from '../../button';
|
|
29
|
-
import { InputWithLabel } from '../../input-with-label';
|
|
30
|
-
import { $createTableNodeWithDimensions, TableNode } from '../nodes/TableNode';
|
|
31
|
-
|
|
32
|
-
export type InsertTableCommandPayload = Readonly<{
|
|
33
|
-
columns: string;
|
|
34
|
-
rows: string;
|
|
35
|
-
includeHeaders?: boolean;
|
|
36
|
-
}>;
|
|
37
|
-
|
|
38
|
-
export type CellContextShape = {
|
|
39
|
-
cellEditorConfig: null | CellEditorConfig;
|
|
40
|
-
cellEditorPlugins: null | JSX.Element | Array<JSX.Element>;
|
|
41
|
-
set: (cellEditorConfig: null | CellEditorConfig, cellEditorPlugins: null | JSX.Element | Array<JSX.Element>) => void;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
export type CellEditorConfig = Readonly<{
|
|
45
|
-
namespace: string;
|
|
46
|
-
nodes?: ReadonlyArray<Klass<LexicalNode>>;
|
|
47
|
-
onError: (error: Error, editor: LexicalEditor) => void;
|
|
48
|
-
readOnly?: boolean;
|
|
49
|
-
theme?: EditorThemeClasses;
|
|
50
|
-
}>;
|
|
51
|
-
|
|
52
|
-
export const INSERT_NEW_TABLE_COMMAND: LexicalCommand<InsertTableCommandPayload> =
|
|
53
|
-
createCommand('INSERT_NEW_TABLE_COMMAND');
|
|
54
|
-
|
|
55
|
-
export const CellContext = createContext<CellContextShape>({
|
|
56
|
-
cellEditorConfig: null,
|
|
57
|
-
cellEditorPlugins: null,
|
|
58
|
-
set: () => {
|
|
59
|
-
// Empty
|
|
60
|
-
},
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
export function TableContext({ children }: { children: JSX.Element }) {
|
|
64
|
-
const [contextValue, setContextValue] = useState<{
|
|
65
|
-
cellEditorConfig: null | CellEditorConfig;
|
|
66
|
-
cellEditorPlugins: null | JSX.Element | Array<JSX.Element>;
|
|
67
|
-
}>({
|
|
68
|
-
cellEditorConfig: null,
|
|
69
|
-
cellEditorPlugins: null,
|
|
70
|
-
});
|
|
71
|
-
return (
|
|
72
|
-
<CellContext.Provider
|
|
73
|
-
value={useMemo(
|
|
74
|
-
() => ({
|
|
75
|
-
cellEditorConfig: contextValue.cellEditorConfig,
|
|
76
|
-
cellEditorPlugins: contextValue.cellEditorPlugins,
|
|
77
|
-
set: (cellEditorConfig, cellEditorPlugins) => {
|
|
78
|
-
setContextValue({ cellEditorConfig, cellEditorPlugins });
|
|
79
|
-
},
|
|
80
|
-
}),
|
|
81
|
-
[contextValue.cellEditorConfig, contextValue.cellEditorPlugins],
|
|
82
|
-
)}
|
|
83
|
-
>
|
|
84
|
-
{children}
|
|
85
|
-
</CellContext.Provider>
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export function InsertNewTableDialog({ activeEditor }: { activeEditor: LexicalEditor }): JSX.Element {
|
|
90
|
-
const [rows, setRows] = useState('5');
|
|
91
|
-
const [columns, setColumns] = useState('5');
|
|
92
|
-
|
|
93
|
-
const onClick = () => {
|
|
94
|
-
if (parseInt(rows) < 1 || parseInt(columns) < 1) {
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
activeEditor.dispatchCommand(INSERT_NEW_TABLE_COMMAND, { columns, rows });
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
return (
|
|
101
|
-
<>
|
|
102
|
-
<div className="grid grid-cols-[1fr_1px_1fr] border border-gray-100-800 border-solid shadow-sm rounded-md ">
|
|
103
|
-
<InputWithLabel
|
|
104
|
-
label="Rows"
|
|
105
|
-
value={rows}
|
|
106
|
-
placeholder="0"
|
|
107
|
-
type="text"
|
|
108
|
-
inputMode="numeric"
|
|
109
|
-
onChange={e => setRows(e.target.value)}
|
|
110
|
-
/>
|
|
111
|
-
<span className="h-full bg-gray-100-800" />
|
|
112
|
-
<InputWithLabel
|
|
113
|
-
type="text"
|
|
114
|
-
label="Columns"
|
|
115
|
-
placeholder="0"
|
|
116
|
-
value={columns}
|
|
117
|
-
inputMode="numeric"
|
|
118
|
-
onChange={e => setColumns(e.target.value)}
|
|
119
|
-
/>
|
|
120
|
-
</div>
|
|
121
|
-
<div className="flex justify-end mt-3">
|
|
122
|
-
<Button size="sm" intent="action" aria-label="Confirm" onClick={onClick}>
|
|
123
|
-
Confirm
|
|
124
|
-
</Button>
|
|
125
|
-
</div>
|
|
126
|
-
</>
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export function TablePlugin({
|
|
131
|
-
cellEditorConfig,
|
|
132
|
-
children,
|
|
133
|
-
}: {
|
|
134
|
-
cellEditorConfig: CellEditorConfig;
|
|
135
|
-
children: JSX.Element | Array<JSX.Element>;
|
|
136
|
-
}): JSX.Element | null {
|
|
137
|
-
const [editor] = useLexicalComposerContext();
|
|
138
|
-
const cellContext = useContext(CellContext);
|
|
139
|
-
|
|
140
|
-
useEffect(() => {
|
|
141
|
-
if (!editor.hasNodes([TableNode])) {
|
|
142
|
-
throw new Error('TablePlugin: TableNode is not registered on editor');
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
cellContext.set(cellEditorConfig, children);
|
|
146
|
-
|
|
147
|
-
return editor.registerCommand<InsertTableCommandPayload>(
|
|
148
|
-
INSERT_NEW_TABLE_COMMAND,
|
|
149
|
-
({ columns, rows, includeHeaders }) => {
|
|
150
|
-
const selection = $getSelection();
|
|
151
|
-
|
|
152
|
-
if (!$isRangeSelection(selection)) {
|
|
153
|
-
return true;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const focus = selection.focus;
|
|
157
|
-
const focusNode = focus.getNode();
|
|
158
|
-
|
|
159
|
-
if (focusNode !== null) {
|
|
160
|
-
const tableNode = $createTableNodeWithDimensions(Number(rows), Number(columns), includeHeaders);
|
|
161
|
-
|
|
162
|
-
if ($isRootOrShadowRoot(focusNode)) {
|
|
163
|
-
const target = focusNode.getChildAtIndex(focus.offset);
|
|
164
|
-
|
|
165
|
-
if (target !== null) {
|
|
166
|
-
target.insertBefore(tableNode);
|
|
167
|
-
} else {
|
|
168
|
-
focusNode.append(tableNode);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
tableNode.insertBefore($createParagraphNode());
|
|
172
|
-
} else {
|
|
173
|
-
const topLevelNode = focusNode.getTopLevelElementOrThrow();
|
|
174
|
-
topLevelNode.insertAfter(tableNode);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
tableNode.insertAfter($createParagraphNode());
|
|
178
|
-
const nodeSelection = $createNodeSelection();
|
|
179
|
-
nodeSelection.add(tableNode.getKey());
|
|
180
|
-
$setSelection(nodeSelection);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return true;
|
|
184
|
-
},
|
|
185
|
-
COMMAND_PRIORITY_EDITOR,
|
|
186
|
-
);
|
|
187
|
-
}, [cellContext, cellEditorConfig, children, editor]);
|
|
188
|
-
|
|
189
|
-
return null;
|
|
190
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the MIT license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
10
|
-
import { TreeView } from '@lexical/react/LexicalTreeView';
|
|
11
|
-
import * as React from 'react';
|
|
12
|
-
|
|
13
|
-
export default function TreeViewPlugin(): JSX.Element {
|
|
14
|
-
const [editor] = useLexicalComposerContext();
|
|
15
|
-
return (
|
|
16
|
-
<TreeView
|
|
17
|
-
viewClassName="tree-view-output"
|
|
18
|
-
timeTravelPanelClassName="debug-timetravel-panel"
|
|
19
|
-
timeTravelButtonClassName="debug-timetravel-button"
|
|
20
|
-
timeTravelPanelSliderClassName="debug-timetravel-panel-slider"
|
|
21
|
-
timeTravelPanelButtonClassName="debug-timetravel-panel-button"
|
|
22
|
-
editor={editor}
|
|
23
|
-
/>
|
|
24
|
-
);
|
|
25
|
-
}
|