@veltra/sheet 2.0.1 → 2.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/dist/index.d.ts +4 -26
- package/dist/index.js +3 -23
- package/dist/tools/builtin.js +279 -8
- package/dist/tools/context.d.ts +54 -11
- package/dist/tools/context.js +28 -5
- package/dist/tools/download.js +68 -0
- package/dist/tools/export.worker.d.ts +16 -0
- package/dist/tools/export.worker.js +29 -0
- package/dist/tools/registry.d.ts +7 -4
- package/dist/tools/registry.js +1 -3
- package/dist/types/index.d.ts +1 -0
- package/dist/types/sheet.d.ts +6 -5
- package/dist/vue/formula-bar.js +393 -0
- package/dist/vue/formula-suggest-list.js +66 -0
- package/dist/vue/import-file.js +140 -0
- package/dist/vue/insert-count-menu-item.js +68 -0
- package/dist/vue/insert-image.js +79 -0
- package/dist/vue/popup-helpers.js +73 -0
- package/dist/vue/popups/border-popup.js +75 -0
- package/dist/vue/popups/border-preset-glyph.js +106 -0
- package/dist/vue/popups/export-popup.js +51 -0
- package/dist/vue/popups/fill-color-popup.js +37 -0
- package/dist/vue/popups/find-popup.js +113 -0
- package/dist/vue/popups/font-color-popup.js +37 -0
- package/dist/vue/popups/font-size-popup.js +63 -0
- package/dist/vue/popups/import.worker.d.ts +21 -0
- package/dist/vue/popups/import.worker.js +41 -0
- package/dist/vue/popups/insert-image-popup.js +38 -0
- package/dist/vue/sheet-context-menu.js +200 -0
- package/dist/vue/sheet-tabs.js +162 -0
- package/dist/vue/sheet-toolbar.js +106 -0
- package/dist/vue/sheet.js +144 -164
- package/dist/vue/style.d.ts +11 -1
- package/dist/vue/style.js +10 -0
- package/dist/vue/style2.css +564 -3
- package/dist/vue/use-find-replace.js +161 -0
- package/dist/vue/use-formula-ref-select.js +37 -0
- package/dist/vue/use-formula-suggest.js +126 -0
- package/dist/vue/use-sheet-grid.js +180 -0
- package/dist/vue/use-sheet-state.js +122 -0
- package/dist/vue/use-sheet-tabs-bar.js +90 -0
- package/dist/vue/use-tool-groups.js +42 -0
- package/dist/vue/use-tool-popup.js +123 -0
- package/dist/vue/use-toolbar-scroll.js +72 -0
- package/package.json +12 -7
- package/src/env.d.ts +11 -0
- package/src/index.ts +203 -14
- package/src/tools/__test__/builtin.test.ts +208 -66
- package/src/tools/__test__/context.test.ts +62 -2
- package/src/tools/builtin.ts +350 -6
- package/src/tools/context.ts +89 -11
- package/src/tools/download.ts +82 -0
- package/src/tools/export.worker.ts +61 -0
- package/src/tools/registry.ts +16 -1
- package/src/types/index.ts +6 -0
- package/src/types/sheet.ts +5 -3
- package/src/vue/__test__/formula-bar.test.ts +455 -0
- package/src/vue/__test__/import-file.test.ts +183 -0
- package/src/vue/__test__/insert-count-menu-item.test.ts +123 -0
- package/src/vue/__test__/insert-image-popup.test.ts +89 -0
- package/src/vue/__test__/insert-image.test.ts +100 -0
- package/src/vue/__test__/sheet-component.test.ts +716 -27
- package/src/vue/__test__/sheet-context-menu.test.ts +206 -0
- package/src/vue/__test__/use-formula-ref-select.test.ts +35 -0
- package/src/vue/__test__/use-formula-suggest.test.ts +83 -0
- package/src/vue/formula-bar.vue +473 -0
- package/src/vue/formula-suggest-list.vue +64 -0
- package/src/vue/import-file.ts +173 -0
- package/src/vue/insert-count-menu-item.vue +69 -0
- package/src/vue/insert-image.ts +90 -0
- package/src/vue/parsing.ts +11 -0
- package/src/vue/popup-helpers.ts +50 -0
- package/src/vue/popups/border-popup.vue +93 -0
- package/src/vue/popups/border-preset-glyph.vue +111 -0
- package/src/vue/popups/export-popup.vue +52 -0
- package/src/vue/popups/fill-color-popup.vue +39 -0
- package/src/vue/popups/find-popup.vue +111 -0
- package/src/vue/popups/font-color-popup.vue +39 -0
- package/src/vue/popups/font-size-popup.vue +52 -0
- package/src/vue/popups/import.worker.ts +66 -0
- package/src/vue/popups/insert-image-popup.vue +39 -0
- package/src/vue/sheet-context-menu.ts +229 -0
- package/src/vue/sheet-tabs.vue +162 -0
- package/src/vue/sheet-toolbar.vue +91 -0
- package/src/vue/sheet.vue +161 -186
- package/src/vue/style.scss +646 -3
- package/src/vue/style.ts +11 -0
- package/src/vue/use-find-replace.ts +200 -0
- package/src/vue/use-formula-ref-select.ts +34 -0
- package/src/vue/use-formula-suggest.ts +150 -0
- package/src/vue/use-sheet-grid.ts +243 -0
- package/src/vue/use-sheet-state.ts +161 -0
- package/src/vue/use-sheet-tabs-bar.ts +115 -0
- package/src/vue/use-tool-groups.ts +61 -0
- package/src/vue/use-tool-popup.ts +150 -0
- package/src/vue/use-toolbar-scroll.ts +95 -0
- package/dist/core/address.d.ts +0 -60
- package/dist/core/address.js +0 -142
- package/dist/core/address.js.map +0 -1
- package/dist/core/cell-store.d.ts +0 -61
- package/dist/core/cell-store.js +0 -135
- package/dist/core/cell-store.js.map +0 -1
- package/dist/core/command/default-registry.d.ts +0 -10
- package/dist/core/command/default-registry.js +0 -18
- package/dist/core/command/default-registry.js.map +0 -1
- package/dist/core/command/history.d.ts +0 -64
- package/dist/core/command/history.js +0 -127
- package/dist/core/command/history.js.map +0 -1
- package/dist/core/command/merge-cells.d.ts +0 -21
- package/dist/core/command/merge-cells.js +0 -74
- package/dist/core/command/merge-cells.js.map +0 -1
- package/dist/core/command/registry.d.ts +0 -17
- package/dist/core/command/registry.js +0 -26
- package/dist/core/command/registry.js.map +0 -1
- package/dist/core/command/set-cell-formula.d.ts +0 -17
- package/dist/core/command/set-cell-formula.js +0 -29
- package/dist/core/command/set-cell-formula.js.map +0 -1
- package/dist/core/command/set-cell-value.d.ts +0 -22
- package/dist/core/command/set-cell-value.js +0 -35
- package/dist/core/command/set-cell-value.js.map +0 -1
- package/dist/core/command/types.d.ts +0 -68
- package/dist/core/events.js +0 -29
- package/dist/core/events.js.map +0 -1
- package/dist/core/fill.d.ts +0 -34
- package/dist/core/fill.js +0 -320
- package/dist/core/fill.js.map +0 -1
- package/dist/core/formula/ast.d.ts +0 -58
- package/dist/core/formula/ast.js +0 -38
- package/dist/core/formula/ast.js.map +0 -1
- package/dist/core/formula/dependency-graph.d.ts +0 -70
- package/dist/core/formula/dependency-graph.js +0 -269
- package/dist/core/formula/dependency-graph.js.map +0 -1
- package/dist/core/formula/errors.d.ts +0 -25
- package/dist/core/formula/errors.js +0 -36
- package/dist/core/formula/errors.js.map +0 -1
- package/dist/core/formula/evaluator.d.ts +0 -41
- package/dist/core/formula/evaluator.js +0 -154
- package/dist/core/formula/evaluator.js.map +0 -1
- package/dist/core/formula/functions.d.ts +0 -30
- package/dist/core/formula/functions.js +0 -209
- package/dist/core/formula/functions.js.map +0 -1
- package/dist/core/formula/parser.d.ts +0 -7
- package/dist/core/formula/parser.js +0 -208
- package/dist/core/formula/parser.js.map +0 -1
- package/dist/core/formula/tokenizer.d.ts +0 -37
- package/dist/core/formula/tokenizer.js +0 -146
- package/dist/core/formula/tokenizer.js.map +0 -1
- package/dist/core/merge-manager.d.ts +0 -64
- package/dist/core/merge-manager.js +0 -111
- package/dist/core/merge-manager.js.map +0 -1
- package/dist/core/selection.d.ts +0 -31
- package/dist/core/selection.js +0 -62
- package/dist/core/selection.js.map +0 -1
- package/dist/core/sheet.d.ts +0 -116
- package/dist/core/sheet.js +0 -224
- package/dist/core/sheet.js.map +0 -1
- package/dist/core/workbook.d.ts +0 -43
- package/dist/core/workbook.js +0 -77
- package/dist/core/workbook.js.map +0 -1
- package/dist/grid/sheet-grid.d.ts +0 -81
- package/dist/grid/sheet-grid.js +0 -331
- package/dist/grid/sheet-grid.js.map +0 -1
- package/dist/grid/vtable-theme.js +0 -80
- package/dist/grid/vtable-theme.js.map +0 -1
- package/dist/tools/builtin.js.map +0 -1
- package/dist/tools/context.js.map +0 -1
- package/dist/tools/registry.js.map +0 -1
- package/dist/vue/index.d.ts +0 -2
- package/dist/vue/sheet.js.map +0 -1
- package/dist/vue/sheet.vue.d.ts +0 -24
- package/src/core/__test__/address.test.ts +0 -113
- package/src/core/__test__/cell-store.test.ts +0 -97
- package/src/core/__test__/command.test.ts +0 -377
- package/src/core/__test__/fill.test.ts +0 -140
- package/src/core/__test__/formula-adversarial.test.ts +0 -265
- package/src/core/__test__/formula-engine.test.ts +0 -470
- package/src/core/__test__/formula-functions.test.ts +0 -178
- package/src/core/__test__/formula-parser.test.ts +0 -160
- package/src/core/__test__/history.test.ts +0 -225
- package/src/core/__test__/merge-manager.test.ts +0 -106
- package/src/core/__test__/sheet.test.ts +0 -142
- package/src/core/address.ts +0 -166
- package/src/core/cell-store.ts +0 -173
- package/src/core/command/default-registry.ts +0 -15
- package/src/core/command/history.ts +0 -167
- package/src/core/command/index.ts +0 -7
- package/src/core/command/merge-cells.ts +0 -74
- package/src/core/command/registry.ts +0 -30
- package/src/core/command/set-cell-formula.ts +0 -29
- package/src/core/command/set-cell-value.ts +0 -38
- package/src/core/command/types.ts +0 -73
- package/src/core/events.ts +0 -37
- package/src/core/fill.ts +0 -314
- package/src/core/formula/ast.ts +0 -66
- package/src/core/formula/dependency-graph.ts +0 -329
- package/src/core/formula/errors.ts +0 -41
- package/src/core/formula/evaluator.ts +0 -219
- package/src/core/formula/functions.ts +0 -266
- package/src/core/formula/index.ts +0 -7
- package/src/core/formula/parser.ts +0 -198
- package/src/core/formula/tokenizer.ts +0 -160
- package/src/core/merge-manager.ts +0 -158
- package/src/core/selection.ts +0 -66
- package/src/core/sheet.ts +0 -282
- package/src/core/workbook.ts +0 -99
- package/src/grid/__test__/canvas-mock.ts +0 -49
- package/src/grid/__test__/setup.ts +0 -3
- package/src/grid/__test__/sheet-grid-formula.test.ts +0 -140
- package/src/grid/__test__/sheet-grid.test.ts +0 -275
- package/src/grid/sheet-grid.ts +0 -407
- package/src/grid/vtable-theme.ts +0 -61
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { nextTick, onBeforeUnmount, onMounted, shallowRef, watch } from "vue";
|
|
2
|
+
import { applyWheelHorizontalScroll, computeOverflowNavState, scrollElementIntoView, scrollViewportByStep } from "@veltra/utils";
|
|
3
|
+
//#region src/vue/use-sheet-tabs-bar.ts
|
|
4
|
+
/**
|
|
5
|
+
* Sheet 底部标签栏溢出滚动(滚动几何/滚轮转横滚/元素滚入视野共享
|
|
6
|
+
* @veltra/utils overflow-nav,见 #17;此处保留事件绑定与 watch 差异):
|
|
7
|
+
* - showNav / canPrev / canNext
|
|
8
|
+
* - 箭头按视口宽度 ~80% 步进
|
|
9
|
+
* - 活动 tab 滚入视野
|
|
10
|
+
* - 纵向滚轮转横滚;触控板横滑不拦截
|
|
11
|
+
* - 原生 ResizeObserver(不引入 @veltra/compositions peer)
|
|
12
|
+
*/
|
|
13
|
+
function useSheetTabsBar(options) {
|
|
14
|
+
const { viewportRef, listRef, sheetList, activeIndex } = options;
|
|
15
|
+
const showNav = shallowRef(false);
|
|
16
|
+
const canPrev = shallowRef(false);
|
|
17
|
+
const canNext = shallowRef(false);
|
|
18
|
+
let resizeObserver;
|
|
19
|
+
const updateNavState = () => {
|
|
20
|
+
const vp = viewportRef.value;
|
|
21
|
+
if (!vp) return;
|
|
22
|
+
const state = computeOverflowNavState(vp);
|
|
23
|
+
showNav.value = state.overflowing;
|
|
24
|
+
canPrev.value = state.canPrev;
|
|
25
|
+
canNext.value = state.canNext;
|
|
26
|
+
};
|
|
27
|
+
const scrollByStep = (dir) => {
|
|
28
|
+
const vp = viewportRef.value;
|
|
29
|
+
if (!vp) return;
|
|
30
|
+
scrollViewportByStep(vp, dir);
|
|
31
|
+
};
|
|
32
|
+
const ensureActiveVisible = () => {
|
|
33
|
+
const vp = viewportRef.value;
|
|
34
|
+
const list = listRef.value;
|
|
35
|
+
if (!vp || !list) return;
|
|
36
|
+
const index = activeIndex.value;
|
|
37
|
+
if (index < 0) return;
|
|
38
|
+
const el = list.children[index];
|
|
39
|
+
if (!el) return;
|
|
40
|
+
scrollElementIntoView(vp, el);
|
|
41
|
+
};
|
|
42
|
+
/** 鼠标滚轮(纵向)驱动水平滚动;触控板横滑(已有 deltaX)不拦截 */
|
|
43
|
+
const handleWheel = (e) => {
|
|
44
|
+
const vp = viewportRef.value;
|
|
45
|
+
if (!vp) return;
|
|
46
|
+
applyWheelHorizontalScroll(e, vp, showNav.value);
|
|
47
|
+
};
|
|
48
|
+
watch(activeIndex, async () => {
|
|
49
|
+
await nextTick();
|
|
50
|
+
ensureActiveVisible();
|
|
51
|
+
updateNavState();
|
|
52
|
+
});
|
|
53
|
+
watch(sheetList, async () => {
|
|
54
|
+
await nextTick();
|
|
55
|
+
updateNavState();
|
|
56
|
+
ensureActiveVisible();
|
|
57
|
+
}, { deep: false });
|
|
58
|
+
onMounted(() => {
|
|
59
|
+
const vp = viewportRef.value;
|
|
60
|
+
const list = listRef.value;
|
|
61
|
+
if (vp) {
|
|
62
|
+
vp.addEventListener("wheel", handleWheel, { passive: false });
|
|
63
|
+
vp.addEventListener("scroll", updateNavState, { passive: true });
|
|
64
|
+
}
|
|
65
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
66
|
+
resizeObserver = new ResizeObserver(() => updateNavState());
|
|
67
|
+
if (vp) resizeObserver.observe(vp);
|
|
68
|
+
if (list) resizeObserver.observe(list);
|
|
69
|
+
}
|
|
70
|
+
updateNavState();
|
|
71
|
+
nextTick(ensureActiveVisible);
|
|
72
|
+
});
|
|
73
|
+
onBeforeUnmount(() => {
|
|
74
|
+
const vp = viewportRef.value;
|
|
75
|
+
if (vp) {
|
|
76
|
+
vp.removeEventListener("wheel", handleWheel);
|
|
77
|
+
vp.removeEventListener("scroll", updateNavState);
|
|
78
|
+
}
|
|
79
|
+
resizeObserver?.disconnect();
|
|
80
|
+
resizeObserver = void 0;
|
|
81
|
+
});
|
|
82
|
+
return {
|
|
83
|
+
showNav,
|
|
84
|
+
canPrev,
|
|
85
|
+
canNext,
|
|
86
|
+
scrollByStep
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//#endregion
|
|
90
|
+
export { useSheetTabsBar };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { defaultToolRegistry } from "../tools/registry.js";
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
//#region src/vue/use-tool-groups.ts
|
|
4
|
+
/**
|
|
5
|
+
* 内置组稳定顺序:history | cell | text | edit | insert | file。
|
|
6
|
+
* 未列出的自定义组按注册先后排在已知组之后。
|
|
7
|
+
*/
|
|
8
|
+
const BUILTIN_GROUP_ORDER = [
|
|
9
|
+
"history",
|
|
10
|
+
"cell",
|
|
11
|
+
"text",
|
|
12
|
+
"edit",
|
|
13
|
+
"insert",
|
|
14
|
+
"file"
|
|
15
|
+
];
|
|
16
|
+
/**
|
|
17
|
+
* 工具栏分组视图模型:工具的 visible/disabled/active 是 (ctx) => boolean 纯函数,
|
|
18
|
+
* 依赖 stateTick 版本号(选区 / 历史 / 单元格 / 合并 / 冻结 / 注册表变化时 bump)触发重算。
|
|
19
|
+
*/
|
|
20
|
+
function useToolGroups(context, stateTick) {
|
|
21
|
+
return computed(() => {
|
|
22
|
+
stateTick.value;
|
|
23
|
+
const groups = defaultToolRegistry.getGroups().map((group) => ({
|
|
24
|
+
name: group.name,
|
|
25
|
+
tools: group.tools.map((tool) => ({
|
|
26
|
+
tool,
|
|
27
|
+
visible: tool.visible?.(context) ?? true,
|
|
28
|
+
disabled: tool.disabled?.(context) ?? false,
|
|
29
|
+
active: tool.active?.(context) ?? false
|
|
30
|
+
})).filter((item) => item.visible)
|
|
31
|
+
})).filter((group) => group.tools.length > 0);
|
|
32
|
+
const orderIndex = new Map(BUILTIN_GROUP_ORDER.map((name, index) => [name, index]));
|
|
33
|
+
return groups.sort((a, b) => {
|
|
34
|
+
const ai = orderIndex.get(a.name) ?? BUILTIN_GROUP_ORDER.length;
|
|
35
|
+
const bi = orderIndex.get(b.name) ?? BUILTIN_GROUP_ORDER.length;
|
|
36
|
+
if (ai !== bi) return ai - bi;
|
|
37
|
+
return 0;
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
export { useToolGroups };
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { defaultToolRegistry } from "../tools/registry.js";
|
|
2
|
+
import { onBeforeUnmount, onMounted, shallowRef } from "vue";
|
|
3
|
+
//#region src/vue/use-tool-popup.ts
|
|
4
|
+
/**
|
|
5
|
+
* 面板打开期间的写入是否合并为一个 undo 单元(关闭时提交):
|
|
6
|
+
* 填充颜色 / 边框 / 字体颜色 / 字号参与事务;查找(每次替换独立 undo)、
|
|
7
|
+
* 导出(下载侧效应,无模型写入)不参与。导入无弹层,不经此路径。
|
|
8
|
+
*/
|
|
9
|
+
function joinsTransaction(tool) {
|
|
10
|
+
return tool.popup === "fill-color" || tool.popup === "border" || tool.popup === "font-color" || tool.popup === "font-size";
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 弹层型工具编排(填充颜色 / 边框 / 查找 / 插入图片 / 导出):
|
|
14
|
+
* - popupTool:当前打开的弹层工具(null = 未打开)
|
|
15
|
+
* - popupAnchor:触发按钮元素(面板定位参照,见 sheet.vue 的 left 计算)
|
|
16
|
+
* - 打开 / 关闭时的事务包裹(面板期间写入合并为一个 undo 单元,关闭时提交)
|
|
17
|
+
* - 点击面板外关闭(面板内 @click.stop 不冒泡到 window)
|
|
18
|
+
* - Ctrl/Cmd+F 开合查找条(与工具按钮同一 toggle 逻辑)
|
|
19
|
+
* 导入在 sheet.vue 特殊处理(直接系统文件选择),不经弹层。
|
|
20
|
+
*/
|
|
21
|
+
function useToolPopup(context, rootEl) {
|
|
22
|
+
/** 当前打开的弹层工具(null = 未打开) */
|
|
23
|
+
const popupTool = shallowRef(null);
|
|
24
|
+
/** 触发按钮元素(打开时的 currentTarget;用于面板 left 对齐按钮) */
|
|
25
|
+
const popupAnchor = shallowRef(null);
|
|
26
|
+
/** 延迟打开定时器(#23:组件卸载后不再执行 openPopup) */
|
|
27
|
+
let openTimer = null;
|
|
28
|
+
function openPopup(tool, anchor) {
|
|
29
|
+
closePopup();
|
|
30
|
+
popupTool.value = tool;
|
|
31
|
+
popupAnchor.value = anchor ?? null;
|
|
32
|
+
if (joinsTransaction(tool)) context.beginTransaction();
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 延迟到本次点击事件流结束后打开(setTimeout 宏任务,避开冒泡到 window 时
|
|
36
|
+
* onWindowClick 误关——queueMicrotask 会在事件传播中途的 microtask checkpoint
|
|
37
|
+
* 执行,面板会被同一 click 关闭)。保存 timer id,卸载/提前关闭时取消。
|
|
38
|
+
*/
|
|
39
|
+
function scheduleOpen(tool, anchor) {
|
|
40
|
+
if (openTimer !== null) clearTimeout(openTimer);
|
|
41
|
+
openTimer = setTimeout(() => {
|
|
42
|
+
openTimer = null;
|
|
43
|
+
openPopup(tool, anchor);
|
|
44
|
+
}, 0);
|
|
45
|
+
}
|
|
46
|
+
/** 关闭弹层并提交面板期间的事务(无写入则空事务,不入历史) */
|
|
47
|
+
function closePopup() {
|
|
48
|
+
if (openTimer !== null) {
|
|
49
|
+
clearTimeout(openTimer);
|
|
50
|
+
openTimer = null;
|
|
51
|
+
}
|
|
52
|
+
const tool = popupTool.value;
|
|
53
|
+
if (!tool) return;
|
|
54
|
+
popupTool.value = null;
|
|
55
|
+
popupAnchor.value = null;
|
|
56
|
+
if (!joinsTransaction(tool)) return;
|
|
57
|
+
try {
|
|
58
|
+
context.commit();
|
|
59
|
+
} catch {
|
|
60
|
+
context.rollback();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function handleToolClick(tool, event) {
|
|
64
|
+
if (tool.disabled?.(context)) return;
|
|
65
|
+
if (tool.popup) {
|
|
66
|
+
if (popupTool.value?.id === tool.id) {
|
|
67
|
+
closePopup();
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
scheduleOpen(tool, event?.currentTarget instanceof HTMLElement ? event.currentTarget : null);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
tool.onClick(context);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 点击面板外任意处关闭。面板内部 @click.stop 不冒泡到 window;
|
|
77
|
+
* 触发按钮本身的点击由 handleToolClick 同步处理(打开/关闭 toggle),
|
|
78
|
+
* 冒泡到达这里时 popupTool 已更新,不会误关。
|
|
79
|
+
*/
|
|
80
|
+
function onWindowClick() {
|
|
81
|
+
if (!popupTool.value) return;
|
|
82
|
+
closePopup();
|
|
83
|
+
}
|
|
84
|
+
/** Ctrl/Cmd+F 打开 / 关闭查找条(与工具按钮同一 toggle 逻辑) */
|
|
85
|
+
function onGlobalKeydown(event) {
|
|
86
|
+
if (!(event.metaKey || event.ctrlKey) || event.key.toLowerCase() !== "f") return;
|
|
87
|
+
const root = rootEl.value;
|
|
88
|
+
if (root) {
|
|
89
|
+
const target = event.target instanceof Node ? event.target : null;
|
|
90
|
+
const active = document.activeElement instanceof Node ? document.activeElement : null;
|
|
91
|
+
if (!(target !== null && root.contains(target) || active !== null && root.contains(active)) && popupTool.value === null) return;
|
|
92
|
+
}
|
|
93
|
+
event.preventDefault();
|
|
94
|
+
const findTool = defaultToolRegistry.get("find");
|
|
95
|
+
if (!findTool) return;
|
|
96
|
+
if (popupTool.value?.id === findTool.id) {
|
|
97
|
+
closePopup();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
scheduleOpen(findTool);
|
|
101
|
+
}
|
|
102
|
+
onMounted(() => {
|
|
103
|
+
window.addEventListener("click", onWindowClick);
|
|
104
|
+
window.addEventListener("keydown", onGlobalKeydown);
|
|
105
|
+
});
|
|
106
|
+
onBeforeUnmount(() => {
|
|
107
|
+
if (openTimer !== null) {
|
|
108
|
+
clearTimeout(openTimer);
|
|
109
|
+
openTimer = null;
|
|
110
|
+
}
|
|
111
|
+
closePopup();
|
|
112
|
+
window.removeEventListener("click", onWindowClick);
|
|
113
|
+
window.removeEventListener("keydown", onGlobalKeydown);
|
|
114
|
+
});
|
|
115
|
+
return {
|
|
116
|
+
popupTool,
|
|
117
|
+
popupAnchor,
|
|
118
|
+
closePopup,
|
|
119
|
+
handleToolClick
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
//#endregion
|
|
123
|
+
export { useToolPopup };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { onBeforeUnmount, onMounted, shallowRef, watch } from "vue";
|
|
2
|
+
import { applyWheelHorizontalScroll, computeOverflowNavState, scrollViewportByStep } from "@veltra/utils";
|
|
3
|
+
//#region src/vue/use-toolbar-scroll.ts
|
|
4
|
+
/**
|
|
5
|
+
* 工具栏溢出滚动(滚动几何/滚轮转横滚共享 @veltra/utils overflow-nav,见 #17;
|
|
6
|
+
* 无活动项跟随):
|
|
7
|
+
* - 内容超出视口宽度时显示左右箭头(showNav / canPrev / canNext)
|
|
8
|
+
* - 箭头按视口宽度 ~80% 步进
|
|
9
|
+
* - 纵向滚轮转横滚;触控板横滑不拦截
|
|
10
|
+
* - 原生 ResizeObserver(不引入 @veltra/compositions peer)
|
|
11
|
+
*/
|
|
12
|
+
function useToolbarScroll(options) {
|
|
13
|
+
const { viewportRef, listRef, content } = options;
|
|
14
|
+
const showNav = shallowRef(false);
|
|
15
|
+
const canPrev = shallowRef(false);
|
|
16
|
+
const canNext = shallowRef(false);
|
|
17
|
+
let resizeObserver;
|
|
18
|
+
const updateNavState = () => {
|
|
19
|
+
const vp = viewportRef.value;
|
|
20
|
+
if (!vp) return;
|
|
21
|
+
const state = computeOverflowNavState(vp);
|
|
22
|
+
showNav.value = state.overflowing;
|
|
23
|
+
canPrev.value = state.canPrev;
|
|
24
|
+
canNext.value = state.canNext;
|
|
25
|
+
};
|
|
26
|
+
const scrollByStep = (dir) => {
|
|
27
|
+
const vp = viewportRef.value;
|
|
28
|
+
if (!vp) return;
|
|
29
|
+
scrollViewportByStep(vp, dir);
|
|
30
|
+
};
|
|
31
|
+
/** 鼠标滚轮(纵向)驱动水平滚动;触控板横滑(已有 deltaX)不拦截 */
|
|
32
|
+
const handleWheel = (e) => {
|
|
33
|
+
const vp = viewportRef.value;
|
|
34
|
+
if (!vp) return;
|
|
35
|
+
applyWheelHorizontalScroll(e, vp, showNav.value);
|
|
36
|
+
};
|
|
37
|
+
watch(content, async () => {
|
|
38
|
+
await Promise.resolve();
|
|
39
|
+
updateNavState();
|
|
40
|
+
}, { deep: false });
|
|
41
|
+
onMounted(() => {
|
|
42
|
+
const vp = viewportRef.value;
|
|
43
|
+
if (vp) {
|
|
44
|
+
vp.addEventListener("wheel", handleWheel, { passive: false });
|
|
45
|
+
vp.addEventListener("scroll", updateNavState, { passive: true });
|
|
46
|
+
}
|
|
47
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
48
|
+
resizeObserver = new ResizeObserver(() => updateNavState());
|
|
49
|
+
if (vp) resizeObserver.observe(vp);
|
|
50
|
+
const list = listRef.value;
|
|
51
|
+
if (list) resizeObserver.observe(list);
|
|
52
|
+
}
|
|
53
|
+
updateNavState();
|
|
54
|
+
});
|
|
55
|
+
onBeforeUnmount(() => {
|
|
56
|
+
const vp = viewportRef.value;
|
|
57
|
+
if (vp) {
|
|
58
|
+
vp.removeEventListener("wheel", handleWheel);
|
|
59
|
+
vp.removeEventListener("scroll", updateNavState);
|
|
60
|
+
}
|
|
61
|
+
resizeObserver?.disconnect();
|
|
62
|
+
resizeObserver = void 0;
|
|
63
|
+
});
|
|
64
|
+
return {
|
|
65
|
+
showNav,
|
|
66
|
+
canPrev,
|
|
67
|
+
canNext,
|
|
68
|
+
scrollByStep
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
export { useToolbarScroll };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veltra/sheet",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"files": [
|
|
5
5
|
"dist",
|
|
6
6
|
"src"
|
|
@@ -25,14 +25,19 @@
|
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"
|
|
29
|
-
"@visactor/vtable-editors": "^1.26.5"
|
|
28
|
+
"hucre": "^1.0.0"
|
|
30
29
|
},
|
|
31
30
|
"peerDependencies": {
|
|
32
31
|
"@cat-kit/core": ">=1.1.8",
|
|
33
|
-
"@
|
|
34
|
-
"@veltra/
|
|
35
|
-
"@veltra/
|
|
36
|
-
"
|
|
32
|
+
"@cat-kit/fe": ">=1.1.8",
|
|
33
|
+
"@veltra/desktop": "^1.5.0",
|
|
34
|
+
"@veltra/icons": "^1.5.0",
|
|
35
|
+
"@veltra/sheet-core": "^2.1.1",
|
|
36
|
+
"@veltra/styles": "^1.5.0",
|
|
37
|
+
"@veltra/utils": "^1.5.0",
|
|
38
|
+
"vue": ">=3.5.41"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@visactor/vtable": "^1.26.6"
|
|
37
42
|
}
|
|
38
43
|
}
|
package/src/env.d.ts
CHANGED
|
@@ -8,3 +8,14 @@ declare module '*.scss' {}
|
|
|
8
8
|
|
|
9
9
|
// 跨包样式副作用子路径(veltra-dev → src/* 无扩展名,TS 不做扩展探测)
|
|
10
10
|
declare module '@veltra/desktop/components/*/style' {}
|
|
11
|
+
|
|
12
|
+
// 供 lint typeCheck 识别 import.meta.env(worker 的 dev/prod URL 分支),无需安装 vite
|
|
13
|
+
interface ImportMetaEnv {
|
|
14
|
+
readonly DEV: boolean
|
|
15
|
+
readonly PROD: boolean
|
|
16
|
+
readonly MODE: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface ImportMeta {
|
|
20
|
+
readonly env: ImportMetaEnv
|
|
21
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,17 +1,206 @@
|
|
|
1
1
|
// 内置工具注册(undo/redo/合并/取消合并):随包入口完成,
|
|
2
|
-
// 与 core
|
|
2
|
+
// 与 sheet-core command 的 default-registry 同构;深导入 sheet-core 子路径的
|
|
3
|
+
// 无头场景不涉及
|
|
3
4
|
import './tools/builtin'
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
6
|
+
// 数据模型 / 渲染内核(原 src/core、src/grid)已迁至 @veltra/sheet-core,
|
|
7
|
+
// 下方 core/grid 来源的导出全部为其主入口白名单的 re-export(公开 API 不变)。
|
|
8
|
+
// 聚合导出为**公开 API 白名单**:仅测试引用的内部符号(如 rangeContainsRange、
|
|
9
|
+
// mergeCellStyle、shiftFormulaRefs、io 转换函数、grid 样式映射、normalizeStyle、
|
|
10
|
+
// ToolRegistry 类等,见 #31)不在此导出,测试一律深导入 @veltra/sheet-core 子路径。
|
|
11
|
+
// 类成员方法(Sheet.setCell / setCellStyles、CellStore.setCellValue 等)随类整体
|
|
12
|
+
// 导出,属内部实现细节,见 packages/sheet/AGENTS.md「核心语义」注。
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
cellKey,
|
|
16
|
+
colIndexToName,
|
|
17
|
+
colNameToIndex,
|
|
18
|
+
parseAddress,
|
|
19
|
+
formatAddress,
|
|
20
|
+
createRange,
|
|
21
|
+
parseRange,
|
|
22
|
+
formatRange,
|
|
23
|
+
rangesEqual,
|
|
24
|
+
rangesIntersect,
|
|
25
|
+
rangeContainsAddress,
|
|
26
|
+
boundingBox,
|
|
27
|
+
iterateRange,
|
|
28
|
+
type CellAddress,
|
|
29
|
+
type CellRange
|
|
30
|
+
} from '@veltra/sheet-core'
|
|
31
|
+
|
|
32
|
+
export {
|
|
33
|
+
NUMERIC_TEXT_RE,
|
|
34
|
+
normalizeInputValue,
|
|
35
|
+
inferCellType,
|
|
36
|
+
isEmptyCellData,
|
|
37
|
+
cellDataEqual,
|
|
38
|
+
CellStore,
|
|
39
|
+
type CellType,
|
|
40
|
+
type CellValue,
|
|
41
|
+
type CellData,
|
|
42
|
+
type CellSnapshotItem
|
|
43
|
+
} from '@veltra/sheet-core'
|
|
44
|
+
|
|
45
|
+
export {
|
|
46
|
+
computeFillTargetRange,
|
|
47
|
+
generateFill,
|
|
48
|
+
type FillDirection,
|
|
49
|
+
type GenerateFillOptions
|
|
50
|
+
} from '@veltra/sheet-core'
|
|
51
|
+
|
|
52
|
+
export {
|
|
53
|
+
findAll,
|
|
54
|
+
findNext,
|
|
55
|
+
findNextFrom,
|
|
56
|
+
findPrev,
|
|
57
|
+
findPrevFrom,
|
|
58
|
+
type FindOptions,
|
|
59
|
+
type FindMatch
|
|
60
|
+
} from '@veltra/sheet-core'
|
|
61
|
+
|
|
62
|
+
export {
|
|
63
|
+
MergeManager,
|
|
64
|
+
type MergedCellKind,
|
|
65
|
+
type CellInfo,
|
|
66
|
+
type MergeResult
|
|
67
|
+
} from '@veltra/sheet-core'
|
|
68
|
+
|
|
69
|
+
export { SelectionModel, type SelectionState } from '@veltra/sheet-core'
|
|
70
|
+
|
|
71
|
+
export { Sheet, type FrozenState, type SheetSnapshot, type SheetEvents } from '@veltra/sheet-core'
|
|
72
|
+
|
|
73
|
+
export {
|
|
74
|
+
createImageId,
|
|
75
|
+
cloneImageAnchor,
|
|
76
|
+
cloneSheetImage,
|
|
77
|
+
type SheetImageType,
|
|
78
|
+
type SheetImageAnchor,
|
|
79
|
+
type SheetImage,
|
|
80
|
+
type ImageInput
|
|
81
|
+
} from '@veltra/sheet-core'
|
|
82
|
+
|
|
83
|
+
export {
|
|
84
|
+
BORDER_SIDES,
|
|
85
|
+
BORDER_STYLE_WIDTH,
|
|
86
|
+
BORDER_EDGE_DEFAULTS,
|
|
87
|
+
FONT_STYLE_KEYS,
|
|
88
|
+
ALIGN_STYLE_KEYS,
|
|
89
|
+
type BorderLineStyle,
|
|
90
|
+
type BorderSide,
|
|
91
|
+
type BorderEdge,
|
|
92
|
+
type HorizontalAlign,
|
|
93
|
+
type VerticalAlign,
|
|
94
|
+
type CellFont,
|
|
95
|
+
type CellAlign,
|
|
96
|
+
type CellStyle,
|
|
97
|
+
type StyleId,
|
|
98
|
+
type CellStylePatch
|
|
99
|
+
} from '@veltra/sheet-core'
|
|
100
|
+
|
|
101
|
+
export { StylePool } from '@veltra/sheet-core'
|
|
102
|
+
|
|
103
|
+
export {
|
|
104
|
+
buildBorderPresetItems,
|
|
105
|
+
type BorderPreset,
|
|
106
|
+
type BorderPresetItem
|
|
107
|
+
} from '@veltra/sheet-core'
|
|
108
|
+
|
|
109
|
+
export { Workbook, type WorkbookEvents } from '@veltra/sheet-core'
|
|
110
|
+
|
|
111
|
+
export {
|
|
112
|
+
HistoryManager,
|
|
113
|
+
type HistoryState,
|
|
114
|
+
type PatchDirection,
|
|
115
|
+
type CellPatch,
|
|
116
|
+
type MergePatch,
|
|
117
|
+
type StructureChange,
|
|
118
|
+
type StructurePatch,
|
|
119
|
+
type SnapshotPatch,
|
|
120
|
+
type ImagePatch,
|
|
121
|
+
type Patch,
|
|
122
|
+
type Mutation,
|
|
123
|
+
type CommandResult,
|
|
124
|
+
type CommandContext,
|
|
125
|
+
type Command,
|
|
126
|
+
type SetCellValueItem,
|
|
127
|
+
type SetCellValueParams,
|
|
128
|
+
SetCellValueCommand,
|
|
129
|
+
type SetCellFormulaParams,
|
|
130
|
+
SetCellFormulaCommand,
|
|
131
|
+
type SetCellStyleItem,
|
|
132
|
+
type SetCellStyleParams,
|
|
133
|
+
SetCellStyleCommand,
|
|
134
|
+
type InsertCellsParams,
|
|
135
|
+
InsertCellsCommand,
|
|
136
|
+
type MergeCellsParams,
|
|
137
|
+
MergeCellsCommand,
|
|
138
|
+
type UnmergeCellsParams,
|
|
139
|
+
UnmergeCellsCommand,
|
|
140
|
+
type InsertImageParams,
|
|
141
|
+
InsertImageCommand,
|
|
142
|
+
type RemoveImageParams,
|
|
143
|
+
RemoveImageCommand,
|
|
144
|
+
type ImageUpdateFields,
|
|
145
|
+
type UpdateImageParams,
|
|
146
|
+
UpdateImageCommand,
|
|
147
|
+
defaultCommandRegistry
|
|
148
|
+
} from '@veltra/sheet-core'
|
|
149
|
+
|
|
150
|
+
export {
|
|
151
|
+
FORMULA_ERROR_CODES,
|
|
152
|
+
formulaError,
|
|
153
|
+
isFormulaError,
|
|
154
|
+
isFormulaErrorCode,
|
|
155
|
+
type FormulaErrorCode,
|
|
156
|
+
type FormulaError,
|
|
157
|
+
type BinaryOperator,
|
|
158
|
+
type AstNode,
|
|
159
|
+
type AstReference,
|
|
160
|
+
collectReferences,
|
|
161
|
+
FormulaParseError,
|
|
162
|
+
tokenizeFormula,
|
|
163
|
+
type FormulaOperator,
|
|
164
|
+
type FormulaToken,
|
|
165
|
+
parseFormula,
|
|
166
|
+
type ScalarValue,
|
|
167
|
+
type EvalValue,
|
|
168
|
+
type FormulaEvalContext,
|
|
169
|
+
coerceToNumber,
|
|
170
|
+
coerceToText,
|
|
171
|
+
coerceToBoolean,
|
|
172
|
+
evaluateAst,
|
|
173
|
+
registerFormulaFunction,
|
|
174
|
+
listFormulaFunctions,
|
|
175
|
+
invokeFormulaFunction,
|
|
176
|
+
type FormulaFunctionMeta,
|
|
177
|
+
type FormulaFunction,
|
|
178
|
+
type FormulaDependency,
|
|
179
|
+
type FormulaNode,
|
|
180
|
+
DependencyGraph
|
|
181
|
+
} from '@veltra/sheet-core'
|
|
182
|
+
|
|
183
|
+
export { exportWorkbookXlsx, exportSheetCsv } from '@veltra/sheet-core'
|
|
184
|
+
export { importXlsx, importCsv, replaceWorkbook } from '@veltra/sheet-core'
|
|
185
|
+
|
|
186
|
+
export {
|
|
187
|
+
SheetGrid,
|
|
188
|
+
type SheetGridOptions,
|
|
189
|
+
type SheetGridContextMenuKind,
|
|
190
|
+
type SheetGridContextMenuInfo
|
|
191
|
+
} from '@veltra/sheet-core'
|
|
192
|
+
|
|
193
|
+
export { createSheetContext, type SheetContext } from './tools/context'
|
|
194
|
+
|
|
195
|
+
export {
|
|
196
|
+
defaultToolRegistry,
|
|
197
|
+
registerTool,
|
|
198
|
+
unregisterTool,
|
|
199
|
+
type SheetToolPopupType,
|
|
200
|
+
type SheetTool,
|
|
201
|
+
type SheetToolGroup
|
|
202
|
+
} from './tools/registry'
|
|
203
|
+
|
|
204
|
+
export { type SheetProps, type SheetEmits, type _SheetExposed, type SheetExposed } from './types'
|
|
205
|
+
|
|
206
|
+
export { default as USheet } from './vue/sheet.vue'
|