xiaodao-spreader 0.1.18 → 0.1.20

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.
@@ -0,0 +1,101 @@
1
+ /**
2
+ * BorderPool — 边框池,用于减少重复边框数据的存储体积。
3
+ *
4
+ * 核心思路:
5
+ * - 每个 Sheet 维护一个 borders: BorderStyle[] 数组,borders[0] 始终为默认空边框 {}。
6
+ * - 单元格样式通过 borderId(数组下标)引用边框,而非内联存储完整边框对象。
7
+ * - 相同内容的边框(即使属性顺序不同)自动复用同一 borderId。
8
+ * - 已注册的边框对象禁止直接修改(Object.freeze),修改必须创建副本后重新注册。
9
+ *
10
+ * 持久化注意:
11
+ * - index(Map<string, number>)仅运行时使用,不参与序列化。
12
+ * - 序列化时只需输出 borders 数组 + cells 中 style 的 borderId。
13
+ */
14
+ import type { BorderStyle, BorderSide, CellData, CellStyle } from './types';
15
+ /**
16
+ * 边框池结构化接口:BorderPool 实例与运行时适配器(如 CoreState 的 borders 数组 + 索引)均可满足。
17
+ */
18
+ export interface BorderPoolLike {
19
+ get(borderId: number): BorderStyle;
20
+ getId(border: BorderStyle): number;
21
+ }
22
+ export declare class BorderPool {
23
+ /** 边框数组:borders[0] 始终为默认空边框 {} */
24
+ private borders;
25
+ /** 运行时去重索引:stableKey → borderId,不参与持久化 */
26
+ private index;
27
+ constructor(existingBorders?: BorderStyle[]);
28
+ /**
29
+ * 生成稳定的边框 key:对属性名排序后 JSON.stringify。
30
+ * 保证属性顺序不同但内容相同的边框产生相同的 key。
31
+ */
32
+ private stableKey;
33
+ /**
34
+ * 根据 borderId 获取边框对象(只读)。
35
+ * 返回 Object.freeze 冻结的对象,禁止直接修改。
36
+ */
37
+ get(borderId: number): BorderStyle;
38
+ /**
39
+ * 查找或注册边框,返回对应的 borderId。
40
+ * 相同内容的边框自动复用已有 id。
41
+ */
42
+ getId(border: BorderStyle): number;
43
+ /** 判断边框是否为空 */
44
+ private isEmptyBorder;
45
+ /** 深拷贝边框对象 */
46
+ private deepCloneBorder;
47
+ /** 返回 borders 数组的浅拷贝(用于持久化/快照) */
48
+ getBorders(): BorderStyle[];
49
+ /** 直接设置 borders 数组(用于恢复快照),同时重建 index */
50
+ setBorders(borders: BorderStyle[]): void;
51
+ /**
52
+ * Border GC(垃圾回收):
53
+ * 扫描 styles 中实际使用的 borderId,删除未被引用的 borders,
54
+ * 重新生成连续的 borderId 并同步更新所有 styles。
55
+ * borders[0] 始终保留。
56
+ *
57
+ * 建议在保存/持久化/导出时调用,不要在每次编辑时执行。
58
+ */
59
+ compactBorders(styles: CellStyle[]): BorderStyle[];
60
+ }
61
+ /**
62
+ * 获取单元格的 BorderSide。
63
+ * 通过 cell.styleId → style.borderId → borderPool → BorderStyle[side]
64
+ */
65
+ export declare function getCellBorderSide(cell: CellData | undefined, side: 'top' | 'right' | 'bottom' | 'left', styles: CellStyle[], borderPool: BorderPoolLike): BorderSide | undefined;
66
+ /**
67
+ * 获取单元格的完整 BorderStyle。
68
+ */
69
+ export declare function getCellBorder(cell: CellData | undefined, styles: CellStyle[], borderPool: BorderPoolLike): BorderStyle | undefined;
70
+ /**
71
+ * 设置单元格的某一侧边框。
72
+ * 读取旧 BorderStyle → 创建副本 → 修改指定边 → 注册到 BorderPool → 更新 style.borderId。
73
+ * 不会影响其他共享相同 borderId 的单元格。
74
+ */
75
+ export declare function setCellBorderSide(cell: CellData, side: 'top' | 'right' | 'bottom' | 'left', borderSide: BorderSide | undefined, styles: CellStyle[], borderPool: BorderPoolLike, registerStyle: (style: CellStyle) => number): void;
76
+ /**
77
+ * 设置单元格的完整边框(四边)。
78
+ */
79
+ export declare function setCellBorder(cell: CellData, border: BorderStyle, styles: CellStyle[], borderPool: BorderPoolLike, registerStyle: (style: CellStyle) => number): void;
80
+ /**
81
+ * 清除单元格的边框。
82
+ */
83
+ export declare function clearCellBorder(cell: CellData, styles: CellStyle[], registerStyle: (style: CellStyle) => number): void;
84
+ /**
85
+ * 迁移旧版边框数据(borderTopWidth 等)到新的 BorderPool 机制。
86
+ * 扫描 styles 数组中所有含旧边框属性的样式,转换为 BorderStyle 注册到 BorderPool。
87
+ */
88
+ export declare function migrateBordersInStyles(styles: CellStyle[]): {
89
+ styles: CellStyle[];
90
+ borders: BorderStyle[];
91
+ };
92
+ /**
93
+ * 清理 merge 内部的边框数据(可选,保存时调用)。
94
+ * merge 内部 grid cell 的边框在渲染时会被忽略,此函数清理这些冗余数据。
95
+ */
96
+ export declare function cleanupMergeInternalBorders(cells: Record<string, CellData>, merges: Record<string, {
97
+ startCol: number;
98
+ startRow: number;
99
+ endCol: number;
100
+ endRow: number;
101
+ }>, styles: CellStyle[], borderPool: BorderPoolLike, cellKey: (c: number, r: number) => string, registerStyle: (style: CellStyle) => number): void;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Border Resolve — 公共边统一解析。
3
+ *
4
+ * 核心函数 resolveSharedBorder 负责处理相邻两个 BorderSide 的冲突,
5
+ * 产生唯一的最终视觉边框结果。
6
+ *
7
+ * 冲突规则(按优先级):
8
+ * 1. 两侧都 undefined/空 → 不绘制
9
+ * 2. 一侧存在、另一侧不存在 → 使用存在的一侧
10
+ * 3. 两侧都存在:
11
+ * a. width 更大者优先
12
+ * b. width 相同时:first 侧优先(稳定 tie-break)
13
+ * 4. merge 不无条件覆盖 cell(firstSource/secondSource 预留但当前不影响优先级)
14
+ */
15
+ import type { BorderSide, BorderSource } from './types';
16
+ /**
17
+ * 判断 BorderSide 是否有效(有实际宽度)。
18
+ */
19
+ export declare function hasBorderSide(border: BorderSide | undefined): boolean;
20
+ /**
21
+ * 判断 BorderSide 是否为空。
22
+ */
23
+ export declare function isEmptyBorderSide(border: BorderSide | undefined): boolean;
24
+ /**
25
+ * 统一解析两个相邻 BorderSide 的冲突,返回最终要绘制的 BorderSide。
26
+ *
27
+ * @param first - 第一个候选边框(对于水平公共边:上方 cell 的 bottom;对于垂直公共边:左方 cell 的 right)
28
+ * @param second - 第二个候选边框(对于水平公共边:下方 cell 的 top;对于垂直公共边:右方 cell 的 left)
29
+ * @param _firstSource - 第一个候选的来源('cell' 或 'merge'),预留参数,当前不影响优先级
30
+ * @param _secondSource - 第二个候选的来源('cell' 或 'merge'),预留参数,当前不影响优先级
31
+ * @returns 最终要绘制的 BorderSide,或 undefined(不绘制)
32
+ *
33
+ * 规则:
34
+ * 1. 两侧都空 → undefined
35
+ * 2. 一侧空 → 另一侧
36
+ * 3. 两侧都有:
37
+ * a. width 更大者优先
38
+ * b. width 相同 → first 优先(稳定 tie-break)
39
+ */
40
+ export declare function resolveSharedBorder(first: BorderSide | undefined, second: BorderSide | undefined, _firstSource?: BorderSource, _secondSource?: BorderSource): BorderSide | undefined;
41
+ /**
42
+ * 获取公共边的宽度(便捷函数)。
43
+ */
44
+ export declare function resolveSharedBorderWidth(first: BorderSide | undefined, second: BorderSide | undefined, firstSource?: BorderSource, secondSource?: BorderSource): number;
45
+ /**
46
+ * 获取公共边的颜色(便捷函数)。
47
+ */
48
+ export declare function resolveSharedBorderColor(first: BorderSide | undefined, second: BorderSide | undefined, firstSource?: BorderSource, secondSource?: BorderSource): string | undefined;
@@ -0,0 +1,84 @@
1
+ /**
2
+ * StylePool — 样式池,用于减少重复样式数据的存储体积。
3
+ *
4
+ * 核心思路:
5
+ * - 每个 Sheet 维护一个 styles: CellStyle[] 数组,styles[0] 始终为默认空样式 {}。
6
+ * - 单元格通过 styleId(数组下标)引用样式,而非内联存储完整样式对象。
7
+ * - 相同内容的样式(即使属性顺序不同)自动复用同一 styleId。
8
+ * - 已注册的样式对象禁止直接修改(Object.freeze),修改必须创建副本后重新注册。
9
+ *
10
+ * 持久化注意:
11
+ * - index(Map<string, number>)仅运行时使用,不参与序列化。
12
+ * - 序列化时只需输出 styles 数组 + cells 中的 styleId。
13
+ */
14
+ import type { CellData, CellStyle } from './types';
15
+ export declare class StylePool {
16
+ /** 样式数组:styles[0] 始终为默认空样式 {} */
17
+ private styles;
18
+ /** 运行时去重索引:stableKey → styleId,不参与持久化 */
19
+ private index;
20
+ constructor(existingStyles?: CellStyle[]);
21
+ /**
22
+ * 生成稳定的样式 key:对属性名排序后 JSON.stringify。
23
+ * 保证属性顺序不同但内容相同的样式产生相同的 key。
24
+ */
25
+ private stableKey;
26
+ /**
27
+ * 根据 styleId 获取样式对象(只读)。
28
+ * 返回 Object.freeze 冻结的对象,禁止直接修改。
29
+ */
30
+ get(styleId: number): CellStyle;
31
+ /**
32
+ * 查找或注册样式,返回对应的 styleId。
33
+ * 相同内容的样式自动复用已有 id。
34
+ */
35
+ getId(style: CellStyle): number;
36
+ /** 返回 styles 数组的浅拷贝(用于持久化/快照) */
37
+ getStyles(): CellStyle[];
38
+ /** 直接设置 styles 数组(用于恢复快照),同时重建 index */
39
+ setStyles(styles: CellStyle[]): void;
40
+ /**
41
+ * Style GC(垃圾回收):
42
+ * 扫描 cells 中实际使用的 styleId,删除未被引用的 styles,
43
+ * 重新生成连续的 styleId 并同步更新所有 cells。
44
+ * styles[0] 始终保留。
45
+ *
46
+ * 建议在保存/持久化/导出时调用,不要在每次编辑时执行。
47
+ */
48
+ compactStyles(cells: Record<string, CellData>): CellStyle[];
49
+ }
50
+ /**
51
+ * 解析单元格样式:根据 styleId 从 styles 数组中获取样式对象。
52
+ * styleId 不存在或为 0 时返回 null(表示默认样式)。
53
+ */
54
+ export declare function resolveStyle(cell: CellData | undefined, styles: CellStyle[]): CellStyle | null;
55
+ /**
56
+ * 统一的单元格样式修改:读取旧样式 → 创建副本 → 合并 patch → 注册到 StylePool → 更新 styleId。
57
+ * 不会影响其他共享相同 styleId 的单元格。
58
+ */
59
+ export declare function updateCellStyle(cell: CellData, patch: Record<string, unknown>, pool: StylePool): void;
60
+ /**
61
+ * 删除单元格的某个样式属性。
62
+ */
63
+ export declare function unsetCellStyle(cell: CellData, key: string, pool: StylePool): void;
64
+ /**
65
+ * 批量修改多个单元格的样式。
66
+ */
67
+ export declare function updateCellsStyle(cells: CellData[], patch: Record<string, unknown>, pool: StylePool): void;
68
+ /**
69
+ * 一次性迁移旧格式 cells({value, style})到新格式({value, styleId})。
70
+ * 扫描所有 cells,对 style 去重,创建 styles[],将 cell.style 转换为 cell.styleId。
71
+ * 迁移前后视觉效果和数据语义完全一致。
72
+ */
73
+ export declare function migrateCells(oldCells: Record<string, {
74
+ value: string;
75
+ style?: Record<string, unknown> | null;
76
+ styleId?: number;
77
+ }>): {
78
+ cells: Record<string, CellData>;
79
+ styles: CellStyle[];
80
+ };
81
+ /**
82
+ * 深拷贝 cells(同时保留 styleId 引用)。
83
+ */
84
+ export declare function cloneCells(src: Record<string, CellData>): Record<string, CellData>;
@@ -8,9 +8,52 @@ export interface SelectionRange {
8
8
  endCol: number;
9
9
  endRow: number;
10
10
  }
