@vue-ui-kit/ant 2.5.2 → 2.5.3

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/dist/style.css CHANGED
@@ -1,4 +1,61 @@
1
1
  @charset "UTF-8";
2
+ /**
3
+ * EVirtTable(PCanvasGrid / PCanvasTable)主题变量
4
+ * - 与 PGrid 共用 --p-* 语义变量,保证 Canvas 表格与 DOM 表格同色
5
+ * - 无对应 --p-* 的项使用 storybook theme.css 默认值
6
+ * - e-virt-table 初始化时通过 Config.updateCssVar() 读取 --evt-*
7
+ */
8
+ :root {
9
+ --evt-border-color: var(--p-border-color, #d9d9d9);
10
+ --evt-header-bg-color: var(--p-table-thead-bg-color, #f2f3f6);
11
+ --evt-body-bg-color: var(--p-table-row-bg-color, #fff);
12
+ --evt-stripe-color: var(--p-striped-bg-color, #f2f3f6);
13
+ --evt-highlight-hover-row-color: var(--p-table-row-hover-bg-color, #e6e7ea);
14
+ --evt-select-border-color: var(--p-primary-color, #4096ff);
15
+ --evt-sort-icon-color: var(--p-primary-color, #4096ff);
16
+ --evt-required-color: var(--p-danger-color, #f5222d);
17
+ --evt-error-tip-color: var(--p-danger-color, #f5222d);
18
+ --evt-error-tip-icon-color: var(--p-danger-color, #f5222d);
19
+ --evt-readonly-color: var(--p-table-row-bg-color, #fff);
20
+ --evt-scroller-track-color: var(--p-table-row-bg-color, #fff);
21
+ /* Canvas 专用(白天 = storybook 默认值) */
22
+ --evt-header-text-color: #1d2129;
23
+ --evt-body-text-color: #4e5969;
24
+ --evt-footer-text-color: #4e5969;
25
+ --evt-readonly-text-color: #4e5969;
26
+ --evt-scroller-color: #dee0e3;
27
+ --evt-scroller-focus-color: #bbbec4;
28
+ --evt-edit-bg-color: #fcf6ed;
29
+ --evt-footer-bg-color: #fafafa;
30
+ --evt-autofill-point-border-color: #fff;
31
+ --evt-editor-bg-color: #fff;
32
+ --evt-editor-text-color: #333;
33
+ --evt-context-menu-bg-color: #fff;
34
+ --evt-context-menu-text-color: #333;
35
+ --evt-context-menu-item-hover-bg-color: #f5f5f5;
36
+ }
37
+
38
+ /* 夜间:背景随 --p-* 传递,仅覆盖 Canvas 专用色 */
39
+ html[theme-mode=dark],
40
+ :root[data-theme=dark],
41
+ :root.dark {
42
+ --evt-header-text-color: #a3a6ad;
43
+ --evt-body-text-color: #cfd3dc;
44
+ --evt-footer-text-color: #cfd3dc;
45
+ --evt-readonly-text-color: #a3a6ad;
46
+ --evt-scroller-color: #414243;
47
+ --evt-scroller-track-color: #141414;
48
+ --evt-scroller-focus-color: #a3a6ad;
49
+ --evt-edit-bg-color: #141414;
50
+ --evt-footer-bg-color: #262727;
51
+ --evt-autofill-point-border-color: #a3a6ad;
52
+ --evt-editor-bg-color: #434343;
53
+ --evt-editor-text-color: #cfd3dc;
54
+ --evt-context-menu-bg-color: #141414;
55
+ --evt-context-menu-text-color: #cfd3dc;
56
+ --evt-context-menu-item-hover-bg-color: #414243;
57
+ }
58
+
2
59
  .p-pane {
3
60
  background-color: var(--p-theme-bg, #fff);
4
61
  padding: 16px;
package/dist/style.scss CHANGED
@@ -1,3 +1,5 @@
1
+ @use 'canvas-theme';
2
+
1
3
  .p-pane {
2
4
  background-color: var(--p-theme-bg, #fff);
3
5
  padding: 16px;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vue-ui-kit/ant",
3
- "version": "2.5.2",
3
+ "version": "2.5.3",
4
4
  "description": "Vue3 UI Kit based on Ant Design",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",
@@ -1,5 +1,9 @@
1
- <script lang="ts" setup generic="D extends Recordable = Recordable, F extends Recordable = Recordable"
2
- name="PCanvasGrid">
1
+ <script
2
+ lang="ts"
3
+ setup
4
+ generic="D extends Recordable = Recordable, F extends Recordable = Recordable"
5
+ name="PCanvasGrid"
6
+ >
3
7
  import {
4
8
  CanvasColumnProps,
5
9
  PCanvasGridProps,
@@ -95,13 +99,13 @@
95
99
  const pg = computed(() =>
96
100
  mode.value === 'pagination'
97
101
  ? {
98
- current: pagination.page,
99
- total: totalCount.value,
100
- pageSize: pagination.size,
101
- responsive: false,
102
- showSizeChanger: true,
103
- showTotal: (total: number) => `共${total}条数据`,
104
- }
102
+ current: pagination.page,
103
+ total: totalCount.value,
104
+ pageSize: pagination.size,
105
+ responsive: false,
106
+ showSizeChanger: true,
107
+ showTotal: (total: number) => `共${total}条数据`,
108
+ }
105
109
  : false,
106
110
  );
107
111
 
@@ -184,30 +188,30 @@
184
188
  const handleResponse = (response: Recordable, pathConfig?: ResponsePathConfig<D>) =>
185
189
  pathConfig
186
190
  ? {
187
- list: isString(pathConfig.list)
188
- ? get(response, pathConfig.list)
189
- : isFunction(pathConfig.list)
190
- ? pathConfig.list(response)
191
- : undefined,
192
- total: isString(pathConfig.total)
193
- ? get(response, pathConfig.total)
194
- : isFunction(pathConfig.total)
195
- ? pathConfig.total(response)
196
- : undefined,
197
- result: isString(pathConfig.result)
198
- ? get(response, pathConfig.result)
199
- : isFunction(pathConfig.result)
200
- ? pathConfig.result(response)
201
- : undefined,
202
- message: isString(pathConfig.message)
203
- ? get(response, pathConfig.message)
204
- : isFunction(pathConfig.message)
205
- ? pathConfig.message(response)
206
- : undefined,
207
- }
191
+ list: isString(pathConfig.list)
192
+ ? get(response, pathConfig.list)
193
+ : isFunction(pathConfig.list)
194
+ ? pathConfig.list(response)
195
+ : undefined,
196
+ total: isString(pathConfig.total)
197
+ ? get(response, pathConfig.total)
198
+ : isFunction(pathConfig.total)
199
+ ? pathConfig.total(response)
200
+ : undefined,
201
+ result: isString(pathConfig.result)
202
+ ? get(response, pathConfig.result)
203
+ : isFunction(pathConfig.result)
204
+ ? pathConfig.result(response)
205
+ : undefined,
206
+ message: isString(pathConfig.message)
207
+ ? get(response, pathConfig.message)
208
+ : isFunction(pathConfig.message)
209
+ ? pathConfig.message(response)
210
+ : undefined,
211
+ }
208
212
  : {
209
- list: response,
210
- };
213
+ list: response,
214
+ };
211
215
  const toolBtnClick = (code: string) => {
212
216
  emit('toolbarButtonClick', {
213
217
  data: tableData.value,
@@ -329,31 +333,31 @@
329
333
  const firstColumn: CanvasColumnProps<D> =
330
334
  staticConfig.value.selectable && staticConfig.value.tree
331
335
  ? {
332
- type: 'selection-tree',
333
- width: 40,
334
- widthFillDisable: true,
335
- title: '',
336
- }
337
- : staticConfig.value.selectable
338
- ? {
339
- type: 'selection',
336
+ type: 'selection-tree',
340
337
  width: 40,
341
338
  widthFillDisable: true,
342
339
  title: '',
343
340
  }
344
- : staticConfig.value.tree
345
- ? {
346
- type: 'tree',
341
+ : staticConfig.value.selectable
342
+ ? {
343
+ type: 'selection',
347
344
  width: 40,
348
345
  widthFillDisable: true,
349
346
  title: '',
350
347
  }
348
+ : staticConfig.value.tree
349
+ ? {
350
+ type: 'tree',
351
+ width: 40,
352
+ widthFillDisable: true,
353
+ title: '',
354
+ }
351
355
  : {
352
- type: 'index',
353
- width: 40,
354
- widthFillDisable: true,
355
- title: '',
356
- };
356
+ type: 'index',
357
+ width: 40,
358
+ widthFillDisable: true,
359
+ title: '',
360
+ };
357
361
  return [firstColumn, ...columns.value];
358
362
  });
359
363
  const resetQueryFormData = (lazy?: boolean) => {
@@ -531,40 +535,66 @@
531
535
  });
532
536
  </script>
533
537
  <template>
534
- <div ref="boxEl" :class="[
535
- 'p-wrapper flex flex-col gap-8px overflow-y-auto',
536
- autoBoxSize ? 'min-h-0 min-w-0 flex-1 w-full' : 'h-full',
537
- ]" v-bind="attrs">
538
+ <div
539
+ ref="boxEl"
540
+ :class="[
541
+ 'p-wrapper flex flex-col gap-8px overflow-y-auto',
542
+ autoBoxSize ? 'min-h-0 min-w-0 flex-1 w-full' : 'h-full',
543
+ ]"
544
+ v-bind="attrs"
545
+ >
538
546
  <div v-if="mode === 'bad'">请检查配置</div>
539
547
  <template v-else>
540
- <div v-if="formConfig?.items?.some((s: PFormItemProps<F>) => s.field && s.itemRender)"
541
- class="p-pane p-form-wrapper" ref="pFormWrapper">
548
+ <div
549
+ v-if="formConfig?.items?.some((s: PFormItemProps<F>) => s.field && s.itemRender)"
550
+ class="p-pane p-form-wrapper"
551
+ ref="pFormWrapper"
552
+ >
542
553
  <a-spin :spinning="loading.form">
543
- <a-form :key="renderFormKey" ref="formEl" :model="queryFormData" v-bind="fc" @submit="handleFormSubmit">
554
+ <a-form
555
+ :key="renderFormKey"
556
+ ref="formEl"
557
+ :model="queryFormData"
558
+ v-bind="fc"
559
+ @submit="handleFormSubmit"
560
+ >
544
561
  <a-row :gutter="[6, 12]">
545
- <p-form-col v-for="(item, idx) in formConfig!.items" :key="`_col_${item.field || idx}`"
546
- :form-data="queryFormData" :item="item as PFormItemProps<Partial<F>>"
547
- @reset="resetQueryFormData(props.lazyReset)" />
562
+ <p-form-col
563
+ v-for="(item, idx) in formConfig!.items"
564
+ :key="`_col_${item.field || idx}`"
565
+ :form-data="queryFormData"
566
+ :item="item as PFormItemProps<Partial<F>>"
567
+ @reset="resetQueryFormData(props.lazyReset)"
568
+ />
548
569
  </a-row>
549
570
  </a-form>
550
571
  </a-spin>
551
572
  </div>
552
- <div v-if="toolbarConfig"
553
- class="p-canvas-toolbar-wrapper flex items-center w-full justify-between p-theme-bg pt-8px px-16px">
573
+ <div
574
+ v-if="toolbarConfig"
575
+ class="p-canvas-toolbar-wrapper flex items-center w-full justify-between p-theme-bg pt-8px px-16px"
576
+ >
554
577
  <div class="flex items-center flex-1 gap-4px">
555
578
  <template v-if="toolbarConfig.buttons && toolbarConfig.buttons.length > 0">
556
579
  <template v-for="(btn, idx) in toolbarConfig.buttons" :key="idx">
557
580
  <a-dropdown v-if="btn.dropdowns && btn.dropdowns.length">
558
581
  <template #overlay>
559
582
  <a-menu @click="toolBtnMenuClick">
560
- <a-menu-item v-for="sub in btn.dropdowns" :key="sub.code">{{ sub.content }}
583
+ <a-menu-item v-for="sub in btn.dropdowns" :key="sub.code"
584
+ >{{ sub.content }}
561
585
  </a-menu-item>
562
586
  </a-menu>
563
587
  </template>
564
- <a-button :type="btn.type" :size="btn.size ?? 'middle'"
588
+ <a-button
589
+ :type="btn.type"
590
+ :size="btn.size ?? 'middle'"
565
591
  :disabled="toolbarConfig.disabled || btn.disabled"
566
- :loading="loading.toolbar || (!!btn.code && codeLoadings[btn.code])" :danger="btn.danger"
567
- :shape="btn.shape" :ghost="btn.ghost" :block="btn.block">
592
+ :loading="loading.toolbar || (!!btn.code && codeLoadings[btn.code])"
593
+ :danger="btn.danger"
594
+ :shape="btn.shape"
595
+ :ghost="btn.ghost"
596
+ :block="btn.block"
597
+ >
568
598
  <div class="flex items-center gap-4px">
569
599
  <Icon v-if="btn.icon" :icon="btn.icon" />
570
600
  <template v-if="btn.content && isStringContent(renderContent(btn.content))">
@@ -575,10 +605,18 @@
575
605
  </div>
576
606
  </a-button>
577
607
  </a-dropdown>
578
- <a-button v-else-if="btn.code" :type="btn.type" :size="btn.size ?? 'middle'"
608
+ <a-button
609
+ v-else-if="btn.code"
610
+ :type="btn.type"
611
+ :size="btn.size ?? 'middle'"
579
612
  :disabled="toolbarConfig.disabled || btn.disabled"
580
- :loading="loading.toolbar || (!!btn.code && codeLoadings[btn.code])" :danger="btn.danger"
581
- :shape="btn.shape" :ghost="btn.ghost" :block="btn.block" @click="debounceToolBtnClick(btn.code)">
613
+ :loading="loading.toolbar || (!!btn.code && codeLoadings[btn.code])"
614
+ :danger="btn.danger"
615
+ :shape="btn.shape"
616
+ :ghost="btn.ghost"
617
+ :block="btn.block"
618
+ @click="debounceToolBtnClick(btn.code)"
619
+ >
582
620
  <div class="flex items-center gap-4px">
583
621
  <Icon v-if="btn.icon" :icon="btn.icon" />
584
622
  <template v-if="btn.content && isStringContent(renderContent(btn.content))">
@@ -593,10 +631,19 @@
593
631
  </div>
594
632
  <span class="flex items-center gap-4px">
595
633
  <template v-if="toolbarConfig.tools && toolbarConfig.tools.length > 0">
596
- <a-button v-for="(tool, idx) in toolbarConfig.tools" :key="idx" :type="tool.type"
597
- :size="tool.size ?? 'middle'" :disabled="toolbarConfig.disabled || tool.disabled" :danger="tool.danger"
598
- :shape="tool.shape" :ghost="tool.ghost" :block="tool.block" @click="debounceToolToolClick(tool.code)"
599
- :loading="loading.toolbar || (!!tool.code && codeLoadings[tool.code])">
634
+ <a-button
635
+ v-for="(tool, idx) in toolbarConfig.tools"
636
+ :key="idx"
637
+ :type="tool.type"
638
+ :size="tool.size ?? 'middle'"
639
+ :disabled="toolbarConfig.disabled || tool.disabled"
640
+ :danger="tool.danger"
641
+ :shape="tool.shape"
642
+ :ghost="tool.ghost"
643
+ :block="tool.block"
644
+ @click="debounceToolToolClick(tool.code)"
645
+ :loading="loading.toolbar || (!!tool.code && codeLoadings[tool.code])"
646
+ >
600
647
  <div class="flex items-center gap-4px">
601
648
  <Icon v-if="tool.icon" :icon="tool.icon" />
602
649
  <template v-if="tool.content && isStringContent(renderContent(tool.content))">
@@ -610,21 +657,38 @@
610
657
  </div>
611
658
  <div ref="tableWrapperEl" class="flex-1 h-0 min-h-0 flex flex-col p-inner-scroll">
612
659
  <div ref="tableBodyEl" class="flex-1 min-h-0 overflow-hidden">
613
- <p-canvas-table ref="canvasTableRef" :columns="finalColumns" :config="{
614
- ...propsWithDefaults.config,
615
- HEIGHT: renderHeight,
616
- }" :data="tableData" :loading="loading.table" @selection-change="handleSelectionChange">
660
+ <p-canvas-table
661
+ ref="canvasTableRef"
662
+ :columns="finalColumns"
663
+ :config="{
664
+ ...propsWithDefaults.config,
665
+ HEIGHT: renderHeight,
666
+ }"
667
+ :data="tableData"
668
+ :loading="loading.table"
669
+ @selection-change="handleSelectionChange"
670
+ >
617
671
  <template v-for="(_, name) in $slots" #[name]="slotProps">
618
672
  <slot :name="name" v-bind="slotProps"></slot>
619
673
  </template>
620
674
  </p-canvas-table>
621
675
  </div>
622
676
  <div ref="tableFooterEl" class="flex-shrink-0">
623
- <div v-if="staticConfig?.selectable && staticConfig.showCount" class="w-full text-slate-5 pl-4">
677
+ <div
678
+ v-if="staticConfig?.selectable && staticConfig.showCount"
679
+ class="w-full text-slate-5 pl-4"
680
+ >
624
681
  已选:{{ selectedRowKeys.length }}
625
682
  </div>
626
- <a-pagination class="p-canvas-pagination" v-if="mode === 'pagination'" size="small" :current="pagination.page"
627
- :page-size="pagination.size" :total="totalCount" @change="handleTableChange" />
683
+ <a-pagination
684
+ class="p-canvas-pagination"
685
+ v-if="mode === 'pagination'"
686
+ size="small"
687
+ :current="pagination.page"
688
+ :page-size="pagination.size"
689
+ :total="totalCount"
690
+ @change="handleTableChange"
691
+ />
628
692
  </div>
629
693
  </div>
630
694
  </template>
@@ -12,7 +12,7 @@
12
12
  OverlayerContainer,
13
13
  FormatterMethod,
14
14
  } from 'e-virt-table';
15
- import { ref, onMounted, computed, useAttrs, watch } from 'vue';
15
+ import { ref, onMounted, onUnmounted, computed, useAttrs, watch } from 'vue';
16
16
  import { EventCallback } from 'e-virt-table/dist/lib/EventBus';
17
17
  import { isArray, isEqual, isFunction, isString, omit } from 'xe-utils';
18
18
  import renderStore from '@/store/renderStore';
@@ -20,8 +20,10 @@
20
20
  import type { CanvasColumnProps, CanvasTableProps, FormatterFunc, CellRender } from '#/antProxy';
21
21
  import { v4 as uuidv4 } from 'uuid';
22
22
  import { antFormatters } from '@/utils/AFormatters';
23
+ import { bindCanvasTableThemeSync, syncCanvasThemeCssVars, type CanvasTableThemeHandle } from '@/utils/canvasTableTheme';
23
24
  import { getCanvasTableDefaults } from '@/utils/config';
24
25
  import { watchPreviousDeep } from '@/utils/core';
26
+ import '../styles/canvas-theme.scss';
25
27
 
26
28
  const emit = defineEmits<{
27
29
  (e: 'change', value: any[]): void; // 需要默认实现change,不能动态绑定
@@ -45,6 +47,7 @@
45
47
  },
46
48
  }));
47
49
  let eVirtTable: EVirtTable | null = null;
50
+ let themeSyncHandle: CanvasTableThemeHandle | null = null;
48
51
  const attrs = useAttrs();
49
52
  const eVirtTableRef = ref(null);
50
53
  const eVirtTableEditorRef = ref(null);
@@ -150,6 +153,7 @@
150
153
  if (!eVirtTableRef.value) {
151
154
  return;
152
155
  }
156
+ syncCanvasThemeCssVars();
153
157
  eVirtTable = new EVirtTable(eVirtTableRef.value, {
154
158
  config: propsWithDefaults.value.config,
155
159
  columns: props.columns.map((col) => parseToEVirtColumn(col)),
@@ -190,6 +194,13 @@
190
194
  emit('selectionChange', selection);
191
195
  });
192
196
  emit('ready', eVirtTable);
197
+ themeSyncHandle = bindCanvasTableThemeSync({
198
+ getTable: () => eVirtTable,
199
+ getConfig: () => propsWithDefaults.value.config,
200
+ });
201
+ });
202
+ onUnmounted(() => {
203
+ themeSyncHandle?.disconnect();
193
204
  });
194
205
  function saveCellValue(value) {
195
206
  if (!eVirtTable || !editorCell.value) {
@@ -0,0 +1,57 @@
1
+ /**
2
+ * EVirtTable(PCanvasGrid / PCanvasTable)主题变量
3
+ * - 与 PGrid 共用 --p-* 语义变量,保证 Canvas 表格与 DOM 表格同色
4
+ * - 无对应 --p-* 的项使用 storybook theme.css 默认值
5
+ * - e-virt-table 初始化时通过 Config.updateCssVar() 读取 --evt-*
6
+ */
7
+ :root {
8
+ --evt-border-color: var(--p-border-color, #d9d9d9);
9
+ --evt-header-bg-color: var(--p-table-thead-bg-color, #f2f3f6);
10
+ --evt-body-bg-color: var(--p-table-row-bg-color, #fff);
11
+ --evt-stripe-color: var(--p-striped-bg-color, #f2f3f6);
12
+ --evt-highlight-hover-row-color: var(--p-table-row-hover-bg-color, #e6e7ea);
13
+ --evt-select-border-color: var(--p-primary-color, #4096ff);
14
+ --evt-sort-icon-color: var(--p-primary-color, #4096ff);
15
+ --evt-required-color: var(--p-danger-color, #f5222d);
16
+ --evt-error-tip-color: var(--p-danger-color, #f5222d);
17
+ --evt-error-tip-icon-color: var(--p-danger-color, #f5222d);
18
+ --evt-readonly-color: var(--p-table-row-bg-color, #fff);
19
+ --evt-scroller-track-color: var(--p-table-row-bg-color, #fff);
20
+
21
+ /* Canvas 专用(白天 = storybook 默认值) */
22
+ --evt-header-text-color: #1d2129;
23
+ --evt-body-text-color: #4e5969;
24
+ --evt-footer-text-color: #4e5969;
25
+ --evt-readonly-text-color: #4e5969;
26
+ --evt-scroller-color: #dee0e3;
27
+ --evt-scroller-focus-color: #bbbec4;
28
+ --evt-edit-bg-color: #fcf6ed;
29
+ --evt-footer-bg-color: #fafafa;
30
+ --evt-autofill-point-border-color: #fff;
31
+ --evt-editor-bg-color: #fff;
32
+ --evt-editor-text-color: #333;
33
+ --evt-context-menu-bg-color: #fff;
34
+ --evt-context-menu-text-color: #333;
35
+ --evt-context-menu-item-hover-bg-color: #f5f5f5;
36
+ }
37
+
38
+ /* 夜间:背景随 --p-* 传递,仅覆盖 Canvas 专用色 */
39
+ html[theme-mode='dark'],
40
+ :root[data-theme='dark'],
41
+ :root.dark {
42
+ --evt-header-text-color: #a3a6ad;
43
+ --evt-body-text-color: #cfd3dc;
44
+ --evt-footer-text-color: #cfd3dc;
45
+ --evt-readonly-text-color: #a3a6ad;
46
+ --evt-scroller-color: #414243;
47
+ --evt-scroller-track-color: #141414;
48
+ --evt-scroller-focus-color: #a3a6ad;
49
+ --evt-edit-bg-color: #141414;
50
+ --evt-footer-bg-color: #262727;
51
+ --evt-autofill-point-border-color: #a3a6ad;
52
+ --evt-editor-bg-color: #434343;
53
+ --evt-editor-text-color: #cfd3dc;
54
+ --evt-context-menu-bg-color: #141414;
55
+ --evt-context-menu-text-color: #cfd3dc;
56
+ --evt-context-menu-item-hover-bg-color: #414243;
57
+ }
@@ -1,3 +1,5 @@
1
+ @use 'canvas-theme';
2
+
1
3
  .p-pane {
2
4
  background-color: var(--p-theme-bg, #fff);
3
5
  padding: 16px;
@@ -0,0 +1,111 @@
1
+ import type EVirtTable from 'e-virt-table';
2
+ import type { ConfigType } from 'e-virt-table';
3
+
4
+ /** --p-* → --evt-* 桥接(与 canvas-theme.scss / storybook theme.css 对齐) */
5
+ const P_TO_EVT_BRIDGE: ReadonlyArray<readonly [evt: string, p: string, fallback: string]> = [
6
+ ['--evt-border-color', '--p-border-color', '#d9d9d9'],
7
+ ['--evt-header-bg-color', '--p-table-thead-bg-color', '#f2f3f6'],
8
+ ['--evt-body-bg-color', '--p-table-row-bg-color', '#fff'],
9
+ ['--evt-stripe-color', '--p-striped-bg-color', '#f2f3f6'],
10
+ ['--evt-highlight-hover-row-color', '--p-table-row-hover-bg-color', '#e6e7ea'],
11
+ ['--evt-select-border-color', '--p-primary-color', '#4096ff'],
12
+ ['--evt-sort-icon-color', '--p-primary-color', '#4096ff'],
13
+ ['--evt-required-color', '--p-danger-color', '#f5222d'],
14
+ ['--evt-error-tip-color', '--p-danger-color', '#f5222d'],
15
+ ['--evt-error-tip-icon-color', '--p-danger-color', '#f5222d'],
16
+ ['--evt-readonly-color', '--p-table-row-bg-color', '#fff'],
17
+ ['--evt-scroller-track-color', '--p-table-row-bg-color', '#fff'],
18
+ ];
19
+
20
+ /** Canvas 专用色(无 --p-* 对应项,storybook 默认值) */
21
+ const LIGHT_EVT_DEDICATED: Readonly<Record<string, string>> = {
22
+ '--evt-header-text-color': '#1d2129',
23
+ '--evt-body-text-color': '#4e5969',
24
+ '--evt-footer-text-color': '#4e5969',
25
+ '--evt-readonly-text-color': '#4e5969',
26
+ '--evt-scroller-color': '#dee0e3',
27
+ '--evt-scroller-focus-color': '#bbbec4',
28
+ '--evt-edit-bg-color': '#fcf6ed',
29
+ '--evt-footer-bg-color': '#fafafa',
30
+ '--evt-autofill-point-border-color': '#fff',
31
+ '--evt-editor-bg-color': '#fff',
32
+ '--evt-editor-text-color': '#333',
33
+ '--evt-context-menu-bg-color': '#fff',
34
+ '--evt-context-menu-text-color': '#333',
35
+ '--evt-context-menu-item-hover-bg-color': '#f5f5f5',
36
+ };
37
+
38
+ const DARK_EVT_DEDICATED: Readonly<Record<string, string>> = {
39
+ '--evt-header-text-color': '#a3a6ad',
40
+ '--evt-body-text-color': '#cfd3dc',
41
+ '--evt-footer-text-color': '#cfd3dc',
42
+ '--evt-readonly-text-color': '#a3a6ad',
43
+ '--evt-scroller-color': '#414243',
44
+ '--evt-scroller-track-color': '#141414',
45
+ '--evt-scroller-focus-color': '#a3a6ad',
46
+ '--evt-edit-bg-color': '#141414',
47
+ '--evt-footer-bg-color': '#262727',
48
+ '--evt-autofill-point-border-color': '#a3a6ad',
49
+ '--evt-editor-bg-color': '#434343',
50
+ '--evt-editor-text-color': '#cfd3dc',
51
+ '--evt-context-menu-bg-color': '#141414',
52
+ '--evt-context-menu-text-color': '#cfd3dc',
53
+ '--evt-context-menu-item-hover-bg-color': '#414243',
54
+ };
55
+
56
+ export function isDarkThemeRoot(el: HTMLElement = document.documentElement): boolean {
57
+ return (
58
+ el.getAttribute('theme-mode') === 'dark' ||
59
+ el.getAttribute('data-theme') === 'dark' ||
60
+ el.classList.contains('dark')
61
+ );
62
+ }
63
+
64
+ /**
65
+ * 将 --p-* 解析值写入 --evt-*,覆盖 e-virt-table 运行时注入的浅色默认值。
66
+ */
67
+ export function syncCanvasThemeCssVars(el: HTMLElement = document.documentElement): void {
68
+ const computed = getComputedStyle(el);
69
+ for (const [evt, p, fallback] of P_TO_EVT_BRIDGE) {
70
+ const value = computed.getPropertyValue(p).trim() || fallback;
71
+ el.style.setProperty(evt, value);
72
+ }
73
+ const dedicated = isDarkThemeRoot(el) ? DARK_EVT_DEDICATED : LIGHT_EVT_DEDICATED;
74
+ for (const [evt, value] of Object.entries(dedicated)) {
75
+ el.style.setProperty(evt, value);
76
+ }
77
+ }
78
+
79
+ export type CanvasTableThemeHandle = {
80
+ disconnect: () => void;
81
+ sync: () => void;
82
+ };
83
+
84
+ /**
85
+ * 同步 CSS 变量并 loadConfig,使 Canvas 表格与 PGrid 主题一致。
86
+ */
87
+ export function bindCanvasTableThemeSync(options: {
88
+ getTable: () => EVirtTable | null;
89
+ getConfig: () => ConfigType;
90
+ }): CanvasTableThemeHandle {
91
+ const sync = () => {
92
+ syncCanvasThemeCssVars();
93
+ const table = options.getTable();
94
+ if (table) {
95
+ table.loadConfig(options.getConfig());
96
+ }
97
+ };
98
+
99
+ const observer = new MutationObserver(sync);
100
+ observer.observe(document.documentElement, {
101
+ attributes: true,
102
+ attributeFilter: ['theme-mode', 'class', 'data-theme'],
103
+ });
104
+
105
+ sync();
106
+
107
+ return {
108
+ sync,
109
+ disconnect: () => observer.disconnect(),
110
+ };
111
+ }