@quadrats/react 1.0.0 → 1.1.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.
Files changed (108) hide show
  1. package/card/components/Card.js +83 -75
  2. package/card/index.cjs.js +82 -74
  3. package/carousel/components/Carousel.js +32 -28
  4. package/carousel/index.cjs.js +32 -28
  5. package/components/Tooltip/index.js +5 -2
  6. package/components/index.cjs.js +5 -2
  7. package/embed/renderers/base/components/BaseEmbedElement.js +51 -43
  8. package/embed/renderers/base/index.cjs.js +50 -42
  9. package/image/components/Image.js +34 -26
  10. package/image/createReactImage.js +1 -1
  11. package/image/index.cjs.js +34 -26
  12. package/package.json +4 -4
  13. package/table/components/Table.d.ts +9 -0
  14. package/table/components/Table.js +231 -0
  15. package/table/components/TableBody.d.ts +5 -0
  16. package/table/components/TableBody.js +8 -0
  17. package/table/components/TableCell.d.ts +5 -0
  18. package/table/components/TableCell.js +191 -0
  19. package/table/components/TableHeader.d.ts +5 -0
  20. package/table/components/TableHeader.js +13 -0
  21. package/table/components/TableMain.d.ts +5 -0
  22. package/table/components/TableMain.js +225 -0
  23. package/table/components/TableRow.d.ts +5 -0
  24. package/table/components/TableRow.js +8 -0
  25. package/table/components/TableTitle.d.ts +5 -0
  26. package/table/components/TableTitle.js +18 -0
  27. package/table/contexts/TableActionsContext.d.ts +3 -0
  28. package/table/contexts/TableActionsContext.js +5 -0
  29. package/table/contexts/TableHeaderContext.d.ts +2 -0
  30. package/table/contexts/TableHeaderContext.js +7 -0
  31. package/table/contexts/TableMetadataContext.d.ts +3 -0
  32. package/table/contexts/TableMetadataContext.js +5 -0
  33. package/table/contexts/TableScrollContext.d.ts +2 -0
  34. package/table/contexts/TableScrollContext.js +9 -0
  35. package/table/contexts/TableStateContext.d.ts +3 -0
  36. package/table/contexts/TableStateContext.js +5 -0
  37. package/table/createReactTable.d.ts +4 -0
  38. package/table/createReactTable.js +297 -0
  39. package/table/defaultRenderTableElements.d.ts +2 -0
  40. package/table/defaultRenderTableElements.js +20 -0
  41. package/table/hooks/useColumnResize.d.ts +12 -0
  42. package/table/hooks/useColumnResize.js +139 -0
  43. package/table/hooks/useTableActions.d.ts +25 -0
  44. package/table/hooks/useTableActions.js +886 -0
  45. package/table/hooks/useTableActionsContext.d.ts +1 -0
  46. package/table/hooks/useTableActionsContext.js +12 -0
  47. package/table/hooks/useTableCell.d.ts +16 -0
  48. package/table/hooks/useTableCell.js +166 -0
  49. package/table/hooks/useTableCellToolbarActions.d.ts +34 -0
  50. package/table/hooks/useTableCellToolbarActions.js +404 -0
  51. package/table/hooks/useTableMetadata.d.ts +1 -0
  52. package/table/hooks/useTableMetadata.js +12 -0
  53. package/table/hooks/useTableStateContext.d.ts +1 -0
  54. package/table/hooks/useTableStateContext.js +12 -0
  55. package/table/hooks/useTableStates.d.ts +18 -0
  56. package/table/hooks/useTableStates.js +14 -0
  57. package/table/index.cjs.js +3254 -0
  58. package/table/index.d.ts +16 -0
  59. package/table/index.js +24 -0
  60. package/table/jsx-serializer/components/Table.d.ts +3 -0
  61. package/table/jsx-serializer/components/Table.js +7 -0
  62. package/table/jsx-serializer/components/TableBody.d.ts +3 -0
  63. package/table/jsx-serializer/components/TableBody.js +7 -0
  64. package/table/jsx-serializer/components/TableCell.d.ts +5 -0
  65. package/table/jsx-serializer/components/TableCell.js +33 -0
  66. package/table/jsx-serializer/components/TableHeader.d.ts +3 -0
  67. package/table/jsx-serializer/components/TableHeader.js +10 -0
  68. package/table/jsx-serializer/components/TableMain.d.ts +6 -0
  69. package/table/jsx-serializer/components/TableMain.js +18 -0
  70. package/table/jsx-serializer/components/TableRow.d.ts +3 -0
  71. package/table/jsx-serializer/components/TableRow.js +7 -0
  72. package/table/jsx-serializer/components/TableTitle.d.ts +3 -0
  73. package/table/jsx-serializer/components/TableTitle.js +7 -0
  74. package/table/jsx-serializer/contexts/TableHeaderContext.d.ts +1 -0
  75. package/table/jsx-serializer/contexts/TableHeaderContext.js +5 -0
  76. package/table/jsx-serializer/contexts/TableScrollContext.d.ts +2 -0
  77. package/table/jsx-serializer/contexts/TableScrollContext.js +7 -0
  78. package/table/jsx-serializer/createJsxSerializeTable.d.ts +5 -0
  79. package/table/jsx-serializer/createJsxSerializeTable.js +113 -0
  80. package/table/jsx-serializer/defaultRenderTableElements.d.ts +2 -0
  81. package/table/jsx-serializer/defaultRenderTableElements.js +20 -0
  82. package/table/jsx-serializer/index.cjs.js +195 -0
  83. package/table/jsx-serializer/index.d.ts +3 -0
  84. package/table/jsx-serializer/index.js +2 -0
  85. package/table/jsx-serializer/package.json +7 -0
  86. package/table/jsx-serializer/typings.d.ts +12 -0
  87. package/table/package.json +10 -0
  88. package/table/table.css +1 -0
  89. package/table/table.scss +393 -0
  90. package/table/toolbar/TableToolbarIcon.d.ts +8 -0
  91. package/table/toolbar/TableToolbarIcon.js +12 -0
  92. package/table/toolbar/index.cjs.js +24 -0
  93. package/table/toolbar/index.d.ts +2 -0
  94. package/table/toolbar/index.js +2 -0
  95. package/table/toolbar/package.json +7 -0
  96. package/table/toolbar/useTableTool.d.ts +4 -0
  97. package/table/toolbar/useTableTool.js +13 -0
  98. package/table/typings.d.ts +66 -0
  99. package/table/utils/helper.d.ts +160 -0
  100. package/table/utils/helper.js +693 -0
  101. package/toolbar/components/InlineToolbar.d.ts +12 -11
  102. package/toolbar/components/InlineToolbar.js +23 -19
  103. package/toolbar/components/Toolbar.js +2 -2
  104. package/toolbar/index.cjs.js +24 -21
  105. package/toolbar/toolbar.css +1 -1
  106. package/toolbar/toolbar.scss +4 -1
  107. package/utils/index.cjs.js +7 -1
  108. package/utils/removePreviousElement.js +7 -1
