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,71 @@
1
+ import type { MouseEvent, ReactNode } from "react";
2
+ import type { Cell, Column, RowData, Table } from "@tanstack/react-table";
3
+ import { type CellRenderProps, type ColumnDataType, type ColumnMeta, type Registry } from "../../../core/src/index";
4
+ import type { AggregationDef, ExportFormatterDef } from "../../../core/src/index";
5
+ /**
6
+ * 셀 렌더러 레지스트리 — 설계 문서 4절.
7
+ *
8
+ * 해석 순서(`renderCellValue`):
9
+ * 1. 컬럼 `cell`(코어 포맷터·`setCell`) 결과가 `ctx.renderedValue` 로 들어온다 — 항상 먼저.
10
+ * 2. 값이 비었고 `meta.placeholder` 가 있으면 `placeholder` 정의 → 끝.
11
+ * 3. `when(ctx)` 가 참인 정의 중 `order` 오름차순(같으면 등록 순) 첫 것 → 없으면 `id === meta.dataType` 이고 `when` 이 없는 정의
12
+ * → 없으면 `renderedValue` 그대로.
13
+ * 4. `meta.chip` 이면 `chip` 정의가, `meta.link` 면 `link` 정의가 3 의 결과를 `renderedValue` 로 받아 감싼다.
14
+ *
15
+ * `link`·`chip`·`placeholder` 는 **장식 슬롯**이다 — 컬럼 meta 플래그가 있을 때 id 로 찾으므로 `when` 없이 등록한다.
16
+ * 내장 세트도 같은 API 로 정의돼 있다(dogfooding). Provider 의 예전 `cellRenderers` 맵도 `toCellRendererDefs` 로 같은 모양이 된다.
17
+ */
18
+ export type CellRendererId = ColumnDataType | "link" | "chip" | "placeholder" | (string & {});
19
+ /** 렌더러가 받는 것 — 코어 `CellRenderProps` 에 인스턴스·메타를 더한 것 */
20
+ export interface CellContext<T extends RowData = any> extends CellRenderProps<T> {
21
+ cell: Cell<T, unknown>;
22
+ column: Column<T, unknown>;
23
+ table: Table<T>;
24
+ meta?: ColumnMeta;
25
+ /** `link` 슬롯에만 — `meta.link.to()` 결과 */
26
+ href?: string;
27
+ /** `link` 슬롯에만 — `TableContent onNavigate` (SPA 라우터 연결). 없으면 일반 `<a href>` */
28
+ onNavigate?: (href: string, row: T, event: MouseEvent<HTMLAnchorElement>) => void;
29
+ }
30
+ export interface CellRendererDef<T extends RowData = any> {
31
+ id: CellRendererId;
32
+ /** 이 정의를 어느 셀에 쓸지 — 있으면 dataType 일치보다 먼저 본다 */
33
+ when?: (ctx: CellContext<T>) => boolean;
34
+ render: (ctx: CellContext<T>) => ReactNode;
35
+ /** `when` 정의끼리의 우선순위 — 작을수록 먼저 (미지정 = 등록 순서) */
36
+ order?: number;
37
+ }
38
+ /** 정의 헬퍼 — `T` 를 고정해 `ctx.row` 가 좁혀진다 */
39
+ export declare function defineCellRenderer<T extends RowData = any>(def: CellRendererDef<T>): CellRendererDef<T>;
40
+ export declare function isEmptyCellValue(value: unknown): boolean;
41
+ export declare const BUILTIN_CELL_RENDERERS: readonly CellRendererDef[];
42
+ /** 전역 기본 레지스트리 — `cellRenderers.register(def)` 로 앱 전체에 추가한다 */
43
+ export declare const cellRenderers: Registry<CellRendererDef>;
44
+ /** Provider 의 예전 맵(`{ number: fn, link: fn }`) → 정의 배열 */
45
+ export declare function toCellRendererDefs(map: Partial<Record<string, (ctx: CellContext) => ReactNode>> | undefined): CellRendererDef[];
46
+ /**
47
+ * 값 렌더러 해석 — `when` 이 참인 것 중 order 순 첫 것 → `id === dataType`(when 없음) → undefined.
48
+ * 장식 슬롯(`link`·`chip`·`placeholder`)은 `when` 이 없으므로 여기서 걸리지 않는다.
49
+ */
50
+ export declare function resolveCellRenderer<T extends RowData>(ctx: CellContext<T>, registry?: Registry<CellRendererDef>): CellRendererDef | undefined;
51
+ /** Provider 가 내려주는 레지스트리 묶음 (헤더 에이전트의 `KokoTableConfig.registries` 와 같은 모양) */
52
+ export interface KokoRegistries {
53
+ cells?: Registry<CellRendererDef>;
54
+ aggregations?: Registry<AggregationDef>;
55
+ exportFormatters?: Registry<ExportFormatterDef>;
56
+ }
57
+ /** `useKokoTableConfig().registries` — Provider 가 아직 자리를 안 만들었으면 빈 객체 */
58
+ export declare function registriesOf(config: unknown): KokoRegistries;
59
+ /**
60
+ * Provider 레지스트리(덮어쓴 항목만 들어 있다)를 내장 기본 세트 위에 얹는다 — 같은 id 는 Provider 가 이긴다.
61
+ * Provider 가 비어 있으면 기본 세트 그대로. 같은 (기본, Provider) 조합은 같은 객체를 돌려줘 `useMemo` 의존성으로 쓸 수 있다.
62
+ * 내장 항목을 **빼려면** 전역 레지스트리에서 `with({ remove })` 한 것을 컴포넌트 `registry` prop / `useGrouping({ aggregations })` 에 직접 넘긴다.
63
+ */
64
+ export declare function layerRegistry<Def extends {
65
+ id: string;
66
+ }>(defaults: Registry<Def>, overlay: Registry<Def> | undefined): Registry<Def>;
67
+ /**
68
+ * 현재 Provider 의 셀 렌더러 레지스트리 — 내장 기본 세트 위에 `registries.cells`(Provider `cellRenderers` 배열/레지스트리) 를 얹고,
69
+ * 그 위에 예전 `cellRenderers` 맵을 얹은 것(컬럼 `cell` → Provider → 기본).
70
+ */
71
+ export declare function useCellRenderers(): Registry<CellRendererDef>;
@@ -0,0 +1,127 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Box, Chip, Link } from "@mui/material";
3
+ import { createRegistry, toRegistry, } from "../../../core/src/index";
4
+ import { useKokoTableConfig } from "../provider/KokoTableProvider";
5
+ /** 정의 헬퍼 — `T` 를 고정해 `ctx.row` 가 좁혀진다 */
6
+ export function defineCellRenderer(def) {
7
+ return def;
8
+ }
9
+ export function isEmptyCellValue(value) {
10
+ return value === null || value === undefined || value === "";
11
+ }
12
+ // ─────────────────────────────────────────────────────────────
13
+ // 내장 세트 — 같은 API 로 등록한다
14
+ // ─────────────────────────────────────────────────────────────
15
+ /** dataType 렌더러의 기본은 통과 — 값 포맷은 코어 `formatByDataType` 이 이미 `renderedValue` 에 넣었다 */
16
+ const passthrough = (ctx) => ctx.renderedValue;
17
+ export const BUILTIN_CELL_RENDERERS = [
18
+ defineCellRenderer({ id: "number", render: passthrough }),
19
+ defineCellRenderer({ id: "date", render: passthrough }),
20
+ defineCellRenderer({ id: "datetime", render: passthrough }),
21
+ defineCellRenderer({ id: "boolean", render: passthrough }),
22
+ defineCellRenderer({ id: "enum", render: passthrough }),
23
+ defineCellRenderer({ id: "select", render: passthrough }),
24
+ defineCellRenderer({ id: "text", render: passthrough }),
25
+ defineCellRenderer({
26
+ id: "placeholder",
27
+ render: (ctx) => _jsx(Box, { component: "span", sx: { color: "text.disabled" }, children: ctx.renderedValue }),
28
+ }),
29
+ defineCellRenderer({
30
+ id: "chip",
31
+ render: (ctx) => _jsx(Chip, { size: "small", variant: "outlined", label: ctx.renderedValue, sx: { maxWidth: "100%" } }),
32
+ }),
33
+ defineCellRenderer({
34
+ id: "link",
35
+ render: (ctx) => {
36
+ const { href, onNavigate, row } = ctx;
37
+ return (_jsx(Link, { href: href, underline: "hover", onClick: (event) => {
38
+ // 행 클릭(선택·상세) 으로 번지지 않게 한다
39
+ event.stopPropagation();
40
+ if (onNavigate && href !== undefined) {
41
+ event.preventDefault();
42
+ onNavigate(href, row, event);
43
+ }
44
+ }, children: ctx.renderedValue }));
45
+ },
46
+ }),
47
+ ];
48
+ /** 전역 기본 레지스트리 — `cellRenderers.register(def)` 로 앱 전체에 추가한다 */
49
+ export const cellRenderers = createRegistry([...BUILTIN_CELL_RENDERERS]);
50
+ /** Provider 의 예전 맵(`{ number: fn, link: fn }`) → 정의 배열 */
51
+ export function toCellRendererDefs(map) {
52
+ if (!map)
53
+ return [];
54
+ const defs = [];
55
+ for (const [id, render] of Object.entries(map))
56
+ if (render)
57
+ defs.push({ id, render });
58
+ return defs;
59
+ }
60
+ /**
61
+ * 값 렌더러 해석 — `when` 이 참인 것 중 order 순 첫 것 → `id === dataType`(when 없음) → undefined.
62
+ * 장식 슬롯(`link`·`chip`·`placeholder`)은 `when` 이 없으므로 여기서 걸리지 않는다.
63
+ */
64
+ export function resolveCellRenderer(ctx, registry = cellRenderers) {
65
+ const defs = registry.list();
66
+ let best;
67
+ defs.forEach((def, index) => {
68
+ if (!def.when || !def.when(ctx))
69
+ return;
70
+ const order = def.order ?? Number.MAX_SAFE_INTEGER;
71
+ if (!best || order < best.order || (order === best.order && index < best.index))
72
+ best = { def, order, index };
73
+ });
74
+ if (best)
75
+ return best.def;
76
+ const dataType = ctx.meta?.dataType;
77
+ if (dataType) {
78
+ const byType = defs.find((def) => def.id === dataType && !def.when);
79
+ if (byType)
80
+ return byType;
81
+ }
82
+ return undefined;
83
+ }
84
+ /** `useKokoTableConfig().registries` — Provider 가 아직 자리를 안 만들었으면 빈 객체 */
85
+ export function registriesOf(config) {
86
+ const registries = config?.registries;
87
+ return registries ?? {};
88
+ }
89
+ const layered = new WeakMap();
90
+ /**
91
+ * Provider 레지스트리(덮어쓴 항목만 들어 있다)를 내장 기본 세트 위에 얹는다 — 같은 id 는 Provider 가 이긴다.
92
+ * Provider 가 비어 있으면 기본 세트 그대로. 같은 (기본, Provider) 조합은 같은 객체를 돌려줘 `useMemo` 의존성으로 쓸 수 있다.
93
+ * 내장 항목을 **빼려면** 전역 레지스트리에서 `with({ remove })` 한 것을 컴포넌트 `registry` prop / `useGrouping({ aggregations })` 에 직접 넘긴다.
94
+ */
95
+ export function layerRegistry(defaults, overlay) {
96
+ if (!overlay)
97
+ return defaults;
98
+ const entries = overlay.list();
99
+ if (entries.length === 0)
100
+ return defaults;
101
+ let byDefaults = layered.get(overlay);
102
+ if (!byDefaults)
103
+ layered.set(overlay, (byDefaults = new WeakMap()));
104
+ let result = byDefaults.get(defaults);
105
+ if (!result) {
106
+ result = defaults.with({ add: entries });
107
+ byDefaults.set(defaults, result);
108
+ }
109
+ return result;
110
+ }
111
+ /**
112
+ * 현재 Provider 의 셀 렌더러 레지스트리 — 내장 기본 세트 위에 `registries.cells`(Provider `cellRenderers` 배열/레지스트리) 를 얹고,
113
+ * 그 위에 예전 `cellRenderers` 맵을 얹은 것(컬럼 `cell` → Provider → 기본).
114
+ */
115
+ export function useCellRenderers() {
116
+ const config = useKokoTableConfig();
117
+ const base = layerRegistry(cellRenderers, registriesOf(config).cells);
118
+ const map = config.cellRenderers;
119
+ if (!map || Object.keys(map).length === 0)
120
+ return base;
121
+ let legacy = legacyRegistries.get(map);
122
+ if (!legacy)
123
+ legacyRegistries.set(map, (legacy = toRegistry(toCellRendererDefs(map))));
124
+ return layerRegistry(base, legacy);
125
+ }
126
+ /** 예전 맵 객체 → 레지스트리 (같은 맵이면 같은 객체) */
127
+ const legacyRegistries = new WeakMap();
@@ -0,0 +1,27 @@
1
+ import type { MouseEvent, ReactNode } from "react";
2
+ import { type Cell, type RowData } from "@tanstack/react-table";
3
+ import { type Registry } from "../../../core/src/index";
4
+ import type { KokoCellRenderers } from "../provider/KokoTableProvider";
5
+ import { type CellRendererDef } from "./cellRenderers";
6
+ export interface CellValueOptions<T extends RowData> {
7
+ /**
8
+ * 링크 셀 클릭. 주면 `<a href>` 기본 이동을 막고 이 콜백을 부른다(SPA 라우터 연결 자리).
9
+ * 없으면 일반 `<a href>` 로 동작한다 — 렌더러는 라우터를 모른다.
10
+ */
11
+ onNavigate?: (href: string, row: T, event: MouseEvent<HTMLAnchorElement>) => void;
12
+ /**
13
+ * Provider 의 `cellRenderers` — 예전 맵(dataType 별 / `link` / `chip` / `placeholder`)이든
14
+ * 정의 배열·레지스트리든 받는다. 맵·배열은 `registry` 위에 같은 id 로 얹힌다.
15
+ */
16
+ renderers?: KokoCellRenderers | CellRendererDef[] | Registry<CellRendererDef>;
17
+ /** 셀 렌더러 레지스트리 — 미지정 시 전역 기본. `useCellRenderers()` 결과를 넣는다 */
18
+ registry?: Registry<CellRendererDef>;
19
+ }
20
+ /**
21
+ * 셀 값 렌더 — 셀 렌더러 레지스트리(`content/cellRenderers.tsx`)로 해석한다.
22
+ *
23
+ * 우선순위: 컬럼 `cell`(코어 포맷터·`setCell`) 결과가 `renderedValue` → 빈 값 + `meta.placeholder` 는 `placeholder` 슬롯
24
+ * → `when` 이 참인 정의(order 순) → `id === dataType` 정의 → 그대로 → `meta.chip` 이면 `chip` 슬롯, `meta.link` 면 `link` 슬롯이 감싼다.
25
+ * 컬럼이 자기 `cell` 을 선언했으면 그 결과가 항상 `renderedValue` 로 들어온다 — 렌더러가 무시하지 않는 한 살아 있다.
26
+ */
27
+ export declare function renderCellValue<T extends RowData>(cell: Cell<T, unknown>, options?: CellValueOptions<T>): ReactNode;
@@ -0,0 +1,82 @@
1
+ import { flexRender } from "@tanstack/react-table";
2
+ import { columnMetaOf, isRegistry, toRegistry } from "../../../core/src/index";
3
+ import { cellRenderers as defaultCellRenderers, isEmptyCellValue, resolveCellRenderer, toCellRendererDefs, } from "./cellRenderers";
4
+ /** `renderers` 맵 + 레지스트리 조합을 셀마다 다시 만들지 않게 잡아 둔다 */
5
+ const combined = new WeakMap();
6
+ function effectiveRegistry(options) {
7
+ const base = options.registry ?? defaultCellRenderers;
8
+ const given = options.renderers;
9
+ if (!given)
10
+ return base;
11
+ if (isRegistry(given))
12
+ return given;
13
+ if (Array.isArray(given) ? given.length === 0 : Object.keys(given).length === 0)
14
+ return base;
15
+ let byBase = combined.get(given);
16
+ if (!byBase)
17
+ combined.set(given, (byBase = new WeakMap()));
18
+ let result = byBase.get(base);
19
+ if (!result) {
20
+ const defs = Array.isArray(given)
21
+ ? given
22
+ : toCellRendererDefs(given);
23
+ result = toRegistry(defs, base.list());
24
+ byBase.set(base, result);
25
+ }
26
+ return result;
27
+ }
28
+ /**
29
+ * 셀 값 렌더 — 셀 렌더러 레지스트리(`content/cellRenderers.tsx`)로 해석한다.
30
+ *
31
+ * 우선순위: 컬럼 `cell`(코어 포맷터·`setCell`) 결과가 `renderedValue` → 빈 값 + `meta.placeholder` 는 `placeholder` 슬롯
32
+ * → `when` 이 참인 정의(order 순) → `id === dataType` 정의 → 그대로 → `meta.chip` 이면 `chip` 슬롯, `meta.link` 면 `link` 슬롯이 감싼다.
33
+ * 컬럼이 자기 `cell` 을 선언했으면 그 결과가 항상 `renderedValue` 로 들어온다 — 렌더러가 무시하지 않는 한 살아 있다.
34
+ */
35
+ export function renderCellValue(cell, options = {}) {
36
+ const meta = columnMetaOf(cell.column.columnDef);
37
+ const value = cell.getValue();
38
+ const registry = effectiveRegistry(options);
39
+ let content = flexRender(cell.column.columnDef.cell, cell.getContext());
40
+ const ctxOf = (renderedValue, href) => ({
41
+ value,
42
+ row: cell.row.original,
43
+ rowIndex: cell.row.index,
44
+ columnId: cell.column.id,
45
+ renderedValue,
46
+ cell,
47
+ column: cell.column,
48
+ table: cell.getContext().table,
49
+ meta,
50
+ href,
51
+ onNavigate: options.onNavigate,
52
+ });
53
+ if (isEmptyCellValue(value)) {
54
+ if (meta?.placeholder !== undefined) {
55
+ const placeholder = registry.get("placeholder");
56
+ return placeholder ? placeholder.render(ctxOf(meta.placeholder)) : meta.placeholder;
57
+ }
58
+ return content;
59
+ }
60
+ const renderer = resolveCellRenderer(ctxOf(content), registry);
61
+ if (renderer)
62
+ content = renderer.render(ctxOf(content));
63
+ if (meta?.chip) {
64
+ const chip = registry.get("chip");
65
+ if (chip)
66
+ content = chip.render(ctxOf(content));
67
+ }
68
+ if (meta?.link) {
69
+ const row = cell.row;
70
+ const href = meta.link.to({
71
+ value,
72
+ row: row.original,
73
+ rowIndex: row.index,
74
+ columnId: cell.column.id,
75
+ renderedValue: content,
76
+ });
77
+ const link = registry.get("link");
78
+ if (link)
79
+ content = link.render(ctxOf(content, href));
80
+ }
81
+ return content;
82
+ }
@@ -0,0 +1,7 @@
1
+ import type { RowData, Table } from "@tanstack/react-table";
2
+ /**
3
+ * 인접한 **보이는** 컬럼과 자리를 바꾼다. 숨겨진 컬럼을 건너뛰지 않으면
4
+ * "이동했는데 화면이 그대로" 가 된다.
5
+ */
6
+ export declare function moveColumn<T extends RowData>(table: Table<T>, columnId: string, direction: "left" | "right"): void;
7
+ export declare function canMoveColumn<T extends RowData>(table: Table<T>, columnId: string, direction: "left" | "right"): boolean;
@@ -0,0 +1,48 @@
1
+ import { isDisplayColumnId } from "../columns/displayColumns";
2
+ /** 현재 유효한 컬럼 순서 — `columnOrder` 상태가 비어 있으면 정의 순서다 */
3
+ function effectiveOrder(table) {
4
+ const state = table.getState().columnOrder;
5
+ const all = table.getAllLeafColumns().map((column) => column.id);
6
+ if (!state || state.length === 0)
7
+ return all;
8
+ // 상태에 없는(나중에 추가된) 컬럼은 뒤에 붙인다 — TanStack 의 orderColumns 와 같은 규칙
9
+ const rest = all.filter((id) => !state.includes(id));
10
+ return [...state.filter((id) => all.includes(id)), ...rest];
11
+ }
12
+ /**
13
+ * 인접한 **보이는** 컬럼과 자리를 바꾼다. 숨겨진 컬럼을 건너뛰지 않으면
14
+ * "이동했는데 화면이 그대로" 가 된다.
15
+ */
16
+ export function moveColumn(table, columnId, direction) {
17
+ const order = effectiveOrder(table);
18
+ const from = order.indexOf(columnId);
19
+ if (from < 0)
20
+ return;
21
+ const step = direction === "left" ? -1 : 1;
22
+ let to = from + step;
23
+ while (to >= 0 && to < order.length) {
24
+ const candidate = table.getColumn(order[to]);
25
+ if (candidate?.getIsVisible() && !isDisplayColumnId(candidate.id))
26
+ break;
27
+ to += step;
28
+ }
29
+ if (to < 0 || to >= order.length)
30
+ return;
31
+ const next = [...order];
32
+ next.splice(from, 1);
33
+ next.splice(to, 0, columnId);
34
+ table.setColumnOrder(next);
35
+ }
36
+ export function canMoveColumn(table, columnId, direction) {
37
+ const order = effectiveOrder(table);
38
+ const from = order.indexOf(columnId);
39
+ if (from < 0)
40
+ return false;
41
+ const step = direction === "left" ? -1 : 1;
42
+ for (let i = from + step; i >= 0 && i < order.length; i += step) {
43
+ const candidate = table.getColumn(order[i]);
44
+ if (candidate?.getIsVisible() && !isDisplayColumnId(candidate.id))
45
+ return true;
46
+ }
47
+ return false;
48
+ }
@@ -0,0 +1,13 @@
1
+ /** 행 밀도 — 프리셋의 `density` 값이 그대로 들어온다 */
2
+ export type Density = "compact" | "comfortable" | "spacious";
3
+ export interface DensitySpec {
4
+ size: "small" | "medium";
5
+ /** 본문 셀 세로 여백(theme spacing 단위). undefined 면 MUI 기본 */
6
+ cellPy?: number;
7
+ cellPx?: number;
8
+ }
9
+ /**
10
+ * `density` 가 있으면 그것을, 없으면 `dense` 를 본다.
11
+ * compact = small + 여백 축소, comfortable = small, spacious = medium.
12
+ */
13
+ export declare function resolveDensity(density: Density | undefined, dense: boolean): DensitySpec;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * `density` 가 있으면 그것을, 없으면 `dense` 를 본다.
3
+ * compact = small + 여백 축소, comfortable = small, spacious = medium.
4
+ */
5
+ export function resolveDensity(density, dense) {
6
+ switch (density) {
7
+ case "compact": return { size: "small", cellPy: 0.25, cellPx: 1 };
8
+ case "comfortable": return { size: "small" };
9
+ case "spacious": return { size: "medium" };
10
+ default: return { size: dense ? "small" : "medium" };
11
+ }
12
+ }
@@ -0,0 +1,118 @@
1
+ import type { AggregationSpec } from "../../../core/src/index";
2
+ import type { ReactNode } from "react";
3
+ import { type PopoverPosition } from "@mui/material";
4
+ import type { Column, Header, Row, RowData, Table } from "@tanstack/react-table";
5
+ import type { SortSource } from "../../../core/src/index";
6
+ import type { KokoTableLabels } from "../provider/labels";
7
+ import type { Registry } from "../registry";
8
+ import type { HeaderContext, HeaderDef } from "../headers/types";
9
+ import { type ColumnMenuCtx, type ColumnMenuItemDef } from "../menus/columnMenu";
10
+ import { type GroupRowCtx, type RowMenuCtx, type RowMenuItemDef } from "../menus/rowMenu";
11
+ /**
12
+ * 메뉴 항목 하나 — 데이터다. 컬럼 메뉴·행 컨텍스트 메뉴가 같은 모양을 쓴다.
13
+ * `divider: true` 면 항목이 아니라 구분선이다 (연속·앞뒤 구분선은 그릴 때 합쳐진다).
14
+ *
15
+ * 레지스트리(`MenuItemDef`)가 해석된 결과가 이 모양이다 — `columnMenuItems`/`rowMenuItems` prop 은
16
+ * 이 배열(`defaultItems`)을 받아 마지막으로 손본다.
17
+ */
18
+ export interface MenuItemSpec<Ctx> {
19
+ key: string;
20
+ label?: ReactNode | ((ctx: Ctx) => ReactNode);
21
+ icon?: ReactNode;
22
+ onClick?: (ctx: Ctx) => void;
23
+ disabled?: boolean | ((ctx: Ctx) => boolean);
24
+ hidden?: boolean | ((ctx: Ctx) => boolean);
25
+ divider?: boolean;
26
+ }
27
+ /**
28
+ * `ColumnMenu` 가 받는 최소 컨텍스트 (기존 prop 계약). 레지스트리 항목은 이것을 `ColumnMenuCtx` 로 넓힌 것을 받는다.
29
+ * `header`·`labels` 는 없으면 테이블에서 찾는다/기본값을 쓴다.
30
+ */
31
+ export interface ColumnMenuContext<T extends RowData = any> {
32
+ column: Column<T, unknown>;
33
+ table: Table<T>;
34
+ sort?: SortSource;
35
+ /** 현재 그룹 기준 — `TableContent grouping` prop 또는 `table.getState().grouping` */
36
+ grouping: string[];
37
+ /** 있을 때만 "그룹 기준 추가/제거" 항목이 생긴다 */
38
+ onGroupingChange?: (grouping: string[]) => void;
39
+ /** 있을 때만 "필터 열기" 항목이 생긴다 */
40
+ openFilter?: () => void;
41
+ /** 그룹핑 중 집계 함수 토글 — 둘 다 있을 때만 "집계" 항목이 생긴다 */
42
+ aggregation?: AggregationSpec;
43
+ onAggregationChange?: (next: AggregationSpec) => void;
44
+ header?: Header<T, unknown>;
45
+ copy?: (text: string) => void;
46
+ }
47
+ export type ColumnMenuItem<T extends RowData = any> = MenuItemSpec<ColumnMenuContext<T>>;
48
+ /** `columnMenuItems` prop 의 인자 — 기본 항목을 받아 추가·제거·재배열한 배열을 돌려준다 */
49
+ export interface ColumnMenuItemsContext<T extends RowData = any> extends ColumnMenuContext<T> {
50
+ defaultItems: Array<ColumnMenuItem<T>>;
51
+ }
52
+ export type ColumnMenuItemsFn<T extends RowData = any> = (ctx: ColumnMenuItemsContext<T>) => Array<ColumnMenuItem<T>>;
53
+ /** `HeaderContext` — 헤더 셀과 메뉴가 같은 모양으로 만든다 */
54
+ export declare function createHeaderContext<T extends RowData>(input: {
55
+ header: Header<T, unknown>;
56
+ column: Column<T, unknown>;
57
+ table: Table<T>;
58
+ sort?: SortSource;
59
+ labels: KokoTableLabels;
60
+ }): HeaderContext<T>;
61
+ /**
62
+ * 기존 컨텍스트 → 레지스트리 항목이 받는 `ColumnMenuCtx`.
63
+ * 헤더 정의의 `rules` 를 여기서도 해석한다 — 헤더 셀 없이 `ColumnMenu` 만 써도 규칙이 같게.
64
+ */
65
+ export declare function createColumnMenuCtx<T extends RowData>(ctx: ColumnMenuContext<T>, labels: KokoTableLabels, headers?: ReadonlyArray<HeaderDef<T>>): ColumnMenuCtx<T>;
66
+ /**
67
+ * 기본 컬럼 메뉴 항목 — 레지스트리(`registry` 미지정 시 내장 세트)를 해석한 결과.
68
+ * 정렬 / 고정 / 이동 / 숨기기 / 그룹 기준(콜백 있을 때) / 필터 열기(콜백 있을 때) / 너비 초기화(리사이즈 켜져 있을 때) / 헤더 복사.
69
+ * 조건에 맞지 않는 항목은 아예 넣지 않는다 (`hidden` 이 아니라).
70
+ */
71
+ export declare function defaultColumnMenuItems<T extends RowData>(ctx: ColumnMenuContext<T>, labels: KokoTableLabels, registry?: Registry<ColumnMenuItemDef<any>>, headers?: ReadonlyArray<HeaderDef<T>>): Array<ColumnMenuItem<T>>;
72
+ /** `rowMenuItems` prop 이 받는 것 — 레지스트리 ctx 에 기본 항목을 더한 것 */
73
+ export interface RowMenuContext<T extends RowData = any> extends RowMenuCtx<T> {
74
+ /** 레지스트리를 해석한 기본 항목 (말단: 행 복사 / 그룹: 펼치기·접기·N단계까지 펼치기) */
75
+ defaultItems: Array<RowMenuItem<T>>;
76
+ }
77
+ export type RowMenuItem<T extends RowData = any> = MenuItemSpec<RowMenuContext<T>>;
78
+ export type RowMenuItemsFn<T extends RowData = any> = (ctx: RowMenuContext<T>) => Array<RowMenuItem<T>>;
79
+ export type { GroupRowCtx };
80
+ /** 기존 컨텍스트(`copy`·`labels` 없을 수 있음) → 레지스트리 항목이 받는 `RowMenuCtx` */
81
+ export declare function createRowMenuCtx<T extends RowData>(ctx: {
82
+ row?: Row<T>;
83
+ table: Table<T>;
84
+ group?: GroupRowCtx<T>;
85
+ copy?: (text: string) => void;
86
+ }, labels: KokoTableLabels): RowMenuCtx<T>;
87
+ /** 기본 행 메뉴 항목 — 레지스트리(`registry` 미지정 시 내장 세트)를 해석한 결과 */
88
+ export declare function defaultRowMenuItems<T extends RowData>(ctx: {
89
+ row?: Row<T>;
90
+ table: Table<T>;
91
+ group?: GroupRowCtx<T>;
92
+ copy?: (text: string) => void;
93
+ }, labels: KokoTableLabels, registry?: Registry<RowMenuItemDef<any>>): Array<RowMenuItem<T>>;
94
+ /** ERP `GroupRowContextMenu` 대응 — 그룹 행의 기본 항목만 (말단 행이면 빈 배열). `defaultRowMenuItems` 의 하위 호환 */
95
+ export declare function defaultGroupRowMenuItems<T extends RowData>(ctx: {
96
+ row?: Row<T>;
97
+ table: Table<T>;
98
+ group?: GroupRowCtx<T>;
99
+ }, labels: KokoTableLabels, registry?: Registry<RowMenuItemDef<any>>): Array<RowMenuItem<T>>;
100
+ /** 보이는 항목만 남기고, 앞·뒤·연속 구분선을 합친다 */
101
+ export declare function visibleMenuItems<Ctx>(items: Array<MenuItemSpec<Ctx>>, ctx: Ctx): Array<MenuItemSpec<Ctx>>;
102
+ export interface MenuItemListProps<Ctx> {
103
+ items: Array<MenuItemSpec<Ctx>>;
104
+ ctx: Ctx;
105
+ /** 항목을 누른 뒤 (메뉴 닫기) */
106
+ onPick?: () => void;
107
+ }
108
+ /** 항목 배열 → `MenuItem`/`Divider`. `Menu` 안에 놓는다 */
109
+ export declare function MenuItemList<Ctx>({ items, ctx, onPick }: MenuItemListProps<Ctx>): import("react").JSX.Element;
110
+ export interface ContextMenuProps<Ctx> {
111
+ /** 커서 위치. null 이면 닫힘 */
112
+ position: PopoverPosition | null;
113
+ items: Array<MenuItemSpec<Ctx>>;
114
+ ctx: Ctx;
115
+ onClose: () => void;
116
+ }
117
+ /** 커서 위치에 뜨는 메뉴 — 헤더·행 우클릭이 쓴다 */
118
+ export declare function ContextMenu<Ctx>({ position, items, ctx, onClose }: ContextMenuProps<Ctx>): import("react").JSX.Element;
@@ -0,0 +1,128 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Divider, ListItemIcon, ListItemText, Menu, MenuItem } from "@mui/material";
3
+ import { applyHeaderRules, resolveHeaderDef } from "../headers/defineHeader";
4
+ import { defaultHeader, headerRegistry } from "../headers/defaultHeader";
5
+ import { columnMenuRegistry } from "../menus/columnMenu";
6
+ import { rowMenuRegistry } from "../menus/rowMenu";
7
+ import { menuSpecsFrom } from "../menus/resolve";
8
+ import { copyToClipboard } from "../menus/copy";
9
+ /**
10
+ * 레지스트리 ctx 로 해석된 항목을 다른 ctx 의 `MenuItemSpec` 으로 — 라벨·disabled 는 값으로 굳히고,
11
+ * 콜백은 레지스트리 ctx 를 닫아 둔다 (`MenuItemList` 가 넘기는 ctx 와 무관하게 동작한다).
12
+ */
13
+ function narrowSpecs(specs, ctx) {
14
+ return specs.map((spec) => ({
15
+ key: spec.key,
16
+ divider: spec.divider,
17
+ icon: spec.icon,
18
+ label: typeof spec.label === "function" ? spec.label(ctx) : spec.label,
19
+ disabled: typeof spec.disabled === "function" ? spec.disabled(ctx) : spec.disabled,
20
+ hidden: typeof spec.hidden === "function" ? spec.hidden(ctx) : spec.hidden,
21
+ onClick: spec.onClick ? () => spec.onClick(ctx) : undefined,
22
+ }));
23
+ }
24
+ function leafHeaderOf(table, column) {
25
+ const found = table.getLeafHeaders().find((header) => header.column.id === column.id)
26
+ ?? table.getFlatHeaders().find((header) => header.column.id === column.id);
27
+ if (found)
28
+ return found;
29
+ // 헤더 그룹이 아직 없을 때(테스트·단독 사용) — 컬럼만으로 최소 헤더를 흉내낸다
30
+ return {
31
+ id: column.id, column, colSpan: 1, rowSpan: 1, depth: 0, index: 0, isPlaceholder: false,
32
+ placeholderId: undefined, subHeaders: [], headerGroup: undefined,
33
+ getContext: () => ({ table, header: undefined, column }),
34
+ getLeafHeaders: () => [], getSize: () => column.getSize(), getStart: () => 0, getResizeHandler: () => () => { },
35
+ };
36
+ }
37
+ /** `HeaderContext` — 헤더 셀과 메뉴가 같은 모양으로 만든다 */
38
+ export function createHeaderContext(input) {
39
+ const { header, column, table, sort, labels } = input;
40
+ const sortState = sort?.getColumnSort(column.id) ?? null;
41
+ const multiSortIndex = sortState && sort && sort.getSort().length > 1 ? sortState.index + 1 : null;
42
+ return { header, column, table, sort, labels, sortState, multiSortIndex };
43
+ }
44
+ /**
45
+ * 기존 컨텍스트 → 레지스트리 항목이 받는 `ColumnMenuCtx`.
46
+ * 헤더 정의의 `rules` 를 여기서도 해석한다 — 헤더 셀 없이 `ColumnMenu` 만 써도 규칙이 같게.
47
+ */
48
+ export function createColumnMenuCtx(ctx, labels, headers = []) {
49
+ const header = ctx.header ?? leafHeaderOf(ctx.table, ctx.column);
50
+ const base = createHeaderContext({ header, column: ctx.column, table: ctx.table, sort: ctx.sort, labels });
51
+ const def = resolveHeaderDef(base, headers, headerRegistry, defaultHeader);
52
+ const can = applyHeaderRules(base, def);
53
+ return {
54
+ ...base,
55
+ kind: "column",
56
+ can,
57
+ grouping: ctx.grouping,
58
+ setGrouping: ctx.onGroupingChange,
59
+ openFilter: ctx.openFilter,
60
+ aggregation: ctx.aggregation,
61
+ setAggregation: ctx.onAggregationChange,
62
+ copy: ctx.copy ?? copyToClipboard,
63
+ };
64
+ }
65
+ /**
66
+ * 기본 컬럼 메뉴 항목 — 레지스트리(`registry` 미지정 시 내장 세트)를 해석한 결과.
67
+ * 정렬 / 고정 / 이동 / 숨기기 / 그룹 기준(콜백 있을 때) / 필터 열기(콜백 있을 때) / 너비 초기화(리사이즈 켜져 있을 때) / 헤더 복사.
68
+ * 조건에 맞지 않는 항목은 아예 넣지 않는다 (`hidden` 이 아니라).
69
+ */
70
+ export function defaultColumnMenuItems(ctx, labels, registry = columnMenuRegistry, headers = []) {
71
+ const menuCtx = createColumnMenuCtx(ctx, labels, headers);
72
+ return narrowSpecs(menuSpecsFrom(registry.list(), menuCtx), menuCtx);
73
+ }
74
+ /** 기존 컨텍스트(`copy`·`labels` 없을 수 있음) → 레지스트리 항목이 받는 `RowMenuCtx` */
75
+ export function createRowMenuCtx(ctx, labels) {
76
+ return { kind: "row", row: ctx.row, table: ctx.table, group: ctx.group, labels, copy: ctx.copy ?? copyToClipboard };
77
+ }
78
+ /** 기본 행 메뉴 항목 — 레지스트리(`registry` 미지정 시 내장 세트)를 해석한 결과 */
79
+ export function defaultRowMenuItems(ctx, labels, registry = rowMenuRegistry) {
80
+ const menuCtx = createRowMenuCtx(ctx, labels);
81
+ return menuSpecsFrom(registry.list(), menuCtx).map((spec) => ({
82
+ ...spec,
83
+ onClick: spec.onClick ? () => spec.onClick(menuCtx) : undefined,
84
+ }));
85
+ }
86
+ /** ERP `GroupRowContextMenu` 대응 — 그룹 행의 기본 항목만 (말단 행이면 빈 배열). `defaultRowMenuItems` 의 하위 호환 */
87
+ export function defaultGroupRowMenuItems(ctx, labels, registry = rowMenuRegistry) {
88
+ if (!ctx.group)
89
+ return [];
90
+ return defaultRowMenuItems({ table: ctx.table, group: ctx.group }, labels, registry);
91
+ }
92
+ // ── 그리기 ──
93
+ function resolve(value, ctx) {
94
+ return typeof value === "function" ? value(ctx) : value;
95
+ }
96
+ /** 보이는 항목만 남기고, 앞·뒤·연속 구분선을 합친다 */
97
+ export function visibleMenuItems(items, ctx) {
98
+ const out = [];
99
+ for (const item of items) {
100
+ if (resolve(item.hidden, ctx))
101
+ continue;
102
+ if (item.divider) {
103
+ if (out.length === 0 || out[out.length - 1].divider)
104
+ continue;
105
+ out.push(item);
106
+ }
107
+ else {
108
+ out.push(item);
109
+ }
110
+ }
111
+ while (out.length > 0 && out[out.length - 1].divider)
112
+ out.pop();
113
+ return out;
114
+ }
115
+ /** 항목 배열 → `MenuItem`/`Divider`. `Menu` 안에 놓는다 */
116
+ export function MenuItemList({ items, ctx, onPick }) {
117
+ return (_jsx(_Fragment, { children: visibleMenuItems(items, ctx).map((item) => item.divider
118
+ ? _jsx(Divider, {}, item.key)
119
+ : (_jsxs(MenuItem, { dense: true, "data-menu-key": item.key, disabled: !!resolve(item.disabled, ctx), onClick: (event) => {
120
+ event.stopPropagation();
121
+ item.onClick?.(ctx);
122
+ onPick?.();
123
+ }, children: [item.icon && _jsx(ListItemIcon, { children: item.icon }), _jsx(ListItemText, { primary: resolve(item.label, ctx) })] }, item.key))) }));
124
+ }
125
+ /** 커서 위치에 뜨는 메뉴 — 헤더·행 우클릭이 쓴다 */
126
+ export function ContextMenu({ position, items, ctx, onClose }) {
127
+ return (_jsx(Menu, { open: !!position, onClose: onClose, anchorReference: "anchorPosition", anchorPosition: position ?? undefined, onClick: (event) => event.stopPropagation(), onContextMenu: (event) => { event.preventDefault(); event.stopPropagation(); }, slotProps: { paper: { sx: { minWidth: 180 } } }, children: _jsx(MenuItemList, { items: items, ctx: ctx, onPick: onClose }) }));
128
+ }