@vmscloud/moz-ui-grid-react 0.1.19 → 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.
- package/dist/index.cjs +3 -3
- package/dist/index.js +48 -23
- package/dist/legacy/index.d.ts +1 -1
- package/dist/legacy/types/props.d.ts +12 -3
- package/dist/legacy/types/toolbar.d.ts +1 -1
- package/docs/manual/examples.md +2 -2
- package/docs/manual/reference.md +120 -5
- package/docs/manual/reference_react.md +6 -2
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1685,6 +1685,11 @@ const MozGrid = forwardRef(function MozGrid2(props, ref) {
|
|
|
1685
1685
|
useBuiltinTooltip: p.useBuiltinTooltip,
|
|
1686
1686
|
usePivot: p.usePivot,
|
|
1687
1687
|
usePivotBar: p.usePivotBar,
|
|
1688
|
+
useRowGroupSettings: p.useRowGroupSettings,
|
|
1689
|
+
useFieldSettings: p.useFieldSettings,
|
|
1690
|
+
useFormatSettings: p.useFormatSettings,
|
|
1691
|
+
useLayoutSettings: p.useLayoutSettings,
|
|
1692
|
+
useAggregateSettings: p.useAggregateSettings,
|
|
1688
1693
|
useChart: p.useChart,
|
|
1689
1694
|
useMultipleChart: p.useMultipleChart,
|
|
1690
1695
|
chartIncludeGrandTotal: p.chartIncludeGrandTotal,
|
|
@@ -1779,6 +1784,11 @@ const MozGrid = forwardRef(function MozGrid2(props, ref) {
|
|
|
1779
1784
|
useBuiltinTooltip: props.useBuiltinTooltip,
|
|
1780
1785
|
usePivot: props.usePivot,
|
|
1781
1786
|
usePivotBar: props.usePivotBar,
|
|
1787
|
+
useRowGroupSettings: props.useRowGroupSettings,
|
|
1788
|
+
useFieldSettings: props.useFieldSettings,
|
|
1789
|
+
useFormatSettings: props.useFormatSettings,
|
|
1790
|
+
useLayoutSettings: props.useLayoutSettings,
|
|
1791
|
+
useAggregateSettings: props.useAggregateSettings,
|
|
1782
1792
|
loading: props.loading
|
|
1783
1793
|
});
|
|
1784
1794
|
}, [
|
|
@@ -1792,6 +1802,11 @@ const MozGrid = forwardRef(function MozGrid2(props, ref) {
|
|
|
1792
1802
|
props.useBuiltinTooltip,
|
|
1793
1803
|
props.usePivot,
|
|
1794
1804
|
props.usePivotBar,
|
|
1805
|
+
props.useRowGroupSettings,
|
|
1806
|
+
props.useFieldSettings,
|
|
1807
|
+
props.useFormatSettings,
|
|
1808
|
+
props.useLayoutSettings,
|
|
1809
|
+
props.useAggregateSettings,
|
|
1795
1810
|
props.loading
|
|
1796
1811
|
]);
|
|
1797
1812
|
useEffect(() => {
|
|
@@ -1907,7 +1922,8 @@ const CONFIG_PROP_KEYS = [
|
|
|
1907
1922
|
"headerStyle",
|
|
1908
1923
|
"rowHeightChangeThreshold"
|
|
1909
1924
|
];
|
|
1910
|
-
const FLAT_ONLY_PROP_KEYS = ["
|
|
1925
|
+
const FLAT_ONLY_PROP_KEYS = ["columnGroups", "rowTemplate"];
|
|
1926
|
+
const FLAT_ONLY_PROP_KEY_MAP = { group: "rowGroupConfig" };
|
|
1911
1927
|
const BRIDGED_EVENTS = [
|
|
1912
1928
|
"data:loaded",
|
|
1913
1929
|
"row:click",
|
|
@@ -2097,6 +2113,10 @@ const MozGridReactCore = forwardRef(function MozGridReactCore2(props, ref) {
|
|
|
2097
2113
|
const v = p[key];
|
|
2098
2114
|
if (v !== void 0) config[key] = v;
|
|
2099
2115
|
}
|
|
2116
|
+
for (const [propKey, configKey] of Object.entries(FLAT_ONLY_PROP_KEY_MAP)) {
|
|
2117
|
+
const v = p[propKey];
|
|
2118
|
+
if (v !== void 0) config[configKey] = v;
|
|
2119
|
+
}
|
|
2100
2120
|
}
|
|
2101
2121
|
return config;
|
|
2102
2122
|
}, []);
|
|
@@ -9598,7 +9618,7 @@ function GridSort({ visible, onVisibleChange, width = 410 }) {
|
|
|
9598
9618
|
binding: s.id,
|
|
9599
9619
|
ascending: s.direction === "asc",
|
|
9600
9620
|
ascendingStr: s.direction === "asc" ? locale.Grid.ascending : locale.Grid.descending,
|
|
9601
|
-
|
|
9621
|
+
by: s.by ?? ""
|
|
9602
9622
|
};
|
|
9603
9623
|
});
|
|
9604
9624
|
} catch {
|
|
@@ -9665,7 +9685,7 @@ function GridSort({ visible, onVisibleChange, width = 410 }) {
|
|
|
9665
9685
|
id: s.binding,
|
|
9666
9686
|
direction: s.ascending ? "asc" : "desc",
|
|
9667
9687
|
sequence: idx + 1,
|
|
9668
|
-
...s.
|
|
9688
|
+
...s.by ? { by: s.by } : {}
|
|
9669
9689
|
}));
|
|
9670
9690
|
void grid.sort(states);
|
|
9671
9691
|
},
|
|
@@ -9690,8 +9710,8 @@ function GridSort({ visible, onVisibleChange, width = 410 }) {
|
|
|
9690
9710
|
setSorts(updated);
|
|
9691
9711
|
applyIfImmediate(updated);
|
|
9692
9712
|
};
|
|
9693
|
-
const
|
|
9694
|
-
const updated = sorts.map((s) => s.sequence === sort2.sequence ? { ...s,
|
|
9713
|
+
const onSortByChanged = (sort2, by) => {
|
|
9714
|
+
const updated = sorts.map((s) => s.sequence === sort2.sequence ? { ...s, by } : s);
|
|
9695
9715
|
setSorts(updated);
|
|
9696
9716
|
applyIfImmediate(updated);
|
|
9697
9717
|
};
|
|
@@ -9721,7 +9741,7 @@ function GridSort({ visible, onVisibleChange, width = 410 }) {
|
|
|
9721
9741
|
binding: (fieldInfo == null ? void 0 : fieldInfo.id) ?? "",
|
|
9722
9742
|
ascending: true,
|
|
9723
9743
|
ascendingStr: locale.Grid.ascending,
|
|
9724
|
-
|
|
9744
|
+
by: ""
|
|
9725
9745
|
};
|
|
9726
9746
|
const updated = [...sorts, newEntry];
|
|
9727
9747
|
setSorts(updated);
|
|
@@ -9792,7 +9812,7 @@ function GridSort({ visible, onVisibleChange, width = 410 }) {
|
|
|
9792
9812
|
setDragIndex(-1);
|
|
9793
9813
|
setDropIndicator(null);
|
|
9794
9814
|
};
|
|
9795
|
-
const
|
|
9815
|
+
const byOptions = useMemo(
|
|
9796
9816
|
() => [
|
|
9797
9817
|
{ value: "", label: "레이블" },
|
|
9798
9818
|
...pivotValueFields.map((vf) => ({ value: vf.field, label: vf.header ?? vf.field }))
|
|
@@ -9894,11 +9914,11 @@ function GridSort({ visible, onVisibleChange, width = 410 }) {
|
|
|
9894
9914
|
Select,
|
|
9895
9915
|
{
|
|
9896
9916
|
width: 120,
|
|
9897
|
-
itemsSource:
|
|
9898
|
-
value: sort2.
|
|
9917
|
+
itemsSource: byOptions,
|
|
9918
|
+
value: sort2.by,
|
|
9899
9919
|
keyProp: "value",
|
|
9900
9920
|
displayProp: "label",
|
|
9901
|
-
onChange: (v) =>
|
|
9921
|
+
onChange: (v) => onSortByChanged(sort2, String(v))
|
|
9902
9922
|
}
|
|
9903
9923
|
),
|
|
9904
9924
|
/* @__PURE__ */ jsx("span", { className: "remove-row", onClick: () => onRemoveSort(sort2), children: /* @__PURE__ */ jsx(IconClose$1, {}) })
|
|
@@ -10235,7 +10255,7 @@ function useGridSort() {
|
|
|
10235
10255
|
header: (patch2 == null ? void 0 : patch2.header) ?? "",
|
|
10236
10256
|
binding: (patch2 == null ? void 0 : patch2.binding) ?? "",
|
|
10237
10257
|
ascending: (patch2 == null ? void 0 : patch2.ascending) ?? true,
|
|
10238
|
-
|
|
10258
|
+
by: patch2 == null ? void 0 : patch2.by
|
|
10239
10259
|
}
|
|
10240
10260
|
]);
|
|
10241
10261
|
}, []);
|
|
@@ -12866,10 +12886,10 @@ function GridFooter({ filteredRowCount: extFiltered, totalRowCount: extTotal, ch
|
|
|
12866
12886
|
aggregateUnsubRef.current = null;
|
|
12867
12887
|
if (!grid) return;
|
|
12868
12888
|
const gridWithOn = grid;
|
|
12869
|
-
const unsub = (_b2 = gridWithOn.on) == null ? void 0 : _b2.call(gridWithOn, "selection:changed", () => {
|
|
12870
|
-
var _a3
|
|
12871
|
-
const
|
|
12872
|
-
if (
|
|
12889
|
+
const unsub = (_b2 = gridWithOn.on) == null ? void 0 : _b2.call(gridWithOn, "selection:changed", (payload) => {
|
|
12890
|
+
var _a3;
|
|
12891
|
+
const total = (_a3 = payload == null ? void 0 : payload.aggregates) == null ? void 0 : _a3.total;
|
|
12892
|
+
if (total && total.count > 0) setSelectionTotal(total);
|
|
12873
12893
|
else setSelectionTotal(null);
|
|
12874
12894
|
});
|
|
12875
12895
|
if (unsub) aggregateUnsubRef.current = unsub;
|
|
@@ -14497,18 +14517,20 @@ const GridContextMenu = forwardRef(function GridContextMenu2(props, ref) {
|
|
|
14497
14517
|
ctx
|
|
14498
14518
|
);
|
|
14499
14519
|
requestAnimationFrame(() => {
|
|
14500
|
-
|
|
14501
|
-
|
|
14520
|
+
openMenu(() => buildMozContextMenuItems(ctx, []));
|
|
14521
|
+
void calculateAggregates().then((cols) => {
|
|
14522
|
+
openMenu(() => buildMozContextMenuItems(ctx, cols));
|
|
14523
|
+
});
|
|
14502
14524
|
});
|
|
14503
14525
|
},
|
|
14504
14526
|
close: closeMenu
|
|
14505
14527
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
14506
14528
|
}), [ctxMenu, openMenu, closeMenu]);
|
|
14507
|
-
const calculateAggregates = useCallback(() => {
|
|
14529
|
+
const calculateAggregates = useCallback(async () => {
|
|
14508
14530
|
var _a2, _b2;
|
|
14509
14531
|
if (!grid) return [];
|
|
14510
14532
|
try {
|
|
14511
|
-
const result = (_b2 = (_a2 = grid.rows) == null ? void 0 : _a2.selectionAggregates) == null ? void 0 : _b2.call(_a2);
|
|
14533
|
+
const result = await ((_b2 = (_a2 = grid.rows) == null ? void 0 : _a2.selectionAggregates) == null ? void 0 : _b2.call(_a2));
|
|
14512
14534
|
const cols = (result == null ? void 0 : result.columns) ?? [];
|
|
14513
14535
|
setAggregateColumns(cols);
|
|
14514
14536
|
return cols;
|
|
@@ -21260,18 +21282,21 @@ const PivotContextMenu = forwardRef(function PivotContextMenu2({ config = {}, on
|
|
|
21260
21282
|
ctx
|
|
21261
21283
|
);
|
|
21262
21284
|
requestAnimationFrame(() => {
|
|
21263
|
-
|
|
21264
|
-
|
|
21285
|
+
openMenu(() => buildMenuItems(ctx, []));
|
|
21286
|
+
void calculateAggregates().then((cols) => {
|
|
21287
|
+
if (ctxAtOpenRef.current !== ctx) return;
|
|
21288
|
+
openMenu(() => buildMenuItems(ctx, cols));
|
|
21289
|
+
});
|
|
21265
21290
|
});
|
|
21266
21291
|
},
|
|
21267
21292
|
close: closeMenu
|
|
21268
21293
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
21269
21294
|
}), [ctxMenu, openMenu, closeMenu]);
|
|
21270
|
-
const calculateAggregates = useCallback(() => {
|
|
21295
|
+
const calculateAggregates = useCallback(async () => {
|
|
21271
21296
|
var _a2, _b2;
|
|
21272
21297
|
if (!grid) return [];
|
|
21273
21298
|
try {
|
|
21274
|
-
const result = (_b2 = (_a2 = grid.rows) == null ? void 0 : _a2.selectionAggregates) == null ? void 0 : _b2.call(_a2);
|
|
21299
|
+
const result = await ((_b2 = (_a2 = grid.rows) == null ? void 0 : _a2.selectionAggregates) == null ? void 0 : _b2.call(_a2));
|
|
21275
21300
|
const cols = (result == null ? void 0 : result.columns) ?? [];
|
|
21276
21301
|
setAggregateColumns(cols);
|
|
21277
21302
|
return cols;
|
package/dist/legacy/index.d.ts
CHANGED
|
@@ -55,7 +55,7 @@ export { GridInstanceContext, GridContainerContext, GridRendererContext, GridTem
|
|
|
55
55
|
export type { MozGridReactCoreProps, MozGridReactProps, } from './types/props';
|
|
56
56
|
export type { CellSlotProps, HeaderSlotProps, EditorSlotProps, DetailSlotProps, GroupSlotProps, TemplateRegistry, TemplateEntry, } from '../types/slots';
|
|
57
57
|
export type { ComparisonOperator, LogicalOperator, IFilterDef, ISortDef, ICustomCellDef, ICustomCellRuleSet, ICustomCellConfig, IContextMenuItem, IContextMenuConfig, IContextMenuExcelEventArgs, AggregateType, IAggregateValues, } from './types/toolbar';
|
|
58
|
-
export type { PureSheetConfig, FieldDef, PureSheetEventType, SortState, FilterState, FilterOperator, Row, ColumnDef, ColumnState, EditorConfig, GridState, GridActivity, ViewState, RowSelectionMode, CellSelectionMode, RowSelectionTrigger, RowSelectionConfig, CellSelectionConfig, DataType, AggregateFunc, RowState, ValidationRule, ValidationError, ValidationTrigger,
|
|
58
|
+
export type { PureSheetConfig, FieldDef, PureSheetEventType, SortState, FilterState, FilterOperator, Row, ColumnDef, ColumnState, EditorConfig, GridState, GridActivity, ViewState, RowSelectionMode, CellSelectionMode, RowSelectionTrigger, RowSelectionConfig, CellSelectionConfig, DataType, AggregateFunc, RowState, ValidationRule, ValidationError, ValidationTrigger, RowGroupConfig, RowGroupAggregate, TreeConfig, MasterDetailConfig, ColumnGroupDef, FormatRowCallback, PartialTranslationMap, IPivotAPI, PivotState, PivotConfig, PivotRowField, PivotColumnField, PivotValueField, PivotResult, PivotHeaderNode, PivotRow, ShowValueAs, IRowsAPI, IColumnsAPI, IChangesAPI, IUndoManagerAPI, IGroupAPI, ITreeAPI, IMasterDetailAPI, IValidationAPI, IClipboardAPI, IHeadersAPI, } from '@vmscloud/moz-ui-grid-core';
|
|
59
59
|
export { UndoStack } from '@vmscloud/moz-ui-grid-core';
|
|
60
60
|
export { getRowHeaderCell, getCornerCell, ROW_HEADER_COLUMN_ID } from '@vmscloud/moz-ui-grid-core';
|
|
61
61
|
export { CheckBox, type CheckBoxProps } from './ui/checkbox';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FieldDef, PureSheetEventType, PivotRowField, PivotColumnField, PivotValueField, FormatRowCallback, PartialTranslationMap,
|
|
1
|
+
import { FieldDef, PureSheetEventType, PivotRowField, PivotColumnField, PivotValueField, FormatRowCallback, PartialTranslationMap, RowGroupConfig, ColumnGroupDef, RowHeaderConfig, FieldRowTemplate, LoaderConfig, RowSelectionConfig, CellSelectionConfig, ScrollEndReachedPayload, ScrollPayload, UndoStack } from '@vmscloud/moz-ui-grid-core';
|
|
2
2
|
import { IContextMenuConfig } from './toolbar';
|
|
3
3
|
/**
|
|
4
4
|
* MozGridReactCore Props
|
|
@@ -50,7 +50,7 @@ export interface MozGridReactCoreProps {
|
|
|
50
50
|
rowStyle?: string;
|
|
51
51
|
headerStyle?: string;
|
|
52
52
|
rowHeightChangeThreshold?: number;
|
|
53
|
-
group?:
|
|
53
|
+
group?: RowGroupConfig;
|
|
54
54
|
columnGroups?: ColumnGroupDef[];
|
|
55
55
|
rowTemplate?: FieldRowTemplate;
|
|
56
56
|
/** PureSheet 인스턴스가 준비됐을 때 */
|
|
@@ -112,7 +112,16 @@ export interface MozGridReactProps extends MozGridReactCoreProps {
|
|
|
112
112
|
}
|
|
113
113
|
/** Props → PureSheetConfig 변환에 사용하는 키 목록 (Vue와 동일) */
|
|
114
114
|
export declare const CONFIG_PROP_KEYS: readonly ["keyFields", "theme", "rowHeight", "headerHeight", "showHeader", "resizableColumns", "reorderableColumns", "showRowHeader", "rowHeader", "rowSelection", "cellSelection", "cellSelectionImpliesRows", "rowModel", "endReachedThresholdRows", "editable", "tooltipMode", "alternatingRows", "autoFitColumns", "dynamicRowHeights", "reorderableRows", "locale", "engine", "useWorker", "loader", "preventKeyEdit", "showStatusBar", "showDragHandleColumn", "undoStack", "formatRow", "translations", "rowStyle", "headerStyle", "rowHeightChangeThreshold"];
|
|
115
|
-
export declare const FLAT_ONLY_PROP_KEYS: readonly ["
|
|
115
|
+
export declare const FLAT_ONLY_PROP_KEYS: readonly ["columnGroups", "rowTemplate"];
|
|
116
|
+
/**
|
|
117
|
+
* flat 전용 prop 중 **core 설정 키 이름이 다른 것** — `prop 이름 → core 설정 키`.
|
|
118
|
+
*
|
|
119
|
+
* legacy `group` prop 은 소비처 표면이라 이름을 유지하되, core 설정 키는
|
|
120
|
+
* `rowGroupConfig`(`treeConfig`/`masterDetailConfig` 와 같은 규약)로 옮겨졌다.
|
|
121
|
+
*/
|
|
122
|
+
export declare const FLAT_ONLY_PROP_KEY_MAP: {
|
|
123
|
+
readonly group: "rowGroupConfig";
|
|
124
|
+
};
|
|
116
125
|
export declare const BRIDGED_EVENTS: PureSheetEventType[];
|
|
117
126
|
/** PureSheet 이벤트 → onXxx prop 이름 매핑 */
|
|
118
127
|
export declare const EVENT_TO_PROP: Record<PureSheetEventType, keyof MozGridReactCoreProps>;
|
package/docs/manual/examples.md
CHANGED
|
@@ -668,8 +668,8 @@ const collapsedRows = grid.pivot.getCollapsedRowNodes();
|
|
|
668
668
|
// ── 피벗 정렬/필터 (viewState 단일 채널 — field-level sort 옵션 없음) ──
|
|
669
669
|
// 라벨 기준 정렬
|
|
670
670
|
await grid.sort([{ id: 'region', direction: 'asc', sequence: 1 }]);
|
|
671
|
-
// 값(집계) 기준 정렬 —
|
|
672
|
-
await grid.sort([{ id: 'region', direction: 'desc', sequence: 1,
|
|
671
|
+
// 값(집계) 기준 정렬 — by 로 집계 값 기준 정렬
|
|
672
|
+
await grid.sort([{ id: 'region', direction: 'desc', sequence: 1, by: 'sales' }]);
|
|
673
673
|
|
|
674
674
|
// 차원(행/열 필드) 필터 → core 가 자동으로 pre(소스 축소 후 재집계)로 분류
|
|
675
675
|
await grid.filter([{ id: 'region', operator: 'eq', filterValue: '서울', sequence: 1 }]);
|
package/docs/manual/reference.md
CHANGED
|
@@ -195,6 +195,7 @@ grid.on('row:click', ({ rowIndex }) => {
|
|
|
195
195
|
| `showHeader` | `boolean` | `true` | 헤더 표시 여부 |
|
|
196
196
|
| `rowHeader` | `boolean \| RowHeaderConfig` | `false` | 좌측 행 헤더 컬럼(`_rowHeader`) 표시. `true`면 빈 셀(너비 40, 체크박스 트리거 시 체크박스), 객체면 `width`/`cellRenderer`/`headerRenderer`로 커스터마이즈 (→ [RowHeaderConfig](#rowheaderconfig)). `rowSelection.trigger`가 `'rowHeader'`/`'checkbox'`면 미지정이어도 자동 ON. (구 `showRowHeader` — deprecated alias 유지) |
|
|
197
197
|
| `showStatusBar` | `boolean` | `true` | 상태 바 표시 |
|
|
198
|
+
| `summaryRow` | `'none' \| 'pinnedTop' \| 'pinnedBottom'` | `'none'` | 집계(총합계) 행 표시 위치. `FieldDef.aggregate` 가 지정된 컬럼을 모아 core 가 행을 직접 소유하며, `getConfig()` 에 실려 레이아웃 프리셋으로 저장·복원된다 |
|
|
198
199
|
| `alternatingRows` | `boolean` | `false` | 줄무늬 행 스타일 |
|
|
199
200
|
| `rowStyle` | `string` | — | 행 CSS 스타일 |
|
|
200
201
|
| `headerStyle` | `string` | — | 헤더 CSS 스타일 |
|
|
@@ -352,7 +353,7 @@ grid.on('row:click', ({ rowIndex }) => {
|
|
|
352
353
|
| 속성 | 타입 | 설명 |
|
|
353
354
|
|------|------|------|
|
|
354
355
|
| `mask` | `MaskConfig` | 마스킹 설정 |
|
|
355
|
-
| `aggregate` | `AggregateFunc` | 그룹/피벗 집계
|
|
356
|
+
| `aggregate` | `AggregateFunc` | 그룹/피벗 집계 함수. wrapper의 `useSummaryFooter: true`에서는 컬럼 하단 집계에도 사용한다(기본 OFF). 표시를 꺼도 함수는 유지된다 |
|
|
356
357
|
|
|
357
358
|
### 그룹 행
|
|
358
359
|
|
|
@@ -669,7 +670,7 @@ interface GridConfigExport {
|
|
|
669
670
|
| **뷰 상태** | `sorts`, `filters` |
|
|
670
671
|
| **서버/수동 row-model** | `rowModel`, `endReachedThresholdRows` |
|
|
671
672
|
| **트리/디테일** | `treeConfig`, `masterDetailConfig` |
|
|
672
|
-
| **UI 옵션** | `theme`, `rowHeight`, `headerHeight`, `rowSelection`, `cellSelection`, `cellSelectionImpliesRows`, `editable`, `tooltipMode`, `alternatingRows`, `showHeader`, `resizableColumns`, `reorderableColumns`, `rowHeader`, `reorderableRows`, `showDragHandleColumn`, `autoFitColumns`, `showStatusBar`, `locale`, `translations`, `keyFields` 등 |
|
|
673
|
+
| **UI 옵션** | `theme`, `rowHeight`, `headerHeight`, `rowSelection`, `cellSelection`, `cellSelectionImpliesRows`, `editable`, `tooltipMode`, `alternatingRows`, `showHeader`, `resizableColumns`, `reorderableColumns`, `rowHeader`, `reorderableRows`, `showDragHandleColumn`, `autoFitColumns`, `showStatusBar`, `summaryRow`, `locale`, `translations`, `keyFields` 등 |
|
|
673
674
|
|
|
674
675
|
**제외되는 항목**
|
|
675
676
|
|
|
@@ -919,7 +920,7 @@ rowSelection(선택된 행들)·cellSelection(선택된 셀 range)은 서로 다
|
|
|
919
920
|
|--------|------|------|
|
|
920
921
|
| `addPinnedTop(row \| RowConfig)` | `Row` | 새 행/설정으로 상단 고정 행 추가 |
|
|
921
922
|
| `addPinnedBottom(row \| RowConfig)` | `Row` | 새 행/설정으로 하단 고정 행 추가 |
|
|
922
|
-
| `addGrandTotal(aggregates)` | `Row` | 전체 합계 행 추가 |
|
|
923
|
+
| `addGrandTotal(aggregates)` | `Row` | **(deprecated)** 전체 합계 행 추가 — `grid.setSummaryRow('pinnedBottom')` 를 사용할 것. 이 API 로 꽂은 행은 `getConfig()` 에 실리지 않아 레이아웃 프리셋으로 저장·복원되지 않는다 |
|
|
923
924
|
| `addFilter()` | `Row` | 필터 행 추가 |
|
|
924
925
|
|
|
925
926
|
#### 고정 관리
|
|
@@ -1229,6 +1230,55 @@ await grid.changes.commit({ allowInvalid: true });
|
|
|
1229
1230
|
|
|
1230
1231
|
---
|
|
1231
1232
|
|
|
1233
|
+
#### 그룹 집계 식별자
|
|
1234
|
+
|
|
1235
|
+
`RowGroupConfig.aggregates`의 각 항목에는 선택적인 `id`를 지정할 수 있습니다.
|
|
1236
|
+
기본 ID는 내장 함수의 경우 `${func}_${column}`(예: `sum_salary`), 콜백은 `column`입니다.
|
|
1237
|
+
`getRowGroupAggregateId(aggregate)`를 core 패키지에서 가져와 유효 ID를 조회할 수 있습니다.
|
|
1238
|
+
입력과 저장 설정은 원형을 보존하므로 이 조회가 생략된 `id`를 설정 객체에 써넣지는 않습니다.
|
|
1239
|
+
|
|
1240
|
+
- 명시한 ID는 그대로 사용합니다. 이름을 분해해 컬럼·함수를 추론하지 않습니다.
|
|
1241
|
+
- 같은 레벨에서 실제로 적용되는 집계 ID는 유일해야 합니다. 서로 다른 레벨의 scope에서는
|
|
1242
|
+
같은 ID를 사용할 수 있지만, 모든 레벨 선언과 특정 레벨 선언의 scope가 겹치면 충돌합니다.
|
|
1243
|
+
- `setConfig` 및 그룹 컬럼 변경 시 충돌을 검사합니다. 충돌하면 예외가 발생하며 기존 그룹
|
|
1244
|
+
설정은 변경되지 않습니다. 그룹 해제 중 보관한 선언은 그룹 복원 시 다시 검사합니다.
|
|
1245
|
+
- 공개 ID는 내부 계산 alias와 별개입니다. ID를 지정해도 기존 집계값·서식의 alias는 바뀌지 않습니다.
|
|
1246
|
+
- 콜백 기본값은 함수의 영속 식별자가 아닙니다. 같은 컬럼에 여러 콜백을 쓰면 ID를 명시해야 하며,
|
|
1247
|
+
콜백 자체의 JSON 직렬화를 보장하지 않습니다. 수식에서 참조 가능한 문법 역시 별도 계약입니다.
|
|
1248
|
+
|
|
1249
|
+
#### 그룹행 정렬 기준
|
|
1250
|
+
|
|
1251
|
+
core의 `RowGroupConfig.sorts`는 같은 부모 아래 그룹행을 그룹 컬럼별로 정렬합니다.
|
|
1252
|
+
각 규칙은 `{ column, direction, by }`이며 `column`은 해당 그룹 레벨의 컬럼 id,
|
|
1253
|
+
`direction`은 `'asc' | 'desc'`입니다.
|
|
1254
|
+
|
|
1255
|
+
- `id`: 정렬할 그룹 레벨의 컬럼 ID (집계 데이터 컬럼이 아님).
|
|
1256
|
+
- `basis: 'groupValue'`: **그룹 이름** — 원본 scalar 값을 비교합니다. 생략해도 이 기준입니다.
|
|
1257
|
+
- `basis: 'rowCount'`: 하위 데이터 행 개수.
|
|
1258
|
+
- `basis: 'aggregate', by: 'salaryTotal'`: 해당 레벨의 공개 집계 ID를 정확히 참조합니다.
|
|
1259
|
+
`by`는 문자열 하나이며 객체/배열이 아닙니다. 명시 ID가 없으면 `${func}_${column}`을 사용합니다.
|
|
1260
|
+
공백 제거·별칭 추측 없이 ID를 비교하며 `scope`는 전체 그룹 경로와 정확히 일치해야 합니다.
|
|
1261
|
+
유효하지 않은 활성 집계 참조는 오류입니다. `by`만 제공해도 집계 기준을 추론하지 않습니다.
|
|
1262
|
+
|
|
1263
|
+
```ts
|
|
1264
|
+
await grid.rowGroup.setConfig({
|
|
1265
|
+
columns: ['dept', 'team'],
|
|
1266
|
+
aggregates: [{ id: 'salaryTotal', column: 'salary', func: 'sum', scope: ['dept', 'team'] }],
|
|
1267
|
+
sorts: [
|
|
1268
|
+
{ id: 'dept', direction: 'asc', basis: 'groupValue' },
|
|
1269
|
+
{ id: 'team', direction: 'desc', basis: 'aggregate', by: 'salaryTotal' },
|
|
1270
|
+
],
|
|
1271
|
+
});
|
|
1272
|
+
```
|
|
1273
|
+
|
|
1274
|
+
저장본 0.4 → 0.5 마이그레이션은 옛 그룹 정렬 `column`/객체 `by`를 새 모델로 변환하고,
|
|
1275
|
+
피벗 `SortState.byValue`는 동일한 scalar 값 그대로 `by`로 개명합니다. 피벗 집계/정렬 의미는 변하지 않습니다.
|
|
1276
|
+
|
|
1277
|
+
그룹 내부 데이터 행의 일반 정렬은 별도로 유지됩니다. null/undefined는 기존 정렬 규약대로
|
|
1278
|
+
오름차순에서는 뒤, 내림차순에서는 앞에 위치합니다. wrapper 정렬 패널의 **그룹 정렬 → 정렬 기준**에서도
|
|
1279
|
+
‘그룹 이름’을 선택할 수 있습니다. 정렬 규칙이 없을 때와 새 규칙을 추가할 때 모두
|
|
1280
|
+
**그룹 이름 오름차순**이 기본입니다. 기존에 저장한 하위 행 개수·집계 정렬은 그대로 유지됩니다.
|
|
1281
|
+
|
|
1232
1282
|
### grid.tree — 트리 API
|
|
1233
1283
|
|
|
1234
1284
|
> 트리 미설정 시 `getConfig()`는 `null` 반환.
|
|
@@ -2213,7 +2263,8 @@ grid.off('cell:click', handler);
|
|
|
2213
2263
|
| `formattedValue` | `string` | 렌더링된 텍스트 (헤더는 컬럼 라벨) |
|
|
2214
2264
|
| `tooltipText?` | `string` | 컬럼 커스텀 툴팁 문구(`ColumnDef.headerTooltip`/`cellTooltip`). 있으면 `formattedValue` 대신 표시에 우선 |
|
|
2215
2265
|
| `isOverflowing` | `boolean` | 셀 내용이 잘려서 표시되는지 |
|
|
2216
|
-
| `cellRect` | `DOMRect` | 셀/헤더 DOM 영역 |
|
|
2266
|
+
| `cellRect` | `DOMRect` | 셀/헤더 DOM 영역 (셀 전체. 뷰포트 밖까지 포함) |
|
|
2267
|
+
| `anchorRect` | `DOMRect` | **툴팁을 놓을 기준 영역** — 셀에서 지금 화면에 보이는 띠. 셀이 전부 보이면 `cellRect` 와 같다. 뷰포트보다 긴 세로 병합 셀은 글자가 가시 영역 중앙에 붙어 있으므로, 이 값을 기준으로 배치해야 툴팁이 글자를 따라간다 |
|
|
2217
2268
|
| `element` | `HTMLElement` | 셀/헤더 DOM 요소 |
|
|
2218
2269
|
| `errors?` | `string[]` | 유효성 검사 에러 메시지 (없으면 `undefined`). **셀 전용** |
|
|
2219
2270
|
| `hasError?` | `boolean` | 에러 존재 여부 빠른 플래그. **셀 전용**(헤더엔 없음) |
|
|
@@ -2987,7 +3038,7 @@ interface SortState {
|
|
|
2987
3038
|
/** 우선순위 (낮을수록 먼저 적용) */
|
|
2988
3039
|
sequence: number;
|
|
2989
3040
|
/** 피벗 전용: 값 필드 기준 정렬 (레이블 대신 집계 값 기준) */
|
|
2990
|
-
|
|
3041
|
+
by?: string;
|
|
2991
3042
|
/** 커스텀 정렬 키 함수 — 셀 값을 정렬 가능한 키로 변환 */
|
|
2992
3043
|
sortKey?: (value: CellValue) => number | string;
|
|
2993
3044
|
/**
|
|
@@ -3147,6 +3198,69 @@ await grid.filter([{
|
|
|
3147
3198
|
| `conditionFiltersToFormula(filters)` | 조건식 배열 → 수식 문자열 (`ConditionFilterConversion`) |
|
|
3148
3199
|
| `conditionFiltersToFormulaState(...)` | 조건식 배열 → `FormulaFilterState` |
|
|
3149
3200
|
|
|
3201
|
+
#### FilterGroupMap — 일반 행과 그룹 결과 필터
|
|
3202
|
+
|
|
3203
|
+
`grid.filter(map)`의 최상위 키는 **필터 UI 소유권**이다. 컬럼 ID가 아니다.
|
|
3204
|
+
`scope` 생략 또는 `'row'`는 일반 행 필터, `'group'`은 행 그룹 결과 필터다.
|
|
3205
|
+
그룹 **조건식**의 `states[].id`는 그룹 기준 컬럼 ID이며, 각 조건이 자신의 `basis`를 지정한다.
|
|
3206
|
+
**수식**은 일반 필터처럼 `operator: 'formula'`와 `expression` 하나로 저장한다.
|
|
3207
|
+
wrapper는 수식의 `id`를 `'__formula__'`로 쓰며, 대상 그룹은 수식 안의 참조로 정한다.
|
|
3208
|
+
|
|
3209
|
+
```typescript
|
|
3210
|
+
await grid.rowGroup.setConfig({
|
|
3211
|
+
columns: ['dept', 'team'],
|
|
3212
|
+
aggregates: [{ id: 'total', column: 'amount', func: 'sum' }],
|
|
3213
|
+
sorts: [{ id: 'dept', basis: 'aggregate', by: 'total', direction: 'desc' }],
|
|
3214
|
+
});
|
|
3215
|
+
await grid.filter({
|
|
3216
|
+
rowEditor: {
|
|
3217
|
+
type: 'conditional', priority: 0, applied: true,
|
|
3218
|
+
states: [{ id: 'amount', operator: 'gte', filterValue: 0, sequence: 0 }],
|
|
3219
|
+
},
|
|
3220
|
+
groupEditor: {
|
|
3221
|
+
scope: 'group', type: 'conditional', priority: 1, applied: true,
|
|
3222
|
+
states: [
|
|
3223
|
+
{ id: 'dept', basis: 'aggregate', by: 'total', operator: 'gt', filterValue: 50, sequence: 0 },
|
|
3224
|
+
{ id: 'team', basis: 'groupValue', operator: 'eq', filterValue: 'X', logical: 'and', sequence: 1 },
|
|
3225
|
+
],
|
|
3226
|
+
},
|
|
3227
|
+
});
|
|
3228
|
+
```
|
|
3229
|
+
|
|
3230
|
+
- `basis: 'groupValue'`: 해당 그룹의 원본 값. 표시 문자열이나 마스크 변환 결과가 아니다.
|
|
3231
|
+
- `basis: 'rowCount'`: 해당 그룹의 데이터 행 개수.
|
|
3232
|
+
- `basis: 'aggregate'`: 해당 레벨 집계의 공개 ID를 `by`로 정확히 참조한다.
|
|
3233
|
+
ID 문자열을 분해해 컬럼·함수를 추측하지 않는다.
|
|
3234
|
+
- 수식 참조는 `GROUP("id", "groupValue")`, `GROUP("id", "rowCount")`,
|
|
3235
|
+
`GROUP("id", "aggregate", "by")`다. 인자는 정확한 ID와 basis 문자열 리터럴이며 기본 레벨은 없다.
|
|
3236
|
+
예: `{ id: '__formula__', operator: 'formula', expression: 'GROUP("dept", "aggregate", "total") > 50 AND GROUP("team", "groupValue") = "X"', sequence: 0 }`.
|
|
3237
|
+
한 수식에서 같은 최하위 경로의 여러 레벨·집계·그룹 값·행 개수를 비교하거나 계산할 수 있다.
|
|
3238
|
+
`GROUP`은 그룹 수식 컨텍스트의 참조이며 일반 행 수식/조건부 서식의 함수가 아니다.
|
|
3239
|
+
기존 `id: 'dept', expression: '$total > 50'` 로컬 집계 수식도 읽을 수 있다.
|
|
3240
|
+
- wrapper 고급 필터의 일반/그룹 탭은 동일한 textarea와 조건 트리 편집기를 공유한다.
|
|
3241
|
+
그룹 자동완성은 `[현재 그룹 라벨 · 대상 라벨]`을 제안하며 저장 직전에 명시적인 `GROUP(...)` 참조로 변환한다.
|
|
3242
|
+
트리에서 표현할 수 없는 계산식은 원문을 보존하고 수식 모드에서 편집한다.
|
|
3243
|
+
기존 조건 목록은 열기만 해서는 재저장하지 않으며, 실제 편집 시 기존 좌결합을 보존한 수식 하나로 저장한다.
|
|
3244
|
+
- `sequence` 순서로 `logical`을 좌→우 결합한다. 묶음 간에는 AND를 적용한다.
|
|
3245
|
+
부모와 자식 조건은 **같은 최하위 그룹 경로**에서 평가하므로 부모가 false여도 OR 자식 조건을 평가한다.
|
|
3246
|
+
- 일반 행 필터 후 **A 집계로 한 번 판정 → 생존 데이터로 B 재집계·정렬**한다.
|
|
3247
|
+
예를 들어 부모 A 합계가 100이라 통과한 뒤 팀 필터로 B 합계가 10이 되어도 다시 탈락시키지 않는다.
|
|
3248
|
+
- `applied: false`는 저장하되 실행하지 않는다. 묶음의 대상 그룹 레벨 중 하나라도 없으면
|
|
3249
|
+
**묶음 전체**가 실행에서 제외되며 원본 상태는 유지된다. 활성 묶음의 잘못된 집계 참조·수식은 오류다.
|
|
3250
|
+
- `getFilterGroups()` 및 `getViewState().filterGroups`가 원본 맵을 반환한다.
|
|
3251
|
+
`getViewState().filters`는 실행 가능한 일반 행 필터의 평탄화 결과다.
|
|
3252
|
+
`getConfig()`/`applyConfig()`와 `getViewState()`/`setViewState()` 왕복은 소유 맵을 보존한다.
|
|
3253
|
+
- 피벗에서는 행 그룹 결과 필터를 실행하지 않고 보존한다. 서버 row-model도 상태만 보존하며
|
|
3254
|
+
서버가 준 행을 로컬에서 탈락시키지 않는다.
|
|
3255
|
+
- Worker는 조건식·수식을 지원한다. 실행 대상 그룹의 함수형 `custom` predicate는 직렬화할 수 없어
|
|
3256
|
+
명시적으로 거부한다. 비활성·대상 레벨 부재 묶음은 Worker 전송에서 제외하되 원본에서 삭제하지 않는다.
|
|
3257
|
+
- 집계 `id`는 선택적이며 생략 시 `getRowGroupAggregateId()`의 결정적 계산 alias를 사용한다.
|
|
3258
|
+
같은 레벨에서 ID가 충돌하면 core는 거부한다. wrapper는 동일 컬럼·함수의 중복 추가·변경을 막으며,
|
|
3259
|
+
같은 컬럼의 다른 함수 집계는 허용한다. 자동 접미사나 UUID를 붙이지 않는다.
|
|
3260
|
+
|
|
3261
|
+
저장본 버전 `0.5`는 wrapper migrator에서 기존 그룹 정렬과 피벗 `byValue`를 새 정렬 구조로 변환한다.
|
|
3262
|
+
새 그룹 필터 편집 UI는 제공하지 않으며, 위 core 설정으로 적용한다.
|
|
3263
|
+
|
|
3150
3264
|
#### ChangesSummary
|
|
3151
3265
|
|
|
3152
3266
|
`grid.changes.getAll()` 반환 타입:
|
|
@@ -3784,6 +3898,7 @@ interface GridConfigSnapshot {
|
|
|
3784
3898
|
showDragHandleColumn?: boolean;
|
|
3785
3899
|
autoFitColumns?: boolean;
|
|
3786
3900
|
showStatusBar?: boolean;
|
|
3901
|
+
summaryRow?: 'none' | 'pinnedTop' | 'pinnedBottom';
|
|
3787
3902
|
locale?: string;
|
|
3788
3903
|
translations?: PartialTranslationMap;
|
|
3789
3904
|
keyFields?: string[];
|
|
@@ -207,8 +207,13 @@ type MozGridCoreProps =
|
|
|
207
207
|
| `useToolBox` | `boolean` | `true` | 툴박스 표시 |
|
|
208
208
|
| `useToolBoxSetting` | `boolean` | `true` | 툴박스 설정(기어) 버튼 표시 |
|
|
209
209
|
| `useExtendFooter` | `boolean` | `true` | 확장 푸터 표시 |
|
|
210
|
-
| `useSummaryFooter` | `boolean` | `false` |
|
|
210
|
+
| `useSummaryFooter` | `boolean` | `false` | 플랫 컬럼 하단 집계 행. 켰을 때 `fields[].aggregate`가 있는 컬럼만 현재 필터 결과로 계산한다. OFF는 footer 전용 계산도 하지 않는다. 컬럼 옵션 → 집계에서 표시·함수 편집 가능 |
|
|
211
211
|
| `useSort` | `boolean` | `true` | 정렬 기능 활성화 |
|
|
212
|
+
| `useRowGroupSettings` | `boolean` | `true` | 그룹 설정 변경 허용. `false`이면 보기 설정의 그룹 패널 토글을 비활성화하고 정보 아이콘에 안내 툴팁 표시. 컨텍스트 메뉴 진입점은 숨기고 그리드 설정의 그룹핑 탭은 읽기 전용. 기존 그룹·그룹별 집계 보존. 런타임 변경 지원 |
|
|
213
|
+
| `useFieldSettings` | `boolean` | `true` | 플랫 왼쪽 컬럼 목록의 표시·순서 변경 허용. false이면 피벗 필드 탭 본문 전체(검색·선택·드롭존·집계 편집)와 옵션 바 드래그를 차단. 옵션 바에는 별도 안내 표시 없이 정렬·필터·닫기는 유지. 고정·너비는 오른쪽 서식 영역에 속하므로 `useFormatSettings`로 제어. 런타임 변경 지원 |
|
|
214
|
+
| `useFormatSettings` | `boolean` | `true` | 헤더명·헤더/셀 서식·표시형식 변경 허용. 플랫·피벗 서식 영역에 적용. `false`이면 툴박스의 값 필드 설정 항목 전체를 비활성화하고 정보 아이콘·안내 툴팁 표시. 피벗에서는 서식 탭 본문 전체(왼쪽 목록·검색·선택·값 필드 설정 포함)를 단일 덮개로 차단. 기존 집계 결과·계산은 유지하며 레이아웃 탭은 `useLayoutSettings`로 별도 제어. 플랫에서 두 필드 권한 중 하나만 false이면 일부 설정 안내와 영역별 차단(검색·선택 유지), 둘 다 false이면 본문 전체 차단. 두 영역을 함께 바꾸는 컬럼 초기화는 둘 다 true일 때만 허용. 기존 설정·계산 보존, 런타임 변경 지원 |
|
|
215
|
+
| `useLayoutSettings` | `boolean` | `true` | 피벗 레이아웃(합계 표시·위치, 소계 기준, 0값 표시, 접기, 요약 모드) 변경 허용. `false`이면 레이아웃 탭은 안내·덮개로 본문 조작 차단, 툴박스 레이아웃 항목은 정보 아이콘·툴팁과 함께 비활성화. 기존 설정·계산 유지, 런타임 변경 지원. 플랫에는 영향 없음 |
|
|
216
|
+
| `useAggregateSettings` | `boolean` | `true` | 집계 탭의 함수·푸터 표시 설정 변경 허용. `false`여도 기존 집계·푸터 표시·계산 유지. 탭 진입은 유지하고 본문 검색·조작은 차단. 런타임 변경 지원 |
|
|
212
217
|
| `useCustomCell` | `boolean` | `true` | 조건부 서식(커스텀 셀) 활성화 |
|
|
213
218
|
| `useContextMenu` | `boolean` | `true` | 컨텍스트 메뉴 활성화 |
|
|
214
219
|
| `useBuiltinTooltip` | `boolean` | `true` | 내장 셀/헤더 툴팁 렌더러 사용. `false`면 wrapper가 툴팁을 그리지 않음 — 코어 `cell:tooltip` 이벤트는 그대로 발행되므로 소비처가 `onReady`의 `grid.on('cell:tooltip', …)`로 직접 렌더 가능(발행은 `tooltipMode`로 제어) |
|
|
@@ -527,7 +532,6 @@ React 어댑터는 Vue 어댑터와 다음 표면이 **다릅니다**. 마이그
|
|
|
527
532
|
|------|------|------|
|
|
528
533
|
| `useViewSelectColumn` | `boolean?` | 컬럼 표시 선택 항목 토글 |
|
|
529
534
|
| `useFixedColumn` | `boolean?` | 컬럼 고정 항목 |
|
|
530
|
-
| `useGroupColumn` | `boolean?` | 컬럼 그룹화 항목 |
|
|
531
535
|
| `useContextMenu` | `boolean?` | 컨텍스트 메뉴 마스터 토글 (`WrapperUIOptions.useContextMenu`와는 별개) |
|
|
532
536
|
| `useSort` | `boolean?` | 정렬 항목 |
|
|
533
537
|
| `useFilter` | `boolean?` | 필터 항목 |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vmscloud/moz-ui-grid-react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.20",
|
|
4
4
|
"description": "MozGrid - React 18+ wrapping library for @vmscloud/moz-ui-grid-core",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"type": "module",
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
"echarts-for-react": "^3.0.2",
|
|
49
49
|
"es-toolkit": "^1.0.0",
|
|
50
50
|
"react-resizable-panels": "^4.11.1",
|
|
51
|
-
"@vmscloud/moz-ui-grid-
|
|
52
|
-
"@vmscloud/moz-ui-grid-
|
|
51
|
+
"@vmscloud/moz-ui-grid-wrapper": "^0.1.14",
|
|
52
|
+
"@vmscloud/moz-ui-grid-core": "^0.1.43"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"dayjs": ">=1.11.0",
|