@quadrats/react 1.1.0 → 1.1.1
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/core/components/Quadrats.js +5 -2
- package/core/contexts/modal/CarouselModal/CarouselModal.js +14 -17
- package/index.cjs.js +19 -19
- package/package.json +3 -3
- package/table/components/ColumnDragButton.d.ts +10 -0
- package/table/components/ColumnDragButton.js +41 -0
- package/table/components/RowDragButton.d.ts +10 -0
- package/table/components/RowDragButton.js +42 -0
- package/table/components/Table.js +22 -17
- package/table/components/TableCell.js +129 -23
- package/table/components/TableDragLayer.d.ts +6 -0
- package/table/components/TableDragLayer.js +89 -0
- package/table/components/TableMain.js +14 -6
- package/table/contexts/TableActionsContext.d.ts +1 -1
- package/table/contexts/TableDragContext.d.ts +26 -0
- package/table/contexts/TableDragContext.js +26 -0
- package/table/hooks/useColumnResize.js +29 -0
- package/table/hooks/useTableActions.d.ts +2 -0
- package/table/hooks/useTableActions.js +217 -11
- package/table/hooks/useTableCellToolbarActions.js +126 -4
- package/table/index.cjs.js +873 -125
- package/table/index.js +3 -0
- package/table/table.css +1 -1
- package/table/table.scss +35 -0
- package/table/typings.d.ts +2 -0
- package/table/utils/helper.d.ts +34 -8
- package/table/utils/helper.js +178 -72
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useMemo } from 'react';
|
|
2
|
-
import { UnorderedList, OrderedList, Paragraph, AddRowAtBottom, AddRowAtTop, AddColumnAtLeft, AddColumnAtRight, Unpinned, Pinned, TableRemoveTitle, TableSetColumnTitle, TableSetRowTitle, AlignLeft, AlignCenter, AlignRight, Trash } from '@quadrats/icons';
|
|
2
|
+
import { UnorderedList, OrderedList, Paragraph, AddRowAtBottom, AddRowAtTop, AddColumnAtLeft, AddColumnAtRight, Unpinned, Pinned, TableRemoveTitle, TableSetColumnTitle, TableSetRowTitle, AlignLeft, AlignCenter, AlignRight, TableMoveDown, TableMoveUp, TableMoveRight, TableMoveLeft, Trash } from '@quadrats/icons';
|
|
3
3
|
import { Element, PARAGRAPH_TYPE } from '@quadrats/core';
|
|
4
4
|
import { LIST_TYPES } from '@quadrats/common/list';
|
|
5
5
|
import { useTableActionsContext } from './useTableActionsContext.js';
|
|
@@ -15,10 +15,10 @@ import { useSlateStatic } from 'slate-react';
|
|
|
15
15
|
function useTableCellToolbarActions({ element, cellPosition, isHeader, transformCellContent, }) {
|
|
16
16
|
const editor = useSlateStatic();
|
|
17
17
|
const { tableSelectedOn, setTableSelectedOn } = useTableStateContext();
|
|
18
|
-
const { tableElement, isReachMaximumColumns, isReachMinimumNormalColumns, isReachMinimumBodyRows, isColumnPinned, isRowPinned, } = useTableMetadata();
|
|
18
|
+
const { tableElement, columnCount, rowCount, isReachMaximumColumns, isReachMinimumNormalColumns, isReachMinimumBodyRows, isColumnPinned, isRowPinned, } = useTableMetadata();
|
|
19
19
|
const setAlign = useTableCellAlign(tableElement, editor);
|
|
20
20
|
const getAlign = useTableCellAlignStatus(tableElement, editor);
|
|
21
|
-
const { deleteRow, deleteColumn, addRow, addColumn, moveRowToBody, moveRowToHeader, unsetColumnAsTitle, setColumnAsTitle, pinColumn, unpinColumn, pinRow, unpinRow, } = useTableActionsContext();
|
|
21
|
+
const { deleteRow, deleteColumn, addRow, addColumn, moveRowToBody, moveRowToHeader, unsetColumnAsTitle, setColumnAsTitle, pinColumn, unpinColumn, pinRow, unpinRow, moveOrSwapRow, moveOrSwapColumn, } = useTableActionsContext();
|
|
22
22
|
// 獲取當前 cell 內容的類型(用於顯示對應的 icon)
|
|
23
23
|
const getCurrentContentType = useMemo(() => {
|
|
24
24
|
// 檢查 cell 的第一個 child 的類型
|
|
@@ -359,6 +359,116 @@ function useTableCellToolbarActions({ element, cellPosition, isHeader, transform
|
|
|
359
359
|
},
|
|
360
360
|
].filter((i) => i !== undefined);
|
|
361
361
|
}, [tableSelectedOn, addColumn, setTableSelectedOn, isReachMaximumColumns]);
|
|
362
|
+
// Row move actions
|
|
363
|
+
const rowMoveActions = useMemo(() => {
|
|
364
|
+
if ((tableSelectedOn === null || tableSelectedOn === void 0 ? void 0 : tableSelectedOn.region) !== 'row' || typeof tableSelectedOn.index !== 'number') {
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
const rowIndex = tableSelectedOn.index;
|
|
368
|
+
// 從 tableElement 獲取 header 和 body 的資訊
|
|
369
|
+
const tableMainElement = tableElement.children.find((child) => Element.isElement(child) && child.type.includes('table_main'));
|
|
370
|
+
if (!tableMainElement || !Element.isElement(tableMainElement)) {
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
const tableHeaderElement = tableMainElement.children.find((child) => Element.isElement(child) && child.type.includes('table_header'));
|
|
374
|
+
const headerRowCount = tableHeaderElement && Element.isElement(tableHeaderElement) ? tableHeaderElement.children.length : 0;
|
|
375
|
+
// 判斷當前列是在 header 還是 body 中
|
|
376
|
+
const currentInHeader = rowIndex < headerRowCount;
|
|
377
|
+
// 判斷上方和下方是否可以互換
|
|
378
|
+
const canMoveUp = rowIndex > 0; // 不在第一列
|
|
379
|
+
const canMoveDown = rowIndex < rowCount - 1; // 不在最後一列
|
|
380
|
+
// 檢查目標位置是否在相同的容器中(header 或 body)
|
|
381
|
+
const targetUpInHeader = rowIndex - 1 < headerRowCount;
|
|
382
|
+
const targetDownInHeader = rowIndex + 1 < headerRowCount;
|
|
383
|
+
// 標題列只能與標題列互換,一般列只能與一般列互換
|
|
384
|
+
const canSwapUp = canMoveUp && currentInHeader === targetUpInHeader;
|
|
385
|
+
const canSwapDown = canMoveDown && currentInHeader === targetDownInHeader;
|
|
386
|
+
return [
|
|
387
|
+
canSwapDown
|
|
388
|
+
? {
|
|
389
|
+
icon: TableMoveDown,
|
|
390
|
+
onClick: () => {
|
|
391
|
+
if (typeof tableSelectedOn.index === 'number') {
|
|
392
|
+
moveOrSwapRow(tableSelectedOn.index, tableSelectedOn.index + 1, 'swap');
|
|
393
|
+
setTableSelectedOn(undefined);
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
}
|
|
397
|
+
: undefined,
|
|
398
|
+
canSwapUp
|
|
399
|
+
? {
|
|
400
|
+
icon: TableMoveUp,
|
|
401
|
+
onClick: () => {
|
|
402
|
+
if (typeof tableSelectedOn.index === 'number') {
|
|
403
|
+
moveOrSwapRow(tableSelectedOn.index, tableSelectedOn.index - 1, 'swap');
|
|
404
|
+
setTableSelectedOn(undefined);
|
|
405
|
+
}
|
|
406
|
+
},
|
|
407
|
+
}
|
|
408
|
+
: undefined,
|
|
409
|
+
].filter((i) => i !== undefined);
|
|
410
|
+
}, [tableSelectedOn, setTableSelectedOn, rowCount, tableElement, moveOrSwapRow]);
|
|
411
|
+
// Column move actions
|
|
412
|
+
const columnMoveActions = useMemo(() => {
|
|
413
|
+
if ((tableSelectedOn === null || tableSelectedOn === void 0 ? void 0 : tableSelectedOn.region) !== 'column' || typeof tableSelectedOn.index !== 'number') {
|
|
414
|
+
return null;
|
|
415
|
+
}
|
|
416
|
+
const columnIndex = tableSelectedOn.index;
|
|
417
|
+
// 檢查當前行是否為標題行
|
|
418
|
+
const currentIsTitle = !!element.treatAsTitle;
|
|
419
|
+
// 判斷左右是否可以移動
|
|
420
|
+
const canMoveLeft = columnIndex > 0;
|
|
421
|
+
const canMoveRight = columnIndex < columnCount - 1;
|
|
422
|
+
// 檢查相鄰行是否為相同類型(都是標題行或都不是標題行)
|
|
423
|
+
const checkAdjacentColumnType = (adjacentIndex) => {
|
|
424
|
+
// 從 tableElement 中獲取相鄰行的 treatAsTitle 狀態
|
|
425
|
+
const tableMainElement = tableElement.children.find((child) => Element.isElement(child) && child.type.includes('table_main'));
|
|
426
|
+
if (!tableMainElement || !Element.isElement(tableMainElement)) {
|
|
427
|
+
return false;
|
|
428
|
+
}
|
|
429
|
+
const tableBodyElement = tableMainElement.children.find((child) => Element.isElement(child) && child.type.includes('table_body'));
|
|
430
|
+
if (!tableBodyElement || !Element.isElement(tableBodyElement)) {
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
// 從 body 的第一列獲取相鄰 cell 的 treatAsTitle 屬性
|
|
434
|
+
const firstRow = tableBodyElement.children[0];
|
|
435
|
+
if (!Element.isElement(firstRow)) {
|
|
436
|
+
return false;
|
|
437
|
+
}
|
|
438
|
+
const adjacentCell = firstRow.children[adjacentIndex];
|
|
439
|
+
if (!Element.isElement(adjacentCell)) {
|
|
440
|
+
return false;
|
|
441
|
+
}
|
|
442
|
+
return !!adjacentCell.treatAsTitle;
|
|
443
|
+
};
|
|
444
|
+
// 標題行只能與標題行互換,一般行只能與一般行互換
|
|
445
|
+
const canSwapLeft = canMoveLeft && currentIsTitle === checkAdjacentColumnType(columnIndex - 1);
|
|
446
|
+
const canSwapRight = canMoveRight && currentIsTitle === checkAdjacentColumnType(columnIndex + 1);
|
|
447
|
+
return [
|
|
448
|
+
canSwapRight
|
|
449
|
+
? {
|
|
450
|
+
icon: TableMoveRight,
|
|
451
|
+
onClick: () => {
|
|
452
|
+
if (typeof tableSelectedOn.index === 'number') {
|
|
453
|
+
moveOrSwapColumn(tableSelectedOn.index, tableSelectedOn.index + 1, 'swap');
|
|
454
|
+
setTableSelectedOn(undefined);
|
|
455
|
+
}
|
|
456
|
+
},
|
|
457
|
+
}
|
|
458
|
+
: undefined,
|
|
459
|
+
canSwapLeft
|
|
460
|
+
? {
|
|
461
|
+
icon: TableMoveLeft,
|
|
462
|
+
onClick: () => {
|
|
463
|
+
if (typeof tableSelectedOn.index === 'number') {
|
|
464
|
+
moveOrSwapColumn(tableSelectedOn.index, tableSelectedOn.index - 1, 'swap');
|
|
465
|
+
setTableSelectedOn(undefined);
|
|
466
|
+
}
|
|
467
|
+
},
|
|
468
|
+
}
|
|
469
|
+
: undefined,
|
|
470
|
+
].filter((i) => i !== undefined);
|
|
471
|
+
}, [tableSelectedOn, setTableSelectedOn, columnCount, element.treatAsTitle, tableElement, moveOrSwapColumn]);
|
|
362
472
|
// Delete actions
|
|
363
473
|
const deleteActions = useMemo(() => {
|
|
364
474
|
return [
|
|
@@ -390,11 +500,23 @@ function useTableCellToolbarActions({ element, cellPosition, isHeader, transform
|
|
|
390
500
|
{
|
|
391
501
|
icons: rowAddActions || columnAddActions || [],
|
|
392
502
|
},
|
|
503
|
+
{
|
|
504
|
+
icons: rowMoveActions || columnMoveActions || [],
|
|
505
|
+
},
|
|
393
506
|
{
|
|
394
507
|
icons: deleteActions,
|
|
395
508
|
},
|
|
396
509
|
];
|
|
397
|
-
}, [
|
|
510
|
+
}, [
|
|
511
|
+
rowActions,
|
|
512
|
+
columnActions,
|
|
513
|
+
columnAlignActions,
|
|
514
|
+
rowAddActions,
|
|
515
|
+
columnAddActions,
|
|
516
|
+
rowMoveActions,
|
|
517
|
+
columnMoveActions,
|
|
518
|
+
deleteActions,
|
|
519
|
+
]);
|
|
398
520
|
return {
|
|
399
521
|
focusToolbarIconGroups,
|
|
400
522
|
inlineToolbarIconGroups,
|