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,45 @@
1
+ /**
2
+ * 필터 값 → 사람이 읽는 문구 (순수 함수, JSX 없음).
3
+ *
4
+ * 기존 mui `searchSummary.formatConditionValue` 의 규칙을 core 로 옮긴 것이다 —
5
+ * 내장 kind 의 `operators[op].describe` 가 이 조각들을 조합하고, kind 가 없는 컬럼은
6
+ * `describeFilterValue` 의 일반 규칙(값 모양으로 추정)을 그대로 쓴다.
7
+ * 문구는 `FilterDescribeLabels` 로 바꿀 수 있다 (기본 한국어).
8
+ */
9
+ import type { FilterOperator } from "../types/operators";
10
+ import type { AnyFilterKind, FilterDescribeContext, FilterDescribeLabels } from "../types/filterKind";
11
+ import type { RelationFilterValue } from "./relation";
12
+ import type { LinearFilterValue } from "./linear";
13
+ export declare const DEFAULT_DESCRIBE_LABELS: FilterDescribeLabels;
14
+ export type DescribeOptions = Partial<FilterDescribeContext>;
15
+ /** 스칼라 하나 — 선택지 라벨 · 예/아니오 · 날짜(`YYYY-MM-DD`) · 객체는 JSON */
16
+ export declare function describeScalar(value: unknown, options?: DescribeOptions): string;
17
+ /** 두 경계 — `a ~ b`, 빈 쪽은 `…`, 둘 다 비면 empty */
18
+ export declare function describeRange(value: unknown, options?: DescribeOptions): string;
19
+ /** 목록 — 쉼표, 길면 "외 N개" */
20
+ export declare function describeList(value: unknown, options?: DescribeOptions): string;
21
+ /** 관계 필터 — 그룹이 전부 "equals 하나" 면 컬럼별 값 묶음, 아니면 그룹 수 */
22
+ export declare function describeRelation(value: RelationFilterValue, options?: DescribeOptions): string;
23
+ /** 선형결합 필터 — "볼트 ≥2, 너트 (모두 충족)" */
24
+ export declare function describeLinear(value: LinearFilterValue, options?: DescribeOptions): string;
25
+ /** 일정 필터 — 날짜 하나 또는 기간 */
26
+ export declare function describeSchedule(value: Record<string, unknown>, options?: DescribeOptions): string;
27
+ export interface DescribeFilterValueOptions extends DescribeOptions {
28
+ operator?: FilterOperator | string;
29
+ /** 값 모양이 애매할 때 판단 근거 (relation/linear/schedule) */
30
+ variant?: string;
31
+ }
32
+ /**
33
+ * kind 가 없는 컬럼의 일반 규칙 — 값 모양으로 추정한다.
34
+ *
35
+ * - 값 없는 연산자(`empty`/`hasChild` …) → `labels.valueless`
36
+ * - 선택지가 있으면 값 대신 라벨
37
+ * - 두 원소 범위(숫자·날짜) → `a ~ b`, 그 외 배열은 쉼표
38
+ * - 관계(`groups`)/선형(`terms`)/일정(`date`|`start`) 은 요약 문구
39
+ */
40
+ export declare function describeFilterValue(value: unknown, options?: DescribeFilterValueOptions): string;
41
+ /**
42
+ * kind 경로의 문구 — 값 없는 연산자·빈 값을 먼저 처리하고 `operators[op].describe` 를 부른다.
43
+ * 연산자가 kind 에 없으면 `describeFilterValue` 의 일반 규칙으로 떨어진다.
44
+ */
45
+ export declare function describeFilter(kind: AnyFilterKind | undefined, operator: string | undefined, value: unknown, options?: DescribeFilterValueOptions): string;
@@ -0,0 +1,189 @@
1
+ import { isValuelessOperator } from "../types/operators";
2
+ import { isUnsetFilterValue } from "../utils/getValue";
3
+ import { formatLocalDate } from "../utils/dateText";
4
+ export const DEFAULT_DESCRIBE_LABELS = {
5
+ empty: "(없음)",
6
+ valueless: "-",
7
+ yes: "예",
8
+ no: "아니오",
9
+ more: (count) => `외 ${count}개`,
10
+ relationGroups: (groups, conditions) => `${groups}개 그룹 · 조건 ${conditions}개`,
11
+ matchAll: "모두 충족",
12
+ matchAny: "하나라도 충족",
13
+ };
14
+ const DATE_PREFIX = /^\d{4}-\d{2}-\d{2}/;
15
+ const ISO_TIME_PREFIX = /^\d{4}-\d{2}-\d{2}T/;
16
+ function ctxOf(options) {
17
+ return {
18
+ header: options.header ?? "",
19
+ labels: options.labels ?? DEFAULT_DESCRIBE_LABELS,
20
+ options: options.options,
21
+ relationColumns: options.relationColumns,
22
+ maxListItems: options.maxListItems,
23
+ };
24
+ }
25
+ const labelMap = (options) => options ? new Map(options.map((o) => [o.value, o.label])) : undefined;
26
+ /** 스칼라 하나 — 선택지 라벨 · 예/아니오 · 날짜(`YYYY-MM-DD`) · 객체는 JSON */
27
+ export function describeScalar(value, options = {}) {
28
+ const ctx = ctxOf(options);
29
+ const labels = labelMap(ctx.options);
30
+ if (value === null || value === undefined || value === "")
31
+ return ctx.labels.empty;
32
+ if (value === true)
33
+ return ctx.labels.yes;
34
+ if (value === false)
35
+ return ctx.labels.no;
36
+ if (value instanceof Date)
37
+ return formatLocalDate(value) ?? ctx.labels.empty;
38
+ if (typeof value === "string") {
39
+ const mapped = labels?.get(value);
40
+ if (mapped !== undefined)
41
+ return mapped;
42
+ // 기존 SearchConfig 의 Date 직렬화(ISO 시각) 는 날짜만 보인다
43
+ if (ISO_TIME_PREFIX.test(value))
44
+ return value.slice(0, 10);
45
+ return value;
46
+ }
47
+ if (typeof value === "number" || typeof value === "bigint") {
48
+ return labels?.get(String(value)) ?? String(value);
49
+ }
50
+ if (typeof value === "object")
51
+ return JSON.stringify(value);
52
+ return String(value);
53
+ }
54
+ const isRangeElement = (v) => v === null || v === undefined || v === "" || typeof v === "number" || v instanceof Date
55
+ || (typeof v === "string" && DATE_PREFIX.test(v));
56
+ const isRangeAnchor = (v) => typeof v === "number" || v instanceof Date || (typeof v === "string" && DATE_PREFIX.test(v));
57
+ /** 두 경계 — `a ~ b`, 빈 쪽은 `…`, 둘 다 비면 empty */
58
+ export function describeRange(value, options = {}) {
59
+ const ctx = ctxOf(options);
60
+ if (!Array.isArray(value))
61
+ return describeScalar(value, options);
62
+ const [lo, hi] = value;
63
+ const unsetLo = lo === null || lo === undefined || lo === "";
64
+ const unsetHi = hi === null || hi === undefined || hi === "";
65
+ if (unsetLo && unsetHi)
66
+ return ctx.labels.empty;
67
+ return `${unsetLo ? "…" : describeScalar(lo, options)} ~ ${unsetHi ? "…" : describeScalar(hi, options)}`;
68
+ }
69
+ /** 목록 — 쉼표, 길면 "외 N개" */
70
+ export function describeList(value, options = {}) {
71
+ const ctx = ctxOf(options);
72
+ const list = Array.isArray(value) ? value : [value];
73
+ if (list.length === 0)
74
+ return ctx.labels.empty;
75
+ const items = list.map((v) => describeScalar(v, options));
76
+ const max = ctx.maxListItems ?? 5;
77
+ if (items.length > max)
78
+ return `${items.slice(0, max).join(", ")} ${ctx.labels.more(items.length - max)}`;
79
+ return items.join(", ");
80
+ }
81
+ /** 관계 필터 — 그룹이 전부 "equals 하나" 면 컬럼별 값 묶음, 아니면 그룹 수 */
82
+ export function describeRelation(value, options = {}) {
83
+ const ctx = ctxOf(options);
84
+ const groups = value?.groups ?? [];
85
+ if (groups.length === 0)
86
+ return ctx.labels.empty;
87
+ const label = (key) => ctx.relationColumns?.find((c) => c.key === key)?.label ?? key;
88
+ const allSingleEquals = groups.every((g) => (g.conditions?.length ?? 0) === 1 && g.conditions[0]?.operator === "equals");
89
+ if (allSingleEquals) {
90
+ const byColumn = new Map();
91
+ for (const group of groups) {
92
+ const condition = group.conditions[0];
93
+ if (!condition?.column)
94
+ continue;
95
+ const list = byColumn.get(condition.column) ?? [];
96
+ list.push(describeScalar(condition.value, { labels: ctx.labels }));
97
+ byColumn.set(condition.column, list);
98
+ }
99
+ const parts = Array.from(byColumn, ([column, values]) => `${label(column)}: ${values.join(", ")}`);
100
+ if (parts.length > 0)
101
+ return parts.join(" / ");
102
+ }
103
+ const conditionCount = groups.reduce((sum, g) => sum + (g.conditions?.length ?? 0), 0);
104
+ return ctx.labels.relationGroups(groups.length, conditionCount);
105
+ }
106
+ const QUANTITY_OP_SYMBOL = { eq: "=", gte: "≥", lte: "≤", gt: ">", lt: "<" };
107
+ /** 선형결합 필터 — "볼트 ≥2, 너트 (모두 충족)" */
108
+ export function describeLinear(value, options = {}) {
109
+ const ctx = ctxOf(options);
110
+ const terms = value?.terms ?? [];
111
+ if (terms.length === 0)
112
+ return ctx.labels.empty;
113
+ const items = terms.map((term) => {
114
+ const name = term.target_name ?? term.target_code ?? `#${term.target_idx}`;
115
+ if (term.quantity === undefined || value.mode === "exists")
116
+ return name;
117
+ return `${name} ${QUANTITY_OP_SYMBOL[term.quantity_op ?? "gte"] ?? "≥"}${term.quantity}`;
118
+ });
119
+ return `${items.join(", ")} (${value.match_all ? ctx.labels.matchAll : ctx.labels.matchAny})`;
120
+ }
121
+ /** 일정 필터 — 날짜 하나 또는 기간 */
122
+ export function describeSchedule(value, options = {}) {
123
+ const ctx = ctxOf(options);
124
+ if (typeof value.date === "string" && value.date)
125
+ return describeScalar(value.date, options);
126
+ const start = typeof value.start === "string" && value.start ? describeScalar(value.start, options) : "";
127
+ const end = typeof value.end === "string" && value.end ? describeScalar(value.end, options) : "";
128
+ if (!start && !end)
129
+ return ctx.labels.empty;
130
+ return `${start || "…"} ~ ${end || "…"}`;
131
+ }
132
+ const RANGE_OPERATORS = new Set(["between", "betweenInclusive", "outsideRange", "dateBetween"]);
133
+ /**
134
+ * kind 가 없는 컬럼의 일반 규칙 — 값 모양으로 추정한다.
135
+ *
136
+ * - 값 없는 연산자(`empty`/`hasChild` …) → `labels.valueless`
137
+ * - 선택지가 있으면 값 대신 라벨
138
+ * - 두 원소 범위(숫자·날짜) → `a ~ b`, 그 외 배열은 쉼표
139
+ * - 관계(`groups`)/선형(`terms`)/일정(`date`|`start`) 은 요약 문구
140
+ */
141
+ export function describeFilterValue(value, options = {}) {
142
+ const ctx = ctxOf(options);
143
+ const { operator, variant } = options;
144
+ if (operator && isValuelessOperator(operator))
145
+ return ctx.labels.valueless;
146
+ if (value === null || value === undefined || value === "")
147
+ return ctx.labels.empty;
148
+ if (Array.isArray(value)) {
149
+ if (value.length === 0)
150
+ return ctx.labels.empty;
151
+ const rangeOperator = operator === undefined || RANGE_OPERATORS.has(operator);
152
+ if (value.length === 2 && rangeOperator && !ctx.options && value.every(isRangeElement) && value.some(isRangeAnchor)) {
153
+ return describeRange(value, options);
154
+ }
155
+ return describeList(value, options);
156
+ }
157
+ if (typeof value === "object") {
158
+ const record = value;
159
+ if (variant === "relation" || Array.isArray(record.groups)) {
160
+ return describeRelation(value, options);
161
+ }
162
+ if (variant === "linear" || Array.isArray(record.terms)) {
163
+ return describeLinear(value, options);
164
+ }
165
+ if (variant === "schedule" || "date" in record || "start" in record || "end" in record) {
166
+ return describeSchedule(record, options);
167
+ }
168
+ if (value instanceof Date)
169
+ return describeScalar(value, options);
170
+ return JSON.stringify(value);
171
+ }
172
+ return describeScalar(value, options);
173
+ }
174
+ /**
175
+ * kind 경로의 문구 — 값 없는 연산자·빈 값을 먼저 처리하고 `operators[op].describe` 를 부른다.
176
+ * 연산자가 kind 에 없으면 `describeFilterValue` 의 일반 규칙으로 떨어진다.
177
+ */
178
+ export function describeFilter(kind, operator, value, options = {}) {
179
+ const def = kind && operator ? kind.operators[operator] : undefined;
180
+ if (!def)
181
+ return describeFilterValue(value, options);
182
+ const ctx = ctxOf(options);
183
+ if (def.valueless)
184
+ return ctx.labels.valueless;
185
+ const empty = kind?.isEmpty ? kind.isEmpty(value) : isUnsetFilterValue(value);
186
+ if (empty)
187
+ return ctx.labels.empty;
188
+ return def.describe(value, ctx);
189
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * 필터 kind 런타임 — `defineFilterKind` · 레지스트리 `filterKinds` · 컬럼에서 kind 해석.
3
+ * 타입은 `types/filterKind.ts`, 내장 kind 는 `filters/kinds/**`.
4
+ */
5
+ import type { RowData } from "@tanstack/react-table";
6
+ import type { TableColumnDef } from "../types/column";
7
+ import type { AnyFilterKind, CheckedFilterSpec, FilterKind, FilterKindDef, FilterKindInput, FilterKindRef, FilterOperatorDef, FilterSpecOf, FilterVariant } from "../types";
8
+ /**
9
+ * 정의 → 브랜드된 kind. `operators` 의 키 순서를 `operatorNames` 로 남긴다.
10
+ * 값·연산자 타입은 `operators` 에서 추론된다 (`FilterKindInput` 참조) — 나머지 필드는 그 타입으로 검사된다.
11
+ */
12
+ export declare function defineFilterKind<Id extends string, TValue, TOp extends string, TRow = unknown>(def: FilterKindInput<Id, TValue, TOp, TRow>): FilterKind<Id, TValue, TOp, TRow>;
13
+ export declare function isFilterKind(value: unknown): value is AnyFilterKind;
14
+ /**
15
+ * `operators` 표를 이름 목록에서 만든다 — 내장 kind 가 백엔드 연산자 목록(`*_OPERATORS`)을
16
+ * 그대로 키로 써서 1:1 을 유지하는 통로다.
17
+ */
18
+ export declare function operatorTable<TOp extends string, TValue, TRow = unknown>(names: readonly TOp[], build: (op: TOp) => FilterOperatorDef<TValue, TRow>): Record<TOp, FilterOperatorDef<TValue, TRow>>;
19
+ /** `with()` 가 받는 덮어쓰기 — kind 전체 또는 표시 부분(editor/chip)만 */
20
+ export type FilterKindPatch = AnyFilterKind | Partial<Pick<FilterKindDef<string, any, string, any>, "editor" | "chip">>;
21
+ export interface FilterKindStore {
22
+ /** 같은 id 가 있으면 교체 */
23
+ register(kind: AnyFilterKind): void;
24
+ get(id: string): AnyFilterKind | undefined;
25
+ has(id: string): boolean;
26
+ list(): AnyFilterKind[];
27
+ /**
28
+ * 불변 파생 — `{ [id]: kind | { editor, chip } }` 또는 kind 배열을 얹은 새 저장소.
29
+ * 표시 부분만 주면 같은 id 의 기존 kind 위에 병합한다 (Provider 가 editor 를 끼우는 통로).
30
+ */
31
+ with(overrides: Record<string, FilterKindPatch> | AnyFilterKind[]): FilterKindStore;
32
+ }
33
+ export declare function createFilterKindStore(base?: AnyFilterKind[]): FilterKindStore;
34
+ /** 전역 기본 레지스트리 — 내장 kind 는 `filters/kinds/index.ts` 가 여기 등록한다 */
35
+ export declare const filterKinds: FilterKindStore;
36
+ /** `filter.kind` (객체 또는 id) → kind 객체. id 가 미등록이면 undefined (variant 경로로 폴백) */
37
+ export declare function resolveFilterKindRef(ref: FilterKindRef | undefined, store?: FilterKindStore): AnyFilterKind | undefined;
38
+ export declare function resolveFilterKind<T extends RowData>(column: TableColumnDef<T> | undefined, store?: FilterKindStore): AnyFilterKind | undefined;
39
+ /** kind 의 기본 입력 UI 힌트 — `variant` > `dataKind` 유추 > `"custom"` */
40
+ export declare function filterKindVariant(kind: AnyFilterKind): FilterVariant;
41
+ /** 미입력 판정 — kind 의 `isEmpty`, 없으면 공통 규칙 */
42
+ export declare function isFilterValueEmpty(kind: AnyFilterKind | undefined, value: unknown): boolean;
43
+ /** 요청에 실을 값 — `operators[op].serialize`, 없으면 그대로 */
44
+ export declare function serializeFilterValue(kind: AnyFilterKind | undefined, operator: string | undefined, value: unknown): unknown;
45
+ /** 서버 연산자 이름 — `wire`, 없으면 키 그대로 */
46
+ export declare function wireOperator(kind: AnyFilterKind | undefined, operator: string): string;
47
+ /**
48
+ * 컬럼에 kind 를 주는 타입 안전한 spec — `filter: filterSpec(moneyKind, { defaultOperator: "gte" })`.
49
+ * 레지스트리에 등록하지 않은 kind 객체에 연산자·기본값을 주는 통로다 — 제네릭 `K` 자리에서
50
+ * 연산자·값이 검사되고, 결과는 `CheckedFilterSpec`(브랜드만, 런타임 속성 없음) 으로 `filter` 에 들어간다.
51
+ */
52
+ export declare function filterSpec<K extends AnyFilterKind>(kind: K, spec?: Omit<FilterSpecOf<K>, "kind">): CheckedFilterSpec;
@@ -0,0 +1,110 @@
1
+ import { isUnsetFilterValue } from "../utils/getValue";
2
+ /**
3
+ * 정의 → 브랜드된 kind. `operators` 의 키 순서를 `operatorNames` 로 남긴다.
4
+ * 값·연산자 타입은 `operators` 에서 추론된다 (`FilterKindInput` 참조) — 나머지 필드는 그 타입으로 검사된다.
5
+ */
6
+ export function defineFilterKind(def) {
7
+ const operatorNames = Object.keys(def.operators);
8
+ if (!(def.defaultOperator in def.operators)) {
9
+ throw new Error(`[koko-table] defineFilterKind("${def.id}"): defaultOperator "${def.defaultOperator}" 가 operators 에 없습니다.`);
10
+ }
11
+ for (const op of def.offered ?? []) {
12
+ if (!(op in def.operators)) {
13
+ throw new Error(`[koko-table] defineFilterKind("${def.id}"): offered "${op}" 가 operators 에 없습니다.`);
14
+ }
15
+ }
16
+ return { ...def, __filterKind: true, operatorNames };
17
+ }
18
+ export function isFilterKind(value) {
19
+ return !!value && typeof value === "object" && value.__filterKind === true
20
+ && typeof value.id === "string";
21
+ }
22
+ /**
23
+ * `operators` 표를 이름 목록에서 만든다 — 내장 kind 가 백엔드 연산자 목록(`*_OPERATORS`)을
24
+ * 그대로 키로 써서 1:1 을 유지하는 통로다.
25
+ */
26
+ export function operatorTable(names, build) {
27
+ const table = {};
28
+ for (const op of names)
29
+ table[op] = build(op);
30
+ return table;
31
+ }
32
+ export function createFilterKindStore(base = []) {
33
+ const items = new Map(base.map((k) => [k.id, k]));
34
+ const store = {
35
+ register(kind) {
36
+ if (!isFilterKind(kind)) {
37
+ throw new Error("[koko-table] filterKinds.register: defineFilterKind 로 만든 객체만 등록할 수 있습니다.");
38
+ }
39
+ items.set(kind.id, kind);
40
+ },
41
+ get: (id) => items.get(id),
42
+ has: (id) => items.has(id),
43
+ list: () => Array.from(items.values()),
44
+ with(overrides) {
45
+ const next = createFilterKindStore(store.list());
46
+ const entries = Array.isArray(overrides)
47
+ ? overrides.map((k) => [k.id, k])
48
+ : Object.entries(overrides);
49
+ for (const [id, patch] of entries) {
50
+ if (isFilterKind(patch)) {
51
+ next.register(patch.id === id ? patch : { ...patch, id });
52
+ continue;
53
+ }
54
+ const current = items.get(id);
55
+ if (!current)
56
+ continue; // 정의 없는 id 에 표시 부분만 오면 무시한다 — 판정 근거가 없다
57
+ next.register({ ...current, ...patch });
58
+ }
59
+ return next;
60
+ },
61
+ };
62
+ return store;
63
+ }
64
+ /** 전역 기본 레지스트리 — 내장 kind 는 `filters/kinds/index.ts` 가 여기 등록한다 */
65
+ export const filterKinds = createFilterKindStore();
66
+ /** `filter.kind` (객체 또는 id) → kind 객체. id 가 미등록이면 undefined (variant 경로로 폴백) */
67
+ export function resolveFilterKindRef(ref, store = filterKinds) {
68
+ if (!ref)
69
+ return undefined;
70
+ if (typeof ref === "string")
71
+ return store.get(ref);
72
+ return isFilterKind(ref) ? ref : undefined;
73
+ }
74
+ export function resolveFilterKind(column, store = filterKinds) {
75
+ return resolveFilterKindRef(column?.filter?.kind, store);
76
+ }
77
+ /** kind 의 기본 입력 UI 힌트 — `variant` > `dataKind` 유추 > `"custom"` */
78
+ export function filterKindVariant(kind) {
79
+ if (kind.variant)
80
+ return kind.variant;
81
+ switch (kind.dataKind) {
82
+ case "number": return "number";
83
+ case "date": return "date";
84
+ case "boolean": return "boolean";
85
+ case "relation": return "relation";
86
+ case "text": return "text";
87
+ default: return "custom";
88
+ }
89
+ }
90
+ /** 미입력 판정 — kind 의 `isEmpty`, 없으면 공통 규칙 */
91
+ export function isFilterValueEmpty(kind, value) {
92
+ return kind?.isEmpty ? kind.isEmpty(value) : isUnsetFilterValue(value);
93
+ }
94
+ /** 요청에 실을 값 — `operators[op].serialize`, 없으면 그대로 */
95
+ export function serializeFilterValue(kind, operator, value) {
96
+ const def = kind && operator ? kind.operators[operator] : undefined;
97
+ return def?.serialize ? def.serialize(value) : value;
98
+ }
99
+ /** 서버 연산자 이름 — `wire`, 없으면 키 그대로 */
100
+ export function wireOperator(kind, operator) {
101
+ return kind?.operators[operator]?.wire ?? operator;
102
+ }
103
+ /**
104
+ * 컬럼에 kind 를 주는 타입 안전한 spec — `filter: filterSpec(moneyKind, { defaultOperator: "gte" })`.
105
+ * 레지스트리에 등록하지 않은 kind 객체에 연산자·기본값을 주는 통로다 — 제네릭 `K` 자리에서
106
+ * 연산자·값이 검사되고, 결과는 `CheckedFilterSpec`(브랜드만, 런타임 속성 없음) 으로 `filter` 에 들어간다.
107
+ */
108
+ export function filterSpec(kind, spec = {}) {
109
+ return { ...spec, kind };
110
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * 리스트 연산자 표 — enum · commonCode · cascade 가 공유한다.
3
+ *
4
+ * 판정은 `filters/registry.ts` 의 List 분기(`matchColumnFilter` 8단계)와 같은 함수를 부른다.
5
+ * `equals`/`notEquals` 는 텍스트 경로(백엔드는 enum 컬럼도 TextFilter 로 받는다).
6
+ */
7
+ import type { ListOperator } from "../../types/operators";
8
+ import type { FilterOperatorDef } from "../../types/filterKind";
9
+ export type EnumFilterValue = string | number | Array<string | number>;
10
+ export type EnumOperator = ListOperator | "equals" | "notEquals";
11
+ export declare const ENUM_OPERATORS: readonly EnumOperator[];
12
+ export declare function matchListOperator(cellValue: unknown, filterValue: unknown, operator: ListOperator): boolean;
13
+ export declare function listOperatorDef(op: EnumOperator): FilterOperatorDef<EnumFilterValue>;
@@ -0,0 +1,42 @@
1
+ import { LIST_OPERATORS } from "../../types/operators";
2
+ import { matchArrayCell, matchList, matchListBetween, toListFilterValue } from "../list";
3
+ import { matchText } from "../text";
4
+ import { describeList, describeRange } from "../describe";
5
+ export const ENUM_OPERATORS = [...LIST_OPERATORS, "equals", "notEquals"];
6
+ export function matchListOperator(cellValue, filterValue, operator) {
7
+ switch (operator) {
8
+ case "between":
9
+ return matchListBetween(cellValue, filterValue);
10
+ case "notIn":
11
+ case "notInArray":
12
+ return matchList(cellValue, filterValue, true);
13
+ case "arrIncludes":
14
+ return matchArrayCell(cellValue, filterValue, "one");
15
+ case "arrIncludesSome":
16
+ return matchArrayCell(cellValue, filterValue, "some");
17
+ case "arrIncludesAll":
18
+ return matchArrayCell(cellValue, filterValue, "all");
19
+ default:
20
+ return matchList(cellValue, filterValue, false);
21
+ }
22
+ }
23
+ export function listOperatorDef(op) {
24
+ if (op === "equals" || op === "notEquals") {
25
+ return {
26
+ client: (cell, value) => matchText(cell, value, op),
27
+ describe: (value, ctx) => describeList(value, ctx),
28
+ };
29
+ }
30
+ if (op === "between") {
31
+ return {
32
+ client: (cell, value) => matchListOperator(cell, value, op),
33
+ describe: (value, ctx) => describeRange(value, ctx),
34
+ };
35
+ }
36
+ return {
37
+ client: (cell, value) => matchListOperator(cell, value, op),
38
+ // 스칼라는 `[value]` 로 — 서버 `ListFilter.apply` 가 문자열을 글자 단위로 쪼개는 것을 막는다
39
+ serialize: (value) => toListFilterValue(value),
40
+ describe: (value, ctx) => describeList(value, ctx),
41
+ };
42
+ }
@@ -0,0 +1,3 @@
1
+ export type BooleanFilterValue = boolean | "true" | "false";
2
+ /** 백엔드는 `equals` 만 — 문자열 비교(`"true"` === `String(true)`) */
3
+ export declare const booleanKind: import("../..").FilterKind<"boolean", BooleanFilterValue, "equals", unknown>;
@@ -0,0 +1,21 @@
1
+ import { defineFilterKind } from "../kind";
2
+ import { isUnsetFilterValue } from "../../utils/getValue";
3
+ /** 백엔드는 `equals` 만 — 문자열 비교(`"true"` === `String(true)`) */
4
+ export const booleanKind = defineFilterKind({
5
+ id: "boolean",
6
+ dataKind: "boolean",
7
+ variant: "boolean",
8
+ operators: {
9
+ equals: {
10
+ client: (cell, value) => String(cell) === String(value),
11
+ describe: (value, ctx) => {
12
+ const mapped = ctx.options?.find((o) => o.value === String(value))?.label;
13
+ if (mapped !== undefined)
14
+ return mapped;
15
+ return value === true || value === "true" ? ctx.labels.yes : ctx.labels.no;
16
+ },
17
+ },
18
+ },
19
+ defaultOperator: "equals",
20
+ isEmpty: isUnsetFilterValue,
21
+ });
@@ -0,0 +1,6 @@
1
+ import { type EnumFilterValue, type EnumOperator } from "./_list";
2
+ /**
3
+ * 통합 cascade — enum 과 같은 판정에 `meta.cascadeFilterLevels`(레벨별 실제 필드)가 붙는다.
4
+ * 레벨 연산자는 `deriveOperators` 가 메타를 펼쳐 채운다.
5
+ */
6
+ export declare const cascadeKind: import("../..").FilterKind<"cascade", EnumFilterValue, EnumOperator, unknown>;
@@ -0,0 +1,16 @@
1
+ import { defineFilterKind, operatorTable } from "../kind";
2
+ import { ENUM_OPERATORS, listOperatorDef } from "./_list";
3
+ import { isUnsetFilterValue } from "../../utils/getValue";
4
+ /**
5
+ * 통합 cascade — enum 과 같은 판정에 `meta.cascadeFilterLevels`(레벨별 실제 필드)가 붙는다.
6
+ * 레벨 연산자는 `deriveOperators` 가 메타를 펼쳐 채운다.
7
+ */
8
+ export const cascadeKind = defineFilterKind({
9
+ id: "cascade",
10
+ dataKind: "text",
11
+ variant: "select",
12
+ operators: operatorTable(ENUM_OPERATORS, listOperatorDef),
13
+ defaultOperator: "inArray",
14
+ offered: ["inArray", "notInArray"],
15
+ isEmpty: isUnsetFilterValue,
16
+ });
@@ -0,0 +1,3 @@
1
+ import { type EnumFilterValue, type EnumOperator } from "./_list";
2
+ /** 공통코드 — 값은 idx, 라벨은 `meta.selectOptions`. 다중 선택이 기본 */
3
+ export declare const commonCodeKind: import("../..").FilterKind<"commonCode", EnumFilterValue, EnumOperator, unknown>;
@@ -0,0 +1,13 @@
1
+ import { defineFilterKind, operatorTable } from "../kind";
2
+ import { ENUM_OPERATORS, listOperatorDef } from "./_list";
3
+ import { isUnsetFilterValue } from "../../utils/getValue";
4
+ /** 공통코드 — 값은 idx, 라벨은 `meta.selectOptions`. 다중 선택이 기본 */
5
+ export const commonCodeKind = defineFilterKind({
6
+ id: "commonCode",
7
+ dataKind: "text",
8
+ variant: "multiSelect",
9
+ operators: operatorTable(ENUM_OPERATORS, listOperatorDef),
10
+ defaultOperator: "inArray",
11
+ offered: ["inArray", "notInArray"],
12
+ isEmpty: isUnsetFilterValue,
13
+ });
@@ -0,0 +1,9 @@
1
+ import type { DateOperator } from "../../types/operators";
2
+ export type DateBound = string | Date | null;
3
+ /** `YYYY-MM-DD`(또는 Date) 하나 · 범위 `[lo, hi]` · `inPeriod` 토큰 */
4
+ export type DateFilterValue = string | Date | [DateBound, DateBound];
5
+ /**
6
+ * date · datetime 공용. `inPeriod` 도 백엔드 `DateFilter` 의 연산자라 여기 포함한다
7
+ * (`period` kind 는 기간 토큰만 쓰는 컬럼용 축약본).
8
+ */
9
+ export declare const dateKind: import("../..").FilterKind<"date", DateFilterValue, DateOperator, unknown>;
@@ -0,0 +1,32 @@
1
+ import { DATE_OPERATORS } from "../../types/operators";
2
+ import { defineFilterKind, operatorTable } from "../kind";
3
+ import { matchDate } from "../date";
4
+ import { describeRange, describeScalar } from "../describe";
5
+ import { isUnsetFilterValue } from "../../utils/getValue";
6
+ import { toDateOnly } from "../../utils/dateText";
7
+ const RANGE = new Set(["between", "betweenInclusive", "dateBetween"]);
8
+ /**
9
+ * date · datetime 공용. `inPeriod` 도 백엔드 `DateFilter` 의 연산자라 여기 포함한다
10
+ * (`period` kind 는 기간 토큰만 쓰는 컬럼용 축약본).
11
+ */
12
+ export const dateKind = defineFilterKind({
13
+ id: "date",
14
+ dataKind: "date",
15
+ variant: "date",
16
+ operators: operatorTable(DATE_OPERATORS, (op) => ({
17
+ client: (cell, value, ctx) => matchDate(cell, value, op, ctx.now),
18
+ describe: (value, ctx) => {
19
+ if (op === "inPeriod")
20
+ return ctx.labels.periods?.[String(value)] ?? describeScalar(value, ctx);
21
+ return RANGE.has(op) ? describeRange(value, ctx) : describeScalar(value, ctx);
22
+ },
23
+ })),
24
+ defaultOperator: "betweenInclusive",
25
+ offered: ["betweenInclusive", "inPeriod"],
26
+ isEmpty: isUnsetFilterValue,
27
+ // URL·프리셋에는 `YYYY-MM-DD` 만 — 구 SearchConfig 의 ISO 시각 문자열·Date 객체를 정규화한다
28
+ codec: {
29
+ encode: (value) => toDateOnly(value),
30
+ decode: (raw) => (raw === undefined || raw === null ? undefined : toDateOnly(raw)),
31
+ },
32
+ });
@@ -0,0 +1,4 @@
1
+ import { type EnumFilterValue, type EnumOperator } from "./_list";
2
+ export type { EnumFilterValue, EnumOperator };
3
+ /** select / multiSelect — 선택지는 `meta.selectOptions`, 구분은 `filter.variant` */
4
+ export declare const enumKind: import("../..").FilterKind<"enum", EnumFilterValue, EnumOperator, unknown>;
@@ -0,0 +1,13 @@
1
+ import { defineFilterKind, operatorTable } from "../kind";
2
+ import { ENUM_OPERATORS, listOperatorDef } from "./_list";
3
+ import { isUnsetFilterValue } from "../../utils/getValue";
4
+ /** select / multiSelect — 선택지는 `meta.selectOptions`, 구분은 `filter.variant` */
5
+ export const enumKind = defineFilterKind({
6
+ id: "enum",
7
+ dataKind: "text",
8
+ variant: "select",
9
+ operators: operatorTable(ENUM_OPERATORS, listOperatorDef),
10
+ defaultOperator: "inArray",
11
+ offered: ["inArray", "notInArray"],
12
+ isEmpty: isUnsetFilterValue,
13
+ });
@@ -0,0 +1,49 @@
1
+ /**
2
+ * 내장 필터 kind — 전부 `defineFilterKind` 로 정의하고 전역 `filterKinds` 에 등록한다.
3
+ * helper 프리셋·`ColumnBuilder` 가 `filter.kind` 에 이것을 넣는다(dogfooding).
4
+ */
5
+ import type { AnyFilterKind, FilterVariant } from "../../types";
6
+ import { textKind } from "./text";
7
+ import { numberKind } from "./number";
8
+ import { dateKind } from "./date";
9
+ import { periodKind } from "./period";
10
+ import { booleanKind } from "./boolean";
11
+ import { enumKind } from "./enum";
12
+ import { commonCodeKind } from "./commonCode";
13
+ import { cascadeKind } from "./cascade";
14
+ import { relationKind } from "./relation";
15
+ import { scheduleKind } from "./schedule";
16
+ import { linearKind } from "./linear";
17
+ export { textKind, numberKind, dateKind, periodKind, booleanKind, enumKind, commonCodeKind, cascadeKind, relationKind, scheduleKind, linearKind };
18
+ export type { TextFilterValue } from "./text";
19
+ export type { NumberFilterValue, NumberBound } from "./number";
20
+ export type { DateFilterValue, DateBound } from "./date";
21
+ export type { PeriodFilterValue } from "./period";
22
+ export type { BooleanFilterValue } from "./boolean";
23
+ export type { EnumFilterValue, EnumOperator } from "./_list";
24
+ export type { RelationKindValue } from "./relation";
25
+ export type { ScheduleFilterValue } from "./schedule";
26
+ export { ENUM_OPERATORS, matchListOperator } from "./_list";
27
+ export declare const BUILTIN_FILTER_KINDS: readonly [import("../..").FilterKind<"text", import("./text").TextFilterValue, import("../..").TextOperator, unknown>, import("../..").FilterKind<"number", import("./number").NumberFilterValue, import("../..").NumberOperator, unknown>, import("../..").FilterKind<"date", import("./date").DateFilterValue, import("../..").DateOperator, unknown>, import("../..").FilterKind<"period", string, "inPeriod", unknown>, import("../..").FilterKind<"boolean", import("./boolean").BooleanFilterValue, "equals", unknown>, import("../..").FilterKind<"enum", import("./_list").EnumFilterValue, import("./_list").EnumOperator, unknown>, import("../..").FilterKind<"commonCode", import("./_list").EnumFilterValue, import("./_list").EnumOperator, unknown>, import("../..").FilterKind<"cascade", import("./_list").EnumFilterValue, import("./_list").EnumOperator, unknown>, import("../..").FilterKind<"relation", import("./relation").RelationKindValue, import("../..").RelationOperator, unknown>, import("../..").FilterKind<"schedule", import("./schedule").ScheduleFilterValue, import("../..").ScheduleOperator, unknown>, import("../..").FilterKind<"linear", import("./linear").LinearFilterValue, import("../..").LinearOperator, unknown>];
28
+ /** 문자열 id 좁힘용 — `FilterKindRegistry` 가 이 맵을 상속한다 */
29
+ declare module "../../types/filterKind" {
30
+ interface BuiltinFilterKindMap {
31
+ text: typeof textKind;
32
+ number: typeof numberKind;
33
+ date: typeof dateKind;
34
+ period: typeof periodKind;
35
+ boolean: typeof booleanKind;
36
+ enum: typeof enumKind;
37
+ commonCode: typeof commonCodeKind;
38
+ cascade: typeof cascadeKind;
39
+ relation: typeof relationKind;
40
+ schedule: typeof scheduleKind;
41
+ linear: typeof linearKind;
42
+ }
43
+ }
44
+ /**
45
+ * variant → 내장 kind. `ColumnBuilder.setVariant` / `dataType` 유추가 kind 를 함께 붙이는 표.
46
+ * `custom` 은 kind 가 없다(호출부가 `render` 로 값 해석을 전담).
47
+ */
48
+ export declare const BUILTIN_KIND_BY_VARIANT: Partial<Record<FilterVariant, AnyFilterKind>>;
49
+ export declare function builtinKindForVariant(variant: FilterVariant): AnyFilterKind | undefined;