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
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 kokotu0
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
# koko-table
|
|
2
|
+
|
|
3
|
+
NewDewbellSite 의 테이블/QueryBuilder/PivotBuilder 를 **material-react-table 없이**
|
|
4
|
+
다시 세운 패키지. 클라이언트·서버 모드 모두 갖췄고(`@koko-table/query`), 렌더러는 `@koko-table/mui` 다.
|
|
5
|
+
|
|
6
|
+
```
|
|
7
|
+
packages/core kokotable 헤드리스 (MUI·MRT 무의존) — 내부 워크스페이스 이름 @koko-table/core
|
|
8
|
+
packages/mui kokotable/mui MUI 렌더러 · 애드온 · 덮어쓰기 계층
|
|
9
|
+
packages/query kokotable/query 서버 모드 (react-query)
|
|
10
|
+
contract/ kokotable/contract 백엔드 TableRequest JSON Schema
|
|
11
|
+
stories/ Storybook (vite)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## 설치와 사용
|
|
15
|
+
|
|
16
|
+
배포 단위는 **`kokotable` 하나**다. 서브패스로 세 진입점을 낸다.
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm i kokotable
|
|
20
|
+
# peer: react, react-dom, @tanstack/react-table
|
|
21
|
+
# kokotable/mui 를 쓰면: @mui/material @mui/icons-material @emotion/react @emotion/styled
|
|
22
|
+
# kokotable/query 를 쓰면: @tanstack/react-query
|
|
23
|
+
# 행/열 가상화(kokotable/mui/virtual): @tanstack/react-virtual
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
| import | 내용 | 구 이름(vendor 시절) |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| `kokotable` | 헤드리스 코어 — 검색 상태·요청 조립·서버 동형 필터·컬럼 정의·확장 계약·계약 스키마 | `@koko-table/core` |
|
|
29
|
+
| `kokotable/mui` | MUI 렌더러·레이아웃·애드온·`KokoTableProvider`·`TableScreen` | `@koko-table/mui` |
|
|
30
|
+
| `kokotable/mui/virtual` | 행·열 가상화 (`VirtualTableContent`, `VirtualTableScreen`) | `@koko-table/mui/virtual` |
|
|
31
|
+
| `kokotable/query` | 서버 모드 — `useServerTableData`·`useServerGrouping`·`useServerTable` | `@koko-table/query` |
|
|
32
|
+
| `kokotable/contract/table-request.schema.json` | 백엔드 `TableRequest` JSON Schema | — |
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { defineTable, createColumnHelper, buildColumns } from "kokotable";
|
|
36
|
+
import { useServerTable } from "kokotable/query";
|
|
37
|
+
import { KokoTableProvider, TableScreen } from "kokotable/mui";
|
|
38
|
+
|
|
39
|
+
const h = createColumnHelper<Row>();
|
|
40
|
+
const def = defineTable<Row>({
|
|
41
|
+
key: "sales",
|
|
42
|
+
columns: buildColumns([h.ColumnIsText({ key: "name", header: "이름" }), h.ColumnIsNumber({ key: "amount", header: "금액" })]),
|
|
43
|
+
server: { queryFn: (req, { signal }) => api.post("/sales/query", req, { signal }), queryKey: ["sales"] },
|
|
44
|
+
features: { selection: true, expand: true, rowNumbers: true },
|
|
45
|
+
urlSync: true,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
function SalesPage() {
|
|
49
|
+
const bundle = useServerTable(def);
|
|
50
|
+
return (
|
|
51
|
+
<KokoTableProvider defaults={{ density: "compact" }}>
|
|
52
|
+
<TableScreen bundle={bundle} layout="side" />
|
|
53
|
+
</KokoTableProvider>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
서버 요청 계약(`TableRequest`)은 백엔드 pydantic 모델에서 뽑은 JSON Schema(`kokotable/contract/table-request.schema.json`) 와 1:1 이며 `npm run contract:check` 가 koko 가 만드는 요청을 그 스키마로 검증한다(`docs/backend-contract.md`). 백엔드는 파이썬 패키지 `koko-table-server` 로 따로 배포되며 프론트는 그것을 직접 import 하지 않는다 — `CONTRACT_VERSION` 이 같으면 호환된다.
|
|
59
|
+
|
|
60
|
+
### ERP 에서 vendor alias 를 npm 의존으로 바꾸기
|
|
61
|
+
|
|
62
|
+
평가 레인은 빌드본을 `front/vendor/koko-table/{core,mui,query}/` 에 복사하고 `vite.config.ts`·`vitest.config.ts` 의 `resolve.alias` 와 `tsconfig.app.json` 의 `paths` 로 `@koko-table/*` 를 그 경로에 붙였다. npm 으로 바꾸는 순서:
|
|
63
|
+
|
|
64
|
+
1. `npm i kokotable` (front 에서). peer 는 이미 있다(react·@mui·@emotion·@tanstack/react-table·react-query).
|
|
65
|
+
2. import 치환: `@koko-table/core` → `kokotable`, `@koko-table/mui` → `kokotable/mui`, `@koko-table/mui/virtual` → `kokotable/mui/virtual`, `@koko-table/query` → `kokotable/query`. 이름만 바뀌고 export 는 같다. 또는 alias 로 `@koko-table/core: "kokotable"` 등을 붙여 두고 점진 치환.
|
|
66
|
+
3. `vite.config.ts`·`vitest.config.ts` 의 vendor alias 4줄과 `tsconfig.app.json` `paths` 4줄 삭제, `front/vendor/koko-table` 삭제.
|
|
67
|
+
4. React 인스턴스가 하나인지 확인(`npm ls react`) — npm 의존이면 peer 로 front 의 react 를 쓴다.
|
|
68
|
+
|
|
69
|
+
## 화면은 세 구역, 계약은 넷
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
┌─ 필터 구역 ──────────── FilterSource ┐
|
|
73
|
+
├─ 콘텐츠 구역 ────────── ContentSource │ 각 구역은 테이블이 아니라
|
|
74
|
+
└─ 페이지네이션 구역 ──── PaginationSource ┘ 자기 계약에만 의존한다
|
|
75
|
+
|
|
76
|
+
정렬 ───────────────── SortSource 구역이 아니라 계약
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
정렬은 테이블에서 헤더 안에 그려지지만 `ContentSource` 에 넣지 않았다. 두 축이
|
|
80
|
+
독립이기 때문이다 — 카드 그리드는 콘텐츠는 있는데 정렬 UI 가 없고,
|
|
81
|
+
"정렬: 금액↓" 단독 드롭다운은 정렬은 있는데 콘텐츠가 없다.
|
|
82
|
+
|
|
83
|
+
테이블 인스턴스는 이 계약들의 **구현 하나**일 뿐이라, 네 계약 모두
|
|
84
|
+
`table` 을 받을 수도 `search`/`data` 를 받을 수도 있다:
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
// 기존 화면 — 테이블 하나면 전부 붙는다
|
|
88
|
+
<FilterArea source={table} />
|
|
89
|
+
<TableContent table={table} content={contentSource(data)} sort={sortSource(search)} />
|
|
90
|
+
<PaginationArea source={table} />
|
|
91
|
+
|
|
92
|
+
// 카드 화면 — 테이블 인스턴스 없음
|
|
93
|
+
<FilterArea source={search} />
|
|
94
|
+
<CardContent source={contentSource(data)} renderCard={...} />
|
|
95
|
+
<PaginationArea source={paginationSource(search, data)} />
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## 3층 구조
|
|
99
|
+
|
|
100
|
+
| 층 | 훅 | 테이블 필요? |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| 1 | `useTableSearch({ columns })` | ❌ |
|
|
103
|
+
| 2 | `useTableData({ columns, request, data })` | ❌ |
|
|
104
|
+
| 3 | `useDataTable({ columns, search, data })` | ✅ |
|
|
105
|
+
|
|
106
|
+
애드온: `useGrouping`, `useUrlSync` + `readUrlSearchState`, `useSearchHistory`.
|
|
107
|
+
피벗은 순수 함수 `runClientPivot(rows, spec)` / `transposePivot(spec)`.
|
|
108
|
+
|
|
109
|
+
## 실행
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
npm install
|
|
113
|
+
npm test # 600 케이스
|
|
114
|
+
npm run typecheck # 패키지 빌드
|
|
115
|
+
npx tsc -p packages/core/checks # 설계 조건 타입 레벨 검증
|
|
116
|
+
npm run storybook # 개발 서버 (6006)
|
|
117
|
+
npm run storybook:build # 정적 덤프 → storybook-static/
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## client / server 의미 일치
|
|
121
|
+
|
|
122
|
+
클라이언트 필터는 백엔드 `QueryBuilder` 와 **같은 의미**로 구현돼 있다.
|
|
123
|
+
분기 순서(`filters/registry.ts`)까지 `_apply_filter_by_type` 을 따른다 —
|
|
124
|
+
순서가 어긋나면 `between` 처럼 여러 타입이 지원하는 연산자에서 결과가 갈린다.
|
|
125
|
+
`filter.variant` 가 관계·선형·일정이면 `meta.dataType` 보다 먼저 판정한다
|
|
126
|
+
(`ColumnIsRelation` 컬럼은 dataType 이 `text` 여도 관계 필터를 탄다).
|
|
127
|
+
|
|
128
|
+
서버 SQL 의 3값 논리도 그대로 따른다 — `notIn`/`notInArray`/`notEquals`/`notContains`
|
|
129
|
+
는 NULL 셀을 통과시키지 않고, 관계 조건의 `equals` 는 PG 캐스팅처럼 숫자 셀과
|
|
130
|
+
문자열 값(`2` 와 `"2"`)을 같게 본다. `linearExact` 는 수량을 `==` 로만 판정하고,
|
|
131
|
+
`scheduleOverlaps` 상한은 반열림(`start < end+1d`)이다.
|
|
132
|
+
|
|
133
|
+
요청 조립(`TableSearch.request`)에서 맞추는 것:
|
|
134
|
+
|
|
135
|
+
- 리스트 연산자(`inArray`/`notInArray`/`in`/`notIn`/`arrIncludes*`/`inArrayFilter`)의
|
|
136
|
+
스칼라 값은 `[value]` 로 감싼다 — 서버 `ListFilter` 가 문자열을 글자 단위로 쪼개
|
|
137
|
+
enum 컬럼에서 500 을 내기 때문이다.
|
|
138
|
+
- 값 없는 연산자(`empty`/`notEmpty`/`isEmpty`/`hasChild`/`hasNotChild`)는 값이 비어도
|
|
139
|
+
항목을 `true` 로 싣는다 — 서버는 `value None` 인 필터를 통째로 건너뛴다.
|
|
140
|
+
- `meta.sortExpandsTo` 가 있는 통합 컬럼의 정렬은 실제 필드들로 펼쳐 싣는다
|
|
141
|
+
(`expandSorting`). UI 상태는 통합 컬럼 id 를 유지한다.
|
|
142
|
+
- `grouping` 이 있으면 `meta.enableAgg`/`meta.aggregations` 에서 파생한 `aggregation`
|
|
143
|
+
을 싣는다 (`deriveAggregation`). `SearchState.aggregation` 을 명시하면 그것이 우선한다.
|
|
144
|
+
- 정렬·페이지·그룹 변경은 **적용된 params 위에서** 그 필드만 갱신한다 — 미적용
|
|
145
|
+
draft(필터·연산자·전역검색)가 함께 나가지 않는다. `patchParams(partial)` /
|
|
146
|
+
`patchDraft(partial)` 로 부분 상태를 병합할 수 있다.
|
|
147
|
+
|
|
148
|
+
`pageSize 0` 은 서버 `LIMIT 0` 과 같이 0건이다. "전체" 는 `pagination` 미지정 또는
|
|
149
|
+
`PAGE_SIZE_ALL` 로만 표현한다.
|
|
150
|
+
|
|
151
|
+
### 여전히 다를 수 있는 지점
|
|
152
|
+
|
|
153
|
+
| 항목 | 클라이언트 | 서버 | 맞추는 방법 |
|
|
154
|
+
|---|---|---|---|
|
|
155
|
+
| `globalFilter` 대상 | 선언된 컬럼 중 텍스트 계열(`resolveDataKind === "text"`: text/enum/select/common_code). 숫자·날짜·boolean·관계·선형·일정 제외 | 모델의 varchar/text/enum 컬럼 **전부** + FK 대상 테이블의 텍스트 컬럼 (`GlobalFilterMixin._collect_auto_columns`) | 화면에 선언하지 않은 컬럼이나 FK 대상 텍스트(`supplier.name` 등)를 검색해야 하면 `useTableData({ globalFilterFields: ["name", "code", "supplier.name"] })` 로 경로를 명시한다. 서버도 `columns` 를 명시하면 같은 목록만 본다 |
|
|
156
|
+
| `inPeriod` 기준 시각 | 브라우저 `now` | 서버 시각(KST, `datetime.now()`) | 브라우저 시간대가 KST 가 아니면 경계가 어긋날 수 있다. `useTableData({ now })` / `runClientQuery(rows, columns, request, { now })` 로 기준 시각을 주입한다 |
|
|
157
|
+
| 날짜 경계 해석 실패 (`""`, `"abc"`) | 경계 없음으로 통과 | 400 | 입력 단계에서 막는다 |
|
|
158
|
+
| 텍스트 `greaterThan` 계열 | `contains` 로 동작 | `_apply_term` 에 분기가 없어 `ILIKE` (같다) | 계약 구멍 — 텍스트 컬럼에 비교 연산자를 노출하지 않는다 |
|
|
159
|
+
| 문자열 정렬 순서 | 코드포인트 | DB collation | 한글·영문 혼합에서 다를 수 있다 |
|
|
160
|
+
|
|
161
|
+
## 덮어쓰기 계층 (customize)
|
|
162
|
+
|
|
163
|
+
배포된 패키지를 쓰는 화면(ERP 등)이 포크 없이 문구·컴포넌트·셀/필터 렌더러·메뉴·기본값을 바꾸는 통로.
|
|
164
|
+
우선순위는 항상 **컬럼 단위 선언 → `KokoTableProvider` → 기본값** 이다. 중첩 Provider 는 바깥 위에 병합된다.
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
import { KokoTableProvider } from "@koko-table/mui";
|
|
168
|
+
|
|
169
|
+
<KokoTableProvider
|
|
170
|
+
labels={{ operators: { fuzzy: "Contains" }, ui: { search: "Search", empty: "No rows" }, aggregations: { sum: "Sum" } }}
|
|
171
|
+
components={{ EmptyState: BrandEmpty, HeaderCell: BrandHeaderCell, AggregateChip: PlainChip }}
|
|
172
|
+
cellRenderers={{ number: ({ renderedValue }) => <b>{renderedValue}</b>, boolean: ({ value }) => <Chip label={value ? "ON" : "OFF"} /> }}
|
|
173
|
+
filterInputs={{ text: (field) => <MyTextInput field={field} /> }}
|
|
174
|
+
defaults={{ density: "compact", pageSizeOptions: [10, 25, 50], skeletonRows: 3 }}
|
|
175
|
+
>
|
|
176
|
+
<App />
|
|
177
|
+
</KokoTableProvider>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
| 무엇을 | 컬럼 단위 (최우선) | Provider | 기본값 |
|
|
181
|
+
|---|---|---|---|
|
|
182
|
+
| 필터 입력 | `filter.render` (`setFilter({ render })`) | `filterKinds[kind.id].editor` → `filterInputs[variant]` | `kind.editor`(`withEditor`) → 내장 kind 의 기본 입력 (`FilterInput`) |
|
|
183
|
+
| 셀 값 | 컬럼 `cell` (코어 포맷터·`setCell`) 결과가 `renderedValue` 로 전달 | `cellRenderers[dataType]` → `chip` / `link` / `placeholder` | `renderCellValue` 의 Chip/Link/placeholder |
|
|
184
|
+
| 셀 정렬 | `meta.align` (`setHeaderRule({ align })`) | — | 숫자 right, 표시 전용 열 center |
|
|
185
|
+
| 헤더 내용 | `meta.headerTooltip` / `meta.headerAlign` | `TableContent renderHeader({ header, defaultContent })` | `columnDef.header` |
|
|
186
|
+
| 헤더 정의 (슬롯·규칙) | `meta.header` = `"compact"` \| `defineHeader(…)` | `headers={[defineHeader({ when, slots, rules })]}` | `defaultHeader` ("헤더 정의하기" 절) |
|
|
187
|
+
| 헤더 셀 props | — | `TableContent headerCellProps(header, table)` | — |
|
|
188
|
+
| 헤더 셀 컴포넌트 | — | `components.HeaderCell` | `HeaderCell` |
|
|
189
|
+
| 컬럼 메뉴 항목 | 헤더 `rules` 로 항목 제외 | `menus.column: { add, remove, replace, order }` → `TableContent columnMenuItems({ defaultItems })` 가 마지막 | `sort.* · pin.* · move.* · hide · group.* (onGroupingChange) · filter.open (onOpenFilter) · resize.reset (리사이즈) · copy.header` |
|
|
190
|
+
| 컬럼 메뉴 열기 | — | 메뉴 버튼 · 헤더 **우클릭** (같은 항목) | `enableColumnMenu` (Provider `defaults.enableColumnMenu`) |
|
|
191
|
+
| 행 우클릭 메뉴 | — | `menus.row: { add, remove, replace, order }` → `TableContent rowMenuItems({ row, group, defaultItems })` 가 마지막 | 말단 `copy.row` / 그룹 `expand · collapse · expandToDepth` (`onExpandGroupToDepth` 있을 때) |
|
|
192
|
+
| 그룹 행 / 상세 패널 행 | — | `components.GroupRow(ctx)` / `components.DetailPanelRow(ctx)` | `TableContent` 기본 배치 |
|
|
193
|
+
| 빈 상태 / 에러 / 로딩 | `TableContent renderEmpty` / `renderError` | `components.EmptyState` / `ErrorFallback` / `LoadingSkeleton` | 문구 + `TableErrorFallback` + `Skeleton` 행 |
|
|
194
|
+
| 편집 입력 / 집계 칩 | `meta.edit` | `components.EditCell` / `components.AggregateChip` | `EditCell` / `AggregateChip` |
|
|
195
|
+
| 문구 (다국어) | — | `labels.operators` / `labels.ui` / `labels.aggregations(Short)` | 한국어 (`DEFAULT_LABELS`) |
|
|
196
|
+
| 기본값 | 컴포넌트 prop | `defaults.{density, pageSizeOptions, skeletonRows, groupRowLayout, groupedColumnMode, enableColumnMenu, stickyHeader, maxHeight, debounceMs}` | `DEFAULT_TABLE_DEFAULTS` |
|
|
197
|
+
|
|
198
|
+
`useKokoTableConfig()` 로 해석된 설정을 읽고, `resolveTableProps(props, defaults)` 로 자기 컴포넌트에도 같은 규칙을 적용할 수 있다.
|
|
199
|
+
모든 확장점은 `{ id, … }` 항목의 레지스트리다(`createRegistry` · `Registry.with({ add, remove, replace, order })`) — 셀 렌더러·집계·export 포맷터도
|
|
200
|
+
`cellRenderers={[…]}` / `aggregations` / `exportFormatters` 로 받아 `useKokoTableConfig().registries.{cells,aggregations,exportFormatters}` 로 노출한다.
|
|
201
|
+
스토리 "커스터마이즈" · "확장/새 header 정의하기" · "확장/컨텍스트 메뉴 확장" 에 각 통로의 예가 있다.
|
|
202
|
+
|
|
203
|
+
### 헤더 정의하기
|
|
204
|
+
|
|
205
|
+
헤더 셀 안쪽은 **헤더 정의**가 그린다. 기본 헤더(`defaultHeader`)도 같은 API 다 — 다섯 슬롯 `content · sortIndicator · resizeHandle · menuTrigger · pinIndicator` 의 조합.
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
const amountHeader = defineHeader<SalesRow>({
|
|
209
|
+
id: "amount", when: (ctx) => ctx.column.id === "amount", // Provider headers[] 에서 어느 컬럼에 붙일지
|
|
210
|
+
slots: { sortIndicator: (ctx) => (ctx.sortState ? "▼" : null) }, // 일부 자리만 교체 (나머지는 기본)
|
|
211
|
+
rules: { canPin: () => false, canHide: (ctx) => ctx.column.id !== "idx" }, // 메뉴 항목 + 헤더 클릭 + column.getCan*() 모두 반영
|
|
212
|
+
// render: (ctx, slots) => <div>{ctx.defaultContent}{slots.menuTrigger(ctx)}</div> // 셀 내용 통째 교체 (<th> 는 유지)
|
|
213
|
+
});
|
|
214
|
+
<KokoTableProvider headers={[amountHeader]} /> // 컬럼 단위: setMeta({ header: amountHeader | "compact" })
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
적용 순서 **`meta.header` > Provider `headers[]` 중 `when` 이 참인 첫 정의 > 기본**. `ctx` 는 `{ header, column, table, sort, labels, sortState, multiSortIndex }`,
|
|
218
|
+
슬롯·`render` 는 여기에 `can`(규칙 해석 결과) · `defaultContent` · `openMenu(anchor)` · `menuEnabled` 를 더 받는다. 내장 id: `default` · `compact`(메뉴 버튼·리사이즈 없음).
|
|
219
|
+
|
|
220
|
+
### 컨텍스트 메뉴 확장
|
|
221
|
+
|
|
222
|
+
컬럼 메뉴(헤더 버튼·우클릭)와 행 메뉴(본문 우클릭)는 `MenuItemDef` 레지스트리다 — `{ id, label, icon?, when?(ctx), run(ctx), disabled?(ctx), group?, order?, divider? }`.
|
|
223
|
+
|
|
224
|
+
```tsx
|
|
225
|
+
<KokoTableProvider
|
|
226
|
+
menus={{
|
|
227
|
+
column: { add: [{ id: "group.only", label: "이 컬럼으로 그룹핑", when: (ctx) => !!ctx.setGrouping, run: (ctx) => ctx.setGrouping?.([ctx.column.id]) }],
|
|
228
|
+
remove: ["hide"], replace: [{ id: "copy.header", label: "헤더+값 복사", run: (ctx) => ctx.copy(…) }], order: ["group.only"] },
|
|
229
|
+
row: { add: [{ id: "detail", label: "상세 보기", when: (ctx) => !!ctx.row, run: (ctx) => open(ctx.row!.original) }] },
|
|
230
|
+
}}
|
|
231
|
+
onOpenFilter={(column) => …} // 있을 때만 filter.open 이 보인다 (TableContent onOpenFilter 도 같다)
|
|
232
|
+
/>
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
`ColumnMenuCtx` = 헤더 ctx + `{ can, grouping, setGrouping?, openFilter?, copy }`, `RowMenuCtx` = `{ row?, group?, table, copy, labels }` (`kind` 로 구분).
|
|
236
|
+
기본 id — 컬럼 `sort.asc · sort.desc · sort.clear · pin.left · pin.right · pin.clear · move.left · move.right · hide · group.add · group.remove · filter.open · resize.reset · copy.header`,
|
|
237
|
+
행 `copy.row · expand · collapse · expandToDepth`. 중첩 Provider 패치는 바깥 위에 쌓이고, `columnMenuItems`/`rowMenuItems` prop 이 해석 결과(`defaultItems`)를 마지막으로 손본다.
|
|
238
|
+
|
|
239
|
+
## 셀·집계·export 확장
|
|
240
|
+
|
|
241
|
+
셀 렌더러·집계 함수·export 포맷터는 모두 `{ id, when?, … }` 항목의 **레지스트리**다(`createRegistry`, core). 내장 세트도 같은 API 로 등록돼 있다.
|
|
242
|
+
```tsx
|
|
243
|
+
const p90 = defineAggregation({ id: "p90", label: "90분위", shortLabel: "P90", applies: (t) => t === "number", compute: (values) => percentile(values, 0.9) });
|
|
244
|
+
const badge = defineCellRenderer({ id: "status-badge", when: ({ columnId }) => columnId === "status", render: ({ value }) => <Chip label={String(value)} /> });
|
|
245
|
+
aggregations.register(p90); // 앱 전체 — core `aggregations` · `exportFormatters`, mui `cellRenderers`
|
|
246
|
+
<KokoTableProvider cellRenderers={[badge]} aggregations={[p90]} exportFormatters={[defineExportFormatter({ id: "won", when: (c) => c.id === "amount", format: (v) => `${v}원` })]} />
|
|
247
|
+
```
|
|
248
|
+
| 확장점 | 해석 순서 | 소비처 |
|
|
249
|
+
|---|---|---|
|
|
250
|
+
| 셀 (`CellRendererDef`) | 컬럼 `cell` 결과가 `renderedValue` → `when` 참 중 `order` 순 → `id === dataType` → 그대로; `meta.chip/link/placeholder` 는 같은 id 슬롯이 감싼다 | `renderCellValue(cell, { registry: useCellRenderers() })` |
|
|
251
|
+
| 집계 (`AggregationDef`, core) | `applies(dataType)` 가 칩 후보, `compute(values, ctx)` 가 계산, `server` 없으면 점선(클라이언트 전용), `format` 이 칩 문자열 | `useGrouping({ aggregations: useAggregations() })` · 그룹 행 칩(클릭 전환) · 헤더 메뉴 `aggregate`(그룹핑 중) · `AggregationSettingsButton`(상세 설정 팝오버, 안에 `AggregationChips`) |
|
|
252
|
+
| export (`ExportFormatterDef`, core) | `when(column)` 참 → `id === dataType` → `formatValueForExport` | `useTableExport(table, adapter, { formatters: useExportFormatters() })` · `toCsv(data, { formatters })` · `exp.formatRow` |
|
|
253
|
+
|
|
254
|
+
Provider 항목은 내장 위에 같은 id 로 얹힌다(빼려면 `registry.with({ remove })` 를 직접 넘긴다). 예전 `cellRenderers={{ number: fn }}` 맵·`AGG_LABELS` 등 상수는 레지스트리에서 파생돼 그대로다. 스토리 "확장/셀·집계·export 레지스트리".
|
|
255
|
+
|
|
256
|
+
## 필터 kind 정의하기
|
|
257
|
+
|
|
258
|
+
컬럼의 `filter.kind` 에 끼우는 정의 하나가 **연산자·클라이언트 판정·요청 값·문구·URL codec·입력**을 정한다.
|
|
259
|
+
내장 `text · number · date · period · boolean · enum · commonCode · cascade · relation · schedule · linear` 도 같은 `defineFilterKind` 로 정의돼 있고 helper 프리셋이 그것을 쓴다.
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
// core — 의미 부분. 값·연산자 타입은 operators 에서 추론된다
|
|
263
|
+
const moneyKind = defineFilterKind({
|
|
264
|
+
id: "money",
|
|
265
|
+
operators: {
|
|
266
|
+
between: { client: (cell, v: MoneyValue) => …, serialize: (v) => [v.lo, v.hi], wire: "betweenInclusive", describe: (v) => `${v.lo} ~ ${v.hi} ${v.currency}` },
|
|
267
|
+
gte: { client: (cell, v: MoneyValue) => …, wire: "greaterThanOrEqualTo", describe: (v) => `${v.lo} ${v.currency} 이상` },
|
|
268
|
+
},
|
|
269
|
+
defaultOperator: "between",
|
|
270
|
+
isEmpty: (v) => !v || (v.lo == null && v.hi == null),
|
|
271
|
+
codec: { encode: (v) => [v.lo, v.hi, v.currency], decode: (raw) => … },
|
|
272
|
+
});
|
|
273
|
+
// mui — 표시 부분. Provider `filterKinds={{ money: withEditor(moneyKind, { editor: MoneyInput }) }}` 로도 끼운다
|
|
274
|
+
helper.ColumnIsNumber({ key: "amount", header: "금액" }).setFilterKind(withEditor(moneyKind, { editor: (f) => <MoneyInput field={f} /> }), { defaultOperator: "gte" });
|
|
275
|
+
// 문자열 id 로 좁히려면 레지스트리를 병합한다 → filter: { kind: "money", defaultOperator: "gte" } (틀리면 컴파일 에러)
|
|
276
|
+
declare module "@koko-table/core" { interface FilterKindRegistry { money: typeof moneyKind } }
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
kind 가 없는 컬럼은 지금의 `variant` 경로 그대로다. 입력 우선순위는 `filter.render` → Provider(`filterKinds[id].editor` → `filterInputs[variant]`) → `kind.editor` → 내장. 스토리 "확장/필터 kind 정의하기".
|
|
280
|
+
|
|
281
|
+
## 없는 것 (의도적)
|
|
282
|
+
|
|
283
|
+
- XLSX/PDF/print 변환 — `useTableExport` 가 행·컬럼을 내주고 변환은 소비 앱이 동적 import 한다.
|
|
284
|
+
- 프리셋 서버 API — `PresetStore` 인터페이스만 두고 저장소는 소비 앱이 구현한다(localStorage·memory 구현은 제공).
|
|
285
|
+
- 라우터 — 링크 셀은 `onNavigate` 콜백으로 연결한다.
|
|
286
|
+
- 드래그 컬럼 순서 변경 — 헤더 메뉴 이동으로 대신한다(그룹핑 바는 드래그 지원).
|
|
287
|
+
|
|
288
|
+
## 테이블 정의 한 장
|
|
289
|
+
|
|
290
|
+
배포를 가정하면 "테이블 하나를 정의하는 타입" 이 있어야 소비자가 필요한 것만 채워 쓴다.
|
|
291
|
+
`TableDefinition<T>` 가 그 자리다 — 컬럼·기본값·서버 연결·기능 토글·그룹핑·URL 동기화를 객체 하나에 선언하고,
|
|
292
|
+
조립 훅이 1·2·3층 + 애드온을 `TableBundle` 로 묶어 주며, `TableScreen` 이 `features` 대로 화면을 배치한다.
|
|
293
|
+
|
|
294
|
+
```tsx
|
|
295
|
+
// 1. 정의 — 필요한 것만 채운다 (모듈 상수나 useMemo 로 참조를 고정한다)
|
|
296
|
+
const salesTable = defineTable<SalesRow>({
|
|
297
|
+
key: "sales", columns, data, // 서버 모드면 data 대신 server: { queryFn, queryKey }
|
|
298
|
+
features: { rowNumbers: true, selection: true }, // expand · rowActions · globalFilter · filterStatus · virtualColumns …
|
|
299
|
+
grouping: { enabled: true }, urlSync: true, getRowId: (row) => String(row.idx),
|
|
300
|
+
});
|
|
301
|
+
// 2. 조립 — 클라이언트는 core, 서버는 @koko-table/query
|
|
302
|
+
const bundle = useTableFromDefinition(salesTable); // 서버: useServerTable(salesTable)
|
|
303
|
+
// 3. 화면 — 슬롯으로 구역을 갈아끼운다 (filter / content / pagination / groupingBar / selectionActions / emptyState / detailPanel / rowActions)
|
|
304
|
+
return <TableScreen bundle={bundle} title="판매 주문" slots={{ detailPanel: (row) => <Items row={row.original} /> }} />;
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
| 정의 항목 | 뜻 |
|
|
308
|
+
|---|---|
|
|
309
|
+
| `columns` · `data` / `server` · `mode` | 컬럼, 클라이언트 배열 또는 서버 조회(`queryFn`·`queryKey`·`staleTime`·`transformResponse`·`keepPreviousData`·`refetchInterval`·`retry`). `mode` 미지정이면 `server` 유무로 판정 |
|
|
310
|
+
| `initial` · `initialOperators` · `debounceMs` · `globalFilterFields` · `now` | 1·2층 옵션 그대로 |
|
|
311
|
+
| `urlSync` · `history` · `grouping` | 애드온 — `bundle.urlSync` / `bundle.history` / `bundle.grouping`(items·expand·loadMore·rows·batchSize) |
|
|
312
|
+
| `features` | 렌더러가 읽는 토글: `rowNumbers` `selection{multi,selectOnRowClick,canSelect}` `expand{canExpand}` `rowActions` `legacyIds` `groupedColumnMode` `density` `columnMenu` `globalFilter` `filterStatus` `columnVisibilityMenu` `virtualColumns` `virtualize` |
|
|
313
|
+
| `getRowId` · `fieldErrors` · `tableOptions` | 3층. 서버 모드에서 선택·확장을 재조회 뒤에도 유지하려면 `getRowId` 가 **필수**(없으면 `defineTable` 이 경고) |
|
|
314
|
+
|
|
315
|
+
`defineTable` 은 타입 추론용 identity 이면서 검증한다 — 중복 컬럼 id, 서버 모드인데 `queryFn` 없음은 마운트 전에 던진다.
|
|
316
|
+
`TableBundle` 은 `{ definition, mode, search, data, table, grouping?, urlSync?, history?, request, tableColumns, setTableColumns, fetchAllRows }` —
|
|
317
|
+
`fetchAllRows()` 는 현재 조건의 전체 행(서버는 `pagination` 없이 한 번 더 조회)이라 `extractExportData` 에 그대로 넘긴다.
|
|
318
|
+
표시 전용 열·가상 컬럼 값 열은 `TableScreen` 이 `bundle.setTableColumns(withDisplayColumns(...))` 로 3층에 등록한다(코어는 MUI 를 모른다).
|
|
319
|
+
가상화(`features.virtualize`)는 `import { VirtualTableScreen } from "@koko-table/mui/virtual"` 로 그린다 — 메인 `TableScreen` 은 무시하고 경고만 낸다.
|
|
320
|
+
스토리 "테이블 정의" 와 "서버 모드 기능" 에 기능별 예가 있다.
|