open-grid 1.1.0 → 1.2.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.
- package/CHANGELOG.md +40 -0
- package/README.md +30 -1
- package/THIRD_PARTY_LICENSES.txt +43 -0
- package/dist/OpenGrid-B0Spm0rU.js +10404 -0
- package/dist/OpenGrid-CuXj0isp.cjs +97 -0
- package/dist/open-grid-base.css +5 -5
- package/dist/open-grid-react.cjs +1 -1
- package/dist/open-grid-react.js +1 -1
- package/dist/open-grid-skins.css +111 -0
- package/dist/open-grid-vue.cjs +1 -1
- package/dist/open-grid-vue.js +1 -1
- package/dist/open-grid.cjs +5 -5
- package/dist/open-grid.js +149 -136
- package/dist/types/core/AppearanceResolver.d.ts +100 -0
- package/dist/types/core/CellEditManager.d.ts +2 -0
- package/dist/types/core/ChartManager.d.ts +2 -0
- package/dist/types/core/ContextMenu.d.ts +5 -1
- package/dist/types/core/CrossGridController.d.ts +70 -0
- package/dist/types/core/DetailManager.d.ts +2 -0
- package/dist/types/core/ExportManager.d.ts +7 -0
- package/dist/types/core/ExtensionPointRegistry.d.ts +92 -0
- package/dist/types/core/FilterPanel.d.ts +4 -1
- package/dist/types/core/FilterSelect.d.ts +4 -1
- package/dist/types/core/FindBarManager.d.ts +6 -0
- package/dist/types/core/FormulaController.d.ts +81 -0
- package/dist/types/core/GridComposer.d.ts +142 -0
- package/dist/types/core/GridRenderer.d.ts +44 -4
- package/dist/types/core/IconRegistry.d.ts +55 -0
- package/dist/types/core/KeyboardManager.d.ts +2 -0
- package/dist/types/core/MutationService.d.ts +128 -0
- package/dist/types/core/OpenGrid.d.ts +464 -68
- package/dist/types/core/OrgChart.d.ts +2 -0
- package/dist/types/core/Pagination.d.ts +6 -1
- package/dist/types/core/RangeSelectionManager.d.ts +2 -0
- package/dist/types/core/RenderController.d.ts +65 -0
- package/dist/types/core/SkinRegistry.d.ts +53 -0
- package/dist/types/core/SortFilterManager.d.ts +2 -0
- package/dist/types/core/WorksheetManager.d.ts +4 -1
- package/dist/types/core/detail/DetailGlyph.d.ts +3 -1
- package/dist/types/core/editors/CellEditor.d.ts +17 -1
- package/dist/types/core/i18n/LocaleRegistry.d.ts +0 -0
- package/dist/types/core/i18n/interpolate.d.ts +5 -0
- package/dist/types/core/i18n/locales/en.d.ts +166 -0
- package/dist/types/core/i18n/locales/ko.d.ts +166 -0
- package/dist/types/core/i18n/types.d.ts +249 -0
- package/dist/types/core/icons/bootstrap-icons.d.ts +9 -0
- package/dist/types/core/renderers/CellRenderer.d.ts +43 -2
- package/dist/types/core/types.d.ts +387 -91
- package/dist/types/index.d.ts +26 -0
- package/package.json +3 -1
- package/dist/OpenGrid-5flQwc3W.js +0 -8434
- package/dist/OpenGrid-DahxRY7C.cjs +0 -92
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { DataLayer } from './DataLayer.js';
|
|
2
|
+
import { ColumnLayout } from './ColumnLayout.js';
|
|
3
|
+
import { GridOptions, OpenGridInstance, Position, GridDropEvent } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* R7(§3.1 C8, §6-R7): 그리드 간 이동·매핑·drop 표면(`moveRowsTo`/`moveCheckedTo`/크로스변환 해석/
|
|
6
|
+
* 3단계 드롭 이벤트 발화)을 `OpenGrid` God object 에서 **동작 불변**으로 옮긴 것. `OpenGrid` 는
|
|
7
|
+
* 얇은 위임 공개 메서드만 남긴다(공개 API 불변 — R0 `public_api_surface.txt` 동결).
|
|
8
|
+
*
|
|
9
|
+
* 스트랭글러 원칙(A2): `crossGridRegistry`(프로세스 스코프 싱글턴, `CrossGridRegistry.ts`)는 지금은
|
|
10
|
+
* **AS-IS 유지**한다 — 주입 `GridRegistry` 로의 승격(C8, R-6c)은 R8 컴포지션 루트로 이연한다.
|
|
11
|
+
*
|
|
12
|
+
* cross-grid 이동은 **두 그리드**(source=this, target)를 동시에 다룬다. 각 `OpenGrid` 는 자신의
|
|
13
|
+
* CrossGridController 를 소유하므로, target 측 연산(insert/rowCount/컬럼/3단계 발화)은
|
|
14
|
+
* `getPeerController(target)` 로 얻은 상대 컨트롤러의 동명 메서드로 수행한다 — `this`(source) 와
|
|
15
|
+
* peer(target) 로 갈라 원본의 `this._x` / `targetGrid._x` 접근을 1:1 재현한다(회귀 0).
|
|
16
|
+
* **3단계 drop emit 순서(before→후 이동→after→complete, 각 source→target)는 정확히 보존한다.**
|
|
17
|
+
*/
|
|
18
|
+
export interface CrossGridControllerDeps<T extends Record<string, any> = any> {
|
|
19
|
+
/** GridDropEvent 의 sourceGrid/targetGrid 식별자 + 자기동일성 비교에 쓰는 소유 그리드. */
|
|
20
|
+
getSelf: () => OpenGridInstance<T>;
|
|
21
|
+
getData: () => DataLayer<T>;
|
|
22
|
+
getColLayout: () => ColumnLayout<T>;
|
|
23
|
+
getOptions: () => Required<GridOptions<T>>;
|
|
24
|
+
/** EventEmitter fan(this.emit) — 'gridDropBefore/After/Complete'/'gridDropMapping'. */
|
|
25
|
+
emit: (event: string, payload?: any) => void;
|
|
26
|
+
/** 공개 insertRow 위임(MutationService 경유) — target 삽입에 쓰인다. */
|
|
27
|
+
insertRow: (item: Partial<T>, position?: Position) => void;
|
|
28
|
+
/** 공개 deleteRow 위임(MutationService 경유) — source 제거에 쓰인다. */
|
|
29
|
+
deleteRow: (rowIndex: number | number[]) => void;
|
|
30
|
+
/** rowMgr.getChecked() — moveCheckedTo. */
|
|
31
|
+
getChecked: () => Array<{
|
|
32
|
+
rowIndex: number;
|
|
33
|
+
}>;
|
|
34
|
+
/** rowMgr.uncheckAll()(+재렌더) 공개 위임 — moveCheckedTo. */
|
|
35
|
+
uncheckAll: () => void;
|
|
36
|
+
/** 드래그 선택 집합 해석(_dragRowSet). OpenGrid 가 소유(RowDragDrop 배선과 공유). */
|
|
37
|
+
dragRowSet: (fromIndex: number) => number[];
|
|
38
|
+
/** 상대 그리드의 CrossGridController 획득(피어 연산 위임). 비 OpenGrid 대상은 undefined. */
|
|
39
|
+
getPeerController: (grid: OpenGridInstance<T>) => CrossGridController<T> | undefined;
|
|
40
|
+
}
|
|
41
|
+
export declare class CrossGridController<T extends Record<string, any> = any> {
|
|
42
|
+
private _deps;
|
|
43
|
+
constructor(deps: CrossGridControllerDeps<T>);
|
|
44
|
+
/** 이 그리드의 소유 인스턴스(GridDropEvent 식별자). */
|
|
45
|
+
getSelf(): OpenGridInstance<T>;
|
|
46
|
+
private _rowCount;
|
|
47
|
+
private _insertRow;
|
|
48
|
+
private _visibleLeafInfos;
|
|
49
|
+
/** 드래그 드롭 어댑터 → 공개 moveRowsTo 로 위임 */
|
|
50
|
+
handleCrossGridDrop(fromIndex: number, targetBodyEl: HTMLElement, targetIndex: number): void;
|
|
51
|
+
/**
|
|
52
|
+
* 이 그리드의 행들을 다른 그리드로 이동(move)한다. 드래그·화살표 셔틀 공통 경로.
|
|
53
|
+
* 3단계 이벤트(before→after→complete)와 crossGridMapping(필드 매핑)을 적용한다.
|
|
54
|
+
* @param target 대상 그리드
|
|
55
|
+
* @param sourceIndexes 이동할 (표시)행 인덱스들
|
|
56
|
+
* @param targetIndex 대상에서 삽입 위치 (생략 시 맨 끝에 추가)
|
|
57
|
+
* @returns 이동 성공 true, 취소/무효 false
|
|
58
|
+
*/
|
|
59
|
+
moveRowsTo(target: OpenGridInstance<T>, sourceIndexes: number[], targetIndex?: number): Promise<boolean>;
|
|
60
|
+
/** 체크된 행을 다른 그리드로 이동 (화살표 셔틀용). 체크 없으면 무시. */
|
|
61
|
+
moveCheckedTo(target: OpenGridInstance<T>): Promise<boolean>;
|
|
62
|
+
/**
|
|
63
|
+
* 크로스그리드 이동의 행 변환 함수를 결정한다.
|
|
64
|
+
* 반환: null=변환 불필요(그대로) / 함수=변환 적용 / false=매핑 모달 취소(이동 중단)
|
|
65
|
+
*/
|
|
66
|
+
private _resolveCrossTransform;
|
|
67
|
+
fireGridDropBefore(e: GridDropEvent<T>): boolean | void;
|
|
68
|
+
fireGridDropAfter(e: GridDropEvent<T>): void;
|
|
69
|
+
fireGridDropComplete(e: GridDropEvent<T>): void;
|
|
70
|
+
}
|
|
@@ -19,6 +19,8 @@ export interface DetailManagerDeps<T extends Record<string, any> = any> {
|
|
|
19
19
|
doRenderFull: (n: number) => void;
|
|
20
20
|
emit: (ev: string, payload: any) => void;
|
|
21
21
|
announce: (msg: string) => void;
|
|
22
|
+
/** i18n: 깊이 한계/펼침·접힘 announce 메시지 해석. / i18n: resolve depth-limit & expand/collapse announces. */
|
|
23
|
+
t: (key: string, params?: Record<string, string | number>) => string;
|
|
22
24
|
/** 이 그리드 인스턴스의 중첩 깊이(0=최상위, 부모가 자식 생성 시 depth+1 주입). */
|
|
23
25
|
getDepth: () => number;
|
|
24
26
|
/** masterDetail.renderer 의 DetailRenderApi.grid 에 실어줄 인스턴스. */
|
|
@@ -11,6 +11,13 @@ export interface ExportDeps<T extends Record<string, any>> {
|
|
|
11
11
|
getWsManager: () => WorksheetManager<T> | null;
|
|
12
12
|
/** Phase 2: OverrideKernel.getStrategy 주입(슬롯 cellSerializer 도달용). */
|
|
13
13
|
getStrategy?: <F extends Function>(slot: string, fallback: F) => F;
|
|
14
|
+
/** i18n: 인쇄 요약행 해석(미주입 시 ko 폴백). / i18n: resolve print summary row (ko fallback when absent). */
|
|
15
|
+
t?: (key: string, params?: Record<string, string | number>) => string;
|
|
16
|
+
/** i18n: 로케일 포맷 메타(인쇄 lang·날짜 로케일·Excel 폰트). / i18n: locale format meta (print lang, date locale, Excel font). */
|
|
17
|
+
getMeta?: () => {
|
|
18
|
+
intlLocale: string;
|
|
19
|
+
exportFont?: string;
|
|
20
|
+
};
|
|
14
21
|
}
|
|
15
22
|
export declare class ExportManager<T extends Record<string, any> = any> {
|
|
16
23
|
private _d;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { OverrideKernel } from './OverrideKernel.js';
|
|
2
|
+
import { TriggerManager } from './TriggerManager.js';
|
|
3
|
+
import { StrategySlot, StrategyMap, OverrideLayerFn, OverrideCallOptions, OverridePoints, TriggerHandler } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* R11(§4 T3, §3.1 C7): 커널 위 **타입드 확장점 레지스트리**.
|
|
6
|
+
*
|
|
7
|
+
* `OverrideKernel` 은 실행 엔진(가역·host-agnostic·0줄소스, 불가침 — 한 줄도 안 건드린다).
|
|
8
|
+
* 이 레지스트리는 그 위에 얹는 **타입드 정면**으로, 확장 표면을 명시·타입·발견가능하게 만든다.
|
|
9
|
+
* 확대의 부담이 "코어 편집(하드코딩 게이트 추가)" 에서 "데이터 등록" 으로 이동한다(A4).
|
|
10
|
+
*
|
|
11
|
+
* 3범주(§4.1): (a) strategy 슬롯(값·계산) · (b) 컴포넌트 registry(렌더훅 포함) · (c) lifecycle hook.
|
|
12
|
+
* 이중구조(T-ζ): "SemVer 보증 카탈로그"(타입드 좁은 문) + "best-effort 임의 인터셉트 탈출구"(UC-11,
|
|
13
|
+
* 넓은 문). 문서·타입에서 둘을 명확히 분리하되 넓은 문을 닫지 않는다.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* 렌더 참여 훅(§4.2). 렌더층이 셀마다 참조하는 교체가능 지점.
|
|
17
|
+
* - `gate()` : 미설정(등록 override/strategy 없음)이면 false → 렌더층이 resolve 를 호출조차 안 함(제로코스트).
|
|
18
|
+
* - `resolve(rowIndex, field)` : 게이트 통과 시 렌더층에 줄 값(표시문자열/클래스/aria 등). null=미참여.
|
|
19
|
+
* 첫 등록 항목 = 기존 `getDisplayValue` 표시텍스트 동작(동일 출력 → 회귀0). 이후 새 훅은 등록만으로 열린다.
|
|
20
|
+
*/
|
|
21
|
+
export interface RenderHook<R = string> {
|
|
22
|
+
readonly id: string;
|
|
23
|
+
gate(): boolean;
|
|
24
|
+
resolve(rowIndex: number, field: string): R | null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 렌더훅 레지스트리(§4.2). 하드코딩 게이트 1개를 데이터 구동 훅 목록으로 일반화.
|
|
28
|
+
* 등록순 보존(첫 항목=표시텍스트). 렌더층은 이름을 하드코딩하지 않고 `resolve(id,…)` 로 순회 참조한다.
|
|
29
|
+
*/
|
|
30
|
+
export declare class RenderHookRegistry {
|
|
31
|
+
private _order;
|
|
32
|
+
private _hooks;
|
|
33
|
+
register(hook: RenderHook<any>): void;
|
|
34
|
+
get(id: string): RenderHook<any> | undefined;
|
|
35
|
+
has(id: string): boolean;
|
|
36
|
+
/** 등록순 훅 id 목록(첫 항목=표시텍스트). */
|
|
37
|
+
ids(): string[];
|
|
38
|
+
/**
|
|
39
|
+
* 훅 해석. 미등록이거나 게이트가 닫혀 있으면 resolve 를 **호출하지 않고** null 반환(제로코스트 보존).
|
|
40
|
+
*/
|
|
41
|
+
resolve(id: string, rowIndex: number, field: string): any;
|
|
42
|
+
/** 게이트가 열린(활성) 훅 id — 렌더층 스윕/디버깅용. */
|
|
43
|
+
activeIds(): string[];
|
|
44
|
+
}
|
|
45
|
+
/** 단일 커밋 초크포인트(C5 MutationService)가 트리거로 감싸는 변경 연산. */
|
|
46
|
+
export type MutationOp = 'setData' | 'insertRow' | 'deleteRow' | 'writeCell';
|
|
47
|
+
/** 카탈로그(매니페스트) 엔트리 — R-3d "지원 확장점 카탈로그" 산출물. */
|
|
48
|
+
export interface ExtensionCatalogEntry {
|
|
49
|
+
readonly name: string;
|
|
50
|
+
readonly category: 'strategy' | 'renderHook' | 'lifecycle' | 'override' | 'escapeHatch';
|
|
51
|
+
readonly signature: string;
|
|
52
|
+
}
|
|
53
|
+
export interface ExtensionRegistryDeps {
|
|
54
|
+
/** 실행 엔진(불가침). 레지스트리는 소유·위임할 뿐 내부를 건드리지 않는다. */
|
|
55
|
+
kernel: OverrideKernel;
|
|
56
|
+
/** before/after 취소가능 훅을 부착할 커밋 초크포인트의 TriggerManager(늦은-null 견딤). */
|
|
57
|
+
getTrigMgr: () => TriggerManager;
|
|
58
|
+
}
|
|
59
|
+
export declare class ExtensionPointRegistry<T = any> {
|
|
60
|
+
private _deps;
|
|
61
|
+
private _renderHooks;
|
|
62
|
+
constructor(deps: ExtensionRegistryDeps);
|
|
63
|
+
get renderHooks(): RenderHookRegistry;
|
|
64
|
+
/** 렌더훅 등록(코어 편집 없이 렌더층 참여 지점 추가 — OCP). */
|
|
65
|
+
registerRenderHook(hook: RenderHook<any>): void;
|
|
66
|
+
/** 렌더층이 매 셀 호출 — 미등록/게이트닫힘이면 제로코스트 null. */
|
|
67
|
+
resolveRenderHook(id: string, rowIndex: number, field: string): any;
|
|
68
|
+
/** 타입드 슬롯 등록(SemVer 보증 카탈로그). 런타임은 커널 문자열 기반(하위호환). */
|
|
69
|
+
strategy<K extends StrategySlot>(slot: K, fn: StrategyMap[K]): void;
|
|
70
|
+
strategy(slot: string, fn: Function): void;
|
|
71
|
+
/** 슬롯 조회(미등록 시 fallback — 매니저 read API, 제로코스트 철학 보존). */
|
|
72
|
+
getStrategy<F extends Function>(slot: string, fallback: F): F;
|
|
73
|
+
hasStrategy(slot: string): boolean;
|
|
74
|
+
/** 타입드 오버로드: 좁은 "지원됨" 카탈로그(IDE 발견). */
|
|
75
|
+
override<K extends keyof OverridePoints<T>>(name: K, fn: OverrideLayerFn, opts?: OverrideCallOptions): void;
|
|
76
|
+
/** 탈출구(UC-11): 임의 메서드 best-effort 인터셉트 — 넓은 문은 닫지 않는다. */
|
|
77
|
+
override(name: string, fn: OverrideLayerFn, opts?: OverrideCallOptions): void;
|
|
78
|
+
/**
|
|
79
|
+
* 취소가능 before 훅. 단일 커밋 초크포인트(C5 MutationService)가 이미 제공하는 `before:{op}`
|
|
80
|
+
* 트리거를 **타입드로 표면화**할 뿐 메커니즘을 재배선하지 않는다. 핸들러가 `ctx.cancel()` 하면 변경 취소.
|
|
81
|
+
*/
|
|
82
|
+
beforeMutation(op: MutationOp, handler: TriggerHandler): void;
|
|
83
|
+
/** 관찰(취소불가) after 훅 — 커밋 완료 후 `after:{op}` 트리거를 타입드로 표면화. */
|
|
84
|
+
afterMutation(op: MutationOp, handler: TriggerHandler): void;
|
|
85
|
+
/** 등록한 MutationHook 해제. */
|
|
86
|
+
offMutation(when: 'before' | 'after', op: MutationOp, handler: TriggerHandler): void;
|
|
87
|
+
/**
|
|
88
|
+
* 타입드 확장점 카탈로그. render 훅 항목은 실제 등록분(`renderHooks.ids()`)에서 유도 —
|
|
89
|
+
* 유령 확장점(등록 없는 카탈로그 엔트리) 금지(DeMarco M9b).
|
|
90
|
+
*/
|
|
91
|
+
catalog(): ExtensionCatalogEntry[];
|
|
92
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { FilterItem } from './types.js';
|
|
2
2
|
export type FilterApplyFn = (field: string, items: FilterItem[]) => void;
|
|
3
3
|
export type FilterClearFn = (field: string) => void;
|
|
4
|
+
/** i18n: 필터 라벨 로케일 해석기(주입 없으면 전역 t). / i18n: filter-label resolver (global t when not injected). */
|
|
5
|
+
export type FilterPanelT = (key: string, params?: Record<string, string | number>) => string;
|
|
4
6
|
/**
|
|
5
7
|
* 컬럼 헤더 필터 드롭다운 패널.
|
|
6
8
|
* 단일 인스턴스를 재사용(열릴 때 위치 재계산).
|
|
@@ -10,8 +12,9 @@ export declare class FilterPanel {
|
|
|
10
12
|
private _field;
|
|
11
13
|
private _onApply;
|
|
12
14
|
private _onClear;
|
|
15
|
+
private _t;
|
|
13
16
|
private _outsideHandler;
|
|
14
|
-
constructor(container: HTMLElement, onApply: FilterApplyFn, onClear: FilterClearFn);
|
|
17
|
+
constructor(container: HTMLElement, onApply: FilterApplyFn, onClear: FilterClearFn, t?: FilterPanelT);
|
|
15
18
|
open(field: string, anchorEl: HTMLElement, currentFilters: FilterItem[]): void;
|
|
16
19
|
close(): void;
|
|
17
20
|
get isOpen(): boolean;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { FilterItem } from './types.js';
|
|
2
|
+
/** i18n: 필터 셀렉트 라벨 해석기(주입 없으면 전역 t). / i18n: filter-select label resolver (global t when not injected). */
|
|
3
|
+
export type FilterSelectT = (key: string, params?: Record<string, string | number>) => string;
|
|
2
4
|
export interface FilterSelectOption {
|
|
3
5
|
value: string;
|
|
4
6
|
text: string;
|
|
@@ -74,7 +76,8 @@ export declare class FilterSelectPanel {
|
|
|
74
76
|
private _config;
|
|
75
77
|
private _onFilter;
|
|
76
78
|
private _onReset;
|
|
77
|
-
|
|
79
|
+
private _t;
|
|
80
|
+
constructor(container: HTMLElement, config: FilterSelectConfig, onFilter: FilterFn, onReset: ResetFn, gridId?: string, t?: FilterSelectT);
|
|
78
81
|
/**
|
|
79
82
|
* 컬럼의 옵션 목록을 계산한다.
|
|
80
83
|
*
|
|
@@ -9,16 +9,22 @@ export interface FindBarDeps<T extends Record<string, any>> {
|
|
|
9
9
|
getVs: () => VirtualScroll | null;
|
|
10
10
|
getPagination: () => Pagination | null;
|
|
11
11
|
doRender: () => void;
|
|
12
|
+
/** i18n: 메시지 해석(라벨/placeholder/aria/카운트 배지). / i18n: resolve labels/placeholder/aria/count badge. */
|
|
13
|
+
t: (key: string, params?: Record<string, string | number>) => string;
|
|
12
14
|
}
|
|
13
15
|
export declare class FindBarManager<T extends Record<string, any> = any> {
|
|
14
16
|
private _bar;
|
|
15
17
|
private _input;
|
|
16
18
|
private _count;
|
|
19
|
+
private _lbl;
|
|
20
|
+
private _close;
|
|
17
21
|
private _filter;
|
|
18
22
|
private _d;
|
|
19
23
|
constructor(deps: FindBarDeps<T>);
|
|
20
24
|
get findFilter(): string;
|
|
21
25
|
init(container: HTMLElement): void;
|
|
26
|
+
/** i18n: 상주 크롬 라벨을 활성 로케일로 다시 그린다(setLocale 경로). / i18n: repaint resident chrome labels in the active locale (setLocale path). */
|
|
27
|
+
refreshLabels(): void;
|
|
22
28
|
open(): void;
|
|
23
29
|
close(): void;
|
|
24
30
|
private _apply;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { DataLayer } from './DataLayer.js';
|
|
2
|
+
import { ColumnLayout } from './ColumnLayout.js';
|
|
3
|
+
import { FlatRowModel } from './FlatRowModel.js';
|
|
4
|
+
import { GridOptions } from './types.js';
|
|
5
|
+
import { RecalcCoordinator, RecalcSummary } from './formula/RecalcCoordinator.js';
|
|
6
|
+
import { FormulaErrorCode, FormulaGridAccessor } from './formula/types.js';
|
|
7
|
+
/**
|
|
8
|
+
* R7(§3.1 C9, §6-R7): F3 수식 표면(accessor 조립·recalc flush·에러 표현 + 공개 수식 API)을
|
|
9
|
+
* `OpenGrid` God object 에서 **동작 불변**으로 옮긴 것. `OpenGrid` 는 얇은 위임 공개 메서드만
|
|
10
|
+
* 남긴다(공개 API 불변 — R0 `public_api_surface.txt` 동결).
|
|
11
|
+
*
|
|
12
|
+
* 스트랭글러 원칙(A2): `RecalcCoordinator`(`formula/` 헤드리스 코어)는 여전히 `OpenGrid` 가
|
|
13
|
+
* 소유·재생성(setData 시 rowId 재발급 대응)하며, 이 컨트롤러에는 `*Deps` 클로저 역전 패턴으로
|
|
14
|
+
* **주입**만 된다 — `getRecalc()` 는 재할당(resetFormulaState)을 견디는 지연 getter 다.
|
|
15
|
+
* `RecalcCoordinator`/`FormulaGraph`/`FormulaEvaluator` 자체는 한 줄도 수정하지 않는다(불변 보존).
|
|
16
|
+
*
|
|
17
|
+
* ⚠️ 네이밍: root `src/core/FormulaEngine.ts` 와 `src/core/formula/` 패키지는 별개다. 이 컨트롤러는
|
|
18
|
+
* `formula/` 패키지(RecalcCoordinator)에만 배선하며 root `FormulaEngine.ts` 와는 무관하다(병합 금지).
|
|
19
|
+
*/
|
|
20
|
+
export interface FormulaControllerDeps<T extends Record<string, any> = any> {
|
|
21
|
+
getData: () => DataLayer<T>;
|
|
22
|
+
getColLayout: () => ColumnLayout<T>;
|
|
23
|
+
getFlatModel: () => FlatRowModel;
|
|
24
|
+
/** OpenGrid 가 소유하는 RecalcCoordinator. setData 시 재생성되므로 지연 getter 로 읽는다. */
|
|
25
|
+
getRecalc: () => RecalcCoordinator;
|
|
26
|
+
/** writeCell 이 적립한 dirty seed 집합(OpenGrid 소유). flushRecalc 가 소비·clear 한다. */
|
|
27
|
+
getDirtySeeds: () => Set<string>;
|
|
28
|
+
getOptions: () => Required<GridOptions<T>>;
|
|
29
|
+
/** EventEmitter fan(this.emit) — 'formulaRecalc'/'formulaError'/'formulaChange'. */
|
|
30
|
+
emit: (event: string, payload?: any) => void;
|
|
31
|
+
/** aria-live announce(C8.1 공용 인프라). */
|
|
32
|
+
announce: (msg: string) => void;
|
|
33
|
+
/** i18n: 수식 오류 announce/셀 라벨 해석(formulaError.* 통합 키). / i18n: resolve formula error announce/labels. */
|
|
34
|
+
t: (key: string, params?: Record<string, string | number>) => string;
|
|
35
|
+
/** 현재 가시 범위 렌더(this._doRender(...this._visRange())). afterRecalc 가 !skipRender 시 유발. */
|
|
36
|
+
doRenderWindow: () => void;
|
|
37
|
+
}
|
|
38
|
+
export declare class FormulaController<T extends Record<string, any> = any> {
|
|
39
|
+
private _deps;
|
|
40
|
+
constructor(deps: FormulaControllerDeps<T>);
|
|
41
|
+
/** writeCell 이 적립한 dirty seed 를 1회 onValuesChanged 로 소비하고 formulaRecalc 를 emit. */
|
|
42
|
+
flushRecalc(): void;
|
|
43
|
+
/**
|
|
44
|
+
* RecalcCoordinator 호출 결과를 표면화: formulaError 는 onFormulaError 콜백에서 이미 개별
|
|
45
|
+
* emit 되므로 여기선 배치당 1회 formulaRecalc 만 emit(C2.2 개명, `recalc`→`formulaRecalc`).
|
|
46
|
+
* Spike-A §8 교훈: 폐포가 큰 재계산은 large 플래그로 표시(가이드 문서화/모니터링용).
|
|
47
|
+
*/
|
|
48
|
+
afterRecalc(summary: RecalcSummary, opts?: {
|
|
49
|
+
skipRender?: boolean;
|
|
50
|
+
}): void;
|
|
51
|
+
handleFormulaError(rowId: string, field: string, error: FormulaErrorCode): void;
|
|
52
|
+
private _formulaErrorMessageKo;
|
|
53
|
+
/** F3 accessor(C0/C0.5/C1) — FlatRowModel + ColumnLayout.visibleLeaves + DataLayer(rowId 기반)만 본다. */
|
|
54
|
+
buildAccessor(): FormulaGridAccessor;
|
|
55
|
+
setCellFormula(rowIndex: number, field: string, formula: string): void;
|
|
56
|
+
setCellFormulaByRowId(rowId: string, field: string, formula: string, rowIndexHint?: number): void;
|
|
57
|
+
getCellFormula(rowIndex: number, field: string): string | null;
|
|
58
|
+
hasCellFormula(rowIndex: number, field: string): boolean;
|
|
59
|
+
clearCellFormula(rowIndex: number, field: string): void;
|
|
60
|
+
getCellError(rowIndex: number, field: string): FormulaErrorCode | null;
|
|
61
|
+
getDependents(rowIndex: number, field: string): Array<{
|
|
62
|
+
rowIndex: number;
|
|
63
|
+
field: string;
|
|
64
|
+
}>;
|
|
65
|
+
getPrecedents(rowIndex: number, field: string): Array<{
|
|
66
|
+
rowIndex: number;
|
|
67
|
+
field: string;
|
|
68
|
+
}>;
|
|
69
|
+
recalculate(): void;
|
|
70
|
+
recalculateCell(rowIndex: number, field: string): void;
|
|
71
|
+
/** C3(F1 fill 전용): srcRowId/srcField 수식의 상대축만 dRow/dCol 오프셋한 새 수식 원문. */
|
|
72
|
+
offsetFormula(srcRowId: string, srcField: string, dRow: number, dCol: number): string;
|
|
73
|
+
/** F3 렌더 배선(§4.4/C7, §7.4/§7.5/§7.6) — 셀 수식 메타(없으면 null). */
|
|
74
|
+
getFormulaMeta(rowIndex: number, field: string): {
|
|
75
|
+
src: string;
|
|
76
|
+
error: FormulaErrorCode | null;
|
|
77
|
+
approx: boolean;
|
|
78
|
+
} | null;
|
|
79
|
+
/** F3-R13/MCCONNELL-03(P0): 정렬/필터 후 범위-보유(hasRangeRef) 수식 전부 dirty(§3.5). */
|
|
80
|
+
recalcRangeBearingFormulas(): void;
|
|
81
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { DataLayer } from './DataLayer.js';
|
|
2
|
+
import { FlatRowModel } from './FlatRowModel.js';
|
|
3
|
+
import { RowManager } from './RowManager.js';
|
|
4
|
+
import { ColumnLayout } from './ColumnLayout.js';
|
|
5
|
+
import { FormulaController } from './FormulaController.js';
|
|
6
|
+
import { RecalcCoordinator } from './formula/RecalcCoordinator.js';
|
|
7
|
+
import { CellEditManager } from './CellEditManager.js';
|
|
8
|
+
import { ExportManager } from './ExportManager.js';
|
|
9
|
+
import { FooterManager } from './FooterManager.js';
|
|
10
|
+
import { KeyboardManager } from './KeyboardManager.js';
|
|
11
|
+
import { SortFilterManager } from './SortFilterManager.js';
|
|
12
|
+
import { FindBarManager } from './FindBarManager.js';
|
|
13
|
+
import { CellEventHandler } from './CellEventHandler.js';
|
|
14
|
+
import { RangeSelectionManager } from './RangeSelectionManager.js';
|
|
15
|
+
import { GroupTreeManager } from './GroupTreeManager.js';
|
|
16
|
+
import { DetailManager } from './DetailManager.js';
|
|
17
|
+
import { ChartManager } from './ChartManager.js';
|
|
18
|
+
import { OverrideKernel } from './OverrideKernel.js';
|
|
19
|
+
import { LocaleRegistry } from './i18n/LocaleRegistry.js';
|
|
20
|
+
import { GridRenderer } from './GridRenderer.js';
|
|
21
|
+
import { VirtualScroll } from './VirtualScroll.js';
|
|
22
|
+
import { Pagination } from './Pagination.js';
|
|
23
|
+
import { WorksheetManager } from './WorksheetManager.js';
|
|
24
|
+
import { GridOptions } from './types.js';
|
|
25
|
+
/**
|
|
26
|
+
* R8(§3.1 C2, §3.3): GridComposer 가 조립하며 접근하는 OpenGrid 의 내부 표면.
|
|
27
|
+
*
|
|
28
|
+
* OpenGrid 의 private 필드/메서드를 구조적으로 미러링한다. 여기 열거된 멤버만이 컴포저가
|
|
29
|
+
* 조립 중 대입·참조하는 대상이며, 잘못된 이름/타입의 대입은 이 인터페이스로 인해 컴파일
|
|
30
|
+
* 타임에 잡힌다(순수 `any` host 보다 안전). `_mount` 본체(renderer/vs/pagination 등 DOM
|
|
31
|
+
* 배선)는 여전히 OpenGrid 가 소유하며, 컴포저는 mount 단계에서 `_mount()` 를 호출만 한다.
|
|
32
|
+
*/
|
|
33
|
+
export interface ComposerHost<T extends Record<string, any> = any> {
|
|
34
|
+
_container: HTMLElement;
|
|
35
|
+
_options: Required<GridOptions<T>>;
|
|
36
|
+
_data: DataLayer<T>;
|
|
37
|
+
_flatModel: FlatRowModel;
|
|
38
|
+
_rowMgr: RowManager<T>;
|
|
39
|
+
_colLayout: ColumnLayout<T>;
|
|
40
|
+
_formula: FormulaController<T>;
|
|
41
|
+
_recalc: RecalcCoordinator;
|
|
42
|
+
_editMgr: CellEditManager<T>;
|
|
43
|
+
_exportMgr: ExportManager<T>;
|
|
44
|
+
_footerMgr: FooterManager<T>;
|
|
45
|
+
_kbdMgr: KeyboardManager<T>;
|
|
46
|
+
_sfMgr: SortFilterManager<T>;
|
|
47
|
+
_findMgr: FindBarManager<T>;
|
|
48
|
+
_cellEvt: CellEventHandler<T>;
|
|
49
|
+
_rangeMgr: RangeSelectionManager<T>;
|
|
50
|
+
_grpMgr: GroupTreeManager<T>;
|
|
51
|
+
_detailMgr: DetailManager<T>;
|
|
52
|
+
_chartMgr: ChartManager;
|
|
53
|
+
_ovk: OverrideKernel;
|
|
54
|
+
/** i18n: per-instance 로케일 오버라이드 child(전역 localeRegistry 의 child). 미지정 시 null → 전역 직행. */
|
|
55
|
+
_locales: LocaleRegistry | null;
|
|
56
|
+
_renderer: GridRenderer | null;
|
|
57
|
+
_vs: VirtualScroll | null;
|
|
58
|
+
_pagination: Pagination | null;
|
|
59
|
+
_wsManager: WorksheetManager<T> | null;
|
|
60
|
+
_colWidths: number[];
|
|
61
|
+
_formulaDirtySeeds: Set<string>;
|
|
62
|
+
emit(event: string, ...args: any[]): any;
|
|
63
|
+
on(event: string, cb: (...args: any[]) => void): any;
|
|
64
|
+
off(event: string, cb: (...args: any[]) => void): any;
|
|
65
|
+
_announce(msg: string): void;
|
|
66
|
+
/** i18n: 메시지 해석(인스턴스 오버라이드 우선 → 활성 로케일 → ko → 키). / i18n: resolve a message. */
|
|
67
|
+
t(key: string, params?: Record<string, string | number>): string;
|
|
68
|
+
_doRender(startIndex: number, endIndex: number): void;
|
|
69
|
+
_visRange(): [number, number];
|
|
70
|
+
_renderHeader(): void;
|
|
71
|
+
_setFocusCell(ri: number, ci: number): void;
|
|
72
|
+
_handleRowDrop(fromIndex: number, toIndex: number): void;
|
|
73
|
+
_handleCellKeyEvt(name: 'cellKeyDown' | 'cellKeyUp' | 'cellKeyPress', e: KeyboardEvent): void;
|
|
74
|
+
writeCell(rowIndex: number, field: string, value: any): void;
|
|
75
|
+
writeCells(patches: Array<{
|
|
76
|
+
rowIndex: number;
|
|
77
|
+
field: string;
|
|
78
|
+
value: any;
|
|
79
|
+
}>): number;
|
|
80
|
+
getDisplayValue(rowIndex: number, field: string): string;
|
|
81
|
+
getMaskEnabled(field: string): boolean;
|
|
82
|
+
hasCellFormula(rowIndex: number, field: string): boolean;
|
|
83
|
+
getCellFormula(rowIndex: number, field: string): string | null;
|
|
84
|
+
setCellFormula(rowIndex: number, field: string, formula: string): void;
|
|
85
|
+
clearCellFormula(rowIndex: number, field: string): void;
|
|
86
|
+
/** override 커널 배선 후 컴포저가 단 1회 호출(구조적 순서 관문). */
|
|
87
|
+
_mount(): void;
|
|
88
|
+
}
|
|
89
|
+
/** OpenGrid 만 알아야 하는 재귀/전역 배선을 컴포저에 주입(컴포저의 OpenGrid 역-import 회피). */
|
|
90
|
+
export interface ComposerHooks {
|
|
91
|
+
/** F2 서브그리드 재귀 생성(DetailManager createSubgrid). `new OpenGrid(host, {..,_detailDepth})`. */
|
|
92
|
+
createSubgrid: (host: HTMLElement, subgridOptions: any, depth: number) => any;
|
|
93
|
+
}
|
|
94
|
+
export interface CoreServicesToken {
|
|
95
|
+
readonly _phase: 'core';
|
|
96
|
+
}
|
|
97
|
+
export interface FormulaServicesToken {
|
|
98
|
+
readonly _phase: 'formula';
|
|
99
|
+
}
|
|
100
|
+
export interface ManagerRegistryToken {
|
|
101
|
+
readonly _phase: 'managers';
|
|
102
|
+
}
|
|
103
|
+
export interface OverrideKernelToken {
|
|
104
|
+
readonly _phase: 'ovk';
|
|
105
|
+
}
|
|
106
|
+
export interface MountedViewToken {
|
|
107
|
+
readonly _phase: 'mounted';
|
|
108
|
+
}
|
|
109
|
+
/** compose() 산출물 핸들. 모든 협력자는 host 에 대입되며, 이 핸들은 완료 표식이다. */
|
|
110
|
+
export interface GridRuntime {
|
|
111
|
+
readonly mounted: MountedViewToken;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* R8: 컴포지션 루트 / Phased Builder(§6-R8, §3.1 C2, §3.3).
|
|
115
|
+
*
|
|
116
|
+
* 생성자에 융합돼 있던 객체그래프 조립을 외재화한다. 각 build* 단계는 직전 단계의 산출
|
|
117
|
+
* 토큰을 매개변수로 요구하므로, 구성 순서 — 특히 `_ovk`(OverrideKernel) 생성이 `_mount()`
|
|
118
|
+
* 보다 먼저여야 한다는 불변식 — 이 **함수 시그니처의 위상정렬**로 강제된다: `mount(ovk)` 는
|
|
119
|
+
* `buildOverrideKernel()` 가 낸 토큰 없이는 호출 자체가 컴파일되지 않는다.
|
|
120
|
+
*
|
|
121
|
+
* 협력자 생성 순서는 기존 생성자와 바이트 동일(회귀0): core → formula/recalc → 11 매니저
|
|
122
|
+
* → override 커널 → mount. R2 런타임 가드는 belt-and-suspenders 로 유지된다.
|
|
123
|
+
*/
|
|
124
|
+
export declare class GridComposer {
|
|
125
|
+
static compose<T extends Record<string, any>>(host: ComposerHost<T>, container: string | HTMLElement, rawOptions: GridOptions<T>, hooks: ComposerHooks): GridRuntime;
|
|
126
|
+
/** Phase A: 컨테이너 해석 + 옵션 정규화 + 코어 서비스(DataLayer/FlatRowModel/RowManager/ColumnLayout). */
|
|
127
|
+
private static buildCoreServices;
|
|
128
|
+
/** Phase B: F3 수식 컨트롤러 + RecalcCoordinator(헤드리스 재계산 오케스트레이터). */
|
|
129
|
+
private static buildFormula;
|
|
130
|
+
/** Phase C: ~11 매니저(edit/export/footer/kbd/sortFilter/find/cellEvt/range/group/detail/chart). */
|
|
131
|
+
private static buildManagers;
|
|
132
|
+
/**
|
|
133
|
+
* Phase D: grid.override() 확장 커널 부착(★mount 전 — 초기 렌더의 footer/그룹/strategy 슬롯이
|
|
134
|
+
* 매니저 deps 의 getStrategy 클로저를 통해 host._ovk 를 참조하므로, _ovk 선생성이 필수다).
|
|
135
|
+
*
|
|
136
|
+
* 이 단계의 산출 토큰(OverrideKernelToken)이 mount() 의 매개변수라서, mount 는 이 단계
|
|
137
|
+
* 없이는 호출 자체가 불가능하다(§3.3-1 위상정렬 = R2 상처주석의 구조적 대체).
|
|
138
|
+
*/
|
|
139
|
+
private static buildOverrideKernel;
|
|
140
|
+
/** Phase E: 배선 완료 후 단 1회 mount(§3.3-2). ovk 토큰 없이는 호출 불가 → 순서 구조적 강제. */
|
|
141
|
+
private static mount;
|
|
142
|
+
}
|
|
@@ -1,7 +1,41 @@
|
|
|
1
1
|
import { DataLayer } from './DataLayer.js';
|
|
2
2
|
import { RowDragDrop } from './RowDragDrop.js';
|
|
3
3
|
import { MergeEngine } from './MergeEngine.js';
|
|
4
|
-
import {
|
|
4
|
+
import { AppearanceResolver } from './AppearanceResolver.js';
|
|
5
|
+
import { ColumnDef, SortItem, CellRange, GridOptions, FilterItem } from './types.js';
|
|
6
|
+
export interface RenderOptions extends Required<GridOptions> {
|
|
7
|
+
/** ColumnLayout.frozenCount — 고정 컬럼 수(헤더/본문 좌측 오프셋 계산). */
|
|
8
|
+
_frozenCount?: number;
|
|
9
|
+
/** SortFilterManager.filters — 필터 아이콘 활성 표시용. */
|
|
10
|
+
_activeFilters?: Record<string, FilterItem[]>;
|
|
11
|
+
/** DnD 핸들에 넘길 총 행수. */
|
|
12
|
+
_totalRows?: number;
|
|
13
|
+
/** CellEditManager.focusCell — 포커스 셀 하이라이트. */
|
|
14
|
+
_focusCell?: {
|
|
15
|
+
ri: number;
|
|
16
|
+
ci: number;
|
|
17
|
+
} | null;
|
|
18
|
+
/** RangeSelectionManager — 범위 선택 rect 하이라이트 재적용 재료(비-'cells' 모드면 없음). */
|
|
19
|
+
_rangeRects?: CellRange[];
|
|
20
|
+
}
|
|
21
|
+
export interface RenderFrame {
|
|
22
|
+
startIndex: number;
|
|
23
|
+
endIndex: number;
|
|
24
|
+
data: DataLayer<any>;
|
|
25
|
+
leaves: ColumnDef[];
|
|
26
|
+
widths: number[];
|
|
27
|
+
opts: RenderOptions;
|
|
28
|
+
offsetY: number;
|
|
29
|
+
totalHeight: number;
|
|
30
|
+
selectedRows: Set<number>;
|
|
31
|
+
checkedRows: Set<number>;
|
|
32
|
+
groupFlatRows?: Array<any> | null;
|
|
33
|
+
onGroupToggle?: ((key: string) => void) | undefined;
|
|
34
|
+
onTreeToggle?: ((nodeId: any) => void) | undefined;
|
|
35
|
+
extraOpts?: Record<string, any>;
|
|
36
|
+
mergeEngine?: MergeEngine | undefined;
|
|
37
|
+
detailApi?: DetailRenderContext | undefined;
|
|
38
|
+
}
|
|
5
39
|
export interface RendererCallbacks {
|
|
6
40
|
onHeaderClick: (field: string, shiftKey: boolean) => void;
|
|
7
41
|
onCellClick: (ri: number, ci: number, e: MouseEvent) => void;
|
|
@@ -20,11 +54,14 @@ export interface RendererCallbacks {
|
|
|
20
54
|
onColDrop: (toIndex: number) => void;
|
|
21
55
|
getColDragIdx: () => number | null;
|
|
22
56
|
getDisplayText?: (rowIndex: number, field: string) => string | null;
|
|
57
|
+
resolveRenderHook?: (channel: string, rowIndex: number, field: string) => any;
|
|
58
|
+
getDisplayFormatter?: () => ((value: any, field: string, row: any) => string | null) | null;
|
|
23
59
|
getFormulaMeta?: (rowIndex: number, field: string) => {
|
|
24
60
|
src: string;
|
|
25
61
|
error: string | null;
|
|
26
62
|
approx: boolean;
|
|
27
63
|
} | null;
|
|
64
|
+
t?: (key: string, params?: Record<string, string | number>) => string;
|
|
28
65
|
}
|
|
29
66
|
/**
|
|
30
67
|
* F2(11_design_F2_v2.md §4/§5, C6/C10): renderBody 가 detail head/filler 분기·expander 셀을
|
|
@@ -53,14 +90,17 @@ export declare class GridRenderer {
|
|
|
53
90
|
private _body;
|
|
54
91
|
private _opts;
|
|
55
92
|
private _cbs;
|
|
93
|
+
private _ap;
|
|
56
94
|
private _cellMap;
|
|
57
95
|
get bodyWrapper(): HTMLElement;
|
|
58
|
-
|
|
96
|
+
/** i18n: 렌더 로케일 해석기 — cbs.t(인스턴스 로케일) 우선, 미주입 시 전역 t. / i18n: cbs.t (instance locale) first, global t otherwise. */
|
|
97
|
+
private _t;
|
|
98
|
+
constructor(root: HTMLElement, opts: RenderOptions, cbs: RendererCallbacks, appearance?: AppearanceResolver);
|
|
59
99
|
updateSize(totalHeight: number, headerHeight: number): void;
|
|
60
100
|
/** 현재 렌더된 헤더 영역의 실제 높이(px). 헤더 줄바꿈으로 늘어난 높이를 레이아웃에 반영할 때 사용. */
|
|
61
101
|
getHeaderHeight(): number;
|
|
62
|
-
renderHeader(headerRows: any[][], leaves: ColumnDef[], widths: number[], sortList: SortItem[], opts:
|
|
63
|
-
renderBody(
|
|
102
|
+
renderHeader(headerRows: any[][], leaves: ColumnDef[], widths: number[], sortList: SortItem[], opts: RenderOptions): void;
|
|
103
|
+
renderBody(frame: RenderFrame): void;
|
|
64
104
|
getCellEl(rowIndex: number, colIndex: number): HTMLElement | undefined;
|
|
65
105
|
/**
|
|
66
106
|
* F2(§4.3 C6): full-width 디테일 패널을 body-absolute 로 그린다(병합 마스터셀 선례
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** render() 옵션. size 미지정 시 svg 는 viewBox/CSS 로 크기를 상속(width/height 속성 생략). */
|
|
2
|
+
export interface IconRenderOptions {
|
|
3
|
+
/** px 정사각 크기(width=height). 미지정 시 속성 생략(CSS/컨테이너가 결정). */
|
|
4
|
+
size?: number;
|
|
5
|
+
/** 접근성 제목. 지정 시 <title> + role="img" 추가(스크린리더). 미지정 시 장식용(부모가 aria 담당). */
|
|
6
|
+
title?: string;
|
|
7
|
+
/** true → SVGElement(DOMParser) 반환. 기본 false → SVG 마크업 문자열. */
|
|
8
|
+
el?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 시맨틱 ROLE → 아이콘 key(`BOOTSTRAP_ICONS` 의 symbolId) 기본 매핑.
|
|
12
|
+
* 렌더 코드는 이 역할 이름만 참조한다. key 교체는 이 표(혹은 register/setIcon)만 고치면 된다.
|
|
13
|
+
* 참고 스왑: `row.delete`→`trash3`(Bootstrap 의 표준 휴지통, task 의 'trash' 동족), `chart.line`→`graph-up`.
|
|
14
|
+
*/
|
|
15
|
+
export declare const DEFAULT_ICON_ROLES: Readonly<Record<string, string>>;
|
|
16
|
+
/**
|
|
17
|
+
* IconRegistry — role → 글리프 본문(inner SVG markup) 해석 + svg 래핑.
|
|
18
|
+
*
|
|
19
|
+
* 저장 단위는 **글리프 본문 문자열**(<path>/<g> 마크업). register(role, svgOrKey) 는
|
|
20
|
+
* - svgOrKey 가 `BOOTSTRAP_ICONS` 의 알려진 key 면 그 본문으로,
|
|
21
|
+
* - 아니면 **원시 SVG 본문**(사용자 커스텀 <path…>)으로 저장한다.
|
|
22
|
+
* 부모 체인(_parent)으로 per-instance 오버라이드 레지스트리를 전역 위에 얹는다(멀티그리드 격리).
|
|
23
|
+
*/
|
|
24
|
+
export declare class IconRegistry {
|
|
25
|
+
private _roles;
|
|
26
|
+
private _parent;
|
|
27
|
+
constructor(seed?: Readonly<Record<string, string>>, parent?: IconRegistry);
|
|
28
|
+
/**
|
|
29
|
+
* role 에 글리프를 등록/교체. svgOrKey 가 알려진 아이콘 key 면 그 본문을, 아니면 원시 SVG
|
|
30
|
+
* 본문 마크업으로 간주한다(코어 편집 없이 아이콘 교체 — OCP).
|
|
31
|
+
*/
|
|
32
|
+
register(role: string, svgOrKey: string): this;
|
|
33
|
+
/** role 이 (자신 또는 부모 체인에) 등록돼 있는가. */
|
|
34
|
+
has(role: string): boolean;
|
|
35
|
+
/** role → 글리프 본문(inner markup). 미등록이면 null(부모 체인까지 조회). */
|
|
36
|
+
resolveBody(role: string): string | null;
|
|
37
|
+
/** 이 레지스트리를 부모로 하는 자식(per-instance 오버라이드용) 생성. */
|
|
38
|
+
child(): IconRegistry;
|
|
39
|
+
/**
|
|
40
|
+
* role 을 `<svg viewBox=ICON_VIEWBOX>` 로 렌더. 기본 반환은 SVG 마크업 문자열(innerHTML 용);
|
|
41
|
+
* opts.el 이면 SVGElement. 미지원 role 은 빈 svg 폴백(never throw).
|
|
42
|
+
* 스킨 토큰: fill=currentColor(presentation attr) + stroke-linejoin=var(--og-icon-corner,miter).
|
|
43
|
+
*/
|
|
44
|
+
render(role: string, opts?: IconRenderOptions): string | SVGElement;
|
|
45
|
+
/** 등록된 role 목록(자신만, 디버깅/테스트용). */
|
|
46
|
+
roles(): string[];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 프로세스 공유 기본 아이콘 레지스트리(시맨틱 role 시드 완료).
|
|
50
|
+
* CellRenderer 등 팩토리 생성 렌더러(인스턴스 컨텍스트 없음)가 이 초크포인트로 아이콘을 얻는다.
|
|
51
|
+
* per-instance 교체는 `grid.setIcon()`(이 레지스트리의 child) 로, 전역 확장은 `defineIconSet()` 로.
|
|
52
|
+
*/
|
|
53
|
+
export declare const iconRegistry: IconRegistry;
|
|
54
|
+
/** 편의 정적 render — 공유 기본 레지스트리로 위임(`IconRegistry.render(role, opts)`). */
|
|
55
|
+
export declare function renderIcon(role: string, opts?: IconRenderOptions): string | SVGElement;
|
|
@@ -24,6 +24,8 @@ export interface KeyboardDeps<T extends Record<string, any>> {
|
|
|
24
24
|
handleRowDrop: (from: number, to: number) => void;
|
|
25
25
|
doRender: () => void;
|
|
26
26
|
announce: (msg: string) => void;
|
|
27
|
+
/** i18n: 행 이동 announce 해석. / i18n: resolve row-move announce. */
|
|
28
|
+
t: (key: string, params?: Record<string, string | number>) => string;
|
|
27
29
|
emit: (event: string, ...args: any[]) => void;
|
|
28
30
|
visRange: () => [number, number];
|
|
29
31
|
handleCellKeyEvt: (eventName: 'cellKeyDown' | 'cellKeyUp' | 'cellKeyPress', e: KeyboardEvent) => void;
|