11
+ /** 单边边框 */
12
+ export interface BorderSide {
13
+ width?: number;
14
+ color?: string;
15
+ style?: string;
16
+ }
17
+ /** 四边边框组合 */
18
+ export interface BorderStyle {
19
+ top?: BorderSide;
20
+ right?: BorderSide;
21
+ bottom?: BorderSide;
22
+ left?: BorderSide;
23
+ }
24
+ /** 边框来源标识 */
25
+ export type BorderSource = 'cell' | 'merge';
26
+ /** 单元格样式:所有属性均为可选,方便后续扩展数字格式、边框、字体、填充、对齐等 */
27
+ export interface CellStyle {
28
+ fontFamily?: string;
29
+ fontSize?: number | string;
30
+ fontWeight?: string;
31
+ fontStyle?: string;
32
+ underline?: string;
33
+ strikethrough?: string;
34
+ color?: string;
35
+ backgroundColor?: string;
36
+ textAlign?: string;
37
+ verticalAlign?: string;
38
+ wrap?: string;
39
+ borderId?: number;
40
+ /** @deprecated 旧版边框属性,兼容历史数据使用,新代码请通过 borderId 访问 */
41
+ borderTopWidth?: number;
42
+ /** @deprecated 旧版边框属性,兼容历史数据使用,新代码请通过 borderId 访问 */
43
+ borderBottomWidth?: number;
44
+ /** @deprecated 旧版边框属性,兼容历史数据使用,新代码请通过 borderId 访问 */
45
+ borderLeftWidth?: number;
46
+ /** @deprecated 旧版边框属性,兼容历史数据使用,新代码请通过 borderId 访问 */
47
+ borderRightWidth?: number;
48
+ /** @deprecated 旧版边框颜色,兼容历史数据使用,新代码请通过 BorderStyle.color 访问 */
49
+ borderColor?: string;
50
+ numberFormat?: string;
51
+ [key: string]: unknown;
52
+ }
53
+ /** 单元格数据:value 始终为 string,样式通过 styleId 引用表格级 styles 池 */
11
54
  export interface CellData {
12
55
  value: string;
13
- style: Record<string, unknown> | null;
56
+ styleId?: number;
14
57
  }
