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.
Files changed (308) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +320 -0
  3. package/contract/table-request.schema.json +424 -0
  4. package/dist/core/src/adapters/sources.d.ts +59 -0
  5. package/dist/core/src/adapters/sources.js +235 -0
  6. package/dist/core/src/client/aggregate.d.ts +94 -0
  7. package/dist/core/src/client/aggregate.js +222 -0
  8. package/dist/core/src/client/groupRows.d.ts +40 -0
  9. package/dist/core/src/client/groupRows.js +145 -0
  10. package/dist/core/src/client/runClientQuery.d.ts +67 -0
  11. package/dist/core/src/client/runClientQuery.js +157 -0
  12. package/dist/core/src/columns/ColumnBuilder.d.ts +121 -0
  13. package/dist/core/src/columns/ColumnBuilder.js +273 -0
  14. package/dist/core/src/columns/cascade.d.ts +24 -0
  15. package/dist/core/src/columns/cascade.js +93 -0
  16. package/dist/core/src/columns/deriveOperators.d.ts +38 -0
  17. package/dist/core/src/columns/deriveOperators.js +94 -0
  18. package/dist/core/src/columns/expandSorting.d.ts +19 -0
  19. package/dist/core/src/columns/expandSorting.js +52 -0
  20. package/dist/core/src/columns/helper.d.ts +196 -0
  21. package/dist/core/src/columns/helper.js +250 -0
  22. package/dist/core/src/columns/labels.d.ts +12 -0
  23. package/dist/core/src/columns/labels.js +21 -0
  24. package/dist/core/src/contract.d.ts +12 -0
  25. package/dist/core/src/contract.js +12 -0
  26. package/dist/core/src/contracts/aiColumnMeta.d.ts +102 -0
  27. package/dist/core/src/contracts/aiColumnMeta.js +197 -0
  28. package/dist/core/src/contracts/describeColumns.d.ts +48 -0
  29. package/dist/core/src/contracts/describeColumns.js +40 -0
  30. package/dist/core/src/contracts/exportData.d.ts +150 -0
  31. package/dist/core/src/contracts/exportData.js +228 -0
  32. package/dist/core/src/contracts/index.d.ts +6 -0
  33. package/dist/core/src/contracts/index.js +12 -0
  34. package/dist/core/src/contracts/legacyUrl.d.ts +47 -0
  35. package/dist/core/src/contracts/legacyUrl.js +156 -0
  36. package/dist/core/src/contracts/preset.d.ts +104 -0
  37. package/dist/core/src/contracts/preset.js +141 -0
  38. package/dist/core/src/contracts/presetStore.d.ts +81 -0
  39. package/dist/core/src/contracts/presetStore.js +146 -0
  40. package/dist/core/src/contracts/usePresets.d.ts +51 -0
  41. package/dist/core/src/contracts/usePresets.js +170 -0
  42. package/dist/core/src/defaults.d.ts +7 -0
  43. package/dist/core/src/defaults.js +9 -0
  44. package/dist/core/src/filters/codec.d.ts +20 -0
  45. package/dist/core/src/filters/codec.js +61 -0
  46. package/dist/core/src/filters/date.d.ts +30 -0
  47. package/dist/core/src/filters/date.js +179 -0
  48. package/dist/core/src/filters/describe.d.ts +45 -0
  49. package/dist/core/src/filters/describe.js +189 -0
  50. package/dist/core/src/filters/kind.d.ts +52 -0
  51. package/dist/core/src/filters/kind.js +110 -0
  52. package/dist/core/src/filters/kinds/_list.d.ts +13 -0
  53. package/dist/core/src/filters/kinds/_list.js +42 -0
  54. package/dist/core/src/filters/kinds/boolean.d.ts +3 -0
  55. package/dist/core/src/filters/kinds/boolean.js +21 -0
  56. package/dist/core/src/filters/kinds/cascade.d.ts +6 -0
  57. package/dist/core/src/filters/kinds/cascade.js +16 -0
  58. package/dist/core/src/filters/kinds/commonCode.d.ts +3 -0
  59. package/dist/core/src/filters/kinds/commonCode.js +13 -0
  60. package/dist/core/src/filters/kinds/date.d.ts +9 -0
  61. package/dist/core/src/filters/kinds/date.js +32 -0
  62. package/dist/core/src/filters/kinds/enum.d.ts +4 -0
  63. package/dist/core/src/filters/kinds/enum.js +13 -0
  64. package/dist/core/src/filters/kinds/index.d.ts +49 -0
  65. package/dist/core/src/filters/kinds/index.js +39 -0
  66. package/dist/core/src/filters/kinds/linear.d.ts +5 -0
  67. package/dist/core/src/filters/kinds/linear.js +16 -0
  68. package/dist/core/src/filters/kinds/number.d.ts +5 -0
  69. package/dist/core/src/filters/kinds/number.js +19 -0
  70. package/dist/core/src/filters/kinds/period.d.ts +4 -0
  71. package/dist/core/src/filters/kinds/period.js +17 -0
  72. package/dist/core/src/filters/kinds/relation.d.ts +5 -0
  73. package/dist/core/src/filters/kinds/relation.js +17 -0
  74. package/dist/core/src/filters/kinds/schedule.d.ts +5 -0
  75. package/dist/core/src/filters/kinds/schedule.js +16 -0
  76. package/dist/core/src/filters/kinds/text.d.ts +4 -0
  77. package/dist/core/src/filters/kinds/text.js +18 -0
  78. package/dist/core/src/filters/linear.d.ts +33 -0
  79. package/dist/core/src/filters/linear.js +65 -0
  80. package/dist/core/src/filters/list.d.ts +32 -0
  81. package/dist/core/src/filters/list.js +87 -0
  82. package/dist/core/src/filters/number.d.ts +17 -0
  83. package/dist/core/src/filters/number.js +82 -0
  84. package/dist/core/src/filters/registry.d.ts +23 -0
  85. package/dist/core/src/filters/registry.js +121 -0
  86. package/dist/core/src/filters/relation.d.ts +26 -0
  87. package/dist/core/src/filters/relation.js +75 -0
  88. package/dist/core/src/filters/schedule.d.ts +21 -0
  89. package/dist/core/src/filters/schedule.js +60 -0
  90. package/dist/core/src/filters/text.d.ts +44 -0
  91. package/dist/core/src/filters/text.js +127 -0
  92. package/dist/core/src/hooks/index.d.ts +6 -0
  93. package/dist/core/src/hooks/index.js +6 -0
  94. package/dist/core/src/hooks/useDataTable.d.ts +13 -0
  95. package/dist/core/src/hooks/useDataTable.js +109 -0
  96. package/dist/core/src/hooks/useGrouping.d.ts +33 -0
  97. package/dist/core/src/hooks/useGrouping.js +57 -0
  98. package/dist/core/src/hooks/useSearchHistory.d.ts +20 -0
  99. package/dist/core/src/hooks/useSearchHistory.js +52 -0
  100. package/dist/core/src/hooks/useTableData.d.ts +25 -0
  101. package/dist/core/src/hooks/useTableData.js +49 -0
  102. package/dist/core/src/hooks/useTableFromDefinition.d.ts +47 -0
  103. package/dist/core/src/hooks/useTableFromDefinition.js +174 -0
  104. package/dist/core/src/hooks/useTableSearch.d.ts +10 -0
  105. package/dist/core/src/hooks/useTableSearch.js +434 -0
  106. package/dist/core/src/hooks/useUrlSync.d.ts +64 -0
  107. package/dist/core/src/hooks/useUrlSync.js +145 -0
  108. package/dist/core/src/index.d.ts +38 -0
  109. package/dist/core/src/index.js +43 -0
  110. package/dist/core/src/pivot/runClientPivot.d.ts +101 -0
  111. package/dist/core/src/pivot/runClientPivot.js +230 -0
  112. package/dist/core/src/pivot/transforms.d.ts +19 -0
  113. package/dist/core/src/pivot/transforms.js +105 -0
  114. package/dist/core/src/registry.d.ts +46 -0
  115. package/dist/core/src/registry.js +67 -0
  116. package/dist/core/src/types/column.d.ts +213 -0
  117. package/dist/core/src/types/column.js +1 -0
  118. package/dist/core/src/types/data.d.ts +63 -0
  119. package/dist/core/src/types/data.js +1 -0
  120. package/dist/core/src/types/definition.d.ts +239 -0
  121. package/dist/core/src/types/definition.js +59 -0
  122. package/dist/core/src/types/filter.d.ts +94 -0
  123. package/dist/core/src/types/filter.js +1 -0
  124. package/dist/core/src/types/filterKind.d.ts +204 -0
  125. package/dist/core/src/types/filterKind.js +1 -0
  126. package/dist/core/src/types/grouping.d.ts +80 -0
  127. package/dist/core/src/types/grouping.js +4 -0
  128. package/dist/core/src/types/index.d.ts +8 -0
  129. package/dist/core/src/types/index.js +8 -0
  130. package/dist/core/src/types/operators.d.ts +64 -0
  131. package/dist/core/src/types/operators.js +108 -0
  132. package/dist/core/src/types/request.d.ts +114 -0
  133. package/dist/core/src/types/request.js +1 -0
  134. package/dist/core/src/types/search.d.ts +112 -0
  135. package/dist/core/src/types/search.js +1 -0
  136. package/dist/core/src/types/sources.d.ts +84 -0
  137. package/dist/core/src/types/sources.js +1 -0
  138. package/dist/core/src/types/table.d.ts +40 -0
  139. package/dist/core/src/types/table.js +1 -0
  140. package/dist/core/src/utils/compare.d.ts +13 -0
  141. package/dist/core/src/utils/compare.js +53 -0
  142. package/dist/core/src/utils/dateText.d.ts +12 -0
  143. package/dist/core/src/utils/dateText.js +30 -0
  144. package/dist/core/src/utils/getValue.d.ts +9 -0
  145. package/dist/core/src/utils/getValue.js +32 -0
  146. package/dist/index.d.ts +1 -0
  147. package/dist/index.js +2 -0
  148. package/dist/mui/src/TableLayout.d.ts +75 -0
  149. package/dist/mui/src/TableLayout.js +162 -0
  150. package/dist/mui/src/TableScreen.d.ts +70 -0
  151. package/dist/mui/src/TableScreen.js +174 -0
  152. package/dist/mui/src/addons/FilterModal.d.ts +45 -0
  153. package/dist/mui/src/addons/FilterModal.js +39 -0
  154. package/dist/mui/src/addons/FilterStatusModal.d.ts +40 -0
  155. package/dist/mui/src/addons/FilterStatusModal.js +68 -0
  156. package/dist/mui/src/addons/PresetBar.d.ts +56 -0
  157. package/dist/mui/src/addons/PresetBar.js +145 -0
  158. package/dist/mui/src/addons/ShareDropdown.d.ts +35 -0
  159. package/dist/mui/src/addons/ShareDropdown.js +41 -0
  160. package/dist/mui/src/addons/searchStore.d.ts +44 -0
  161. package/dist/mui/src/addons/searchStore.js +112 -0
  162. package/dist/mui/src/addons/searchSummary.d.ts +106 -0
  163. package/dist/mui/src/addons/searchSummary.js +109 -0
  164. package/dist/mui/src/columns/displayColumns.d.ts +100 -0
  165. package/dist/mui/src/columns/displayColumns.js +174 -0
  166. package/dist/mui/src/content/CardContent.d.ts +24 -0
  167. package/dist/mui/src/content/CardContent.js +25 -0
  168. package/dist/mui/src/content/ColumnMenu.d.ts +43 -0
  169. package/dist/mui/src/content/ColumnMenu.js +40 -0
  170. package/dist/mui/src/content/ColumnVisibilityMenu.d.ts +14 -0
  171. package/dist/mui/src/content/ColumnVisibilityMenu.js +37 -0
  172. package/dist/mui/src/content/EditCell.d.ts +19 -0
  173. package/dist/mui/src/content/EditCell.js +61 -0
  174. package/dist/mui/src/content/HeaderCell.d.ts +59 -0
  175. package/dist/mui/src/content/HeaderCell.js +88 -0
  176. package/dist/mui/src/content/SelectionActionBar.d.ts +17 -0
  177. package/dist/mui/src/content/SelectionActionBar.js +19 -0
  178. package/dist/mui/src/content/SortControl.d.ts +17 -0
  179. package/dist/mui/src/content/SortControl.js +45 -0
  180. package/dist/mui/src/content/TableContent.d.ts +191 -0
  181. package/dist/mui/src/content/TableContent.js +525 -0
  182. package/dist/mui/src/content/TableErrorFallback.d.ts +24 -0
  183. package/dist/mui/src/content/TableErrorFallback.js +29 -0
  184. package/dist/mui/src/content/cellError.d.ts +13 -0
  185. package/dist/mui/src/content/cellError.js +20 -0
  186. package/dist/mui/src/content/cellRenderers.d.ts +71 -0
  187. package/dist/mui/src/content/cellRenderers.js +127 -0
  188. package/dist/mui/src/content/cellValue.d.ts +27 -0
  189. package/dist/mui/src/content/cellValue.js +82 -0
  190. package/dist/mui/src/content/columnOrder.d.ts +7 -0
  191. package/dist/mui/src/content/columnOrder.js +48 -0
  192. package/dist/mui/src/content/density.d.ts +13 -0
  193. package/dist/mui/src/content/density.js +12 -0
  194. package/dist/mui/src/content/menuItems.d.ts +118 -0
  195. package/dist/mui/src/content/menuItems.js +128 -0
  196. package/dist/mui/src/content/pinning.d.ts +17 -0
  197. package/dist/mui/src/content/pinning.js +65 -0
  198. package/dist/mui/src/exporters/index.d.ts +1 -0
  199. package/dist/mui/src/exporters/index.js +1 -0
  200. package/dist/mui/src/exporters/useExportFormatters.d.ts +13 -0
  201. package/dist/mui/src/exporters/useExportFormatters.js +17 -0
  202. package/dist/mui/src/filter/FilterArea.d.ts +40 -0
  203. package/dist/mui/src/filter/FilterArea.js +37 -0
  204. package/dist/mui/src/filter/FilterInput.d.ts +14 -0
  205. package/dist/mui/src/filter/FilterInput.js +18 -0
  206. package/dist/mui/src/filter/inputs/DateFilterInput.d.ts +14 -0
  207. package/dist/mui/src/filter/inputs/DateFilterInput.js +112 -0
  208. package/dist/mui/src/filter/inputs/LinearFilterInput.d.ts +10 -0
  209. package/dist/mui/src/filter/inputs/LinearFilterInput.js +35 -0
  210. package/dist/mui/src/filter/inputs/NumberFilterInput.d.ts +12 -0
  211. package/dist/mui/src/filter/inputs/NumberFilterInput.js +111 -0
  212. package/dist/mui/src/filter/inputs/OperatorMenu.d.ts +14 -0
  213. package/dist/mui/src/filter/inputs/OperatorMenu.js +25 -0
  214. package/dist/mui/src/filter/inputs/RelationFilterInput.d.ts +11 -0
  215. package/dist/mui/src/filter/inputs/RelationFilterInput.js +67 -0
  216. package/dist/mui/src/filter/inputs/ScheduleFilterInput.d.ts +8 -0
  217. package/dist/mui/src/filter/inputs/ScheduleFilterInput.js +17 -0
  218. package/dist/mui/src/filter/inputs/SelectFilterInput.d.ts +16 -0
  219. package/dist/mui/src/filter/inputs/SelectFilterInput.js +57 -0
  220. package/dist/mui/src/filter/inputs/TextFilterInput.d.ts +13 -0
  221. package/dist/mui/src/filter/inputs/TextFilterInput.js +55 -0
  222. package/dist/mui/src/filter/kinds.d.ts +58 -0
  223. package/dist/mui/src/filter/kinds.js +103 -0
  224. package/dist/mui/src/grouping/AggregateChip.d.ts +55 -0
  225. package/dist/mui/src/grouping/AggregateChip.js +128 -0
  226. package/dist/mui/src/grouping/AggregationChips.d.ts +49 -0
  227. package/dist/mui/src/grouping/AggregationChips.js +80 -0
  228. package/dist/mui/src/grouping/AggregationSettingsButton.d.ts +14 -0
  229. package/dist/mui/src/grouping/AggregationSettingsButton.js +19 -0
  230. package/dist/mui/src/grouping/GroupingBar.d.ts +59 -0
  231. package/dist/mui/src/grouping/GroupingBar.js +267 -0
  232. package/dist/mui/src/grouping/StepExpandButton.d.ts +12 -0
  233. package/dist/mui/src/grouping/StepExpandButton.js +18 -0
  234. package/dist/mui/src/grouping/groupRow.d.ts +68 -0
  235. package/dist/mui/src/grouping/groupRow.js +129 -0
  236. package/dist/mui/src/headers/defaultHeader.d.ts +28 -0
  237. package/dist/mui/src/headers/defaultHeader.js +90 -0
  238. package/dist/mui/src/headers/defineHeader.d.ts +21 -0
  239. package/dist/mui/src/headers/defineHeader.js +68 -0
  240. package/dist/mui/src/headers/index.d.ts +5 -0
  241. package/dist/mui/src/headers/index.js +3 -0
  242. package/dist/mui/src/headers/meta.d.ts +18 -0
  243. package/dist/mui/src/headers/meta.js +11 -0
  244. package/dist/mui/src/headers/types.d.ts +84 -0
  245. package/dist/mui/src/headers/types.js +1 -0
  246. package/dist/mui/src/index.d.ts +110 -0
  247. package/dist/mui/src/index.js +79 -0
  248. package/dist/mui/src/layout/ResizeHandle.d.ts +30 -0
  249. package/dist/mui/src/layout/ResizeHandle.js +66 -0
  250. package/dist/mui/src/menus/columnMenu.d.ts +45 -0
  251. package/dist/mui/src/menus/columnMenu.js +144 -0
  252. package/dist/mui/src/menus/copy.d.ts +5 -0
  253. package/dist/mui/src/menus/copy.js +25 -0
  254. package/dist/mui/src/menus/index.d.ts +6 -0
  255. package/dist/mui/src/menus/index.js +4 -0
  256. package/dist/mui/src/menus/resolve.d.ts +15 -0
  257. package/dist/mui/src/menus/resolve.js +60 -0
  258. package/dist/mui/src/menus/rowMenu.d.ts +46 -0
  259. package/dist/mui/src/menus/rowMenu.js +76 -0
  260. package/dist/mui/src/pagination/PaginationArea.d.ts +16 -0
  261. package/dist/mui/src/pagination/PaginationArea.js +23 -0
  262. package/dist/mui/src/pivot/PivotTable.d.ts +18 -0
  263. package/dist/mui/src/pivot/PivotTable.js +100 -0
  264. package/dist/mui/src/provider/KokoTableProvider.d.ts +184 -0
  265. package/dist/mui/src/provider/KokoTableProvider.js +118 -0
  266. package/dist/mui/src/provider/labels.d.ts +85 -0
  267. package/dist/mui/src/provider/labels.js +104 -0
  268. package/dist/mui/src/registry.d.ts +30 -0
  269. package/dist/mui/src/registry.js +5 -0
  270. package/dist/mui/src/toolbar/GlobalFilterField.d.ts +36 -0
  271. package/dist/mui/src/toolbar/GlobalFilterField.js +78 -0
  272. package/dist/mui/src/virtual/VirtualTableContent.d.ts +41 -0
  273. package/dist/mui/src/virtual/VirtualTableContent.js +58 -0
  274. package/dist/mui/src/virtual/VirtualTableScreen.d.ts +13 -0
  275. package/dist/mui/src/virtual/VirtualTableScreen.js +23 -0
  276. package/dist/mui/src/virtual.d.ts +4 -0
  277. package/dist/mui/src/virtual.js +4 -0
  278. package/dist/mui/src/virtualColumns/VirtualColumnCard.d.ts +26 -0
  279. package/dist/mui/src/virtualColumns/VirtualColumnCard.js +29 -0
  280. package/dist/mui/src/virtualColumns/VirtualColumnDialog.d.ts +27 -0
  281. package/dist/mui/src/virtualColumns/VirtualColumnDialog.js +154 -0
  282. package/dist/mui/src/virtualColumns/VirtualColumnSection.d.ts +31 -0
  283. package/dist/mui/src/virtualColumns/VirtualColumnSection.js +55 -0
  284. package/dist/mui/src/virtualColumns/expression.d.ts +68 -0
  285. package/dist/mui/src/virtualColumns/expression.js +489 -0
  286. package/dist/mui/src/virtualColumns/useVirtualColumns.d.ts +67 -0
  287. package/dist/mui/src/virtualColumns/useVirtualColumns.js +111 -0
  288. package/dist/mui/src/virtualColumns/virtualColumnDefs.d.ts +29 -0
  289. package/dist/mui/src/virtualColumns/virtualColumnDefs.js +51 -0
  290. package/dist/mui-virtual.d.ts +1 -0
  291. package/dist/mui-virtual.js +2 -0
  292. package/dist/mui.d.ts +1 -0
  293. package/dist/mui.js +2 -0
  294. package/dist/query/src/index.d.ts +6 -0
  295. package/dist/query/src/index.js +7 -0
  296. package/dist/query/src/serverPivot.d.ts +42 -0
  297. package/dist/query/src/serverPivot.js +153 -0
  298. package/dist/query/src/useServerGrouping.d.ts +52 -0
  299. package/dist/query/src/useServerGrouping.js +186 -0
  300. package/dist/query/src/useServerTable.d.ts +20 -0
  301. package/dist/query/src/useServerTable.js +106 -0
  302. package/dist/query/src/useServerTableData.d.ts +48 -0
  303. package/dist/query/src/useServerTableData.js +64 -0
  304. package/dist/query/src/wire.d.ts +16 -0
  305. package/dist/query/src/wire.js +32 -0
  306. package/dist/query.d.ts +1 -0
  307. package/dist/query.js +2 -0
  308. package/package.json +125 -0
