open-grid 1.0.8 → 1.1.0

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.
Files changed (56) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/OpenGrid-5flQwc3W.js +8434 -0
  3. package/dist/OpenGrid-DahxRY7C.cjs +92 -0
  4. package/dist/open-grid-base.css +61 -0
  5. package/dist/open-grid-react.cjs +1 -1
  6. package/dist/open-grid-react.js +1 -1
  7. package/dist/open-grid-themes.css +96 -1
  8. package/dist/open-grid-vue.cjs +1 -1
  9. package/dist/open-grid-vue.js +1 -1
  10. package/dist/open-grid.cjs +1 -1
  11. package/dist/open-grid.js +2 -2
  12. package/dist/types/core/CellEditManager.d.ts +4 -0
  13. package/dist/types/core/CellEventHandler.d.ts +6 -0
  14. package/dist/types/core/ChartManager.d.ts +58 -0
  15. package/dist/types/core/DataLayer.d.ts +17 -0
  16. package/dist/types/core/DetailManager.d.ts +72 -0
  17. package/dist/types/core/FlatRowModel.d.ts +56 -0
  18. package/dist/types/core/GridRenderer.d.ts +33 -1
  19. package/dist/types/core/GroupTreeManager.d.ts +13 -0
  20. package/dist/types/core/KeyboardManager.d.ts +19 -0
  21. package/dist/types/core/OpenGrid.d.ts +109 -1
  22. package/dist/types/core/RangeSelectionManager.d.ts +95 -0
  23. package/dist/types/core/SortFilterManager.d.ts +2 -0
  24. package/dist/types/core/chart/CanvasAdapter.d.ts +52 -0
  25. package/dist/types/core/chart/DataExtractor.d.ts +49 -0
  26. package/dist/types/core/chart/a11y.d.ts +21 -0
  27. package/dist/types/core/chart/downsample.d.ts +25 -0
  28. package/dist/types/core/chart/hittest.d.ts +20 -0
  29. package/dist/types/core/chart/palette.d.ts +56 -0
  30. package/dist/types/core/chart/scales.d.ts +24 -0
  31. package/dist/types/core/chart/types.d.ts +181 -0
  32. package/dist/types/core/detail/DetailGlyph.d.ts +48 -0
  33. package/dist/types/core/detail/DetailSplice.d.ts +67 -0
  34. package/dist/types/core/detail/DetailState.d.ts +67 -0
  35. package/dist/types/core/detail/SubgridCache.d.ts +73 -0
  36. package/dist/types/core/detail/index.d.ts +14 -0
  37. package/dist/types/core/formula/FormulaEvaluator.d.ts +15 -0
  38. package/dist/types/core/formula/FormulaGraph.d.ts +43 -0
  39. package/dist/types/core/formula/FormulaParser.d.ts +6 -0
  40. package/dist/types/core/formula/FormulaStore.d.ts +17 -0
  41. package/dist/types/core/formula/RecalcCoordinator.d.ts +85 -0
  42. package/dist/types/core/formula/normalizeRefs.d.ts +15 -0
  43. package/dist/types/core/formula/numericLiteral.d.ts +7 -0
  44. package/dist/types/core/formula/serializeFormula.d.ts +6 -0
  45. package/dist/types/core/formula/types.d.ts +104 -0
  46. package/dist/types/core/range/ClipboardCodec.d.ts +30 -0
  47. package/dist/types/core/range/FillEngine.d.ts +63 -0
  48. package/dist/types/core/range/RangeModel.d.ts +53 -0
  49. package/dist/types/core/range/RangeQuery.d.ts +16 -0
  50. package/dist/types/core/range/types.d.ts +47 -0
  51. package/dist/types/core/renderers/CellRenderer.d.ts +2 -0
  52. package/dist/types/core/types.d.ts +242 -0
  53. package/dist/types/index.d.ts +2 -1
  54. package/package.json +1 -1
  55. package/dist/OpenGrid-CZRcxruq.cjs +0 -90
  56. package/dist/OpenGrid-Cjv7Os5a.js +0 -4871
