@crystallize/design-system 1.7.0 → 1.9.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 +1717 -4568
- package/dist/index.mjs +1639 -2355
- 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 +1 -1
- 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 +23 -36
- 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
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import * as React from 'react';
|
|
10
9
|
import { ReactPortal, useCallback, useEffect, useRef, useState } from 'react';
|
|
11
10
|
import { $getRoot, $getSelection, $isRangeSelection, DEPRECATED_$isGridSelection } from 'lexical';
|
|
12
11
|
import { createPortal } from 'react-dom';
|
|
@@ -22,6 +21,7 @@ import {
|
|
|
22
21
|
$insertTableColumn,
|
|
23
22
|
$insertTableRow,
|
|
24
23
|
$isTableCellNode,
|
|
24
|
+
$isTableNode,
|
|
25
25
|
$isTableRowNode,
|
|
26
26
|
$removeTableRowAtIndex,
|
|
27
27
|
getTableSelectionFromTableElement,
|
|
@@ -30,24 +30,22 @@ import {
|
|
|
30
30
|
TableCellNode,
|
|
31
31
|
} from '@lexical/table';
|
|
32
32
|
|
|
33
|
+
import { DropdownMenu } from '../../../dropdown-menu';
|
|
33
34
|
import { IconButton } from '../../../icon-button';
|
|
34
35
|
import { Icon } from '../../../iconography';
|
|
35
36
|
|
|
37
|
+
type TableStats = {
|
|
38
|
+
rows: number;
|
|
39
|
+
columns: number;
|
|
40
|
+
};
|
|
41
|
+
|
|
36
42
|
type TableCellActionMenuProps = Readonly<{
|
|
37
|
-
contextRef: { current: null | HTMLElement };
|
|
38
|
-
onClose: () => void;
|
|
39
|
-
setIsMenuOpen: (isOpen: boolean) => void;
|
|
40
43
|
tableCellNode: TableCellNode;
|
|
44
|
+
tableStats: TableStats;
|
|
41
45
|
}>;
|
|
42
46
|
|
|
43
|
-
function TableActionMenu({
|
|
44
|
-
onClose,
|
|
45
|
-
tableCellNode: _tableCellNode,
|
|
46
|
-
setIsMenuOpen,
|
|
47
|
-
contextRef,
|
|
48
|
-
}: TableCellActionMenuProps) {
|
|
47
|
+
function TableActionMenu({ tableCellNode: _tableCellNode, tableStats }: TableCellActionMenuProps) {
|
|
49
48
|
const [editor] = useLexicalComposerContext();
|
|
50
|
-
const dropDownRef = useRef<HTMLDivElement | null>(null);
|
|
51
49
|
const [tableCellNode, updateTableCellNode] = useState(_tableCellNode);
|
|
52
50
|
const [selectionCounts, updateSelectionCounts] = useState({
|
|
53
51
|
columns: 1,
|
|
@@ -81,38 +79,6 @@ function TableActionMenu({
|
|
|
81
79
|
});
|
|
82
80
|
}, [editor]);
|
|
83
81
|
|
|
84
|
-
useEffect(() => {
|
|
85
|
-
const menuButtonElement = contextRef.current;
|
|
86
|
-
const dropDownElement = dropDownRef.current;
|
|
87
|
-
|
|
88
|
-
if (menuButtonElement != null && dropDownElement != null) {
|
|
89
|
-
const menuButtonRect = menuButtonElement.getBoundingClientRect();
|
|
90
|
-
|
|
91
|
-
dropDownElement.style.opacity = '1';
|
|
92
|
-
|
|
93
|
-
dropDownElement.style.left = `${menuButtonRect.left + menuButtonRect.width + window.pageXOffset + 5}px`;
|
|
94
|
-
|
|
95
|
-
dropDownElement.style.top = `${menuButtonRect.top + window.pageYOffset}px`;
|
|
96
|
-
}
|
|
97
|
-
}, [contextRef, dropDownRef]);
|
|
98
|
-
|
|
99
|
-
useEffect(() => {
|
|
100
|
-
function handleClickOutside(event: MouseEvent) {
|
|
101
|
-
if (
|
|
102
|
-
dropDownRef.current != null &&
|
|
103
|
-
contextRef.current != null &&
|
|
104
|
-
!dropDownRef.current.contains(event.target as Node) &&
|
|
105
|
-
!contextRef.current.contains(event.target as Node)
|
|
106
|
-
) {
|
|
107
|
-
setIsMenuOpen(false);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
window.addEventListener('click', handleClickOutside);
|
|
112
|
-
|
|
113
|
-
return () => window.removeEventListener('click', handleClickOutside);
|
|
114
|
-
}, [setIsMenuOpen, contextRef]);
|
|
115
|
-
|
|
116
82
|
const clearTableSelection = useCallback(() => {
|
|
117
83
|
editor.update(() => {
|
|
118
84
|
if (tableCellNode.isAttached()) {
|
|
@@ -158,11 +124,9 @@ function TableActionMenu({
|
|
|
158
124
|
$insertTableRow(tableNode, tableRowIndex, shouldInsertAfter, selectionCounts.rows, grid);
|
|
159
125
|
|
|
160
126
|
clearTableSelection();
|
|
161
|
-
|
|
162
|
-
onClose();
|
|
163
127
|
});
|
|
164
128
|
},
|
|
165
|
-
[editor, tableCellNode, selectionCounts.rows, clearTableSelection
|
|
129
|
+
[editor, tableCellNode, selectionCounts.rows, clearTableSelection],
|
|
166
130
|
);
|
|
167
131
|
|
|
168
132
|
const insertTableColumnAtSelection = useCallback(
|
|
@@ -186,11 +150,9 @@ function TableActionMenu({
|
|
|
186
150
|
$insertTableColumn(tableNode, tableColumnIndex, shouldInsertAfter, selectionCounts.columns, grid);
|
|
187
151
|
|
|
188
152
|
clearTableSelection();
|
|
189
|
-
|
|
190
|
-
onClose();
|
|
191
153
|
});
|
|
192
154
|
},
|
|
193
|
-
[editor, tableCellNode, selectionCounts.columns, clearTableSelection
|
|
155
|
+
[editor, tableCellNode, selectionCounts.columns, clearTableSelection],
|
|
194
156
|
);
|
|
195
157
|
|
|
196
158
|
const deleteTableRowAtSelection = useCallback(() => {
|
|
@@ -201,9 +163,8 @@ function TableActionMenu({
|
|
|
201
163
|
$removeTableRowAtIndex(tableNode, tableRowIndex);
|
|
202
164
|
|
|
203
165
|
clearTableSelection();
|
|
204
|
-
onClose();
|
|
205
166
|
});
|
|
206
|
-
}, [editor, tableCellNode, clearTableSelection
|
|
167
|
+
}, [editor, tableCellNode, clearTableSelection]);
|
|
207
168
|
|
|
208
169
|
const deleteTableAtSelection = useCallback(() => {
|
|
209
170
|
editor.update(() => {
|
|
@@ -211,9 +172,8 @@ function TableActionMenu({
|
|
|
211
172
|
tableNode.remove();
|
|
212
173
|
|
|
213
174
|
clearTableSelection();
|
|
214
|
-
onClose();
|
|
215
175
|
});
|
|
216
|
-
}, [editor, tableCellNode, clearTableSelection
|
|
176
|
+
}, [editor, tableCellNode, clearTableSelection]);
|
|
217
177
|
|
|
218
178
|
const deleteTableColumnAtSelection = useCallback(() => {
|
|
219
179
|
editor.update(() => {
|
|
@@ -224,9 +184,8 @@ function TableActionMenu({
|
|
|
224
184
|
$deleteTableColumn(tableNode, tableColumnIndex);
|
|
225
185
|
|
|
226
186
|
clearTableSelection();
|
|
227
|
-
onClose();
|
|
228
187
|
});
|
|
229
|
-
}, [editor, tableCellNode, clearTableSelection
|
|
188
|
+
}, [editor, tableCellNode, clearTableSelection]);
|
|
230
189
|
|
|
231
190
|
const toggleTableRowIsHeader = useCallback(() => {
|
|
232
191
|
editor.update(() => {
|
|
@@ -255,9 +214,8 @@ function TableActionMenu({
|
|
|
255
214
|
});
|
|
256
215
|
|
|
257
216
|
clearTableSelection();
|
|
258
|
-
onClose();
|
|
259
217
|
});
|
|
260
|
-
}, [editor, tableCellNode, clearTableSelection
|
|
218
|
+
}, [editor, tableCellNode, clearTableSelection]);
|
|
261
219
|
|
|
262
220
|
const toggleTableColumnIsHeader = useCallback(() => {
|
|
263
221
|
editor.update(() => {
|
|
@@ -290,79 +248,59 @@ function TableActionMenu({
|
|
|
290
248
|
}
|
|
291
249
|
|
|
292
250
|
clearTableSelection();
|
|
293
|
-
onClose();
|
|
294
251
|
});
|
|
295
|
-
}, [editor, tableCellNode, clearTableSelection
|
|
296
|
-
|
|
297
|
-
return
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
<
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
</
|
|
315
|
-
<
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
</
|
|
321
|
-
<
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
<button className="item" onClick={() => deleteTableRowAtSelection()}>
|
|
331
|
-
<span className="text-sm">Delete row</span>
|
|
332
|
-
</button>
|
|
333
|
-
<button className="item" onClick={() => deleteTableAtSelection()}>
|
|
334
|
-
<span className="text-sm">Delete table</span>
|
|
335
|
-
</button>
|
|
336
|
-
<hr className="my-1" />
|
|
337
|
-
<button className="item" onClick={() => toggleTableRowIsHeader()}>
|
|
338
|
-
<span className="text-sm">
|
|
339
|
-
{(tableCellNode.__headerState & TableCellHeaderStates.ROW) === TableCellHeaderStates.ROW ? 'Remove' : 'Add'}{' '}
|
|
340
|
-
row header
|
|
341
|
-
</span>
|
|
342
|
-
</button>
|
|
343
|
-
<button className="item" onClick={() => toggleTableColumnIsHeader()}>
|
|
344
|
-
<span className="text-sm">
|
|
345
|
-
{(tableCellNode.__headerState & TableCellHeaderStates.COLUMN) === TableCellHeaderStates.COLUMN
|
|
346
|
-
? 'Remove'
|
|
347
|
-
: 'Add'}{' '}
|
|
348
|
-
column header
|
|
349
|
-
</span>
|
|
350
|
-
</button>
|
|
351
|
-
</div>,
|
|
352
|
-
document.body,
|
|
252
|
+
}, [editor, tableCellNode, clearTableSelection]);
|
|
253
|
+
|
|
254
|
+
return (
|
|
255
|
+
<>
|
|
256
|
+
<DropdownMenu.Item onSelect={() => insertTableRowAtSelection(false)}>
|
|
257
|
+
Insert {selectionCounts.rows === 1 ? 'row' : `${selectionCounts.rows} rows`} above
|
|
258
|
+
</DropdownMenu.Item>
|
|
259
|
+
<DropdownMenu.Item onSelect={() => insertTableRowAtSelection(true)}>
|
|
260
|
+
Insert {selectionCounts.rows === 1 ? 'row' : `${selectionCounts.rows} rows`} below
|
|
261
|
+
</DropdownMenu.Item>
|
|
262
|
+
<DropdownMenu.Item onSelect={() => insertTableColumnAtSelection(false)}>
|
|
263
|
+
Insert {selectionCounts.columns === 1 ? 'column' : `${selectionCounts.columns} columns`} left
|
|
264
|
+
</DropdownMenu.Item>
|
|
265
|
+
<DropdownMenu.Item onSelect={() => insertTableColumnAtSelection(true)}>
|
|
266
|
+
Insert {selectionCounts.columns === 1 ? 'column' : `${selectionCounts.columns} columns`} right
|
|
267
|
+
</DropdownMenu.Item>
|
|
268
|
+
<DropdownMenu.Item onSelect={() => toggleTableRowIsHeader()}>
|
|
269
|
+
{(tableCellNode.__headerState & TableCellHeaderStates.ROW) === TableCellHeaderStates.ROW ? 'Remove' : 'Add'} row
|
|
270
|
+
header
|
|
271
|
+
</DropdownMenu.Item>
|
|
272
|
+
<DropdownMenu.Item onSelect={() => toggleTableColumnIsHeader()}>
|
|
273
|
+
{(tableCellNode.__headerState & TableCellHeaderStates.COLUMN) === TableCellHeaderStates.COLUMN
|
|
274
|
+
? 'Remove'
|
|
275
|
+
: 'Add'}{' '}
|
|
276
|
+
column header
|
|
277
|
+
</DropdownMenu.Item>
|
|
278
|
+
<DropdownMenu.Separator />
|
|
279
|
+
{tableStats.columns > 1 && (
|
|
280
|
+
<DropdownMenu.Item onSelect={() => deleteTableColumnAtSelection()}>Delete column</DropdownMenu.Item>
|
|
281
|
+
)}
|
|
282
|
+
{tableStats.rows > 1 && (
|
|
283
|
+
<DropdownMenu.Item onSelect={() => deleteTableRowAtSelection()}>Delete row</DropdownMenu.Item>
|
|
284
|
+
)}
|
|
285
|
+
<DropdownMenu.Item onSelect={() => deleteTableAtSelection()}>Delete table</DropdownMenu.Item>
|
|
286
|
+
</>
|
|
353
287
|
);
|
|
354
288
|
}
|
|
355
289
|
|
|
356
|
-
function TableCellActionMenuContainer({ anchorElem }: { anchorElem: HTMLElement })
|
|
290
|
+
function TableCellActionMenuContainer({ anchorElem }: { anchorElem: HTMLElement }) {
|
|
357
291
|
const [editor] = useLexicalComposerContext();
|
|
358
292
|
|
|
359
293
|
const menuButtonRef = useRef(null);
|
|
360
|
-
const menuRootRef = useRef(null);
|
|
361
|
-
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
|
362
294
|
|
|
295
|
+
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
|
363
296
|
const [tableCellNode, setTableMenuCellNode] = useState<TableCellNode | null>(null);
|
|
297
|
+
const [tableStats, setTablestats] = useState<TableStats>({ rows: 1, columns: 1 });
|
|
364
298
|
|
|
365
299
|
const moveMenu = useCallback(() => {
|
|
300
|
+
if (isMenuOpen) {
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
|
|
366
304
|
const menu = menuButtonRef.current;
|
|
367
305
|
const selection = $getSelection();
|
|
368
306
|
const nativeSelection = window.getSelection();
|
|
@@ -396,10 +334,26 @@ function TableCellActionMenuContainer({ anchorElem }: { anchorElem: HTMLElement
|
|
|
396
334
|
}
|
|
397
335
|
|
|
398
336
|
setTableMenuCellNode(tableCellNodeFromSelection);
|
|
337
|
+
|
|
338
|
+
let rows = 1;
|
|
339
|
+
let columns = 1;
|
|
340
|
+
const parentRowNode = tableCellNodeFromSelection.getParent();
|
|
341
|
+
if ($isTableRowNode(parentRowNode)) {
|
|
342
|
+
const parentTableNode = parentRowNode.getParent();
|
|
343
|
+
if ($isTableNode(parentTableNode)) {
|
|
344
|
+
rows = parentTableNode.getChildrenSize();
|
|
345
|
+
columns = parentRowNode.getChildrenSize();
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
setTablestats({
|
|
350
|
+
rows,
|
|
351
|
+
columns,
|
|
352
|
+
});
|
|
399
353
|
} else if (!activeElement) {
|
|
400
354
|
setTableMenuCellNode(null);
|
|
401
355
|
}
|
|
402
|
-
}, [editor]);
|
|
356
|
+
}, [editor, isMenuOpen]);
|
|
403
357
|
|
|
404
358
|
useEffect(() => {
|
|
405
359
|
return editor.registerUpdateListener(() => {
|
|
@@ -432,40 +386,17 @@ function TableCellActionMenuContainer({ anchorElem }: { anchorElem: HTMLElement
|
|
|
432
386
|
}
|
|
433
387
|
}, [menuButtonRef, tableCellNode, editor, anchorElem]);
|
|
434
388
|
|
|
435
|
-
const prevTableCellDOM = useRef(tableCellNode);
|
|
436
|
-
|
|
437
|
-
useEffect(() => {
|
|
438
|
-
if (prevTableCellDOM.current !== tableCellNode) {
|
|
439
|
-
setIsMenuOpen(false);
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
prevTableCellDOM.current = tableCellNode;
|
|
443
|
-
}, [prevTableCellDOM, tableCellNode]);
|
|
444
|
-
|
|
445
389
|
return (
|
|
446
390
|
<div className="table-cell-action-button-container" ref={menuButtonRef}>
|
|
447
391
|
{tableCellNode != null && (
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
e.stopPropagation();
|
|
454
|
-
setIsMenuOpen(!isMenuOpen);
|
|
455
|
-
}}
|
|
456
|
-
ref={menuRootRef}
|
|
457
|
-
>
|
|
392
|
+
<DropdownMenu.Root
|
|
393
|
+
onOpenChange={isOpen => setIsMenuOpen(isOpen)}
|
|
394
|
+
content={<TableActionMenu tableCellNode={tableCellNode} tableStats={tableStats} />}
|
|
395
|
+
>
|
|
396
|
+
<IconButton size="xs" className="table-cell-action-button">
|
|
458
397
|
<Icon.Arrow />
|
|
459
398
|
</IconButton>
|
|
460
|
-
|
|
461
|
-
<TableActionMenu
|
|
462
|
-
contextRef={menuRootRef}
|
|
463
|
-
setIsMenuOpen={setIsMenuOpen}
|
|
464
|
-
onClose={() => setIsMenuOpen(false)}
|
|
465
|
-
tableCellNode={tableCellNode}
|
|
466
|
-
/>
|
|
467
|
-
)}
|
|
468
|
-
</>
|
|
399
|
+
</DropdownMenu.Root>
|
|
469
400
|
)}
|
|
470
401
|
</div>
|
|
471
402
|
);
|
|
@@ -62,19 +62,24 @@ import type { CrystallizeRichTextActionMenuItem } from '../../types/types';
|
|
|
62
62
|
import { IS_APPLE } from '../../utils/environment';
|
|
63
63
|
import { getSelectedNode } from '../../utils/getSelectedNode';
|
|
64
64
|
import { sanitizeUrl } from '../../utils/url';
|
|
65
|
-
import { InsertNewTableDialog } from '../TablePlugin';
|
|
66
65
|
import ActionsPlugin from './../ActionsPlugin';
|
|
66
|
+
import { InsertTableDialog } from './insert-table';
|
|
67
67
|
|
|
68
|
-
const
|
|
69
|
-
bullet: 'Bulleted List',
|
|
70
|
-
check: 'Check List',
|
|
71
|
-
code: 'Code Block',
|
|
68
|
+
const headingTypeToBlockName: Record<HeadingTagType, string> = {
|
|
72
69
|
h1: 'Heading 1',
|
|
73
70
|
h2: 'Heading 2',
|
|
74
71
|
h3: 'Heading 3',
|
|
75
72
|
h4: 'Heading 4',
|
|
76
73
|
h5: 'Heading 5',
|
|
77
74
|
h6: 'Heading 6',
|
|
75
|
+
};
|
|
76
|
+
const headings = Object.keys(headingTypeToBlockName) as HeadingTagType[];
|
|
77
|
+
|
|
78
|
+
const blockTypeToBlockName = {
|
|
79
|
+
...headingTypeToBlockName,
|
|
80
|
+
bullet: 'Bulleted List',
|
|
81
|
+
check: 'Check List',
|
|
82
|
+
code: 'Code Block',
|
|
78
83
|
number: 'Numbered List',
|
|
79
84
|
paragraph: 'Normal',
|
|
80
85
|
quote: 'Quote',
|
|
@@ -204,36 +209,18 @@ function BlockFormatDropDown({
|
|
|
204
209
|
Normal
|
|
205
210
|
</span>
|
|
206
211
|
</DropdownMenu.Item>
|
|
207
|
-
|
|
208
|
-
<
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
className={`icon h2 border w-6 h-6 rounded-md bg-no-repeat bg-center bg-[length:18px_18px] ${
|
|
220
|
-
blockType === 'h2' ? 'opacity-100 bg-purple-50-900' : 'opacity-60'
|
|
221
|
-
}`}
|
|
222
|
-
/>
|
|
223
|
-
<span className={`${blockType === 'h2' ? 'font-bold' : 'font-normal'} text-sm px-3 min-w-[150px]`}>
|
|
224
|
-
Heading 2
|
|
225
|
-
</span>
|
|
226
|
-
</DropdownMenu.Item>
|
|
227
|
-
<DropdownMenu.Item onClick={() => formatHeading('h3')}>
|
|
228
|
-
<i
|
|
229
|
-
className={`icon h3 border w-6 h-6 rounded-md bg-no-repeat bg-center bg-[length:18px_18px] ${
|
|
230
|
-
blockType === 'h3' ? 'opacity-100 bg-purple-50-900' : 'opacity-60'
|
|
231
|
-
}`}
|
|
232
|
-
/>
|
|
233
|
-
<span className={`${blockType === 'h3' ? 'font-bold' : 'font-normal'} text-sm px-3 min-w-[150px]`}>
|
|
234
|
-
Heading 3
|
|
235
|
-
</span>
|
|
236
|
-
</DropdownMenu.Item>
|
|
212
|
+
{headings.map(headingSize => (
|
|
213
|
+
<DropdownMenu.Item key={headingSize} onClick={() => formatHeading(headingSize)}>
|
|
214
|
+
<i
|
|
215
|
+
className={`icon ${headingSize} border w-6 h-6 rounded-md bg-no-repeat bg-center bg-[length:18px_18px] ${
|
|
216
|
+
blockType === headingSize ? 'opacity-100 bg-purple-50-900' : 'opacity-60'
|
|
217
|
+
}`}
|
|
218
|
+
/>
|
|
219
|
+
<span className={`${blockType === headingSize ? 'font-bold' : 'font-normal'} text-sm px-3 min-w-[150px]`}>
|
|
220
|
+
{headingTypeToBlockName[headingSize]}
|
|
221
|
+
</span>
|
|
222
|
+
</DropdownMenu.Item>
|
|
223
|
+
))}
|
|
237
224
|
<DropdownMenu.Item onClick={formatBulletList}>
|
|
238
225
|
<i
|
|
239
226
|
className={`icon bullet-list border w-6 h-6 rounded-md bg-no-repeat bg-center bg-[length:18px_18px] ${
|
|
@@ -713,7 +700,7 @@ export default function ToolbarPlugin({
|
|
|
713
700
|
Define your starting point of a table, you can add and remove columns and rows after creation.
|
|
714
701
|
</Dialog.Description>
|
|
715
702
|
<div className="items-center justify-between">
|
|
716
|
-
<
|
|
703
|
+
<InsertTableDialog activeEditor={activeEditor} />
|
|
717
704
|
</div>
|
|
718
705
|
</Dialog.Content>
|
|
719
706
|
</div>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import type { LexicalEditor } from 'lexical';
|
|
3
|
+
import { INSERT_TABLE_COMMAND } from '@lexical/table';
|
|
4
|
+
|
|
5
|
+
import { Button } from '../../../button';
|
|
6
|
+
import { Dialog } from '../../../dialog';
|
|
7
|
+
import { InputWithLabel } from '../../../input-with-label';
|
|
8
|
+
|
|
9
|
+
export function InsertTableDialog({ activeEditor }: { activeEditor: LexicalEditor }) {
|
|
10
|
+
const [rows, setRows] = useState('5');
|
|
11
|
+
const [columns, setColumns] = useState('5');
|
|
12
|
+
|
|
13
|
+
const onClick = () => {
|
|
14
|
+
if (parseInt(rows) < 1 || parseInt(columns) < 1) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
activeEditor.dispatchCommand(INSERT_TABLE_COMMAND, {
|
|
18
|
+
columns,
|
|
19
|
+
rows,
|
|
20
|
+
includeHeaders: {
|
|
21
|
+
columns: false,
|
|
22
|
+
rows: false,
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<>
|
|
29
|
+
<div className="grid grid-cols-[1fr_1px_1fr] border border-gray-100-800 border-solid shadow-sm rounded-md ">
|
|
30
|
+
<InputWithLabel
|
|
31
|
+
label="Rows"
|
|
32
|
+
value={rows}
|
|
33
|
+
placeholder="0"
|
|
34
|
+
type="text"
|
|
35
|
+
inputMode="numeric"
|
|
36
|
+
onChange={e => setRows(e.target.value)}
|
|
37
|
+
/>
|
|
38
|
+
<span className="h-full bg-gray-100-800" />
|
|
39
|
+
<InputWithLabel
|
|
40
|
+
type="text"
|
|
41
|
+
label="Columns"
|
|
42
|
+
placeholder="0"
|
|
43
|
+
value={columns}
|
|
44
|
+
inputMode="numeric"
|
|
45
|
+
onChange={e => setColumns(e.target.value)}
|
|
46
|
+
/>
|
|
47
|
+
</div>
|
|
48
|
+
<div className="flex justify-end mt-3">
|
|
49
|
+
<Button as={Dialog.Close} size="sm" intent="action" aria-label="Confirm" onClick={onClick}>
|
|
50
|
+
Confirm
|
|
51
|
+
</Button>
|
|
52
|
+
</div>
|
|
53
|
+
</>
|
|
54
|
+
);
|
|
55
|
+
}
|