15
58
  /** 搜索范围:当前工作表 / 整个工作簿 / 当前选区 */
16
59
  export type FindScope = 'sheet' | 'workbook' | 'selection';
@@ -33,14 +76,20 @@ export interface SpreadsheetOptions {
33
76
  export interface SpreadsheetData {
34
77
  [cellRef: string]: {
35
78
  value: string;
36
- style?: Record<string, unknown>;
79
+ styleId?: number;
80
+ style?: CellStyle;
37
81
  };
38
82
  }
39
83
  export interface SheetModelData {
40
84
  name: string;
85
+ /** 表格级样式池:styles[0] 始终为默认空样式 {} */
86
+ styles?: CellStyle[];
87
+ /** 表格级边框池:borders[0] 始终为默认空边框 {} */
88
+ borders?: BorderStyle[];
41
89
  cells: Record<string, {
42
90
  value: string;
43
- style?: Record<string, unknown>;
91
+ styleId?: number;
92
+ style?: CellStyle;
44
93
  }>;
45
94
  merges?: Record<string, SelectionRange>;
46
95
  colWidths?: Record<number, number>;
@@ -50,6 +99,10 @@ export interface SheetState {
50
99
  id: string;
51
100
  name: string;
52
101
  cells: Record<string, CellData>;
102
+ /** 表格级样式池:styles[0] 始终为默认空样式 {} */
103
+ styles: CellStyle[];
104
+ /** 表格级边框池:borders[0] 始终为默认空边框 {} */
105
+ borders: BorderStyle[];
53
106
  merges: Record<string, SelectionRange>;
54
107
  selection: SelectionRange | null;
55
108
  activeCell: CellCoord;
@@ -60,6 +113,8 @@ export interface SheetState {
60
113
  }
61
114
  export interface UndoSnapshot {
62
115
  cells: Record<string, CellData>;
116
+ styles: CellStyle[];
117
+ borders: BorderStyle[];
63
118
  colWidths: number[];
64
119
  rowHeights: (number | undefined)[];
65
120
  }
@@ -1,4 +1,5 @@
1
1
  import Spreader from './components/spreader.vue';
2
2
  export default Spreader;
3
3
  export { Spreader };
4
- export type { CellCoord, SelectionRange, CellData, Range, SpreadsheetOptions, SpreadsheetData, SheetModelData, SheetState, UndoSnapshot, ContextMenuItem, ThemeColors, Point, } from './core/types';
4
+ export type { CellCoord, SelectionRange, CellData, CellStyle, BorderStyle, BorderSide, BorderSource, Range, SpreadsheetOptions, SpreadsheetData, SheetModelData, SheetState, UndoSnapshot, ContextMenuItem, ThemeColors, Point, } from './core/types';
5
+ export { StylePool, resolveStyle, migrateCells, cloneCells } from './core/style-pool';
@@ -1,2 +1,2 @@
1
1
  export { default, Spreader } from './components/spreader';
2
- export type { CellCoord, SelectionRange, CellData, Range, SpreadsheetOptions, SpreadsheetData, SheetModelData, SheetState, UndoSnapshot, ContextMenuItem, ThemeColors, Point, } from './components/spreader';
2
+ export type { CellCoord, SelectionRange, CellData, CellStyle, BorderStyle, BorderSide, BorderSource, Range, SpreadsheetOptions, SpreadsheetData, SheetModelData, SheetState, UndoSnapshot, ContextMenuItem, ThemeColors, Point, } from './components/spreader';