@@ -0,0 +1,6 @@
1
+ import { AstNode, FormulaGridAccessor } from './types.js';
2
+ /** 정규화 AST를 다시 "=..." 형태의 A1 원문으로 직렬화한다(offsetFormula 결과물 조립용). */
3
+ export declare function astToSource(ast: AstNode, host: {
4
+ rowId: string;
5
+ field: string;
6
+ }, accessor: FormulaGridAccessor): string;
@@ -0,0 +1,104 @@
1
+ import { OGDecimal } from '../OGDecimal.js';
2
+ export type CellKey = string;
3
+ export declare function cellKey(rowId: string, field: string): CellKey;
4
+ export declare function parseCellKey(key: CellKey): {
5
+ rowId: string;
6
+ field: string;
7
+ };
8
+ export type FormulaErrorCode = '#ERR' | '#REF' | '#CYCLE' | '#DIV0' | '#NAME' | '#VALUE' | '#NUM';
9
+ export declare const FORMULA_ERROR_CODES: ReadonlySet<string>;
10
+ /** 값이 이미 다른 수식의 에러 결과(문자열)인지 판별 — 에러 전파(§6 EVANS/DEMARCO 규칙)용. */
11
+ export declare function isErrorToken(v: unknown): FormulaErrorCode | null;
12
+ export type CellValue = OGDecimal | string | boolean | null;
13
+ export type RefMode = 'stable' | 'relative';
14
+ export interface CanonicalAbsRef {
15
+ kind: 'abs';
16
+ rowId: string;
17
+ field: string;
18
+ dollarRow: boolean;
19
+ dollarCol: boolean;
20
+ }
21
+ export interface CanonicalRelRef {
22
+ kind: 'rel';
23
+ dRow: number;
24
+ field: string;
25
+ dollarRow: boolean;
26
+ dollarCol: boolean;
27
+ }
28
+ export type CanonicalRef = CanonicalAbsRef | CanonicalRelRef;
29
+ export interface CanonicalRangeRef {
30
+ a: CanonicalRef;
31
+ b: CanonicalRef;
32
+ }
33
+ export interface RawCellRefNode {
34
+ t: 'rawRef';
35
+ colLetters: string;
36
+ row: number;
37
+ dollarCol: boolean;
38
+ dollarRow: boolean;
39
+ }
40
+ export interface RawRangeRefNode {
41
+ t: 'rawRange';
42
+ a: RawCellRefNode;
43
+ b: RawCellRefNode;
44
+ }
45
+ export type BinOp = '+' | '-' | '*' | '/' | '%' | '^' | '&' | '=' | '<>' | '<' | '<=' | '>' | '>=';
46
+ export type AstNode = {
47
+ t: 'num';
48
+ v: string;
49
+ } | {
50
+ t: 'str';
51
+ v: string;
52
+ } | {
53
+ t: 'bool';
54
+ v: boolean;
55
+ } | {
56
+ t: 'field';
57
+ field: string;
58
+ } | RawCellRefNode | RawRangeRefNode | {
59
+ t: 'ref';
60
+ ref: CanonicalRef;
61
+ } | {
62
+ t: 'range';
63
+ ref: CanonicalRangeRef;
64
+ } | {
65
+ t: 'error';
66
+ code: FormulaErrorCode;
67
+ } | {
68
+ t: 'call';
69
+ name: string;
70
+ args: AstNode[];
71
+ } | {
72
+ t: 'unary';
73
+ op: '+' | '-';
74
+ arg: AstNode;
75
+ } | {
76
+ t: 'bin';
77
+ op: BinOp;
78
+ left: AstNode;
79
+ right: AstNode;
80
+ };
81
+ export interface FormulaCell {
82
+ src: string;
83
+ ast: AstNode;
84
+ hasRangeRef: boolean;
85
+ value: CellValue;
86
+ error: FormulaErrorCode | null;
87
+ approx?: boolean;
88
+ }
89
+ export interface FormulaGridAccessor {
90
+ /** A1 열문자 매핑 기준 — visibleLeaves(숨김 제외) 순서의 field 배열(§3.1/C1). */
91
+ visibleFields(): string[];
92
+ /** flat index(0-based) → rowId. kind!=='data' 이거나 범위 밖이면 null(§C0.3). */
93
+ rowIdAtFlat(flatIndex: number): string | null;
94
+ /** rowId → 현재 flat index(0-based). 없음/필터아웃/접힘이면 -1. */
95
+ flatIndexOfRowId(rowId: string): number;
96
+ /** 현재 표시(필터 통과) 순서의 rowId 배열 — 범위 evaluate-time 멤버십 해소용(§3.5). */
97
+ displayedRowIds(): string[];
98
+ /** (rowId, field) 셀의 원시 값(비수식, 이미 계산된 값 포함) 조회. */
99
+ getCellValue(rowId: string, field: string): unknown;
100
+ /** rowId 존재 여부(행 삭제 감지, F3-R28). */
101
+ hasRow(rowId: string): boolean;
102
+ /** field 존재 여부(열 삭제 감지, F3-R28). */
103
+ hasField(field: string): boolean;
104
+ }
@@ -0,0 +1,30 @@
1
+ import { CellRange, FlatRowRefLike } from './types.js';
2
+ export interface ClipboardQueryContext {
3
+ fieldAt(ci: number): string | undefined;
4
+ getCellValue(ri: number, field: string): any;
5
+ /** override 데모 정합: 있으면 표시값 우선(§5.1 주석) */
6
+ getDisplayText?(ri: number, field: string): string;
7
+ }
8
+ /** R행×C열 범위 → TSV(행마다 \t조인, 행간 \n) — 엑셀 왕복 호환(UR-4 AC). */
9
+ export declare function rangeToTSV(rect: CellRange, ctx: ClipboardQueryContext): string;
10
+ /** TSV 문자열 → 2D 블록(행×열 문자열 배열). 빈 문자열은 1×1 빈 블록. */
11
+ export declare function parseTSV(text: string): string[][];
12
+ export interface PastePlanContext {
13
+ resolveFlatRow(ri: number): FlatRowRefLike;
14
+ fieldAt(ci: number): string | undefined;
15
+ /** 기본 true(잠금 없음) */
16
+ isEditable?(rowId: string, field: string): boolean;
17
+ }
18
+ export interface PastePlanItem {
19
+ rowIndex: number;
20
+ field: string;
21
+ action: 'value' | 'skip';
22
+ value?: any;
23
+ reason?: string;
24
+ }
25
+ /**
26
+ * 붙여넣기 소스 블록(2D) + 타깃 range → 플랜.
27
+ * 소스가 타깃보다 작으면 타일 반복, 크면(또는 같으면) 블록 그대로 전개(타깃 크기 무시) — 엑셀 규칙(FR-4 AC).
28
+ * `r % blockRows`/`c % blockCols` 단일 공식으로 두 경우 모두 성립(작을 때=주기 반복, 클 때=outRows=blockRows라 항상 r 자신).
29
+ */
30
+ export declare function buildPastePlan(block: string[][], target: CellRange, ctx: PastePlanContext): PastePlanItem[];
@@ -0,0 +1,63 @@
1
+ import { OGDecimal } from '../OGDecimal.js';
2
+ import { CellRange, FillAxis, FillMode, FlatRowRefLike } from './types.js';
3
+ export interface DetectSeriesResult {
4
+ kind: 'copy' | 'arith' | 'text-suffix';
5
+ /** 자연순서(위→아래 / 왼→오) diff. arith/text-suffix에만 존재 */
6
+ step?: OGDecimal;
7
+ /** 자연순서로 파싱된 수치값(arith) 또는 접미 숫자부(text-suffix) */
8
+ values?: OGDecimal[];
9
+ /** text-suffix의 공통 접두문자열 */
10
+ prefix?: string;
11
+ }
12
+ /**
13
+ * 소스 라인(주축과 직교하는 한 행 또는 한 열의 값 배열, 자연순서=위→아래/왼→오) → 감지 결과.
14
+ * 경계 AC(REQ-24): [1,2,4]→copy, [5]→copy, ["a","b"]→copy, ["Q1","Q2"]→arith 아님 text-suffix(step=1).
15
+ */
16
+ export declare function detectSeries(sourceLine: any[]): DetectSeriesResult;
17
+ /**
18
+ * 감지 결과 + 자연순서 소스라인으로 target 거리 d(1..N, 소스에 가장 가까운 셀=1)의 값을 외삽.
19
+ * 방향 부호(§3.4.1 "위/왼쪽 채우면 step 부호 반전")는 axis에 따라 base/부호를 선택해 처리한다.
20
+ */
21
+ export declare function extrapolateValue(result: DetectSeriesResult, sourceLine: any[], axis: FillAxis, d: number): any;
22
+ export interface FillPlanItem {
23
+ rowIndex: number;
24
+ field: string;
25
+ action: 'value' | 'setFormula' | 'skip';
26
+ value?: any;
27
+ formula?: string;
28
+ reason?: string;
29
+ }
30
+ export interface FillPlanResult {
31
+ items: FillPlanItem[];
32
+ /** C3.2 보존된 수식 셀 수(announce용) */
33
+ skippedFormula: number;
34
+ }
35
+ export interface FillPlanContext {
36
+ resolveFlatRow(ri: number): FlatRowRefLike;
37
+ fieldAt(ci: number): string | undefined;
38
+ getCellValue(ri: number, field: string): any;
39
+ /** 기본 true(잠금 없음) */
40
+ isEditable?(rowId: string, field: string): boolean;
41
+ /** 기본 false(수식 없음) */
42
+ hasCellFormula?(rowId: string, field: string): boolean;
43
+ /** C3.1: 상대 ref 오프셋 수식 생성(F3 제공) */
44
+ offsetFormula?(rowId: string, field: string, dRow: number, dCol: number): string;
45
+ /** rangeSelection.fillOverwriteFormula(C3.2 opt-in) */
46
+ overwriteFormula?: boolean;
47
+ /** Ctrl-강제-copy: 수식 원문 복제(오프셋 없음) */
48
+ forceCopyFormula?: boolean;
49
+ }
50
+ /**
51
+ * 소스 rect → 타깃 rect 채우기 플랜(§3.5). 주축과 직교하는 각 라인(행 또는 열) 별로 독립 처리(§3.4.1).
52
+ * non-data 행(kind!=='data')은 항상 skip(C0.3/CON-5). mode==='series'가 detectSeries로 'copy'에
53
+ * 귀결되면(경계 케이스) 그대로 copy 타일 반복으로 처리된다(설계가 의도한 동작).
54
+ */
55
+ export declare function buildFillPlan(source: CellRange, target: CellRange, axis: FillAxis, mode: FillMode, ctx: FillPlanContext): FillPlanResult;
56
+ /**
57
+ * 현재 선택 rect에서 Ctrl+D(아래로)/Ctrl+R(오른쪽으로) 채우기의 source/target rect 산출(순수 함수).
58
+ * 1행(D)/1열(R)뿐이면 채울 대상이 없어 null.
59
+ */
60
+ export declare function ctrlFillSourceTarget(rect: CellRange, axis: 'down' | 'right'): {
61
+ source: CellRange;
62
+ target: CellRange;
63
+ } | null;
@@ -0,0 +1,53 @@
1
+ import { CellCoord, CellRange, Direction, RangeIdentity, RangeModelHost } from './types.js';
2
+ /** anchor/focus → 정규화된 CellRange(§2.3). 역방향 드래그(anchor>focus)도 min/max로 정규화. */
3
+ export declare function normalize(a: CellCoord, f: CellCoord): CellRange;
4
+ export declare class RangeModel {
5
+ private _host;
6
+ private _anchor;
7
+ private _focus;
8
+ private _identity;
9
+ private _rects;
10
+ private _hasSelection;
11
+ private _additive;
12
+ constructor(host: RangeModelHost);
13
+ get hasSelection(): boolean;
14
+ getAnchor(): CellCoord;
15
+ getFocus(): CellCoord;
16
+ getIdentity(): RangeIdentity;
17
+ /** 공개 API 재료(C4): 정규화 rects (없으면 []). MVP는 길이 ≤1. */
18
+ getRangeSelection(): CellRange[];
19
+ /** 공개 API 재료(C4): getRangeSelection()[0] ?? null */
20
+ getActiveRange(): CellRange | null;
21
+ /** 복사/채우기 소스 결정용 별칭(§5.1 getPrimaryRect) */
22
+ getPrimaryRect(): CellRange | null;
23
+ /** 정렬/필터 후에도 유지되는 실제 rowId 집합의 현재 flat 위치(오름차순, 화면밖=-1 제외). */
24
+ getProjectedFlatRows(): number[];
25
+ /** pointerdown. shift=true면 기존 anchor 유지(있을 때만), 아니면 새 1x1 anchor. */
26
+ beginDrag(ri: number, ci: number, opts?: {
27
+ additive?: boolean;
28
+ shift?: boolean;
29
+ }): void;
30
+ /** pointermove. */
31
+ updateFocus(ri: number, ci: number): void;
32
+ /** pointerup — 확정 + 정체성 스냅샷(§2.5). */
33
+ endDrag(): void;
34
+ get additive(): boolean;
35
+ /** 클릭(비-Shift): 새 1×1 anchor(FR-1). */
36
+ click(ri: number, ci: number): void;
37
+ /** Shift+클릭: anchor 유지, focus만 갱신. anchor 없으면 click으로 위임(UC-2 예외). */
38
+ shiftClickExtend(ri: number, ci: number): void;
39
+ /** anchor 고정, focus만 1칸 이동(격자 경계 clamp). 편집 우선순위(C9)는 호출측(KeyboardManager)이 가드. */
40
+ extendFocus(dir: Direction): void;
41
+ setRect(rect: CellRange): void;
42
+ /** clearRangeSelection API 재료. */
43
+ clear(): void;
44
+ /** 현재 rect를 rowId 집합 × field 집합으로 스냅샷(display-index는 렌더용 투영일 뿐). */
45
+ snapshotIdentity(): void;
46
+ /**
47
+ * 정렬/필터 후 호출(onModelReproject 구독 지점). rowId 집합 → 현재 flat 좌표로 재투영.
48
+ * 사라진 행(flatIndexOfRowId === -1)은 정체성에는 남되 투영(rects)에서는 제외된다(불연속 허용).
49
+ * MVP는 단일 bounding rect로 투영(§2.2 rects 길이 1 방침) — 남아있는 행들의 min/max로 계산.
50
+ */
51
+ reproject(): void;
52
+ private _recompute;
53
+ }
@@ -0,0 +1,16 @@
1
+ import { CellRange } from './types.js';
2
+ export interface RangeQueryContext {
3
+ fieldAt(ci: number): string | undefined;
4
+ getCellValue(ri: number, field: string): any;
5
+ }
6
+ /** rect 값 2D 배열(FR-6). */
7
+ export declare function getRangeValues(rect: CellRange, ctx: RangeQueryContext): any[][];
8
+ export interface RangeStats {
9
+ sum: string;
10
+ avg: string;
11
+ count: number;
12
+ min: string;
13
+ max: string;
14
+ }
15
+ /** 숫자 셀에 대해 OGDecimal 기반 sum/avg/count/min/max(FR-6). 숫자 셀이 없으면 null. */
16
+ export declare function getRangeStats(rect: CellRange, ctx: RangeQueryContext): RangeStats | null;
@@ -0,0 +1,47 @@
1
+ import { CellRange } from '../types.js';
2
+ export type { CellRange };
3
+ /** 방향성 원시 좌표. ri=flat/visual index(C0.2), ci=visibleLeaves index(C0.4). */
4
+ export interface CellCoord {
5
+ ri: number;
6
+ ci: number;
7
+ }
8
+ export type Direction = 'up' | 'down' | 'left' | 'right';
9
+ export type FillAxis = Direction;
10
+ export type FillMode = 'copy' | 'series';
11
+ /** 범위 정체성(C0.5) — display-index가 아니라 stable 집합으로 저장. */
12
+ export interface RangeIdentity {
13
+ /** 선택된 data 행의 stable _ogRowId 집합 (정렬/필터를 넘어 보존) */
14
+ rowIds: string[];
15
+ /** 선택된 열의 field 집합 (visibleLeaves.field) */
16
+ fields: string[];
17
+ }
18
+ /** FlatRowModel.resolveFlatRow가 반환하는 참조(C0.3). */
19
+ export interface FlatRowRefLike {
20
+ kind: 'data' | 'group' | 'tree' | 'detailHead' | 'detailFiller';
21
+ rowId?: string;
22
+ dataIndex?: number;
23
+ displayIndex?: number;
24
+ }
25
+ /**
26
+ * F1이 좌표 해소·재투영을 위해 필요로 하는 최소 계약 모양(C0.3 FlatRowModel + visibleLeaves).
27
+ * 실제 구현(baseline FlatRowModel/ColumnLayout)은 이 형태를 만족하는 어댑터를 배선 단계에서 주입한다.
28
+ */
29
+ export interface RangeModelHost {
30
+ /** flat/visual 행 총수 */
31
+ count(): number;
32
+ /** flat index → 참조(kind/rowId 등). 없으면 kind 판별 불가 상태를 반환해야 함(C0.3) */
33
+ resolveFlatRow(flatIndex: number): FlatRowRefLike;
34
+ /** stable rowId → 현재 flat index. 없으면(접힘/필터아웃) -1 */
35
+ flatIndexOfRowId(rowId: string): number;
36
+ /** flat index → stable rowId (data/tree만, 그 외 null) */
37
+ rowIdOfFlat(flatIndex: number): string | null;
38
+ /** 현재 visibleLeaves의 field 목록(순서=ci) */
39
+ visibleFields(): string[];
40
+ }
41
+ /** 채우기 프리뷰(핸들 드래그 중) — 커밋 전 임시 상태 자료(§2.2 FillPreview). */
42
+ export interface FillPreview {
43
+ source: CellRange;
44
+ target: CellRange;
45
+ axis: FillAxis;
46
+ mode: FillMode;
47
+ }
@@ -8,6 +8,8 @@ export interface RenderContext<T = any> {
8
8
  isSelected: boolean;
9
9
  rowState: 'none' | 'added' | 'edited' | 'removed';
10
10
  displayValue?: string | null;
11
+ /** C7(15_cross_contracts.md/F3-R14): 이 셀에 F3 셀 수식이 있으면 true — ColumnDef.formula 재평가를 skip. */
12
+ hasCellFormula?: boolean;
11
13
  }
