@superad/ui 0.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/LICENSE +21 -0
- package/README.md +42 -0
- package/es/Button/Button.d.mts +7 -0
- package/es/Button/Button.mjs +29 -0
- package/es/Button/Button.mjs.map +1 -0
- package/es/Button/index.d.mts +3 -0
- package/es/Button/index.d.ts +1 -0
- package/es/Button/index.js +1 -0
- package/es/Button/index.mjs +2 -0
- package/es/Button/style.mjs +33 -0
- package/es/Button/style.mjs.map +1 -0
- package/es/Button/type.d.mts +21 -0
- package/es/ConfigProvider/index.d.mts +9 -0
- package/es/ConfigProvider/index.d.ts +1 -0
- package/es/ConfigProvider/index.js +1 -0
- package/es/ConfigProvider/index.mjs +82 -0
- package/es/ConfigProvider/index.mjs.map +1 -0
- package/es/ConfigProvider/type.d.mts +24 -0
- package/es/DraggablePanel/DraggablePanel.d.mts +6 -0
- package/es/DraggablePanel/DraggablePanel.mjs +104 -0
- package/es/DraggablePanel/DraggablePanel.mjs.map +1 -0
- package/es/DraggablePanel/index.d.mts +3 -0
- package/es/DraggablePanel/index.d.ts +1 -0
- package/es/DraggablePanel/index.js +1 -0
- package/es/DraggablePanel/index.mjs +3 -0
- package/es/DraggablePanel/style.mjs +86 -0
- package/es/DraggablePanel/style.mjs.map +1 -0
- package/es/DraggablePanel/type.d.mts +27 -0
- package/es/Flex/Center.d.mts +7 -0
- package/es/Flex/Center.mjs +14 -0
- package/es/Flex/Center.mjs.map +1 -0
- package/es/Flex/FlexBasic.d.mts +6 -0
- package/es/Flex/FlexBasic.mjs +46 -0
- package/es/Flex/FlexBasic.mjs.map +1 -0
- package/es/Flex/Flexbox.d.mts +2 -0
- package/es/Flex/index.d.mts +5 -0
- package/es/Flex/index.d.ts +1 -0
- package/es/Flex/index.js +1 -0
- package/es/Flex/index.mjs +3 -0
- package/es/Flex/type.d.mts +35 -0
- package/es/Flex/utils.mjs +24 -0
- package/es/Flex/utils.mjs.map +1 -0
- package/es/FontLoader/index.d.mts +9 -0
- package/es/FontLoader/index.d.ts +1 -0
- package/es/FontLoader/index.js +1 -0
- package/es/FontLoader/index.mjs +23 -0
- package/es/FontLoader/index.mjs.map +1 -0
- package/es/GlobalFocusRing/index.d.mts +6 -0
- package/es/GlobalFocusRing/index.d.ts +1 -0
- package/es/GlobalFocusRing/index.js +1 -0
- package/es/GlobalFocusRing/index.mjs +204 -0
- package/es/GlobalFocusRing/index.mjs.map +1 -0
- package/es/GlobalFocusRing/style.mjs +35 -0
- package/es/GlobalFocusRing/style.mjs.map +1 -0
- package/es/Provider.d.mts +5 -0
- package/es/Table/canvas/canvasPalette.mjs +11 -0
- package/es/Table/canvas/canvasPalette.mjs.map +1 -0
- package/es/Table/canvas/chipPainters.mjs +408 -0
- package/es/Table/canvas/chipPainters.mjs.map +1 -0
- package/es/Table/canvas/controlPainters.mjs +193 -0
- package/es/Table/canvas/controlPainters.mjs.map +1 -0
- package/es/Table/canvas/groupTitle.mjs +181 -0
- package/es/Table/canvas/groupTitle.mjs.map +1 -0
- package/es/Table/canvas/paintUtils.mjs +70 -0
- package/es/Table/canvas/paintUtils.mjs.map +1 -0
- package/es/Table/canvas/rowSeries.mjs +130 -0
- package/es/Table/canvas/rowSeries.mjs.map +1 -0
- package/es/Table/canvas/textPainters.mjs +97 -0
- package/es/Table/canvas/textPainters.mjs.map +1 -0
- package/es/Table/canvas/theme.d.mts +14 -0
- package/es/Table/canvas/theme.mjs +276 -0
- package/es/Table/canvas/theme.mjs.map +1 -0
- package/es/Table/core/cellValue.d.mts +1 -0
- package/es/Table/core/cellValue.mjs +240 -0
- package/es/Table/core/cellValue.mjs.map +1 -0
- package/es/Table/core/rowSelection.mjs +138 -0
- package/es/Table/core/rowSelection.mjs.map +1 -0
- package/es/Table/core/size.mjs +60 -0
- package/es/Table/core/size.mjs.map +1 -0
- package/es/Table/core/tableI18n.d.mts +11 -0
- package/es/Table/core/tableI18n.mjs +123 -0
- package/es/Table/core/tableI18n.mjs.map +1 -0
- package/es/Table/core/tagTone.mjs +245 -0
- package/es/Table/core/tagTone.mjs.map +1 -0
- package/es/Table/core/zIndex.mjs +7 -0
- package/es/Table/core/zIndex.mjs.map +1 -0
- package/es/Table/index.d.mts +6 -0
- package/es/Table/index.d.ts +1 -0
- package/es/Table/index.js +1 -0
- package/es/Table/index.mjs +6 -0
- package/es/Table/react/Table.d.mts +9 -0
- package/es/Table/react/Table.mjs +407 -0
- package/es/Table/react/Table.mjs.map +1 -0
- package/es/Table/react/TableColumnSettings.mjs +65 -0
- package/es/Table/react/TableColumnSettings.mjs.map +1 -0
- package/es/Table/react/a11y.mjs +72 -0
- package/es/Table/react/a11y.mjs.map +1 -0
- package/es/Table/react/editors/base.mjs +427 -0
- package/es/Table/react/editors/base.mjs.map +1 -0
- package/es/Table/react/editors/inline.mjs +225 -0
- package/es/Table/react/editors/inline.mjs.map +1 -0
- package/es/Table/react/editors/picker.mjs +368 -0
- package/es/Table/react/editors/picker.mjs.map +1 -0
- package/es/Table/react/overlayChips.mjs +50 -0
- package/es/Table/react/overlayChips.mjs.map +1 -0
- package/es/Table/react/sameRenderInputs.mjs +50 -0
- package/es/Table/react/sameRenderInputs.mjs.map +1 -0
- package/es/Table/react/style.mjs +650 -0
- package/es/Table/react/style.mjs.map +1 -0
- package/es/Table/react/useTableCellEvents.mjs +32 -0
- package/es/Table/react/useTableCellEvents.mjs.map +1 -0
- package/es/Table/react/useTableColumnSettings.mjs +107 -0
- package/es/Table/react/useTableColumnSettings.mjs.map +1 -0
- package/es/Table/react/useTableEditorSync.mjs +41 -0
- package/es/Table/react/useTableEditorSync.mjs.map +1 -0
- package/es/Table/react/useTableHoverHint.mjs +62 -0
- package/es/Table/react/useTableHoverHint.mjs.map +1 -0
- package/es/Table/react/useTableKeyboard.mjs +41 -0
- package/es/Table/react/useTableKeyboard.mjs.map +1 -0
- package/es/Table/react/useTableRenderState.mjs +194 -0
- package/es/Table/react/useTableRenderState.mjs.map +1 -0
- package/es/Table/react/useTableScroll.mjs +33 -0
- package/es/Table/react/useTableScroll.mjs.map +1 -0
- package/es/Table/react/useTableSelectionInfo.mjs +48 -0
- package/es/Table/react/useTableSelectionInfo.mjs.map +1 -0
- package/es/Table/react/useTableVTableEvents.mjs +132 -0
- package/es/Table/react/useTableVTableEvents.mjs.map +1 -0
- package/es/Table/type.d.mts +279 -0
- package/es/Table/type.mjs +34 -0
- package/es/Table/type.mjs.map +1 -0
- package/es/Table/vtable/columns.d.mts +17 -0
- package/es/Table/vtable/columns.mjs +381 -0
- package/es/Table/vtable/columns.mjs.map +1 -0
- package/es/Table/vtable/frozenShadow.mjs +27 -0
- package/es/Table/vtable/frozenShadow.mjs.map +1 -0
- package/es/Table/vtable/interaction.mjs +175 -0
- package/es/Table/vtable/interaction.mjs.map +1 -0
- package/es/Table/vtable/option.d.mts +39 -0
- package/es/Table/vtable/option.mjs +232 -0
- package/es/Table/vtable/option.mjs.map +1 -0
- package/es/Table/vtable/seriesSelection.mjs +374 -0
- package/es/Table/vtable/seriesSelection.mjs.map +1 -0
- package/es/Table/vtable/vtableAdapter.mjs +96 -0
- package/es/Table/vtable/vtableAdapter.mjs.map +1 -0
- package/es/ThemeProvider/AppElementContext.d.mts +5 -0
- package/es/ThemeProvider/AppElementContext.mjs +10 -0
- package/es/ThemeProvider/AppElementContext.mjs.map +1 -0
- package/es/ThemeProvider/ConfigProvider.mjs +29 -0
- package/es/ThemeProvider/ConfigProvider.mjs.map +1 -0
- package/es/ThemeProvider/GlobalStyle/antdOverride.mjs +73 -0
- package/es/ThemeProvider/GlobalStyle/antdOverride.mjs.map +1 -0
- package/es/ThemeProvider/GlobalStyle/essential.mjs +50 -0
- package/es/ThemeProvider/GlobalStyle/essential.mjs.map +1 -0
- package/es/ThemeProvider/GlobalStyle/global.mjs +90 -0
- package/es/ThemeProvider/GlobalStyle/global.mjs.map +1 -0
- package/es/ThemeProvider/GlobalStyle/index.mjs +14 -0
- package/es/ThemeProvider/GlobalStyle/index.mjs.map +1 -0
- package/es/ThemeProvider/Meta.d.mts +7 -0
- package/es/ThemeProvider/Meta.mjs +48 -0
- package/es/ThemeProvider/Meta.mjs.map +1 -0
- package/es/ThemeProvider/ThemeProvider.d.mts +6 -0
- package/es/ThemeProvider/ThemeProvider.mjs +89 -0
- package/es/ThemeProvider/ThemeProvider.mjs.map +1 -0
- package/es/ThemeProvider/constants.d.mts +5 -0
- package/es/ThemeProvider/constants.mjs +6 -0
- package/es/ThemeProvider/constants.mjs.map +1 -0
- package/es/ThemeProvider/index.d.mts +6 -0
- package/es/ThemeProvider/index.d.ts +1 -0
- package/es/ThemeProvider/index.js +1 -0
- package/es/ThemeProvider/index.mjs +5 -0
- package/es/ThemeProvider/type.d.mts +48 -0
- package/es/_virtual/_rolldown/runtime.mjs +13 -0
- package/es/color/colors/blue.d.mts +6 -0
- package/es/color/colors/blue.mjs +67 -0
- package/es/color/colors/blue.mjs.map +1 -0
- package/es/color/colors/cyan.d.mts +6 -0
- package/es/color/colors/cyan.mjs +67 -0
- package/es/color/colors/cyan.mjs.map +1 -0
- package/es/color/colors/geekblue.d.mts +6 -0
- package/es/color/colors/geekblue.mjs +67 -0
- package/es/color/colors/geekblue.mjs.map +1 -0
- package/es/color/colors/gold.d.mts +6 -0
- package/es/color/colors/gold.mjs +67 -0
- package/es/color/colors/gold.mjs.map +1 -0
- package/es/color/colors/gray.d.mts +6 -0
- package/es/color/colors/gray.mjs +67 -0
- package/es/color/colors/gray.mjs.map +1 -0
- package/es/color/colors/green.d.mts +6 -0
- package/es/color/colors/green.mjs +67 -0
- package/es/color/colors/green.mjs.map +1 -0
- package/es/color/colors/index.d.mts +22 -0
- package/es/color/colors/index.mjs +35 -0
- package/es/color/colors/index.mjs.map +1 -0
- package/es/color/colors/lime.d.mts +6 -0
- package/es/color/colors/lime.mjs +67 -0
- package/es/color/colors/lime.mjs.map +1 -0
- package/es/color/colors/magenta.d.mts +6 -0
- package/es/color/colors/magenta.mjs +67 -0
- package/es/color/colors/magenta.mjs.map +1 -0
- package/es/color/colors/orange.d.mts +6 -0
- package/es/color/colors/orange.mjs +67 -0
- package/es/color/colors/orange.mjs.map +1 -0
- package/es/color/colors/primary.d.mts +6 -0
- package/es/color/colors/primary.mjs +67 -0
- package/es/color/colors/primary.mjs.map +1 -0
- package/es/color/colors/purple.d.mts +6 -0
- package/es/color/colors/purple.mjs +67 -0
- package/es/color/colors/purple.mjs.map +1 -0
- package/es/color/colors/red.d.mts +6 -0
- package/es/color/colors/red.mjs +67 -0
- package/es/color/colors/red.mjs.map +1 -0
- package/es/color/colors/volcano.d.mts +6 -0
- package/es/color/colors/volcano.mjs +67 -0
- package/es/color/colors/volcano.mjs.map +1 -0
- package/es/color/colors/yellow.d.mts +6 -0
- package/es/color/colors/yellow.mjs +67 -0
- package/es/color/colors/yellow.mjs.map +1 -0
- package/es/color/index.d.mts +23 -0
- package/es/color/index.d.ts +1 -0
- package/es/color/index.js +1 -0
- package/es/color/index.mjs +22 -0
- package/es/color/neutrals/index.d.mts +13 -0
- package/es/color/neutrals/index.mjs +17 -0
- package/es/color/neutrals/index.mjs.map +1 -0
- package/es/color/neutrals/mauve.d.mts +6 -0
- package/es/color/neutrals/mauve.mjs +67 -0
- package/es/color/neutrals/mauve.mjs.map +1 -0
- package/es/color/neutrals/olive.d.mts +6 -0
- package/es/color/neutrals/olive.mjs +67 -0
- package/es/color/neutrals/olive.mjs.map +1 -0
- package/es/color/neutrals/sage.d.mts +6 -0
- package/es/color/neutrals/sage.mjs +67 -0
- package/es/color/neutrals/sage.mjs.map +1 -0
- package/es/color/neutrals/sand.d.mts +6 -0
- package/es/color/neutrals/sand.mjs +67 -0
- package/es/color/neutrals/sand.mjs.map +1 -0
- package/es/color/neutrals/slate.d.mts +6 -0
- package/es/color/neutrals/slate.mjs +67 -0
- package/es/color/neutrals/slate.mjs.map +1 -0
- package/es/color/types.d.mts +16 -0
- package/es/eslint/index.d.mts +26 -0
- package/es/eslint/index.d.ts +1 -0
- package/es/eslint/index.js +1 -0
- package/es/eslint/index.mjs +11 -0
- package/es/eslint/index.mjs.map +1 -0
- package/es/hooks/useIsClient.d.mts +8 -0
- package/es/hooks/useIsClient.mjs +13 -0
- package/es/hooks/useIsClient.mjs.map +1 -0
- package/es/i18n/context.d.mts +7 -0
- package/es/i18n/context.mjs +16 -0
- package/es/i18n/context.mjs.map +1 -0
- package/es/i18n/index.d.mts +6 -0
- package/es/i18n/index.d.ts +1 -0
- package/es/i18n/index.js +1 -0
- package/es/i18n/index.mjs +5 -0
- package/es/i18n/resources/en/common.d.mts +35 -0
- package/es/i18n/resources/en/common.mjs +36 -0
- package/es/i18n/resources/en/common.mjs.map +1 -0
- package/es/i18n/resources/en/index.d.mts +7 -0
- package/es/i18n/resources/en/index.mjs +8 -0
- package/es/i18n/resources/en/index.mjs.map +1 -0
- package/es/i18n/resources/zhCn/common.d.mts +35 -0
- package/es/i18n/resources/zhCn/common.mjs +36 -0
- package/es/i18n/resources/zhCn/common.mjs.map +1 -0
- package/es/i18n/resources/zhCn/index.d.mts +7 -0
- package/es/i18n/resources/zhCn/index.mjs +8 -0
- package/es/i18n/resources/zhCn/index.mjs.map +1 -0
- package/es/i18n/types.d.mts +22 -0
- package/es/i18n/useTranslation.d.mts +12 -0
- package/es/i18n/useTranslation.mjs +22 -0
- package/es/i18n/useTranslation.mjs.map +1 -0
- package/es/index.d.mts +43 -0
- package/es/index.mjs +26 -0
- package/es/storybook/StoryBook/StoryBook.d.mts +7 -0
- package/es/storybook/StoryBook/StoryBook.mjs +52 -0
- package/es/storybook/StoryBook/StoryBook.mjs.map +1 -0
- package/es/storybook/StoryBook/index.d.mts +3 -0
- package/es/storybook/StoryBook/style.mjs +97 -0
- package/es/storybook/StoryBook/style.mjs.map +1 -0
- package/es/storybook/StoryBook/type.d.mts +13 -0
- package/es/storybook/index.d.mts +4 -0
- package/es/storybook/index.d.ts +1 -0
- package/es/storybook/index.js +1 -0
- package/es/storybook/index.mjs +2 -0
- package/es/styles/classNames.d.mts +11 -0
- package/es/styles/classNames.mjs +12 -0
- package/es/styles/classNames.mjs.map +1 -0
- package/es/styles/customTheme.d.mts +36 -0
- package/es/styles/customTheme.mjs +71 -0
- package/es/styles/customTheme.mjs.map +1 -0
- package/es/styles/index.d.mts +6 -0
- package/es/styles/index.d.ts +1 -0
- package/es/styles/index.js +1 -0
- package/es/styles/index.mjs +6 -0
- package/es/styles/theme/algorithms/darkAlgorithm.mjs +18 -0
- package/es/styles/theme/algorithms/darkAlgorithm.mjs.map +1 -0
- package/es/styles/theme/algorithms/lightAlgorithm.mjs +18 -0
- package/es/styles/theme/algorithms/lightAlgorithm.mjs.map +1 -0
- package/es/styles/theme/algorithms/resolveScales.mjs +25 -0
- package/es/styles/theme/algorithms/resolveScales.mjs.map +1 -0
- package/es/styles/theme/antdTheme.mjs +31 -0
- package/es/styles/theme/antdTheme.mjs.map +1 -0
- package/es/styles/theme/customStylish.d.mts +7 -0
- package/es/styles/theme/customStylish.mjs +158 -0
- package/es/styles/theme/customStylish.mjs.map +1 -0
- package/es/styles/theme/customStylishStatic.d.mts +6 -0
- package/es/styles/theme/customStylishStatic.mjs +156 -0
- package/es/styles/theme/customStylishStatic.mjs.map +1 -0
- package/es/styles/theme/customToken.d.mts +7 -0
- package/es/styles/theme/customToken.mjs +127 -0
- package/es/styles/theme/customToken.mjs.map +1 -0
- package/es/styles/theme/generateColorPalette.d.mts +16 -0
- package/es/styles/theme/generateColorPalette.mjs +170 -0
- package/es/styles/theme/generateColorPalette.mjs.map +1 -0
- package/es/styles/theme/token/base.mjs +64 -0
- package/es/styles/theme/token/base.mjs.map +1 -0
- package/es/styles/theme/token/dark.mjs +37 -0
- package/es/styles/theme/token/dark.mjs.map +1 -0
- package/es/styles/theme/token/light.mjs +37 -0
- package/es/styles/theme/token/light.mjs.map +1 -0
- package/es/types/customStylish.d.mts +28 -0
- package/es/types/customToken.d.mts +34 -0
- package/es/types/customToken.mjs +32 -0
- package/es/types/customToken.mjs.map +1 -0
- package/es/types/index.d.mts +15 -0
- package/es/types/index.d.ts +1 -0
- package/es/types/index.js +1 -0
- package/es/types/index.mjs +2 -0
- package/es/utils/composeEventHandlers.d.mts +5 -0
- package/es/utils/composeEventHandlers.mjs +10 -0
- package/es/utils/composeEventHandlers.mjs.map +1 -0
- package/es/utils/copyToClipboard.d.mts +5 -0
- package/es/utils/copyToClipboard.mjs +28 -0
- package/es/utils/copyToClipboard.mjs.map +1 -0
- package/es/utils/dom.d.mts +15 -0
- package/es/utils/dom.mjs +16 -0
- package/es/utils/dom.mjs.map +1 -0
- package/es/utils/genCdnUrl.d.mts +12 -0
- package/es/utils/genCdnUrl.mjs +17 -0
- package/es/utils/genCdnUrl.mjs.map +1 -0
- package/es/utils/safeReadableColor.mjs +6 -0
- package/es/utils/safeReadableColor.mjs.map +1 -0
- package/package.json +96 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { handleTableCellClick } from "../vtable/interaction.mjs";
|
|
3
|
+
import { refreshRowSeriesHover } from "../canvas/rowSeries.mjs";
|
|
4
|
+
//#region src/Table/react/useTableCellEvents.ts
|
|
5
|
+
const useTableCellEvents = ({ applyHint, hintAtCell, lastRowSeriesHoverRef, tableRef }) => {
|
|
6
|
+
const onClickCell = (args) => {
|
|
7
|
+
const table = tableRef.current;
|
|
8
|
+
if (table != null) handleTableCellClick(table, args);
|
|
9
|
+
applyHint(null);
|
|
10
|
+
};
|
|
11
|
+
const onMouseEnterCell = (args) => {
|
|
12
|
+
hintAtCell(args.col, args.row);
|
|
13
|
+
};
|
|
14
|
+
const onMouseMoveCell = (args) => {
|
|
15
|
+
const table = tableRef.current;
|
|
16
|
+
if (table != null) {
|
|
17
|
+
const previous = lastRowSeriesHoverRef.current;
|
|
18
|
+
lastRowSeriesHoverRef.current = args.row;
|
|
19
|
+
refreshRowSeriesHover(table, previous, args.row);
|
|
20
|
+
}
|
|
21
|
+
hintAtCell(args.col, args.row);
|
|
22
|
+
};
|
|
23
|
+
return {
|
|
24
|
+
onClickCell,
|
|
25
|
+
onMouseEnterCell,
|
|
26
|
+
onMouseMoveCell
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
//#endregion
|
|
30
|
+
export { useTableCellEvents };
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=useTableCellEvents.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTableCellEvents.mjs","names":[],"sources":["../../../src/Table/react/useTableCellEvents.ts"],"sourcesContent":["'use client';\n\nimport type { ListTable as ListTableInstance } from '@visactor/vtable';\nimport type { RefObject } from 'react';\n\nimport { refreshRowSeriesHover } from '../canvas/rowSeries';\nimport { type CellEditHint, handleTableCellClick } from '../vtable/interaction';\n\nexport const useTableCellEvents = ({\n applyHint,\n hintAtCell,\n lastRowSeriesHoverRef,\n tableRef,\n}: {\n applyHint: (hint: CellEditHint | null) => void;\n hintAtCell: (col: number, row: number) => void;\n lastRowSeriesHoverRef: RefObject<number | null>;\n tableRef: RefObject<ListTableInstance | null>;\n}) => {\n const onClickCell = (args: { col: number; row: number }) => {\n const table = tableRef.current;\n if (table != null) handleTableCellClick(table, args);\n applyHint(null);\n };\n\n const onMouseEnterCell = (args: { col: number; row: number }) => {\n hintAtCell(args.col, args.row);\n };\n\n const onMouseMoveCell = (args: { col: number; row: number }) => {\n const table = tableRef.current;\n if (table != null) {\n const previous = lastRowSeriesHoverRef.current;\n lastRowSeriesHoverRef.current = args.row;\n refreshRowSeriesHover(table, previous, args.row);\n }\n hintAtCell(args.col, args.row);\n };\n\n return { onClickCell, onMouseEnterCell, onMouseMoveCell };\n};\n"],"mappings":";;;;AAQA,MAAa,sBAAsB,EACjC,WACA,YACA,uBACA,eAMI;CACJ,MAAM,eAAe,SAAuC;EAC1D,MAAM,QAAQ,SAAS;EACvB,IAAI,SAAS,MAAM,qBAAqB,OAAO,IAAI;EACnD,UAAU,IAAI;CAChB;CAEA,MAAM,oBAAoB,SAAuC;EAC/D,WAAW,KAAK,KAAK,KAAK,GAAG;CAC/B;CAEA,MAAM,mBAAmB,SAAuC;EAC9D,MAAM,QAAQ,SAAS;EACvB,IAAI,SAAS,MAAM;GACjB,MAAM,WAAW,sBAAsB;GACvC,sBAAsB,UAAU,KAAK;GACrC,sBAAsB,OAAO,UAAU,KAAK,GAAG;EACjD;EACA,WAAW,KAAK,KAAK,KAAK,GAAG;CAC/B;CAEA,OAAO;EAAE;EAAa;EAAkB;CAAgB;AAC1D"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
//#region src/Table/react/useTableColumnSettings.ts
|
|
4
|
+
const getColumnField = (column) => typeof column.field === "string" ? column.field : void 0;
|
|
5
|
+
const getColumnTitle = (column) => {
|
|
6
|
+
const field = getColumnField(column) ?? "";
|
|
7
|
+
return typeof column.title === "string" ? column.title : field;
|
|
8
|
+
};
|
|
9
|
+
const sameStringArray = (left, right) => left.length === right.length && left.every((item, index) => item === right[index]);
|
|
10
|
+
const useTableColumnSettings = ({ columns, onColumnOrderChange, onColumnVisibilityChange }) => {
|
|
11
|
+
const [hiddenFields, setHiddenFields] = useState([]);
|
|
12
|
+
const [columnOrder, setColumnOrder] = useState([]);
|
|
13
|
+
const [columnSettingsOpen, setColumnSettingsOpen] = useState(false);
|
|
14
|
+
const columnSettingsRef = useRef(null);
|
|
15
|
+
const columnEntries = useMemo(() => (columns ?? []).flatMap((column) => {
|
|
16
|
+
const field = getColumnField(column);
|
|
17
|
+
if (field == null) return [];
|
|
18
|
+
return [{
|
|
19
|
+
field,
|
|
20
|
+
title: getColumnTitle(column)
|
|
21
|
+
}];
|
|
22
|
+
}), [columns]);
|
|
23
|
+
const columnFields = useMemo(() => columnEntries.map((entry) => entry.field), [columnEntries]);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
setColumnOrder((previous) => {
|
|
26
|
+
const kept = previous.filter((field) => columnFields.includes(field));
|
|
27
|
+
const added = columnFields.filter((field) => kept.includes(field) === false);
|
|
28
|
+
const next = [...kept, ...added];
|
|
29
|
+
return sameStringArray(previous, next) ? previous : next;
|
|
30
|
+
});
|
|
31
|
+
setHiddenFields((previous) => {
|
|
32
|
+
const next = previous.filter((field) => columnFields.includes(field));
|
|
33
|
+
return sameStringArray(previous, next) ? previous : next;
|
|
34
|
+
});
|
|
35
|
+
}, [columnFields]);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (columnSettingsOpen === false) return;
|
|
38
|
+
const onPointerDown = (event) => {
|
|
39
|
+
if (columnSettingsRef.current?.contains(event.target)) return;
|
|
40
|
+
setColumnSettingsOpen(false);
|
|
41
|
+
};
|
|
42
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
43
|
+
return () => document.removeEventListener("pointerdown", onPointerDown, true);
|
|
44
|
+
}, [columnSettingsOpen]);
|
|
45
|
+
const orderedEntries = useMemo(() => {
|
|
46
|
+
if (columnOrder.length === 0) return columnEntries;
|
|
47
|
+
const byField = new Map(columnEntries.map((entry) => [entry.field, entry]));
|
|
48
|
+
return columnOrder.flatMap((field) => {
|
|
49
|
+
const entry = byField.get(field);
|
|
50
|
+
return entry ? [entry] : [];
|
|
51
|
+
});
|
|
52
|
+
}, [columnEntries, columnOrder]);
|
|
53
|
+
const visibleColumns = useMemo(() => {
|
|
54
|
+
if (columns == null) return void 0;
|
|
55
|
+
const order = columnOrder.length > 0 ? columnOrder : columnFields;
|
|
56
|
+
const orderMap = new Map(order.map((field, index) => [field, index]));
|
|
57
|
+
return columns.map((column, index) => ({
|
|
58
|
+
column,
|
|
59
|
+
index
|
|
60
|
+
})).filter(({ column }) => {
|
|
61
|
+
const field = getColumnField(column);
|
|
62
|
+
return field == null || hiddenFields.includes(field) === false;
|
|
63
|
+
}).sort((left, right) => {
|
|
64
|
+
const leftField = getColumnField(left.column);
|
|
65
|
+
const rightField = getColumnField(right.column);
|
|
66
|
+
return (leftField == null ? left.index : orderMap.get(leftField) ?? left.index) - (rightField == null ? right.index : orderMap.get(rightField) ?? right.index);
|
|
67
|
+
}).map(({ column }) => column);
|
|
68
|
+
}, [
|
|
69
|
+
columnFields,
|
|
70
|
+
columnOrder,
|
|
71
|
+
columns,
|
|
72
|
+
hiddenFields
|
|
73
|
+
]);
|
|
74
|
+
const moveColumn = (field, direction) => {
|
|
75
|
+
const order = columnOrder.length > 0 ? columnOrder : columnFields;
|
|
76
|
+
const index = order.indexOf(field);
|
|
77
|
+
const nextIndex = index + direction;
|
|
78
|
+
if (index < 0 || nextIndex < 0 || nextIndex >= order.length) return;
|
|
79
|
+
const next = [...order];
|
|
80
|
+
[next[index], next[nextIndex]] = [next[nextIndex] ?? field, next[index] ?? field];
|
|
81
|
+
setColumnOrder(next);
|
|
82
|
+
onColumnOrderChange?.(next);
|
|
83
|
+
};
|
|
84
|
+
const toggleColumnVisibility = (field) => {
|
|
85
|
+
const hidden = hiddenFields.includes(field);
|
|
86
|
+
const visibleCount = columnEntries.length - hiddenFields.length;
|
|
87
|
+
if (hidden === false && visibleCount <= 1) return;
|
|
88
|
+
const next = hidden ? hiddenFields.filter((item) => item !== field) : [...hiddenFields, field];
|
|
89
|
+
setHiddenFields(next);
|
|
90
|
+
onColumnVisibilityChange?.(field, hidden);
|
|
91
|
+
};
|
|
92
|
+
return {
|
|
93
|
+
columnEntries,
|
|
94
|
+
columnSettingsOpen,
|
|
95
|
+
columnSettingsRef,
|
|
96
|
+
hiddenFields,
|
|
97
|
+
moveColumn,
|
|
98
|
+
orderedEntries,
|
|
99
|
+
setColumnSettingsOpen,
|
|
100
|
+
toggleColumnVisibility,
|
|
101
|
+
visibleColumns
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
//#endregion
|
|
105
|
+
export { useTableColumnSettings };
|
|
106
|
+
|
|
107
|
+
//# sourceMappingURL=useTableColumnSettings.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTableColumnSettings.mjs","names":[],"sources":["../../../src/Table/react/useTableColumnSettings.ts"],"sourcesContent":["'use client';\n\nimport { useEffect, useMemo, useRef, useState } from 'react';\n\nimport type { TableColumnInput } from '../type';\n\nexport interface TableColumnEntry {\n field: string;\n title: string;\n}\n\nconst getColumnField = (column: { field?: unknown }): string | undefined =>\n typeof column.field === 'string' ? column.field : undefined;\n\nconst getColumnTitle = (column: { field?: unknown; title?: unknown }): string => {\n const field = getColumnField(column) ?? '';\n return typeof column.title === 'string' ? column.title : field;\n};\n\nconst sameStringArray = (left: string[], right: string[]): boolean =>\n left.length === right.length && left.every((item, index) => item === right[index]);\n\nexport const useTableColumnSettings = ({\n columns,\n onColumnOrderChange,\n onColumnVisibilityChange,\n}: {\n columns?: TableColumnInput[];\n onColumnOrderChange?: (fields: string[]) => void;\n onColumnVisibilityChange?: (field: string, visible: boolean) => void;\n}) => {\n const [hiddenFields, setHiddenFields] = useState<string[]>([]);\n const [columnOrder, setColumnOrder] = useState<string[]>([]);\n const [columnSettingsOpen, setColumnSettingsOpen] = useState(false);\n const columnSettingsRef = useRef<HTMLDivElement>(null);\n\n const columnEntries = useMemo(\n () =>\n (columns ?? []).flatMap((column) => {\n const field = getColumnField(column as { field?: unknown });\n if (field == null) return [];\n\n return [{ field, title: getColumnTitle(column as { field?: unknown; title?: unknown }) }];\n }),\n [columns],\n );\n const columnFields = useMemo(() => columnEntries.map((entry) => entry.field), [columnEntries]);\n\n useEffect(() => {\n setColumnOrder((previous) => {\n const kept = previous.filter((field) => columnFields.includes(field));\n const added = columnFields.filter((field) => kept.includes(field) === false);\n const next = [...kept, ...added];\n return sameStringArray(previous, next) ? previous : next;\n });\n setHiddenFields((previous) => {\n const next = previous.filter((field) => columnFields.includes(field));\n return sameStringArray(previous, next) ? previous : next;\n });\n }, [columnFields]);\n\n useEffect(() => {\n if (columnSettingsOpen === false) return;\n\n const onPointerDown = (event: PointerEvent) => {\n if (columnSettingsRef.current?.contains(event.target as Node)) return;\n setColumnSettingsOpen(false);\n };\n\n document.addEventListener('pointerdown', onPointerDown, true);\n return () => document.removeEventListener('pointerdown', onPointerDown, true);\n }, [columnSettingsOpen]);\n\n const orderedEntries = useMemo(() => {\n if (columnOrder.length === 0) return columnEntries;\n\n const byField = new Map(columnEntries.map((entry) => [entry.field, entry]));\n return columnOrder.flatMap((field) => {\n const entry = byField.get(field);\n return entry ? [entry] : [];\n });\n }, [columnEntries, columnOrder]);\n\n const visibleColumns = useMemo(() => {\n if (columns == null) return undefined;\n\n const order = columnOrder.length > 0 ? columnOrder : columnFields;\n const orderMap = new Map(order.map((field, index) => [field, index]));\n\n return (\n columns\n // 原始下标要在 filter 之前取,否则拿到的是过滤后的位置。\n .map((column, index) => ({ column, index }))\n .filter(({ column }) => {\n const field = getColumnField(column as { field?: unknown });\n return field == null || hiddenFields.includes(field) === false;\n })\n .sort((left, right) => {\n const leftField = getColumnField(left.column as { field?: unknown });\n const rightField = getColumnField(right.column as { field?: unknown });\n // 没有 field 的列进不了 columnOrder,用**原始下标**当键。早先这里对含无 field 的一对\n // 直接返回 0,于是那种列能挡住任何列跨过去:用户点了「‹」,表纹丝不动,也没有反馈。\n const leftKey = leftField == null ? left.index : (orderMap.get(leftField) ?? left.index);\n const rightKey =\n rightField == null ? right.index : (orderMap.get(rightField) ?? right.index);\n\n return leftKey - rightKey;\n })\n .map(({ column }) => column)\n );\n }, [columnFields, columnOrder, columns, hiddenFields]);\n\n const moveColumn = (field: string, direction: -1 | 1) => {\n const order = columnOrder.length > 0 ? columnOrder : columnFields;\n const index = order.indexOf(field);\n const nextIndex = index + direction;\n\n if (index < 0 || nextIndex < 0 || nextIndex >= order.length) return;\n\n const next = [...order];\n [next[index], next[nextIndex]] = [next[nextIndex] ?? field, next[index] ?? field];\n setColumnOrder(next);\n onColumnOrderChange?.(next);\n };\n\n const toggleColumnVisibility = (field: string) => {\n const hidden = hiddenFields.includes(field);\n const visibleCount = columnEntries.length - hiddenFields.length;\n\n if (hidden === false && visibleCount <= 1) return;\n\n const next = hidden ? hiddenFields.filter((item) => item !== field) : [...hiddenFields, field];\n setHiddenFields(next);\n onColumnVisibilityChange?.(field, hidden);\n };\n\n return {\n columnEntries,\n columnSettingsOpen,\n columnSettingsRef,\n hiddenFields,\n moveColumn,\n orderedEntries,\n setColumnSettingsOpen,\n toggleColumnVisibility,\n visibleColumns,\n };\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { getEditCell, getEditingEditor } from "../vtable/vtableAdapter.mjs";
|
|
3
|
+
import { resolveTreeTextOffset } from "../vtable/interaction.mjs";
|
|
4
|
+
import { useCallback, useEffect, useRef } from "react";
|
|
5
|
+
//#region src/Table/react/useTableEditorSync.ts
|
|
6
|
+
const useTableEditorSync = ({ tableRef }) => {
|
|
7
|
+
const syncEditorPosition = useCallback(() => {
|
|
8
|
+
const table = tableRef.current;
|
|
9
|
+
const editor = getEditingEditor(table);
|
|
10
|
+
const editCell = getEditCell(table);
|
|
11
|
+
if (table?.getCellRange == null || table.getCellRangeRelativeRect == null || editor?.adjustPosition == null || editCell == null) return;
|
|
12
|
+
const rect = table.getCellRangeRelativeRect(table.getCellRange(editCell.col, editCell.row));
|
|
13
|
+
const treeOffset = resolveTreeTextOffset(table, editCell.col, editCell.row);
|
|
14
|
+
const width = rect.width + (editCell.col === (table.colCount ?? 1) - 1 ? -1 : 1);
|
|
15
|
+
editor.adjustPosition({
|
|
16
|
+
height: rect.height + (editCell.row === (table.rowCount ?? 1) - 1 ? -1 : 1),
|
|
17
|
+
left: rect.left + treeOffset,
|
|
18
|
+
top: rect.top,
|
|
19
|
+
width: Math.max(0, width - treeOffset)
|
|
20
|
+
});
|
|
21
|
+
}, [tableRef]);
|
|
22
|
+
const frameRef = useRef(void 0);
|
|
23
|
+
const scheduleEditorSync = useCallback(() => {
|
|
24
|
+
if (frameRef.current != null) cancelAnimationFrame(frameRef.current);
|
|
25
|
+
frameRef.current = requestAnimationFrame(() => {
|
|
26
|
+
frameRef.current = void 0;
|
|
27
|
+
syncEditorPosition();
|
|
28
|
+
});
|
|
29
|
+
}, [syncEditorPosition]);
|
|
30
|
+
useEffect(() => () => {
|
|
31
|
+
if (frameRef.current != null) cancelAnimationFrame(frameRef.current);
|
|
32
|
+
}, []);
|
|
33
|
+
return {
|
|
34
|
+
scheduleEditorSync,
|
|
35
|
+
syncEditorPosition
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
//#endregion
|
|
39
|
+
export { useTableEditorSync };
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=useTableEditorSync.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTableEditorSync.mjs","names":[],"sources":["../../../src/Table/react/useTableEditorSync.ts"],"sourcesContent":["'use client';\n\nimport type { ListTable as ListTableInstance } from '@visactor/vtable';\nimport { type RefObject, useCallback, useEffect, useRef } from 'react';\n\nimport { resolveTreeTextOffset } from '../vtable/interaction';\nimport { getEditCell, getEditingEditor } from '../vtable/vtableAdapter';\n\nexport const useTableEditorSync = ({\n tableRef,\n}: {\n tableRef: RefObject<ListTableInstance | null>;\n}) => {\n const syncEditorPosition = useCallback(() => {\n const table = tableRef.current as\n | (ListTableInstance & {\n colCount?: number;\n editorManager?: { editCell?: { col: number; row: number }; editingEditor?: unknown };\n getCellRange?: (col: number, row: number) => unknown;\n getCellRangeRelativeRect?: (range: unknown) => {\n height: number;\n left: number;\n top: number;\n width: number;\n };\n })\n | null;\n const editor = getEditingEditor(table) as\n | {\n adjustPosition?: (rect: {\n height: number;\n left: number;\n top: number;\n width: number;\n }) => void;\n }\n | undefined;\n const editCell = getEditCell(table);\n\n if (\n table?.getCellRange == null ||\n table.getCellRangeRelativeRect == null ||\n editor?.adjustPosition == null ||\n editCell == null\n ) {\n return;\n }\n\n const rect = table.getCellRangeRelativeRect(table.getCellRange(editCell.col, editCell.row));\n const treeOffset = resolveTreeTextOffset(table, editCell.col, editCell.row);\n const width = rect.width + (editCell.col === (table.colCount ?? 1) - 1 ? -1 : 1);\n\n editor.adjustPosition({\n height: rect.height + (editCell.row === (table.rowCount ?? 1) - 1 ? -1 : 1),\n left: rect.left + treeOffset,\n top: rect.top,\n width: Math.max(0, width - treeOffset),\n });\n }, [tableRef]);\n\n // 句柄必须留着:回调会在下一帧打到 table 上,而那一帧到来之前表可能已经被 release()\n // (容器塌成 0、组件卸载)。不取消的话 syncEditorPosition 的四道守卫全过不去 ——\n // release() 不会把 editingEditor / editCell 置空 —— 于是在 null 的 internalProps 上取属性。\n const frameRef = useRef<number | undefined>(undefined);\n\n const scheduleEditorSync = useCallback(() => {\n if (frameRef.current != null) cancelAnimationFrame(frameRef.current);\n frameRef.current = requestAnimationFrame(() => {\n frameRef.current = undefined;\n syncEditorPosition();\n });\n }, [syncEditorPosition]);\n\n useEffect(\n () => () => {\n if (frameRef.current != null) cancelAnimationFrame(frameRef.current);\n },\n [],\n );\n\n return { scheduleEditorSync, syncEditorPosition };\n};\n"],"mappings":";;;;;AAQA,MAAa,sBAAsB,EACjC,eAGI;CACJ,MAAM,qBAAqB,kBAAkB;EAC3C,MAAM,QAAQ,SAAS;EAavB,MAAM,SAAS,iBAAiB,KAAK;EAUrC,MAAM,WAAW,YAAY,KAAK;EAElC,IACE,OAAO,gBAAgB,QACvB,MAAM,4BAA4B,QAClC,QAAQ,kBAAkB,QAC1B,YAAY,MAEZ;EAGF,MAAM,OAAO,MAAM,yBAAyB,MAAM,aAAa,SAAS,KAAK,SAAS,GAAG,CAAC;EAC1F,MAAM,aAAa,sBAAsB,OAAO,SAAS,KAAK,SAAS,GAAG;EAC1E,MAAM,QAAQ,KAAK,SAAS,SAAS,SAAS,MAAM,YAAY,KAAK,IAAI,KAAK;EAE9E,OAAO,eAAe;GACpB,QAAQ,KAAK,UAAU,SAAS,SAAS,MAAM,YAAY,KAAK,IAAI,KAAK;GACzE,MAAM,KAAK,OAAO;GAClB,KAAK,KAAK;GACV,OAAO,KAAK,IAAI,GAAG,QAAQ,UAAU;EACvC,CAAC;CACH,GAAG,CAAC,QAAQ,CAAC;CAKb,MAAM,WAAW,OAA2B,KAAA,CAAS;CAErD,MAAM,qBAAqB,kBAAkB;EAC3C,IAAI,SAAS,WAAW,MAAM,qBAAqB,SAAS,OAAO;EACnE,SAAS,UAAU,4BAA4B;GAC7C,SAAS,UAAU,KAAA;GACnB,mBAAmB;EACrB,CAAC;CACH,GAAG,CAAC,kBAAkB,CAAC;CAEvB,sBACc;EACV,IAAI,SAAS,WAAW,MAAM,qBAAqB,SAAS,OAAO;CACrE,GACA,CAAC,CACH;CAEA,OAAO;EAAE;EAAoB;CAAmB;AAClD"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { getEditingEditor, isTableReleased } from "../vtable/vtableAdapter.mjs";
|
|
3
|
+
import { hintFromClientPoint, placeEditHint, resolveEditHint, sameEditHint } from "../vtable/interaction.mjs";
|
|
4
|
+
import { useCallback, useEffect, useState } from "react";
|
|
5
|
+
//#region src/Table/react/useTableHoverHint.ts
|
|
6
|
+
const useTableHoverHint = ({ box, isClient, rootRef, tableRef }) => {
|
|
7
|
+
const [hint, setHint] = useState(null);
|
|
8
|
+
const applyHint = useCallback((next) => {
|
|
9
|
+
setHint((prev) => sameEditHint(prev, next) ? prev : next);
|
|
10
|
+
}, []);
|
|
11
|
+
const hintAtCell = (col, row) => {
|
|
12
|
+
const table = tableRef.current;
|
|
13
|
+
const host = rootRef.current;
|
|
14
|
+
if (table == null || host == null) return;
|
|
15
|
+
if (getEditingEditor(table)) {
|
|
16
|
+
applyHint(null);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
applyHint(placeEditHint(resolveEditHint(table, col, row), table.getElement(), host));
|
|
20
|
+
};
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
const node = rootRef.current;
|
|
23
|
+
if (node == null || isClient === false || box.width <= 0 || box.height <= 0) {
|
|
24
|
+
applyHint(null);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const onMove = (event) => {
|
|
28
|
+
const table = tableRef.current;
|
|
29
|
+
if (table == null || isTableReleased(table) || getEditingEditor(table)) {
|
|
30
|
+
applyHint(null);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
applyHint(hintFromClientPoint(table, node, event.clientX, event.clientY));
|
|
34
|
+
};
|
|
35
|
+
const onLeave = (event) => {
|
|
36
|
+
if (event.relatedTarget && node.contains(event.relatedTarget)) return;
|
|
37
|
+
applyHint(null);
|
|
38
|
+
};
|
|
39
|
+
node.addEventListener("pointermove", onMove, true);
|
|
40
|
+
node.addEventListener("pointerleave", onLeave);
|
|
41
|
+
return () => {
|
|
42
|
+
node.removeEventListener("pointermove", onMove, true);
|
|
43
|
+
node.removeEventListener("pointerleave", onLeave);
|
|
44
|
+
};
|
|
45
|
+
}, [
|
|
46
|
+
box.height,
|
|
47
|
+
box.width,
|
|
48
|
+
isClient,
|
|
49
|
+
rootRef,
|
|
50
|
+
tableRef
|
|
51
|
+
]);
|
|
52
|
+
return {
|
|
53
|
+
applyHint,
|
|
54
|
+
hint,
|
|
55
|
+
hintAtCell,
|
|
56
|
+
setHint
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
//#endregion
|
|
60
|
+
export { useTableHoverHint };
|
|
61
|
+
|
|
62
|
+
//# sourceMappingURL=useTableHoverHint.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTableHoverHint.mjs","names":[],"sources":["../../../src/Table/react/useTableHoverHint.ts"],"sourcesContent":["'use client';\n\nimport type { ListTable as ListTableInstance } from '@visactor/vtable';\nimport { type RefObject, useCallback, useEffect, useState } from 'react';\n\nimport {\n type CellEditHint,\n hintFromClientPoint,\n placeEditHint,\n resolveEditHint,\n sameEditHint,\n} from '../vtable/interaction';\nimport { getEditingEditor, isTableReleased } from '../vtable/vtableAdapter';\n\nexport const useTableHoverHint = ({\n box,\n isClient,\n rootRef,\n tableRef,\n}: {\n box: { height: number; width: number };\n isClient: boolean;\n rootRef: RefObject<HTMLDivElement | null>;\n tableRef: RefObject<ListTableInstance | null>;\n}) => {\n const [hint, setHint] = useState<CellEditHint | null>(null);\n\n // 稳定引用:Table 侧要在 options 变化时用它清掉悬浮框,依赖数组需要一个不每次重建的函数。\n const applyHint = useCallback((next: CellEditHint | null) => {\n setHint((prev) => (sameEditHint(prev, next) ? prev : next));\n }, []);\n\n const hintAtCell = (col: number, row: number) => {\n const table = tableRef.current;\n const host = rootRef.current;\n if (table == null || host == null) return;\n // 编辑浮层自己带 1px 环。hover 框也有描边,编辑时再跟手画一层就是双框。\n if (getEditingEditor(table)) {\n applyHint(null);\n return;\n }\n applyHint(placeEditHint(resolveEditHint(table, col, row), table.getElement(), host));\n };\n\n useEffect(() => {\n const node = rootRef.current;\n // 门槛必须与 <ListTable> 的渲染门一致(宽和高都 > 0):只判宽度时,容器高度为 0 会让表\n // 卸载而监听器还挂着,pointermove 打到一个已 release 的实例上就是 TypeError。\n if (node == null || isClient === false || box.width <= 0 || box.height <= 0) {\n // 容器塌成 0×0 时 <ListTable> 会卸载、pointermove 监听也在这里被摘掉 —— 于是**没有\n // 任何一次 pointermove 会来清 hint**,而 hint 浮层没有和 <ListTable> 一样的渲染门:\n // 它会停在旧坐标上,铅笔按钮还拿已释放的实例去 startEditCell(下面 onMove 里那条\n // 清理正是为此写的,但这条路根本走不到)。\n applyHint(null);\n return;\n }\n\n const onMove = (event: PointerEvent) => {\n const table = tableRef.current;\n // 表被拆掉(release)时要**清掉**旧 hint 而不是直接 return:hint 浮层没有和\n // <ListTable> 一样的渲染门,留着它就悬在旧坐标上,而它的铅笔按钮会拿这个已释放的\n // 实例去 startEditCell。\n if (table == null || isTableReleased(table) || getEditingEditor(table)) {\n applyHint(null);\n return;\n }\n applyHint(hintFromClientPoint(table, node, event.clientX, event.clientY));\n };\n const onLeave = (event: PointerEvent) => {\n if (event.relatedTarget && node.contains(event.relatedTarget as Node)) return;\n applyHint(null);\n };\n\n node.addEventListener('pointermove', onMove, true);\n node.addEventListener('pointerleave', onLeave);\n return () => {\n node.removeEventListener('pointermove', onMove, true);\n node.removeEventListener('pointerleave', onLeave);\n };\n }, [box.height, box.width, isClient, rootRef, tableRef]);\n\n return { applyHint, hint, hintAtCell, setHint };\n};\n"],"mappings":";;;;;AAcA,MAAa,qBAAqB,EAChC,KACA,UACA,SACA,eAMI;CACJ,MAAM,CAAC,MAAM,WAAW,SAA8B,IAAI;CAG1D,MAAM,YAAY,aAAa,SAA8B;EAC3D,SAAS,SAAU,aAAa,MAAM,IAAI,IAAI,OAAO,IAAK;CAC5D,GAAG,CAAC,CAAC;CAEL,MAAM,cAAc,KAAa,QAAgB;EAC/C,MAAM,QAAQ,SAAS;EACvB,MAAM,OAAO,QAAQ;EACrB,IAAI,SAAS,QAAQ,QAAQ,MAAM;EAEnC,IAAI,iBAAiB,KAAK,GAAG;GAC3B,UAAU,IAAI;GACd;EACF;EACA,UAAU,cAAc,gBAAgB,OAAO,KAAK,GAAG,GAAG,MAAM,WAAW,GAAG,IAAI,CAAC;CACrF;CAEA,gBAAgB;EACd,MAAM,OAAO,QAAQ;EAGrB,IAAI,QAAQ,QAAQ,aAAa,SAAS,IAAI,SAAS,KAAK,IAAI,UAAU,GAAG;GAK3E,UAAU,IAAI;GACd;EACF;EAEA,MAAM,UAAU,UAAwB;GACtC,MAAM,QAAQ,SAAS;GAIvB,IAAI,SAAS,QAAQ,gBAAgB,KAAK,KAAK,iBAAiB,KAAK,GAAG;IACtE,UAAU,IAAI;IACd;GACF;GACA,UAAU,oBAAoB,OAAO,MAAM,MAAM,SAAS,MAAM,OAAO,CAAC;EAC1E;EACA,MAAM,WAAW,UAAwB;GACvC,IAAI,MAAM,iBAAiB,KAAK,SAAS,MAAM,aAAqB,GAAG;GACvE,UAAU,IAAI;EAChB;EAEA,KAAK,iBAAiB,eAAe,QAAQ,IAAI;EACjD,KAAK,iBAAiB,gBAAgB,OAAO;EAC7C,aAAa;GACX,KAAK,oBAAoB,eAAe,QAAQ,IAAI;GACpD,KAAK,oBAAoB,gBAAgB,OAAO;EAClD;CACF,GAAG;EAAC,IAAI;EAAQ,IAAI;EAAO;EAAU;EAAS;CAAQ,CAAC;CAEvD,OAAO;EAAE;EAAW;EAAM;EAAY;CAAQ;AAChD"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { getStateManager, isTableReleased } from "../vtable/vtableAdapter.mjs";
|
|
3
|
+
import { clearCascadeSelection, isCascadeSelectionTable, selectAllSeriesRows, toggleSeriesRow } from "../vtable/seriesSelection.mjs";
|
|
4
|
+
import { isTableEditing } from "../vtable/interaction.mjs";
|
|
5
|
+
//#region src/Table/react/useTableKeyboard.ts
|
|
6
|
+
const useTableKeyboard = ({ columnSettingsRef, tableRef }) => {
|
|
7
|
+
const handleKeyDown = (event) => {
|
|
8
|
+
const table = tableRef.current;
|
|
9
|
+
const target = event.target;
|
|
10
|
+
if (table == null || isTableReleased(table) || isTableEditing(table) || target.closest("input, textarea, [contenteditable=\"true\"]") || columnSettingsRef.current?.contains(target)) return;
|
|
11
|
+
const headerRows = table.columnHeaderLevelCount ?? 1;
|
|
12
|
+
const rowCount = table.rowCount ?? 1;
|
|
13
|
+
const selectedRanges = getStateManager(table)?.select?.ranges ?? [];
|
|
14
|
+
if (event.key === "Escape") {
|
|
15
|
+
const cascade = isCascadeSelectionTable(table);
|
|
16
|
+
if (selectedRanges.length === 0 && cascade === false) return;
|
|
17
|
+
event.stopPropagation();
|
|
18
|
+
table.clearSelected?.();
|
|
19
|
+
if (cascade) clearCascadeSelection(table);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if ((event.key === "a" || event.key === "A") && (event.ctrlKey || event.metaKey)) {
|
|
23
|
+
if (selectAllSeriesRows(table) === false) return;
|
|
24
|
+
event.preventDefault();
|
|
25
|
+
event.stopPropagation();
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if ((event.key === "x" || event.key === "X") && event.ctrlKey === false && event.metaKey === false && event.altKey === false) {
|
|
29
|
+
const row = getStateManager(table)?.select?.cellPos?.row ?? -1;
|
|
30
|
+
if (row < headerRows || row >= rowCount) return;
|
|
31
|
+
event.preventDefault();
|
|
32
|
+
event.stopPropagation();
|
|
33
|
+
toggleSeriesRow(table, row, event.shiftKey);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
return handleKeyDown;
|
|
37
|
+
};
|
|
38
|
+
//#endregion
|
|
39
|
+
export { useTableKeyboard };
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=useTableKeyboard.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTableKeyboard.mjs","names":[],"sources":["../../../src/Table/react/useTableKeyboard.ts"],"sourcesContent":["'use client';\n\nimport type { ListTable as ListTableInstance } from '@visactor/vtable';\nimport type { KeyboardEvent, RefObject } from 'react';\n\nimport { isTableEditing } from '../vtable/interaction';\nimport {\n clearCascadeSelection,\n isCascadeSelectionTable,\n selectAllSeriesRows,\n toggleSeriesRow,\n} from '../vtable/seriesSelection';\nimport { getStateManager, isTableReleased } from '../vtable/vtableAdapter';\n\nexport const useTableKeyboard = ({\n columnSettingsRef,\n tableRef,\n}: {\n columnSettingsRef: RefObject<HTMLDivElement | null>;\n tableRef: RefObject<ListTableInstance | null>;\n}) => {\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const table = tableRef.current;\n const target = event.target as HTMLElement;\n\n if (\n table == null ||\n // `release()` 会把 `internalProps` 置 null,而下面每个按键路径都要读\n // `columnHeaderLevelCount` / `rowCount` —— 那些 getter 直接抛 TypeError。\n // (表被拆掉时 canvas 一并消失、焦点回到 body,理论上收不到事件;但这条守卫与\n // useTableSelectionInfo / a11y 那几处保持同一口径,成本是一次属性读。)\n isTableReleased(table) ||\n isTableEditing(table) ||\n target.closest('input, textarea, [contenteditable=\"true\"]') ||\n columnSettingsRef.current?.contains(target)\n ) {\n return;\n }\n\n const headerRows = table.columnHeaderLevelCount ?? 1;\n const rowCount = table.rowCount ?? 1;\n const selectedRanges = getStateManager(table)?.select?.ranges ?? [];\n\n // 三条通路都必须走 seriesSelection,不能自己拼区间:级联模式下选中态的真身是\n // `stateManager.checkedState`(复选框勾选、底部「已选 N 行」、selectionActions 都读它),\n // 而 `clearSelected` / `selectCells` 只动 `select.ranges`。只写 ranges 的后果是行高亮了\n // 却一个勾都没有、计数为 0,并且下一次 `syncCascadeSelectionRanges` 会把高亮抹掉。\n if (event.key === 'Escape') {\n const cascade = isCascadeSelectionTable(table);\n if (selectedRanges.length === 0 && cascade === false) return;\n event.stopPropagation();\n table.clearSelected?.();\n if (cascade) clearCascadeSelection(table);\n return;\n }\n\n if ((event.key === 'a' || event.key === 'A') && (event.ctrlKey || event.metaKey)) {\n // 先做再看结果:没体行可全选时必须放行,不能把浏览器的全选键吞掉。\n if (selectAllSeriesRows(table) === false) return;\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n if (\n (event.key === 'x' || event.key === 'X') &&\n event.ctrlKey === false &&\n event.metaKey === false &&\n event.altKey === false\n ) {\n const row = getStateManager(table)?.select?.cellPos?.row ?? -1;\n\n if (row < headerRows || row >= rowCount) return;\n event.preventDefault();\n event.stopPropagation();\n // 与鼠标点行号列是同一个入口,级联模式下它会翻复选框。\n toggleSeriesRow(table, row, event.shiftKey);\n }\n };\n\n return handleKeyDown;\n};\n"],"mappings":";;;;;AAcA,MAAa,oBAAoB,EAC/B,mBACA,eAII;CACJ,MAAM,iBAAiB,UAAyC;EAC9D,MAAM,QAAQ,SAAS;EACvB,MAAM,SAAS,MAAM;EAErB,IACE,SAAS,QAKT,gBAAgB,KAAK,KACrB,eAAe,KAAK,KACpB,OAAO,QAAQ,6CAA2C,KAC1D,kBAAkB,SAAS,SAAS,MAAM,GAE1C;EAGF,MAAM,aAAa,MAAM,0BAA0B;EACnD,MAAM,WAAW,MAAM,YAAY;EACnC,MAAM,iBAAiB,gBAAgB,KAAK,CAAC,EAAE,QAAQ,UAAU,CAAC;EAMlE,IAAI,MAAM,QAAQ,UAAU;GAC1B,MAAM,UAAU,wBAAwB,KAAK;GAC7C,IAAI,eAAe,WAAW,KAAK,YAAY,OAAO;GACtD,MAAM,gBAAgB;GACtB,MAAM,gBAAgB;GACtB,IAAI,SAAS,sBAAsB,KAAK;GACxC;EACF;EAEA,KAAK,MAAM,QAAQ,OAAO,MAAM,QAAQ,SAAS,MAAM,WAAW,MAAM,UAAU;GAEhF,IAAI,oBAAoB,KAAK,MAAM,OAAO;GAC1C,MAAM,eAAe;GACrB,MAAM,gBAAgB;GACtB;EACF;EAEA,KACG,MAAM,QAAQ,OAAO,MAAM,QAAQ,QACpC,MAAM,YAAY,SAClB,MAAM,YAAY,SAClB,MAAM,WAAW,OACjB;GACA,MAAM,MAAM,gBAAgB,KAAK,CAAC,EAAE,QAAQ,SAAS,OAAO;GAE5D,IAAI,MAAM,cAAc,OAAO,UAAU;GACzC,MAAM,eAAe;GACrB,MAAM,gBAAgB;GAEtB,gBAAgB,OAAO,KAAK,MAAM,QAAQ;EAC5C;CACF;CAEA,OAAO;AACT"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useI18n } from "../../ConfigProvider/index.mjs";
|
|
3
|
+
import { createTableTheme, isOpaqueColor, resolveGroupFill, resolveTableCanvasPalette } from "../canvas/theme.mjs";
|
|
4
|
+
import { resolveTableI18n } from "../core/tableI18n.mjs";
|
|
5
|
+
import { getScenegraph, isTableReleased, updateCellContentRange } from "../vtable/vtableAdapter.mjs";
|
|
6
|
+
import { createSuperadAntdTheme } from "../../styles/theme/antdTheme.mjs";
|
|
7
|
+
import { computeTableHeight, parsePxSize, toCssSize } from "../core/size.mjs";
|
|
8
|
+
import { createTableOption } from "../vtable/option.mjs";
|
|
9
|
+
import { sameRenderInputs } from "./sameRenderInputs.mjs";
|
|
10
|
+
import { useTheme } from "antd-style";
|
|
11
|
+
import { useEffect, useMemo, useRef } from "react";
|
|
12
|
+
//#region src/Table/react/useTableRenderState.ts
|
|
13
|
+
const useTableRenderState = ({ autoFillWidth, autoHeight, columns, editable, emptyText, frozenColCount, groupBy, groupTitleColors, groupTitleStyle, headerRowHeight, height, hover, measuredContentHeight, option, records, rowDrag, rowHeight, showHeader, showRowIndex, showRowSelection, showVerticalBorder, size, style, tableRef, theme, tree, treeExpandLevel, treeIndent, width }) => {
|
|
14
|
+
const themeTokens = useTheme();
|
|
15
|
+
const { colorBgContainer, colorBorderSecondary, colorFillQuaternary, colorFillSecondary, colorFillTertiary, colorInfo, colorPrimary, colorSplit, colorSuccess, colorText, colorTextQuaternary, colorTextSecondary, colorTextTertiary, fontFamily, isDarkMode } = themeTokens;
|
|
16
|
+
/** 送给编辑器 root 的主题。不传的话那边是全新 root、没有父级 context,一律退回 antd 默认。 */
|
|
17
|
+
const editorTheme = useMemo(() => {
|
|
18
|
+
return {
|
|
19
|
+
components: createSuperadAntdTheme({
|
|
20
|
+
appearance: isDarkMode ? "dark" : "light",
|
|
21
|
+
neutralColor: themeTokens.neutralColor,
|
|
22
|
+
primaryColor: themeTokens.primaryColor
|
|
23
|
+
}).components,
|
|
24
|
+
token: themeTokens
|
|
25
|
+
};
|
|
26
|
+
}, [isDarkMode, themeTokens]);
|
|
27
|
+
const token = useMemo(() => ({
|
|
28
|
+
colorBgContainer,
|
|
29
|
+
colorBorderSecondary,
|
|
30
|
+
colorFillQuaternary,
|
|
31
|
+
colorFillSecondary,
|
|
32
|
+
colorFillTertiary,
|
|
33
|
+
colorInfo,
|
|
34
|
+
colorPrimary,
|
|
35
|
+
colorSplit,
|
|
36
|
+
colorSuccess,
|
|
37
|
+
colorText,
|
|
38
|
+
colorTextQuaternary,
|
|
39
|
+
colorTextSecondary,
|
|
40
|
+
colorTextTertiary,
|
|
41
|
+
fontFamily,
|
|
42
|
+
isDarkMode
|
|
43
|
+
}), [
|
|
44
|
+
colorBgContainer,
|
|
45
|
+
colorBorderSecondary,
|
|
46
|
+
colorFillQuaternary,
|
|
47
|
+
colorFillSecondary,
|
|
48
|
+
colorFillTertiary,
|
|
49
|
+
colorInfo,
|
|
50
|
+
colorPrimary,
|
|
51
|
+
colorSplit,
|
|
52
|
+
colorSuccess,
|
|
53
|
+
colorText,
|
|
54
|
+
colorTextQuaternary,
|
|
55
|
+
colorTextSecondary,
|
|
56
|
+
colorTextTertiary,
|
|
57
|
+
fontFamily,
|
|
58
|
+
isDarkMode
|
|
59
|
+
]);
|
|
60
|
+
const baseTheme = useMemo(() => createTableTheme(token, { showVerticalBorder }), [showVerticalBorder, token]);
|
|
61
|
+
/** Column-level style beats the table theme, which beats the built-in theme. */
|
|
62
|
+
const groupTitleStyleMerged = useMemo(() => ({
|
|
63
|
+
...baseTheme.groupTitleStyle,
|
|
64
|
+
...theme?.groupTitleStyle,
|
|
65
|
+
...groupTitleStyle
|
|
66
|
+
}), [
|
|
67
|
+
baseTheme,
|
|
68
|
+
groupTitleStyle,
|
|
69
|
+
theme
|
|
70
|
+
]);
|
|
71
|
+
const stickyGroupBackground = useMemo(() => {
|
|
72
|
+
const background = groupTitleStyleMerged?.bgColor;
|
|
73
|
+
if (typeof background === "string" && background && isOpaqueColor(background)) return background;
|
|
74
|
+
return resolveGroupFill({ isDarkMode: token.isDarkMode });
|
|
75
|
+
}, [groupTitleStyleMerged, token]);
|
|
76
|
+
const { locale, t } = useI18n();
|
|
77
|
+
const i18n = useMemo(() => resolveTableI18n(locale, (key) => t(key)), [locale, t]);
|
|
78
|
+
const optionInputs = {
|
|
79
|
+
autoFillWidth: autoFillWidth ?? true,
|
|
80
|
+
columns,
|
|
81
|
+
editable,
|
|
82
|
+
emptyText,
|
|
83
|
+
i18n,
|
|
84
|
+
frozenColCount,
|
|
85
|
+
groupBy,
|
|
86
|
+
groupTitleColors,
|
|
87
|
+
headerRowHeight,
|
|
88
|
+
hover,
|
|
89
|
+
option,
|
|
90
|
+
records,
|
|
91
|
+
rowDrag,
|
|
92
|
+
rowHeight,
|
|
93
|
+
showHeader,
|
|
94
|
+
showRowIndex,
|
|
95
|
+
showRowSelection,
|
|
96
|
+
showVerticalBorder,
|
|
97
|
+
size,
|
|
98
|
+
theme: {
|
|
99
|
+
...baseTheme,
|
|
100
|
+
...theme,
|
|
101
|
+
groupTitleStyle: groupTitleStyleMerged
|
|
102
|
+
},
|
|
103
|
+
token,
|
|
104
|
+
tree,
|
|
105
|
+
treeExpandLevel,
|
|
106
|
+
treeIndent,
|
|
107
|
+
/**
|
|
108
|
+
* 送给编辑器的主题。编辑器渲染在 `createRoot` 起的**独立 React root** 里,React context 不跨
|
|
109
|
+
* root —— 那边不显式传 theme 就退回 antd 默认(主色是 `#1677ff` 的蓝,而本项目是 `#222222`)。
|
|
110
|
+
* 与 palette 同一条通道:写进 `customConfig`,主题一变随 option 重建一起更新。
|
|
111
|
+
*/
|
|
112
|
+
editorTheme
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* 按**内容**复用上一次的 option 对象,而不是按引用 memo。
|
|
116
|
+
*
|
|
117
|
+
* 使用方写 `columns={[...]}` / `records={rows.map(...)}` 时每次渲染都是新数组,`useMemo`
|
|
118
|
+
* 的引用比较必然失效 → 新 option 里全是新建的函数与编辑器实例 → react-vtable 的
|
|
119
|
+
* `isEqual` 对非纯对象直接返回 false → 每次父组件渲染都走一遍 `updateOption`(整表重建:
|
|
120
|
+
* 重新编译列、重建数据源、9 个事件解绑重绑)。按内容认出来就能让引用保持稳定,
|
|
121
|
+
* `updateOption` 完全不会发生。
|
|
122
|
+
*
|
|
123
|
+
* 在渲染期写 ref 是 `useMemo` 本身的实现方式,这里只是把判据从引用换成内容。
|
|
124
|
+
*/
|
|
125
|
+
const optionRef = useRef(void 0);
|
|
126
|
+
const mergedOption = (() => {
|
|
127
|
+
const previous = optionRef.current;
|
|
128
|
+
if (previous != null && sameRenderInputs(previous.inputs, optionInputs)) return previous.value;
|
|
129
|
+
const value = createTableOption(optionInputs);
|
|
130
|
+
optionRef.current = {
|
|
131
|
+
inputs: optionInputs,
|
|
132
|
+
value
|
|
133
|
+
};
|
|
134
|
+
return value;
|
|
135
|
+
})();
|
|
136
|
+
useEffect(() => {
|
|
137
|
+
const table = tableRef.current;
|
|
138
|
+
if (table == null || isTableReleased(table)) return;
|
|
139
|
+
table.__superadPalette = resolveTableCanvasPalette(token);
|
|
140
|
+
table.__superadTheme = editorTheme;
|
|
141
|
+
table.__superadI18n = i18n;
|
|
142
|
+
const scenegraph = getScenegraph(table);
|
|
143
|
+
const headerRows = table.columnHeaderLevelCount ?? 1;
|
|
144
|
+
const startRow = Math.max(headerRows, scenegraph.proxy?.rowStart ?? headerRows);
|
|
145
|
+
const endRow = Math.min((table.rowCount ?? 1) - 1, scenegraph.proxy?.rowEnd ?? startRow + 40);
|
|
146
|
+
const endCol = (table.colCount ?? 1) - 1;
|
|
147
|
+
if (headerRows > 0) updateCellContentRange(table, 0, 0, endCol, headerRows - 1);
|
|
148
|
+
if (endRow >= startRow) updateCellContentRange(table, 0, startRow, endCol, endRow);
|
|
149
|
+
scenegraph.updateNextFrame?.();
|
|
150
|
+
}, [
|
|
151
|
+
editorTheme,
|
|
152
|
+
i18n,
|
|
153
|
+
mergedOption,
|
|
154
|
+
tableRef,
|
|
155
|
+
token
|
|
156
|
+
]);
|
|
157
|
+
const dataContentHeight = useMemo(() => computeTableHeight({
|
|
158
|
+
groupBy,
|
|
159
|
+
headerRowHeight: parsePxSize(headerRowHeight),
|
|
160
|
+
records,
|
|
161
|
+
rowHeight: parsePxSize(rowHeight),
|
|
162
|
+
showHeader,
|
|
163
|
+
size,
|
|
164
|
+
tree
|
|
165
|
+
}), [
|
|
166
|
+
groupBy,
|
|
167
|
+
headerRowHeight,
|
|
168
|
+
records,
|
|
169
|
+
rowHeight,
|
|
170
|
+
showHeader,
|
|
171
|
+
size,
|
|
172
|
+
tree
|
|
173
|
+
]);
|
|
174
|
+
/**
|
|
175
|
+
* 引擎实测优先:按数据算只在首帧成立(那时还没有引擎实例,SSR 也要有个值),一旦用户折叠过,
|
|
176
|
+
* 行数就只有引擎知道了。见 `useTableVTableEvents` 里 `onHierarchyChange` 的注释。
|
|
177
|
+
*/
|
|
178
|
+
const contentHeight = measuredContentHeight ?? dataContentHeight;
|
|
179
|
+
const resolvedHeight = autoHeight !== false && typeof height === "number" && records?.length ? Math.min(height, contentHeight) : height ?? contentHeight;
|
|
180
|
+
return {
|
|
181
|
+
mergedOption,
|
|
182
|
+
rootStyle: {
|
|
183
|
+
height: toCssSize(resolvedHeight),
|
|
184
|
+
width: toCssSize(width ?? "100%"),
|
|
185
|
+
...style
|
|
186
|
+
},
|
|
187
|
+
stickyGroupBackground,
|
|
188
|
+
token
|
|
189
|
+
};
|
|
190
|
+
};
|
|
191
|
+
//#endregion
|
|
192
|
+
export { useTableRenderState };
|
|
193
|
+
|
|
194
|
+
//# sourceMappingURL=useTableRenderState.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTableRenderState.mjs","names":[],"sources":["../../../src/Table/react/useTableRenderState.ts"],"sourcesContent":["'use client';\n\nimport type { ListTable as ListTableInstance } from '@visactor/vtable';\nimport type { ThemeConfig } from 'antd';\nimport { useTheme } from 'antd-style';\nimport { type CSSProperties, type RefObject, useEffect, useMemo, useRef } from 'react';\n\nimport { useI18n } from '@/ConfigProvider';\nimport type { NeutralColors, PrimaryColors } from '@/styles/customTheme';\nimport { createSuperadAntdTheme } from '@/styles/theme/antdTheme';\n\nimport {\n createTableTheme,\n isOpaqueColor,\n resolveGroupFill,\n resolveTableCanvasPalette,\n type TableToken,\n} from '../canvas/theme';\nimport { computeTableHeight, parsePxSize, toCssSize } from '../core/size';\nimport { resolveTableI18n, type TableI18n } from '../core/tableI18n';\nimport type { TableProps } from '../type';\nimport { createTableOption } from '../vtable/option';\nimport { getScenegraph, isTableReleased, updateCellContentRange } from '../vtable/vtableAdapter';\nimport { sameRenderInputs } from './sameRenderInputs';\n\ntype RenderStateProps = Pick<\n TableProps,\n | 'autoFillWidth'\n | 'autoHeight'\n | 'editable'\n | 'emptyText'\n | 'frozenColCount'\n | 'groupBy'\n | 'groupTitleColors'\n | 'groupTitleStyle'\n | 'headerRowHeight'\n | 'height'\n | 'hover'\n | 'option'\n | 'records'\n | 'rowDrag'\n | 'rowHeight'\n | 'showHeader'\n | 'showRowIndex'\n | 'showRowSelection'\n | 'showVerticalBorder'\n | 'size'\n | 'style'\n | 'theme'\n | 'tree'\n | 'treeExpandLevel'\n | 'treeIndent'\n | 'width'\n> & {\n columns?: TableProps['columns'];\n /**\n * 引擎实测的内容高度(含底部那 8px 的槽),折叠 / 展开之后由\n * `useTableVTableEvents` 写入;没发生过折叠时是 null,走按数据算的那条。\n */\n measuredContentHeight: number | null;\n tableRef: RefObject<ListTableInstance | null>;\n};\n\nexport const useTableRenderState = ({\n autoFillWidth,\n autoHeight,\n columns,\n editable,\n emptyText,\n frozenColCount,\n groupBy,\n groupTitleColors,\n groupTitleStyle,\n headerRowHeight,\n height,\n hover,\n measuredContentHeight,\n option,\n records,\n rowDrag,\n rowHeight,\n showHeader,\n showRowIndex,\n showRowSelection,\n showVerticalBorder,\n size,\n style,\n tableRef,\n theme,\n tree,\n treeExpandLevel,\n treeIndent,\n width,\n}: RenderStateProps) => {\n // 自定义种子(`createSuperadAntdTheme` 的入参)会留在解析后的 token 上;读回来是为了在**编辑器\n // 那个独立 React root** 里原样重建同一份主题 —— context 不跨 root,那边拿不到 ThemeProvider。\n const themeTokens = useTheme() as ReturnType<typeof useTheme> & {\n neutralColor?: NeutralColors;\n primaryColor?: PrimaryColors;\n };\n const {\n colorBgContainer,\n colorBorderSecondary,\n colorFillQuaternary,\n colorFillSecondary,\n colorFillTertiary,\n colorInfo,\n colorPrimary,\n colorSplit,\n colorSuccess,\n colorText,\n colorTextQuaternary,\n colorTextSecondary,\n colorTextTertiary,\n fontFamily,\n isDarkMode,\n } = themeTokens;\n\n /** 送给编辑器 root 的主题。不传的话那边是全新 root、没有父级 context,一律退回 antd 默认。 */\n const editorTheme = useMemo(() => {\n const built = createSuperadAntdTheme({\n appearance: isDarkMode ? 'dark' : 'light',\n neutralColor: themeTokens.neutralColor,\n primaryColor: themeTokens.primaryColor,\n });\n\n // 只交 **已经解析好的 token** + `components` 覆盖,**不带 `algorithm`**:\n // 项目那套自定义 algorithm 在编辑器那个 root 里会算出残缺的 token(实测 `fontSize` /\n // `controlHeight` 是 undefined),日期面板拿不到 `--ant-font-size`,字号退回继承的 16px、\n // 日期区宽度从 288 涨到 906。这里给的是外层主题的终值,让 antd 用默认算法原样收下。\n return { components: built.components, token: themeTokens };\n }, [isDarkMode, themeTokens]);\n\n const token = useMemo<TableToken>(\n () => ({\n colorBgContainer,\n colorBorderSecondary,\n colorFillQuaternary,\n colorFillSecondary,\n colorFillTertiary,\n colorInfo,\n colorPrimary,\n colorSplit,\n colorSuccess,\n colorText,\n colorTextQuaternary,\n colorTextSecondary,\n colorTextTertiary,\n fontFamily,\n isDarkMode,\n }),\n [\n colorBgContainer,\n colorBorderSecondary,\n colorFillQuaternary,\n colorFillSecondary,\n colorFillTertiary,\n colorInfo,\n colorPrimary,\n colorSplit,\n colorSuccess,\n colorText,\n colorTextQuaternary,\n colorTextSecondary,\n colorTextTertiary,\n fontFamily,\n isDarkMode,\n ],\n );\n\n const baseTheme = useMemo(\n () => createTableTheme(token, { showVerticalBorder }),\n [showVerticalBorder, token],\n );\n\n /** Column-level style beats the table theme, which beats the built-in theme. */\n const groupTitleStyleMerged = useMemo(\n () => ({ ...baseTheme.groupTitleStyle, ...theme?.groupTitleStyle, ...groupTitleStyle }),\n [baseTheme, groupTitleStyle, theme],\n );\n\n const stickyGroupBackground = useMemo(() => {\n const background = groupTitleStyleMerged?.bgColor;\n\n // A sticky title sits over the rows scrolling beneath it, so a caller-supplied fill has\n // to clear the same opacity bar as the token does — otherwise `bgColor: 'rgba(…, 0.02)'`\n // would let content show through the pinned title.\n if (typeof background === 'string' && background && isOpaqueColor(background)) {\n return background;\n }\n\n return resolveGroupFill({ isDarkMode: token.isDarkMode } as TableToken);\n }, [groupTitleStyleMerged, token]);\n\n const { locale, t } = useI18n();\n const i18n = useMemo(\n () => resolveTableI18n(locale, (key) => t(key as Parameters<typeof t>[0])),\n [locale, t],\n );\n\n const optionInputs = {\n autoFillWidth: autoFillWidth ?? true,\n columns,\n editable,\n emptyText,\n i18n,\n frozenColCount,\n groupBy,\n groupTitleColors,\n headerRowHeight,\n hover,\n option,\n records,\n rowDrag,\n rowHeight,\n showHeader,\n showRowIndex,\n showRowSelection,\n showVerticalBorder,\n size,\n theme: {\n ...baseTheme,\n ...theme,\n groupTitleStyle: groupTitleStyleMerged,\n },\n token,\n tree,\n treeExpandLevel,\n treeIndent,\n /**\n * 送给编辑器的主题。编辑器渲染在 `createRoot` 起的**独立 React root** 里,React context 不跨\n * root —— 那边不显式传 theme 就退回 antd 默认(主色是 `#1677ff` 的蓝,而本项目是 `#222222`)。\n * 与 palette 同一条通道:写进 `customConfig`,主题一变随 option 重建一起更新。\n */\n editorTheme,\n };\n /**\n * 按**内容**复用上一次的 option 对象,而不是按引用 memo。\n *\n * 使用方写 `columns={[...]}` / `records={rows.map(...)}` 时每次渲染都是新数组,`useMemo`\n * 的引用比较必然失效 → 新 option 里全是新建的函数与编辑器实例 → react-vtable 的\n * `isEqual` 对非纯对象直接返回 false → 每次父组件渲染都走一遍 `updateOption`(整表重建:\n * 重新编译列、重建数据源、9 个事件解绑重绑)。按内容认出来就能让引用保持稳定,\n * `updateOption` 完全不会发生。\n *\n * 在渲染期写 ref 是 `useMemo` 本身的实现方式,这里只是把判据从引用换成内容。\n */\n const optionRef = useRef<\n { inputs: typeof optionInputs; value: ReturnType<typeof createTableOption> } | undefined\n >(undefined);\n const mergedOption = (() => {\n const previous = optionRef.current;\n if (previous != null && sameRenderInputs(previous.inputs, optionInputs)) return previous.value;\n\n const value = createTableOption(optionInputs);\n optionRef.current = { inputs: optionInputs, value };\n return value;\n })();\n\n useEffect(() => {\n const table = tableRef.current;\n // 用 isTableReleased 精确守卫,而不是把整个 effect 包进 try/catch:那个 catch 会把\n // palette 写入失败、私有 API 漂移一并吞掉,症状是「主题换了但 canvas 颜色不更新」而且\n // 没有任何信号。表被 release() 之后 scenegraph 与 internalProps 都是 null,读任何\n // getter 都会抛,那一种情形由守卫覆盖。\n if (table == null || isTableReleased(table)) return;\n\n (\n table as ListTableInstance & {\n __superadPalette?: ReturnType<typeof resolveTableCanvasPalette>;\n }\n ).__superadPalette = resolveTableCanvasPalette(token);\n // 与 palette 同一条通道:编辑器渲染在自己的 React root 里,只能从表实例上取主题。\n (table as ListTableInstance & { __superadTheme?: ThemeConfig }).__superadTheme = editorTheme;\n (table as ListTableInstance & { __superadI18n?: TableI18n }).__superadI18n = i18n;\n\n const scenegraph = getScenegraph(table);\n const headerRows = table.columnHeaderLevelCount ?? 1;\n const startRow = Math.max(headerRows, scenegraph.proxy?.rowStart ?? headerRows);\n // rowCount 是数量、不是行号,要 -1;对照 vtableAdapter 的 getVisibleRowRange 也是这么写的。\n const endRow = Math.min((table.rowCount ?? 1) - 1, scenegraph.proxy?.rowEnd ?? startRow + 40);\n const endCol = (table.colCount ?? 1) - 1;\n\n if (headerRows > 0) updateCellContentRange(table, 0, 0, endCol, headerRows - 1);\n if (endRow >= startRow) updateCellContentRange(table, 0, startRow, endCol, endRow);\n scenegraph.updateNextFrame?.();\n }, [editorTheme, i18n, mergedOption, tableRef, token]);\n\n const dataContentHeight = useMemo(\n () =>\n computeTableHeight({\n groupBy,\n headerRowHeight: parsePxSize(headerRowHeight),\n records,\n rowHeight: parsePxSize(rowHeight),\n showHeader,\n size,\n tree,\n }),\n [groupBy, headerRowHeight, records, rowHeight, showHeader, size, tree],\n );\n /**\n * 引擎实测优先:按数据算只在首帧成立(那时还没有引擎实例,SSR 也要有个值),一旦用户折叠过,\n * 行数就只有引擎知道了。见 `useTableVTableEvents` 里 `onHierarchyChange` 的注释。\n */\n const contentHeight = measuredContentHeight ?? dataContentHeight;\n const resolvedHeight =\n autoHeight !== false && typeof height === 'number' && records?.length\n ? Math.min(height, contentHeight)\n : (height ?? contentHeight);\n const rootStyle: CSSProperties = {\n height: toCssSize(resolvedHeight),\n width: toCssSize(width ?? '100%'),\n ...style,\n };\n\n return { mergedOption, rootStyle, stickyGroupBackground, token };\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { getScenegraph } from "../vtable/vtableAdapter.mjs";
|
|
3
|
+
import { placeEditHint, resolveEditHint, sameEditHint } from "../vtable/interaction.mjs";
|
|
4
|
+
import { useRef } from "react";
|
|
5
|
+
//#region src/Table/react/useTableScroll.ts
|
|
6
|
+
const useTableScroll = ({ rootRef, setA11yVersion, setHint, syncEditorPosition, syncFrozenColumnShadow, tableRef }) => {
|
|
7
|
+
/** 上一次同步给 a11y 层的行窗口;窗口没变就不必重渲染。 */
|
|
8
|
+
const lastA11yRangeRef = useRef("");
|
|
9
|
+
const handleScroll = () => {
|
|
10
|
+
syncFrozenColumnShadow();
|
|
11
|
+
syncEditorPosition();
|
|
12
|
+
const table = tableRef.current;
|
|
13
|
+
const host = rootRef.current;
|
|
14
|
+
if (table != null) {
|
|
15
|
+
const { proxy } = getScenegraph(table) ?? {};
|
|
16
|
+
const key = `${proxy?.rowStart ?? -1}:${proxy?.rowEnd ?? -1}`;
|
|
17
|
+
if (key !== lastA11yRangeRef.current) {
|
|
18
|
+
lastA11yRangeRef.current = key;
|
|
19
|
+
setA11yVersion((version) => version + 1);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
setHint((prev) => {
|
|
23
|
+
if (prev == null || table == null || host == null) return null;
|
|
24
|
+
const next = placeEditHint(resolveEditHint(table, prev.col, prev.row), table.getElement(), host);
|
|
25
|
+
return sameEditHint(prev, next) ? prev : next;
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
return handleScroll;
|
|
29
|
+
};
|
|
30
|
+
//#endregion
|
|
31
|
+
export { useTableScroll };
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=useTableScroll.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTableScroll.mjs","names":[],"sources":["../../../src/Table/react/useTableScroll.ts"],"sourcesContent":["'use client';\n\nimport type { ListTable as ListTableInstance } from '@visactor/vtable';\nimport { type Dispatch, type RefObject, type SetStateAction, useRef } from 'react';\n\nimport {\n type CellEditHint,\n placeEditHint,\n resolveEditHint,\n sameEditHint,\n} from '../vtable/interaction';\nimport { getScenegraph } from '../vtable/vtableAdapter';\n\nexport const useTableScroll = ({\n rootRef,\n setA11yVersion,\n setHint,\n syncEditorPosition,\n syncFrozenColumnShadow,\n tableRef,\n}: {\n rootRef: RefObject<HTMLDivElement | null>;\n setA11yVersion: Dispatch<SetStateAction<number>>;\n setHint: Dispatch<SetStateAction<CellEditHint | null>>;\n syncEditorPosition: () => void;\n syncFrozenColumnShadow: () => void;\n tableRef: RefObject<ListTableInstance | null>;\n}) => {\n /** 上一次同步给 a11y 层的行窗口;窗口没变就不必重渲染。 */\n const lastA11yRangeRef = useRef('');\n\n const handleScroll = () => {\n syncFrozenColumnShadow();\n syncEditorPosition();\n\n const table = tableRef.current;\n const host = rootRef.current;\n\n // a11y 层只镜像可见行,而它每个 cell 都要向 VTable 读值。原先每个 scroll 事件都 bump\n // 一次版本号 —— 实测 30 次滚动触发 29 次整树重渲染,a11y 层 360 个 cell 全量重读。\n // 行窗口没变(横向滚动、行内微调)时它的输出不会变,跳过。\n if (table != null) {\n // 键必须与 a11y.tsx 真正读取的输入一致:它用的是 scenegraph.proxy 的原始行窗口,\n // **不是** getVisibleRowRange(后者有 maxRows=80 的上限,小表上恒覆盖全表、窗口恒定,\n // 用它当键会让 a11y 层在滚动时完全不更新 —— 实测 Tree/Grouping 上 0 次)。\n const { proxy } = getScenegraph(table) ?? {};\n const key = `${proxy?.rowStart ?? -1}:${proxy?.rowEnd ?? -1}`;\n if (key !== lastA11yRangeRef.current) {\n lastA11yRangeRef.current = key;\n setA11yVersion((version) => version + 1);\n }\n }\n\n setHint((prev) => {\n if (prev == null || table == null || host == null) return null;\n\n const next = placeEditHint(\n resolveEditHint(table, prev.col, prev.row),\n table.getElement(),\n host,\n );\n // 去重:placeEditHint 每次都造新对象,直接返回它会让每个 scroll 事件都触发一次重渲染。\n return sameEditHint(prev, next) ? prev : next;\n });\n };\n\n return handleScroll;\n};\n"],"mappings":";;;;;AAaA,MAAa,kBAAkB,EAC7B,SACA,gBACA,SACA,oBACA,wBACA,eAQI;;CAEJ,MAAM,mBAAmB,OAAO,EAAE;CAElC,MAAM,qBAAqB;EACzB,uBAAuB;EACvB,mBAAmB;EAEnB,MAAM,QAAQ,SAAS;EACvB,MAAM,OAAO,QAAQ;EAKrB,IAAI,SAAS,MAAM;GAIjB,MAAM,EAAE,UAAU,cAAc,KAAK,KAAK,CAAC;GAC3C,MAAM,MAAM,GAAG,OAAO,YAAY,GAAG,GAAG,OAAO,UAAU;GACzD,IAAI,QAAQ,iBAAiB,SAAS;IACpC,iBAAiB,UAAU;IAC3B,gBAAgB,YAAY,UAAU,CAAC;GACzC;EACF;EAEA,SAAS,SAAS;GAChB,IAAI,QAAQ,QAAQ,SAAS,QAAQ,QAAQ,MAAM,OAAO;GAE1D,MAAM,OAAO,cACX,gBAAgB,OAAO,KAAK,KAAK,KAAK,GAAG,GACzC,MAAM,WAAW,GACjB,IACF;GAEA,OAAO,aAAa,MAAM,IAAI,IAAI,OAAO;EAC3C,CAAC;CACH;CAEA,OAAO;AACT"}
|