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,94 @@
1
+ import type { ReactNode } from "react";
2
+ import type { FilterOperator, FilterVariant } from "./operators";
3
+ import type { ColumnMeta } from "./column";
4
+ import type { AnyFilterKind, CheckedFilterSpec, FilterKindRef, RegisteredFilterSpec, UnregisteredFilterSpec } from "./filterKind";
5
+ export * from "./filterKind";
6
+ /**
7
+ * 필터 입력 하나가 그려지는 데 필요한 전부.
8
+ *
9
+ * 여기에 **table 도 column 인스턴스도 없다**. 그래서 이 계약으로 그린 필터는
10
+ * 사이드패널·상단바·모달·카드 화면 어디서든 같은 코드로 동작한다.
11
+ */
12
+ export interface FilterField<V = unknown> {
13
+ /** 컬럼 id (= 서버 요청의 필터 키) */
14
+ id: string;
15
+ /** 필터 라벨. 컬럼 헤더에서 옴 */
16
+ header: ReactNode;
17
+ /** 입력 UI 종류. kind 가 있으면 `filter.variant ?? kind.variant` (editor 폴백 선택용) */
18
+ variant: FilterVariant;
19
+ /** 컬럼이 선언한 필터 kind (해석된 객체). 렌더러는 `kind.editor` 를 폴백으로 쓴다 */
20
+ kind?: AnyFilterKind;
21
+ meta?: ColumnMeta;
22
+ value: V | undefined;
23
+ onChange: (value: V | undefined) => void;
24
+ operator: FilterOperator;
25
+ onOperatorChange: (operator: FilterOperator) => void;
26
+ /** 이 컬럼이 허용하는 연산자. 길이 1 이하면 연산자 선택 UI 를 숨긴다 */
27
+ operatorOptions: readonly FilterOperator[];
28
+ /**
29
+ * 값을 즉시 조회에 반영한다 (검색 버튼을 거치지 않는 필터용).
30
+ * 미지정이면 draft 에만 쌓이고 `TableSearch.apply()` 를 기다린다.
31
+ */
32
+ apply?: () => void;
33
+ /** 컬럼이 선언한 커스텀 렌더러 (`FilterSpec.render`) */
34
+ render?: FilterRender<V>;
35
+ /** "상세 조건" 접이식 그룹으로 내릴 필드인가 (`FilterSpec.detail`) */
36
+ detail?: boolean;
37
+ disabled?: boolean;
38
+ }
39
+ export type FilterRender<V = unknown> = (field: FilterField<V>) => ReactNode;
40
+ /**
41
+ * 필터 UI 를 그리는 컴포넌트가 의존하는 계약은 `./sources` 로 옮겼다.
42
+ * 화면을 필터/콘텐츠/페이지네이션 세 구역으로 나누는 계약이 한자리에 모여 있어야
43
+ * "어느 구역이 무엇에 의존하는가"가 한눈에 보인다.
44
+ */
45
+ export type { FilterSource, ContentSource, ContentStatus, PaginationSource, PaginationInfo, SelectionSource, } from "./sources";
46
+ /**
47
+ * 컬럼 정의에 붙는 필터 선언.
48
+ *
49
+ * 기존에 `filterFn` + `columnFilterModeOptions` + `Filter` 렌더 prop +
50
+ * `meta.hideFilter` 로 흩어져 있던 것을 한 곳으로 모은 것이다.
51
+ */
52
+ export interface FilterSpec<V = unknown> {
53
+ /**
54
+ * 필터 kind — 정의 객체(`defineFilterKind`) 또는 등록된 문자열 id.
55
+ * 있으면 연산자 후보·판정·직렬화·문구·codec 을 kind 가 결정하고, 없으면 `variant` 경로다.
56
+ * 이 타입은 **읽기용(느슨한)** 모양이다. 컬럼 정의(`TableColumnDef.filter`)는 `FilterSpecInput` 으로
57
+ * kind 별로 좁혀진다.
58
+ */
59
+ kind?: FilterKindRef;
60
+ variant?: FilterVariant;
61
+ /** 미지정 시 `OPERATORS_BY_VARIANT[variant]` */
62
+ operators?: readonly FilterOperator[];
63
+ /** 미지정 시 `operators[0]` */
64
+ defaultOperator?: FilterOperator;
65
+ /** 커스텀 입력. 지정하면 variant 기본 렌더러 대신 이것이 쓰인다 */
66
+ render?: FilterRender<V>;
67
+ /** 필터 UI 에서 완전히 제외 (기존 `meta.hideFilter` / `meta.forceHidden`) */
68
+ hidden?: boolean;
69
+ /** "상세 조건" 접이식 그룹으로 내림 (기존 `meta.isVisible === false` 파생) */
70
+ detail?: boolean;
71
+ /** 값 변경 즉시 조회 — 검색 버튼을 기다리지 않는다 */
72
+ applyOnChange?: boolean;
73
+ /**
74
+ * `applyOnChange` 의 지연(ms). 마지막 입력 뒤 이 시간이 지나야 `apply()` 가 나간다.
75
+ * 컬럼 단위 값이 `TableSearchOptions.debounceMs` 보다 우선한다. 미지정·0 이면 즉시.
76
+ */
77
+ debounceMs?: number;
78
+ /** 초기값 */
79
+ defaultValue?: V;
80
+ }
81
+ /**
82
+ * 컬럼 정의의 `filter` 자리 — **쓰기용(좁혀진)** 모양.
83
+ *
84
+ * - kind 없음: 지금의 variant 경로(`FilterSpec<V>`, 연산자는 백엔드 목록 `FilterOperator`)
85
+ * - 등록된 kind(내장·augmentation): `FilterSpecOf<K>` — 연산자·기본값이 kind 로 좁혀진다
86
+ * - 등록되지 않은 kind 객체: 인라인이면 연산자·기본값 없이 kind 만 (`UnregisteredFilterSpec`),
87
+ * `filterSpec(kind, { … })` 를 거치면 제네릭 자리에서 검사된 뒤 들어간다 (`CheckedFilterSpec`)
88
+ *
89
+ * 필터 값 타입은 kind 가 정하고 셀 값 `V` 와 독립이다. `V` 는 variant 경로의 `render`/`defaultValue`
90
+ * 편의 타입으로만 남는다.
91
+ */
92
+ export type FilterSpecInput<V = unknown> = (FilterSpec<V> & {
93
+ kind?: undefined;
94
+ }) | RegisteredFilterSpec | UnregisteredFilterSpec | CheckedFilterSpec;
@@ -0,0 +1 @@
1
+ export * from "./filterKind";
@@ -0,0 +1,204 @@
1
+ /**
2
+ * 필터 kind — 확장 계약 (docs/extension-design.md 1절).
3
+ *
4
+ * 컬럼의 `filter.kind` 자리에 넣는 **정의 객체**다. 의미 부분(판정·직렬화·문구·codec)은
5
+ * core 가, 표시 부분(editor·chip)은 mui 가 같은 id 로 합친다(`withEditor`).
6
+ * 내장 kind(text·number·date·…)도 같은 `defineFilterKind` 로 정의한다(dogfooding).
7
+ */
8
+ import type { ReactNode } from "react";
9
+ import type { FilterOperator, FilterVariant } from "./operators";
10
+ import type { FilterRender } from "./filter";
11
+ import type { SelectOption } from "./column";
12
+ /** `operators[op].client` 가 받는 행 문맥 */
13
+ export interface FilterClientContext<TRow = unknown> {
14
+ row: TRow;
15
+ columnId: string;
16
+ /** 상대 기간(`inPeriod`) 기준 시각 — 테스트에서 고정한다 */
17
+ now?: Date;
18
+ }
19
+ /**
20
+ * describe 가 쓰는 문구. core 는 React·Provider 를 모르므로 **문자열 묶음**만 받는다
21
+ * (설계 문서의 `labels: Labels` 자리 — mui 가 자기 `labels` 에서 이 모양으로 뽑아 넘긴다).
22
+ */
23
+ export interface FilterDescribeLabels {
24
+ /** 값이 비어 있음 — 기본 "(없음)" */
25
+ empty: string;
26
+ /** 값 없는 연산자의 값 칸 — 기본 "-" */
27
+ valueless: string;
28
+ yes: string;
29
+ no: string;
30
+ /** "외 N개" */
31
+ more: (count: number) => string;
32
+ /** "N개 그룹 · 조건 M개" */
33
+ relationGroups: (groups: number, conditions: number) => string;
34
+ matchAll: string;
35
+ matchAny: string;
36
+ /** 연산자 라벨 (문구에 연산자를 섞는 kind 용) */
37
+ operators?: Partial<Record<string, string>>;
38
+ /** 상대 기간 토큰 라벨 (`period` kind) */
39
+ periods?: Partial<Record<string, string>>;
40
+ }
41
+ export interface FilterDescribeContext {
42
+ header: string;
43
+ labels: FilterDescribeLabels;
44
+ /** 선택지 라벨 — enum/commonCode 류가 값 대신 라벨을 보일 때 (`meta.selectOptions`) */
45
+ options?: readonly SelectOption[];
46
+ /** 관계 컬럼의 하위 컬럼 라벨 (`meta.relationColumns`) */
47
+ relationColumns?: ReadonlyArray<{
48
+ key: string;
49
+ label: string;
50
+ }>;
51
+ /** 배열 값이 이보다 길면 앞부분만 (기본 5) */
52
+ maxListItems?: number;
53
+ }
54
+ export interface FilterOperatorDef<TValue, TRow = unknown> {
55
+ /** 클라이언트 모드 판정. 서버 QueryBuilder 와 같은 의미여야 한다 */
56
+ client(cell: unknown, value: TValue, ctx: FilterClientContext<TRow>): boolean;
57
+ /** 요청(`columnFilters[].value`)에 실을 값. 미지정 시 그대로 */
58
+ serialize?(value: TValue): unknown;
59
+ /**
60
+ * 사람이 읽는 문구 — 필터 상태 모달·칩·AI 컨텍스트.
61
+ * 값이 비어 있거나(`isEmpty`) 값 없는 연산자면 `describeFilter` 가 먼저 처리하므로
62
+ * 여기는 **값이 있을 때만** 불린다.
63
+ */
64
+ describe(value: TValue, ctx: FilterDescribeContext): string;
65
+ /** 값 없는 연산자(empty/hasChild 류) — 값은 `true` 로 실리고 입력창을 그리지 않는다 */
66
+ valueless?: boolean;
67
+ /** 서버 연산자 이름이 다르면 매핑 (기본 = 키) */
68
+ wire?: FilterOperator;
69
+ }
70
+ export type FilterDataKind = "text" | "number" | "date" | "boolean" | "relation";
71
+ export interface FilterKindCodec<TValue> {
72
+ encode(value: TValue): unknown;
73
+ decode(raw: unknown): TValue | undefined;
74
+ }
75
+ export interface FilterKindDef<Id extends string, TValue, TOp extends string, TRow = unknown> {
76
+ id: Id;
77
+ operators: Record<TOp, FilterOperatorDef<TValue, TRow>>;
78
+ defaultOperator: TOp;
79
+ /**
80
+ * 드롭다운에 **노출**할 축약 목록 (`OFFERED_OPERATORS` 대응). 미지정 시 `operators` 전부.
81
+ * 첫 항목이 기본 연산자가 아니어도 된다 — 기본은 `defaultOperator` 다.
82
+ */
83
+ offered?: readonly TOp[];
84
+ /** URL·프리셋 직렬화 (JSON 안전 값으로). 미지정 시 그대로 */
85
+ codec?: FilterKindCodec<TValue>;
86
+ /** 비어 있음 판정 — 미입력 필터를 요청에서 뺄 때. 미지정 시 `isUnsetFilterValue` */
87
+ isEmpty?(value: TValue | undefined): boolean;
88
+ /** 서버 `column_type` 대응 — `resolveDataKind` 분기용 */
89
+ dataKind?: FilterDataKind;
90
+ /**
91
+ * 기본 입력 UI 힌트 — `editor` 가 없을 때 mui 가 variant 별 기본 입력을 고른다.
92
+ * 미지정 시 `dataKind` 에서 유추, 그것도 없으면 `"custom"`(입력을 그리지 않는다).
93
+ */
94
+ variant?: FilterVariant;
95
+ /** 렌더러가 채우는 자리 (core 는 타입만 안다) — mui `withEditor(kind, { editor })` */
96
+ editor?: FilterRender<TValue>;
97
+ /** 메서드 문법 — Provider 의 느슨한 `(value: unknown, operator: string)` 자리에 그대로 들어간다 */
98
+ chip?(value: TValue, operator: TOp): ReactNode;
99
+ }
100
+ /**
101
+ * `defineFilterKind` 의 **입력** 모양 — `FilterKindDef` 와 같은 필드지만 추론 위치를 고정한다.
102
+ * `TOp` 는 `operators` 의 키에서만, `TValue` 는 `operators[*].client/describe` 의 값 인자에서만 추론되고
103
+ * 나머지(`defaultOperator`·`offered`·`isEmpty`·`codec`·`editor`·`chip`)는 `NoInfer` 로 **검사만** 받는다.
104
+ * (그렇지 않으면 `defaultOperator: "a"` 가 TOp 를 `"a"` 로, `isEmpty: isUnsetFilterValue` 가 TValue 를 `unknown` 으로 끌어내린다.)
105
+ */
106
+ export interface FilterKindInput<Id extends string, TValue, TOp extends string, TRow = unknown> {
107
+ id: Id;
108
+ operators: Record<TOp, FilterOperatorDef<TValue, TRow>>;
109
+ defaultOperator: NoInfer<TOp>;
110
+ offered?: readonly NoInfer<TOp>[];
111
+ codec?: FilterKindCodec<NoInfer<TValue>>;
112
+ isEmpty?(value: NoInfer<TValue> | undefined): boolean;
113
+ dataKind?: FilterDataKind;
114
+ variant?: FilterVariant;
115
+ editor?: FilterRender<NoInfer<TValue>>;
116
+ chip?(value: NoInfer<TValue>, operator: NoInfer<TOp>): ReactNode;
117
+ }
118
+ /** `defineFilterKind` 가 돌려주는 브랜드된 정의 객체 (`as const` 불필요) */
119
+ export interface FilterKind<Id extends string = string, TValue = unknown, TOp extends string = string, TRow = unknown> extends FilterKindDef<Id, TValue, TOp, TRow> {
120
+ readonly __filterKind: true;
121
+ /** `operators` 의 키 (선언 순서) */
122
+ readonly operatorNames: readonly TOp[];
123
+ }
124
+ export type AnyFilterKind = FilterKind<any, any, any, any>;
125
+ export type FilterKindValue<K> = K extends FilterKind<any, infer V, any, any> ? V : never;
126
+ export type FilterKindOperator<K> = K extends FilterKind<any, any, infer O, any> ? O : never;
127
+ export type FilterKindId<K> = K extends FilterKind<infer Id, any, any, any> ? Id : never;
128
+ /**
129
+ * 문자열 id → kind 타입 맵. 소비자가 module augmentation 으로 병합한다:
130
+ *
131
+ * ```ts
132
+ * declare module "kokotable" { interface FilterKindRegistry { money: typeof moneyKind } }
133
+ * // 이후 filter: { kind: "money", defaultOperator: "gte" } — 틀리면 컴파일 에러
134
+ * ```
135
+ * 내장 kind 는 `BuiltinFilterKindMap` 으로 미리 들어 있다.
136
+ */
137
+ export interface FilterKindRegistry extends BuiltinFilterKindMap {
138
+ }
139
+ /** 내장 kind 맵 — `filters/kinds/index.ts` 가 채운다 (타입만 순환 참조) */
140
+ export interface BuiltinFilterKindMap {
141
+ }
142
+ /** 컬럼 `filter.kind` 자리에 올 수 있는 것 — kind 객체 또는 등록된 문자열 id */
143
+ export type FilterKindRef = AnyFilterKind | (keyof FilterKindRegistry & string);
144
+ /** kind 와 무관한 공통 항목 */
145
+ export interface FilterSpecCommon<V = unknown> {
146
+ /** 커스텀 입력. 지정하면 kind.editor·variant 기본 렌더러보다 우선한다 */
147
+ render?: FilterRender<V>;
148
+ /** 필터 UI 에서 완전히 제외 */
149
+ hidden?: boolean;
150
+ /** "상세 조건" 접이식 그룹으로 내림 */
151
+ detail?: boolean;
152
+ /** 값 변경 즉시 조회 */
153
+ applyOnChange?: boolean;
154
+ /** `applyOnChange` 의 지연(ms) */
155
+ debounceMs?: number;
156
+ /**
157
+ * 입력 UI 힌트. kind 가 있으면 **editor 선택에만** 쓰인다 (enum kind 의 select/multiSelect 구분 등).
158
+ * 없으면 지금의 variant 경로(연산자 후보·판정의 근거).
159
+ */
160
+ variant?: FilterVariant;
161
+ }
162
+ /** 컬럼 정의의 filter 자리 — kind 객체를 넣으면 value/operator 가 좁혀진다 */
163
+ export interface FilterSpecOf<K extends AnyFilterKind> extends FilterSpecCommon<FilterKindValue<K>> {
164
+ kind: K;
165
+ operators?: readonly FilterKindOperator<K>[];
166
+ defaultOperator?: FilterKindOperator<K>;
167
+ defaultValue?: FilterKindValue<K>;
168
+ }
169
+ /** 등록된 문자열 id 로 좁히는 버전 (`FilterKindRegistry` 병합 후) */
170
+ export type FilterSpecOfId<Id extends keyof FilterKindRegistry> = FilterKindRegistry[Id] extends AnyFilterKind ? FilterSpecOf<FilterKindRegistry[Id]> : never;
171
+ /**
172
+ * 등록된 kind(내장 + augmentation) 하나하나에 대한 좁혀진 spec 의 유니온.
173
+ * `kind` 는 객체(`numberKind`)로도 문자열(`"number"`)로도 쓸 수 있다.
174
+ */
175
+ export type RegisteredFilterSpec = {
176
+ [Id in keyof FilterKindRegistry & string]: FilterKindRegistry[Id] extends AnyFilterKind ? Omit<FilterSpecOf<FilterKindRegistry[Id]>, "kind"> & {
177
+ kind: FilterKindRegistry[Id] | Id;
178
+ } : never;
179
+ }[keyof FilterKindRegistry & string];
180
+ /**
181
+ * 등록되지 않은 kind 객체를 **인라인**으로 쓸 때 — 좁힐 근거가 없으므로 연산자·기본값을 여기서 줄 수 없다.
182
+ * 연산자·기본값을 주려면 (1) `FilterKindRegistry` 를 병합하거나 (2) `filterSpec(kind, spec)` /
183
+ * `ColumnBuilder.setFilterKind(kind, spec)` 처럼 kind 가 제네릭 인자로 잡히는 자리를 쓴다(`CheckedFilterSpec`).
184
+ * (TS 는 객체 리터럴 안에서 한 속성의 타입을 다른 속성의 값으로 좁히지 못한다 — 등록이 그 대체다.)
185
+ */
186
+ export interface UnregisteredFilterSpec extends FilterSpecCommon<any> {
187
+ kind: AnyFilterKind;
188
+ operators?: never;
189
+ defaultOperator?: never;
190
+ defaultValue?: never;
191
+ }
192
+ declare const FILTER_SPEC_CHECKED: unique symbol;
193
+ /**
194
+ * `filterSpec(kind, spec)` 이 돌려주는 모양 — 제네릭 자리에서 이미 검사됐으므로 느슨하게 들어간다.
195
+ * 브랜드 심볼은 타입에만 있다(런타임 속성 없음). 인라인 리터럴은 이 멤버에 맞지 않는다.
196
+ */
197
+ export interface CheckedFilterSpec extends FilterSpecCommon<any> {
198
+ readonly [FILTER_SPEC_CHECKED]: true;
199
+ kind: AnyFilterKind;
200
+ operators?: readonly string[];
201
+ defaultOperator?: string;
202
+ defaultValue?: unknown;
203
+ }
204
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,80 @@
1
+ import type { AggregateResult } from "../client/aggregate";
2
+ /** 그룹 경로 — `[{ key: "department", value: "영업부" }, ...]` */
3
+ export type GroupPath = Array<{
4
+ key: string;
5
+ value: unknown;
6
+ }>;
7
+ /**
8
+ * 그룹 트리 노드 — **클라이언트 트리**다.
9
+ * 서버 응답의 `GroupNode`(`types/request.ts`)는 평평한 한 레벨 요약이라 다른 타입이다.
10
+ */
11
+ export interface GroupTreeNode<T> {
12
+ /** 이 노드를 만든 컬럼 */
13
+ groupKey: string;
14
+ groupValue: unknown;
15
+ /** 표시용 라벨 (선택지가 있는 컬럼) */
16
+ label?: string;
17
+ /** 하위 말단 행 총 개수 */
18
+ count: number;
19
+ aggregates?: AggregateResult;
20
+ /** 하위 그룹 (마지막 레벨이면 없음) */
21
+ children?: Array<GroupTreeNode<T>>;
22
+ /** 마지막 레벨의 말단 행 */
23
+ rows?: T[];
24
+ /** 루트부터 이 노드까지의 경로 */
25
+ path: GroupPath;
26
+ depth: number;
27
+ /** 하위를 더 받을 수 있는가. 클라이언트 그룹핑에서는 항상 undefined */
28
+ hasMore?: boolean;
29
+ /** 지금까지 받은 하위 개수 */
30
+ loadedCount?: number;
31
+ /** 하위 전체 개수 (서버 meta.total_count) */
32
+ totalCount?: number;
33
+ /** 이 경로의 하위를 받는 중인가 — 행 단위 로딩 표시 */
34
+ isPending?: boolean;
35
+ }
36
+ /**
37
+ * 가상화용 평탄화 항목.
38
+ *
39
+ * `parentIndex` 는 직전 조상 그룹의 평탄 인덱스다 — sticky 헤더가 조상을
40
+ * 역추적할 때 O(depth) 로 끝내기 위해 평탄화 시점에 기록한다.
41
+ */
42
+ export type FlatItem<T> = {
43
+ type: "group";
44
+ node: GroupTreeNode<T>;
45
+ depth: number;
46
+ index: number;
47
+ parentIndex?: number;
48
+ } | {
49
+ type: "leaf";
50
+ row: T;
51
+ depth: number;
52
+ index: number;
53
+ parentIndex?: number;
54
+ leafIndex: number;
55
+ }
56
+ /** 서버 그룹핑의 "더 보기" 행 — 하위를 페이지 단위로 받아 온다 */
57
+ | {
58
+ type: "loadMore";
59
+ path: GroupPath;
60
+ depth: number;
61
+ index: number;
62
+ parentIndex?: number;
63
+ loaded: number;
64
+ total?: number;
65
+ isPending?: boolean;
66
+ };
67
+ /** 경로를 문자열 키로 — 확장 상태의 Set 키 */
68
+ export declare function pathKey(path: GroupPath): string;
69
+ export interface ExpandState {
70
+ isExpanded(path: GroupPath): boolean;
71
+ toggle(path: GroupPath): void;
72
+ expandAll(): void;
73
+ collapseAll(): void;
74
+ /** 지정 깊이까지만 펼친다 (0 = 전부 접기) */
75
+ expandToDepth(depth: number): void;
76
+ /** 현재 펼침 깊이 — 단계 펼치기 버튼이 다음 단계를 계산할 때 쓴다 */
77
+ readonly depth: number;
78
+ readonly maxDepth: number;
79
+ readonly canExpand: boolean;
80
+ }
@@ -0,0 +1,4 @@
1
+ /** 경로를 문자열 키로 — 확장 상태의 Set 키 */
2
+ export function pathKey(path) {
3
+ return path.map((step) => `${step.key}=${String(step.value)}`).join("/");
4
+ }
@@ -0,0 +1,8 @@
1
+ export * from "./operators";
2
+ export * from "./request";
3
+ export * from "./column";
4
+ export * from "./sources";
5
+ export * from "./filter";
6
+ export * from "./search";
7
+ export * from "./data";
8
+ export * from "./table";
@@ -0,0 +1,8 @@
1
+ export * from "./operators";
2
+ export * from "./request";
3
+ export * from "./column";
4
+ export * from "./sources";
5
+ export * from "./filter";
6
+ export * from "./search";
7
+ export * from "./data";
8
+ export * from "./table";
@@ -0,0 +1,64 @@
1
+ /**
2
+ * 필터 연산자 — 백엔드 `QueryBuilder/types.py` 와 1:1 대응한다.
3
+ *
4
+ * 이 목록이 프론트/백 공통 계약의 전부다. 여기 없는 문자열은 서버가
5
+ * 기본 연산자로 강등하므로(TextFilter → "contains", NumberFilter → "equals"),
6
+ * 새 연산자는 반드시 양쪽을 같이 늘린다.
7
+ */
8
+ export type TextOperator = "equals" | "notEquals" | "lessThan" | "lessThanOrEqualTo" | "greaterThan" | "greaterThanOrEqualTo" | "contains" | "notContains" | "startsWith" | "endsWith" | "fuzzy" | "empty" | "notEmpty";
9
+ export type NumberOperator = "equals" | "notEquals" | "lessThan" | "lessThanOrEqualTo" | "greaterThan" | "greaterThanOrEqualTo" | "between" | "betweenInclusive" | "outsideRange" | "isEmpty";
10
+ export type DateOperator = "equals" | "notEquals" | "lessThan" | "lessThanOrEqualTo" | "greaterThan" | "greaterThanOrEqualTo" | "between" | "betweenInclusive" | "dateBetween" | "inPeriod";
11
+ export type ListOperator = "in" | "notIn" | "between" | "arrIncludes" | "arrIncludesSome" | "arrIncludesAll" | "inArray" | "inArrayFilter" | "notInArray";
12
+ export type BooleanOperator = "equals";
13
+ export type RelationOperator = "hasAny" | "hasAll" | "hasChild" | "hasNotChild";
14
+ export type LinearOperator = "linearExact" | "linearContains" | "linearExists";
15
+ export type ScheduleOperator = "scheduleContains" | "scheduleOverlaps";
16
+ /** 서버가 필터를 건너뛰는 연산자 — 값 해석을 호출부가 전담한다 */
17
+ export type PassOperator = "auto" | "custom";
18
+ export type FilterOperator = TextOperator | NumberOperator | DateOperator | ListOperator | BooleanOperator | RelationOperator | LinearOperator | ScheduleOperator | PassOperator;
19
+ /** 필터 입력 UI 의 종류. 연산자 기본 후보를 고르는 기준이기도 하다. */
20
+ export type FilterVariant = "text" | "number" | "date" | "datetime" | "boolean" | "select" | "multiSelect" | "relation" | "linear" | "schedule" | "custom";
21
+ export declare const TEXT_OPERATORS: readonly ["equals", "notEquals", "lessThan", "lessThanOrEqualTo", "greaterThan", "greaterThanOrEqualTo", "contains", "notContains", "startsWith", "endsWith", "fuzzy", "empty", "notEmpty"];
22
+ export declare const NUMBER_OPERATORS: readonly ["equals", "notEquals", "lessThan", "lessThanOrEqualTo", "greaterThan", "greaterThanOrEqualTo", "between", "betweenInclusive", "outsideRange", "isEmpty"];
23
+ export declare const DATE_OPERATORS: readonly ["equals", "notEquals", "lessThan", "lessThanOrEqualTo", "greaterThan", "greaterThanOrEqualTo", "between", "betweenInclusive", "dateBetween", "inPeriod"];
24
+ export declare const LIST_OPERATORS: readonly ["in", "notIn", "between", "arrIncludes", "arrIncludesSome", "arrIncludesAll", "inArray", "inArrayFilter", "notInArray"];
25
+ export declare const BOOLEAN_OPERATORS: readonly ["equals"];
26
+ export declare const RELATION_OPERATORS: readonly ["hasAny", "hasAll", "hasChild", "hasNotChild"];
27
+ export declare const LINEAR_OPERATORS: readonly ["linearExact", "linearContains", "linearExists"];
28
+ export declare const SCHEDULE_OPERATORS: readonly ["scheduleContains", "scheduleOverlaps"];
29
+ /**
30
+ * variant → 연산자 후보. `FilterSpec.operators` 미지정 시의 기본값이다.
31
+ *
32
+ * 위의 `*_OPERATORS` 는 **백엔드 검증 목록**(`types.py` 와 같은 순서)이고,
33
+ * 이 표는 **UI 노출 순서**다. 둘을 같은 배열로 쓰면 안 된다 —
34
+ * 검증 목록의 첫 항목은 아무 의미가 없는데, 이 표는 **첫 항목이 기본 연산자**이기
35
+ * 때문이다 (기존 `columnFilterModeOptions[0]` 규칙 계승). 실제로 그렇게 묶었더니
36
+ * 텍스트 컬럼의 기본이 `equals` 가 되어, 기존 기본값 `fuzzy` 로 걸리던
37
+ * "듀벨" ↔ "듀 벨 상사" 매칭이 조용히 깨졌다.
38
+ */
39
+ export declare const OPERATORS_BY_VARIANT: Record<FilterVariant, readonly FilterOperator[]>;
40
+ /**
41
+ * variant 별 **노출 연산자** — 컬럼을 만들 때 드롭다운에 실제로 띄우는 축약본.
42
+ * `OPERATORS_BY_VARIANT` 는 그 variant 가 지원하는 전체 목록(첫 항목 = 기본값)이고,
43
+ * 이쪽은 기존 `getColumnFilterModeOptions` 와 같은 짧은 목록이다. 전부 띄우면
44
+ * 선택지가 13개가 된다. 없는 variant 는 전체 목록을 그대로 쓴다.
45
+ */
46
+ export declare const OFFERED_OPERATORS: Partial<Record<FilterVariant, readonly FilterOperator[]>>;
47
+ export declare function offeredOperators(variant: FilterVariant): readonly FilterOperator[];
48
+ /**
49
+ * 값을 소비하지 않는 연산자 — 입력창을 그리지 않는다 (백엔드 VALUELESS_OPERATORS 대응).
50
+ *
51
+ * `hasChild`/`hasNotChild` 도 여기 든다. 서버는 `value None` 인 필터를 통째로
52
+ * 건너뛰므로 항목은 있어야 하고 값은 `true` 로 실린다 — 목록에서 빠져 있으면
53
+ * `useTableSearch.normalizeFilters` 가 "미입력" 으로 지워 훅 경로에서 걸리지 않았다.
54
+ */
55
+ export declare const VALUELESS_OPERATORS: readonly ["empty", "notEmpty", "isEmpty", "hasChild", "hasNotChild"];
56
+ export type ValuelessOperator = (typeof VALUELESS_OPERATORS)[number];
57
+ export declare function isValuelessOperator(op: FilterOperator): op is ValuelessOperator;
58
+ /**
59
+ * 값이 **목록**인 리스트 연산자 — `between` 은 `[lo, hi]` 쌍이라 제외한다.
60
+ * 이 연산자의 값이 스칼라로 실리면 서버가 문자열을 글자 단위로 쪼개므로
61
+ * (`ListFilter.apply` 의 `if "" in value`), 요청 조립 시 `[value]` 로 감싼다.
62
+ */
63
+ export declare const LIST_VALUE_OPERATORS: readonly ["in", "notIn", "arrIncludes", "arrIncludesSome", "arrIncludesAll", "inArray", "inArrayFilter", "notInArray"];
64
+ export declare function isListValueOperator(op: FilterOperator): boolean;
@@ -0,0 +1,108 @@
1
+ /**
2
+ * 필터 연산자 — 백엔드 `QueryBuilder/types.py` 와 1:1 대응한다.
3
+ *
4
+ * 이 목록이 프론트/백 공통 계약의 전부다. 여기 없는 문자열은 서버가
5
+ * 기본 연산자로 강등하므로(TextFilter → "contains", NumberFilter → "equals"),
6
+ * 새 연산자는 반드시 양쪽을 같이 늘린다.
7
+ */
8
+ export const TEXT_OPERATORS = [
9
+ "equals", "notEquals", "lessThan", "lessThanOrEqualTo",
10
+ "greaterThan", "greaterThanOrEqualTo", "contains", "notContains",
11
+ "startsWith", "endsWith", "fuzzy", "empty", "notEmpty",
12
+ ];
13
+ export const NUMBER_OPERATORS = [
14
+ "equals", "notEquals", "lessThan", "lessThanOrEqualTo",
15
+ "greaterThan", "greaterThanOrEqualTo", "between", "betweenInclusive",
16
+ "outsideRange", "isEmpty",
17
+ ];
18
+ export const DATE_OPERATORS = [
19
+ "equals", "notEquals", "lessThan", "lessThanOrEqualTo",
20
+ "greaterThan", "greaterThanOrEqualTo", "between", "betweenInclusive",
21
+ "dateBetween", "inPeriod",
22
+ ];
23
+ export const LIST_OPERATORS = [
24
+ "in", "notIn", "between", "arrIncludes", "arrIncludesSome",
25
+ "arrIncludesAll", "inArray", "inArrayFilter", "notInArray",
26
+ ];
27
+ export const BOOLEAN_OPERATORS = ["equals"];
28
+ export const RELATION_OPERATORS = ["hasAny", "hasAll", "hasChild", "hasNotChild"];
29
+ export const LINEAR_OPERATORS = ["linearExact", "linearContains", "linearExists"];
30
+ export const SCHEDULE_OPERATORS = ["scheduleContains", "scheduleOverlaps"];
31
+ /**
32
+ * variant → 연산자 후보. `FilterSpec.operators` 미지정 시의 기본값이다.
33
+ *
34
+ * 위의 `*_OPERATORS` 는 **백엔드 검증 목록**(`types.py` 와 같은 순서)이고,
35
+ * 이 표는 **UI 노출 순서**다. 둘을 같은 배열로 쓰면 안 된다 —
36
+ * 검증 목록의 첫 항목은 아무 의미가 없는데, 이 표는 **첫 항목이 기본 연산자**이기
37
+ * 때문이다 (기존 `columnFilterModeOptions[0]` 규칙 계승). 실제로 그렇게 묶었더니
38
+ * 텍스트 컬럼의 기본이 `equals` 가 되어, 기존 기본값 `fuzzy` 로 걸리던
39
+ * "듀벨" ↔ "듀 벨 상사" 매칭이 조용히 깨졌다.
40
+ */
41
+ export const OPERATORS_BY_VARIANT = {
42
+ text: [
43
+ "fuzzy", "contains", "notContains", "equals", "notEquals",
44
+ "startsWith", "endsWith", "empty", "notEmpty",
45
+ ],
46
+ number: [
47
+ "betweenInclusive", "between", "outsideRange", "equals", "notEquals",
48
+ "lessThan", "lessThanOrEqualTo", "greaterThan", "greaterThanOrEqualTo", "isEmpty",
49
+ ],
50
+ date: [
51
+ "betweenInclusive", "between", "inPeriod", "equals", "notEquals",
52
+ "lessThan", "lessThanOrEqualTo", "greaterThan", "greaterThanOrEqualTo",
53
+ ],
54
+ datetime: [
55
+ "betweenInclusive", "between", "inPeriod", "equals", "notEquals",
56
+ "lessThan", "lessThanOrEqualTo", "greaterThan", "greaterThanOrEqualTo",
57
+ ],
58
+ boolean: BOOLEAN_OPERATORS,
59
+ select: ["inArray", "notInArray", "equals"],
60
+ multiSelect: ["inArray", "notInArray", "arrIncludesSome", "arrIncludesAll"],
61
+ relation: RELATION_OPERATORS,
62
+ linear: ["linearContains", "linearExists", "linearExact"],
63
+ schedule: SCHEDULE_OPERATORS,
64
+ custom: ["custom"],
65
+ };
66
+ /**
67
+ * variant 별 **노출 연산자** — 컬럼을 만들 때 드롭다운에 실제로 띄우는 축약본.
68
+ * `OPERATORS_BY_VARIANT` 는 그 variant 가 지원하는 전체 목록(첫 항목 = 기본값)이고,
69
+ * 이쪽은 기존 `getColumnFilterModeOptions` 와 같은 짧은 목록이다. 전부 띄우면
70
+ * 선택지가 13개가 된다. 없는 variant 는 전체 목록을 그대로 쓴다.
71
+ */
72
+ export const OFFERED_OPERATORS = {
73
+ text: ["fuzzy", "equals", "empty"],
74
+ number: ["betweenInclusive", "outsideRange", "isEmpty"],
75
+ date: ["betweenInclusive", "inPeriod"],
76
+ datetime: ["betweenInclusive", "inPeriod"],
77
+ boolean: ["equals"],
78
+ select: ["inArray", "notInArray"],
79
+ multiSelect: ["inArray", "notInArray"],
80
+ };
81
+ export function offeredOperators(variant) {
82
+ return OFFERED_OPERATORS[variant] ?? OPERATORS_BY_VARIANT[variant];
83
+ }
84
+ /**
85
+ * 값을 소비하지 않는 연산자 — 입력창을 그리지 않는다 (백엔드 VALUELESS_OPERATORS 대응).
86
+ *
87
+ * `hasChild`/`hasNotChild` 도 여기 든다. 서버는 `value None` 인 필터를 통째로
88
+ * 건너뛰므로 항목은 있어야 하고 값은 `true` 로 실린다 — 목록에서 빠져 있으면
89
+ * `useTableSearch.normalizeFilters` 가 "미입력" 으로 지워 훅 경로에서 걸리지 않았다.
90
+ */
91
+ export const VALUELESS_OPERATORS = [
92
+ "empty", "notEmpty", "isEmpty", "hasChild", "hasNotChild",
93
+ ];
94
+ export function isValuelessOperator(op) {
95
+ return VALUELESS_OPERATORS.includes(op);
96
+ }
97
+ /**
98
+ * 값이 **목록**인 리스트 연산자 — `between` 은 `[lo, hi]` 쌍이라 제외한다.
99
+ * 이 연산자의 값이 스칼라로 실리면 서버가 문자열을 글자 단위로 쪼개므로
100
+ * (`ListFilter.apply` 의 `if "" in value`), 요청 조립 시 `[value]` 로 감싼다.
101
+ */
102
+ export const LIST_VALUE_OPERATORS = [
103
+ "in", "notIn", "arrIncludes", "arrIncludesSome", "arrIncludesAll",
104
+ "inArray", "inArrayFilter", "notInArray",
105
+ ];
106
+ export function isListValueOperator(op) {
107
+ return LIST_VALUE_OPERATORS.includes(op);
108
+ }