@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,381 @@
|
|
|
1
|
+
import { TABLE_CHROME } from "../canvas/theme.mjs";
|
|
2
|
+
import { emptyCellLabel, formatAddress, formatDateRange, formatDateTime, formatJson, formatNumber, isEmptyCellValue, isGroupTitleRecord } from "../core/cellValue.mjs";
|
|
3
|
+
import { tableText } from "../core/tableI18n.mjs";
|
|
4
|
+
import { createCanvasTextLayout, createCurrencyLayout } from "../canvas/textPainters.mjs";
|
|
5
|
+
import { createArrayLayout, createLinkLayout, createTagLayout, createUserLayout } from "../canvas/chipPainters.mjs";
|
|
6
|
+
import { JsonEditor, NumberEditor, TextEditor } from "../react/editors/inline.mjs";
|
|
7
|
+
import { AddressEditor, ArrayEditor, DateRangeEditor, DateTimeEditor, OptionEditor, UserEditor } from "../react/editors/picker.mjs";
|
|
8
|
+
import { createBooleanLayout, createCheckboxLayout, createRatingLayout } from "../canvas/controlPainters.mjs";
|
|
9
|
+
import { TABLE_CELL_MIN_WIDTH } from "../type.mjs";
|
|
10
|
+
//#region src/Table/vtable/columns.ts
|
|
11
|
+
const isGroupColumn = (column) => "columns" in column && Array.isArray(column.columns);
|
|
12
|
+
/**
|
|
13
|
+
* 使用方是否要这一列**整列交回 VTable**。
|
|
14
|
+
*
|
|
15
|
+
* 判据只看「这列的渲染方式由 VTable 原生负责」的信号:`cellType` / `customRender` /
|
|
16
|
+
* `customLayout` / `headerType` / 分组子列。
|
|
17
|
+
*
|
|
18
|
+
* **`fieldFormat` **不在**这里**。它只是自定义显示,是极普通的写法,而我们照样能编译这一列 ——
|
|
19
|
+
* 曾经把它也算作「原生列」,代价是整列被原样返回、**不挂编辑器**:只是加了个 `fieldFormat`,
|
|
20
|
+
* 列就静默失去编辑能力(树形表格 demo 的前三列连同树列本身都中招)。
|
|
21
|
+
*/
|
|
22
|
+
const isRawVTableColumn = (column) => isGroupColumn(column) || "cellType" in column || "customRender" in column || "customLayout" in column || "headerType" in column;
|
|
23
|
+
const canEdit = (column, editable) => column.editable ?? editable ?? false;
|
|
24
|
+
const fieldFormatter = (field, format, empty, i18n) => (record) => {
|
|
25
|
+
if (isGroupTitleRecord(record)) return "";
|
|
26
|
+
const text = format(record == null ? void 0 : record[field]);
|
|
27
|
+
if (text.trim()) return text;
|
|
28
|
+
if (!empty) return "";
|
|
29
|
+
return i18n ? tableText({ __superadI18n: i18n }, "setField", { title: empty }) : emptyCellLabel(empty);
|
|
30
|
+
};
|
|
31
|
+
const withCellKind = (define, kind, editable) => {
|
|
32
|
+
const next = define;
|
|
33
|
+
next.superadEditable = editable;
|
|
34
|
+
next.superadKind = kind;
|
|
35
|
+
return next;
|
|
36
|
+
};
|
|
37
|
+
/** 标 `superadKind`,并带上是否可编辑(画布铅笔槽 / 悬停浮层要读)。 */
|
|
38
|
+
const withTextKind = (define, kind, editable) => Object.assign(define, {
|
|
39
|
+
superadEditable: editable,
|
|
40
|
+
superadKind: kind
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* 把选择项挂到编译结果上。
|
|
44
|
+
*
|
|
45
|
+
* painter 是把 `options` 闭包进去的,编译后的列上只剩一个 `customLayout` 函数 —— 于是画布上
|
|
46
|
+
* 是「已完成」、而**按列定义取值的地方**(a11y 隐藏层、剪贴板桥)只能拿到记录里的原始值
|
|
47
|
+
* `done`。屏幕阅读器因此朗读英文键。把 `options` 一并留在列上,这些地方才能解析出同一个标签。
|
|
48
|
+
*/
|
|
49
|
+
const withOptions = (define, options, kind, editable, duration) => Object.assign(define, {
|
|
50
|
+
superadDuration: duration,
|
|
51
|
+
superadEditable: editable,
|
|
52
|
+
superadKind: kind,
|
|
53
|
+
superadOptions: options
|
|
54
|
+
});
|
|
55
|
+
const withLinkKind = (define, linkKind, editable) => {
|
|
56
|
+
const next = define;
|
|
57
|
+
next.superadEditable = editable;
|
|
58
|
+
next.superadKind = "link";
|
|
59
|
+
next.superadLinkKind = linkKind;
|
|
60
|
+
return next;
|
|
61
|
+
};
|
|
62
|
+
const compileSuperAdColumn = (column, ctx, treeField) => {
|
|
63
|
+
const { currency = "¥", field, format, options = [], title, users = [], width } = column;
|
|
64
|
+
const type = column.type ?? "text";
|
|
65
|
+
const editable = canEdit(column, ctx.editable);
|
|
66
|
+
const empty = editable ? title : void 0;
|
|
67
|
+
const multiple = column.multiple ?? [
|
|
68
|
+
"array",
|
|
69
|
+
"email",
|
|
70
|
+
"phone",
|
|
71
|
+
"tag",
|
|
72
|
+
"user"
|
|
73
|
+
].includes(type);
|
|
74
|
+
const tree = field === treeField || column.tree ? true : void 0;
|
|
75
|
+
const sort = column.sort || void 0;
|
|
76
|
+
const token = ctx.token;
|
|
77
|
+
const useCanvasTextLayout = Boolean(ctx.groupedTree) && tree !== true;
|
|
78
|
+
if (type === "checkbox") return withCellKind({
|
|
79
|
+
cellType: "text",
|
|
80
|
+
customLayout: createCheckboxLayout(),
|
|
81
|
+
field,
|
|
82
|
+
sort,
|
|
83
|
+
title,
|
|
84
|
+
tree,
|
|
85
|
+
width
|
|
86
|
+
}, "checkbox", editable);
|
|
87
|
+
if (type === "boolean") return withCellKind({
|
|
88
|
+
cellType: "text",
|
|
89
|
+
customLayout: createBooleanLayout(editable),
|
|
90
|
+
field,
|
|
91
|
+
sort,
|
|
92
|
+
title,
|
|
93
|
+
tree,
|
|
94
|
+
width
|
|
95
|
+
}, "boolean", editable);
|
|
96
|
+
if (type === "rating") return withCellKind({
|
|
97
|
+
cellType: "text",
|
|
98
|
+
customLayout: createRatingLayout(),
|
|
99
|
+
field,
|
|
100
|
+
sort,
|
|
101
|
+
title,
|
|
102
|
+
tree,
|
|
103
|
+
width
|
|
104
|
+
}, "rating", editable);
|
|
105
|
+
if (type === "array") return withTextKind({
|
|
106
|
+
cellType: "text",
|
|
107
|
+
customLayout: createArrayLayout(empty),
|
|
108
|
+
editor: editable ? new ArrayEditor() : void 0,
|
|
109
|
+
field,
|
|
110
|
+
sort,
|
|
111
|
+
title,
|
|
112
|
+
tree,
|
|
113
|
+
width
|
|
114
|
+
}, "array", editable);
|
|
115
|
+
if (type === "email" || type === "phone" || type === "link") return withLinkKind({
|
|
116
|
+
cellType: "text",
|
|
117
|
+
customLayout: createLinkLayout(type, empty),
|
|
118
|
+
editor: editable ? multiple ? new ArrayEditor() : new TextEditor() : void 0,
|
|
119
|
+
field,
|
|
120
|
+
sort,
|
|
121
|
+
title,
|
|
122
|
+
tree,
|
|
123
|
+
width
|
|
124
|
+
}, type, editable);
|
|
125
|
+
if (type === "currency") return {
|
|
126
|
+
cellType: "text",
|
|
127
|
+
customLayout: createCurrencyLayout(currency, empty),
|
|
128
|
+
editor: editable ? new NumberEditor({ prefix: currency }) : void 0,
|
|
129
|
+
field,
|
|
130
|
+
sort,
|
|
131
|
+
title,
|
|
132
|
+
tree,
|
|
133
|
+
width
|
|
134
|
+
};
|
|
135
|
+
if (type === "json") return {
|
|
136
|
+
cellType: "text",
|
|
137
|
+
...useCanvasTextLayout ? { customLayout: createCanvasTextLayout() } : null,
|
|
138
|
+
editor: editable ? new JsonEditor() : void 0,
|
|
139
|
+
field,
|
|
140
|
+
fieldFormat: fieldFormatter(field, formatJson, empty, ctx.i18n),
|
|
141
|
+
sort,
|
|
142
|
+
title,
|
|
143
|
+
tree,
|
|
144
|
+
width
|
|
145
|
+
};
|
|
146
|
+
if (type === "address") return {
|
|
147
|
+
cellType: "text",
|
|
148
|
+
...useCanvasTextLayout ? { customLayout: createCanvasTextLayout() } : null,
|
|
149
|
+
editor: editable ? new AddressEditor() : void 0,
|
|
150
|
+
field,
|
|
151
|
+
fieldFormat: fieldFormatter(field, formatAddress, empty, ctx.i18n),
|
|
152
|
+
sort,
|
|
153
|
+
title,
|
|
154
|
+
tree,
|
|
155
|
+
width
|
|
156
|
+
};
|
|
157
|
+
if (type === "image") return {
|
|
158
|
+
cellType: "image",
|
|
159
|
+
clickToPreview: true,
|
|
160
|
+
field,
|
|
161
|
+
imageAutoSizing: false,
|
|
162
|
+
keepAspectRatio: true,
|
|
163
|
+
style: { margin: 4 },
|
|
164
|
+
title,
|
|
165
|
+
tree,
|
|
166
|
+
width
|
|
167
|
+
};
|
|
168
|
+
if (type === "progress") {
|
|
169
|
+
const unit = column.unit ?? "%";
|
|
170
|
+
return {
|
|
171
|
+
cellType: "progressbar",
|
|
172
|
+
editor: editable ? new NumberEditor({
|
|
173
|
+
max: 100,
|
|
174
|
+
min: 0,
|
|
175
|
+
suffix: unit
|
|
176
|
+
}) : void 0,
|
|
177
|
+
field,
|
|
178
|
+
fieldFormat: fieldFormatter(field, (value) => formatNumber(value, unit)),
|
|
179
|
+
max: 100,
|
|
180
|
+
min: 0,
|
|
181
|
+
sort,
|
|
182
|
+
style: {
|
|
183
|
+
barBgColor: token?.colorFillSecondary ?? "#f5f5f5",
|
|
184
|
+
barBottom: 10,
|
|
185
|
+
barColor: (args) => {
|
|
186
|
+
const value = Number(args.dataValue ?? args.value);
|
|
187
|
+
if (Number.isFinite(value) && value >= 100) return token?.colorSuccess ?? TABLE_CHROME.success;
|
|
188
|
+
return token?.colorInfo ?? TABLE_CHROME.accent;
|
|
189
|
+
},
|
|
190
|
+
barHeight: 6,
|
|
191
|
+
color: token?.colorText ?? TABLE_CHROME.text,
|
|
192
|
+
fontSize: 12,
|
|
193
|
+
textAlign: "right"
|
|
194
|
+
},
|
|
195
|
+
title,
|
|
196
|
+
tree,
|
|
197
|
+
width
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
if (type === "number") {
|
|
201
|
+
const formatValue = (value) => formatNumber(value, column.unit);
|
|
202
|
+
return {
|
|
203
|
+
cellType: "text",
|
|
204
|
+
...useCanvasTextLayout ? { customLayout: createCanvasTextLayout() } : null,
|
|
205
|
+
editor: editable ? new NumberEditor({ suffix: column.unit }) : void 0,
|
|
206
|
+
field,
|
|
207
|
+
fieldFormat: fieldFormatter(field, formatValue, empty, ctx.i18n),
|
|
208
|
+
sort,
|
|
209
|
+
title,
|
|
210
|
+
tree,
|
|
211
|
+
width
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
if (type === "date" || type === "datetime") {
|
|
215
|
+
const pattern = format ?? (type === "datetime" ? "YYYY-MM-DD HH:mm" : "YYYY-MM-DD");
|
|
216
|
+
return {
|
|
217
|
+
cellType: "text",
|
|
218
|
+
...useCanvasTextLayout ? { customLayout: createCanvasTextLayout() } : null,
|
|
219
|
+
editor: editable ? new DateTimeEditor(pattern.includes("HH")) : void 0,
|
|
220
|
+
field,
|
|
221
|
+
fieldFormat: fieldFormatter(field, (value) => formatDateTime(value, pattern), empty, ctx.i18n),
|
|
222
|
+
sort,
|
|
223
|
+
title,
|
|
224
|
+
tree,
|
|
225
|
+
width
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
if (type === "dateRange") {
|
|
229
|
+
const pattern = format ?? "YYYY-MM-DD";
|
|
230
|
+
return {
|
|
231
|
+
cellType: "text",
|
|
232
|
+
...useCanvasTextLayout ? { customLayout: createCanvasTextLayout() } : null,
|
|
233
|
+
editor: editable ? new DateRangeEditor(pattern) : void 0,
|
|
234
|
+
field,
|
|
235
|
+
fieldFormat: fieldFormatter(field, (value) => formatDateRange(value, pattern), empty, ctx.i18n),
|
|
236
|
+
sort,
|
|
237
|
+
title,
|
|
238
|
+
tree,
|
|
239
|
+
width
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
if (type === "tag" || type === "select") return withOptions({
|
|
243
|
+
cellType: "text",
|
|
244
|
+
customLayout: createTagLayout(options, empty, column.duration),
|
|
245
|
+
editor: editable ? new OptionEditor(options, multiple) : void 0,
|
|
246
|
+
field,
|
|
247
|
+
sort,
|
|
248
|
+
title,
|
|
249
|
+
tree,
|
|
250
|
+
width
|
|
251
|
+
}, options, type, editable, column.duration);
|
|
252
|
+
if (type === "user") return withTextKind({
|
|
253
|
+
cellType: "text",
|
|
254
|
+
customLayout: createUserLayout(empty),
|
|
255
|
+
editor: editable ? new UserEditor(users, multiple) : void 0,
|
|
256
|
+
field,
|
|
257
|
+
sort,
|
|
258
|
+
title,
|
|
259
|
+
tree,
|
|
260
|
+
width
|
|
261
|
+
}, "user", editable);
|
|
262
|
+
return {
|
|
263
|
+
cellType: "text",
|
|
264
|
+
...useCanvasTextLayout ? { customLayout: createCanvasTextLayout() } : null,
|
|
265
|
+
editor: editable ? new TextEditor() : void 0,
|
|
266
|
+
field,
|
|
267
|
+
fieldFormat: fieldFormatter(field, (value) => value == null ? "" : String(value), empty, ctx.i18n),
|
|
268
|
+
sort,
|
|
269
|
+
style: tree ? {
|
|
270
|
+
color: token?.colorText || TABLE_CHROME.text,
|
|
271
|
+
fontSize: 14
|
|
272
|
+
} : void 0,
|
|
273
|
+
title,
|
|
274
|
+
tree,
|
|
275
|
+
width
|
|
276
|
+
};
|
|
277
|
+
};
|
|
278
|
+
const resolveTreeField = (columns, tree) => {
|
|
279
|
+
const marked = columns.find((column) => !isRawVTableColumn(column) && "tree" in column && column.tree);
|
|
280
|
+
if (marked?.field) return marked.field;
|
|
281
|
+
if (!tree) return void 0;
|
|
282
|
+
return columns.find((column) => !isRawVTableColumn(column))?.field;
|
|
283
|
+
};
|
|
284
|
+
const resolveColumnMinWidth = (column, treeField) => {
|
|
285
|
+
if (column.minWidth != null) return column.minWidth;
|
|
286
|
+
if (column.tree || column.field === treeField) return 160;
|
|
287
|
+
return TABLE_CELL_MIN_WIDTH[column.type ?? "text"];
|
|
288
|
+
};
|
|
289
|
+
const withMinWidth = (column, minWidth) => {
|
|
290
|
+
const next = {
|
|
291
|
+
...column,
|
|
292
|
+
minWidth: column.minWidth ?? minWidth
|
|
293
|
+
};
|
|
294
|
+
const children = column.columns;
|
|
295
|
+
if (Array.isArray(children)) next.columns = children.map((child) => withMinWidth(child, 80));
|
|
296
|
+
return next;
|
|
297
|
+
};
|
|
298
|
+
const withDefaultColumnMinWidths = (columns) => columns?.map((column) => withMinWidth(column, 80));
|
|
299
|
+
/**
|
|
300
|
+
* 空值时把文字压成弱色 —— 与 canvas 那条路径(`createEmptyCellText`)对齐。
|
|
301
|
+
*
|
|
302
|
+
* 原生渲染的列(有 `fieldFormat`、没有 `customLayout`)用的是列样式,不区分空值就会同一张表里
|
|
303
|
+
* 「设置 名称」深、「设置 状态」浅。json / address / progress / number / date 这几个分支各写各的
|
|
304
|
+
* `fieldFormat`,所以在这里一处收口。
|
|
305
|
+
*
|
|
306
|
+
* 两个必须注意的点:
|
|
307
|
+
* - 判空看**原始值**:格式化后的文本在空值时正好是占位文案(「设置 X」),拿它比会误判。
|
|
308
|
+
* - 使用方给了 `fieldFormat` 时**不介入**:显示值来自那个函数、未必是 `field`。树表的 department
|
|
309
|
+
* 列就是这样(值取 `rec.department ?? rec.group ?? rec.name`,而记录里 `group` 是空的),
|
|
310
|
+
* 按 `field` 判空会把整列错涂成弱色。
|
|
311
|
+
*/
|
|
312
|
+
const withBlankMutedColor = (define, column, token) => {
|
|
313
|
+
if (column.fieldFormat != null || define.fieldFormat == null || define.customLayout != null) return;
|
|
314
|
+
const base = define.style;
|
|
315
|
+
define.style = ((args) => {
|
|
316
|
+
const record = args.table?.getCellOriginRecord?.(args.col, args.row);
|
|
317
|
+
const blank = record != null && isEmptyCellValue(record[column.field]);
|
|
318
|
+
const inherited = typeof base === "function" ? base(args) : base ?? {};
|
|
319
|
+
return {
|
|
320
|
+
...inherited,
|
|
321
|
+
color: blank ? token?.colorTextTertiary ?? TABLE_CHROME.textMuted : inherited.color ?? token?.colorText ?? TABLE_CHROME.text
|
|
322
|
+
};
|
|
323
|
+
});
|
|
324
|
+
};
|
|
325
|
+
/**
|
|
326
|
+
* 原生渲染(无 customLayout)且**真有编辑器**的列:右侧 padding 多留铅笔槽。
|
|
327
|
+
*
|
|
328
|
+
* 判据必须与 `resolveEditHint`(看 `getEditor`)对齐 —— 只看 `canEdit` 会给 image 这类
|
|
329
|
+
* 「表可编辑但本列没有 editor」的列白白让出 28px,进度条 / 封面被挤窄却永远不出现铅笔。
|
|
330
|
+
* customLayout 那条路径由各 painter 自己减 `EDIT_HINT_GUTTER`,这里再加会双倍。
|
|
331
|
+
*/
|
|
332
|
+
const withEditHintPadding = (define) => {
|
|
333
|
+
if (define.customLayout != null || define.editor == null) return;
|
|
334
|
+
const base = define.style;
|
|
335
|
+
define.style = ((args) => {
|
|
336
|
+
const inherited = typeof base === "function" ? base(args) : base ?? {};
|
|
337
|
+
const padding = inherited.padding;
|
|
338
|
+
let next;
|
|
339
|
+
if (Array.isArray(padding)) next = [
|
|
340
|
+
Number(padding[0] ?? 0),
|
|
341
|
+
Number(padding[1] ?? 0) + 28,
|
|
342
|
+
Number(padding[2] ?? 0),
|
|
343
|
+
Number(padding[3] ?? 0)
|
|
344
|
+
];
|
|
345
|
+
else if (typeof padding === "number") next = [
|
|
346
|
+
padding,
|
|
347
|
+
padding + 28,
|
|
348
|
+
padding,
|
|
349
|
+
padding
|
|
350
|
+
];
|
|
351
|
+
else next = [
|
|
352
|
+
0,
|
|
353
|
+
TABLE_CHROME.paddingX + 28,
|
|
354
|
+
0,
|
|
355
|
+
TABLE_CHROME.paddingX
|
|
356
|
+
];
|
|
357
|
+
return {
|
|
358
|
+
...inherited,
|
|
359
|
+
padding: next
|
|
360
|
+
};
|
|
361
|
+
});
|
|
362
|
+
};
|
|
363
|
+
const compileColumns = (columns, ctx = {}) => {
|
|
364
|
+
if (!columns) return void 0;
|
|
365
|
+
const treeField = resolveTreeField(columns, ctx.tree);
|
|
366
|
+
return columns.map((column) => {
|
|
367
|
+
if (isRawVTableColumn(column)) return withMinWidth(column, 80);
|
|
368
|
+
const tableColumn = column;
|
|
369
|
+
const compiled = compileSuperAdColumn(tableColumn, ctx, treeField);
|
|
370
|
+
if (tableColumn.style != null) compiled.style = tableColumn.style;
|
|
371
|
+
if (tableColumn.fieldFormat != null) compiled.fieldFormat = tableColumn.fieldFormat;
|
|
372
|
+
withBlankMutedColor(compiled, tableColumn, ctx.token);
|
|
373
|
+
withEditHintPadding(compiled);
|
|
374
|
+
if (compiled.editor != null) compiled.superadEditable = true;
|
|
375
|
+
return withMinWidth(compiled, resolveColumnMinWidth(tableColumn, treeField));
|
|
376
|
+
});
|
|
377
|
+
};
|
|
378
|
+
//#endregion
|
|
379
|
+
export { compileColumns, withDefaultColumnMinWidths };
|
|
380
|
+
|
|
381
|
+
//# sourceMappingURL=columns.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"columns.mjs","names":[],"sources":["../../../src/Table/vtable/columns.ts"],"sourcesContent":["import type { ColumnDefine, ColumnsDefine } from '@visactor/vtable';\n\nimport {\n createArrayLayout,\n createLinkLayout,\n createTagLayout,\n createUserLayout,\n} from '../canvas/chipPainters';\nimport {\n createBooleanLayout,\n createCheckboxLayout,\n createRatingLayout,\n} from '../canvas/controlPainters';\nimport { EDIT_HINT_GUTTER } from '../canvas/paintUtils';\nimport { createCanvasTextLayout, createCurrencyLayout } from '../canvas/textPainters';\nimport { TABLE_CHROME, type TableToken } from '../canvas/theme';\nimport {\n emptyCellLabel,\n formatAddress,\n formatDateRange,\n formatDateTime,\n formatJson,\n formatNumber,\n isEmptyCellValue,\n isGroupTitleRecord,\n type LinkKind,\n} from '../core/cellValue';\nimport { type TableI18n, tableText } from '../core/tableI18n';\nimport {\n AddressEditor,\n ArrayEditor,\n DateRangeEditor,\n DateTimeEditor,\n JsonEditor,\n NumberEditor,\n OptionEditor,\n TextEditor,\n UserEditor,\n} from '../react/editors';\nimport {\n DEFAULT_TABLE_COLUMN_MIN_WIDTH,\n TABLE_CELL_MIN_WIDTH,\n type TableCellType,\n type TableColumn,\n type TableColumnInput,\n type TableSelectOption,\n} from '../type';\n\nexport interface CompileColumnsContext {\n editable?: boolean;\n groupedTree?: boolean;\n i18n?: TableI18n;\n token?: TableToken;\n tree?: boolean;\n}\n\nconst isGroupColumn = (column: TableColumnInput): boolean =>\n 'columns' in column && Array.isArray((column as { columns?: unknown }).columns);\n\n/**\n * 使用方是否要这一列**整列交回 VTable**。\n *\n * 判据只看「这列的渲染方式由 VTable 原生负责」的信号:`cellType` / `customRender` /\n * `customLayout` / `headerType` / 分组子列。\n *\n * **`fieldFormat` **不在**这里**。它只是自定义显示,是极普通的写法,而我们照样能编译这一列 ——\n * 曾经把它也算作「原生列」,代价是整列被原样返回、**不挂编辑器**:只是加了个 `fieldFormat`,\n * 列就静默失去编辑能力(树形表格 demo 的前三列连同树列本身都中招)。\n */\nconst isRawVTableColumn = (column: TableColumnInput): column is ColumnDefine =>\n isGroupColumn(column) ||\n 'cellType' in column ||\n 'customRender' in column ||\n 'customLayout' in column ||\n 'headerType' in column;\n\nconst canEdit = (column: TableColumn, editable?: boolean) => column.editable ?? editable ?? false;\n\nconst fieldFormatter =\n (\n field: string,\n format: (value: unknown) => string,\n empty?: string,\n i18n?: TableI18n,\n ): ((record: Record<string, unknown>) => string) =>\n (record) => {\n if (isGroupTitleRecord(record)) return '';\n const text = format(record == null ? undefined : record[field]);\n\n if (text.trim()) return text;\n if (!empty) return '';\n return i18n\n ? tableText({ __superadI18n: i18n }, 'setField', { title: empty })\n : emptyCellLabel(empty);\n };\n\n/** Kinds that toggle in place when their cell is clicked. */\ntype SuperAdToggleKind = 'boolean' | 'checkbox' | 'rating';\n\n/**\n * Every `superadKind` marker value written onto a compiled VTable column.\n *\n * `array` / `select` / `tag` / `user` 不参与点击切换,标出来是给 **a11y 隐藏层与剪贴板**\n * 用的:这几类的显示文本由 painter 从 `options` / 姓名 / 分隔符映射出来,而 `getCellValue`\n * 给的是记录原始值(读屏于是念 `done` 而不是「已完成」,对象值更是一串 `[object Object]`)。\n */\nexport type SuperAdCellKind = SuperAdToggleKind | 'array' | 'link' | 'select' | 'tag' | 'user';\n\n/** Markers read back by `interaction.ts` via `getBodyColumnDefine`. */\nexport interface SuperAdCellMarkers {\n /** 状态标题后跟的时长来源(见 `TableColumn.duration`),供悬停浮层与画布用同一份预留。 */\n superadDuration?: string | { from: string; to: string };\n superadEditable?: boolean;\n superadKind?: SuperAdCellKind;\n superadLinkKind?: LinkKind;\n /** 选择项,供 a11y / 剪贴板把原始值还原成画面上的标签(见 `withOptions`)。 */\n superadOptions?: TableSelectOption[];\n}\n\nconst withCellKind = (\n define: ColumnDefine,\n kind: SuperAdToggleKind,\n editable: boolean,\n): ColumnDefine => {\n const next = define as ColumnDefine & SuperAdCellMarkers;\n next.superadEditable = editable;\n next.superadKind = kind;\n return next;\n};\n\n/** 标 `superadKind`,并带上是否可编辑(画布铅笔槽 / 悬停浮层要读)。 */\nconst withTextKind = (\n define: ColumnDefine,\n kind: 'array' | 'user',\n editable: boolean,\n): ColumnDefine =>\n Object.assign(define, {\n superadEditable: editable,\n superadKind: kind,\n } as Partial<SuperAdCellMarkers>);\n\n/**\n * 把选择项挂到编译结果上。\n *\n * painter 是把 `options` 闭包进去的,编译后的列上只剩一个 `customLayout` 函数 —— 于是画布上\n * 是「已完成」、而**按列定义取值的地方**(a11y 隐藏层、剪贴板桥)只能拿到记录里的原始值\n * `done`。屏幕阅读器因此朗读英文键。把 `options` 一并留在列上,这些地方才能解析出同一个标签。\n */\nconst withOptions = (\n define: ColumnDefine,\n options: TableSelectOption[],\n kind: 'select' | 'tag',\n editable: boolean,\n duration?: string | { from: string; to: string },\n): ColumnDefine =>\n Object.assign(define, {\n superadDuration: duration,\n superadEditable: editable,\n superadKind: kind,\n superadOptions: options,\n } as Partial<SuperAdCellMarkers>);\n\nconst withLinkKind = (\n define: ColumnDefine,\n linkKind: LinkKind,\n editable: boolean,\n): ColumnDefine => {\n const next = define as ColumnDefine & SuperAdCellMarkers;\n next.superadEditable = editable;\n next.superadKind = 'link';\n next.superadLinkKind = linkKind;\n return next;\n};\n\nconst compileSuperAdColumn = (\n column: TableColumn,\n ctx: CompileColumnsContext,\n treeField?: string,\n): ColumnDefine => {\n const { currency = '¥', field, format, options = [], title, users = [], width } = column;\n const type: TableCellType = column.type ?? 'text';\n const editable = canEdit(column, ctx.editable);\n const empty = editable ? title : undefined;\n const multiple = column.multiple ?? ['array', 'email', 'phone', 'tag', 'user'].includes(type);\n const tree = field === treeField || column.tree ? true : undefined;\n const sort = column.sort || undefined;\n const token = ctx.token;\n const useCanvasTextLayout = Boolean(ctx.groupedTree) && tree !== true;\n\n if (type === 'checkbox') {\n return withCellKind(\n {\n cellType: 'text',\n customLayout: createCheckboxLayout(),\n field,\n sort,\n title,\n tree,\n width,\n },\n 'checkbox',\n editable,\n );\n }\n\n if (type === 'boolean') {\n return withCellKind(\n {\n cellType: 'text',\n customLayout: createBooleanLayout(editable),\n field,\n sort,\n title,\n tree,\n width,\n },\n 'boolean',\n editable,\n );\n }\n\n if (type === 'rating') {\n return withCellKind(\n {\n cellType: 'text',\n customLayout: createRatingLayout(),\n field,\n sort,\n title,\n tree,\n width,\n },\n 'rating',\n editable,\n );\n }\n\n if (type === 'array') {\n return withTextKind(\n {\n cellType: 'text',\n customLayout: createArrayLayout(empty),\n editor: editable ? new ArrayEditor() : undefined,\n field,\n sort,\n title,\n tree,\n width,\n },\n 'array',\n editable,\n );\n }\n\n if (type === 'email' || type === 'phone' || type === 'link') {\n return withLinkKind(\n {\n cellType: 'text',\n customLayout: createLinkLayout(type, empty),\n editor: editable ? (multiple ? new ArrayEditor() : new TextEditor()) : undefined,\n field,\n sort,\n title,\n tree,\n width,\n },\n type,\n editable,\n );\n }\n\n if (type === 'currency') {\n return {\n cellType: 'text',\n customLayout: createCurrencyLayout(currency, empty),\n editor: editable ? new NumberEditor({ prefix: currency }) : undefined,\n field,\n sort,\n title,\n tree,\n width,\n };\n }\n\n if (type === 'json') {\n return {\n cellType: 'text',\n ...(useCanvasTextLayout ? { customLayout: createCanvasTextLayout() } : null),\n editor: editable ? new JsonEditor() : undefined,\n field,\n fieldFormat: fieldFormatter(field, formatJson, empty, ctx.i18n),\n sort,\n title,\n tree,\n width,\n };\n }\n\n if (type === 'address') {\n return {\n cellType: 'text',\n ...(useCanvasTextLayout ? { customLayout: createCanvasTextLayout() } : null),\n editor: editable ? new AddressEditor() : undefined,\n field,\n fieldFormat: fieldFormatter(field, formatAddress, empty, ctx.i18n),\n sort,\n title,\n tree,\n width,\n };\n }\n\n if (type === 'image') {\n return {\n cellType: 'image',\n clickToPreview: true,\n field,\n imageAutoSizing: false,\n keepAspectRatio: true,\n style: { margin: 4 },\n title,\n tree,\n width,\n };\n }\n\n if (type === 'progress') {\n const unit = column.unit ?? '%';\n return {\n cellType: 'progressbar',\n editor: editable ? new NumberEditor({ max: 100, min: 0, suffix: unit }) : undefined,\n field,\n // 走 fieldFormatter:它有分组标题行与 record == null 的守卫,其它类型的 fieldFormat\n // 都从这里出。直接 `record[field]` 会在分组标题行上抛(record 可能为空)。\n fieldFormat: fieldFormatter(field, (value) => formatNumber(value, unit)),\n max: 100,\n min: 0,\n sort,\n style: {\n barBgColor: token?.colorFillSecondary ?? '#f5f5f5',\n barBottom: 10,\n barColor: (args) => {\n const value = Number(args.dataValue ?? args.value);\n if (Number.isFinite(value) && value >= 100)\n return token?.colorSuccess ?? TABLE_CHROME.success;\n return token?.colorInfo ?? TABLE_CHROME.accent;\n },\n barHeight: 6,\n // 走 token,否则暗色模式下是近黑色压在同为暗色的容器上。\n color: token?.colorText ?? TABLE_CHROME.text,\n fontSize: 12,\n textAlign: 'right',\n },\n title,\n tree,\n width,\n };\n }\n\n if (type === 'number') {\n const formatValue = (value: unknown) => formatNumber(value, column.unit);\n return {\n cellType: 'text',\n ...(useCanvasTextLayout ? { customLayout: createCanvasTextLayout() } : null),\n editor: editable ? new NumberEditor({ suffix: column.unit }) : undefined,\n field,\n fieldFormat: fieldFormatter(field, formatValue, empty, ctx.i18n),\n sort,\n title,\n tree,\n width,\n };\n }\n\n if (type === 'date' || type === 'datetime') {\n const pattern = format ?? (type === 'datetime' ? 'YYYY-MM-DD HH:mm' : 'YYYY-MM-DD');\n return {\n cellType: 'text',\n ...(useCanvasTextLayout ? { customLayout: createCanvasTextLayout() } : null),\n editor: editable ? new DateTimeEditor(pattern.includes('HH')) : undefined,\n field,\n fieldFormat: fieldFormatter(\n field,\n (value) => formatDateTime(value, pattern),\n empty,\n ctx.i18n,\n ),\n sort,\n title,\n tree,\n width,\n };\n }\n\n if (type === 'dateRange') {\n const pattern = format ?? 'YYYY-MM-DD';\n return {\n cellType: 'text',\n ...(useCanvasTextLayout ? { customLayout: createCanvasTextLayout() } : null),\n editor: editable ? new DateRangeEditor(pattern) : undefined,\n field,\n fieldFormat: fieldFormatter(\n field,\n (value) => formatDateRange(value, pattern),\n empty,\n ctx.i18n,\n ),\n sort,\n title,\n tree,\n width,\n };\n }\n\n if (type === 'tag' || type === 'select') {\n return withOptions(\n {\n cellType: 'text',\n customLayout: createTagLayout(options, empty, column.duration),\n editor: editable ? new OptionEditor(options, multiple) : undefined,\n field,\n sort,\n title,\n tree,\n width,\n },\n options,\n type,\n editable,\n column.duration,\n );\n }\n\n if (type === 'user') {\n return withTextKind(\n {\n cellType: 'text',\n customLayout: createUserLayout(empty),\n editor: editable ? new UserEditor(users, multiple) : undefined,\n field,\n sort,\n title,\n tree,\n width,\n },\n 'user',\n editable,\n );\n }\n\n return {\n cellType: 'text',\n ...(useCanvasTextLayout ? { customLayout: createCanvasTextLayout() } : null),\n editor: editable ? new TextEditor() : undefined,\n field,\n fieldFormat: fieldFormatter(\n field,\n (value) => (value == null ? '' : String(value)),\n empty,\n ctx.i18n,\n ),\n sort,\n style: tree ? { color: token?.colorText || TABLE_CHROME.text, fontSize: 14 } : undefined,\n title,\n tree,\n width,\n };\n};\n\nconst resolveTreeField = (columns: TableColumnInput[], tree?: boolean): string | undefined => {\n const marked = columns.find(\n (column) => !isRawVTableColumn(column) && 'tree' in column && column.tree,\n ) as TableColumn | undefined;\n if (marked?.field) return marked.field;\n if (!tree) return undefined;\n const first = columns.find((column) => !isRawVTableColumn(column)) as TableColumn | undefined;\n return first?.field;\n};\n\nconst resolveColumnMinWidth = (column: TableColumn, treeField?: string): number | string => {\n if (column.minWidth != null) return column.minWidth;\n if (column.tree || column.field === treeField) return 160;\n return TABLE_CELL_MIN_WIDTH[column.type ?? 'text'];\n};\n\nconst withMinWidth = (column: ColumnDefine, minWidth: number | string): ColumnDefine => {\n const next = {\n ...column,\n minWidth: (column as { minWidth?: number | string }).minWidth ?? minWidth,\n } as ColumnDefine & { columns?: ColumnDefine[] };\n const children = (column as { columns?: ColumnDefine[] }).columns;\n\n if (Array.isArray(children)) {\n next.columns = children.map((child) => withMinWidth(child, DEFAULT_TABLE_COLUMN_MIN_WIDTH));\n }\n\n return next;\n};\n\nexport const withDefaultColumnMinWidths = (columns?: ColumnsDefine): ColumnsDefine | undefined =>\n columns?.map((column) => withMinWidth(column, DEFAULT_TABLE_COLUMN_MIN_WIDTH));\n\n/**\n * 空值时把文字压成弱色 —— 与 canvas 那条路径(`createEmptyCellText`)对齐。\n *\n * 原生渲染的列(有 `fieldFormat`、没有 `customLayout`)用的是列样式,不区分空值就会同一张表里\n * 「设置 名称」深、「设置 状态」浅。json / address / progress / number / date 这几个分支各写各的\n * `fieldFormat`,所以在这里一处收口。\n *\n * 两个必须注意的点:\n * - 判空看**原始值**:格式化后的文本在空值时正好是占位文案(「设置 X」),拿它比会误判。\n * - 使用方给了 `fieldFormat` 时**不介入**:显示值来自那个函数、未必是 `field`。树表的 department\n * 列就是这样(值取 `rec.department ?? rec.group ?? rec.name`,而记录里 `group` 是空的),\n * 按 `field` 判空会把整列错涂成弱色。\n */\nconst withBlankMutedColor = (\n define: ColumnDefine,\n column: TableColumn,\n token?: TableToken,\n): void => {\n if (column.fieldFormat != null || define.fieldFormat == null || define.customLayout != null)\n return;\n\n const base = define.style as\n ((args: unknown) => Record<string, unknown>) | Record<string, unknown> | undefined;\n\n define.style = ((args: { col: number; row: number; table?: unknown }) => {\n const table = args.table as\n | { getCellOriginRecord?: (col: number, row: number) => Record<string, unknown> | undefined }\n | undefined;\n const record = table?.getCellOriginRecord?.(args.col, args.row);\n const blank = record != null && isEmptyCellValue(record[column.field]);\n const inherited = typeof base === 'function' ? base(args) : (base ?? {});\n\n return {\n ...inherited,\n color: blank\n ? (token?.colorTextTertiary ?? TABLE_CHROME.textMuted)\n : ((inherited as { color?: string }).color ?? token?.colorText ?? TABLE_CHROME.text),\n };\n }) as ColumnDefine['style'];\n};\n\n/**\n * 原生渲染(无 customLayout)且**真有编辑器**的列:右侧 padding 多留铅笔槽。\n *\n * 判据必须与 `resolveEditHint`(看 `getEditor`)对齐 —— 只看 `canEdit` 会给 image 这类\n * 「表可编辑但本列没有 editor」的列白白让出 28px,进度条 / 封面被挤窄却永远不出现铅笔。\n * customLayout 那条路径由各 painter 自己减 `EDIT_HINT_GUTTER`,这里再加会双倍。\n */\nconst withEditHintPadding = (define: ColumnDefine): void => {\n if (define.customLayout != null || define.editor == null) return;\n\n const base = define.style as\n ((args: unknown) => Record<string, unknown>) | Record<string, unknown> | undefined;\n\n define.style = ((args: unknown) => {\n const inherited = typeof base === 'function' ? base(args) : (base ?? {});\n const padding = (inherited as { padding?: number | (number | null)[] }).padding;\n let next: [number, number, number, number];\n\n if (Array.isArray(padding)) {\n next = [\n Number(padding[0] ?? 0),\n Number(padding[1] ?? 0) + EDIT_HINT_GUTTER,\n Number(padding[2] ?? 0),\n Number(padding[3] ?? 0),\n ];\n } else if (typeof padding === 'number') {\n next = [padding, padding + EDIT_HINT_GUTTER, padding, padding];\n } else {\n next = [0, TABLE_CHROME.paddingX + EDIT_HINT_GUTTER, 0, TABLE_CHROME.paddingX];\n }\n\n return { ...inherited, padding: next };\n }) as ColumnDefine['style'];\n};\n\nexport const compileColumns = (\n columns: TableColumnInput[] | undefined,\n ctx: CompileColumnsContext = {},\n): ColumnsDefine | undefined => {\n if (!columns) return undefined;\n const treeField = resolveTreeField(columns, ctx.tree);\n\n return columns.map((column) => {\n if (isRawVTableColumn(column)) {\n return withMinWidth(column, DEFAULT_TABLE_COLUMN_MIN_WIDTH);\n }\n\n const tableColumn = column as TableColumn;\n const compiled = compileSuperAdColumn(tableColumn, ctx, treeField);\n if (tableColumn.style != null) compiled.style = tableColumn.style;\n // 使用方给的 `fieldFormat` 是这一列显示的唯一真相,压过按 `type` 生成的格式化器 ——\n // 否则「带 fieldFormat 的列现在会被编译」这条改动会把它们的显示改掉。\n if (tableColumn.fieldFormat != null) compiled.fieldFormat = tableColumn.fieldFormat;\n withBlankMutedColor(compiled, tableColumn, ctx.token);\n withEditHintPadding(compiled);\n // customLayout 列的铅笔槽读 `superadEditable`,不走上面的 padding。chip / 开关列各自\n // 已经打过;currency 与 groupedTree 下的文本 / 日期 / JSON 一直漏 —— CellTypes 的预算列\n // 和 Group demo 的日期列就会金额 / 日期顶进铅笔。有 editor 就打,与 resolveEditHint 同口径。\n if (compiled.editor != null) {\n (compiled as ColumnDefine & SuperAdCellMarkers).superadEditable = true;\n }\n return withMinWidth(compiled, resolveColumnMinWidth(tableColumn, treeField));\n });\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { getScenegraphComponent, updateNextFrame } from "./vtableAdapter.mjs";
|
|
2
|
+
//#region src/Table/vtable/frozenShadow.ts
|
|
3
|
+
const hasFrozenColumns = (table) => (table?.frozenColCount ?? 0) > 0;
|
|
4
|
+
/** SuperAd 只在横向滚动离开最左侧时才显示固定列阴影。 */
|
|
5
|
+
const shouldShowFrozenShadow = (table) => hasFrozenColumns(table) && (table?.scrollLeft ?? 0) > 0;
|
|
6
|
+
const applyFrozenShadow = (table, visible) => {
|
|
7
|
+
if (table == null) return;
|
|
8
|
+
const shadowLine = getScenegraphComponent(table)?.frozenShadowLine;
|
|
9
|
+
if (shadowLine == null) return;
|
|
10
|
+
shadowLine.setAttribute("visible", visible);
|
|
11
|
+
updateNextFrame(table);
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* VTable 的 show/hide 会同时控制左右两条阴影线;SuperAd 只需要固定列内侧阴影。
|
|
15
|
+
* 用只控制 frozenShadowLine 的版本替换,避免右侧出现阴影。
|
|
16
|
+
*/
|
|
17
|
+
const patchFrozenShadowControls = (table) => {
|
|
18
|
+
if (table == null) return;
|
|
19
|
+
const component = getScenegraphComponent(table);
|
|
20
|
+
if (component == null) return;
|
|
21
|
+
component.showFrozenColumnShadow = () => applyFrozenShadow(table, shouldShowFrozenShadow(table));
|
|
22
|
+
component.hideFrozenColumnShadow = () => applyFrozenShadow(table, false);
|
|
23
|
+
};
|
|
24
|
+
//#endregion
|
|
25
|
+
export { applyFrozenShadow, hasFrozenColumns, patchFrozenShadowControls, shouldShowFrozenShadow };
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=frozenShadow.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frozenShadow.mjs","names":[],"sources":["../../../src/Table/vtable/frozenShadow.ts"],"sourcesContent":["import { getScenegraphComponent, updateNextFrame } from './vtableAdapter';\n\nexport interface FrozenShadowLine {\n setAttribute: (key: string, value: boolean) => void;\n}\n\nexport interface FrozenShadowComponent {\n frozenShadowLine?: FrozenShadowLine;\n hideFrozenColumnShadow?: () => void;\n showFrozenColumnShadow?: () => void;\n}\n\nexport interface FrozenShadowTable {\n frozenColCount?: number;\n scenegraph?: {\n component?: FrozenShadowComponent;\n updateNextFrame?: () => void;\n };\n scrollLeft?: number;\n}\n\nexport const hasFrozenColumns = (table?: FrozenShadowTable | null): boolean =>\n (table?.frozenColCount ?? 0) > 0;\n\n/** SuperAd 只在横向滚动离开最左侧时才显示固定列阴影。 */\nexport const shouldShowFrozenShadow = (table?: FrozenShadowTable | null): boolean =>\n hasFrozenColumns(table) && (table?.scrollLeft ?? 0) > 0;\n\nexport const applyFrozenShadow = (\n table: FrozenShadowTable | null | undefined,\n visible: boolean,\n): void => {\n if (table == null) return;\n\n const component = getScenegraphComponent(table as never);\n const shadowLine = component?.frozenShadowLine;\n if (shadowLine == null) return;\n\n shadowLine.setAttribute('visible', visible);\n updateNextFrame(table as never);\n};\n\n/**\n * VTable 的 show/hide 会同时控制左右两条阴影线;SuperAd 只需要固定列内侧阴影。\n * 用只控制 frozenShadowLine 的版本替换,避免右侧出现阴影。\n */\nexport const patchFrozenShadowControls = (table: FrozenShadowTable | null | undefined): void => {\n if (table == null) return;\n\n const component = getScenegraphComponent(table as never);\n if (component == null) return;\n\n component.showFrozenColumnShadow = () => applyFrozenShadow(table, shouldShowFrozenShadow(table));\n component.hideFrozenColumnShadow = () => applyFrozenShadow(table, false);\n};\n"],"mappings":";;AAqBA,MAAa,oBAAoB,WAC9B,OAAO,kBAAkB,KAAK;;AAGjC,MAAa,0BAA0B,UACrC,iBAAiB,KAAK,MAAM,OAAO,cAAc,KAAK;AAExD,MAAa,qBACX,OACA,YACS;CACT,IAAI,SAAS,MAAM;CAGnB,MAAM,aADY,uBAAuB,KACd,CAAC,EAAE;CAC9B,IAAI,cAAc,MAAM;CAExB,WAAW,aAAa,WAAW,OAAO;CAC1C,gBAAgB,KAAc;AAChC;;;;;AAMA,MAAa,6BAA6B,UAAsD;CAC9F,IAAI,SAAS,MAAM;CAEnB,MAAM,YAAY,uBAAuB,KAAc;CACvD,IAAI,aAAa,MAAM;CAEvB,UAAU,+BAA+B,kBAAkB,OAAO,uBAAuB,KAAK,CAAC;CAC/F,UAAU,+BAA+B,kBAAkB,OAAO,KAAK;AACzE"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { hrefFor, isGroupTitleRecord, toBoolean, toRating, toValueList } from "../core/cellValue.mjs";
|
|
2
|
+
import { getEditingEditor, getInternalProps, isTableReleased, updateCellContent, updateNextFrame } from "./vtableAdapter.mjs";
|
|
3
|
+
import { isPickerEditor, pickerJustClosed } from "../react/editors/base.mjs";
|
|
4
|
+
import { toggleSeriesHeader, toggleSeriesRow } from "./seriesSelection.mjs";
|
|
5
|
+
//#region src/Table/vtable/interaction.ts
|
|
6
|
+
/**
|
|
7
|
+
* 单元格里直接移除一个值 —— chip 上悬停出来的那个 × 走这条路(人员的姓名 chip、标签 chip)。
|
|
8
|
+
*
|
|
9
|
+
* 值写进 `getCellOriginRecord` 拿到的记录对象,再让引擎只重绘这一格,**不走
|
|
10
|
+
* `changeCellValue`**:它在「分组 + 树」的嵌套行上会静默无操作,症状是「点了没反应,人还在」。
|
|
11
|
+
* 口径与编辑器提交时一致(见 `writeBackOnCommit`)。
|
|
12
|
+
*
|
|
13
|
+
* `index` 是**记录原始数组**里的下标(与 `resolveUserEntries` / `layoutTagChips` 同一套编号)。
|
|
14
|
+
* 值的容器类型保持使用方给的原样:数组仍是数组,单选写回首个剩余项、空了写 `''` —— 与 picker
|
|
15
|
+
* 的 `publish` 同口径,避免「删一个值顺手把字段从 string 改成了数组」。
|
|
16
|
+
*/
|
|
17
|
+
const removeChipAt = (table, col, row, index) => {
|
|
18
|
+
const record = table.getCellOriginRecord(col, row);
|
|
19
|
+
const field = table.getBodyColumnDefine(col, row)?.field;
|
|
20
|
+
if (record == null || typeof field !== "string") return false;
|
|
21
|
+
const current = record[field];
|
|
22
|
+
const rest = toValueList(current).filter((_, position) => position !== index);
|
|
23
|
+
record[field] = Array.isArray(current) ? rest : rest[0] ?? "";
|
|
24
|
+
updateCellContent(table, col, row);
|
|
25
|
+
updateNextFrame(table);
|
|
26
|
+
return true;
|
|
27
|
+
};
|
|
28
|
+
const TREE_ICON_GAP = 4;
|
|
29
|
+
const getGroupToggleCol = (table, col, row) => table.isSeriesNumber(col, row) ? col + 1 : col;
|
|
30
|
+
const isTableEditing = (table) => Boolean(getEditingEditor(table));
|
|
31
|
+
const sameEditHint = (left, right) => {
|
|
32
|
+
if (left === right) return true;
|
|
33
|
+
if (!left || !right) return false;
|
|
34
|
+
return left.col === right.col && left.row === right.row && left.left === right.left && left.top === right.top && left.width === right.width && left.height === right.height;
|
|
35
|
+
};
|
|
36
|
+
const resolveTreeTextOffset = (table, col, row) => {
|
|
37
|
+
if ((table?.getBodyColumnDefine?.(col, row))?.tree !== true) return 0;
|
|
38
|
+
const internalProps = getInternalProps(table);
|
|
39
|
+
const layoutMap = internalProps?.layoutMap;
|
|
40
|
+
const bodyHelper = internalProps?.bodyHelper;
|
|
41
|
+
const showIndex = table?.getRecordShowIndexByCell?.(col, row);
|
|
42
|
+
const indexKey = table?.dataSource?.getIndexKey?.(showIndex);
|
|
43
|
+
const groupLength = table?.dataSource?.getGroupLength?.() ?? 0;
|
|
44
|
+
let level = Array.isArray(indexKey) ? indexKey.length - 1 : 0;
|
|
45
|
+
if (groupLength > 0) level = Math.max(0, level - groupLength);
|
|
46
|
+
const indent = Math.max(0, level) * (layoutMap?.hierarchyIndent ?? 20);
|
|
47
|
+
const hasIcon = Boolean(bodyHelper?.getHierarchyIcon?.(col, row));
|
|
48
|
+
const iconWidth = bodyHelper?.getHierarchyIconWidth?.() ?? 16;
|
|
49
|
+
const padding = (table?.getCellStyle?.(col, row))?.padding;
|
|
50
|
+
const paddingLeft = Array.isArray(padding) ? Number(padding[3] || 0) : typeof padding === "number" ? padding : 0;
|
|
51
|
+
return indent + (hasIcon ? iconWidth + TREE_ICON_GAP : 0) + paddingLeft;
|
|
52
|
+
};
|
|
53
|
+
const resolveEditHint = (table, col, row) => {
|
|
54
|
+
if (isTableEditing(table)) return null;
|
|
55
|
+
if (col < 0 || row < 0) return null;
|
|
56
|
+
if (table.isHeader(col, row) || table.isSeriesNumber(col, row)) return null;
|
|
57
|
+
if (isGroupTitleRecord(table.getCellOriginRecord(col, row))) return null;
|
|
58
|
+
if (!table.getEditor(col, row)) return null;
|
|
59
|
+
const rect = table.getCellRelativeRect(col, row);
|
|
60
|
+
if (!rect || rect.width <= 0 || rect.height <= 0) return null;
|
|
61
|
+
const treeOffset = resolveTreeTextOffset(table, col, row);
|
|
62
|
+
const left = rect.left + treeOffset;
|
|
63
|
+
const width = rect.width - treeOffset;
|
|
64
|
+
if (width <= 0) return null;
|
|
65
|
+
return {
|
|
66
|
+
col,
|
|
67
|
+
height: rect.height,
|
|
68
|
+
left,
|
|
69
|
+
row,
|
|
70
|
+
top: rect.top,
|
|
71
|
+
width
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
const placeEditHint = (hint, tableEl, host) => {
|
|
75
|
+
if (!hint || !tableEl || !host) return hint;
|
|
76
|
+
const tableRect = tableEl.getBoundingClientRect();
|
|
77
|
+
const hostRect = host.getBoundingClientRect();
|
|
78
|
+
return {
|
|
79
|
+
...hint,
|
|
80
|
+
left: hint.left + (tableRect.left - hostRect.left),
|
|
81
|
+
top: hint.top + (tableRect.top - hostRect.top)
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
const hintFromClientPoint = (table, host, clientX, clientY) => {
|
|
85
|
+
const tableEl = table.getElement();
|
|
86
|
+
const rect = tableEl.getBoundingClientRect();
|
|
87
|
+
const cell = table.getCellAtRelativePosition(clientX - rect.left, clientY - rect.top);
|
|
88
|
+
if (!cell || cell.col < 0 || cell.row < 0) return null;
|
|
89
|
+
return placeEditHint(resolveEditHint(table, cell.col, cell.row), tableEl, host);
|
|
90
|
+
};
|
|
91
|
+
const writeCellValue = (table, col, row, value) => {
|
|
92
|
+
table.changeCellValue(col, row, value);
|
|
93
|
+
};
|
|
94
|
+
const resolveRatingStar = (table, col, row, event) => {
|
|
95
|
+
const rect = table.getCellRelativeRect(col, row);
|
|
96
|
+
const offsetX = event != null && "offsetX" in event ? event.offsetX : void 0;
|
|
97
|
+
if (rect == null || rect.width <= 0 || typeof offsetX !== "number") return 5;
|
|
98
|
+
const ratio = (offsetX - rect.left) / rect.width;
|
|
99
|
+
return Math.min(5, Math.max(1, Math.ceil(ratio * 5)));
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* 去掉 URL 解析本来就会忽略的字符:空白、C0 控制字符与 DEL。按字面前缀匹配会被
|
|
103
|
+
* `java\tscript:` / ` javascript:` 绕过,所以匹配前先归一化。
|
|
104
|
+
* 写成显式字符码而不是控制字符正则:这里要的正是「码点大于空格」这个精确条件。
|
|
105
|
+
*/
|
|
106
|
+
const stripUrlNoise = (href) => {
|
|
107
|
+
let out = "";
|
|
108
|
+
for (const char of href) {
|
|
109
|
+
const code = char.codePointAt(0) ?? 0;
|
|
110
|
+
if (code > 32 && code !== 127) out += char;
|
|
111
|
+
}
|
|
112
|
+
return out;
|
|
113
|
+
};
|
|
114
|
+
/** 会执行脚本的协议。 */
|
|
115
|
+
const SCRIPT_URL = /^(?:javascript|vbscript):/i;
|
|
116
|
+
const isScriptUrl = (href) => SCRIPT_URL.test(stripUrlNoise(href));
|
|
117
|
+
const openHref = (href) => {
|
|
118
|
+
if (typeof document === "undefined") return;
|
|
119
|
+
if (isScriptUrl(href)) return;
|
|
120
|
+
const anchor = document.createElement("a");
|
|
121
|
+
anchor.href = href;
|
|
122
|
+
anchor.rel = "noreferrer";
|
|
123
|
+
anchor.target = "_blank";
|
|
124
|
+
anchor.click();
|
|
125
|
+
};
|
|
126
|
+
const handleSuperAdCellClick = (table, args) => {
|
|
127
|
+
const define = table.getBodyColumnDefine?.(args.col, args.row);
|
|
128
|
+
const kind = define?.superadKind;
|
|
129
|
+
if (define == null || kind == null) return false;
|
|
130
|
+
const value = table.getCellOriginValue(args.col, args.row);
|
|
131
|
+
if (kind === "link") {
|
|
132
|
+
if (define.superadEditable === true) return false;
|
|
133
|
+
const href = hrefFor(define.superadLinkKind ?? "link", value);
|
|
134
|
+
if (href) openHref(href);
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
if (define.superadEditable !== true) return false;
|
|
138
|
+
if (kind === "checkbox" || kind === "boolean") {
|
|
139
|
+
writeCellValue(table, args.col, args.row, toBoolean(value) !== true);
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
if (kind === "rating") {
|
|
143
|
+
const current = toRating(value);
|
|
144
|
+
const star = resolveRatingStar(table, args.col, args.row, args.event);
|
|
145
|
+
writeCellValue(table, args.col, args.row, current === star ? 0 : star);
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
return false;
|
|
149
|
+
};
|
|
150
|
+
const handleTableCellClick = (table, args) => {
|
|
151
|
+
if (table.isSeriesNumber?.(args.col, args.row)) {
|
|
152
|
+
if (table.isHeader?.(args.col, args.row)) toggleSeriesHeader(table);
|
|
153
|
+
else toggleSeriesRow(table, args.row, args.event?.shiftKey);
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
const record = table.getCellOriginRecord(args.col, args.row);
|
|
157
|
+
if (isGroupTitleRecord(record)) {
|
|
158
|
+
if (args.targetIcon) return true;
|
|
159
|
+
table.clearSelected();
|
|
160
|
+
table.toggleHierarchyState(getGroupToggleCol(table, args.col, args.row), args.row);
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
if (pickerJustClosed(table)) return true;
|
|
164
|
+
if (handleSuperAdCellClick(table, args)) return true;
|
|
165
|
+
if (!isPickerEditor(table.getEditor(args.col, args.row))) return false;
|
|
166
|
+
window.setTimeout(() => {
|
|
167
|
+
if (isTableReleased(table)) return;
|
|
168
|
+
table.startEditCell(args.col, args.row);
|
|
169
|
+
}, 0);
|
|
170
|
+
return false;
|
|
171
|
+
};
|
|
172
|
+
//#endregion
|
|
173
|
+
export { getGroupToggleCol, handleTableCellClick, hintFromClientPoint, isTableEditing, placeEditHint, removeChipAt, resolveEditHint, resolveTreeTextOffset, sameEditHint };
|
|
174
|
+
|
|
175
|
+
//# sourceMappingURL=interaction.mjs.map
|