kokotable 0.95.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/LICENSE +21 -0
- package/README.md +320 -0
- package/contract/table-request.schema.json +424 -0
- package/dist/core/src/adapters/sources.d.ts +59 -0
- package/dist/core/src/adapters/sources.js +235 -0
- package/dist/core/src/client/aggregate.d.ts +94 -0
- package/dist/core/src/client/aggregate.js +222 -0
- package/dist/core/src/client/groupRows.d.ts +40 -0
- package/dist/core/src/client/groupRows.js +145 -0
- package/dist/core/src/client/runClientQuery.d.ts +67 -0
- package/dist/core/src/client/runClientQuery.js +157 -0
- package/dist/core/src/columns/ColumnBuilder.d.ts +121 -0
- package/dist/core/src/columns/ColumnBuilder.js +273 -0
- package/dist/core/src/columns/cascade.d.ts +24 -0
- package/dist/core/src/columns/cascade.js +93 -0
- package/dist/core/src/columns/deriveOperators.d.ts +38 -0
- package/dist/core/src/columns/deriveOperators.js +94 -0
- package/dist/core/src/columns/expandSorting.d.ts +19 -0
- package/dist/core/src/columns/expandSorting.js +52 -0
- package/dist/core/src/columns/helper.d.ts +196 -0
- package/dist/core/src/columns/helper.js +250 -0
- package/dist/core/src/columns/labels.d.ts +12 -0
- package/dist/core/src/columns/labels.js +21 -0
- package/dist/core/src/contract.d.ts +12 -0
- package/dist/core/src/contract.js +12 -0
- package/dist/core/src/contracts/aiColumnMeta.d.ts +102 -0
- package/dist/core/src/contracts/aiColumnMeta.js +197 -0
- package/dist/core/src/contracts/describeColumns.d.ts +48 -0
- package/dist/core/src/contracts/describeColumns.js +40 -0
- package/dist/core/src/contracts/exportData.d.ts +150 -0
- package/dist/core/src/contracts/exportData.js +228 -0
- package/dist/core/src/contracts/index.d.ts +6 -0
- package/dist/core/src/contracts/index.js +12 -0
- package/dist/core/src/contracts/legacyUrl.d.ts +47 -0
- package/dist/core/src/contracts/legacyUrl.js +156 -0
- package/dist/core/src/contracts/preset.d.ts +104 -0
- package/dist/core/src/contracts/preset.js +141 -0
- package/dist/core/src/contracts/presetStore.d.ts +81 -0
- package/dist/core/src/contracts/presetStore.js +146 -0
- package/dist/core/src/contracts/usePresets.d.ts +51 -0
- package/dist/core/src/contracts/usePresets.js +170 -0
- package/dist/core/src/defaults.d.ts +7 -0
- package/dist/core/src/defaults.js +9 -0
- package/dist/core/src/filters/codec.d.ts +20 -0
- package/dist/core/src/filters/codec.js +61 -0
- package/dist/core/src/filters/date.d.ts +30 -0
- package/dist/core/src/filters/date.js +179 -0
- package/dist/core/src/filters/describe.d.ts +45 -0
- package/dist/core/src/filters/describe.js +189 -0
- package/dist/core/src/filters/kind.d.ts +52 -0
- package/dist/core/src/filters/kind.js +110 -0
- package/dist/core/src/filters/kinds/_list.d.ts +13 -0
- package/dist/core/src/filters/kinds/_list.js +42 -0
- package/dist/core/src/filters/kinds/boolean.d.ts +3 -0
- package/dist/core/src/filters/kinds/boolean.js +21 -0
- package/dist/core/src/filters/kinds/cascade.d.ts +6 -0
- package/dist/core/src/filters/kinds/cascade.js +16 -0
- package/dist/core/src/filters/kinds/commonCode.d.ts +3 -0
- package/dist/core/src/filters/kinds/commonCode.js +13 -0
- package/dist/core/src/filters/kinds/date.d.ts +9 -0
- package/dist/core/src/filters/kinds/date.js +32 -0
- package/dist/core/src/filters/kinds/enum.d.ts +4 -0
- package/dist/core/src/filters/kinds/enum.js +13 -0
- package/dist/core/src/filters/kinds/index.d.ts +49 -0
- package/dist/core/src/filters/kinds/index.js +39 -0
- package/dist/core/src/filters/kinds/linear.d.ts +5 -0
- package/dist/core/src/filters/kinds/linear.js +16 -0
- package/dist/core/src/filters/kinds/number.d.ts +5 -0
- package/dist/core/src/filters/kinds/number.js +19 -0
- package/dist/core/src/filters/kinds/period.d.ts +4 -0
- package/dist/core/src/filters/kinds/period.js +17 -0
- package/dist/core/src/filters/kinds/relation.d.ts +5 -0
- package/dist/core/src/filters/kinds/relation.js +17 -0
- package/dist/core/src/filters/kinds/schedule.d.ts +5 -0
- package/dist/core/src/filters/kinds/schedule.js +16 -0
- package/dist/core/src/filters/kinds/text.d.ts +4 -0
- package/dist/core/src/filters/kinds/text.js +18 -0
- package/dist/core/src/filters/linear.d.ts +33 -0
- package/dist/core/src/filters/linear.js +65 -0
- package/dist/core/src/filters/list.d.ts +32 -0
- package/dist/core/src/filters/list.js +87 -0
- package/dist/core/src/filters/number.d.ts +17 -0
- package/dist/core/src/filters/number.js +82 -0
- package/dist/core/src/filters/registry.d.ts +23 -0
- package/dist/core/src/filters/registry.js +121 -0
- package/dist/core/src/filters/relation.d.ts +26 -0
- package/dist/core/src/filters/relation.js +75 -0
- package/dist/core/src/filters/schedule.d.ts +21 -0
- package/dist/core/src/filters/schedule.js +60 -0
- package/dist/core/src/filters/text.d.ts +44 -0
- package/dist/core/src/filters/text.js +127 -0
- package/dist/core/src/hooks/index.d.ts +6 -0
- package/dist/core/src/hooks/index.js +6 -0
- package/dist/core/src/hooks/useDataTable.d.ts +13 -0
- package/dist/core/src/hooks/useDataTable.js +109 -0
- package/dist/core/src/hooks/useGrouping.d.ts +33 -0
- package/dist/core/src/hooks/useGrouping.js +57 -0
- package/dist/core/src/hooks/useSearchHistory.d.ts +20 -0
- package/dist/core/src/hooks/useSearchHistory.js +52 -0
- package/dist/core/src/hooks/useTableData.d.ts +25 -0
- package/dist/core/src/hooks/useTableData.js +49 -0
- package/dist/core/src/hooks/useTableFromDefinition.d.ts +47 -0
- package/dist/core/src/hooks/useTableFromDefinition.js +174 -0
- package/dist/core/src/hooks/useTableSearch.d.ts +10 -0
- package/dist/core/src/hooks/useTableSearch.js +434 -0
- package/dist/core/src/hooks/useUrlSync.d.ts +64 -0
- package/dist/core/src/hooks/useUrlSync.js +145 -0
- package/dist/core/src/index.d.ts +38 -0
- package/dist/core/src/index.js +43 -0
- package/dist/core/src/pivot/runClientPivot.d.ts +101 -0
- package/dist/core/src/pivot/runClientPivot.js +230 -0
- package/dist/core/src/pivot/transforms.d.ts +19 -0
- package/dist/core/src/pivot/transforms.js +105 -0
- package/dist/core/src/registry.d.ts +46 -0
- package/dist/core/src/registry.js +67 -0
- package/dist/core/src/types/column.d.ts +213 -0
- package/dist/core/src/types/column.js +1 -0
- package/dist/core/src/types/data.d.ts +63 -0
- package/dist/core/src/types/data.js +1 -0
- package/dist/core/src/types/definition.d.ts +239 -0
- package/dist/core/src/types/definition.js +59 -0
- package/dist/core/src/types/filter.d.ts +94 -0
- package/dist/core/src/types/filter.js +1 -0
- package/dist/core/src/types/filterKind.d.ts +204 -0
- package/dist/core/src/types/filterKind.js +1 -0
- package/dist/core/src/types/grouping.d.ts +80 -0
- package/dist/core/src/types/grouping.js +4 -0
- package/dist/core/src/types/index.d.ts +8 -0
- package/dist/core/src/types/index.js +8 -0
- package/dist/core/src/types/operators.d.ts +64 -0
- package/dist/core/src/types/operators.js +108 -0
- package/dist/core/src/types/request.d.ts +114 -0
- package/dist/core/src/types/request.js +1 -0
- package/dist/core/src/types/search.d.ts +112 -0
- package/dist/core/src/types/search.js +1 -0
- package/dist/core/src/types/sources.d.ts +84 -0
- package/dist/core/src/types/sources.js +1 -0
- package/dist/core/src/types/table.d.ts +40 -0
- package/dist/core/src/types/table.js +1 -0
- package/dist/core/src/utils/compare.d.ts +13 -0
- package/dist/core/src/utils/compare.js +53 -0
- package/dist/core/src/utils/dateText.d.ts +12 -0
- package/dist/core/src/utils/dateText.js +30 -0
- package/dist/core/src/utils/getValue.d.ts +9 -0
- package/dist/core/src/utils/getValue.js +32 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/mui/src/TableLayout.d.ts +75 -0
- package/dist/mui/src/TableLayout.js +162 -0
- package/dist/mui/src/TableScreen.d.ts +70 -0
- package/dist/mui/src/TableScreen.js +174 -0
- package/dist/mui/src/addons/FilterModal.d.ts +45 -0
- package/dist/mui/src/addons/FilterModal.js +39 -0
- package/dist/mui/src/addons/FilterStatusModal.d.ts +40 -0
- package/dist/mui/src/addons/FilterStatusModal.js +68 -0
- package/dist/mui/src/addons/PresetBar.d.ts +56 -0
- package/dist/mui/src/addons/PresetBar.js +145 -0
- package/dist/mui/src/addons/ShareDropdown.d.ts +35 -0
- package/dist/mui/src/addons/ShareDropdown.js +41 -0
- package/dist/mui/src/addons/searchStore.d.ts +44 -0
- package/dist/mui/src/addons/searchStore.js +112 -0
- package/dist/mui/src/addons/searchSummary.d.ts +106 -0
- package/dist/mui/src/addons/searchSummary.js +109 -0
- package/dist/mui/src/columns/displayColumns.d.ts +100 -0
- package/dist/mui/src/columns/displayColumns.js +174 -0
- package/dist/mui/src/content/CardContent.d.ts +24 -0
- package/dist/mui/src/content/CardContent.js +25 -0
- package/dist/mui/src/content/ColumnMenu.d.ts +43 -0
- package/dist/mui/src/content/ColumnMenu.js +40 -0
- package/dist/mui/src/content/ColumnVisibilityMenu.d.ts +14 -0
- package/dist/mui/src/content/ColumnVisibilityMenu.js +37 -0
- package/dist/mui/src/content/EditCell.d.ts +19 -0
- package/dist/mui/src/content/EditCell.js +61 -0
- package/dist/mui/src/content/HeaderCell.d.ts +59 -0
- package/dist/mui/src/content/HeaderCell.js +88 -0
- package/dist/mui/src/content/SelectionActionBar.d.ts +17 -0
- package/dist/mui/src/content/SelectionActionBar.js +19 -0
- package/dist/mui/src/content/SortControl.d.ts +17 -0
- package/dist/mui/src/content/SortControl.js +45 -0
- package/dist/mui/src/content/TableContent.d.ts +191 -0
- package/dist/mui/src/content/TableContent.js +525 -0
- package/dist/mui/src/content/TableErrorFallback.d.ts +24 -0
- package/dist/mui/src/content/TableErrorFallback.js +29 -0
- package/dist/mui/src/content/cellError.d.ts +13 -0
- package/dist/mui/src/content/cellError.js +20 -0
- package/dist/mui/src/content/cellRenderers.d.ts +71 -0
- package/dist/mui/src/content/cellRenderers.js +127 -0
- package/dist/mui/src/content/cellValue.d.ts +27 -0
- package/dist/mui/src/content/cellValue.js +82 -0
- package/dist/mui/src/content/columnOrder.d.ts +7 -0
- package/dist/mui/src/content/columnOrder.js +48 -0
- package/dist/mui/src/content/density.d.ts +13 -0
- package/dist/mui/src/content/density.js +12 -0
- package/dist/mui/src/content/menuItems.d.ts +118 -0
- package/dist/mui/src/content/menuItems.js +128 -0
- package/dist/mui/src/content/pinning.d.ts +17 -0
- package/dist/mui/src/content/pinning.js +65 -0
- package/dist/mui/src/exporters/index.d.ts +1 -0
- package/dist/mui/src/exporters/index.js +1 -0
- package/dist/mui/src/exporters/useExportFormatters.d.ts +13 -0
- package/dist/mui/src/exporters/useExportFormatters.js +17 -0
- package/dist/mui/src/filter/FilterArea.d.ts +40 -0
- package/dist/mui/src/filter/FilterArea.js +37 -0
- package/dist/mui/src/filter/FilterInput.d.ts +14 -0
- package/dist/mui/src/filter/FilterInput.js +18 -0
- package/dist/mui/src/filter/inputs/DateFilterInput.d.ts +14 -0
- package/dist/mui/src/filter/inputs/DateFilterInput.js +112 -0
- package/dist/mui/src/filter/inputs/LinearFilterInput.d.ts +10 -0
- package/dist/mui/src/filter/inputs/LinearFilterInput.js +35 -0
- package/dist/mui/src/filter/inputs/NumberFilterInput.d.ts +12 -0
- package/dist/mui/src/filter/inputs/NumberFilterInput.js +111 -0
- package/dist/mui/src/filter/inputs/OperatorMenu.d.ts +14 -0
- package/dist/mui/src/filter/inputs/OperatorMenu.js +25 -0
- package/dist/mui/src/filter/inputs/RelationFilterInput.d.ts +11 -0
- package/dist/mui/src/filter/inputs/RelationFilterInput.js +67 -0
- package/dist/mui/src/filter/inputs/ScheduleFilterInput.d.ts +8 -0
- package/dist/mui/src/filter/inputs/ScheduleFilterInput.js +17 -0
- package/dist/mui/src/filter/inputs/SelectFilterInput.d.ts +16 -0
- package/dist/mui/src/filter/inputs/SelectFilterInput.js +57 -0
- package/dist/mui/src/filter/inputs/TextFilterInput.d.ts +13 -0
- package/dist/mui/src/filter/inputs/TextFilterInput.js +55 -0
- package/dist/mui/src/filter/kinds.d.ts +58 -0
- package/dist/mui/src/filter/kinds.js +103 -0
- package/dist/mui/src/grouping/AggregateChip.d.ts +55 -0
- package/dist/mui/src/grouping/AggregateChip.js +128 -0
- package/dist/mui/src/grouping/AggregationChips.d.ts +49 -0
- package/dist/mui/src/grouping/AggregationChips.js +80 -0
- package/dist/mui/src/grouping/AggregationSettingsButton.d.ts +14 -0
- package/dist/mui/src/grouping/AggregationSettingsButton.js +19 -0
- package/dist/mui/src/grouping/GroupingBar.d.ts +59 -0
- package/dist/mui/src/grouping/GroupingBar.js +267 -0
- package/dist/mui/src/grouping/StepExpandButton.d.ts +12 -0
- package/dist/mui/src/grouping/StepExpandButton.js +18 -0
- package/dist/mui/src/grouping/groupRow.d.ts +68 -0
- package/dist/mui/src/grouping/groupRow.js +129 -0
- package/dist/mui/src/headers/defaultHeader.d.ts +28 -0
- package/dist/mui/src/headers/defaultHeader.js +90 -0
- package/dist/mui/src/headers/defineHeader.d.ts +21 -0
- package/dist/mui/src/headers/defineHeader.js +68 -0
- package/dist/mui/src/headers/index.d.ts +5 -0
- package/dist/mui/src/headers/index.js +3 -0
- package/dist/mui/src/headers/meta.d.ts +18 -0
- package/dist/mui/src/headers/meta.js +11 -0
- package/dist/mui/src/headers/types.d.ts +84 -0
- package/dist/mui/src/headers/types.js +1 -0
- package/dist/mui/src/index.d.ts +110 -0
- package/dist/mui/src/index.js +79 -0
- package/dist/mui/src/layout/ResizeHandle.d.ts +30 -0
- package/dist/mui/src/layout/ResizeHandle.js +66 -0
- package/dist/mui/src/menus/columnMenu.d.ts +45 -0
- package/dist/mui/src/menus/columnMenu.js +144 -0
- package/dist/mui/src/menus/copy.d.ts +5 -0
- package/dist/mui/src/menus/copy.js +25 -0
- package/dist/mui/src/menus/index.d.ts +6 -0
- package/dist/mui/src/menus/index.js +4 -0
- package/dist/mui/src/menus/resolve.d.ts +15 -0
- package/dist/mui/src/menus/resolve.js +60 -0
- package/dist/mui/src/menus/rowMenu.d.ts +46 -0
- package/dist/mui/src/menus/rowMenu.js +76 -0
- package/dist/mui/src/pagination/PaginationArea.d.ts +16 -0
- package/dist/mui/src/pagination/PaginationArea.js +23 -0
- package/dist/mui/src/pivot/PivotTable.d.ts +18 -0
- package/dist/mui/src/pivot/PivotTable.js +100 -0
- package/dist/mui/src/provider/KokoTableProvider.d.ts +184 -0
- package/dist/mui/src/provider/KokoTableProvider.js +118 -0
- package/dist/mui/src/provider/labels.d.ts +85 -0
- package/dist/mui/src/provider/labels.js +104 -0
- package/dist/mui/src/registry.d.ts +30 -0
- package/dist/mui/src/registry.js +5 -0
- package/dist/mui/src/toolbar/GlobalFilterField.d.ts +36 -0
- package/dist/mui/src/toolbar/GlobalFilterField.js +78 -0
- package/dist/mui/src/virtual/VirtualTableContent.d.ts +41 -0
- package/dist/mui/src/virtual/VirtualTableContent.js +58 -0
- package/dist/mui/src/virtual/VirtualTableScreen.d.ts +13 -0
- package/dist/mui/src/virtual/VirtualTableScreen.js +23 -0
- package/dist/mui/src/virtual.d.ts +4 -0
- package/dist/mui/src/virtual.js +4 -0
- package/dist/mui/src/virtualColumns/VirtualColumnCard.d.ts +26 -0
- package/dist/mui/src/virtualColumns/VirtualColumnCard.js +29 -0
- package/dist/mui/src/virtualColumns/VirtualColumnDialog.d.ts +27 -0
- package/dist/mui/src/virtualColumns/VirtualColumnDialog.js +154 -0
- package/dist/mui/src/virtualColumns/VirtualColumnSection.d.ts +31 -0
- package/dist/mui/src/virtualColumns/VirtualColumnSection.js +55 -0
- package/dist/mui/src/virtualColumns/expression.d.ts +68 -0
- package/dist/mui/src/virtualColumns/expression.js +489 -0
- package/dist/mui/src/virtualColumns/useVirtualColumns.d.ts +67 -0
- package/dist/mui/src/virtualColumns/useVirtualColumns.js +111 -0
- package/dist/mui/src/virtualColumns/virtualColumnDefs.d.ts +29 -0
- package/dist/mui/src/virtualColumns/virtualColumnDefs.js +51 -0
- package/dist/mui-virtual.d.ts +1 -0
- package/dist/mui-virtual.js +2 -0
- package/dist/mui.d.ts +1 -0
- package/dist/mui.js +2 -0
- package/dist/query/src/index.d.ts +6 -0
- package/dist/query/src/index.js +7 -0
- package/dist/query/src/serverPivot.d.ts +42 -0
- package/dist/query/src/serverPivot.js +153 -0
- package/dist/query/src/useServerGrouping.d.ts +52 -0
- package/dist/query/src/useServerGrouping.js +186 -0
- package/dist/query/src/useServerTable.d.ts +20 -0
- package/dist/query/src/useServerTable.js +106 -0
- package/dist/query/src/useServerTableData.d.ts +48 -0
- package/dist/query/src/useServerTableData.js +64 -0
- package/dist/query/src/wire.d.ts +16 -0
- package/dist/query/src/wire.js +32 -0
- package/dist/query.d.ts +1 -0
- package/dist/query.js +2 -0
- package/package.json +125 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { MenuItem, Pagination, Stack, TextField, Typography } from "@mui/material";
|
|
3
|
+
import { toPaginationSource } from "../../../core/src/index";
|
|
4
|
+
import { useKokoTableConfig } from "../provider/KokoTableProvider";
|
|
5
|
+
/**
|
|
6
|
+
* 페이지네이션 구역.
|
|
7
|
+
*
|
|
8
|
+
* `PaginationSource` 만 요구하므로 테이블 인스턴스가 없어도 붙는다 —
|
|
9
|
+
* 카드 화면에서는 `paginationSource(search, data)` 를 넘긴다.
|
|
10
|
+
*/
|
|
11
|
+
export function PaginationArea({ source, pageSizeOptions: pageSizeOptionsProp, showTotal = true, }) {
|
|
12
|
+
const { defaults } = useKokoTableConfig();
|
|
13
|
+
const pageSizeOptions = pageSizeOptionsProp ?? defaults.pageSizeOptions;
|
|
14
|
+
const pagination = toPaginationSource(source);
|
|
15
|
+
const { pageIndex, pageSize, total, pageCount } = pagination.getPagination();
|
|
16
|
+
// 선택지에 없는 크기(프리셋 복원 등)도 드롭다운에 보여야 사용자가 현재 값을 안다
|
|
17
|
+
const sizes = pageSizeOptions.includes(pageSize)
|
|
18
|
+
? pageSizeOptions
|
|
19
|
+
: [...pageSizeOptions, pageSize].sort((a, b) => a - b);
|
|
20
|
+
const from = total === 0 ? 0 : pageIndex * pageSize + 1;
|
|
21
|
+
const to = Math.min((pageIndex + 1) * pageSize, total);
|
|
22
|
+
return (_jsxs(Stack, { direction: "row", alignItems: "center", justifyContent: "space-between", spacing: 2, sx: { py: 1, flexWrap: "wrap", gap: 1 }, children: [showTotal && (_jsx(Typography, { variant: "body2", color: "text.secondary", children: total === 0 ? "0건" : `${from.toLocaleString("ko-KR")}–${to.toLocaleString("ko-KR")} / ${total.toLocaleString("ko-KR")}건` })), _jsxs(Stack, { direction: "row", alignItems: "center", spacing: 2, children: [_jsx(TextField, { select: true, size: "small", variant: "standard", value: pageSize, onChange: (event) => pagination.setPageSize(Number(event.target.value)), sx: { width: 90 }, slotProps: { htmlInput: { "aria-label": "페이지당 행 수" } }, children: sizes.map((size) => (_jsxs(MenuItem, { value: size, children: [size, "\uD589"] }, size))) }), _jsx(Pagination, { size: "small", shape: "rounded", count: Math.max(pageCount, 1), page: pageIndex + 1, onChange: (_event, page) => pagination.setPageIndex(page - 1), disabled: pageCount <= 1 })] })] }));
|
|
23
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { PivotResult } from "../../../core/src/index";
|
|
2
|
+
export interface PivotTableProps {
|
|
3
|
+
result: PivotResult;
|
|
4
|
+
/** 보여줄 값 키. 미지정이면 첫 번째 하나만 (여러 개면 셀이 빽빽해진다) */
|
|
5
|
+
valueKey?: string;
|
|
6
|
+
formatValue?: (value: unknown) => string;
|
|
7
|
+
/** 총계 열 표시 */
|
|
8
|
+
showTotal?: boolean;
|
|
9
|
+
maxHeight?: number | string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 피벗 결과 표.
|
|
13
|
+
*
|
|
14
|
+
* 행 축은 트리라 접고 펼 수 있고, 열 축은 중첩 헤더로 그린다.
|
|
15
|
+
* 두 축이 동등하므로 전환은 `transposePivot(spec)` 으로 데이터 쪽에서 처리한다 —
|
|
16
|
+
* 이 컴포넌트는 축의 의미를 모른다.
|
|
17
|
+
*/
|
|
18
|
+
export declare function PivotTable({ result, valueKey, formatValue, showTotal, maxHeight, }: PivotTableProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment, useMemo, useState } from "react";
|
|
3
|
+
import { Alert, Box, IconButton, Stack, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Typography, } from "@mui/material";
|
|
4
|
+
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
|
|
5
|
+
import KeyboardArrowRightIcon from "@mui/icons-material/KeyboardArrowRight";
|
|
6
|
+
const defaultFormat = (value) => {
|
|
7
|
+
if (value === null || value === undefined)
|
|
8
|
+
return "";
|
|
9
|
+
if (typeof value === "number") {
|
|
10
|
+
return Number.isInteger(value) ? value.toLocaleString("ko-KR") : value.toFixed(2);
|
|
11
|
+
}
|
|
12
|
+
return String(value);
|
|
13
|
+
};
|
|
14
|
+
/** 헤더 레벨별로 노드를 모은다 — 중첩 헤더를 행으로 펼치기 위해 */
|
|
15
|
+
function headerLevels(nodes) {
|
|
16
|
+
const levels = [];
|
|
17
|
+
const walk = (list, depth) => {
|
|
18
|
+
if (list.length === 0)
|
|
19
|
+
return;
|
|
20
|
+
if (!levels[depth])
|
|
21
|
+
levels[depth] = [];
|
|
22
|
+
levels[depth].push(...list);
|
|
23
|
+
for (const node of list)
|
|
24
|
+
if (node.children)
|
|
25
|
+
walk(node.children, depth + 1);
|
|
26
|
+
};
|
|
27
|
+
walk(nodes, 0);
|
|
28
|
+
return levels;
|
|
29
|
+
}
|
|
30
|
+
/** 이 노드가 차지하는 leaf 열 수 */
|
|
31
|
+
function leafSpan(node) {
|
|
32
|
+
if (!node.children || node.children.length === 0)
|
|
33
|
+
return 1;
|
|
34
|
+
return node.children.reduce((sum, child) => sum + leafSpan(child), 0);
|
|
35
|
+
}
|
|
36
|
+
function collectRowKeys(rows) {
|
|
37
|
+
const keys = [];
|
|
38
|
+
const walk = (list) => {
|
|
39
|
+
for (const row of list) {
|
|
40
|
+
keys.push(row.key);
|
|
41
|
+
if (row.children)
|
|
42
|
+
walk(row.children);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
walk(rows);
|
|
46
|
+
return keys;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 피벗 결과 표.
|
|
50
|
+
*
|
|
51
|
+
* 행 축은 트리라 접고 펼 수 있고, 열 축은 중첩 헤더로 그린다.
|
|
52
|
+
* 두 축이 동등하므로 전환은 `transposePivot(spec)` 으로 데이터 쪽에서 처리한다 —
|
|
53
|
+
* 이 컴포넌트는 축의 의미를 모른다.
|
|
54
|
+
*/
|
|
55
|
+
export function PivotTable({ result, valueKey, formatValue = defaultFormat, showTotal = true, maxHeight, }) {
|
|
56
|
+
const key = valueKey ?? result.valueKeys[0];
|
|
57
|
+
const levels = useMemo(() => headerLevels(result.columns), [result.columns]);
|
|
58
|
+
const [collapsed, setCollapsed] = useState(new Set());
|
|
59
|
+
const allKeys = useMemo(() => collectRowKeys(result.rows), [result.rows]);
|
|
60
|
+
void allKeys;
|
|
61
|
+
/**
|
|
62
|
+
* 열 합계. 코어가 `PivotResult.colTotals`(leaf 키 → 값 키 → 집계값) 를 주면 그것을 쓴다 —
|
|
63
|
+
* AVG/COUNT_DISTINCT 는 행 합계를 더해서 만들 수 없다. 아직 없으면 SUM 에서만 맞는
|
|
64
|
+
* 예전 방식(행 값 합산)으로 되돌아간다.
|
|
65
|
+
*/
|
|
66
|
+
const colTotals = result.colTotals;
|
|
67
|
+
if (!key)
|
|
68
|
+
return _jsx(Alert, { severity: "warning", children: "\uD45C\uC2DC\uD560 \uC9D1\uACC4 \uAC12\uC774 \uC5C6\uC2B5\uB2C8\uB2E4" });
|
|
69
|
+
const toggle = (rowKey) => setCollapsed((prev) => {
|
|
70
|
+
const next = new Set(prev);
|
|
71
|
+
if (next.has(rowKey))
|
|
72
|
+
next.delete(rowKey);
|
|
73
|
+
else
|
|
74
|
+
next.add(rowKey);
|
|
75
|
+
return next;
|
|
76
|
+
});
|
|
77
|
+
const renderRows = (rows) => rows.map((row) => {
|
|
78
|
+
const isCollapsed = collapsed.has(row.key);
|
|
79
|
+
const hasChildren = !!row.children && row.children.length > 0;
|
|
80
|
+
return (_jsxs(Fragment, { children: [_jsxs(TableRow, { hover: true, children: [_jsx(TableCell, { sx: {
|
|
81
|
+
pl: 1 + row.depth * 2,
|
|
82
|
+
whiteSpace: "nowrap",
|
|
83
|
+
position: "sticky", left: 0, zIndex: 1,
|
|
84
|
+
backgroundColor: "background.paper",
|
|
85
|
+
fontWeight: hasChildren ? 600 : 400,
|
|
86
|
+
}, children: _jsxs(Stack, { direction: "row", alignItems: "center", spacing: 0.5, children: [hasChildren ? (_jsx(IconButton, { size: "small", "aria-label": isCollapsed ? "펼치기" : "접기", onClick: () => toggle(row.key), children: isCollapsed ? _jsx(KeyboardArrowRightIcon, { fontSize: "small" }) : _jsx(KeyboardArrowDownIcon, { fontSize: "small" }) })) : (_jsx(Box, { sx: { width: 30 } })), _jsx("span", { children: row.label })] }) }), result.leafKeys.map((leafKey) => (_jsx(TableCell, { align: "right", sx: { whiteSpace: "nowrap" }, children: formatValue(row.cells[leafKey]?.[key]) }, leafKey))), showTotal && (_jsx(TableCell, { align: "right", sx: { fontWeight: 600, whiteSpace: "nowrap" }, children: formatValue(row.total[key]) }))] }), hasChildren && !isCollapsed && renderRows(row.children)] }, row.key));
|
|
87
|
+
});
|
|
88
|
+
return (_jsxs(Stack, { spacing: 1, children: [result.droppedColumns > 0 && (_jsxs(Alert, { severity: "info", sx: { py: 0 }, children: ["\uC5F4\uC774 \uB9CE\uC544 ", result.droppedColumns, "\uAC1C\uB97C \uC81C\uC678\uD588\uC2B5\uB2C8\uB2E4 \u2014 \uC0C1\uD55C\uC744 \uC62C\uB9AC\uAC70\uB098 \uC870\uAC74\uC744 \uC881\uD600 \uC8FC\uC138\uC694"] })), _jsx(TableContainer, { sx: { maxHeight, border: "1px solid", borderColor: "divider", borderRadius: 1 }, children: _jsxs(Table, { stickyHeader: true, size: "small", children: [_jsx(TableHead, { children: levels.map((level, depth) => (_jsxs(TableRow, { children: [depth === 0 && (_jsx(TableCell, { rowSpan: levels.length, sx: {
|
|
89
|
+
position: "sticky", left: 0, zIndex: 3,
|
|
90
|
+
backgroundColor: "background.paper", fontWeight: 600,
|
|
91
|
+
} })), level.map((node) => (_jsx(TableCell, { align: "center", colSpan: leafSpan(node), sx: { fontWeight: 600, whiteSpace: "nowrap", backgroundColor: "background.paper" }, children: node.label }, node.key))), depth === 0 && showTotal && (_jsx(TableCell, { rowSpan: levels.length, align: "right", sx: { fontWeight: 700, backgroundColor: "background.paper", whiteSpace: "nowrap" }, children: "\uD569\uACC4" }))] }, depth))) }), _jsx(TableBody, { children: result.rows.length === 0 ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: result.leafKeys.length + (showTotal ? 2 : 1), sx: { py: 6, textAlign: "center" }, children: _jsx(Typography, { variant: "body2", color: "text.secondary", children: "\uD45C\uC2DC\uD560 \uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4" }) }) })) : (_jsxs(_Fragment, { children: [renderRows(result.rows), showTotal && (_jsxs(TableRow, { sx: { backgroundColor: "action.hover" }, children: [_jsx(TableCell, { sx: { fontWeight: 700, position: "sticky", left: 0, zIndex: 1, backgroundColor: "inherit" }, children: "\uD569\uACC4" }), result.leafKeys.map((leafKey) => {
|
|
92
|
+
const columnTotal = colTotals
|
|
93
|
+
? colTotals[leafKey]?.[key]
|
|
94
|
+
: result.rows.reduce((sum, row) => {
|
|
95
|
+
const value = row.cells[leafKey]?.[key];
|
|
96
|
+
return typeof value === "number" ? sum + value : sum;
|
|
97
|
+
}, 0);
|
|
98
|
+
return (_jsx(TableCell, { align: "right", sx: { fontWeight: 700 }, children: formatValue(columnTotal) }, leafKey));
|
|
99
|
+
}), _jsx(TableCell, { align: "right", sx: { fontWeight: 700 }, children: formatValue(result.grandTotal[key]) })] }))] })) })] }) })] }));
|
|
100
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { type ComponentType, type ReactNode } from "react";
|
|
2
|
+
import type { Cell, Column, Row, RowData, Table } from "@tanstack/react-table";
|
|
3
|
+
import type { AggregateResult, CellRenderProps as CoreCellRenderProps, ColumnDataType, ColumnMeta, FilterRender, FilterVariant, GroupTreeNode } from "../../../core/src/index";
|
|
4
|
+
import type { HeaderCellProps } from "../content/HeaderCell";
|
|
5
|
+
import type { ColumnMenuProps } from "../content/ColumnMenu";
|
|
6
|
+
import type { TableErrorFallbackProps } from "../content/TableErrorFallback";
|
|
7
|
+
import type { EditCellProps } from "../content/EditCell";
|
|
8
|
+
import type { AggregateChipProps } from "../grouping/AggregateChip";
|
|
9
|
+
import type { Density } from "../content/density";
|
|
10
|
+
import type { GroupRowLayout, GroupedColumnMode } from "../content/TableContent";
|
|
11
|
+
import { type KokoTableLabels, type KokoTableLabelsInput } from "./labels";
|
|
12
|
+
import { applyPatch, toRegistry, type AggregationDef, type CellRendererDef, type ExportFormatterDef, type Registry } from "../registry";
|
|
13
|
+
import type { HeaderDef } from "../headers/types";
|
|
14
|
+
import { type ColumnMenuItemDef, type ColumnMenuPatch } from "../menus/columnMenu";
|
|
15
|
+
import { type RowMenuItemDef, type RowMenuPatch } from "../menus/rowMenu";
|
|
16
|
+
export interface EmptyStateProps {
|
|
17
|
+
message: ReactNode;
|
|
18
|
+
table: Table<any>;
|
|
19
|
+
columnCount: number;
|
|
20
|
+
}
|
|
21
|
+
export interface LoadingSkeletonProps {
|
|
22
|
+
rows: number;
|
|
23
|
+
columns: Array<Column<any, unknown>>;
|
|
24
|
+
columnCount: number;
|
|
25
|
+
size: "small" | "medium";
|
|
26
|
+
}
|
|
27
|
+
/** 그룹 행 전체를 교체할 때 받는 것. `<TableRow>` 하나를 돌려줘야 한다 */
|
|
28
|
+
export interface GroupRowRenderContext<T extends RowData = any> {
|
|
29
|
+
node: GroupTreeNode<T>;
|
|
30
|
+
depth: number;
|
|
31
|
+
/** 지금 그려지는 순서의 리프 컬럼 (열 가상화·그룹 컬럼 재배치 반영) */
|
|
32
|
+
columns: Array<Column<T, unknown>>;
|
|
33
|
+
aggregates: AggregateResult;
|
|
34
|
+
toggle: () => void;
|
|
35
|
+
expanded: boolean;
|
|
36
|
+
table: Table<T>;
|
|
37
|
+
columnCount: number;
|
|
38
|
+
/** 이 depth 의 그룹 기준 컬럼 (없으면 숨김·제거된 것) */
|
|
39
|
+
groupColumn?: Column<T, unknown>;
|
|
40
|
+
/** 기본 규칙으로 해석한 그룹값 라벨 */
|
|
41
|
+
groupValue: ReactNode;
|
|
42
|
+
/** 기본 행 props — `data-index`·ref·onClick·sx. 그대로 펼치면 가상화·키보드가 유지된다 */
|
|
43
|
+
rowProps: Record<string, unknown>;
|
|
44
|
+
}
|
|
45
|
+
export interface DetailPanelRowContext<T extends RowData = any> {
|
|
46
|
+
row: Row<T>;
|
|
47
|
+
table: Table<T>;
|
|
48
|
+
columnCount: number;
|
|
49
|
+
/** `renderDetailPanel(row, table)` 결과 */
|
|
50
|
+
content: ReactNode;
|
|
51
|
+
}
|
|
52
|
+
export interface KokoTableComponents {
|
|
53
|
+
HeaderCell: ComponentType<HeaderCellProps<any>>;
|
|
54
|
+
ColumnMenu: ComponentType<ColumnMenuProps<any>>;
|
|
55
|
+
EmptyState: ComponentType<EmptyStateProps>;
|
|
56
|
+
ErrorFallback: ComponentType<TableErrorFallbackProps>;
|
|
57
|
+
/** `<tr>` 들을 돌려준다 — `<tbody>` 안에 놓인다 */
|
|
58
|
+
LoadingSkeleton: ComponentType<LoadingSkeletonProps>;
|
|
59
|
+
AggregateChip: ComponentType<AggregateChipProps>;
|
|
60
|
+
/** 그룹 행 전체 교체 */
|
|
61
|
+
GroupRow: (ctx: GroupRowRenderContext<any>) => ReactNode;
|
|
62
|
+
/** 펼친 행 아래 상세 패널 행 전체 교체 */
|
|
63
|
+
DetailPanelRow: (ctx: DetailPanelRowContext<any>) => ReactNode;
|
|
64
|
+
EditCell: ComponentType<EditCellProps<any>>;
|
|
65
|
+
}
|
|
66
|
+
/** Provider 셀 렌더러가 받는 것 — 코어 `CellRenderProps` 에 인스턴스를 더한 것 */
|
|
67
|
+
export interface CellRendererProps<T extends RowData = any> extends CoreCellRenderProps<T> {
|
|
68
|
+
cell: Cell<T, unknown>;
|
|
69
|
+
column: Column<T, unknown>;
|
|
70
|
+
table: Table<T>;
|
|
71
|
+
meta?: ColumnMeta;
|
|
72
|
+
/** `link` 렌더러에만 — `meta.link.to()` 결과 */
|
|
73
|
+
href?: string;
|
|
74
|
+
}
|
|
75
|
+
export type CellRendererKey = ColumnDataType | "link" | "chip" | "placeholder";
|
|
76
|
+
export type CellRenderer<T extends RowData = any> = (props: CellRendererProps<T>) => ReactNode;
|
|
77
|
+
export type KokoCellRenderers = Partial<Record<CellRendererKey, CellRenderer>>;
|
|
78
|
+
export type KokoFilterInputs = Partial<Record<FilterVariant, FilterRender<any>>>;
|
|
79
|
+
export interface KokoTableDefaults {
|
|
80
|
+
density?: Density;
|
|
81
|
+
pageSizeOptions: number[];
|
|
82
|
+
skeletonRows: number;
|
|
83
|
+
groupRowLayout: GroupRowLayout;
|
|
84
|
+
groupedColumnMode: GroupedColumnMode;
|
|
85
|
+
enableColumnMenu: boolean;
|
|
86
|
+
stickyHeader: boolean;
|
|
87
|
+
maxHeight?: number | string;
|
|
88
|
+
/** 검색 입력 debounce(ms) — 값만 내려준다. 실제 적용은 검색 훅·입력 컴포넌트 몫 */
|
|
89
|
+
debounceMs: number;
|
|
90
|
+
}
|
|
91
|
+
export declare const DEFAULT_TABLE_DEFAULTS: KokoTableDefaults;
|
|
92
|
+
/** 필터 kind 의 표시 부분 — 의미(predicate·serialize)는 core 의 kind 가, 편집기·칩은 여기가 맡는다 */
|
|
93
|
+
export interface FilterKindUi {
|
|
94
|
+
editor?: FilterRender<any>;
|
|
95
|
+
chip?: (value: unknown, operator: string) => ReactNode;
|
|
96
|
+
}
|
|
97
|
+
export type KokoFilterKinds = Record<string, FilterKindUi>;
|
|
98
|
+
/** 해석된 메뉴 레지스트리 — `ColumnMenu`/`TableContent` 가 항목을 여기서 꺼낸다 */
|
|
99
|
+
export interface KokoTableMenus {
|
|
100
|
+
column: Registry<ColumnMenuItemDef<any>>;
|
|
101
|
+
row: Registry<RowMenuItemDef<any>>;
|
|
102
|
+
}
|
|
103
|
+
export interface KokoTableMenusInput {
|
|
104
|
+
column?: ColumnMenuPatch<any>;
|
|
105
|
+
row?: RowMenuPatch<any>;
|
|
106
|
+
}
|
|
107
|
+
/** 셀 렌더러 · 집계 · export 포맷터 레지스트리 — 항목 타입은 각 담당 파일이 채운다 */
|
|
108
|
+
export interface KokoTableRegistries {
|
|
109
|
+
cells: Registry<CellRendererDef>;
|
|
110
|
+
aggregations: Registry<AggregationDef>;
|
|
111
|
+
exportFormatters: Registry<ExportFormatterDef>;
|
|
112
|
+
}
|
|
113
|
+
/** 컬럼 메뉴 "필터 열기" — 있을 때만 항목이 보인다 */
|
|
114
|
+
export type OpenFilterHandler = (column: Column<any, unknown>, table: Table<any>) => void;
|
|
115
|
+
/** 해석된 설정 — 라벨·기본값·레지스트리는 항상 채워져 있고, 컴포넌트·렌더러는 덮어쓴 것만 있다 */
|
|
116
|
+
export interface KokoTableConfig {
|
|
117
|
+
components: Partial<KokoTableComponents>;
|
|
118
|
+
/** dataType 별 셀 렌더러 맵 (기존 통로). 배열/레지스트리로 준 정의는 `registries.cells` 에 있다 */
|
|
119
|
+
cellRenderers: KokoCellRenderers;
|
|
120
|
+
filterInputs: KokoFilterInputs;
|
|
121
|
+
labels: KokoTableLabels;
|
|
122
|
+
defaults: KokoTableDefaults;
|
|
123
|
+
menus: KokoTableMenus;
|
|
124
|
+
/** Provider 헤더 정의 — 안쪽 Provider 것이 앞에 온다 (`when` 이 참인 첫 정의가 이긴다) */
|
|
125
|
+
headers: Array<HeaderDef<any>>;
|
|
126
|
+
filterKinds: KokoFilterKinds;
|
|
127
|
+
registries: KokoTableRegistries;
|
|
128
|
+
onOpenFilter?: OpenFilterHandler;
|
|
129
|
+
}
|
|
130
|
+
export interface KokoTableConfigInput {
|
|
131
|
+
components?: Partial<KokoTableComponents>;
|
|
132
|
+
/** dataType 맵(기존) 또는 `CellRendererDef[]`/레지스트리(설계 4절) — 둘 다 받는다 */
|
|
133
|
+
cellRenderers?: KokoCellRenderers | CellRendererDef[] | Registry<CellRendererDef>;
|
|
134
|
+
filterInputs?: KokoFilterInputs;
|
|
135
|
+
labels?: KokoTableLabelsInput;
|
|
136
|
+
defaults?: Partial<KokoTableDefaults>;
|
|
137
|
+
/** 컬럼·행 컨텍스트 메뉴 add · remove · replace · order */
|
|
138
|
+
menus?: KokoTableMenusInput;
|
|
139
|
+
headers?: Array<HeaderDef<any>>;
|
|
140
|
+
filterKinds?: KokoFilterKinds;
|
|
141
|
+
aggregations?: AggregationDef[] | Registry<AggregationDef>;
|
|
142
|
+
exportFormatters?: ExportFormatterDef[] | Registry<ExportFormatterDef>;
|
|
143
|
+
onOpenFilter?: OpenFilterHandler;
|
|
144
|
+
}
|
|
145
|
+
export declare const DEFAULT_KOKO_TABLE_CONFIG: KokoTableConfig;
|
|
146
|
+
/**
|
|
147
|
+
* 부모 설정 위에 입력을 병합한다 — 항목별 얕은 병합(지정한 키만 바뀐다).
|
|
148
|
+
* 메뉴 패치는 부모 레지스트리에서 `with()` 로 파생(안쪽이 바깥 위에 쌓인다), 헤더는 안쪽 정의가 앞에 온다.
|
|
149
|
+
*/
|
|
150
|
+
export declare function mergeKokoTableConfig(base: KokoTableConfig, input?: KokoTableConfigInput): KokoTableConfig;
|
|
151
|
+
export interface KokoTableProviderProps extends KokoTableConfigInput {
|
|
152
|
+
children?: ReactNode;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* 덮어쓰기 계층의 입구 — 단일 진입점 (설계 5절).
|
|
156
|
+
*
|
|
157
|
+
* 우선순위는 **컬럼 단위 선언 → Provider → 기본값** 이다:
|
|
158
|
+
* - 필터 입력: `filter.render` → `filterInputs[variant]` / `filterKinds[kind].editor` → variant 기본 컴포넌트
|
|
159
|
+
* - 셀: 컬럼 `cell`(코어 포맷터 포함) 결과를 `cellRenderers[dataType]` 이 받아 감싼다 → `chip`/`link`/`placeholder`
|
|
160
|
+
* - 헤더: `meta.header`(id 또는 `defineHeader`) → `headers[]` 중 `when` 이 참인 첫 정의 → 기본 헤더
|
|
161
|
+
* - 메뉴: `menus.column` / `menus.row` 패치가 내장 세트 위에 쌓인다 → `TableContent columnMenuItems`/`rowMenuItems` 가 마지막
|
|
162
|
+
* - 문구: `labels` (연산자·UI·집계) — 다국어 통로
|
|
163
|
+
* - 기본값: `TableContent`/`PaginationArea` 의 미지정 prop 이 `defaults` 를 본다
|
|
164
|
+
*
|
|
165
|
+
* 중첩하면 안쪽 Provider 가 바깥 설정 위에 병합된다 — 화면 하나만 영어로 바꾸는 식이 된다.
|
|
166
|
+
*/
|
|
167
|
+
export declare function KokoTableProvider({ children, ...input }: KokoTableProviderProps): import("react").JSX.Element;
|
|
168
|
+
/** 가장 가까운 Provider 의 해석된 설정. Provider 가 없으면 기본값 */
|
|
169
|
+
export declare function useKokoTableConfig(): KokoTableConfig;
|
|
170
|
+
/** 정의 배열·레지스트리·undefined 를 레지스트리로 — 소비자가 자기 확장점에 같은 규칙을 쓸 때 */
|
|
171
|
+
export { toRegistry, applyPatch };
|
|
172
|
+
/**
|
|
173
|
+
* `props ?? defaults` — `TableContent`/`PaginationArea` 가 미지정 prop 을 Provider 기본값으로 채울 때 쓴다.
|
|
174
|
+
* 명시한 prop(undefined 가 아닌 것)은 그대로다.
|
|
175
|
+
*/
|
|
176
|
+
export declare function resolveTableProps<P extends {
|
|
177
|
+
density?: Density;
|
|
178
|
+
skeletonRows?: number;
|
|
179
|
+
groupRowLayout?: GroupRowLayout;
|
|
180
|
+
groupedColumnMode?: GroupedColumnMode;
|
|
181
|
+
enableColumnMenu?: boolean;
|
|
182
|
+
stickyHeader?: boolean;
|
|
183
|
+
maxHeight?: number | string;
|
|
184
|
+
}>(props: P, defaults: KokoTableDefaults): P;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext, useMemo } from "react";
|
|
3
|
+
import { DEFAULT_LABELS, mergeLabels } from "./labels";
|
|
4
|
+
import { applyPatch, createRegistry, isRegistry, toRegistry, } from "../registry";
|
|
5
|
+
import { columnMenuRegistry } from "../menus/columnMenu";
|
|
6
|
+
import { rowMenuRegistry } from "../menus/rowMenu";
|
|
7
|
+
export const DEFAULT_TABLE_DEFAULTS = {
|
|
8
|
+
pageSizeOptions: [15, 30, 50, 100],
|
|
9
|
+
skeletonRows: 5,
|
|
10
|
+
groupRowLayout: "columns",
|
|
11
|
+
groupedColumnMode: "reorder",
|
|
12
|
+
enableColumnMenu: true,
|
|
13
|
+
stickyHeader: true,
|
|
14
|
+
debounceMs: 300,
|
|
15
|
+
};
|
|
16
|
+
export const DEFAULT_KOKO_TABLE_CONFIG = {
|
|
17
|
+
components: {},
|
|
18
|
+
cellRenderers: {},
|
|
19
|
+
filterInputs: {},
|
|
20
|
+
labels: DEFAULT_LABELS,
|
|
21
|
+
defaults: DEFAULT_TABLE_DEFAULTS,
|
|
22
|
+
menus: { column: columnMenuRegistry, row: rowMenuRegistry },
|
|
23
|
+
headers: [],
|
|
24
|
+
filterKinds: {},
|
|
25
|
+
registries: {
|
|
26
|
+
cells: createRegistry(),
|
|
27
|
+
aggregations: createRegistry(),
|
|
28
|
+
exportFormatters: createRegistry(),
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
function isCellRendererMap(value) {
|
|
32
|
+
return !!value && !Array.isArray(value) && !isRegistry(value);
|
|
33
|
+
}
|
|
34
|
+
/** 배열이면 부모 레지스트리에 add, 레지스트리면 그것으로 교체 */
|
|
35
|
+
function mergeRegistry(base, input) {
|
|
36
|
+
if (!input)
|
|
37
|
+
return base;
|
|
38
|
+
if (isRegistry(input))
|
|
39
|
+
return input;
|
|
40
|
+
return base.with({ add: input });
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 부모 설정 위에 입력을 병합한다 — 항목별 얕은 병합(지정한 키만 바뀐다).
|
|
44
|
+
* 메뉴 패치는 부모 레지스트리에서 `with()` 로 파생(안쪽이 바깥 위에 쌓인다), 헤더는 안쪽 정의가 앞에 온다.
|
|
45
|
+
*/
|
|
46
|
+
export function mergeKokoTableConfig(base, input) {
|
|
47
|
+
if (!input)
|
|
48
|
+
return base;
|
|
49
|
+
const cellMap = isCellRendererMap(input.cellRenderers) ? input.cellRenderers : undefined;
|
|
50
|
+
const cellDefs = isCellRendererMap(input.cellRenderers) ? undefined : input.cellRenderers;
|
|
51
|
+
return {
|
|
52
|
+
components: { ...base.components, ...input.components },
|
|
53
|
+
cellRenderers: { ...base.cellRenderers, ...cellMap },
|
|
54
|
+
filterInputs: { ...base.filterInputs, ...input.filterInputs },
|
|
55
|
+
labels: mergeLabels(base.labels, input.labels),
|
|
56
|
+
defaults: { ...base.defaults, ...input.defaults },
|
|
57
|
+
menus: {
|
|
58
|
+
column: input.menus?.column ? base.menus.column.with(input.menus.column) : base.menus.column,
|
|
59
|
+
row: input.menus?.row ? base.menus.row.with(input.menus.row) : base.menus.row,
|
|
60
|
+
},
|
|
61
|
+
headers: input.headers ? [...input.headers, ...base.headers] : base.headers,
|
|
62
|
+
filterKinds: { ...base.filterKinds, ...input.filterKinds },
|
|
63
|
+
registries: {
|
|
64
|
+
cells: mergeRegistry(base.registries.cells, cellDefs),
|
|
65
|
+
aggregations: mergeRegistry(base.registries.aggregations, input.aggregations),
|
|
66
|
+
exportFormatters: mergeRegistry(base.registries.exportFormatters, input.exportFormatters),
|
|
67
|
+
},
|
|
68
|
+
onOpenFilter: input.onOpenFilter ?? base.onOpenFilter,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const KokoTableContext = createContext(DEFAULT_KOKO_TABLE_CONFIG);
|
|
72
|
+
/**
|
|
73
|
+
* 덮어쓰기 계층의 입구 — 단일 진입점 (설계 5절).
|
|
74
|
+
*
|
|
75
|
+
* 우선순위는 **컬럼 단위 선언 → Provider → 기본값** 이다:
|
|
76
|
+
* - 필터 입력: `filter.render` → `filterInputs[variant]` / `filterKinds[kind].editor` → variant 기본 컴포넌트
|
|
77
|
+
* - 셀: 컬럼 `cell`(코어 포맷터 포함) 결과를 `cellRenderers[dataType]` 이 받아 감싼다 → `chip`/`link`/`placeholder`
|
|
78
|
+
* - 헤더: `meta.header`(id 또는 `defineHeader`) → `headers[]` 중 `when` 이 참인 첫 정의 → 기본 헤더
|
|
79
|
+
* - 메뉴: `menus.column` / `menus.row` 패치가 내장 세트 위에 쌓인다 → `TableContent columnMenuItems`/`rowMenuItems` 가 마지막
|
|
80
|
+
* - 문구: `labels` (연산자·UI·집계) — 다국어 통로
|
|
81
|
+
* - 기본값: `TableContent`/`PaginationArea` 의 미지정 prop 이 `defaults` 를 본다
|
|
82
|
+
*
|
|
83
|
+
* 중첩하면 안쪽 Provider 가 바깥 설정 위에 병합된다 — 화면 하나만 영어로 바꾸는 식이 된다.
|
|
84
|
+
*/
|
|
85
|
+
export function KokoTableProvider({ children, ...input }) {
|
|
86
|
+
const parent = useContext(KokoTableContext);
|
|
87
|
+
const { components, cellRenderers, filterInputs, labels, defaults, menus, headers, filterKinds, aggregations, exportFormatters, onOpenFilter, } = input;
|
|
88
|
+
const value = useMemo(() => mergeKokoTableConfig(parent, {
|
|
89
|
+
components, cellRenderers, filterInputs, labels, defaults, menus, headers, filterKinds, aggregations,
|
|
90
|
+
exportFormatters, onOpenFilter,
|
|
91
|
+
}), [
|
|
92
|
+
parent, components, cellRenderers, filterInputs, labels, defaults, menus, headers, filterKinds, aggregations,
|
|
93
|
+
exportFormatters, onOpenFilter,
|
|
94
|
+
]);
|
|
95
|
+
return _jsx(KokoTableContext.Provider, { value: value, children: children });
|
|
96
|
+
}
|
|
97
|
+
/** 가장 가까운 Provider 의 해석된 설정. Provider 가 없으면 기본값 */
|
|
98
|
+
export function useKokoTableConfig() {
|
|
99
|
+
return useContext(KokoTableContext);
|
|
100
|
+
}
|
|
101
|
+
/** 정의 배열·레지스트리·undefined 를 레지스트리로 — 소비자가 자기 확장점에 같은 규칙을 쓸 때 */
|
|
102
|
+
export { toRegistry, applyPatch };
|
|
103
|
+
/**
|
|
104
|
+
* `props ?? defaults` — `TableContent`/`PaginationArea` 가 미지정 prop 을 Provider 기본값으로 채울 때 쓴다.
|
|
105
|
+
* 명시한 prop(undefined 가 아닌 것)은 그대로다.
|
|
106
|
+
*/
|
|
107
|
+
export function resolveTableProps(props, defaults) {
|
|
108
|
+
return {
|
|
109
|
+
...props,
|
|
110
|
+
density: props.density ?? defaults.density,
|
|
111
|
+
skeletonRows: props.skeletonRows ?? defaults.skeletonRows,
|
|
112
|
+
groupRowLayout: props.groupRowLayout ?? defaults.groupRowLayout,
|
|
113
|
+
groupedColumnMode: props.groupedColumnMode ?? defaults.groupedColumnMode,
|
|
114
|
+
enableColumnMenu: props.enableColumnMenu ?? defaults.enableColumnMenu,
|
|
115
|
+
stickyHeader: props.stickyHeader ?? defaults.stickyHeader,
|
|
116
|
+
maxHeight: props.maxHeight ?? defaults.maxHeight,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { AggFnKey, FilterOperator } from "../../../core/src/index";
|
|
2
|
+
/**
|
|
3
|
+
* 연산자 한국어 라벨 — 없는 것은 키를 그대로 보여준다.
|
|
4
|
+
* `KokoTableProvider({ labels: { operators } })` 로 덮어쓴다 (다국어 통로).
|
|
5
|
+
*/
|
|
6
|
+
export declare const OPERATOR_LABELS: Partial<Record<FilterOperator, string>>;
|
|
7
|
+
/**
|
|
8
|
+
* UI 문구. 문자열이거나, 값이 끼는 문구는 함수다.
|
|
9
|
+
* 렌더러 패키지 안의 모든 고정 문구는 여기서 나온다 — 소비자는 Provider 로 일부만 바꾼다.
|
|
10
|
+
*/
|
|
11
|
+
export interface KokoUiLabels {
|
|
12
|
+
search: string;
|
|
13
|
+
reset: string;
|
|
14
|
+
filterTitle: string;
|
|
15
|
+
detailConditions: string;
|
|
16
|
+
/** 연산자 버튼 툴팁 — `filterMode("포함")` */
|
|
17
|
+
filterMode: (operatorLabel: string) => string;
|
|
18
|
+
changeFilterMode: string;
|
|
19
|
+
empty: string;
|
|
20
|
+
loading: string;
|
|
21
|
+
retry: string;
|
|
22
|
+
loadFailed: string;
|
|
23
|
+
badRequest: string;
|
|
24
|
+
resetFilters: string;
|
|
25
|
+
/** 서버 그룹핑 "더 보기" */
|
|
26
|
+
loadMore: (loaded: number, total?: number) => string;
|
|
27
|
+
/** 그룹 트리에는 있는데 행 모델에 없을 때 */
|
|
28
|
+
missingRows: string;
|
|
29
|
+
expand: string;
|
|
30
|
+
collapse: string;
|
|
31
|
+
expandAll: string;
|
|
32
|
+
collapseAll: string;
|
|
33
|
+
selectAll: string;
|
|
34
|
+
selectRow: string;
|
|
35
|
+
expandGroup: string;
|
|
36
|
+
collapseGroup: string;
|
|
37
|
+
/** "2단계까지 펼치기 (지역)" */
|
|
38
|
+
expandToDepth: (depth: number, columnName: string) => string;
|
|
39
|
+
expandChildren: string;
|
|
40
|
+
/** 헤더 정렬 툴팁 */
|
|
41
|
+
sortHint: string;
|
|
42
|
+
/** 컬럼 메뉴 버튼 aria — 컬럼 id 뒤에 붙는다 */
|
|
43
|
+
columnMenu: string;
|
|
44
|
+
resizeHandle: (columnId: string) => string;
|
|
45
|
+
sortAsc: string;
|
|
46
|
+
sortDesc: string;
|
|
47
|
+
clearSort: string;
|
|
48
|
+
pinLeft: string;
|
|
49
|
+
pinRight: string;
|
|
50
|
+
unpin: string;
|
|
51
|
+
moveLeft: string;
|
|
52
|
+
moveRight: string;
|
|
53
|
+
hide: string;
|
|
54
|
+
groupBy: string;
|
|
55
|
+
ungroup: string;
|
|
56
|
+
resetColumnSize: string;
|
|
57
|
+
/** 컬럼 메뉴 "필터 열기" (`onOpenFilter` 가 있을 때) */
|
|
58
|
+
openFilter: string;
|
|
59
|
+
/** 컬럼 메뉴 "헤더 복사" */
|
|
60
|
+
copyHeader: string;
|
|
61
|
+
/** 헤더 메뉴 "집계" 항목·상세 설정 버튼 */
|
|
62
|
+
aggregation: string;
|
|
63
|
+
aggregationSettings: string;
|
|
64
|
+
/** 행 메뉴 "행 복사" */
|
|
65
|
+
copyRow: string;
|
|
66
|
+
}
|
|
67
|
+
export declare const DEFAULT_UI_LABELS: KokoUiLabels;
|
|
68
|
+
/** 해석된 라벨 — Provider 가 기본값과 병합해 내려준다 */
|
|
69
|
+
export interface KokoTableLabels {
|
|
70
|
+
operators: Partial<Record<FilterOperator, string>>;
|
|
71
|
+
aggregations: Record<AggFnKey, string>;
|
|
72
|
+
aggregationsShort: Record<AggFnKey, string>;
|
|
73
|
+
ui: KokoUiLabels;
|
|
74
|
+
}
|
|
75
|
+
/** Provider 에 넘기는 부분 덮어쓰기 */
|
|
76
|
+
export interface KokoTableLabelsInput {
|
|
77
|
+
operators?: Partial<Record<FilterOperator, string>>;
|
|
78
|
+
aggregations?: Partial<Record<AggFnKey, string>>;
|
|
79
|
+
aggregationsShort?: Partial<Record<AggFnKey, string>>;
|
|
80
|
+
ui?: Partial<KokoUiLabels>;
|
|
81
|
+
}
|
|
82
|
+
export declare const DEFAULT_LABELS: KokoTableLabels;
|
|
83
|
+
export declare function mergeLabels(base: KokoTableLabels, input?: KokoTableLabelsInput): KokoTableLabels;
|
|
84
|
+
/** 연산자 라벨 — `labels` 를 주면 그것을, 없으면 기본 한국어 표를 본다 */
|
|
85
|
+
export declare function operatorLabel(operator: FilterOperator, labels?: Partial<Record<FilterOperator, string>>): string;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { AGG_LABELS, AGG_SHORT_LABELS } from "../../../core/src/index";
|
|
2
|
+
/**
|
|
3
|
+
* 연산자 한국어 라벨 — 없는 것은 키를 그대로 보여준다.
|
|
4
|
+
* `KokoTableProvider({ labels: { operators } })` 로 덮어쓴다 (다국어 통로).
|
|
5
|
+
*/
|
|
6
|
+
export const OPERATOR_LABELS = {
|
|
7
|
+
fuzzy: "포함(공백무시)",
|
|
8
|
+
contains: "포함",
|
|
9
|
+
notContains: "미포함",
|
|
10
|
+
equals: "같음",
|
|
11
|
+
notEquals: "다름",
|
|
12
|
+
startsWith: "시작",
|
|
13
|
+
endsWith: "끝",
|
|
14
|
+
empty: "비어 있음",
|
|
15
|
+
notEmpty: "비어 있지 않음",
|
|
16
|
+
isEmpty: "비어 있음",
|
|
17
|
+
between: "범위(초과·미만)",
|
|
18
|
+
betweenInclusive: "범위",
|
|
19
|
+
outsideRange: "범위 밖",
|
|
20
|
+
lessThan: "미만",
|
|
21
|
+
lessThanOrEqualTo: "이하",
|
|
22
|
+
greaterThan: "초과",
|
|
23
|
+
greaterThanOrEqualTo: "이상",
|
|
24
|
+
inPeriod: "기간",
|
|
25
|
+
inArray: "포함",
|
|
26
|
+
notInArray: "제외",
|
|
27
|
+
in: "포함",
|
|
28
|
+
notIn: "제외",
|
|
29
|
+
hasAny: "하나라도",
|
|
30
|
+
hasAll: "모두",
|
|
31
|
+
hasChild: "자식 있음",
|
|
32
|
+
hasNotChild: "자식 없음",
|
|
33
|
+
linearContains: "수량 포함",
|
|
34
|
+
linearExists: "존재",
|
|
35
|
+
linearExact: "정확히",
|
|
36
|
+
scheduleContains: "그 날 포함",
|
|
37
|
+
scheduleOverlaps: "기간 겹침",
|
|
38
|
+
};
|
|
39
|
+
export const DEFAULT_UI_LABELS = {
|
|
40
|
+
search: "검색",
|
|
41
|
+
reset: "초기화",
|
|
42
|
+
filterTitle: "검색 조건",
|
|
43
|
+
detailConditions: "상세 조건",
|
|
44
|
+
filterMode: (label) => `필터 방식: ${label}`,
|
|
45
|
+
changeFilterMode: "필터 방식 변경",
|
|
46
|
+
empty: "표시할 데이터가 없습니다",
|
|
47
|
+
loading: "불러오는 중…",
|
|
48
|
+
retry: "다시 시도",
|
|
49
|
+
loadFailed: "조회에 실패했습니다",
|
|
50
|
+
badRequest: "필터를 해석할 수 없습니다",
|
|
51
|
+
resetFilters: "필터 초기화",
|
|
52
|
+
loadMore: (loaded, total) => (total != null ? `더 보기 (${loaded} / ${total})` : `더 보기 (${loaded})`),
|
|
53
|
+
missingRows: "행을 테이블에 전달하지 못했습니다 — useDataTable 에 그룹핑의 rows 를 넘겨 주세요",
|
|
54
|
+
expand: "펼치기",
|
|
55
|
+
collapse: "접기",
|
|
56
|
+
expandAll: "모두 펼치기",
|
|
57
|
+
collapseAll: "모두 접기",
|
|
58
|
+
selectAll: "전체 선택",
|
|
59
|
+
selectRow: "행 선택",
|
|
60
|
+
expandGroup: "이 그룹 펼치기",
|
|
61
|
+
collapseGroup: "이 그룹 접기",
|
|
62
|
+
expandToDepth: (depth, columnName) => `${depth}단계까지 펼치기 (${columnName})`,
|
|
63
|
+
expandChildren: "하위 펼치기",
|
|
64
|
+
sortHint: "클릭: 정렬 · Shift+클릭: 정렬 추가",
|
|
65
|
+
columnMenu: "컬럼 메뉴",
|
|
66
|
+
resizeHandle: (columnId) => `${columnId} 너비 조절`,
|
|
67
|
+
sortAsc: "오름차순 정렬",
|
|
68
|
+
sortDesc: "내림차순 정렬",
|
|
69
|
+
clearSort: "정렬 해제",
|
|
70
|
+
pinLeft: "왼쪽 고정",
|
|
71
|
+
pinRight: "오른쪽 고정",
|
|
72
|
+
unpin: "고정 해제",
|
|
73
|
+
moveLeft: "왼쪽으로 이동",
|
|
74
|
+
moveRight: "오른쪽으로 이동",
|
|
75
|
+
hide: "숨기기",
|
|
76
|
+
groupBy: "그룹 기준에 추가",
|
|
77
|
+
ungroup: "그룹 기준에서 제거",
|
|
78
|
+
resetColumnSize: "컬럼 너비 초기화",
|
|
79
|
+
openFilter: "필터 열기",
|
|
80
|
+
copyHeader: "헤더 복사",
|
|
81
|
+
aggregation: "집계",
|
|
82
|
+
aggregationSettings: "집계 설정",
|
|
83
|
+
copyRow: "행 복사",
|
|
84
|
+
};
|
|
85
|
+
export const DEFAULT_LABELS = {
|
|
86
|
+
operators: OPERATOR_LABELS,
|
|
87
|
+
aggregations: AGG_LABELS,
|
|
88
|
+
aggregationsShort: AGG_SHORT_LABELS,
|
|
89
|
+
ui: DEFAULT_UI_LABELS,
|
|
90
|
+
};
|
|
91
|
+
export function mergeLabels(base, input) {
|
|
92
|
+
if (!input)
|
|
93
|
+
return base;
|
|
94
|
+
return {
|
|
95
|
+
operators: { ...base.operators, ...input.operators },
|
|
96
|
+
aggregations: { ...base.aggregations, ...input.aggregations },
|
|
97
|
+
aggregationsShort: { ...base.aggregationsShort, ...input.aggregationsShort },
|
|
98
|
+
ui: { ...base.ui, ...input.ui },
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/** 연산자 라벨 — `labels` 를 주면 그것을, 없으면 기본 한국어 표를 본다 */
|
|
102
|
+
export function operatorLabel(operator, labels) {
|
|
103
|
+
return (labels ?? OPERATOR_LABELS)[operator] ?? operator;
|
|
104
|
+
}
|