12
14
  export interface CellRenderer {
13
15
  render(ctx: RenderContext): HTMLElement;
@@ -1,3 +1,5 @@
1
+ import { FormulaErrorCode } from './formula/types.js';
2
+ import { RangeStats as _RangeStats } from './range/RangeQuery.js';
1
3
  export type DataType = 'string' | 'number' | 'date' | 'boolean' | 'select' | 'radio' | 'img' | 'html' | 'barcode';
2
4
  export type { MaskType, MaskDef } from './MaskingEngine.js';
3
5
  export type SelectionMode = 'single' | 'row' | 'multiple' | 'cells';
@@ -103,12 +105,144 @@ export interface SelectionEvent<T = any> {
103
105
  rowIndexes: number[];
104
106
  cells?: CellRange[];
105
107
  }
108
+ /**
109
+ * CellRangeSemantics — CellRange 의미 규범(C0.4, 15_cross_contracts.md). 소유자 = F1(범위 선택).
110
+ * F3(수식 ref)·F4(차트 소스)는 이 의미로만 CellRange 를 소비한다.
111
+ * - startRow/endRow : flat/visual index (C0.2 — FlatRowModel 이 다루는 화면 표시 순서).
112
+ * group/tree pseudo-row, (F2 도입 후) detail head/filler 도 포함한 인덱스 공간이며,
113
+ * display index(정렬/필터만 반영, group/tree 제외)와 다르다.
114
+ * - startCol/endCol : `ColumnLayout.visibleLeaves` 인덱스(숨김 컬럼 제외). 숨김 컬럼은
115
+ * 좌표를 흔들지 않되, 언하이드 시 재렌더로 좌표 표시(A1 등)가 갱신된다.
116
+ * - 선택 자체의 영속 정체성은 이 인덱스가 아니라 stable (rowId × field) 앵커로 저장한다
117
+ * (C0.5) — CellRange 는 어디까지나 "현재 화면에 투영된" 사각형 표현이다.
118
+ */
106
119
  export interface CellRange {
107
120
  startRow: number;
108
121
  endRow: number;
109
122
  startCol: number;
110
123
  endCol: number;
111
124
  }
125
+ export interface RangeSelectionOptions {
126
+ /** 기본 selection==='cells' 와 동치 */
127
+ enabled?: boolean;
128
+ /** 기본 true — 핸들 표시/드래그 */
129
+ fillHandle?: boolean;
130
+ /** 기본 false — Ctrl 멀티 rect(Full, 미구현) */
131
+ multiRange?: boolean;
132
+ /** 기본 24(px) — autoscroll 밴드 폭 */
133
+ autoScrollEdge?: number;
134
+ /** 기본 true — false 면 항상 copy(시리즈 감지 비활성) */
135
+ seriesFill?: boolean;
136
+ /** 기본 false — 그룹/트리 모드 범위선택(MVP 비활성) */
137
+ enabledInTreeGroup?: boolean;
138
+ /** 기본 false — 수식 대상 덮어쓰기(C3.2 opt-in) */
139
+ fillOverwriteFormula?: boolean;
140
+ }
141
+ export interface RangeFillEvent {
142
+ source: CellRange;
143
+ target: CellRange;
144
+ mode: 'copy' | 'series';
145
+ written: Array<{
146
+ rowIndex: number;
147
+ field: string;
148
+ oldValue: any;
149
+ newValue: any;
150
+ }>;
151
+ skippedFormula?: number;
152
+ /** before 훅에서 true 로 바꾸면 채우기 취소(현재 배선은 이벤트 emit 뒤 즉시 확인) */
153
+ cancel?: boolean;
154
+ }
155
+ export interface RangeCopyEvent {
156
+ range: CellRange;
157
+ text: string;
158
+ }
159
+ export interface RangeChangeEvent {
160
+ range: CellRange | null;
161
+ }
162
+ export type { FormulaErrorCode } from './formula/types.js';
163
+ /** F3 옵션(C5.1 단일 중첩 — 최상위 flat 키 금지). */
164
+ export interface FormulaOptions {
165
+ /** 셀 수식 인-셀 '=' 편집 자동 인식 on(기본 false — 회귀 0). setCellFormula API 는 이 값과 무관하게 항상 동작. */
166
+ enabled?: boolean;
167
+ /** 참조 정규화 정책(기본 'stable', §3.2). */
168
+ refMode?: 'stable' | 'relative';
169
+ /** 나눗셈 소수 자리(기본 30, FormulaEngine 계승). */
170
+ divisionPrecision?: number;
171
+ /** 수식 바 표시(P1, 기본 false — 미구현). */
172
+ formulaBar?: boolean;
173
+ /** 수식 셀 마커(기본 true — HANMS-09/R-FORMULA-MARKER). */
174
+ cellMarker?: boolean;
175
+ /** 편집 시 자동 재계산(기본 true). */
176
+ autoRecalc?: boolean;
177
+ onFormulaChange?: (e: FormulaChangeEvent) => void;
178
+ onFormulaRecalc?: (e: FormulaRecalcEvent) => void;
179
+ onFormulaError?: (e: FormulaErrorEvent) => void;
180
+ }
181
+ export interface FormulaChangeEvent {
182
+ rowIndex: number;
183
+ field: string;
184
+ formula: string;
185
+ oldFormula: string | null;
186
+ }
187
+ export interface FormulaRecalcEvent {
188
+ changed: string[];
189
+ cycles: number;
190
+ ms: number;
191
+ /** Spike-A §8 교훈: 폐포가 임계(500) 초과 시 true(가이드 문서화/모니터링용). */
192
+ large: boolean;
193
+ }
194
+ export interface FormulaErrorEvent {
195
+ rowIndex: number;
196
+ field: string;
197
+ error: FormulaErrorCode;
198
+ }
199
+ export type { RangeStats } from './range/RangeQuery.js';
200
+ /** masterDetail.renderer 3번째 인자(§6.1). */
201
+ export interface DetailRenderApi<T = any> {
202
+ grid: OpenGridInstance<T>;
203
+ rowId: string;
204
+ /** 현재 그리드의 중첩 깊이(CON-4). 0 = 최상위. */
205
+ depth: number;
206
+ collapse: () => void;
207
+ /** 패널 재측정(Phase2 auto 대비 자리 — MVP 는 no-op 에 가까움). */
208
+ refresh: () => void;
209
+ }
210
+ /** F2 옵션(C5.1 단일 중첩 — 구 flat `detail*`/`masterDetail:boolean` 은 이 안으로 접힘). */
211
+ export interface MasterDetailOptions<T = any> {
212
+ /** 기능 on/off. 기본 false. */
213
+ enabled?: boolean;
214
+ /** 임의 HTML/컴포넌트를 host 에 주입(§5). subgridOptions 와 동시 지정 시 이 쪽이 우선. */
215
+ renderer?: (row: T, host: HTMLElement, api: DetailRenderApi<T>) => void | HTMLElement;
216
+ /** 패널 높이(px). 기본 200. MVP 는 rowHeight 배수로 양자화(EC-10). */
217
+ height?: number;
218
+ /**
219
+ * 'fixed'(기본)만 MVP 에서 동작. 'auto' 는 Spike-B(C12.2) 통과 전 미공개 — 지정해도
220
+ * DetailManager 가 'fixed' 로 무시 처리하고 1회 console.warn 한다.
221
+ */
222
+ heightMode?: 'fixed' | 'auto';
223
+ /** 기본 true. false = 아코디언(펼침 1개만 허용). */
224
+ expandMultiple?: boolean;
225
+ /** 기본 false. true 면 collapse 해도 host/instance 캐시를 유지(재펼침 시 재생성 생략). */
226
+ cache?: boolean;
227
+ /** 어포던스 위치. 기본 'expander-col'(전용 컬럼). */
228
+ toggle?: 'expander-col' | 'first-cell';
229
+ /** 패널 role=region 의 aria-label. 기본 '상세 내용'. */
230
+ ariaLabel?: string;
231
+ /** 중첩 깊이 한계(CON-4/FR-10). 기본 2. */
232
+ maxDepth?: number;
233
+ /** 지정 시 height 대신 이 값을 슬롯수(정수, 최소 1)로 직접 사용. */
234
+ detailRowCount?: number;
235
+ /** renderer 미지정 시: 자식 OpenGrid 를 이 옵션으로 자동 생성(§5 ②). */
236
+ subgridOptions?: GridOptions<any>;
237
+ }
238
+ /** rowExpand/rowCollapse payload(C5.2, §6.3). */
239
+ export interface RowExpandEvent<T = any> {
240
+ /** flat/visual index(C0.2). */
241
+ rowIndex: number;
242
+ rowId: string;
243
+ row: T;
244
+ host: HTMLElement | null;
245
+ }
112
246
  export interface RendererDef {
113
247
  type: RendererType;
114
248
  [key: string]: any;
@@ -281,12 +415,31 @@ export interface GridOptions<T = any> {
281
415
  autoHeight?: boolean;
282
416
  fillWidth?: boolean;
283
417
  defaultColumnWidth?: number;
418
+ /**
419
+ * 뷰포트 안전장치(옵트인, 기본 undefined = OFF = 기존 동작 완전 불변).
420
+ * 호스트가 그리드 컨테이너 조상 체인에 확정 높이(definite height)를 주지 않으면
421
+ * 내부 스페이서(totalRows×rowHeight)가 컨테이너를 전체 콘텐츠 크기로 부풀리고,
422
+ * ResizeObserver 되먹임으로 windowing 이 무력화되어 전 행이 DOM 렌더되는 폭주가 발생한다
423
+ * (대량 데이터일수록 재앙적). 이 값을 지정하면, 컨테이너가 전 콘텐츠를 다 담는 "언바운드"
424
+ * 상태로 감지될 때에 한해 윈도잉 뷰포트 높이를 이 값(px)으로 클램프해 폭주를 차단한다.
425
+ * 정상적으로 확정 높이가 있는 바운드 컨테이너에는 영향이 없다.
426
+ * 1순위 권장은 컨테이너/그리드에 확정 height 를 주는 것이며, 이 옵션은 안전망이다.
427
+ */
428
+ fallbackViewportHeight?: number;
284
429
  editable?: boolean;
285
430
  editMode?: 'click' | 'dblclick' | 'none';
286
431
  history?: boolean;
287
432
  historySize?: number;
288
433
  selection?: SelectionMode;
289
434
  clipboard?: boolean;
435
+ /** F1: 범위 선택 + 채우기 핸들(C5.1 단일 중첩 — 최상위 flat 키 금지). */
436
+ rangeSelection?: RangeSelectionOptions;
437
+ /** F3: 셀 수식(C5.1 단일 중첩). */
438
+ formula?: FormulaOptions;
439
+ /** F2: 마스터/디테일(C5.1 단일 중첩). */
440
+ masterDetail?: MasterDetailOptions<T>;
441
+ /** F4: 그리드 데이터 통합 차트(C5.1 단일 중첩). 타입은 chart/types 순환-안전 type-only import. */
442
+ chart?: import('./chart/types.js').ChartGlobalOptions;
290
443
  sortable?: boolean;
291
444
  multiSort?: boolean;
292
445
  filterable?: boolean;
@@ -334,6 +487,15 @@ export interface GridOptions<T = any> {
334
487
  onEditBefore?: (e: EditEvent<T>) => boolean;
335
488
  onRowClick?: (e: RowEvent<T>) => void;
336
489
  onSelectionChange?: (e: SelectionEvent<T>) => void;
490
+ /** F1: 범위 rects 변경 시(C4, F4 라이브 소비) */
491
+ onRangeChange?: (e: RangeChangeEvent) => void;
492
+ /** F1: 채우기 커밋 결과(§6.3) */
493
+ onRangeFill?: (e: RangeFillEvent) => void;
494
+ /** F1: 범위 복사 시(§6.3) */
495
+ onRangeCopy?: (e: RangeCopyEvent) => void;
496
+ /** F2: 행 상세 패널 펼침/접힘 시(C5.1 on* 버킷). */
497
+ onRowExpand?: (e: RowExpandEvent<T>) => void;
498
+ onRowCollapse?: (e: RowExpandEvent<T>) => void;
337
499
  onSortChange?: (e: SortEvent) => void;
338
500
  onFilterChange?: (e: FilterEvent) => void;
339
501
  onScroll?: (e: ScrollEvent) => void;
@@ -393,6 +555,11 @@ export type CellSerializerFn = (value: any, col: any, row: any) => any;
393
555
  export type GroupKeyFn = (row: any, remainingFields: string[]) => any;
394
556
  /** 집계 연산. null 반환 시 기본 SUM/AVG/COUNT/MAX/MIN 분기로 폴백. */
395
557
  export type SummaryOpFn = (op: string, nums: any[], field: string) => number | null;
558
+ /**
559
+ * F1 채우기 시리즈 커스텀 리졸버 슬롯(C5.3, 예약). 사용자가 날짜/커스텀 시리즈를 주입할 수 있다.
560
+ * ⚠️ 슬롯 등록 경로만 확보되어 있으며, RangeSelectionManager/FillEngine 소비 배선은 F1-b(Full) 대상.
561
+ */
562
+ export type FillSeriesResolverFn = (sourceLine: any[], k: number, axisSign: 1 | -1) => any;
396
563
  /** 슬롯명 → 시그니처 매핑. */
397
564
  export interface StrategyMap {
398
565
  sortComparator: SortComparatorFn;
@@ -401,6 +568,7 @@ export interface StrategyMap {
401
568
  cellSerializer: CellSerializerFn;
402
569
  groupKeyFn: GroupKeyFn;
403
570
  summaryOp: SummaryOpFn;
571
+ fillSeriesResolver: FillSeriesResolverFn;
404
572
  }
405
573
  /** 호출가능 + .strategy 멤버를 가진 하이브리드 override API. */
406
574
  export interface OverrideApi<T = any> {
@@ -439,6 +607,21 @@ export interface OpenGridInstance<T = any> {
439
607
  getDisplayValue(rowIndex: number, field: string): string;
440
608
  writeCell(rowIndex: number, field: string, value: any): void;
441
609
  getRowAt(rowIndex: number): T;
610
+ /** flat/visual index ↔ data 리졸버. F1/F3/F4 는 이 모델을 경유해 대상을 해소한다. */
611
+ getFlatRowModel(): import('./FlatRowModel.js').FlatRowModel;
612
+ /** 배치 쓰기 시작 — 이후 writeCell 들의 render/dataChange 를 지연·coalesce(reentrant). */
613
+ beginBatch(): void;
614
+ /** 배치 종료 — 배치 중 쓰기가 있었으면 1회 render + 1회 coalesced dataChange. */
615
+ endBatch(): void;
616
+ /**
617
+ * beginBatch+루프+endBatch 래퍼. rowIndex 는 flat index — kind!=='data' 대상(group/tree/
618
+ * detail 의사행)은 쓰기 전에 skip 한다(C0.3 쓰기 안전). 반환값 = 건너뛴 셀 수.
619
+ */
620
+ writeCells(patches: Array<{
621
+ rowIndex: number;
622
+ field: string;
623
+ value: any;
624
+ }>): number;
442
625
  getChanges(): {
443
626
  added: T[];
444
627
  edited: T[];
@@ -480,6 +663,64 @@ export interface OpenGridInstance<T = any> {
480
663
  getActiveRow(): number;
481
664
  activate(index: number): void;
482
665
  deselect(): void;
666
+ /** 정규화 rects(없으면 []). MVP 는 길이 ≤1. */
667
+ getRangeSelection(): CellRange[];
668
+ /** = getRangeSelection()[0] ?? null(C4, F4 소비). */
669
+ getActiveRange(): CellRange | null;
670
+ setRangeSelection(range: CellRange | CellRange[]): void;
671
+ clearRangeSelection(): void;
672
+ /** 현재 활성 범위의 값 2D 배열(FR-6, F4 필수 계약). */
673
+ getRangeValues(): any[][];
674
+ /** 현재 활성 범위 숫자 셀의 OGDecimal 기반 통계(FR-6, F4 필수 계약). */
675
+ getRangeStats(): _RangeStats | null;
676
+ /** source→target 채우기(배치 경유, C2). axis 는 두 rect 상대 위치로 추론. */
677
+ fillRange(source: CellRange, target: CellRange, mode?: 'copy' | 'series'): void;
678
+ createChart(config: import('./chart/types.js').ChartConfig): import('./chart/types.js').ChartInstance;
679
+ getCharts(): import('./chart/types.js').ChartInstance[];
680
+ destroyCharts(): void;
681
+ /** "=A1+B2" 형태. rowIndex 는 flat(C0), 내부 즉시 stable rowId 로 정규화. */
682
+ setCellFormula(rowIndex: number, field: string, formula: string): void;
683
+ getCellFormula(rowIndex: number, field: string): string | null;
684
+ hasCellFormula(rowIndex: number, field: string): boolean;
685
+ /** 수식 제거(값은 유지). */
686
+ clearCellFormula(rowIndex: number, field: string): void;
687
+ getCellError(rowIndex: number, field: string): FormulaErrorCode | null;
688
+ /** 디버깅용 — 이 셀을 참조하는(종속) 셀들. */
689
+ getDependents(rowIndex: number, field: string): Array<{
690
+ rowIndex: number;
691
+ field: string;
692
+ }>;
693
+ /** 디버깅용 — 이 셀이 참조하는(선행) 셀들. */
694
+ getPrecedents(rowIndex: number, field: string): Array<{
695
+ rowIndex: number;
696
+ field: string;
697
+ }>;
698
+ /** 전체 수식 위상 재계산(setData/컬럼 변경 등). */
699
+ recalculate(): void;
700
+ /** 단일 셀 + 종속 폐포만 재계산. */
701
+ recalculateCell(rowIndex: number, field: string): void;
702
+ /** C3(F1 fill 전용): srcRowId/srcField 수식의 상대축만 dRow/dCol 오프셋한 새 수식 원문. */
703
+ offsetFormula(srcRowId: string, srcField: string, dRow: number, dCol: number): string;
704
+ /** rowRef 는 flat/visual index(C0.2) 또는 stable id. maxDepth 초과 시 거부(announce, FR-10). */
705
+ expandRow(rowRef: number | {
706
+ id: string;
707
+ }): void;
708
+ collapseRow(rowRef: number | {
709
+ id: string;
710
+ }): void;
711
+ toggleRow(rowRef: number | {
712
+ id: string;
713
+ }): void;
714
+ isRowExpanded(rowRef: number | {
715
+ id: string;
716
+ }): boolean;
717
+ collapseAllDetails(): void;
718
+ /** 펼쳐진 적 없으면 undefined. renderer 반환값 또는 자동 생성 서브그리드 인스턴스. */
719
+ getDetailInstance<D = any>(rowRef: number | {
720
+ id: string;
721
+ }): D | undefined;
722
+ /** FR-11: 컬럼/호스트 리사이즈 후 열린 패널 폭을 강제 재동기(보통은 재렌더가 자동 처리). */
723
+ resyncPanelWidths(): void;
483
724
  getChecked(): Array<{
484
725
  row: T;
485
726
  rowIndex: number;
@@ -575,6 +816,7 @@ export interface ContextMenuItem {
575
816
  type?: 'divider';
576
817
  }
577
818
  export type { FilterSelectColumn, FilterSelectConfig } from './FilterSelect.js';
819
+ export type { FlatRowRef } from './FlatRowModel.js';
578
820
  export interface WorksheetDef<T = any> {
579
821
  name: string;
580
822
  columns?: ColumnDef<T>[];
@@ -6,5 +6,6 @@ export { XmlConverter } from './core/XmlConverter.js';
6
6
  export type { OrgChartOptions, OrgChartColumnDef } from './core/OrgChart.js';
7
7
  export type { TreeNodeIconDef } from './core/types.js';
8
8
  export type { FilterSelectConfig, FilterSelectColumn } from './core/FilterSelect.js';
9
- export type { GridOptions, ColumnDef, OpenGridInstance, CellEvent, CellKeyEvent, EditEvent, RowEvent, SortItem, FilterItem, ExportOptions, FooterDef, SummaryOptions, RendererDef, EditorDef, DataType, SelectionMode, SortDir, Position, TriggerContext, TriggerHandler, TriggerEvent, } from './core/types.js';
9
+ export type { GridOptions, ColumnDef, OpenGridInstance, CellEvent, CellKeyEvent, EditEvent, RowEvent, SortItem, FilterItem, ExportOptions, FooterDef, SummaryOptions, RendererDef, EditorDef, DataType, SelectionMode, SortDir, Position, TriggerContext, TriggerHandler, TriggerEvent, CellRange, FlatRowRef, } from './core/types.js';
10
10
  export type { XmlParseOptions, XmlStringifyOptions, SapParseResult, } from './core/XmlConverter.js';
11
+ export type { ChartType, ChartSource, ChartSeriesSpec, ChartSeries, ChartDataModel, ChartConfig, ChartInstance, ChartGlobalOptions, ChartPoint, ChartAdapter, ChartRenderSpec, ChartTheme, A11yTableModel, } from './core/chart/types.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-grid",
3
- "version": "1.0.8",
3
+ "version": "1.1.0",
4
4
  "description": "Ultra-light data grid with a zero-dependency core — works with React, Vue, Angular, jQuery, or vanilla JS. MIT-licensed, endlessly customizable, with an AI-friendly override guide.",
5
5
  "type": "module",
6
6
  "main": "dist/open-grid.cjs",