@@ -13,50 +13,58 @@ const BaseEmbedElement = ({ element, haveAlignConfig = true, type = 'input', pla
13
13
  const { setEmbedModalConfig } = react.useModal();
14
14
  const editor = react.useSlateStatic();
15
15
  const path = react.ReactEditor.findPath(editor, element);
16
- return (React.createElement("div", { className: "qdr-embed" }, children(React.createElement(toolbar.InlineToolbar, { className: "qdr-embed__inline-toolbar", leftIcons: haveAlignConfig
17
- ? [
18
- {
19
- icon: icons.AlignLeft,
20
- onClick: () => {
21
- core.Transforms.setNodes(editor, { align: 'left' }, { at: path });
22
- },
23
- active: element.align === 'left' || !element.align,
24
- },
25
- {
26
- icon: icons.AlignCenter,
27
- onClick: () => {
28
- core.Transforms.setNodes(editor, { align: 'center' }, { at: path });
29
- },
30
- active: element.align === 'center',
31
- },
32
- {
33
- icon: icons.AlignRight,
34
- onClick: () => {
35
- core.Transforms.setNodes(editor, { align: 'right' }, { at: path });
36
- },
37
- active: element.align === 'right',
38
- },
39
- ]
40
- : [], rightIcons: [
41
- {
42
- icon: icons.Edit,
43
- onClick: () => {
44
- setEmbedModalConfig({
45
- placeholder: placeholder || '',
46
- confirmText: confirmText || '',
47
- hint: hint || '',
48
- type,
49
- onConfirm: (value) => {
50
- onConfirm === null || onConfirm === void 0 ? void 0 : onConfirm(editor, path, value);
16
+ return (React.createElement("div", { className: "qdr-embed" }, children(React.createElement(toolbar.InlineToolbar, { className: "qdr-embed__inline-toolbar", iconGroups: [
17
+ haveAlignConfig
18
+ ? {
19
+ enabledBgColor: true,
20
+ icons: [
21
+ {
22
+ icon: icons.AlignLeft,
23
+ onClick: () => {
24
+ core.Transforms.setNodes(editor, { align: 'left' }, { at: path });
25
+ },
26
+ active: element.align === 'left' || !element.align,
51
27
  },
52
- });
53
- },
54
- },
28
+ {
29
+ icon: icons.AlignCenter,
30
+ onClick: () => {
31
+ core.Transforms.setNodes(editor, { align: 'center' }, { at: path });
32
+ },
33
+ active: element.align === 'center',
34
+ },
35
+ {
36
+ icon: icons.AlignRight,
37
+ onClick: () => {
38
+ core.Transforms.setNodes(editor, { align: 'right' }, { at: path });
39
+ },
40
+ active: element.align === 'right',
41
+ },
42
+ ],
43
+ }
44
+ : { icons: [] },
55
45
  {
56
- icon: icons.Trash,
57
- onClick: () => {
58
- core.Transforms.removeNodes(editor, { at: path });
59
- },
46
+ icons: [
47
+ {
48
+ icon: icons.Edit,
49
+ onClick: () => {
50
+ setEmbedModalConfig({
51
+ placeholder: placeholder || '',
52
+ confirmText: confirmText || '',
53
+ hint: hint || '',
54
+ type,
55
+ onConfirm: (value) => {
56
+ onConfirm === null || onConfirm === void 0 ? void 0 : onConfirm(editor, path, value);
57
+ },
58
+ });
59
+ },
60
+ },
61
+ {
62
+ icon: icons.Trash,
63
+ onClick: () => {
64
+ core.Transforms.removeNodes(editor, { at: path });
65
+ },
66
+ },
67
+ ],
60
68
  },
61
69
  ] }))));
62
70
  };
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { Editor, Element, Transforms } from '@quadrats/core';
3
- import { Trash, AlignLeft, AlignCenter, AlignRight } from '@quadrats/icons';
3
+ import { AlignLeft, AlignCenter, AlignRight, Trash } from '@quadrats/icons';
4
4
  import { useSlateStatic, ReactEditor } from '@quadrats/react';
5
5
  import { InlineToolbar } from '@quadrats/react/toolbar';
6
6
 
@@ -22,34 +22,42 @@ function Image(props) {
22
22
  return (React.createElement("div", Object.assign({}, attributes, { className: "qdr-image qdr-image--with-inline-toolbar", onClick: () => Transforms.select(editor, ReactEditor.findPath(editor, element)), onMouseDown: (event) => event.preventDefault(), role: "img" }),
23
23
  React.createElement("div", { className: "qdr-image__spacer" }, children),
24
24
  React.createElement("div", { contentEditable: false, style: { position: 'relative' } },
25
- React.createElement(InlineToolbar, { className: "qdr-image__inline-toolbar", leftIcons: [
25
+ React.createElement(InlineToolbar, { className: "qdr-image__inline-toolbar", iconGroups: [
26
26
  {
27
- icon: AlignLeft,
28
- onClick: () => {
29
- Transforms.setNodes(editor, { align: 'start' }, { at: parentPath });
30
- },
31
- active: parentNode.align === 'start' || !parentNode.align,
27
+ enabledBgColor: true,
28
+ icons: [
29
+ {
30
+ icon: AlignLeft,
31
+ onClick: () => {
32
+ Transforms.setNodes(editor, { align: 'start' }, { at: parentPath });
33
+ },
34
+ active: parentNode.align === 'start' || !parentNode.align,
35
+ },
36
+ {
37
+ icon: AlignCenter,
38
+ onClick: () => {
39
+ Transforms.setNodes(editor, { align: 'center' }, { at: parentPath });
40
+ },
41
+ active: parentNode.align === 'center',
42
+ },
43
+ {
44
+ icon: AlignRight,
45
+ onClick: () => {
46
+ Transforms.setNodes(editor, { align: 'end' }, { at: parentPath });
47
+ },
48
+ active: parentNode.align === 'end',
49
+ },
50
+ ],
32
51
  },
33
52
  {
34
- icon: AlignCenter,
35
- onClick: () => {
36
- Transforms.setNodes(editor, { align: 'center' }, { at: parentPath });
37
- },
38
- active: parentNode.align === 'center',
39
- },
40
- {
41
- icon: AlignRight,
42
- onClick: () => {
43
- Transforms.setNodes(editor, { align: 'end' }, { at: parentPath });
44
- },
45
- active: parentNode.align === 'end',
46
- },
47
- ], rightIcons: [
48
- {
49
- icon: Trash,
50
- onClick: () => {
51
- Transforms.removeNodes(editor, { at: parentPath });
52
- },
53
+ icons: [
54
+ {
55
+ icon: Trash,
56
+ onClick: () => {
57
+ Transforms.removeNodes(editor, { at: parentPath });
58
+ },
59
+ },
60
+ ],
53
61
  },
54
62
  ] }),
55
63
  React.createElement("img", {
@@ -101,7 +101,7 @@ function createReactImage(options = {}, getUploadOptions) {
101
101
  })
102
102
  .reduce((prev, imageFile) => __awaiter(this, void 0, void 0, function* () {
103
103
  yield prev;
104
- return readFileAsDataURL(imageFile).then(dataURL => core.insertImage(editor, dataURL));
104
+ return readFileAsDataURL(imageFile).then((dataURL) => core.insertImage(editor, dataURL));
105
105
  }), Promise.resolve());
106
106
  return;
107
107
  }
@@ -41,34 +41,42 @@ function Image(props) {
41
41
  return (React.createElement("div", Object.assign({}, attributes, { className: "qdr-image qdr-image--with-inline-toolbar", onClick: () => core.Transforms.select(editor, react.ReactEditor.findPath(editor, element)), onMouseDown: (event) => event.preventDefault(), role: "img" }),
42
42
  React.createElement("div", { className: "qdr-image__spacer" }, children),
43
43
  React.createElement("div", { contentEditable: false, style: { position: 'relative' } },
44
- React.createElement(toolbar.InlineToolbar, { className: "qdr-image__inline-toolbar", leftIcons: [
44
+ React.createElement(toolbar.InlineToolbar, { className: "qdr-image__inline-toolbar", iconGroups: [
45
45
  {
46
- icon: icons.AlignLeft,
47
- onClick: () => {
48
- core.Transforms.setNodes(editor, { align: 'start' }, { at: parentPath });
49
- },
50
- active: parentNode.align === 'start' || !parentNode.align,
46
+ enabledBgColor: true,
47
+ icons: [
48
+ {
49
+ icon: icons.AlignLeft,
50
+ onClick: () => {
51
+ core.Transforms.setNodes(editor, { align: 'start' }, { at: parentPath });
52
+ },
53
+ active: parentNode.align === 'start' || !parentNode.align,
54
+ },
55
+ {
56
+ icon: icons.AlignCenter,
57
+ onClick: () => {
58
+ core.Transforms.setNodes(editor, { align: 'center' }, { at: parentPath });
59
+ },
60
+ active: parentNode.align === 'center',
61
+ },
62
+ {
63
+ icon: icons.AlignRight,
64
+ onClick: () => {
65
+ core.Transforms.setNodes(editor, { align: 'end' }, { at: parentPath });
66
+ },
67
+ active: parentNode.align === 'end',
68
+ },
69
+ ],
51
70
  },
52
71
  {
53
- icon: icons.AlignCenter,
54
- onClick: () => {
55
- core.Transforms.setNodes(editor, { align: 'center' }, { at: parentPath });
56
- },
57
- active: parentNode.align === 'center',
58
- },
59
- {
60
- icon: icons.AlignRight,
61
- onClick: () => {
62
- core.Transforms.setNodes(editor, { align: 'end' }, { at: parentPath });
63
- },
64
- active: parentNode.align === 'end',
65
- },
66
- ], rightIcons: [
67
- {
68
- icon: icons.Trash,
69
- onClick: () => {
70
- core.Transforms.removeNodes(editor, { at: parentPath });
71
- },
72
+ icons: [
73
+ {
74
+ icon: icons.Trash,
75
+ onClick: () => {
76
+ core.Transforms.removeNodes(editor, { at: parentPath });
77
+ },
78
+ },
79
+ ],
72
80
  },
73
81
  ] }),
74
82
  React.createElement("img", {
@@ -290,7 +298,7 @@ function createReactImage(options = {}, getUploadOptions) {
290
298
  })
291
299
  .reduce((prev, imageFile) => tslib.__awaiter(this, void 0, void 0, function* () {
292
300
  yield prev;
293
- return utils.readFileAsDataURL(imageFile).then(dataURL => core$1.insertImage(editor, dataURL));
301
+ return utils.readFileAsDataURL(imageFile).then((dataURL) => core$1.insertImage(editor, dataURL));
294
302
  }), Promise.resolve());
295
303
  return;
296
304
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quadrats/react",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "",
5
5
  "author": "Rytass",
6
6
  "homepage": "https://github.com/Quadrats/quadrats#readme",
@@ -20,9 +20,9 @@
20
20
  "url": "https://github.com/Quadrats/quadrats/issues"
21
21
  },
22
22
  "dependencies": {
23
- "@quadrats/common": "^1.0.0",
24
- "@quadrats/core": "^1.0.0",
25
- "@quadrats/icons": "^1.0.0",
23
+ "@quadrats/common": "^1.1.0",
24
+ "@quadrats/core": "^1.1.0",
25
+ "@quadrats/icons": "^1.1.0",
26
26
  "@quadrats/locales": "^1.0.0",
27
27
  "@quadrats/theme": "^1.0.0",
28
28
  "@quadrats/utils": "^1.0.0",
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import { RenderElementProps } from '@quadrats/react';
3
+ import { RenderTableElementProps } from '../typings';
4
+ declare function Table({ attributes, children, element, }: {
5
+ attributes?: RenderElementProps['attributes'];
6
+ children: RenderElementProps['children'];
7
+ element: RenderTableElementProps['element'];
8
+ }): React.JSX.Element;
9
+ export default Table;
@@ -0,0 +1,231 @@
1
+ import React, { useRef, useMemo, useCallback } from 'react';
2
+ import { Element } from '@quadrats/core';
3
+ import { TableActionsContext } from '../contexts/TableActionsContext.js';
4
+ import { TableMetadataContext } from '../contexts/TableMetadataContext.js';
5
+ import { TableStateContext } from '../contexts/TableStateContext.js';
6
+ import { TABLE_ROW_TYPE, TABLE_CELL_TYPE, TABLE_DEFAULT_MAX_COLUMNS, TABLE_DEFAULT_MAX_ROWS } from '@quadrats/common/table';
7
+ import { useTableActions } from '../hooks/useTableActions.js';
8
+ import { Icon } from '@quadrats/react/components';
9
+ import { Drag } from '@quadrats/icons';
10
+ import { useTableStates } from '../hooks/useTableStates.js';
11
+ import { getTableElements } from '../utils/helper.js';
12
+
13
+ function Table({ attributes, children, element, }) {
14
+ const { addColumn, addRow, addColumnAndRow, deleteRow, deleteColumn, moveRowToBody, moveRowToHeader, unsetColumnAsTitle, setColumnAsTitle, pinColumn, pinRow, unpinColumn, unpinRow, } = useTableActions(element);
15
+ const { tableSelectedOn, setTableSelectedOn, tableHoveredOn, setTableHoveredOn } = useTableStates();
16
+ const portalContainerRef = useRef(null);
17
+ // 優化表格結構計算 - 使用 getTableElements 重用邏輯
18
+ const { columnCount, rowCount, normalCols, bodyCount, tableElements } = useMemo(() => {
19
+ const elements = getTableElements(element);
20
+ if (!elements.tableMainElement) {
21
+ return {
22
+ columnCount: 0,
23
+ rowCount: 0,
24
+ treatAsTitleCols: 0,
25
+ normalCols: 0,
26
+ bodyCount: 0,
27
+ headerCount: 0,
28
+ tableElements: elements,
29
+ };
30
+ }
31
+ const headerRowElements = elements.tableHeaderElement
32
+ ? elements.tableHeaderElement.children.filter((child) => Element.isElement(child) && child.type.includes(TABLE_ROW_TYPE))
33
+ : [];
34
+ const bodyRowElements = elements.tableBodyElement
35
+ ? elements.tableBodyElement.children.filter((child) => Element.isElement(child) && child.type.includes(TABLE_ROW_TYPE))
36
+ : [];
37
+ const cols = bodyRowElements.length > 0 && Element.isElement(bodyRowElements[0]) ? bodyRowElements[0].children.length : 0;
38
+ const treatAsTitleCols = bodyRowElements.length > 0 && Element.isElement(bodyRowElements[0])
39
+ ? bodyRowElements[0].children.filter((row) => (Element.isElement(row) ? row.treatAsTitle : false)).length
40
+ : 0;
41
+ const rows = headerRowElements.length + bodyRowElements.length;
42
+ return {
43
+ columnCount: cols,
44
+ rowCount: rows,
45
+ headerCount: headerRowElements.length,
46
+ bodyCount: bodyRowElements.length,
47
+ treatAsTitleCols,
48
+ normalCols: cols - treatAsTitleCols,
49
+ tableElements: elements,
50
+ };
51
+ }, [element]);
52
+ // 預計算所有 cell positions
53
+ const cellPositions = useMemo(() => {
54
+ const positions = new Map();
55
+ if (!tableElements.tableMainElement)
56
+ return positions;
57
+ const { tableHeaderElement, tableBodyElement } = tableElements;
58
+ let globalRowIndex = 0;
59
+ // Process header rows
60
+ if (tableHeaderElement && Element.isElement(tableHeaderElement)) {
61
+ for (const row of tableHeaderElement.children) {
62
+ if (Element.isElement(row) && row.type.includes(TABLE_ROW_TYPE)) {
63
+ for (let colIndex = 0; colIndex < row.children.length; colIndex++) {
64
+ const cell = row.children[colIndex];
65
+ if (Element.isElement(cell) && cell.type.includes(TABLE_CELL_TYPE)) {
66
+ positions.set(cell, {
67
+ columnIndex: colIndex,
68
+ rowIndex: globalRowIndex,
69
+ });
70
+ }
71
+ }
72
+ globalRowIndex++;
73
+ }
74
+ }
75
+ }
76
+ // Process body rows
77
+ if (tableBodyElement && Element.isElement(tableBodyElement)) {
78
+ for (const row of tableBodyElement.children) {
79
+ if (Element.isElement(row) && row.type.includes(TABLE_ROW_TYPE)) {
80
+ for (let colIndex = 0; colIndex < row.children.length; colIndex++) {
81
+ const cell = row.children[colIndex];
82
+ if (Element.isElement(cell) && cell.type.includes(TABLE_CELL_TYPE)) {
83
+ positions.set(cell, {
84
+ columnIndex: colIndex,
85
+ rowIndex: globalRowIndex,
86
+ });
87
+ }
88
+ }
89
+ globalRowIndex++;
90
+ }
91
+ }
92
+ }
93
+ return positions;
94
+ }, [tableElements]);
95
+ // 預計算 pinned columns 和 rows
96
+ const { pinnedColumns, pinnedRows } = useMemo(() => {
97
+ const columns = new Set();
98
+ const rows = new Set();
99
+ if (!tableElements.tableBodyElement)
100
+ return { pinnedColumns: columns, pinnedRows: rows };
101
+ const { tableHeaderElement, tableBodyElement } = tableElements;
102
+ // 檢查 pinned columns - 只需要檢查第一個 body row
103
+ if (Element.isElement(tableBodyElement) && tableBodyElement.children.length > 0) {
104
+ const firstBodyRow = tableBodyElement.children[0];
105
+ if (Element.isElement(firstBodyRow) && firstBodyRow.type.includes(TABLE_ROW_TYPE)) {
106
+ for (let colIndex = 0; colIndex < firstBodyRow.children.length; colIndex++) {
107
+ const cell = firstBodyRow.children[colIndex];
108
+ if (Element.isElement(cell) &&
109
+ cell.type.includes(TABLE_CELL_TYPE) &&
110
+ cell.treatAsTitle &&
111
+ cell.pinned) {
112
+ columns.add(colIndex);
113
+ }
114
+ }
115
+ }
116
+ }
117
+ // 檢查 pinned rows - 只需要檢查 header rows
118
+ if (tableHeaderElement && Element.isElement(tableHeaderElement)) {
119
+ for (let rowIndex = 0; rowIndex < tableHeaderElement.children.length; rowIndex++) {
120
+ const row = tableHeaderElement.children[rowIndex];
121
+ if (Element.isElement(row) && row.type.includes(TABLE_ROW_TYPE)) {
122
+ // 檢查這一行的所有 cells 是否都是 pinned
123
+ const allCellsPinned = row.children.every((cell) => Element.isElement(cell) && cell.type.includes(TABLE_CELL_TYPE) && cell.pinned);
124
+ if (allCellsPinned) {
125
+ rows.add(rowIndex);
126
+ }
127
+ }
128
+ }
129
+ }
130
+ return { pinnedColumns: columns, pinnedRows: rows };
131
+ }, [tableElements]);
132
+ const isReachMaximumColumns = useMemo(() => {
133
+ return columnCount >= TABLE_DEFAULT_MAX_COLUMNS;
134
+ }, [columnCount]);
135
+ const isReachMaximumRows = useMemo(() => {
136
+ return TABLE_DEFAULT_MAX_ROWS > 0 ? rowCount >= TABLE_DEFAULT_MAX_ROWS : false;
137
+ }, [rowCount]);
138
+ const isReachMinimumNormalColumns = useMemo(() => {
139
+ return normalCols <= 1;
140
+ }, [normalCols]);
141
+ const isReachMinimumBodyRows = useMemo(() => {
142
+ return bodyCount <= 1;
143
+ }, [bodyCount]);
144
+ const isColumnPinned = useCallback((columnIndex) => {
145
+ return pinnedColumns.has(columnIndex);
146
+ }, [pinnedColumns]);
147
+ const isRowPinned = useCallback((rowIndex) => {
148
+ return pinnedRows.has(rowIndex);
149
+ }, [pinnedRows]);
150
+ const actionsValue = useMemo(() => ({
151
+ addColumn,
152
+ addRow,
153
+ addColumnAndRow,
154
+ deleteRow,
155
+ deleteColumn,
156
+ moveRowToBody,
157
+ moveRowToHeader,
158
+ unsetColumnAsTitle,
159
+ setColumnAsTitle,
160
+ pinColumn,
161
+ pinRow,
162
+ unpinColumn,
163
+ unpinRow,
164
+ }), [
165
+ addColumn,
166
+ addRow,
167
+ addColumnAndRow,
168
+ deleteRow,
169
+ deleteColumn,
170
+ moveRowToBody,
171
+ moveRowToHeader,
172
+ unsetColumnAsTitle,
173
+ setColumnAsTitle,
174
+ pinColumn,
175
+ pinRow,
176
+ unpinColumn,
177
+ unpinRow,
178
+ ]);
179
+ const metadataValue = useMemo(() => ({
180
+ tableElement: element,
181
+ columnCount,
182
+ rowCount,
183
+ portalContainerRef,
184
+ isReachMaximumColumns,
185
+ isReachMaximumRows,
186
+ isReachMinimumNormalColumns,
187
+ isReachMinimumBodyRows,
188
+ pinnedColumns,
189
+ pinnedRows,
190
+ cellPositions,
191
+ isColumnPinned,
192
+ isRowPinned,
193
+ }), [
194
+ element,
195
+ columnCount,
196
+ rowCount,
197
+ portalContainerRef,
198
+ isReachMaximumColumns,
199
+ isReachMaximumRows,
200
+ isReachMinimumNormalColumns,
201
+ isReachMinimumBodyRows,
202
+ pinnedColumns,
203
+ pinnedRows,
204
+ cellPositions,
205
+ isColumnPinned,
206
+ isRowPinned,
207
+ ]);
208
+ const stateValue = useMemo(() => ({
209
+ tableSelectedOn,
210
+ setTableSelectedOn,
211
+ tableHoveredOn,
212
+ setTableHoveredOn,
213
+ }), [tableSelectedOn, setTableSelectedOn, tableHoveredOn, setTableHoveredOn]);
214
+ return (React.createElement(TableActionsContext.Provider, { value: actionsValue },
215
+ React.createElement(TableMetadataContext.Provider, { value: metadataValue },
216
+ React.createElement(TableStateContext.Provider, { value: stateValue },
217
+ React.createElement("div", Object.assign({}, attributes, { className: "qdr-table" }),
218
+ children,
219
+ React.createElement("button", { type: "button", onClick: (evt) => {
220
+ evt.preventDefault();
221
+ evt.stopPropagation();
222
+ setTableSelectedOn((prev) => ((prev === null || prev === void 0 ? void 0 : prev.region) === 'table' ? undefined : { region: 'table' }));
223
+ }, onMouseDown: (evt) => {
224
+ evt.preventDefault();
225
+ evt.stopPropagation();
226
+ }, className: "qdr-table__selection", title: (tableSelectedOn === null || tableSelectedOn === void 0 ? void 0 : tableSelectedOn.region) === 'table' ? 'Deselect Table' : 'Select Table' },
227
+ React.createElement(Icon, { icon: Drag, width: 20, height: 20 })),
228
+ React.createElement("div", { ref: portalContainerRef, className: "qdr-table__portal-container", "data-slate-editor": false, contentEditable: false }))))));
229
+ }
230
+
231
+ export { Table as default };
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import { RenderElementProps } from '@quadrats/react';
3
+ import { TableElement } from '@quadrats/common/table';
4
+ declare function TableBody(props: RenderElementProps<TableElement>): React.JSX.Element;
5
+ export default TableBody;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+
3
+ function TableBody(props) {
4
+ const { attributes, children } = props;
5
+ return (React.createElement("tbody", Object.assign({}, attributes, { className: "qdr-table__body" }), children));
6
+ }
7
+
8
+ export { TableBody as default };
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import { RenderElementProps } from '@quadrats/react';
3
+ import { TableElement } from '@quadrats/common/table';
4
+ declare function TableCell(props: RenderElementProps<TableElement>): React.JSX.Element;
5
+ export default TableCell;