@@ -0,0 +1,114 @@
1
+ import type { FilterOperator } from "./operators";
2
+ /**
3
+ * 서버 테이블 요청 — 백엔드 `QueryBuilder/types.py` 와 1:1.
4
+ *
5
+ * `columnFilterFns` 를 뺀 나머지는 전부 TanStack Table v8 의 상태 모양 그대로다
6
+ * (`ColumnFiltersState`, `PaginationState`, `SortingState`, `GroupingState`).
7
+ * 그래서 이 계약은 테이블 구현을 갈아끼워도 그대로 살아남는다.
8
+ */
9
+ export interface TableRequest {
10
+ /** 컬럼별 연산자. **클라이언트에서는 상태가 아니라 파생값이다** — `TableSearch.operators` 참조 */
11
+ columnFilterFns?: Record<string, FilterOperator>;
12
+ columnFilters?: ColumnFilterEntry[];
13
+ pagination?: Pagination;
14
+ sorting?: SortEntry[];
15
+ globalFilter?: string;
16
+ grouping?: string[];
17
+ /**
18
+ * @deprecated 백엔드 `TableRequest` 에 없는 키다 — 서버는 무시하고, `grouping` 이 있으면
19
+ * `groupExpansion` 기본값(`path: [], offset: pageIndex*pageSize, limit: pageSize`)으로
20
+ * 최상위 그룹 노드(`groups.nodes`)를 돌려준다. `useServerTableData` 는 이 키를 wire 에서
21
+ * 제거하고 `groupExpansion` 을 명시해 보낸다(기존 ERP `useTableQuery.buildParams` 와 동일).
22
+ */
23
+ groupHeaderOnly?: boolean;
24
+ /**
25
+ * 그룹 확장 요청 (백엔드 `GroupExpansion`).
26
+ * - `path` 깊이 < `grouping` 깊이 → 다음 레벨 그룹 노드(`groups.nodes`)
27
+ * - `path` 깊이 = `grouping` 깊이 → 말단 행(`data`)
28
+ * - `path: []` 가 최상위 헤더 페이지다. 없으면 서버가 `pagination` 으로 같은 값을 만든다.
29
+ */
30
+ groupExpansion?: GroupExpansionRequest;
31
+ virtualColumns?: Record<string, VirtualColumnSpec>;
32
+ /** `{ "quantity": ["sum", "avg"] }` — 미지정 시 집계 없음 */
33
+ aggregation?: Record<string, string[]>;
34
+ }
35
+ export interface ColumnFilterEntry<V = unknown> {
36
+ id: string;
37
+ value: V;
38
+ }
39
+ export interface SortEntry {
40
+ id: string;
41
+ desc: boolean;
42
+ /** 가상/통합 컬럼이 실제로 정렬할 서버 필드 */
43
+ key?: string;
44
+ }
45
+ export interface Pagination {
46
+ pageIndex: number;
47
+ pageSize: number;
48
+ }
49
+ export interface VirtualColumnSpec {
50
+ expr: string;
51
+ type?: "number" | "string" | "boolean";
52
+ }
53
+ /** 백엔드 `GroupPathItem` — 그룹 경로의 한 단계 */
54
+ export interface GroupPathItem {
55
+ /** 그룹 컬럼명 (요청 `grouping` 의 키, dot-notation 가능) */
56
+ key: string;
57
+ value: unknown;
58
+ }
59
+ /** 백엔드 `GroupExpansion` 과 1:1 */
60
+ export interface GroupExpansionRequest {
61
+ path: GroupPathItem[];
62
+ offset: number;
63
+ limit: number;
64
+ }
65
+ /**
66
+ * 서버 응답 봉투 — 백엔드 `StandardResponse` 의 `data`·`meta`·`groups`.
67
+ *
68
+ * 그룹 노드 조회(`grouping` 있고 `groupExpansion.path` 깊이 < `grouping` 깊이)면
69
+ * `data` 는 비고 `groups.nodes` 가 차며 `meta.total_count` 는 **그 레벨의 전체 그룹 수**다.
70
+ * 말단 행 조회·일반 조회면 `groups` 가 없고 `data` 가 찬다.
71
+ */
72
+ export interface TableResponse<T> {
73
+ data: T[];
74
+ meta?: TableResponseMeta | null;
75
+ groups?: GroupsResult | null;
76
+ }
77
+ export interface TableResponseMeta {
78
+ total_count?: number | null;
79
+ failed_count?: number | null;
80
+ success_count?: number | null;
81
+ [key: string]: unknown;
82
+ }
83
+ /**
84
+ * 백엔드 `CRUD/schemas.py` 의 `GroupsResult` 와 1:1.
85
+ *
86
+ * 실제 서버(`GroupMixin.execute_group`)는 `nodes` 만 채운다. `headers` 는 스키마에
87
+ * 남아 있는 구 포맷이라 하위 호환으로만 읽는다.
88
+ */
89
+ export interface GroupsResult {
90
+ /** @deprecated 구 `groupHeaderOnly` 포맷 — 현행 백엔드는 채우지 않는다 */
91
+ headers?: GroupHeader[] | null;
92
+ /** 요청한 경로의 다음 레벨 그룹 노드 (한 레벨, 페이지 단위) */
93
+ nodes?: GroupNode[] | null;
94
+ }
95
+ /** @deprecated 백엔드 `GroupHeader` — 구 `groupHeaderOnly` 응답. `GroupNode` 를 쓴다 */
96
+ export interface GroupHeader {
97
+ group_values: Array<{
98
+ key: string;
99
+ value: unknown;
100
+ label?: string | null;
101
+ }>;
102
+ count: number;
103
+ aggregates?: Record<string, Record<string, unknown>>;
104
+ }
105
+ /** 백엔드 `GroupNode` 와 1:1 — 한 레벨의 그룹 하나 */
106
+ export interface GroupNode {
107
+ /** 이 노드를 만든 그룹 컬럼 (요청 `grouping` 의 키) */
108
+ group_key: string;
109
+ group_value: unknown;
110
+ /** 하위 말단 행 수 */
111
+ count: number;
112
+ /** `{ 컬럼: { 함수: 값 } }` — 서버는 항상 싣는다(기본 `{}`) */
113
+ aggregates?: Record<string, Record<string, unknown>>;
114
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,112 @@
1
+ import type { RowData } from "@tanstack/react-table";
2
+ import type { FilterOperator } from "./operators";
3
+ import type { FilterSource } from "./filter";
4
+ import type { TableColumnDefs } from "./column";
5
+ import type { ColumnFilterEntry, Pagination, SortEntry, TableRequest, VirtualColumnSpec } from "./request";
6
+ import type { AggregationSpec } from "../client/aggregate";
7
+ /**
8
+ * 사용자가 편집/적용하는 검색 상태.
9
+ *
10
+ * `columnFilterFns` 는 **여기 있어야 한다.** 연산자도 조회 조건의 일부라서,
11
+ * 상태 밖에 두면 `fuzzy -> equals` 로 바꾸는 순간 검색 버튼을 누르지 않았는데
12
+ * 결과가 바뀌고 `isDirty` 도 올라가지 않는다 (draft/params 계약 붕괴).
13
+ *
14
+ * 다만 **초기화는 effect 가 아니다.** `useState` 초기값에서
15
+ * `deriveOperators(columns)` 로 동기 계산한다 — 원본의 `useFilterFnsInit` +
16
+ * `filterFnsReady` 게이트가 사라지는 지점은 그대로다.
17
+ */
18
+ export interface SearchState {
19
+ columnFilters: ColumnFilterEntry[];
20
+ /** 컬럼별 연산자. 컬럼에서 파생된 기본값 위에 사용자 변경분이 얹힌 **완전한 맵** */
21
+ columnFilterFns: Record<string, FilterOperator>;
22
+ globalFilter: string;
23
+ pagination: Pagination;
24
+ sorting: SortEntry[];
25
+ grouping?: string[];
26
+ virtualColumns?: Record<string, VirtualColumnSpec>;
27
+ /**
28
+ * 그룹 집계 명세. 미지정이면 컬럼 `meta.enableAgg`/`meta.aggregations` 에서 파생한
29
+ * 값(`deriveAggregation`)이 그룹핑 요청에 실린다. 명시하면 그쪽이 우선한다.
30
+ */
31
+ aggregation?: AggregationSpec;
32
+ }
33
+ export interface TableSearchOptions<T extends RowData> {
34
+ columns: TableColumnDefs<T>;
35
+ initial?: Partial<SearchState>;
36
+ /** 컬럼 기본 연산자를 덮어쓸 초기값 */
37
+ initialOperators?: Record<string, FilterOperator>;
38
+ /** `apply()` 직후 호출 — URL 히스토리 push 등 */
39
+ onApply?: (params: SearchState) => void;
40
+ /**
41
+ * 즉시 조회(`applyOnChange` 컬럼 · `globalFilterApplyOnChange`) 의 기본 지연(ms).
42
+ * 마지막 입력 뒤 이 시간이 지나야 `apply()` 가 나간다. 컬럼의 `filter.debounceMs` 가 우선한다.
43
+ * 기본 0 = 즉시. 대기 중에는 `TableSearch.pendingApply` 가 true 다.
44
+ */
45
+ debounceMs?: number;
46
+ /**
47
+ * `setGlobalFilter` 도 값 변경 즉시(`debounceMs` 뒤) 조회한다. 기본 false —
48
+ * 전역검색은 Enter/검색 버튼으로 적용하는 것이 기본이다.
49
+ */
50
+ globalFilterApplyOnChange?: boolean;
51
+ }
52
+ /**
53
+ * 1층 — 검색 상태. **테이블 인스턴스가 없어도 동작한다.**
54
+ *
55
+ * `FilterSource` 를 직접 만족하므로 `<FilterArea source={search} />` 가
56
+ * 테이블 없이 그대로 붙는다.
57
+ *
58
+ * `PaginationSource` 는 **만족하지 않는다** — 총 건수는 2층(`TableData`)만 안다.
59
+ * 페이지네이션 UI 에는 `paginationSource(search, data)` 로 둘을 합쳐 넘긴다.
60
+ */
61
+ export interface TableSearch<T extends RowData> extends FilterSource {
62
+ columns: TableColumnDefs<T>;
63
+ /** 편집 중인 조건 (검색 버튼 누르기 전) */
64
+ draft: SearchState;
65
+ /** 적용된 조건 — 실제 조회에 쓰이는 값 */
66
+ params: SearchState;
67
+ /** 마운트 시점의 조건. `reset()` 의 목적지 */
68
+ initialParams: SearchState;
69
+ /**
70
+ * 적용된 연산자 맵 (= `params.columnFilterFns` 에 컬럼 기본값을 덧댄 것).
71
+ * 컬럼이 나중에 추가돼도 기본값이 비지 않도록 파생값을 밑에 깔아 둔다.
72
+ */
73
+ readonly operators: Readonly<Record<string, FilterOperator>>;
74
+ /** 편집 중인 연산자 맵 — 필터 UI 는 이걸 본다 */
75
+ readonly draftOperators: Readonly<Record<string, FilterOperator>>;
76
+ setFilter<V = unknown>(id: string, value: V | undefined): void;
77
+ setOperator(id: string, operator: FilterOperator): void;
78
+ setGlobalFilter(value: string): void;
79
+ setSorting(sorting: SortEntry[]): void;
80
+ setGrouping(grouping: string[]): void;
81
+ setPagination(pagination: Pagination): void;
82
+ /** 페이지 이동 — 검색 버튼을 거치지 않고 즉시 반영된다 */
83
+ setPageIndex(pageIndex: number): void;
84
+ /** 페이지 크기 변경 — 첫 페이지로 되돌린다 */
85
+ setPageSize(pageSize: number): void;
86
+ setDraft(updater: SearchState | ((prev: SearchState) => SearchState)): void;
87
+ /** draft 를 건너뛰고 즉시 적용 (정렬·페이지 이동처럼 버튼이 없는 조작). draft 도 같은 값이 된다 */
88
+ setParams(params: SearchState): void;
89
+ /**
90
+ * 부분 상태를 **현재 params 와 병합**해 즉시 적용한다 (`setParams` 의 부분 버전).
91
+ * `columnFilterFns` 는 얕게 병합한다 — 한 컬럼의 연산자만 바꿔도 나머지 맵이 살아 있다.
92
+ * 기존 `table.setParams(partial)` 호출부(AI 검색 레지스트리 등)가 그대로 붙는 자리다.
93
+ */
94
+ patchParams(partial: Partial<SearchState>): void;
95
+ /** 부분 상태를 현재 draft 와 병합한다 (`setDraft` 의 부분 버전). 적용은 `apply()` 가 한다 */
96
+ patchDraft(partial: Partial<SearchState>): void;
97
+ /**
98
+ * draft → params. 대기 중인 debounce 타이머가 있으면 취소하고 **즉시** 적용한다.
99
+ */
100
+ apply(): void;
101
+ /**
102
+ * debounce 대기 중 (`applyOnChange` + `debounceMs`) — 입력 끝에 스피너를 그리는 용도.
103
+ * `apply()` · `reset()` · 언마운트가 대기를 취소한다.
104
+ */
105
+ readonly pendingApply: boolean;
106
+ /** initialParams 로 복원. 연산자 오버라이드도 함께 비운다 */
107
+ reset(): void;
108
+ /** draft ≠ params (미적용 변경 존재) */
109
+ readonly isDirty: boolean;
110
+ /** `params` + `operators` → 서버 요청 본문 */
111
+ readonly request: TableRequest;
112
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,84 @@
1
+ import type { FilterField } from "./filter";
2
+ import type { SortEntry } from "./request";
3
+ /**
4
+ * 화면은 세 구역으로 나뉜다 — **필터 / 콘텐츠 / 페이지네이션**.
5
+ *
6
+ * 각 구역은 테이블 인스턴스가 아니라 **자기가 필요한 최소 계약**에만 의존한다.
7
+ * 테이블은 그 계약의 구현 하나일 뿐이라(`*FromTable` 어댑터), 세 구역 모두
8
+ * `table` 을 받을 수도 있고 `search`/`data` 를 받을 수도 있다.
9
+ *
10
+ * 그래서 이런 조합이 전부 성립한다:
11
+ *
12
+ * - 필터 + 테이블 본문 + 페이지네이션 (기존 화면)
13
+ * - 필터 + **카드 그리드** + 페이지네이션 (테이블 인스턴스 없음)
14
+ * - 필터만, 콘텐츠만, 페이지네이션만
15
+ *
16
+ * 세 계약 모두 값이 아니라 **메서드**를 노출한다. 테이블 인스턴스는 in-place 로
17
+ * 변이되므로 스냅샷을 들고 있으면 갱신을 놓치기 때문이다.
18
+ */
19
+ /** 필터 구역 */
20
+ export interface FilterSource {
21
+ getFilterFields(): FilterField[];
22
+ }
23
+ /** 콘텐츠 구역 — 테이블 본문이든 카드 그리드든 차트든 이것만 있으면 그린다 */
24
+ export interface ContentSource<T> {
25
+ getRows(): T[];
26
+ getStatus(): ContentStatus;
27
+ refetch(): void;
28
+ }
29
+ export interface ContentStatus {
30
+ isLoading: boolean;
31
+ /** 첫 로드인가 — 이후 refetch 는 기존 행을 유지한 채 갱신된다 */
32
+ isInitialLoading: boolean;
33
+ isError: boolean;
34
+ error?: Error;
35
+ /** 필터를 걸어 0건인가, 애초에 데이터가 없는가 */
36
+ isEmpty: boolean;
37
+ }
38
+ /**
39
+ * 정렬 — **구역이 아니라 계약이다.**
40
+ *
41
+ * 테이블에서는 정렬 UI 가 헤더에 붙으므로 콘텐츠 구역 안에 그려진다. 그렇다고
42
+ * `ContentSource` 에 넣으면 안 된다. 두 축이 독립이기 때문이다:
43
+ * 카드 그리드는 콘텐츠는 있는데 정렬 UI 가 없고, "정렬: 금액↓" 단독 드롭다운은
44
+ * 정렬은 있는데 콘텐츠가 없다. 필터를 콘텐츠에서 뺀 것과 같은 이유다.
45
+ */
46
+ export interface SortSource {
47
+ getSort(): SortEntry[];
48
+ /** 이 컬럼의 정렬 상태. 정렬 중이 아니면 null */
49
+ getColumnSort(columnId: string): ColumnSortState | null;
50
+ toggleSort(columnId: string, options?: ToggleSortOptions): void;
51
+ /** columnId 를 주면 그 컬럼만, 안 주면 전체 해제 */
52
+ clearSort(columnId?: string): void;
53
+ }
54
+ export interface ColumnSortState {
55
+ desc: boolean;
56
+ /** 다중 정렬에서의 순서 (0부터) */
57
+ index: number;
58
+ }
59
+ export interface ToggleSortOptions {
60
+ /** 명시하면 그 방향으로 고정, 없으면 asc -> desc -> 해제 순환 */
61
+ desc?: boolean;
62
+ /** 기존 정렬을 유지한 채 추가 (다중 정렬) */
63
+ multi?: boolean;
64
+ }
65
+ /** 페이지네이션 구역 */
66
+ export interface PaginationSource {
67
+ getPagination(): PaginationInfo;
68
+ setPageIndex(pageIndex: number): void;
69
+ setPageSize(pageSize: number): void;
70
+ }
71
+ export interface PaginationInfo {
72
+ pageIndex: number;
73
+ pageSize: number;
74
+ total: number;
75
+ pageCount: number;
76
+ }
77
+ /** 선택 액션바 — 콘텐츠 구역에 얹히는 부가 계약 */
78
+ export interface SelectionSource<T> {
79
+ getSelectedRows(): T[];
80
+ selectAll(): void;
81
+ deselectAll(): void;
82
+ isAllSelected(): boolean;
83
+ isSomeSelected(): boolean;
84
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,40 @@
1
+ import type { RowData, Table, TableOptions } from "@tanstack/react-table";
2
+ import type { TableColumnDefs } from "./column";
3
+ import type { ContentSource, FilterSource, PaginationSource, SelectionSource, SortSource } from "./sources";
4
+ import type { TableSearch } from "./search";
5
+ import type { FieldErrors, TableData } from "./data";
6
+ export interface DataTableOptions<T extends RowData> {
7
+ columns: TableColumnDefs<T>;
8
+ search: TableSearch<T>;
9
+ data: TableData<T>;
10
+ fieldErrors?: FieldErrors;
11
+ /** TanStack 원본 옵션 통과구 — 이 패키지가 감싸지 않은 기능을 그대로 쓴다 */
12
+ tableOptions?: Partial<TableOptions<T>>;
13
+ }
14
+ /**
15
+ * 3층 — TanStack 인스턴스에 1·2층을 연결한 것. **선택 사항이다.**
16
+ *
17
+ * 1·2층만으로 필터·페이지네이션·데이터가 전부 성립하므로, 결과를 카드나 차트로
18
+ * 그리는 화면은 이 층을 만들지 않아도 된다.
19
+ *
20
+ * `search` / `data` 를 프로퍼티로 얹기만 하고 `getState()` 는 건드리지 않는다.
21
+ * 기존 `extendTableInstance` 는 렌더마다 `getState` 를 다시 감쌌는데, TanStack
22
+ * 인스턴스는 `useState(() => createTable(...))` 로 생애 내내 같은 객체라서
23
+ * 래퍼가 렌더 수만큼 중첩됐다 (`getState()` 한 번에 스프레드 N회).
24
+ */
25
+ export type DataTable<T extends RowData> = Table<T> & {
26
+ search: TableSearch<T>;
27
+ data: TableData<T>;
28
+ fieldErrors?: FieldErrors;
29
+ };
30
+ /**
31
+ * `FilterArea` 등이 받는 값. 테이블 인스턴스든 검색 상태든 상관없다.
32
+ *
33
+ * 기존 호출부 109곳은 `table={table}` 그대로 두면 되고,
34
+ * 카드 화면만 `source={search}` 로 넘긴다.
35
+ */
36
+ export type AnyFilterSource<T extends RowData> = FilterSource | Table<T> | DataTable<T>;
37
+ export type AnyPaginationSource<T extends RowData> = PaginationSource | Table<T> | DataTable<T>;
38
+ export type AnySelectionSource<T extends RowData> = SelectionSource<T> | Table<T> | DataTable<T>;
39
+ export type AnyContentSource<T extends RowData> = ContentSource<T> | Table<T> | DataTable<T>;
40
+ export type AnySortSource<T extends RowData> = SortSource | Table<T> | DataTable<T>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ /** between 경계가 비어 있는가 — 비어 있으면 그쪽은 무한대로 본다 */
2
+ export declare function isEmptyBound(value: unknown): boolean;
3
+ /**
4
+ * 두 값 비교 — 양쪽이 숫자로 읽히면 숫자로, 아니면 소문자 trim 문자열로.
5
+ * (기존 클라이언트 필터 `compareValues` 와 동일 규칙)
6
+ *
7
+ * 한쪽이 `Date` 인스턴스면 **시각**으로 비교한다 — `String(Date)` 는
8
+ * `"Sat Mar 01 2025 …"` 라 ISO 문자열 셀과 섞이면 문자열 순서로 밀려났다.
9
+ * 상대편을 날짜로 읽을 수 없을 때만 문자열 비교로 떨어진다.
10
+ */
11
+ export declare function compareValues(a: unknown, b: unknown): number;
12
+ /** 검색 정규화 — 공백 전부 제거 + 소문자. 백엔드 `normalize_search_text` 와 같다 */
13
+ export declare function normalizeSearchText(text: string): string;
@@ -0,0 +1,53 @@
1
+ import { parseDateValue } from "../filters/date";
2
+ /** between 경계가 비어 있는가 — 비어 있으면 그쪽은 무한대로 본다 */
3
+ export function isEmptyBound(value) {
4
+ return value === null || value === undefined || value === "";
5
+ }
6
+ /**
7
+ * Date 인스턴스와 섞인 비교에서 상대편을 시각으로 읽는다.
8
+ * `Date` 그대로, ISO 문자열은 `parseDateValue`, 숫자는 epoch ms. 읽을 수 없으면 null.
9
+ */
10
+ function toTimeIfDateLike(value) {
11
+ if (value instanceof Date) {
12
+ const time = value.getTime();
13
+ return Number.isNaN(time) ? null : time;
14
+ }
15
+ if (typeof value === "number")
16
+ return Number.isNaN(value) ? null : value;
17
+ if (typeof value === "string" && value !== "") {
18
+ const parsed = parseDateValue(value);
19
+ return parsed === null ? null : parsed.date.getTime();
20
+ }
21
+ return null;
22
+ }
23
+ /**
24
+ * 두 값 비교 — 양쪽이 숫자로 읽히면 숫자로, 아니면 소문자 trim 문자열로.
25
+ * (기존 클라이언트 필터 `compareValues` 와 동일 규칙)
26
+ *
27
+ * 한쪽이 `Date` 인스턴스면 **시각**으로 비교한다 — `String(Date)` 는
28
+ * `"Sat Mar 01 2025 …"` 라 ISO 문자열 셀과 섞이면 문자열 순서로 밀려났다.
29
+ * 상대편을 날짜로 읽을 수 없을 때만 문자열 비교로 떨어진다.
30
+ */
31
+ export function compareValues(a, b) {
32
+ if (a instanceof Date || b instanceof Date) {
33
+ const at = toTimeIfDateLike(a);
34
+ const bt = toTimeIfDateLike(b);
35
+ if (at !== null && bt !== null)
36
+ return at - bt;
37
+ }
38
+ const an = Number(a);
39
+ const bn = Number(b);
40
+ if (!Number.isNaN(an) && !Number.isNaN(bn) && a !== "" && b !== "")
41
+ return an - bn;
42
+ const as = String(a ?? "").toLowerCase().trim();
43
+ const bs = String(b ?? "").toLowerCase().trim();
44
+ if (as < bs)
45
+ return -1;
46
+ if (as > bs)
47
+ return 1;
48
+ return 0;
49
+ }
50
+ /** 검색 정규화 — 공백 전부 제거 + 소문자. 백엔드 `normalize_search_text` 와 같다 */
51
+ export function normalizeSearchText(text) {
52
+ return text.replace(/\s+/g, "").toLowerCase();
53
+ }
@@ -0,0 +1,12 @@
1
+ /** 날짜 문자열 정규화 — codec(URL·프리셋)과 describe 가 같은 규칙을 쓴다 */
2
+ /** `2026-06-30T15:00:00.000Z` / `2026-06-30T15:00:00+09:00` 같은 ISO 시각 문자열 */
3
+ export declare const ISO_DATETIME: RegExp;
4
+ /** 로컬 `YYYY-MM-DD`. 유효하지 않은 Date 면 undefined */
5
+ export declare function formatLocalDate(date: Date): string | undefined;
6
+ /** ISO 시각 문자열 → 로컬 `YYYY-MM-DD`. 패턴이 아니거나 파싱 실패면 원값 */
7
+ export declare function isoToLocalDate(value: unknown): unknown;
8
+ /**
9
+ * `Date` 인스턴스·ISO 시각 문자열을 `YYYY-MM-DD` 로. 그 외는 원값 (배열은 원소별).
10
+ * 바뀐 원소가 없으면 **같은 배열 참조**를 돌려준다 — codec 이 "변경 없음" 을 참조로 판단한다.
11
+ */
12
+ export declare function toDateOnly(value: unknown): unknown;
@@ -0,0 +1,30 @@
1
+ /** 날짜 문자열 정규화 — codec(URL·프리셋)과 describe 가 같은 규칙을 쓴다 */
2
+ /** `2026-06-30T15:00:00.000Z` / `2026-06-30T15:00:00+09:00` 같은 ISO 시각 문자열 */
3
+ export const ISO_DATETIME = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})?$/;
4
+ const pad = (n) => String(n).padStart(2, "0");
5
+ /** 로컬 `YYYY-MM-DD`. 유효하지 않은 Date 면 undefined */
6
+ export function formatLocalDate(date) {
7
+ if (Number.isNaN(date.getTime()))
8
+ return undefined;
9
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
10
+ }
11
+ /** ISO 시각 문자열 → 로컬 `YYYY-MM-DD`. 패턴이 아니거나 파싱 실패면 원값 */
12
+ export function isoToLocalDate(value) {
13
+ if (typeof value !== "string" || !ISO_DATETIME.test(value))
14
+ return value;
15
+ const date = new Date(value);
16
+ return formatLocalDate(date) ?? value;
17
+ }
18
+ /**
19
+ * `Date` 인스턴스·ISO 시각 문자열을 `YYYY-MM-DD` 로. 그 외는 원값 (배열은 원소별).
20
+ * 바뀐 원소가 없으면 **같은 배열 참조**를 돌려준다 — codec 이 "변경 없음" 을 참조로 판단한다.
21
+ */
22
+ export function toDateOnly(value) {
23
+ if (Array.isArray(value)) {
24
+ const next = value.map(toDateOnly);
25
+ return next.every((v, i) => v === value[i]) ? value : next;
26
+ }
27
+ if (value instanceof Date)
28
+ return formatLocalDate(value) ?? value;
29
+ return isoToLocalDate(value);
30
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * dot-path 값 추출 (lodash `get` 대체 — 코어는 의존성 0 을 유지한다).
3
+ * `"supplier.name"` 처럼 중첩 경로를 지원한다.
4
+ */
5
+ export declare function getValue(obj: unknown, path: string): unknown;
6
+ /** 값이 "비어 있음"인가 — NULL/undefined/빈 문자열/공백만 */
7
+ export declare function isBlank(value: unknown): boolean;
8
+ /** 필터 값이 미입력인가 — 미입력 필터는 적용하지 않는다 */
9
+ export declare function isUnsetFilterValue(value: unknown): boolean;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * dot-path 값 추출 (lodash `get` 대체 — 코어는 의존성 0 을 유지한다).
3
+ * `"supplier.name"` 처럼 중첩 경로를 지원한다.
4
+ */
5
+ export function getValue(obj, path) {
6
+ if (obj == null)
7
+ return undefined;
8
+ if (!path.includes("."))
9
+ return obj[path];
10
+ let current = obj;
11
+ for (const key of path.split(".")) {
12
+ if (current == null)
13
+ return undefined;
14
+ current = current[key];
15
+ }
16
+ return current;
17
+ }
18
+ /** 값이 "비어 있음"인가 — NULL/undefined/빈 문자열/공백만 */
19
+ export function isBlank(value) {
20
+ if (value === null || value === undefined)
21
+ return true;
22
+ return typeof value === "string" && value.trim() === "";
23
+ }
24
+ /** 필터 값이 미입력인가 — 미입력 필터는 적용하지 않는다 */
25
+ export function isUnsetFilterValue(value) {
26
+ if (value === undefined || value === null || value === "")
27
+ return true;
28
+ if (Array.isArray(value)) {
29
+ return !value.some((v) => v !== null && v !== undefined && v !== "");
30
+ }
31
+ return false;
32
+ }
@@ -0,0 +1 @@
1
+ export * from "./core/src/index";
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ // kokotable — 헤드리스 코어
2
+ export * from "./core/src/index";
@@ -0,0 +1,75 @@
1
+ import { type ReactNode } from "react";
2
+ export interface SearchBarProps {
3
+ onSearch: () => void;
4
+ onReset: () => void;
5
+ /** 미적용 변경이 있는지 — 있으면 검색 버튼을 강조한다 */
6
+ isDirty?: boolean;
7
+ disabled?: boolean;
8
+ }
9
+ /** 검색·초기화 버튼 — 필터 구역 아래에 붙는다 */
10
+ export declare function SearchBar({ onSearch, onReset, isDirty, disabled }: SearchBarProps): import("react").JSX.Element;
11
+ export interface TableLayoutProps {
12
+ filter?: ReactNode;
13
+ content: ReactNode;
14
+ pagination?: ReactNode;
15
+ /** 우측 툴바 슬롯의 별칭 (`toolbarRight` 와 같다) — 기존 호출부 호환 */
16
+ toolbar?: ReactNode;
17
+ /** 제목 옆 좌측 슬롯 — 기존 `renderTopToolbarCustomActions` 자리(전역검색·AI 버튼 등) */
18
+ toolbarLeft?: ReactNode;
19
+ /** 우측 슬롯 — 기존 `renderToolbarInternalActions` 자리(컬럼 토글·내보내기 등) */
20
+ toolbarRight?: ReactNode;
21
+ title?: ReactNode;
22
+ }
23
+ /** 필터 구역 접기 — Top/Side 레이아웃이 공유하는 옵션. 상태는 제어(`collapsed`)·비제어(`defaultCollapsed`) 둘 다 된다 */
24
+ export interface CollapsibleFilterProps {
25
+ /** 접기 버튼을 보인다 */
26
+ collapsible?: boolean;
27
+ /** 제어 모드 — 주면 내부 상태를 쓰지 않는다 */
28
+ collapsed?: boolean;
29
+ /** 비제어 초기값. 미지정이면 xs 화면에서만 접힌 채 시작한다 */
30
+ defaultCollapsed?: boolean;
31
+ onCollapsedChange?: (collapsed: boolean) => void;
32
+ /** 접힌 상태에 보여 줄 적용 조건 수 (배지) */
33
+ activeCount?: number;
34
+ /** 필터 구역 제목 (기본 "검색 조건") */
35
+ filterTitle?: ReactNode;
36
+ /**
37
+ * localStorage 키 — 접힘 상태(와 사이드 패널 폭)를 기억한다.
38
+ * 화면마다 다른 키를 주면 화면별로 기억된다.
39
+ */
40
+ storageKey?: string;
41
+ }
42
+ export interface TopFilterLayoutProps extends TableLayoutProps, CollapsibleFilterProps {
43
+ /** 접힌 상태에 제목 옆에 보일 요약 문구. 없으면 `activeCount` 로 "N개 조건 적용 중" */
44
+ collapsedSummary?: ReactNode;
45
+ }
46
+ /**
47
+ * 상단 필터 레이아웃 — 필터 / 콘텐츠 / 페이지네이션 세 구역을 세로로 쌓는다.
48
+ *
49
+ * 레이아웃은 세 구역을 **배치만** 한다. 각 구역이 무엇에 의존하는지는
50
+ * 구역 컴포넌트가 각자 정하므로, 여기서 테이블 인스턴스를 요구하지 않는다.
51
+ * `collapsible` 이면 필터 Paper 에 접기 헤더가 생기고, 접힌 상태에는 요약 문구만 남는다.
52
+ */
53
+ export declare function TopFilterLayout(props: TopFilterLayoutProps): import("react").JSX.Element;
54
+ export interface SideFilterLayoutProps extends TableLayoutProps, CollapsibleFilterProps {
55
+ /** 사이드 패널 너비. `resizable` 이면 초기값이자(비제어) 외부에서 바꾸면 따라가는 값(제어) */
56
+ filterWidth?: number;
57
+ /** 패널 위치 (기본 right) */
58
+ filterPosition?: "left" | "right";
59
+ /** 폭 드래그 핸들 */
60
+ resizable?: boolean;
61
+ minWidth?: number;
62
+ maxWidth?: number;
63
+ /** 드래그 중 폭이 바뀔 때마다 */
64
+ onFilterWidthChange?: (width: number) => void;
65
+ /** 접힌 패널의 폭 (기본 44) */
66
+ collapsedWidth?: number;
67
+ }
68
+ /**
69
+ * 사이드 필터 레이아웃 — 필터를 옆 패널로 뺀다 (기본 오른쪽).
70
+ *
71
+ * - `collapsible`: 패널을 세로 탭으로 접는다. xs 에서는 가로 막대가 된다
72
+ * - `resizable`: 안쪽 변의 드래그 핸들로 폭을 바꾼다 (`minWidth`~`maxWidth`)
73
+ * - `storageKey`: 접힘·폭을 localStorage 에 기억한다
74
+ */
75
+ export declare function SideFilterLayout(props: SideFilterLayoutProps): import("react").JSX.Element;