@flanksource/clicky-ui 0.3.18 → 0.3.20

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 (609) hide show
  1. package/dist/components/ComboboxMenu.cjs +5 -1
  2. package/dist/components/ComboboxMenu.cjs.map +1 -1
  3. package/dist/components/ComboboxMenu.d.ts.map +1 -1
  4. package/dist/components/ComboboxMenu.js +5 -1
  5. package/dist/components/ComboboxMenu.js.map +1 -1
  6. package/dist/components/EndpointSelector.model.cjs +96 -0
  7. package/dist/components/EndpointSelector.model.cjs.map +1 -0
  8. package/dist/components/EndpointSelector.model.d.ts +2 -0
  9. package/dist/components/EndpointSelector.model.d.ts.map +1 -1
  10. package/dist/components/EndpointSelector.model.js +96 -0
  11. package/dist/components/EndpointSelector.model.js.map +1 -0
  12. package/dist/components/ErrorWrapper.cjs +1 -1
  13. package/dist/components/ErrorWrapper.cjs.map +1 -1
  14. package/dist/components/ErrorWrapper.js +1 -1
  15. package/dist/components/ErrorWrapper.js.map +1 -1
  16. package/dist/components/FilterBar.cjs +52 -2
  17. package/dist/components/FilterBar.cjs.map +1 -1
  18. package/dist/components/FilterBar.d.ts +20 -2
  19. package/dist/components/FilterBar.d.ts.map +1 -1
  20. package/dist/components/FilterBar.js +52 -2
  21. package/dist/components/FilterBar.js.map +1 -1
  22. package/dist/components/JSONPathField.cjs +87 -66
  23. package/dist/components/JSONPathField.cjs.map +1 -1
  24. package/dist/components/JSONPathField.d.ts +26 -9
  25. package/dist/components/JSONPathField.d.ts.map +1 -1
  26. package/dist/components/JSONPathField.js +88 -67
  27. package/dist/components/JSONPathField.js.map +1 -1
  28. package/dist/components/JSONPathPlayground.cjs +225 -0
  29. package/dist/components/JSONPathPlayground.cjs.map +1 -0
  30. package/dist/components/JSONPathPlayground.d.ts +59 -0
  31. package/dist/components/JSONPathPlayground.d.ts.map +1 -0
  32. package/dist/components/JSONPathPlayground.js +225 -0
  33. package/dist/components/JSONPathPlayground.js.map +1 -0
  34. package/dist/components/OnePasswordSelector.cjs +178 -0
  35. package/dist/components/OnePasswordSelector.cjs.map +1 -0
  36. package/dist/components/OnePasswordSelector.d.ts +8 -0
  37. package/dist/components/OnePasswordSelector.d.ts.map +1 -0
  38. package/dist/components/OnePasswordSelector.js +178 -0
  39. package/dist/components/OnePasswordSelector.js.map +1 -0
  40. package/dist/components/OnePasswordSelector.model.cjs +31 -0
  41. package/dist/components/OnePasswordSelector.model.cjs.map +1 -0
  42. package/dist/components/OnePasswordSelector.model.d.ts +27 -0
  43. package/dist/components/OnePasswordSelector.model.d.ts.map +1 -0
  44. package/dist/components/OnePasswordSelector.model.js +31 -0
  45. package/dist/components/OnePasswordSelector.model.js.map +1 -0
  46. package/dist/components/SecretFormField.cjs +142 -0
  47. package/dist/components/SecretFormField.cjs.map +1 -0
  48. package/dist/components/SecretFormField.d.ts +9 -0
  49. package/dist/components/SecretFormField.d.ts.map +1 -0
  50. package/dist/components/SecretFormField.js +142 -0
  51. package/dist/components/SecretFormField.js.map +1 -0
  52. package/dist/components/SecretKeySelector.cjs +20 -14
  53. package/dist/components/SecretKeySelector.cjs.map +1 -1
  54. package/dist/components/SecretKeySelector.d.ts +4 -1
  55. package/dist/components/SecretKeySelector.d.ts.map +1 -1
  56. package/dist/components/SecretKeySelector.js +20 -14
  57. package/dist/components/SecretKeySelector.js.map +1 -1
  58. package/dist/components/TreePickerField.cjs +55 -29
  59. package/dist/components/TreePickerField.cjs.map +1 -1
  60. package/dist/components/TreePickerField.d.ts +10 -1
  61. package/dist/components/TreePickerField.d.ts.map +1 -1
  62. package/dist/components/TreePickerField.js +56 -30
  63. package/dist/components/TreePickerField.js.map +1 -1
  64. package/dist/components/UnitStepControls.cjs +55 -0
  65. package/dist/components/UnitStepControls.cjs.map +1 -0
  66. package/dist/components/UnitStepControls.d.ts +10 -0
  67. package/dist/components/UnitStepControls.d.ts.map +1 -0
  68. package/dist/components/UnitStepControls.js +55 -0
  69. package/dist/components/UnitStepControls.js.map +1 -0
  70. package/dist/components/combobox-types.d.ts +9 -0
  71. package/dist/components/combobox-types.d.ts.map +1 -1
  72. package/dist/components/filter-bar-utils.cjs +7 -0
  73. package/dist/components/filter-bar-utils.cjs.map +1 -1
  74. package/dist/components/filter-bar-utils.d.ts.map +1 -1
  75. package/dist/components/filter-bar-utils.js +7 -0
  76. package/dist/components/filter-bar-utils.js.map +1 -1
  77. package/dist/components/jotai-bindings-core.cjs.map +1 -1
  78. package/dist/components/jotai-bindings-core.d.ts +4 -1
  79. package/dist/components/jotai-bindings-core.d.ts.map +1 -1
  80. package/dist/components/jotai-bindings-core.js.map +1 -1
  81. package/dist/components/json-schema-form-accordion-array.cjs +5 -73
  82. package/dist/components/json-schema-form-accordion-array.cjs.map +1 -1
  83. package/dist/components/json-schema-form-accordion-array.d.ts.map +1 -1
  84. package/dist/components/json-schema-form-accordion-array.js +3 -71
  85. package/dist/components/json-schema-form-accordion-array.js.map +1 -1
  86. package/dist/components/json-schema-form-array.cjs +6 -1
  87. package/dist/components/json-schema-form-array.cjs.map +1 -1
  88. package/dist/components/json-schema-form-array.d.ts.map +1 -1
  89. package/dist/components/json-schema-form-array.js +6 -1
  90. package/dist/components/json-schema-form-array.js.map +1 -1
  91. package/dist/components/json-schema-form-cards-array.cjs +96 -0
  92. package/dist/components/json-schema-form-cards-array.cjs.map +1 -0
  93. package/dist/components/json-schema-form-cards-array.d.ts +7 -0
  94. package/dist/components/json-schema-form-cards-array.d.ts.map +1 -0
  95. package/dist/components/json-schema-form-cards-array.js +96 -0
  96. package/dist/components/json-schema-form-cards-array.js.map +1 -0
  97. package/dist/components/json-schema-form-item-row.cjs +81 -0
  98. package/dist/components/json-schema-form-item-row.cjs.map +1 -0
  99. package/dist/components/json-schema-form-item-row.d.ts +19 -0
  100. package/dist/components/json-schema-form-item-row.d.ts.map +1 -0
  101. package/dist/components/json-schema-form-item-row.js +81 -0
  102. package/dist/components/json-schema-form-item-row.js.map +1 -0
  103. package/dist/components/json-schema-form-render.cjs +4 -3
  104. package/dist/components/json-schema-form-render.cjs.map +1 -1
  105. package/dist/components/json-schema-form-render.d.ts.map +1 -1
  106. package/dist/components/json-schema-form-render.js +4 -3
  107. package/dist/components/json-schema-form-render.js.map +1 -1
  108. package/dist/components/json-schema-form-resolve.cjs +1 -1
  109. package/dist/components/json-schema-form-resolve.cjs.map +1 -1
  110. package/dist/components/json-schema-form-resolve.js +1 -1
  111. package/dist/components/json-schema-form-resolve.js.map +1 -1
  112. package/dist/components/json-schema-form-tone.cjs +12 -0
  113. package/dist/components/json-schema-form-tone.cjs.map +1 -1
  114. package/dist/components/json-schema-form-tone.js +12 -0
  115. package/dist/components/json-schema-form-tone.js.map +1 -1
  116. package/dist/components/json-schema-form-types.d.ts +10 -1
  117. package/dist/components/json-schema-form-types.d.ts.map +1 -1
  118. package/dist/components/jsonPathTree.cjs +189 -0
  119. package/dist/components/jsonPathTree.cjs.map +1 -0
  120. package/dist/components/jsonPathTree.d.ts +92 -0
  121. package/dist/components/jsonPathTree.d.ts.map +1 -0
  122. package/dist/components/jsonPathTree.js +189 -0
  123. package/dist/components/jsonPathTree.js.map +1 -0
  124. package/dist/components/secret-form-extension.cjs +30 -0
  125. package/dist/components/secret-form-extension.cjs.map +1 -0
  126. package/dist/components/secret-form-extension.d.ts +23 -0
  127. package/dist/components/secret-form-extension.d.ts.map +1 -0
  128. package/dist/components/secret-form-extension.js +30 -0
  129. package/dist/components/secret-form-extension.js.map +1 -0
  130. package/dist/components/unit-form-extension.cjs +126 -0
  131. package/dist/components/unit-form-extension.cjs.map +1 -0
  132. package/dist/components/unit-form-extension.d.ts +8 -0
  133. package/dist/components/unit-form-extension.d.ts.map +1 -0
  134. package/dist/components/unit-form-extension.js +126 -0
  135. package/dist/components/unit-form-extension.js.map +1 -0
  136. package/dist/components.cjs +20 -0
  137. package/dist/components.cjs.map +1 -1
  138. package/dist/components.d.ts +7 -0
  139. package/dist/components.d.ts.map +1 -1
  140. package/dist/components.js +20 -0
  141. package/dist/components.js.map +1 -1
  142. package/dist/data/TaskExecDetails.cjs +40 -0
  143. package/dist/data/TaskExecDetails.cjs.map +1 -0
  144. package/dist/data/TaskExecDetails.d.ts +5 -0
  145. package/dist/data/TaskExecDetails.d.ts.map +1 -0
  146. package/dist/data/TaskExecDetails.js +40 -0
  147. package/dist/data/TaskExecDetails.js.map +1 -0
  148. package/dist/data/TaskProgress.cjs +9 -3
  149. package/dist/data/TaskProgress.cjs.map +1 -1
  150. package/dist/data/TaskProgress.d.ts.map +1 -1
  151. package/dist/data/TaskProgress.js +9 -3
  152. package/dist/data/TaskProgress.js.map +1 -1
  153. package/dist/data/TaskSnapshot.cjs.map +1 -1
  154. package/dist/data/TaskSnapshot.d.ts +12 -1
  155. package/dist/data/TaskSnapshot.d.ts.map +1 -1
  156. package/dist/data/TaskSnapshot.js.map +1 -1
  157. package/dist/data/TreeNode.cjs +3 -0
  158. package/dist/data/TreeNode.cjs.map +1 -1
  159. package/dist/data/TreeNode.d.ts.map +1 -1
  160. package/dist/data/TreeNode.js +3 -0
  161. package/dist/data/TreeNode.js.map +1 -1
  162. package/dist/data/data-table-filter-values.cjs +20 -0
  163. package/dist/data/data-table-filter-values.cjs.map +1 -1
  164. package/dist/data/data-table-filter-values.d.ts +16 -0
  165. package/dist/data/data-table-filter-values.d.ts.map +1 -1
  166. package/dist/data/data-table-filter-values.js +20 -0
  167. package/dist/data/data-table-filter-values.js.map +1 -1
  168. package/dist/data/data-table-server-filters.cjs +23 -29
  169. package/dist/data/data-table-server-filters.cjs.map +1 -1
  170. package/dist/data/data-table-server-filters.d.ts.map +1 -1
  171. package/dist/data/data-table-server-filters.js +21 -27
  172. package/dist/data/data-table-server-filters.js.map +1 -1
  173. package/dist/data/diagnostics/ErrorDetails.cjs +61 -8
  174. package/dist/data/diagnostics/ErrorDetails.cjs.map +1 -1
  175. package/dist/data/diagnostics/ErrorDetails.d.ts.map +1 -1
  176. package/dist/data/diagnostics/ErrorDetails.js +61 -8
  177. package/dist/data/diagnostics/ErrorDetails.js.map +1 -1
  178. package/dist/data/diagnostics/error-diagnostics.cjs +10 -4
  179. package/dist/data/diagnostics/error-diagnostics.cjs.map +1 -1
  180. package/dist/data/diagnostics/error-diagnostics.d.ts.map +1 -1
  181. package/dist/data/diagnostics/error-diagnostics.js +10 -4
  182. package/dist/data/diagnostics/error-diagnostics.js.map +1 -1
  183. package/dist/data/query-browser/QueryBrowser.cjs +139 -161
  184. package/dist/data/query-browser/QueryBrowser.cjs.map +1 -1
  185. package/dist/data/query-browser/QueryBrowser.d.ts +1 -71
  186. package/dist/data/query-browser/QueryBrowser.d.ts.map +1 -1
  187. package/dist/data/query-browser/QueryBrowser.editor.cjs +88 -0
  188. package/dist/data/query-browser/QueryBrowser.editor.cjs.map +1 -0
  189. package/dist/data/query-browser/QueryBrowser.editor.d.ts +12 -0
  190. package/dist/data/query-browser/QueryBrowser.editor.d.ts.map +1 -0
  191. package/dist/data/query-browser/QueryBrowser.editor.js +88 -0
  192. package/dist/data/query-browser/QueryBrowser.editor.js.map +1 -0
  193. package/dist/data/query-browser/QueryBrowser.js +140 -162
  194. package/dist/data/query-browser/QueryBrowser.js.map +1 -1
  195. package/dist/data/query-browser/QueryBrowser.types.cjs +12 -0
  196. package/dist/data/query-browser/QueryBrowser.types.cjs.map +1 -0
  197. package/dist/data/query-browser/QueryBrowser.types.d.ts +94 -0
  198. package/dist/data/query-browser/QueryBrowser.types.d.ts.map +1 -0
  199. package/dist/data/query-browser/QueryBrowser.types.js +12 -0
  200. package/dist/data/query-browser/QueryBrowser.types.js.map +1 -0
  201. package/dist/data/query-browser/QueryBrowserDiagnosticsPanel.cjs +56 -0
  202. package/dist/data/query-browser/QueryBrowserDiagnosticsPanel.cjs.map +1 -0
  203. package/dist/data/query-browser/QueryBrowserDiagnosticsPanel.d.ts +5 -0
  204. package/dist/data/query-browser/QueryBrowserDiagnosticsPanel.d.ts.map +1 -0
  205. package/dist/data/query-browser/QueryBrowserDiagnosticsPanel.js +56 -0
  206. package/dist/data/query-browser/QueryBrowserDiagnosticsPanel.js.map +1 -0
  207. package/dist/data/query-browser/QueryBrowserResults.cjs +80 -0
  208. package/dist/data/query-browser/QueryBrowserResults.cjs.map +1 -0
  209. package/dist/data/query-browser/QueryBrowserResults.d.ts +16 -0
  210. package/dist/data/query-browser/QueryBrowserResults.d.ts.map +1 -0
  211. package/dist/data/query-browser/QueryBrowserResults.js +80 -0
  212. package/dist/data/query-browser/QueryBrowserResults.js.map +1 -0
  213. package/dist/data/query-browser/index.d.ts +2 -1
  214. package/dist/data/query-browser/index.d.ts.map +1 -1
  215. package/dist/data/task-exec-details.cjs +9 -0
  216. package/dist/data/task-exec-details.cjs.map +1 -0
  217. package/dist/data/task-exec-details.d.ts +3 -0
  218. package/dist/data/task-exec-details.d.ts.map +1 -0
  219. package/dist/data/task-exec-details.js +9 -0
  220. package/dist/data/task-exec-details.js.map +1 -0
  221. package/dist/data/version-info.cjs +3 -3
  222. package/dist/data/version-info.js +3 -3
  223. package/dist/data.cjs +2 -0
  224. package/dist/data.cjs.map +1 -1
  225. package/dist/data.d.ts +1 -1
  226. package/dist/data.d.ts.map +1 -1
  227. package/dist/data.js +2 -0
  228. package/dist/data.js.map +1 -1
  229. package/dist/index.cjs +22 -0
  230. package/dist/index.cjs.map +1 -1
  231. package/dist/index.js +22 -0
  232. package/dist/index.js.map +1 -1
  233. package/dist/lib/string.cjs +8 -0
  234. package/dist/lib/string.cjs.map +1 -1
  235. package/dist/lib/string.d.ts +1 -0
  236. package/dist/lib/string.d.ts.map +1 -1
  237. package/dist/lib/string.js +8 -0
  238. package/dist/lib/string.js.map +1 -1
  239. package/dist/profiles/catalogTree.cjs +133 -0
  240. package/dist/profiles/catalogTree.cjs.map +1 -0
  241. package/dist/profiles/catalogTree.d.ts +11 -0
  242. package/dist/profiles/catalogTree.d.ts.map +1 -0
  243. package/dist/profiles/catalogTree.js +133 -0
  244. package/dist/profiles/catalogTree.js.map +1 -0
  245. package/dist/profiles/connectionBrowserModel.cjs +185 -0
  246. package/dist/profiles/connectionBrowserModel.cjs.map +1 -0
  247. package/dist/profiles/connectionBrowserModel.d.ts +169 -0
  248. package/dist/profiles/connectionBrowserModel.d.ts.map +1 -0
  249. package/dist/profiles/connectionBrowserModel.js +185 -0
  250. package/dist/profiles/connectionBrowserModel.js.map +1 -0
  251. package/dist/profiles/connectionQueryWorkspace.cjs +185 -0
  252. package/dist/profiles/connectionQueryWorkspace.cjs.map +1 -0
  253. package/dist/profiles/connectionQueryWorkspace.d.ts +63 -0
  254. package/dist/profiles/connectionQueryWorkspace.d.ts.map +1 -0
  255. package/dist/profiles/connectionQueryWorkspace.js +185 -0
  256. package/dist/profiles/connectionQueryWorkspace.js.map +1 -0
  257. package/dist/profiles/connectionQueryWorkspaceModel.cjs +28 -0
  258. package/dist/profiles/connectionQueryWorkspaceModel.cjs.map +1 -0
  259. package/dist/profiles/connectionQueryWorkspaceModel.d.ts +38 -0
  260. package/dist/profiles/connectionQueryWorkspaceModel.d.ts.map +1 -0
  261. package/dist/profiles/connectionQueryWorkspaceModel.js +28 -0
  262. package/dist/profiles/connectionQueryWorkspaceModel.js.map +1 -0
  263. package/dist/profiles/esFieldValues.cjs +64 -0
  264. package/dist/profiles/esFieldValues.cjs.map +1 -0
  265. package/dist/profiles/esFieldValues.d.ts +48 -0
  266. package/dist/profiles/esFieldValues.d.ts.map +1 -0
  267. package/dist/profiles/esFieldValues.js +64 -0
  268. package/dist/profiles/esFieldValues.js.map +1 -0
  269. package/dist/profiles/esParamMappingModel.cjs +301 -0
  270. package/dist/profiles/esParamMappingModel.cjs.map +1 -0
  271. package/dist/profiles/esParamMappingModel.d.ts +37 -0
  272. package/dist/profiles/esParamMappingModel.d.ts.map +1 -0
  273. package/dist/profiles/esParamMappingModel.js +301 -0
  274. package/dist/profiles/esParamMappingModel.js.map +1 -0
  275. package/dist/profiles/esParamMappingPill.cjs +24 -0
  276. package/dist/profiles/esParamMappingPill.cjs.map +1 -0
  277. package/dist/profiles/esParamMappingPill.d.ts +13 -0
  278. package/dist/profiles/esParamMappingPill.d.ts.map +1 -0
  279. package/dist/profiles/esParamMappingPill.js +24 -0
  280. package/dist/profiles/esParamMappingPill.js.map +1 -0
  281. package/dist/profiles/esParamOperandExtension.cjs +75 -0
  282. package/dist/profiles/esParamOperandExtension.cjs.map +1 -0
  283. package/dist/profiles/esParamOperandExtension.d.ts +11 -0
  284. package/dist/profiles/esParamOperandExtension.d.ts.map +1 -0
  285. package/dist/profiles/esParamOperandExtension.js +75 -0
  286. package/dist/profiles/esParamOperandExtension.js.map +1 -0
  287. package/dist/profiles/esQueryBuilder.cjs +205 -0
  288. package/dist/profiles/esQueryBuilder.cjs.map +1 -0
  289. package/dist/profiles/esQueryBuilder.d.ts +35 -0
  290. package/dist/profiles/esQueryBuilder.d.ts.map +1 -0
  291. package/dist/profiles/esQueryBuilder.js +205 -0
  292. package/dist/profiles/esQueryBuilder.js.map +1 -0
  293. package/dist/profiles/esQueryBuilderExtension.cjs +23 -0
  294. package/dist/profiles/esQueryBuilderExtension.cjs.map +1 -0
  295. package/dist/profiles/esQueryBuilderExtension.d.ts +5 -0
  296. package/dist/profiles/esQueryBuilderExtension.d.ts.map +1 -0
  297. package/dist/profiles/esQueryBuilderExtension.js +23 -0
  298. package/dist/profiles/esQueryBuilderExtension.js.map +1 -0
  299. package/dist/profiles/esQueryBuilderForm.cjs +26 -0
  300. package/dist/profiles/esQueryBuilderForm.cjs.map +1 -0
  301. package/dist/profiles/esQueryBuilderForm.d.ts +18 -0
  302. package/dist/profiles/esQueryBuilderForm.d.ts.map +1 -0
  303. package/dist/profiles/esQueryBuilderForm.js +26 -0
  304. package/dist/profiles/esQueryBuilderForm.js.map +1 -0
  305. package/dist/profiles/esQueryBuilderModel.cjs +131 -0
  306. package/dist/profiles/esQueryBuilderModel.cjs.map +1 -0
  307. package/dist/profiles/esQueryBuilderModel.d.ts +108 -0
  308. package/dist/profiles/esQueryBuilderModel.d.ts.map +1 -0
  309. package/dist/profiles/esQueryBuilderModel.js +131 -0
  310. package/dist/profiles/esQueryBuilderModel.js.map +1 -0
  311. package/dist/profiles/esQueryClauseGroup.cjs +144 -0
  312. package/dist/profiles/esQueryClauseGroup.cjs.map +1 -0
  313. package/dist/profiles/esQueryClauseGroup.d.ts +10 -0
  314. package/dist/profiles/esQueryClauseGroup.d.ts.map +1 -0
  315. package/dist/profiles/esQueryClauseGroup.js +144 -0
  316. package/dist/profiles/esQueryClauseGroup.js.map +1 -0
  317. package/dist/profiles/esQueryCompile.cjs +47 -0
  318. package/dist/profiles/esQueryCompile.cjs.map +1 -0
  319. package/dist/profiles/esQueryCompile.d.ts +39 -0
  320. package/dist/profiles/esQueryCompile.d.ts.map +1 -0
  321. package/dist/profiles/esQueryCompile.js +47 -0
  322. package/dist/profiles/esQueryCompile.js.map +1 -0
  323. package/dist/profiles/esQueryConditionRow.cjs +168 -0
  324. package/dist/profiles/esQueryConditionRow.cjs.map +1 -0
  325. package/dist/profiles/esQueryConditionRow.d.ts +37 -0
  326. package/dist/profiles/esQueryConditionRow.d.ts.map +1 -0
  327. package/dist/profiles/esQueryConditionRow.js +168 -0
  328. package/dist/profiles/esQueryConditionRow.js.map +1 -0
  329. package/dist/profiles/esQueryGroupModel.cjs +12 -0
  330. package/dist/profiles/esQueryGroupModel.cjs.map +1 -0
  331. package/dist/profiles/esQueryGroupModel.d.ts +9 -0
  332. package/dist/profiles/esQueryGroupModel.d.ts.map +1 -0
  333. package/dist/profiles/esQueryGroupModel.js +12 -0
  334. package/dist/profiles/esQueryGroupModel.js.map +1 -0
  335. package/dist/profiles/esQueryOccur.cjs +16 -0
  336. package/dist/profiles/esQueryOccur.cjs.map +1 -0
  337. package/dist/profiles/esQueryOccur.d.ts +11 -0
  338. package/dist/profiles/esQueryOccur.d.ts.map +1 -0
  339. package/dist/profiles/esQueryOccur.js +16 -0
  340. package/dist/profiles/esQueryOccur.js.map +1 -0
  341. package/dist/profiles/esQueryOperandEditors.cjs +279 -0
  342. package/dist/profiles/esQueryOperandEditors.cjs.map +1 -0
  343. package/dist/profiles/esQueryOperandEditors.d.ts +24 -0
  344. package/dist/profiles/esQueryOperandEditors.d.ts.map +1 -0
  345. package/dist/profiles/esQueryOperandEditors.js +279 -0
  346. package/dist/profiles/esQueryOperandEditors.js.map +1 -0
  347. package/dist/profiles/esQueryOperandModel.cjs +28 -0
  348. package/dist/profiles/esQueryOperandModel.cjs.map +1 -0
  349. package/dist/profiles/esQueryOperandModel.d.ts +17 -0
  350. package/dist/profiles/esQueryOperandModel.d.ts.map +1 -0
  351. package/dist/profiles/esQueryOperandModel.js +28 -0
  352. package/dist/profiles/esQueryOperandModel.js.map +1 -0
  353. package/dist/profiles/esQueryOperators.cjs +165 -0
  354. package/dist/profiles/esQueryOperators.cjs.map +1 -0
  355. package/dist/profiles/esQueryOperators.d.ts +83 -0
  356. package/dist/profiles/esQueryOperators.d.ts.map +1 -0
  357. package/dist/profiles/esQueryOperators.js +165 -0
  358. package/dist/profiles/esQueryOperators.js.map +1 -0
  359. package/dist/profiles/esQueryOutputEditor.cjs +138 -0
  360. package/dist/profiles/esQueryOutputEditor.cjs.map +1 -0
  361. package/dist/profiles/esQueryOutputEditor.d.ts +7 -0
  362. package/dist/profiles/esQueryOutputEditor.d.ts.map +1 -0
  363. package/dist/profiles/esQueryOutputEditor.js +138 -0
  364. package/dist/profiles/esQueryOutputEditor.js.map +1 -0
  365. package/dist/profiles/esQueryOutputModel.cjs +16 -0
  366. package/dist/profiles/esQueryOutputModel.cjs.map +1 -0
  367. package/dist/profiles/esQueryOutputModel.d.ts +14 -0
  368. package/dist/profiles/esQueryOutputModel.d.ts.map +1 -0
  369. package/dist/profiles/esQueryOutputModel.js +16 -0
  370. package/dist/profiles/esQueryOutputModel.js.map +1 -0
  371. package/dist/profiles/esQueryPreview.cjs +30 -0
  372. package/dist/profiles/esQueryPreview.cjs.map +1 -0
  373. package/dist/profiles/esQueryPreview.d.ts +6 -0
  374. package/dist/profiles/esQueryPreview.d.ts.map +1 -0
  375. package/dist/profiles/esQueryPreview.js +30 -0
  376. package/dist/profiles/esQueryPreview.js.map +1 -0
  377. package/dist/profiles/esQuerySortEditor.cjs +143 -0
  378. package/dist/profiles/esQuerySortEditor.cjs.map +1 -0
  379. package/dist/profiles/esQuerySortEditor.d.ts +9 -0
  380. package/dist/profiles/esQuerySortEditor.d.ts.map +1 -0
  381. package/dist/profiles/esQuerySortEditor.js +143 -0
  382. package/dist/profiles/esQuerySortEditor.js.map +1 -0
  383. package/dist/profiles/esQuerySortModel.cjs +13 -0
  384. package/dist/profiles/esQuerySortModel.cjs.map +1 -0
  385. package/dist/profiles/esQuerySortModel.d.ts +4 -0
  386. package/dist/profiles/esQuerySortModel.d.ts.map +1 -0
  387. package/dist/profiles/esQuerySortModel.js +13 -0
  388. package/dist/profiles/esQuerySortModel.js.map +1 -0
  389. package/dist/profiles/esValueCombobox.cjs +86 -0
  390. package/dist/profiles/esValueCombobox.cjs.map +1 -0
  391. package/dist/profiles/esValueCombobox.d.ts +15 -0
  392. package/dist/profiles/esValueCombobox.d.ts.map +1 -0
  393. package/dist/profiles/esValueCombobox.js +86 -0
  394. package/dist/profiles/esValueCombobox.js.map +1 -0
  395. package/dist/profiles/jsonPathSample.cjs +75 -0
  396. package/dist/profiles/jsonPathSample.cjs.map +1 -0
  397. package/dist/profiles/jsonPathSample.d.ts +27 -0
  398. package/dist/profiles/jsonPathSample.d.ts.map +1 -0
  399. package/dist/profiles/jsonPathSample.js +75 -0
  400. package/dist/profiles/jsonPathSample.js.map +1 -0
  401. package/dist/profiles/jsonPathSampleRow.cjs +14 -0
  402. package/dist/profiles/jsonPathSampleRow.cjs.map +1 -0
  403. package/dist/profiles/jsonPathSampleRow.d.ts +6 -0
  404. package/dist/profiles/jsonPathSampleRow.d.ts.map +1 -0
  405. package/dist/profiles/jsonPathSampleRow.js +14 -0
  406. package/dist/profiles/jsonPathSampleRow.js.map +1 -0
  407. package/dist/profiles/profileApi.cjs +37 -0
  408. package/dist/profiles/profileApi.cjs.map +1 -0
  409. package/dist/profiles/profileApi.d.ts +32 -0
  410. package/dist/profiles/profileApi.d.ts.map +1 -0
  411. package/dist/profiles/profileApi.js +37 -0
  412. package/dist/profiles/profileApi.js.map +1 -0
  413. package/dist/profiles/profileBuilder.cjs +65 -0
  414. package/dist/profiles/profileBuilder.cjs.map +1 -0
  415. package/dist/profiles/profileBuilder.d.ts +11 -0
  416. package/dist/profiles/profileBuilder.d.ts.map +1 -0
  417. package/dist/profiles/profileBuilder.js +65 -0
  418. package/dist/profiles/profileBuilder.js.map +1 -0
  419. package/dist/profiles/profileBuilderExtension.cjs +25 -0
  420. package/dist/profiles/profileBuilderExtension.cjs.map +1 -0
  421. package/dist/profiles/profileBuilderExtension.d.ts +5 -0
  422. package/dist/profiles/profileBuilderExtension.d.ts.map +1 -0
  423. package/dist/profiles/profileBuilderExtension.js +25 -0
  424. package/dist/profiles/profileBuilderExtension.js.map +1 -0
  425. package/dist/profiles/profileBuilderWorkspace.cjs +368 -0
  426. package/dist/profiles/profileBuilderWorkspace.cjs.map +1 -0
  427. package/dist/profiles/profileBuilderWorkspace.d.ts +21 -0
  428. package/dist/profiles/profileBuilderWorkspace.d.ts.map +1 -0
  429. package/dist/profiles/profileBuilderWorkspace.js +368 -0
  430. package/dist/profiles/profileBuilderWorkspace.js.map +1 -0
  431. package/dist/profiles/profileColumnModel.cjs +23 -0
  432. package/dist/profiles/profileColumnModel.cjs.map +1 -0
  433. package/dist/profiles/profileColumnModel.d.ts +8 -0
  434. package/dist/profiles/profileColumnModel.d.ts.map +1 -0
  435. package/dist/profiles/profileColumnModel.js +23 -0
  436. package/dist/profiles/profileColumnModel.js.map +1 -0
  437. package/dist/profiles/profileColumnPicker.cjs +68 -0
  438. package/dist/profiles/profileColumnPicker.cjs.map +1 -0
  439. package/dist/profiles/profileColumnPicker.d.ts +11 -0
  440. package/dist/profiles/profileColumnPicker.d.ts.map +1 -0
  441. package/dist/profiles/profileColumnPicker.js +68 -0
  442. package/dist/profiles/profileColumnPicker.js.map +1 -0
  443. package/dist/profiles/profileEditor.cjs +386 -0
  444. package/dist/profiles/profileEditor.cjs.map +1 -0
  445. package/dist/profiles/profileEditor.d.ts +19 -0
  446. package/dist/profiles/profileEditor.d.ts.map +1 -0
  447. package/dist/profiles/profileEditor.js +386 -0
  448. package/dist/profiles/profileEditor.js.map +1 -0
  449. package/dist/profiles/profileEditorModel.cjs +181 -0
  450. package/dist/profiles/profileEditorModel.cjs.map +1 -0
  451. package/dist/profiles/profileEditorModel.d.ts +74 -0
  452. package/dist/profiles/profileEditorModel.d.ts.map +1 -0
  453. package/dist/profiles/profileEditorModel.js +181 -0
  454. package/dist/profiles/profileEditorModel.js.map +1 -0
  455. package/dist/profiles/profileEditorPreview.cjs +38 -0
  456. package/dist/profiles/profileEditorPreview.cjs.map +1 -0
  457. package/dist/profiles/profileEditorPreview.d.ts +12 -0
  458. package/dist/profiles/profileEditorPreview.d.ts.map +1 -0
  459. package/dist/profiles/profileEditorPreview.js +38 -0
  460. package/dist/profiles/profileEditorPreview.js.map +1 -0
  461. package/dist/profiles/profileEditorRail.cjs +46 -0
  462. package/dist/profiles/profileEditorRail.cjs.map +1 -0
  463. package/dist/profiles/profileEditorRail.d.ts +8 -0
  464. package/dist/profiles/profileEditorRail.d.ts.map +1 -0
  465. package/dist/profiles/profileEditorRail.js +46 -0
  466. package/dist/profiles/profileEditorRail.js.map +1 -0
  467. package/dist/profiles/profileEditorRaw.cjs +118 -0
  468. package/dist/profiles/profileEditorRaw.cjs.map +1 -0
  469. package/dist/profiles/profileEditorRaw.d.ts +7 -0
  470. package/dist/profiles/profileEditorRaw.d.ts.map +1 -0
  471. package/dist/profiles/profileEditorRaw.js +118 -0
  472. package/dist/profiles/profileEditorRaw.js.map +1 -0
  473. package/dist/profiles/profileEditorRoutes.cjs +7 -0
  474. package/dist/profiles/profileEditorRoutes.cjs.map +1 -0
  475. package/dist/profiles/profileEditorRoutes.d.ts +2 -0
  476. package/dist/profiles/profileEditorRoutes.d.ts.map +1 -0
  477. package/dist/profiles/profileEditorRoutes.js +7 -0
  478. package/dist/profiles/profileEditorRoutes.js.map +1 -0
  479. package/dist/profiles/profileEditorSections.cjs +213 -0
  480. package/dist/profiles/profileEditorSections.cjs.map +1 -0
  481. package/dist/profiles/profileEditorSections.d.ts +23 -0
  482. package/dist/profiles/profileEditorSections.d.ts.map +1 -0
  483. package/dist/profiles/profileEditorSections.js +213 -0
  484. package/dist/profiles/profileEditorSections.js.map +1 -0
  485. package/dist/profiles/profileFieldEditor.cjs +200 -0
  486. package/dist/profiles/profileFieldEditor.cjs.map +1 -0
  487. package/dist/profiles/profileFieldEditor.d.ts +34 -0
  488. package/dist/profiles/profileFieldEditor.d.ts.map +1 -0
  489. package/dist/profiles/profileFieldEditor.js +200 -0
  490. package/dist/profiles/profileFieldEditor.js.map +1 -0
  491. package/dist/profiles/profileFieldGrid.cjs +250 -0
  492. package/dist/profiles/profileFieldGrid.cjs.map +1 -0
  493. package/dist/profiles/profileFieldGrid.d.ts +20 -0
  494. package/dist/profiles/profileFieldGrid.d.ts.map +1 -0
  495. package/dist/profiles/profileFieldGrid.js +250 -0
  496. package/dist/profiles/profileFieldGrid.js.map +1 -0
  497. package/dist/profiles/profileFieldManager.cjs +103 -0
  498. package/dist/profiles/profileFieldManager.cjs.map +1 -0
  499. package/dist/profiles/profileFieldManager.d.ts +9 -0
  500. package/dist/profiles/profileFieldManager.d.ts.map +1 -0
  501. package/dist/profiles/profileFieldManager.js +103 -0
  502. package/dist/profiles/profileFieldManager.js.map +1 -0
  503. package/dist/profiles/profileFieldState.cjs +136 -0
  504. package/dist/profiles/profileFieldState.cjs.map +1 -0
  505. package/dist/profiles/profileFieldState.d.ts +41 -0
  506. package/dist/profiles/profileFieldState.d.ts.map +1 -0
  507. package/dist/profiles/profileFieldState.js +136 -0
  508. package/dist/profiles/profileFieldState.js.map +1 -0
  509. package/dist/profiles/profileFieldTypes.cjs +17 -0
  510. package/dist/profiles/profileFieldTypes.cjs.map +1 -0
  511. package/dist/profiles/profileFieldTypes.d.ts +8 -0
  512. package/dist/profiles/profileFieldTypes.d.ts.map +1 -0
  513. package/dist/profiles/profileFieldTypes.js +17 -0
  514. package/dist/profiles/profileFieldTypes.js.map +1 -0
  515. package/dist/profiles/profileParamModel.cjs +78 -0
  516. package/dist/profiles/profileParamModel.cjs.map +1 -0
  517. package/dist/profiles/profileParamModel.d.ts +3 -0
  518. package/dist/profiles/profileParamModel.d.ts.map +1 -0
  519. package/dist/profiles/profileParamModel.js +78 -0
  520. package/dist/profiles/profileParamModel.js.map +1 -0
  521. package/dist/profiles/profileSamplePayload.cjs +15 -0
  522. package/dist/profiles/profileSamplePayload.cjs.map +1 -0
  523. package/dist/profiles/profileSamplePayload.d.ts +13 -0
  524. package/dist/profiles/profileSamplePayload.d.ts.map +1 -0
  525. package/dist/profiles/profileSamplePayload.js +15 -0
  526. package/dist/profiles/profileSamplePayload.js.map +1 -0
  527. package/dist/profiles/profileWizard.cjs +257 -0
  528. package/dist/profiles/profileWizard.cjs.map +1 -0
  529. package/dist/profiles/profileWizard.d.ts +12 -0
  530. package/dist/profiles/profileWizard.d.ts.map +1 -0
  531. package/dist/profiles/profileWizard.js +257 -0
  532. package/dist/profiles/profileWizard.js.map +1 -0
  533. package/dist/profiles/profileWizardHelp.cjs +10 -0
  534. package/dist/profiles/profileWizardHelp.cjs.map +1 -0
  535. package/dist/profiles/profileWizardHelp.d.ts +13 -0
  536. package/dist/profiles/profileWizardHelp.d.ts.map +1 -0
  537. package/dist/profiles/profileWizardHelp.js +10 -0
  538. package/dist/profiles/profileWizardHelp.js.map +1 -0
  539. package/dist/profiles/profileWizardModel.cjs +198 -0
  540. package/dist/profiles/profileWizardModel.cjs.map +1 -0
  541. package/dist/profiles/profileWizardModel.d.ts +255 -0
  542. package/dist/profiles/profileWizardModel.d.ts.map +1 -0
  543. package/dist/profiles/profileWizardModel.js +198 -0
  544. package/dist/profiles/profileWizardModel.js.map +1 -0
  545. package/dist/profiles/profileWizardQueryStep.cjs +215 -0
  546. package/dist/profiles/profileWizardQueryStep.cjs.map +1 -0
  547. package/dist/profiles/profileWizardQueryStep.d.ts +18 -0
  548. package/dist/profiles/profileWizardQueryStep.d.ts.map +1 -0
  549. package/dist/profiles/profileWizardQueryStep.js +215 -0
  550. package/dist/profiles/profileWizardQueryStep.js.map +1 -0
  551. package/dist/profiles/profileWizardSteps.cjs +214 -0
  552. package/dist/profiles/profileWizardSteps.cjs.map +1 -0
  553. package/dist/profiles/profileWizardSteps.d.ts +35 -0
  554. package/dist/profiles/profileWizardSteps.d.ts.map +1 -0
  555. package/dist/profiles/profileWizardSteps.js +214 -0
  556. package/dist/profiles/profileWizardSteps.js.map +1 -0
  557. package/dist/profiles/profileYaml.cjs +19 -0
  558. package/dist/profiles/profileYaml.cjs.map +1 -0
  559. package/dist/profiles/profileYaml.d.ts +4 -0
  560. package/dist/profiles/profileYaml.d.ts.map +1 -0
  561. package/dist/profiles/profileYaml.js +19 -0
  562. package/dist/profiles/profileYaml.js.map +1 -0
  563. package/dist/profiles/prometheusResults.cjs +60 -0
  564. package/dist/profiles/prometheusResults.cjs.map +1 -0
  565. package/dist/profiles/prometheusResults.d.ts +7 -0
  566. package/dist/profiles/prometheusResults.d.ts.map +1 -0
  567. package/dist/profiles/prometheusResults.js +60 -0
  568. package/dist/profiles/prometheusResults.js.map +1 -0
  569. package/dist/profiles/queryRowLimits.cjs +82 -0
  570. package/dist/profiles/queryRowLimits.cjs.map +1 -0
  571. package/dist/profiles/queryRowLimits.d.ts +9 -0
  572. package/dist/profiles/queryRowLimits.d.ts.map +1 -0
  573. package/dist/profiles/queryRowLimits.js +82 -0
  574. package/dist/profiles/queryRowLimits.js.map +1 -0
  575. package/dist/profiles/queryRowLimitsModel.cjs +10 -0
  576. package/dist/profiles/queryRowLimitsModel.cjs.map +1 -0
  577. package/dist/profiles/queryRowLimitsModel.d.ts +9 -0
  578. package/dist/profiles/queryRowLimitsModel.d.ts.map +1 -0
  579. package/dist/profiles/queryRowLimitsModel.js +10 -0
  580. package/dist/profiles/queryRowLimitsModel.js.map +1 -0
  581. package/dist/profiles/queryTargetPicker.cjs +42 -0
  582. package/dist/profiles/queryTargetPicker.cjs.map +1 -0
  583. package/dist/profiles/queryTargetPicker.d.ts +8 -0
  584. package/dist/profiles/queryTargetPicker.d.ts.map +1 -0
  585. package/dist/profiles/queryTargetPicker.js +42 -0
  586. package/dist/profiles/queryTargetPicker.js.map +1 -0
  587. package/dist/profiles/testSchema.d.ts +3 -0
  588. package/dist/profiles/testSchema.d.ts.map +1 -0
  589. package/dist/profiles.cjs +223 -0
  590. package/dist/profiles.cjs.map +1 -0
  591. package/dist/profiles.d.ts +68 -0
  592. package/dist/profiles.d.ts.map +1 -0
  593. package/dist/profiles.js +223 -0
  594. package/dist/profiles.js.map +1 -0
  595. package/dist/rpc/FilterForm.cjs +20 -0
  596. package/dist/rpc/FilterForm.cjs.map +1 -1
  597. package/dist/rpc/FilterForm.js +20 -0
  598. package/dist/rpc/FilterForm.js.map +1 -1
  599. package/dist/rpc/formMetadata.cjs +34 -0
  600. package/dist/rpc/formMetadata.cjs.map +1 -1
  601. package/dist/rpc/formMetadata.d.ts.map +1 -1
  602. package/dist/rpc/formMetadata.js +35 -1
  603. package/dist/rpc/formMetadata.js.map +1 -1
  604. package/dist/rpc/types.cjs.map +1 -1
  605. package/dist/rpc/types.d.ts +9 -1
  606. package/dist/rpc/types.d.ts.map +1 -1
  607. package/dist/rpc/types.js.map +1 -1
  608. package/dist/styles.css +1 -1
  609. package/package.json +6 -1
@@ -1 +1 @@
1
- {"version":3,"file":"TreeNode.cjs","sources":["../../src/data/TreeNode.tsx"],"sourcesContent":["import { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon } from \"./Icon\";\nimport { UiChevronDown, UiChevronRight } from \"../icons\";\n\nexport type TreeRowContext<T> = {\n node: T;\n depth: number;\n open: boolean;\n selected: boolean;\n hasChildren: boolean;\n toggle: () => void;\n /** True while this node's lazy children are being fetched via loadChildren. */\n loading: boolean;\n /** The rejection value from loadChildren, or null when there was no error. */\n error: unknown;\n};\n\nexport type TreeNodeProps<T> = {\n node: T;\n depth?: number;\n expandAll?: boolean | null;\n forcedOpenKeys?: Set<string | number> | null;\n selected?: T | null;\n defaultOpen?: (node: T, depth: number) => boolean;\n getChildren: (node: T) => T[] | undefined;\n getKey: (node: T) => string | number;\n getAriaLabel?: (node: T) => string;\n onSelect?: (node: T) => void;\n renderRow: (ctx: TreeRowContext<T>) => ReactNode;\n rowClass?: (node: T, selected: boolean) => string;\n indentPx?: number;\n basePaddingPx?: number;\n /**\n * Reports that a node has children that are not yet loaded — it renders an\n * expand chevron even when `getChildren` returns nothing. On the first open\n * the node fetches them via `loadChildren`. Without this (the default), a\n * node is expandable only when `getChildren` already returns children.\n */\n hasMoreChildren?: (node: T) => boolean;\n /**\n * Lazily fetch a node's children the first time it is opened. Resolves to the\n * child nodes (which may themselves be lazy). A rejection is surfaced to\n * `renderRow` via `ctx.error` and is not retried until the node is collapsed\n * and reopened. Required for any node `hasMoreChildren` returns true for.\n */\n loadChildren?: (node: T) => Promise<T[]>;\n /**\n * Marks a node as a **secondary child** of its parent. Secondary\n * children keep the full tree structure (they render, they can be\n * opened manually) but opt out of the bulk behaviours a caller\n * typically wants when they click the toolbar:\n *\n * - Tree-wide filter: their text is skipped during match detection\n * so typing in the search box never surfaces a row because one\n * of its secondary children happened to match.\n * - Expand all: secondary nodes stay at their default-open state\n * instead of being forced open, preventing 28k field rows from\n * flooding the viewport when an operator hits the button on a\n * schema with hundreds of tables.\n *\n * Default: every node is primary (returns false).\n */\n isSecondary?: (node: T) => boolean;\n};\n\nexport function TreeNode<T>({\n node,\n depth = 0,\n expandAll = null,\n forcedOpenKeys = null,\n selected = null,\n defaultOpen,\n getChildren,\n getKey,\n getAriaLabel,\n onSelect,\n renderRow,\n rowClass,\n indentPx = 16,\n basePaddingPx = 8,\n isSecondary,\n hasMoreChildren,\n loadChildren,\n}: TreeNodeProps<T>) {\n // Lazily-fetched children take precedence over the synchronous ones once a\n // load has resolved; until then `loadedChildren` is null and we fall back to\n // getChildren. A node can be \"lazy\" (hasMoreChildren) with no sync children.\n const [loadedChildren, setLoadedChildren] = useState<T[] | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<unknown>(null);\n const syncChildren = getChildren(node);\n const children = loadedChildren ?? syncChildren;\n const hasChildren = (children?.length ?? 0) > 0;\n const lazyUnloaded = (hasMoreChildren?.(node) ?? false) && loadedChildren === null;\n // The chevron shows when there is something to reveal: either real children\n // are present, or the node is lazy and has not been loaded yet.\n const expandable = hasChildren || lazyUnloaded;\n // A node opts out of bulk expand-all in two distinct cases:\n //\n // 1. The node itself is secondary (its edge from the parent is\n // secondary) — rare at the root, but the rule is symmetric.\n // 2. All of the node's children are secondary — the common case.\n // This is what keeps an \"Expand all\" on a schema tree from\n // flooding the viewport with every table's field rows: the\n // table opens to nothing structural worth seeing in bulk, so\n // we leave it closed until the operator clicks it manually.\n //\n // In both cases the manual toggle still works, and filter matches\n // still force the row open via forcedOpenKeys, so users never\n // lose access — they just don't get auto-flooded.\n const secondaryNode = isSecondary?.(node) ?? false;\n const childrenAllSecondary =\n hasChildren && isSecondary != null && children!.every((c) => isSecondary(c));\n const skipExpandAll = secondaryNode || childrenAllSecondary;\n // A non-null `expandAll` is a live bulk state, not just a one-off change\n // signal: a node mounted *while* expand-all is active (because an ancestor\n // just opened) inherits it as its initial open state, so opening a parent\n // cascades all the way down — expand/collapse-all are recursive. The\n // skipExpandAll guard keeps secondary subtrees from auto-flooding. When\n // expandAll is null (before any toolbar click) we fall back to defaultOpen.\n const initialOpen =\n expandAll !== null && !skipExpandAll\n ? expandAll\n : defaultOpen\n ? defaultOpen(node, depth)\n : depth < 1;\n const [open, setOpen] = useState(initialOpen);\n const prevExpandAll = useRef(expandAll);\n const isSelected = selected === node;\n const key = getKey(node);\n const isForcedOpen = forcedOpenKeys?.has(key) ?? false;\n const isOpen = isForcedOpen || open;\n\n useEffect(() => {\n if (expandAll !== null && expandAll !== prevExpandAll.current && !skipExpandAll) {\n setOpen(expandAll);\n }\n prevExpandAll.current = expandAll;\n }, [expandAll, skipExpandAll]);\n\n // Guards a lazy fetch so a node loads its children at most once per mount and\n // a resolution arriving after the node was reused (key changed) is ignored.\n const loadRequested = useRef(false);\n const nodeKey = getKey(node);\n const loadKeyRef = useRef(nodeKey);\n\n function loadLazyChildren() {\n if (!loadChildren || loadRequested.current) return;\n loadRequested.current = true;\n loadKeyRef.current = nodeKey;\n setLoading(true);\n setError(null);\n loadChildren(node)\n .then((kids) => {\n if (loadKeyRef.current !== nodeKey) return;\n setLoadedChildren(kids);\n setLoading(false);\n })\n .catch((err) => {\n if (loadKeyRef.current !== nodeKey) return;\n // Surfaced to renderRow via ctx.error; allow a retry on re-toggle.\n loadRequested.current = false;\n setError(err);\n setLoading(false);\n });\n }\n\n function toggle() {\n if (!expandable) return;\n setOpen((o) => {\n const next = !o;\n // Only fetch when transitioning into the open state, so collapsing a\n // not-yet-loaded (e.g. previously-failed) lazy node never triggers a load.\n if (next && lazyUnloaded) loadLazyChildren();\n return next;\n });\n }\n\n const defaultRowBg = isSelected ? \"bg-primary/10 border-l-2 border-primary\" : \"hover:bg-accent\";\n const rowClassName = rowClass ? rowClass(node, isSelected) : defaultRowBg;\n\n return (\n <div\n role=\"treeitem\"\n aria-label={getAriaLabel?.(node)}\n aria-expanded={expandable ? isOpen : undefined}\n aria-selected={isSelected}\n >\n <div\n className={cn(\"flex items-center gap-1.5 py-1 px-2 cursor-pointer text-sm\", rowClassName)}\n style={{ paddingLeft: `${depth * indentPx + basePaddingPx}px` }}\n onClick={(e) => {\n e.stopPropagation();\n onSelect?.(node);\n toggle();\n }}\n >\n {expandable ? (\n <button\n type=\"button\"\n aria-label={isOpen ? \"Collapse\" : \"Expand\"}\n // The caret only toggles expansion — stopPropagation keeps the row's\n // onClick (which selects) from firing, so expanding a node never\n // selects it.\n onClick={(e) => {\n e.stopPropagation();\n toggle();\n }}\n className=\"flex shrink-0 items-center text-muted-foreground\"\n >\n <Icon icon={isOpen ? UiChevronDown : UiChevronRight} className=\"text-xs w-3\" />\n </button>\n ) : (\n <span className=\"w-3 shrink-0\" aria-hidden />\n )}\n {renderRow({\n node,\n depth,\n open: isOpen,\n selected: isSelected,\n hasChildren,\n toggle,\n loading,\n error,\n })}\n </div>\n {isOpen && hasChildren && (\n <div role=\"group\">\n {children!.map((child) => (\n <TreeNode\n key={getKey(child)}\n node={child}\n depth={depth + 1}\n expandAll={expandAll}\n forcedOpenKeys={forcedOpenKeys}\n selected={selected}\n getChildren={getChildren}\n getKey={getKey}\n renderRow={renderRow}\n indentPx={indentPx}\n basePaddingPx={basePaddingPx}\n {...(defaultOpen ? { defaultOpen } : {})}\n {...(getAriaLabel ? { getAriaLabel } : {})}\n {...(onSelect ? { onSelect } : {})}\n {...(rowClass ? { rowClass } : {})}\n {...(isSecondary ? { isSecondary } : {})}\n {...(hasMoreChildren ? { hasMoreChildren } : {})}\n {...(loadChildren ? { loadChildren } : {})}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n"],"names":["useState","useRef","useEffect","jsxs","cn","jsx","Icon","UiChevronDown","UiChevronRight"],"mappings":";;;;;;;;AAkEO,SAAS,SAAY;AAAA,EAC1B;AAAA,EACA,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,gBAAgB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AACF,GAAqB;AAInB,QAAM,CAAC,gBAAgB,iBAAiB,IAAIA,MAAAA,SAAqB,IAAI;AACrE,QAAM,CAAC,SAAS,UAAU,IAAIA,MAAAA,SAAS,KAAK;AAC5C,QAAM,CAAC,OAAO,QAAQ,IAAIA,MAAAA,SAAkB,IAAI;AAChD,QAAM,eAAe,YAAY,IAAI;AACrC,QAAM,WAAW,kBAAkB;AACnC,QAAM,gBAAe,qCAAU,WAAU,KAAK;AAC9C,QAAM,iBAAgB,mDAAkB,UAAS,UAAU,mBAAmB;AAG9E,QAAM,aAAa,eAAe;AAclC,QAAM,iBAAgB,2CAAc,UAAS;AAC7C,QAAM,uBACJ,eAAe,eAAe,QAAQ,SAAU,MAAM,CAAC,MAAM,YAAY,CAAC,CAAC;AAC7E,QAAM,gBAAgB,iBAAiB;AAOvC,QAAM,cACJ,cAAc,QAAQ,CAAC,gBACnB,YACA,cACE,YAAY,MAAM,KAAK,IACvB,QAAQ;AAChB,QAAM,CAAC,MAAM,OAAO,IAAIA,MAAAA,SAAS,WAAW;AAC5C,QAAM,gBAAgBC,MAAAA,OAAO,SAAS;AACtC,QAAM,aAAa,aAAa;AAChC,QAAM,MAAM,OAAO,IAAI;AACvB,QAAM,gBAAe,iDAAgB,IAAI,SAAQ;AACjD,QAAM,SAAS,gBAAgB;AAE/BC,QAAAA,UAAU,MAAM;AACd,QAAI,cAAc,QAAQ,cAAc,cAAc,WAAW,CAAC,eAAe;AAC/E,cAAQ,SAAS;AAAA,IACnB;AACA,kBAAc,UAAU;AAAA,EAC1B,GAAG,CAAC,WAAW,aAAa,CAAC;AAI7B,QAAM,gBAAgBD,MAAAA,OAAO,KAAK;AAClC,QAAM,UAAU,OAAO,IAAI;AAC3B,QAAM,aAAaA,MAAAA,OAAO,OAAO;AAEjC,WAAS,mBAAmB;AAC1B,QAAI,CAAC,gBAAgB,cAAc,QAAS;AAC5C,kBAAc,UAAU;AACxB,eAAW,UAAU;AACrB,eAAW,IAAI;AACf,aAAS,IAAI;AACb,iBAAa,IAAI,EACd,KAAK,CAAC,SAAS;AACd,UAAI,WAAW,YAAY,QAAS;AACpC,wBAAkB,IAAI;AACtB,iBAAW,KAAK;AAAA,IAClB,CAAC,EACA,MAAM,CAAC,QAAQ;AACd,UAAI,WAAW,YAAY,QAAS;AAEpC,oBAAc,UAAU;AACxB,eAAS,GAAG;AACZ,iBAAW,KAAK;AAAA,IAClB,CAAC;AAAA,EACL;AAEA,WAAS,SAAS;AAChB,QAAI,CAAC,WAAY;AACjB,YAAQ,CAAC,MAAM;AACb,YAAM,OAAO,CAAC;AAGd,UAAI,QAAQ,aAAc,kBAAA;AAC1B,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,QAAM,eAAe,aAAa,4CAA4C;AAC9E,QAAM,eAAe,WAAW,SAAS,MAAM,UAAU,IAAI;AAE7D,SACEE,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAY,6CAAe;AAAA,MAC3B,iBAAe,aAAa,SAAS;AAAA,MACrC,iBAAe;AAAA,MAEf,UAAA;AAAA,QAAAA,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAWC,MAAAA,GAAG,8DAA8D,YAAY;AAAA,YACxF,OAAO,EAAE,aAAa,GAAG,QAAQ,WAAW,aAAa,KAAA;AAAA,YACzD,SAAS,CAAC,MAAM;AACd,gBAAE,gBAAA;AACF,mDAAW;AACX,qBAAA;AAAA,YACF;AAAA,YAEC,UAAA;AAAA,cAAA,aACCC,2BAAAA;AAAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,MAAK;AAAA,kBACL,cAAY,SAAS,aAAa;AAAA,kBAIlC,SAAS,CAAC,MAAM;AACd,sBAAE,gBAAA;AACF,2BAAA;AAAA,kBACF;AAAA,kBACA,WAAU;AAAA,kBAEV,yCAACC,KAAAA,MAAA,EAAK,MAAM,SAASC,8BAAgBC,eAAAA,gBAAgB,WAAU,cAAA,CAAc;AAAA,gBAAA;AAAA,cAAA,IAG/EH,2BAAAA,IAAC,QAAA,EAAK,WAAU,gBAAe,eAAW,MAAC;AAAA,cAE5C,UAAU;AAAA,gBACT;AAAA,gBACA;AAAA,gBACA,MAAM;AAAA,gBACN,UAAU;AAAA,gBACV;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,cAAA,CACD;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA;AAAA,QAEF,UAAU,eACTA,+BAAC,OAAA,EAAI,MAAK,SACP,UAAA,SAAU,IAAI,CAAC,UACdA,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YAEC,MAAM;AAAA,YACN,OAAO,QAAQ;AAAA,YACf;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACC,GAAI,cAAc,EAAE,YAAA,IAAgB,CAAA;AAAA,YACpC,GAAI,eAAe,EAAE,aAAA,IAAiB,CAAA;AAAA,YACtC,GAAI,WAAW,EAAE,SAAA,IAAa,CAAA;AAAA,YAC9B,GAAI,WAAW,EAAE,SAAA,IAAa,CAAA;AAAA,YAC9B,GAAI,cAAc,EAAE,YAAA,IAAgB,CAAA;AAAA,YACpC,GAAI,kBAAkB,EAAE,gBAAA,IAAoB,CAAA;AAAA,YAC5C,GAAI,eAAe,EAAE,iBAAiB,CAAA;AAAA,UAAC;AAAA,UAjBnC,OAAO,KAAK;AAAA,QAAA,CAmBpB,EAAA,CACH;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAIR;;"}
1
+ {"version":3,"file":"TreeNode.cjs","sources":["../../src/data/TreeNode.tsx"],"sourcesContent":["import { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon } from \"./Icon\";\nimport { UiChevronDown, UiChevronRight } from \"../icons\";\n\nexport type TreeRowContext<T> = {\n node: T;\n depth: number;\n open: boolean;\n selected: boolean;\n hasChildren: boolean;\n toggle: () => void;\n /** True while this node's lazy children are being fetched via loadChildren. */\n loading: boolean;\n /** The rejection value from loadChildren, or null when there was no error. */\n error: unknown;\n};\n\nexport type TreeNodeProps<T> = {\n node: T;\n depth?: number;\n expandAll?: boolean | null;\n forcedOpenKeys?: Set<string | number> | null;\n selected?: T | null;\n defaultOpen?: (node: T, depth: number) => boolean;\n getChildren: (node: T) => T[] | undefined;\n getKey: (node: T) => string | number;\n getAriaLabel?: (node: T) => string;\n onSelect?: (node: T) => void;\n renderRow: (ctx: TreeRowContext<T>) => ReactNode;\n rowClass?: (node: T, selected: boolean) => string;\n indentPx?: number;\n basePaddingPx?: number;\n /**\n * Reports that a node has children that are not yet loaded — it renders an\n * expand chevron even when `getChildren` returns nothing. On the first open\n * the node fetches them via `loadChildren`. Without this (the default), a\n * node is expandable only when `getChildren` already returns children.\n */\n hasMoreChildren?: (node: T) => boolean;\n /**\n * Lazily fetch a node's children the first time it is opened. Resolves to the\n * child nodes (which may themselves be lazy). A rejection is surfaced to\n * `renderRow` via `ctx.error` and is not retried until the node is collapsed\n * and reopened. Required for any node `hasMoreChildren` returns true for.\n */\n loadChildren?: (node: T) => Promise<T[]>;\n /**\n * Marks a node as a **secondary child** of its parent. Secondary\n * children keep the full tree structure (they render, they can be\n * opened manually) but opt out of the bulk behaviours a caller\n * typically wants when they click the toolbar:\n *\n * - Tree-wide filter: their text is skipped during match detection\n * so typing in the search box never surfaces a row because one\n * of its secondary children happened to match.\n * - Expand all: secondary nodes stay at their default-open state\n * instead of being forced open, preventing 28k field rows from\n * flooding the viewport when an operator hits the button on a\n * schema with hundreds of tables.\n *\n * Default: every node is primary (returns false).\n */\n isSecondary?: (node: T) => boolean;\n};\n\nexport function TreeNode<T>({\n node,\n depth = 0,\n expandAll = null,\n forcedOpenKeys = null,\n selected = null,\n defaultOpen,\n getChildren,\n getKey,\n getAriaLabel,\n onSelect,\n renderRow,\n rowClass,\n indentPx = 16,\n basePaddingPx = 8,\n isSecondary,\n hasMoreChildren,\n loadChildren,\n}: TreeNodeProps<T>) {\n // Lazily-fetched children take precedence over the synchronous ones once a\n // load has resolved; until then `loadedChildren` is null and we fall back to\n // getChildren. A node can be \"lazy\" (hasMoreChildren) with no sync children.\n const [loadedChildren, setLoadedChildren] = useState<T[] | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<unknown>(null);\n const syncChildren = getChildren(node);\n const children = loadedChildren ?? syncChildren;\n const hasChildren = (children?.length ?? 0) > 0;\n const lazyUnloaded = (hasMoreChildren?.(node) ?? false) && loadedChildren === null;\n // The chevron shows when there is something to reveal: either real children\n // are present, or the node is lazy and has not been loaded yet.\n const expandable = hasChildren || lazyUnloaded;\n // A node opts out of bulk expand-all in two distinct cases:\n //\n // 1. The node itself is secondary (its edge from the parent is\n // secondary) — rare at the root, but the rule is symmetric.\n // 2. All of the node's children are secondary — the common case.\n // This is what keeps an \"Expand all\" on a schema tree from\n // flooding the viewport with every table's field rows: the\n // table opens to nothing structural worth seeing in bulk, so\n // we leave it closed until the operator clicks it manually.\n //\n // In both cases the manual toggle still works, and filter matches\n // still force the row open via forcedOpenKeys, so users never\n // lose access — they just don't get auto-flooded.\n const secondaryNode = isSecondary?.(node) ?? false;\n const childrenAllSecondary =\n hasChildren && isSecondary != null && children!.every((c) => isSecondary(c));\n const skipExpandAll = secondaryNode || childrenAllSecondary;\n // A non-null `expandAll` is a live bulk state, not just a one-off change\n // signal: a node mounted *while* expand-all is active (because an ancestor\n // just opened) inherits it as its initial open state, so opening a parent\n // cascades all the way down — expand/collapse-all are recursive. The\n // skipExpandAll guard keeps secondary subtrees from auto-flooding. When\n // expandAll is null (before any toolbar click) we fall back to defaultOpen.\n const initialOpen =\n expandAll !== null && !skipExpandAll\n ? expandAll\n : defaultOpen\n ? defaultOpen(node, depth)\n : depth < 1;\n const [open, setOpen] = useState(initialOpen);\n const prevExpandAll = useRef(expandAll);\n const isSelected = selected === node;\n const key = getKey(node);\n const isForcedOpen = forcedOpenKeys?.has(key) ?? false;\n const isOpen = isForcedOpen || open;\n\n useEffect(() => {\n if (expandAll !== null && expandAll !== prevExpandAll.current && !skipExpandAll) {\n setOpen(expandAll);\n }\n prevExpandAll.current = expandAll;\n }, [expandAll, skipExpandAll]);\n\n // Guards a lazy fetch so a node loads its children at most once per mount and\n // a resolution arriving after the node was reused (key changed) is ignored.\n const loadRequested = useRef(false);\n const nodeKey = getKey(node);\n const loadKeyRef = useRef(nodeKey);\n\n function loadLazyChildren() {\n if (!loadChildren || loadRequested.current) return;\n loadRequested.current = true;\n loadKeyRef.current = nodeKey;\n setLoading(true);\n setError(null);\n loadChildren(node)\n .then((kids) => {\n if (loadKeyRef.current !== nodeKey) return;\n setLoadedChildren(kids);\n setLoading(false);\n })\n .catch((err) => {\n if (loadKeyRef.current !== nodeKey) return;\n // Surfaced to renderRow via ctx.error; allow a retry on re-toggle.\n loadRequested.current = false;\n setError(err);\n setLoading(false);\n });\n }\n\n // A lazy node can be open without ever having been clicked — defaultOpen said\n // so, expand-all did, or the filter forced it open to reveal a match. Loading\n // only on the open transition would leave every one of those showing a caret\n // over nothing.\n //\n // A node that already failed is skipped: loadLazyChildren clears its own retry\n // guard on failure so a re-toggle can try again, and re-running here would\n // turn that into an unbounded retry loop instead.\n useEffect(() => {\n if (isOpen && lazyUnloaded && error === null) loadLazyChildren();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen, lazyUnloaded, error]);\n\n function toggle() {\n if (!expandable) return;\n setOpen((o) => {\n const next = !o;\n // Only fetch when transitioning into the open state, so collapsing a\n // not-yet-loaded (e.g. previously-failed) lazy node never triggers a load.\n if (next && lazyUnloaded) loadLazyChildren();\n return next;\n });\n }\n\n const defaultRowBg = isSelected ? \"bg-primary/10 border-l-2 border-primary\" : \"hover:bg-accent\";\n const rowClassName = rowClass ? rowClass(node, isSelected) : defaultRowBg;\n\n return (\n <div\n role=\"treeitem\"\n aria-label={getAriaLabel?.(node)}\n aria-expanded={expandable ? isOpen : undefined}\n aria-selected={isSelected}\n >\n <div\n className={cn(\"flex items-center gap-1.5 py-1 px-2 cursor-pointer text-sm\", rowClassName)}\n style={{ paddingLeft: `${depth * indentPx + basePaddingPx}px` }}\n onClick={(e) => {\n e.stopPropagation();\n onSelect?.(node);\n toggle();\n }}\n >\n {expandable ? (\n <button\n type=\"button\"\n aria-label={isOpen ? \"Collapse\" : \"Expand\"}\n // The caret only toggles expansion — stopPropagation keeps the row's\n // onClick (which selects) from firing, so expanding a node never\n // selects it.\n onClick={(e) => {\n e.stopPropagation();\n toggle();\n }}\n className=\"flex shrink-0 items-center text-muted-foreground\"\n >\n <Icon icon={isOpen ? UiChevronDown : UiChevronRight} className=\"text-xs w-3\" />\n </button>\n ) : (\n <span className=\"w-3 shrink-0\" aria-hidden />\n )}\n {renderRow({\n node,\n depth,\n open: isOpen,\n selected: isSelected,\n hasChildren,\n toggle,\n loading,\n error,\n })}\n </div>\n {isOpen && hasChildren && (\n <div role=\"group\">\n {children!.map((child) => (\n <TreeNode\n key={getKey(child)}\n node={child}\n depth={depth + 1}\n expandAll={expandAll}\n forcedOpenKeys={forcedOpenKeys}\n selected={selected}\n getChildren={getChildren}\n getKey={getKey}\n renderRow={renderRow}\n indentPx={indentPx}\n basePaddingPx={basePaddingPx}\n {...(defaultOpen ? { defaultOpen } : {})}\n {...(getAriaLabel ? { getAriaLabel } : {})}\n {...(onSelect ? { onSelect } : {})}\n {...(rowClass ? { rowClass } : {})}\n {...(isSecondary ? { isSecondary } : {})}\n {...(hasMoreChildren ? { hasMoreChildren } : {})}\n {...(loadChildren ? { loadChildren } : {})}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n"],"names":["useState","useRef","useEffect","jsxs","cn","jsx","Icon","UiChevronDown","UiChevronRight"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"TreeNode.d.ts","sourceRoot":"","sources":["../../src/data/TreeNode.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAKpE,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAC9B,IAAI,EAAE,CAAC,CAAC;IACR,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,+EAA+E;IAC/E,OAAO,EAAE,OAAO,CAAC;IACjB,8EAA8E;IAC9E,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI;IAC7B,IAAI,EAAE,CAAC,CAAC;IACR,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC;IAC7C,QAAQ,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC;IACpB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IAClD,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,SAAS,CAAC;IAC1C,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,GAAG,MAAM,CAAC;IACrC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC;IACnC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IAC7B,SAAS,EAAE,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC;IACjD,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,OAAO,KAAK,MAAM,CAAC;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;IACvC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IACzC;;;;;;;;;;;;;;;OAeG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;CACpC,CAAC;AAEF,wBAAgB,QAAQ,CAAC,CAAC,EAAE,EAC1B,IAAI,EACJ,KAAS,EACT,SAAgB,EAChB,cAAqB,EACrB,QAAe,EACf,WAAW,EACX,WAAW,EACX,MAAM,EACN,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,QAAa,EACb,aAAiB,EACjB,WAAW,EACX,eAAe,EACf,YAAY,GACb,EAAE,aAAa,CAAC,CAAC,CAAC,2CA2KlB"}
1
+ {"version":3,"file":"TreeNode.d.ts","sourceRoot":"","sources":["../../src/data/TreeNode.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAKpE,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAC9B,IAAI,EAAE,CAAC,CAAC;IACR,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,+EAA+E;IAC/E,OAAO,EAAE,OAAO,CAAC;IACjB,8EAA8E;IAC9E,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI;IAC7B,IAAI,EAAE,CAAC,CAAC;IACR,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC;IAC7C,QAAQ,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC;IACpB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IAClD,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,SAAS,CAAC;IAC1C,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,GAAG,MAAM,CAAC;IACrC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC;IACnC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IAC7B,SAAS,EAAE,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC;IACjD,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,OAAO,KAAK,MAAM,CAAC;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;IACvC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IACzC;;;;;;;;;;;;;;;OAeG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;CACpC,CAAC;AAEF,wBAAgB,QAAQ,CAAC,CAAC,EAAE,EAC1B,IAAI,EACJ,KAAS,EACT,SAAgB,EAChB,cAAqB,EACrB,QAAe,EACf,WAAW,EACX,WAAW,EACX,MAAM,EACN,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,QAAa,EACb,aAAiB,EACjB,WAAW,EACX,eAAe,EACf,YAAY,GACb,EAAE,aAAa,CAAC,CAAC,CAAC,2CAwLlB"}
@@ -67,6 +67,9 @@ function TreeNode({
67
67
  setLoading(false);
68
68
  });
69
69
  }
70
+ useEffect(() => {
71
+ if (isOpen && lazyUnloaded && error === null) loadLazyChildren();
72
+ }, [isOpen, lazyUnloaded, error]);
70
73
  function toggle() {
71
74
  if (!expandable) return;
72
75
  setOpen((o) => {
@@ -1 +1 @@
1
- {"version":3,"file":"TreeNode.js","sources":["../../src/data/TreeNode.tsx"],"sourcesContent":["import { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon } from \"./Icon\";\nimport { UiChevronDown, UiChevronRight } from \"../icons\";\n\nexport type TreeRowContext<T> = {\n node: T;\n depth: number;\n open: boolean;\n selected: boolean;\n hasChildren: boolean;\n toggle: () => void;\n /** True while this node's lazy children are being fetched via loadChildren. */\n loading: boolean;\n /** The rejection value from loadChildren, or null when there was no error. */\n error: unknown;\n};\n\nexport type TreeNodeProps<T> = {\n node: T;\n depth?: number;\n expandAll?: boolean | null;\n forcedOpenKeys?: Set<string | number> | null;\n selected?: T | null;\n defaultOpen?: (node: T, depth: number) => boolean;\n getChildren: (node: T) => T[] | undefined;\n getKey: (node: T) => string | number;\n getAriaLabel?: (node: T) => string;\n onSelect?: (node: T) => void;\n renderRow: (ctx: TreeRowContext<T>) => ReactNode;\n rowClass?: (node: T, selected: boolean) => string;\n indentPx?: number;\n basePaddingPx?: number;\n /**\n * Reports that a node has children that are not yet loaded — it renders an\n * expand chevron even when `getChildren` returns nothing. On the first open\n * the node fetches them via `loadChildren`. Without this (the default), a\n * node is expandable only when `getChildren` already returns children.\n */\n hasMoreChildren?: (node: T) => boolean;\n /**\n * Lazily fetch a node's children the first time it is opened. Resolves to the\n * child nodes (which may themselves be lazy). A rejection is surfaced to\n * `renderRow` via `ctx.error` and is not retried until the node is collapsed\n * and reopened. Required for any node `hasMoreChildren` returns true for.\n */\n loadChildren?: (node: T) => Promise<T[]>;\n /**\n * Marks a node as a **secondary child** of its parent. Secondary\n * children keep the full tree structure (they render, they can be\n * opened manually) but opt out of the bulk behaviours a caller\n * typically wants when they click the toolbar:\n *\n * - Tree-wide filter: their text is skipped during match detection\n * so typing in the search box never surfaces a row because one\n * of its secondary children happened to match.\n * - Expand all: secondary nodes stay at their default-open state\n * instead of being forced open, preventing 28k field rows from\n * flooding the viewport when an operator hits the button on a\n * schema with hundreds of tables.\n *\n * Default: every node is primary (returns false).\n */\n isSecondary?: (node: T) => boolean;\n};\n\nexport function TreeNode<T>({\n node,\n depth = 0,\n expandAll = null,\n forcedOpenKeys = null,\n selected = null,\n defaultOpen,\n getChildren,\n getKey,\n getAriaLabel,\n onSelect,\n renderRow,\n rowClass,\n indentPx = 16,\n basePaddingPx = 8,\n isSecondary,\n hasMoreChildren,\n loadChildren,\n}: TreeNodeProps<T>) {\n // Lazily-fetched children take precedence over the synchronous ones once a\n // load has resolved; until then `loadedChildren` is null and we fall back to\n // getChildren. A node can be \"lazy\" (hasMoreChildren) with no sync children.\n const [loadedChildren, setLoadedChildren] = useState<T[] | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<unknown>(null);\n const syncChildren = getChildren(node);\n const children = loadedChildren ?? syncChildren;\n const hasChildren = (children?.length ?? 0) > 0;\n const lazyUnloaded = (hasMoreChildren?.(node) ?? false) && loadedChildren === null;\n // The chevron shows when there is something to reveal: either real children\n // are present, or the node is lazy and has not been loaded yet.\n const expandable = hasChildren || lazyUnloaded;\n // A node opts out of bulk expand-all in two distinct cases:\n //\n // 1. The node itself is secondary (its edge from the parent is\n // secondary) — rare at the root, but the rule is symmetric.\n // 2. All of the node's children are secondary — the common case.\n // This is what keeps an \"Expand all\" on a schema tree from\n // flooding the viewport with every table's field rows: the\n // table opens to nothing structural worth seeing in bulk, so\n // we leave it closed until the operator clicks it manually.\n //\n // In both cases the manual toggle still works, and filter matches\n // still force the row open via forcedOpenKeys, so users never\n // lose access — they just don't get auto-flooded.\n const secondaryNode = isSecondary?.(node) ?? false;\n const childrenAllSecondary =\n hasChildren && isSecondary != null && children!.every((c) => isSecondary(c));\n const skipExpandAll = secondaryNode || childrenAllSecondary;\n // A non-null `expandAll` is a live bulk state, not just a one-off change\n // signal: a node mounted *while* expand-all is active (because an ancestor\n // just opened) inherits it as its initial open state, so opening a parent\n // cascades all the way down — expand/collapse-all are recursive. The\n // skipExpandAll guard keeps secondary subtrees from auto-flooding. When\n // expandAll is null (before any toolbar click) we fall back to defaultOpen.\n const initialOpen =\n expandAll !== null && !skipExpandAll\n ? expandAll\n : defaultOpen\n ? defaultOpen(node, depth)\n : depth < 1;\n const [open, setOpen] = useState(initialOpen);\n const prevExpandAll = useRef(expandAll);\n const isSelected = selected === node;\n const key = getKey(node);\n const isForcedOpen = forcedOpenKeys?.has(key) ?? false;\n const isOpen = isForcedOpen || open;\n\n useEffect(() => {\n if (expandAll !== null && expandAll !== prevExpandAll.current && !skipExpandAll) {\n setOpen(expandAll);\n }\n prevExpandAll.current = expandAll;\n }, [expandAll, skipExpandAll]);\n\n // Guards a lazy fetch so a node loads its children at most once per mount and\n // a resolution arriving after the node was reused (key changed) is ignored.\n const loadRequested = useRef(false);\n const nodeKey = getKey(node);\n const loadKeyRef = useRef(nodeKey);\n\n function loadLazyChildren() {\n if (!loadChildren || loadRequested.current) return;\n loadRequested.current = true;\n loadKeyRef.current = nodeKey;\n setLoading(true);\n setError(null);\n loadChildren(node)\n .then((kids) => {\n if (loadKeyRef.current !== nodeKey) return;\n setLoadedChildren(kids);\n setLoading(false);\n })\n .catch((err) => {\n if (loadKeyRef.current !== nodeKey) return;\n // Surfaced to renderRow via ctx.error; allow a retry on re-toggle.\n loadRequested.current = false;\n setError(err);\n setLoading(false);\n });\n }\n\n function toggle() {\n if (!expandable) return;\n setOpen((o) => {\n const next = !o;\n // Only fetch when transitioning into the open state, so collapsing a\n // not-yet-loaded (e.g. previously-failed) lazy node never triggers a load.\n if (next && lazyUnloaded) loadLazyChildren();\n return next;\n });\n }\n\n const defaultRowBg = isSelected ? \"bg-primary/10 border-l-2 border-primary\" : \"hover:bg-accent\";\n const rowClassName = rowClass ? rowClass(node, isSelected) : defaultRowBg;\n\n return (\n <div\n role=\"treeitem\"\n aria-label={getAriaLabel?.(node)}\n aria-expanded={expandable ? isOpen : undefined}\n aria-selected={isSelected}\n >\n <div\n className={cn(\"flex items-center gap-1.5 py-1 px-2 cursor-pointer text-sm\", rowClassName)}\n style={{ paddingLeft: `${depth * indentPx + basePaddingPx}px` }}\n onClick={(e) => {\n e.stopPropagation();\n onSelect?.(node);\n toggle();\n }}\n >\n {expandable ? (\n <button\n type=\"button\"\n aria-label={isOpen ? \"Collapse\" : \"Expand\"}\n // The caret only toggles expansion — stopPropagation keeps the row's\n // onClick (which selects) from firing, so expanding a node never\n // selects it.\n onClick={(e) => {\n e.stopPropagation();\n toggle();\n }}\n className=\"flex shrink-0 items-center text-muted-foreground\"\n >\n <Icon icon={isOpen ? UiChevronDown : UiChevronRight} className=\"text-xs w-3\" />\n </button>\n ) : (\n <span className=\"w-3 shrink-0\" aria-hidden />\n )}\n {renderRow({\n node,\n depth,\n open: isOpen,\n selected: isSelected,\n hasChildren,\n toggle,\n loading,\n error,\n })}\n </div>\n {isOpen && hasChildren && (\n <div role=\"group\">\n {children!.map((child) => (\n <TreeNode\n key={getKey(child)}\n node={child}\n depth={depth + 1}\n expandAll={expandAll}\n forcedOpenKeys={forcedOpenKeys}\n selected={selected}\n getChildren={getChildren}\n getKey={getKey}\n renderRow={renderRow}\n indentPx={indentPx}\n basePaddingPx={basePaddingPx}\n {...(defaultOpen ? { defaultOpen } : {})}\n {...(getAriaLabel ? { getAriaLabel } : {})}\n {...(onSelect ? { onSelect } : {})}\n {...(rowClass ? { rowClass } : {})}\n {...(isSecondary ? { isSecondary } : {})}\n {...(hasMoreChildren ? { hasMoreChildren } : {})}\n {...(loadChildren ? { loadChildren } : {})}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TreeNode.js","sources":["../../src/data/TreeNode.tsx"],"sourcesContent":["import { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon } from \"./Icon\";\nimport { UiChevronDown, UiChevronRight } from \"../icons\";\n\nexport type TreeRowContext<T> = {\n node: T;\n depth: number;\n open: boolean;\n selected: boolean;\n hasChildren: boolean;\n toggle: () => void;\n /** True while this node's lazy children are being fetched via loadChildren. */\n loading: boolean;\n /** The rejection value from loadChildren, or null when there was no error. */\n error: unknown;\n};\n\nexport type TreeNodeProps<T> = {\n node: T;\n depth?: number;\n expandAll?: boolean | null;\n forcedOpenKeys?: Set<string | number> | null;\n selected?: T | null;\n defaultOpen?: (node: T, depth: number) => boolean;\n getChildren: (node: T) => T[] | undefined;\n getKey: (node: T) => string | number;\n getAriaLabel?: (node: T) => string;\n onSelect?: (node: T) => void;\n renderRow: (ctx: TreeRowContext<T>) => ReactNode;\n rowClass?: (node: T, selected: boolean) => string;\n indentPx?: number;\n basePaddingPx?: number;\n /**\n * Reports that a node has children that are not yet loaded — it renders an\n * expand chevron even when `getChildren` returns nothing. On the first open\n * the node fetches them via `loadChildren`. Without this (the default), a\n * node is expandable only when `getChildren` already returns children.\n */\n hasMoreChildren?: (node: T) => boolean;\n /**\n * Lazily fetch a node's children the first time it is opened. Resolves to the\n * child nodes (which may themselves be lazy). A rejection is surfaced to\n * `renderRow` via `ctx.error` and is not retried until the node is collapsed\n * and reopened. Required for any node `hasMoreChildren` returns true for.\n */\n loadChildren?: (node: T) => Promise<T[]>;\n /**\n * Marks a node as a **secondary child** of its parent. Secondary\n * children keep the full tree structure (they render, they can be\n * opened manually) but opt out of the bulk behaviours a caller\n * typically wants when they click the toolbar:\n *\n * - Tree-wide filter: their text is skipped during match detection\n * so typing in the search box never surfaces a row because one\n * of its secondary children happened to match.\n * - Expand all: secondary nodes stay at their default-open state\n * instead of being forced open, preventing 28k field rows from\n * flooding the viewport when an operator hits the button on a\n * schema with hundreds of tables.\n *\n * Default: every node is primary (returns false).\n */\n isSecondary?: (node: T) => boolean;\n};\n\nexport function TreeNode<T>({\n node,\n depth = 0,\n expandAll = null,\n forcedOpenKeys = null,\n selected = null,\n defaultOpen,\n getChildren,\n getKey,\n getAriaLabel,\n onSelect,\n renderRow,\n rowClass,\n indentPx = 16,\n basePaddingPx = 8,\n isSecondary,\n hasMoreChildren,\n loadChildren,\n}: TreeNodeProps<T>) {\n // Lazily-fetched children take precedence over the synchronous ones once a\n // load has resolved; until then `loadedChildren` is null and we fall back to\n // getChildren. A node can be \"lazy\" (hasMoreChildren) with no sync children.\n const [loadedChildren, setLoadedChildren] = useState<T[] | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<unknown>(null);\n const syncChildren = getChildren(node);\n const children = loadedChildren ?? syncChildren;\n const hasChildren = (children?.length ?? 0) > 0;\n const lazyUnloaded = (hasMoreChildren?.(node) ?? false) && loadedChildren === null;\n // The chevron shows when there is something to reveal: either real children\n // are present, or the node is lazy and has not been loaded yet.\n const expandable = hasChildren || lazyUnloaded;\n // A node opts out of bulk expand-all in two distinct cases:\n //\n // 1. The node itself is secondary (its edge from the parent is\n // secondary) — rare at the root, but the rule is symmetric.\n // 2. All of the node's children are secondary — the common case.\n // This is what keeps an \"Expand all\" on a schema tree from\n // flooding the viewport with every table's field rows: the\n // table opens to nothing structural worth seeing in bulk, so\n // we leave it closed until the operator clicks it manually.\n //\n // In both cases the manual toggle still works, and filter matches\n // still force the row open via forcedOpenKeys, so users never\n // lose access — they just don't get auto-flooded.\n const secondaryNode = isSecondary?.(node) ?? false;\n const childrenAllSecondary =\n hasChildren && isSecondary != null && children!.every((c) => isSecondary(c));\n const skipExpandAll = secondaryNode || childrenAllSecondary;\n // A non-null `expandAll` is a live bulk state, not just a one-off change\n // signal: a node mounted *while* expand-all is active (because an ancestor\n // just opened) inherits it as its initial open state, so opening a parent\n // cascades all the way down — expand/collapse-all are recursive. The\n // skipExpandAll guard keeps secondary subtrees from auto-flooding. When\n // expandAll is null (before any toolbar click) we fall back to defaultOpen.\n const initialOpen =\n expandAll !== null && !skipExpandAll\n ? expandAll\n : defaultOpen\n ? defaultOpen(node, depth)\n : depth < 1;\n const [open, setOpen] = useState(initialOpen);\n const prevExpandAll = useRef(expandAll);\n const isSelected = selected === node;\n const key = getKey(node);\n const isForcedOpen = forcedOpenKeys?.has(key) ?? false;\n const isOpen = isForcedOpen || open;\n\n useEffect(() => {\n if (expandAll !== null && expandAll !== prevExpandAll.current && !skipExpandAll) {\n setOpen(expandAll);\n }\n prevExpandAll.current = expandAll;\n }, [expandAll, skipExpandAll]);\n\n // Guards a lazy fetch so a node loads its children at most once per mount and\n // a resolution arriving after the node was reused (key changed) is ignored.\n const loadRequested = useRef(false);\n const nodeKey = getKey(node);\n const loadKeyRef = useRef(nodeKey);\n\n function loadLazyChildren() {\n if (!loadChildren || loadRequested.current) return;\n loadRequested.current = true;\n loadKeyRef.current = nodeKey;\n setLoading(true);\n setError(null);\n loadChildren(node)\n .then((kids) => {\n if (loadKeyRef.current !== nodeKey) return;\n setLoadedChildren(kids);\n setLoading(false);\n })\n .catch((err) => {\n if (loadKeyRef.current !== nodeKey) return;\n // Surfaced to renderRow via ctx.error; allow a retry on re-toggle.\n loadRequested.current = false;\n setError(err);\n setLoading(false);\n });\n }\n\n // A lazy node can be open without ever having been clicked — defaultOpen said\n // so, expand-all did, or the filter forced it open to reveal a match. Loading\n // only on the open transition would leave every one of those showing a caret\n // over nothing.\n //\n // A node that already failed is skipped: loadLazyChildren clears its own retry\n // guard on failure so a re-toggle can try again, and re-running here would\n // turn that into an unbounded retry loop instead.\n useEffect(() => {\n if (isOpen && lazyUnloaded && error === null) loadLazyChildren();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen, lazyUnloaded, error]);\n\n function toggle() {\n if (!expandable) return;\n setOpen((o) => {\n const next = !o;\n // Only fetch when transitioning into the open state, so collapsing a\n // not-yet-loaded (e.g. previously-failed) lazy node never triggers a load.\n if (next && lazyUnloaded) loadLazyChildren();\n return next;\n });\n }\n\n const defaultRowBg = isSelected ? \"bg-primary/10 border-l-2 border-primary\" : \"hover:bg-accent\";\n const rowClassName = rowClass ? rowClass(node, isSelected) : defaultRowBg;\n\n return (\n <div\n role=\"treeitem\"\n aria-label={getAriaLabel?.(node)}\n aria-expanded={expandable ? isOpen : undefined}\n aria-selected={isSelected}\n >\n <div\n className={cn(\"flex items-center gap-1.5 py-1 px-2 cursor-pointer text-sm\", rowClassName)}\n style={{ paddingLeft: `${depth * indentPx + basePaddingPx}px` }}\n onClick={(e) => {\n e.stopPropagation();\n onSelect?.(node);\n toggle();\n }}\n >\n {expandable ? (\n <button\n type=\"button\"\n aria-label={isOpen ? \"Collapse\" : \"Expand\"}\n // The caret only toggles expansion — stopPropagation keeps the row's\n // onClick (which selects) from firing, so expanding a node never\n // selects it.\n onClick={(e) => {\n e.stopPropagation();\n toggle();\n }}\n className=\"flex shrink-0 items-center text-muted-foreground\"\n >\n <Icon icon={isOpen ? UiChevronDown : UiChevronRight} className=\"text-xs w-3\" />\n </button>\n ) : (\n <span className=\"w-3 shrink-0\" aria-hidden />\n )}\n {renderRow({\n node,\n depth,\n open: isOpen,\n selected: isSelected,\n hasChildren,\n toggle,\n loading,\n error,\n })}\n </div>\n {isOpen && hasChildren && (\n <div role=\"group\">\n {children!.map((child) => (\n <TreeNode\n key={getKey(child)}\n node={child}\n depth={depth + 1}\n expandAll={expandAll}\n forcedOpenKeys={forcedOpenKeys}\n selected={selected}\n getChildren={getChildren}\n getKey={getKey}\n renderRow={renderRow}\n indentPx={indentPx}\n basePaddingPx={basePaddingPx}\n {...(defaultOpen ? { defaultOpen } : {})}\n {...(getAriaLabel ? { getAriaLabel } : {})}\n {...(onSelect ? { onSelect } : {})}\n {...(rowClass ? { rowClass } : {})}\n {...(isSecondary ? { isSecondary } : {})}\n {...(hasMoreChildren ? { hasMoreChildren } : {})}\n {...(loadChildren ? { loadChildren } : {})}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -67,6 +67,24 @@ function serializeMultiFilterValue(value) {
67
67
  function splitCommaValues(value) {
68
68
  return value.split(",").map((item) => item.trim()).filter(Boolean);
69
69
  }
70
+ function parseBoundsValue(raw) {
71
+ const bounds = {};
72
+ for (const token of raw.split(",")) {
73
+ const trimmed = token.trim();
74
+ if (trimmed.startsWith(">")) {
75
+ bounds.min = trimmed.replace(/^>=?/, "");
76
+ } else if (trimmed.startsWith("<")) {
77
+ bounds.max = trimmed.replace(/^<=?/, "");
78
+ }
79
+ }
80
+ return bounds;
81
+ }
82
+ function serializeBoundsValue(value) {
83
+ const tokens = [];
84
+ if (value.min) tokens.push(`>=${value.min}`);
85
+ if (value.max) tokens.push(`<=${value.max}`);
86
+ return tokens.join(",");
87
+ }
70
88
  function updateFilterSelection(selection, key, serialized) {
71
89
  const next = { ...selection };
72
90
  if (serialized) {
@@ -76,7 +94,9 @@ function updateFilterSelection(selection, key, serialized) {
76
94
  }
77
95
  return next;
78
96
  }
97
+ exports.parseBoundsValue = parseBoundsValue;
79
98
  exports.parseMultiFilterValue = parseMultiFilterValue;
99
+ exports.serializeBoundsValue = serializeBoundsValue;
80
100
  exports.serializeMultiFilterValue = serializeMultiFilterValue;
81
101
  exports.splitCommaValues = splitCommaValues;
82
102
  exports.updateFilterSelection = updateFilterSelection;
@@ -1 +1 @@
1
- {"version":3,"file":"data-table-filter-values.cjs","sources":["../../src/data/data-table-filter-values.ts"],"sourcesContent":["import type { FilterBarMultiFilterMode } from \"../components/filter-bar-field-utils\";\n\n/**\n * A filter selection as one flat, URL-safe record: filter key → comma-joined\n * values, each optionally `!`-prefixed to exclude. It is the one encoding the\n * profile catalog (which syncs it to the URL) and the ad-hoc query browser both\n * speak, so a selection means the same thing wherever it is read.\n */\nexport type DataTableFilterSelection = Record<string, string>;\n\n// The serialized multi-filter value is a wire contract, not internal state: it\n// is packed into a query parameter and parsed server-side by clicky's\n// `entity.MultiFilter` (collections.MatchItems semantics — `,` separates\n// patterns, a leading `!` negates). That grammar has no escape sequence, so a\n// value that itself starts with `!` or contains `,` cannot be expressed on the\n// wire at all. Backslash escapes below therefore only ever apply to values the\n// server could never represent, leaving every representable value byte\n// identical, while making the local parse/serialize pair lossless so an\n// *included* \"!failed\" is not read back as an *exclusion* of \"failed\" on the\n// next render.\n//\n// WORKAROUND(no-server-escape-syntax): the escapes are understood by this\n// module only; a backslash sent to the server is matched literally.\n// Correct fix: teach entity.MultiFilter / collections.MatchItems an escape\n// sequence, then drop this note.\n// Ref: PR review, discussed with user 2026-08-05\n//\n// Grammar: `\\\\`, `\\!`, `\\,` and `\\<whitespace>` decode to the bare character; a\n// backslash before anything else is literal. Unescaped whitespace around an\n// item is trimmed (hand-edited URLs), unescaped `,` separates items, and an\n// unescaped leading `!` marks an exclusion. Empty keys are not representable\n// and are dropped.\ntype MultiFilterChar = { char: string; escaped: boolean };\n\nfunction isMultiFilterEscapable(char: string) {\n return char === \"\\\\\" || char === \"!\" || char === \",\" || /\\s/.test(char);\n}\n\nfunction isUnescapedSpace(entry: MultiFilterChar) {\n return !entry.escaped && /\\s/.test(entry.char);\n}\n\nfunction splitMultiFilterItems(value: string): MultiFilterChar[][] {\n const items: MultiFilterChar[][] = [[]];\n for (let index = 0; index < value.length; index++) {\n const char = value[index]!;\n const next = value[index + 1];\n if (char === \"\\\\\" && next !== undefined && isMultiFilterEscapable(next)) {\n items[items.length - 1]!.push({ char: next, escaped: true });\n index++;\n } else if (char === \",\") {\n items.push([]);\n } else {\n items[items.length - 1]!.push({ char, escaped: false });\n }\n }\n return items.map((item) => {\n let start = 0;\n let end = item.length;\n while (start < end && isUnescapedSpace(item[start]!)) start++;\n while (end > start && isUnescapedSpace(item[end - 1]!)) end--;\n return item.slice(start, end);\n });\n}\n\nexport function parseMultiFilterValue(value: string): Record<string, FilterBarMultiFilterMode> {\n const parsed: Record<string, FilterBarMultiFilterMode> = {};\n for (const item of splitMultiFilterItems(value)) {\n if (item.length === 0) continue;\n const excluded = item.length > 1 && item[0]!.char === \"!\" && !item[0]!.escaped;\n const key = (excluded ? item.slice(1) : item).map((entry) => entry.char).join(\"\");\n if (key) parsed[key] = excluded ? \"exclude\" : \"include\";\n }\n return parsed;\n}\n\nfunction escapeMultiFilterKey(key: string): string {\n let escaped = \"\";\n for (let index = 0; index < key.length; index++) {\n const char = key[index]!;\n const isBoundary = index === 0 || index === key.length - 1;\n if (char === \",\") {\n escaped += \"\\\\,\";\n } else if (char === \"\\\\\" && isMultiFilterEscapable(key[index + 1] ?? \"\")) {\n escaped += \"\\\\\\\\\";\n } else if (isBoundary && /\\s/.test(char)) {\n escaped += `\\\\${char}`;\n } else {\n escaped += char;\n }\n }\n return escaped;\n}\n\nexport function serializeMultiFilterValue(value: Record<string, FilterBarMultiFilterMode>): string {\n return Object.entries(value)\n .flatMap(([key, mode]) => {\n if (!key) return [];\n const escaped = escapeMultiFilterKey(key);\n if (mode === \"include\") return [key.startsWith(\"!\") ? `\\\\${escaped}` : escaped];\n if (mode === \"exclude\") return [`!${escaped}`];\n return [];\n })\n .join(\",\");\n}\n\nexport function splitCommaValues(value: string): string[] {\n return value\n .split(\",\")\n .map((item) => item.trim())\n .filter(Boolean);\n}\n\n/**\n * Writes a serialized value into a selection, dropping the key when it is\n * empty. An absent key and a key holding \"\" would send different query strings\n * for the same \"nothing selected\", so only one of them is ever built.\n */\nexport function updateFilterSelection(\n selection: DataTableFilterSelection,\n key: string,\n serialized: string,\n): DataTableFilterSelection {\n const next = { ...selection };\n if (serialized) {\n next[key] = serialized;\n } else {\n delete next[key];\n }\n return next;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"data-table-filter-values.cjs","sources":["../../src/data/data-table-filter-values.ts"],"sourcesContent":["import type { FilterBarMultiFilterMode } from \"../components/filter-bar-field-utils\";\n\n/**\n * A filter selection as one flat, URL-safe record: filter key → comma-joined\n * values, each optionally `!`-prefixed to exclude. It is the one encoding the\n * profile catalog (which syncs it to the URL) and the ad-hoc query browser both\n * speak, so a selection means the same thing wherever it is read.\n */\nexport type DataTableFilterSelection = Record<string, string>;\n\n// The serialized multi-filter value is a wire contract, not internal state: it\n// is packed into a query parameter and parsed server-side by clicky's\n// `entity.MultiFilter` (collections.MatchItems semantics — `,` separates\n// patterns, a leading `!` negates). That grammar has no escape sequence, so a\n// value that itself starts with `!` or contains `,` cannot be expressed on the\n// wire at all. Backslash escapes below therefore only ever apply to values the\n// server could never represent, leaving every representable value byte\n// identical, while making the local parse/serialize pair lossless so an\n// *included* \"!failed\" is not read back as an *exclusion* of \"failed\" on the\n// next render.\n//\n// WORKAROUND(no-server-escape-syntax): the escapes are understood by this\n// module only; a backslash sent to the server is matched literally.\n// Correct fix: teach entity.MultiFilter / collections.MatchItems an escape\n// sequence, then drop this note.\n// Ref: PR review, discussed with user 2026-08-05\n//\n// Grammar: `\\\\`, `\\!`, `\\,` and `\\<whitespace>` decode to the bare character; a\n// backslash before anything else is literal. Unescaped whitespace around an\n// item is trimmed (hand-edited URLs), unescaped `,` separates items, and an\n// unescaped leading `!` marks an exclusion. Empty keys are not representable\n// and are dropped.\ntype MultiFilterChar = { char: string; escaped: boolean };\n\nfunction isMultiFilterEscapable(char: string) {\n return char === \"\\\\\" || char === \"!\" || char === \",\" || /\\s/.test(char);\n}\n\nfunction isUnescapedSpace(entry: MultiFilterChar) {\n return !entry.escaped && /\\s/.test(entry.char);\n}\n\nfunction splitMultiFilterItems(value: string): MultiFilterChar[][] {\n const items: MultiFilterChar[][] = [[]];\n for (let index = 0; index < value.length; index++) {\n const char = value[index]!;\n const next = value[index + 1];\n if (char === \"\\\\\" && next !== undefined && isMultiFilterEscapable(next)) {\n items[items.length - 1]!.push({ char: next, escaped: true });\n index++;\n } else if (char === \",\") {\n items.push([]);\n } else {\n items[items.length - 1]!.push({ char, escaped: false });\n }\n }\n return items.map((item) => {\n let start = 0;\n let end = item.length;\n while (start < end && isUnescapedSpace(item[start]!)) start++;\n while (end > start && isUnescapedSpace(item[end - 1]!)) end--;\n return item.slice(start, end);\n });\n}\n\nexport function parseMultiFilterValue(value: string): Record<string, FilterBarMultiFilterMode> {\n const parsed: Record<string, FilterBarMultiFilterMode> = {};\n for (const item of splitMultiFilterItems(value)) {\n if (item.length === 0) continue;\n const excluded = item.length > 1 && item[0]!.char === \"!\" && !item[0]!.escaped;\n const key = (excluded ? item.slice(1) : item).map((entry) => entry.char).join(\"\");\n if (key) parsed[key] = excluded ? \"exclude\" : \"include\";\n }\n return parsed;\n}\n\nfunction escapeMultiFilterKey(key: string): string {\n let escaped = \"\";\n for (let index = 0; index < key.length; index++) {\n const char = key[index]!;\n const isBoundary = index === 0 || index === key.length - 1;\n if (char === \",\") {\n escaped += \"\\\\,\";\n } else if (char === \"\\\\\" && isMultiFilterEscapable(key[index + 1] ?? \"\")) {\n escaped += \"\\\\\\\\\";\n } else if (isBoundary && /\\s/.test(char)) {\n escaped += `\\\\${char}`;\n } else {\n escaped += char;\n }\n }\n return escaped;\n}\n\nexport function serializeMultiFilterValue(value: Record<string, FilterBarMultiFilterMode>): string {\n return Object.entries(value)\n .flatMap(([key, mode]) => {\n if (!key) return [];\n const escaped = escapeMultiFilterKey(key);\n if (mode === \"include\") return [key.startsWith(\"!\") ? `\\\\${escaped}` : escaped];\n if (mode === \"exclude\") return [`!${escaped}`];\n return [];\n })\n .join(\",\");\n}\n\nexport function splitCommaValues(value: string): string[] {\n return value\n .split(\",\")\n .map((item) => item.trim())\n .filter(Boolean);\n}\n\n/**\n * A bounded selection: both edges under one key, each token carrying its own\n * comparison operator. It is the other half of the selection grammar, and the\n * one a range and a time bound share.\n */\nexport type FilterBoundsValue = {\n min?: string;\n max?: string;\n};\n\n/**\n * Reads a bounded selection. The bar's controls are inclusive on both edges, so\n * that is what they write back — but a bound typed by hand or arriving in a URL\n * keeps whatever operator it came with.\n */\nexport function parseBoundsValue(raw: string): FilterBoundsValue {\n const bounds: FilterBoundsValue = {};\n for (const token of raw.split(\",\")) {\n const trimmed = token.trim();\n if (trimmed.startsWith(\">\")) {\n bounds.min = trimmed.replace(/^>=?/, \"\");\n } else if (trimmed.startsWith(\"<\")) {\n bounds.max = trimmed.replace(/^<=?/, \"\");\n }\n }\n return bounds;\n}\n\nexport function serializeBoundsValue(value: FilterBoundsValue): string {\n const tokens: string[] = [];\n if (value.min) tokens.push(`>=${value.min}`);\n if (value.max) tokens.push(`<=${value.max}`);\n return tokens.join(\",\");\n}\n\n/**\n * Writes a serialized value into a selection, dropping the key when it is\n * empty. An absent key and a key holding \"\" would send different query strings\n * for the same \"nothing selected\", so only one of them is ever built.\n */\nexport function updateFilterSelection(\n selection: DataTableFilterSelection,\n key: string,\n serialized: string,\n): DataTableFilterSelection {\n const next = { ...selection };\n if (serialized) {\n next[key] = serialized;\n } else {\n delete next[key];\n }\n return next;\n}\n"],"names":[],"mappings":"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"}
@@ -9,6 +9,22 @@ export type DataTableFilterSelection = Record<string, string>;
9
9
  export declare function parseMultiFilterValue(value: string): Record<string, FilterBarMultiFilterMode>;
10
10
  export declare function serializeMultiFilterValue(value: Record<string, FilterBarMultiFilterMode>): string;
11
11
  export declare function splitCommaValues(value: string): string[];
12
+ /**
13
+ * A bounded selection: both edges under one key, each token carrying its own
14
+ * comparison operator. It is the other half of the selection grammar, and the
15
+ * one a range and a time bound share.
16
+ */
17
+ export type FilterBoundsValue = {
18
+ min?: string;
19
+ max?: string;
20
+ };
21
+ /**
22
+ * Reads a bounded selection. The bar's controls are inclusive on both edges, so
23
+ * that is what they write back — but a bound typed by hand or arriving in a URL
24
+ * keeps whatever operator it came with.
25
+ */
26
+ export declare function parseBoundsValue(raw: string): FilterBoundsValue;
27
+ export declare function serializeBoundsValue(value: FilterBoundsValue): string;
12
28
  /**
13
29
  * Writes a serialized value into a selection, dropping the key when it is
14
30
  * empty. An absent key and a key holding "" would send different query strings
@@ -1 +1 @@
1
- {"version":3,"file":"data-table-filter-values.d.ts","sourceRoot":"","sources":["../../src/data/data-table-filter-values.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAC;AAErF;;;;;GAKG;AACH,MAAM,MAAM,wBAAwB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAyD9D,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAS7F;AAoBD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,GAAG,MAAM,CAUjG;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAKxD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,wBAAwB,EACnC,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GACjB,wBAAwB,CAQ1B"}
1
+ {"version":3,"file":"data-table-filter-values.d.ts","sourceRoot":"","sources":["../../src/data/data-table-filter-values.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAC;AAErF;;;;;GAKG;AACH,MAAM,MAAM,wBAAwB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAyD9D,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAS7F;AAoBD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,GAAG,MAAM,CAUjG;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAKxD;AAED;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,CAW/D;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAKrE;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,wBAAwB,EACnC,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,GACjB,wBAAwB,CAQ1B"}
@@ -65,6 +65,24 @@ function serializeMultiFilterValue(value) {
65
65
  function splitCommaValues(value) {
66
66
  return value.split(",").map((item) => item.trim()).filter(Boolean);
67
67
  }
68
+ function parseBoundsValue(raw) {
69
+ const bounds = {};
70
+ for (const token of raw.split(",")) {
71
+ const trimmed = token.trim();
72
+ if (trimmed.startsWith(">")) {
73
+ bounds.min = trimmed.replace(/^>=?/, "");
74
+ } else if (trimmed.startsWith("<")) {
75
+ bounds.max = trimmed.replace(/^<=?/, "");
76
+ }
77
+ }
78
+ return bounds;
79
+ }
80
+ function serializeBoundsValue(value) {
81
+ const tokens = [];
82
+ if (value.min) tokens.push(`>=${value.min}`);
83
+ if (value.max) tokens.push(`<=${value.max}`);
84
+ return tokens.join(",");
85
+ }
68
86
  function updateFilterSelection(selection, key, serialized) {
69
87
  const next = { ...selection };
70
88
  if (serialized) {
@@ -75,7 +93,9 @@ function updateFilterSelection(selection, key, serialized) {
75
93
  return next;
76
94
  }
77
95
  export {
96
+ parseBoundsValue,
78
97
  parseMultiFilterValue,
98
+ serializeBoundsValue,
79
99
  serializeMultiFilterValue,
80
100
  splitCommaValues,
81
101
  updateFilterSelection
@@ -1 +1 @@
1
- {"version":3,"file":"data-table-filter-values.js","sources":["../../src/data/data-table-filter-values.ts"],"sourcesContent":["import type { FilterBarMultiFilterMode } from \"../components/filter-bar-field-utils\";\n\n/**\n * A filter selection as one flat, URL-safe record: filter key → comma-joined\n * values, each optionally `!`-prefixed to exclude. It is the one encoding the\n * profile catalog (which syncs it to the URL) and the ad-hoc query browser both\n * speak, so a selection means the same thing wherever it is read.\n */\nexport type DataTableFilterSelection = Record<string, string>;\n\n// The serialized multi-filter value is a wire contract, not internal state: it\n// is packed into a query parameter and parsed server-side by clicky's\n// `entity.MultiFilter` (collections.MatchItems semantics — `,` separates\n// patterns, a leading `!` negates). That grammar has no escape sequence, so a\n// value that itself starts with `!` or contains `,` cannot be expressed on the\n// wire at all. Backslash escapes below therefore only ever apply to values the\n// server could never represent, leaving every representable value byte\n// identical, while making the local parse/serialize pair lossless so an\n// *included* \"!failed\" is not read back as an *exclusion* of \"failed\" on the\n// next render.\n//\n// WORKAROUND(no-server-escape-syntax): the escapes are understood by this\n// module only; a backslash sent to the server is matched literally.\n// Correct fix: teach entity.MultiFilter / collections.MatchItems an escape\n// sequence, then drop this note.\n// Ref: PR review, discussed with user 2026-08-05\n//\n// Grammar: `\\\\`, `\\!`, `\\,` and `\\<whitespace>` decode to the bare character; a\n// backslash before anything else is literal. Unescaped whitespace around an\n// item is trimmed (hand-edited URLs), unescaped `,` separates items, and an\n// unescaped leading `!` marks an exclusion. Empty keys are not representable\n// and are dropped.\ntype MultiFilterChar = { char: string; escaped: boolean };\n\nfunction isMultiFilterEscapable(char: string) {\n return char === \"\\\\\" || char === \"!\" || char === \",\" || /\\s/.test(char);\n}\n\nfunction isUnescapedSpace(entry: MultiFilterChar) {\n return !entry.escaped && /\\s/.test(entry.char);\n}\n\nfunction splitMultiFilterItems(value: string): MultiFilterChar[][] {\n const items: MultiFilterChar[][] = [[]];\n for (let index = 0; index < value.length; index++) {\n const char = value[index]!;\n const next = value[index + 1];\n if (char === \"\\\\\" && next !== undefined && isMultiFilterEscapable(next)) {\n items[items.length - 1]!.push({ char: next, escaped: true });\n index++;\n } else if (char === \",\") {\n items.push([]);\n } else {\n items[items.length - 1]!.push({ char, escaped: false });\n }\n }\n return items.map((item) => {\n let start = 0;\n let end = item.length;\n while (start < end && isUnescapedSpace(item[start]!)) start++;\n while (end > start && isUnescapedSpace(item[end - 1]!)) end--;\n return item.slice(start, end);\n });\n}\n\nexport function parseMultiFilterValue(value: string): Record<string, FilterBarMultiFilterMode> {\n const parsed: Record<string, FilterBarMultiFilterMode> = {};\n for (const item of splitMultiFilterItems(value)) {\n if (item.length === 0) continue;\n const excluded = item.length > 1 && item[0]!.char === \"!\" && !item[0]!.escaped;\n const key = (excluded ? item.slice(1) : item).map((entry) => entry.char).join(\"\");\n if (key) parsed[key] = excluded ? \"exclude\" : \"include\";\n }\n return parsed;\n}\n\nfunction escapeMultiFilterKey(key: string): string {\n let escaped = \"\";\n for (let index = 0; index < key.length; index++) {\n const char = key[index]!;\n const isBoundary = index === 0 || index === key.length - 1;\n if (char === \",\") {\n escaped += \"\\\\,\";\n } else if (char === \"\\\\\" && isMultiFilterEscapable(key[index + 1] ?? \"\")) {\n escaped += \"\\\\\\\\\";\n } else if (isBoundary && /\\s/.test(char)) {\n escaped += `\\\\${char}`;\n } else {\n escaped += char;\n }\n }\n return escaped;\n}\n\nexport function serializeMultiFilterValue(value: Record<string, FilterBarMultiFilterMode>): string {\n return Object.entries(value)\n .flatMap(([key, mode]) => {\n if (!key) return [];\n const escaped = escapeMultiFilterKey(key);\n if (mode === \"include\") return [key.startsWith(\"!\") ? `\\\\${escaped}` : escaped];\n if (mode === \"exclude\") return [`!${escaped}`];\n return [];\n })\n .join(\",\");\n}\n\nexport function splitCommaValues(value: string): string[] {\n return value\n .split(\",\")\n .map((item) => item.trim())\n .filter(Boolean);\n}\n\n/**\n * Writes a serialized value into a selection, dropping the key when it is\n * empty. An absent key and a key holding \"\" would send different query strings\n * for the same \"nothing selected\", so only one of them is ever built.\n */\nexport function updateFilterSelection(\n selection: DataTableFilterSelection,\n key: string,\n serialized: string,\n): DataTableFilterSelection {\n const next = { ...selection };\n if (serialized) {\n next[key] = serialized;\n } else {\n delete next[key];\n }\n return next;\n}\n"],"names":[],"mappings":"AAkCA,SAAS,uBAAuB,MAAc;AAC5C,SAAO,SAAS,QAAQ,SAAS,OAAO,SAAS,OAAO,KAAK,KAAK,IAAI;AACxE;AAEA,SAAS,iBAAiB,OAAwB;AAChD,SAAO,CAAC,MAAM,WAAW,KAAK,KAAK,MAAM,IAAI;AAC/C;AAEA,SAAS,sBAAsB,OAAoC;AACjE,QAAM,QAA6B,CAAC,EAAE;AACtC,WAAS,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS;AACjD,UAAM,OAAO,MAAM,KAAK;AACxB,UAAM,OAAO,MAAM,QAAQ,CAAC;AAC5B,QAAI,SAAS,QAAQ,SAAS,UAAa,uBAAuB,IAAI,GAAG;AACvE,YAAM,MAAM,SAAS,CAAC,EAAG,KAAK,EAAE,MAAM,MAAM,SAAS,MAAM;AAC3D;AAAA,IACF,WAAW,SAAS,KAAK;AACvB,YAAM,KAAK,EAAE;AAAA,IACf,OAAO;AACL,YAAM,MAAM,SAAS,CAAC,EAAG,KAAK,EAAE,MAAM,SAAS,OAAO;AAAA,IACxD;AAAA,EACF;AACA,SAAO,MAAM,IAAI,CAAC,SAAS;AACzB,QAAI,QAAQ;AACZ,QAAI,MAAM,KAAK;AACf,WAAO,QAAQ,OAAO,iBAAiB,KAAK,KAAK,CAAE,EAAG;AACtD,WAAO,MAAM,SAAS,iBAAiB,KAAK,MAAM,CAAC,CAAE,EAAG;AACxD,WAAO,KAAK,MAAM,OAAO,GAAG;AAAA,EAC9B,CAAC;AACH;AAEO,SAAS,sBAAsB,OAAyD;AAC7F,QAAM,SAAmD,CAAA;AACzD,aAAW,QAAQ,sBAAsB,KAAK,GAAG;AAC/C,QAAI,KAAK,WAAW,EAAG;AACvB,UAAM,WAAW,KAAK,SAAS,KAAK,KAAK,CAAC,EAAG,SAAS,OAAO,CAAC,KAAK,CAAC,EAAG;AACvE,UAAM,OAAO,WAAW,KAAK,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC,UAAU,MAAM,IAAI,EAAE,KAAK,EAAE;AAChF,QAAI,IAAK,QAAO,GAAG,IAAI,WAAW,YAAY;AAAA,EAChD;AACA,SAAO;AACT;AAEA,SAAS,qBAAqB,KAAqB;AACjD,MAAI,UAAU;AACd,WAAS,QAAQ,GAAG,QAAQ,IAAI,QAAQ,SAAS;AAC/C,UAAM,OAAO,IAAI,KAAK;AACtB,UAAM,aAAa,UAAU,KAAK,UAAU,IAAI,SAAS;AACzD,QAAI,SAAS,KAAK;AAChB,iBAAW;AAAA,IACb,WAAW,SAAS,QAAQ,uBAAuB,IAAI,QAAQ,CAAC,KAAK,EAAE,GAAG;AACxE,iBAAW;AAAA,IACb,WAAW,cAAc,KAAK,KAAK,IAAI,GAAG;AACxC,iBAAW,KAAK,IAAI;AAAA,IACtB,OAAO;AACL,iBAAW;AAAA,IACb;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,0BAA0B,OAAyD;AACjG,SAAO,OAAO,QAAQ,KAAK,EACxB,QAAQ,CAAC,CAAC,KAAK,IAAI,MAAM;AACxB,QAAI,CAAC,IAAK,QAAO,CAAA;AACjB,UAAM,UAAU,qBAAqB,GAAG;AACxC,QAAI,SAAS,UAAW,QAAO,CAAC,IAAI,WAAW,GAAG,IAAI,KAAK,OAAO,KAAK,OAAO;AAC9E,QAAI,SAAS,UAAW,QAAO,CAAC,IAAI,OAAO,EAAE;AAC7C,WAAO,CAAA;AAAA,EACT,CAAC,EACA,KAAK,GAAG;AACb;AAEO,SAAS,iBAAiB,OAAyB;AACxD,SAAO,MACJ,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,KAAK,KAAA,CAAM,EACzB,OAAO,OAAO;AACnB;AAOO,SAAS,sBACd,WACA,KACA,YAC0B;AAC1B,QAAM,OAAO,EAAE,GAAG,UAAA;AAClB,MAAI,YAAY;AACd,SAAK,GAAG,IAAI;AAAA,EACd,OAAO;AACL,WAAO,KAAK,GAAG;AAAA,EACjB;AACA,SAAO;AACT;"}
1
+ {"version":3,"file":"data-table-filter-values.js","sources":["../../src/data/data-table-filter-values.ts"],"sourcesContent":["import type { FilterBarMultiFilterMode } from \"../components/filter-bar-field-utils\";\n\n/**\n * A filter selection as one flat, URL-safe record: filter key → comma-joined\n * values, each optionally `!`-prefixed to exclude. It is the one encoding the\n * profile catalog (which syncs it to the URL) and the ad-hoc query browser both\n * speak, so a selection means the same thing wherever it is read.\n */\nexport type DataTableFilterSelection = Record<string, string>;\n\n// The serialized multi-filter value is a wire contract, not internal state: it\n// is packed into a query parameter and parsed server-side by clicky's\n// `entity.MultiFilter` (collections.MatchItems semantics — `,` separates\n// patterns, a leading `!` negates). That grammar has no escape sequence, so a\n// value that itself starts with `!` or contains `,` cannot be expressed on the\n// wire at all. Backslash escapes below therefore only ever apply to values the\n// server could never represent, leaving every representable value byte\n// identical, while making the local parse/serialize pair lossless so an\n// *included* \"!failed\" is not read back as an *exclusion* of \"failed\" on the\n// next render.\n//\n// WORKAROUND(no-server-escape-syntax): the escapes are understood by this\n// module only; a backslash sent to the server is matched literally.\n// Correct fix: teach entity.MultiFilter / collections.MatchItems an escape\n// sequence, then drop this note.\n// Ref: PR review, discussed with user 2026-08-05\n//\n// Grammar: `\\\\`, `\\!`, `\\,` and `\\<whitespace>` decode to the bare character; a\n// backslash before anything else is literal. Unescaped whitespace around an\n// item is trimmed (hand-edited URLs), unescaped `,` separates items, and an\n// unescaped leading `!` marks an exclusion. Empty keys are not representable\n// and are dropped.\ntype MultiFilterChar = { char: string; escaped: boolean };\n\nfunction isMultiFilterEscapable(char: string) {\n return char === \"\\\\\" || char === \"!\" || char === \",\" || /\\s/.test(char);\n}\n\nfunction isUnescapedSpace(entry: MultiFilterChar) {\n return !entry.escaped && /\\s/.test(entry.char);\n}\n\nfunction splitMultiFilterItems(value: string): MultiFilterChar[][] {\n const items: MultiFilterChar[][] = [[]];\n for (let index = 0; index < value.length; index++) {\n const char = value[index]!;\n const next = value[index + 1];\n if (char === \"\\\\\" && next !== undefined && isMultiFilterEscapable(next)) {\n items[items.length - 1]!.push({ char: next, escaped: true });\n index++;\n } else if (char === \",\") {\n items.push([]);\n } else {\n items[items.length - 1]!.push({ char, escaped: false });\n }\n }\n return items.map((item) => {\n let start = 0;\n let end = item.length;\n while (start < end && isUnescapedSpace(item[start]!)) start++;\n while (end > start && isUnescapedSpace(item[end - 1]!)) end--;\n return item.slice(start, end);\n });\n}\n\nexport function parseMultiFilterValue(value: string): Record<string, FilterBarMultiFilterMode> {\n const parsed: Record<string, FilterBarMultiFilterMode> = {};\n for (const item of splitMultiFilterItems(value)) {\n if (item.length === 0) continue;\n const excluded = item.length > 1 && item[0]!.char === \"!\" && !item[0]!.escaped;\n const key = (excluded ? item.slice(1) : item).map((entry) => entry.char).join(\"\");\n if (key) parsed[key] = excluded ? \"exclude\" : \"include\";\n }\n return parsed;\n}\n\nfunction escapeMultiFilterKey(key: string): string {\n let escaped = \"\";\n for (let index = 0; index < key.length; index++) {\n const char = key[index]!;\n const isBoundary = index === 0 || index === key.length - 1;\n if (char === \",\") {\n escaped += \"\\\\,\";\n } else if (char === \"\\\\\" && isMultiFilterEscapable(key[index + 1] ?? \"\")) {\n escaped += \"\\\\\\\\\";\n } else if (isBoundary && /\\s/.test(char)) {\n escaped += `\\\\${char}`;\n } else {\n escaped += char;\n }\n }\n return escaped;\n}\n\nexport function serializeMultiFilterValue(value: Record<string, FilterBarMultiFilterMode>): string {\n return Object.entries(value)\n .flatMap(([key, mode]) => {\n if (!key) return [];\n const escaped = escapeMultiFilterKey(key);\n if (mode === \"include\") return [key.startsWith(\"!\") ? `\\\\${escaped}` : escaped];\n if (mode === \"exclude\") return [`!${escaped}`];\n return [];\n })\n .join(\",\");\n}\n\nexport function splitCommaValues(value: string): string[] {\n return value\n .split(\",\")\n .map((item) => item.trim())\n .filter(Boolean);\n}\n\n/**\n * A bounded selection: both edges under one key, each token carrying its own\n * comparison operator. It is the other half of the selection grammar, and the\n * one a range and a time bound share.\n */\nexport type FilterBoundsValue = {\n min?: string;\n max?: string;\n};\n\n/**\n * Reads a bounded selection. The bar's controls are inclusive on both edges, so\n * that is what they write back — but a bound typed by hand or arriving in a URL\n * keeps whatever operator it came with.\n */\nexport function parseBoundsValue(raw: string): FilterBoundsValue {\n const bounds: FilterBoundsValue = {};\n for (const token of raw.split(\",\")) {\n const trimmed = token.trim();\n if (trimmed.startsWith(\">\")) {\n bounds.min = trimmed.replace(/^>=?/, \"\");\n } else if (trimmed.startsWith(\"<\")) {\n bounds.max = trimmed.replace(/^<=?/, \"\");\n }\n }\n return bounds;\n}\n\nexport function serializeBoundsValue(value: FilterBoundsValue): string {\n const tokens: string[] = [];\n if (value.min) tokens.push(`>=${value.min}`);\n if (value.max) tokens.push(`<=${value.max}`);\n return tokens.join(\",\");\n}\n\n/**\n * Writes a serialized value into a selection, dropping the key when it is\n * empty. An absent key and a key holding \"\" would send different query strings\n * for the same \"nothing selected\", so only one of them is ever built.\n */\nexport function updateFilterSelection(\n selection: DataTableFilterSelection,\n key: string,\n serialized: string,\n): DataTableFilterSelection {\n const next = { ...selection };\n if (serialized) {\n next[key] = serialized;\n } else {\n delete next[key];\n }\n return next;\n}\n"],"names":[],"mappings":"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"}
@@ -33,12 +33,7 @@ function serverFiltersToFilterBar(columns, values, setValues, options = {}) {
33
33
  }
34
34
  claimed.set(filterKey, column.name);
35
35
  const label = column.label ?? dataTableUtils.prettifyKey(column.name);
36
- if (filter.kind === "time") {
37
- if (config.timeRange) {
38
- throw new Error(
39
- `Columns ${claimed.get(filterKey)} and ${column.name} both declare a time range; the filter bar has one`
40
- );
41
- }
36
+ if (filter.kind === "time" && !config.timeRange) {
42
37
  config.timeRange = buildTimeRange(filterKey, filter, values, setValues);
43
38
  continue;
44
39
  }
@@ -62,12 +57,21 @@ function buildFilter(args) {
62
57
  ...filter.disabled !== void 0 ? { disabled: filter.disabled } : {}
63
58
  };
64
59
  switch (filter.kind) {
60
+ case "time":
61
+ return {
62
+ ...shared,
63
+ kind: "date-range",
64
+ ...boundsToRange(dataTableFilterValues.parseBoundsValue(raw)),
65
+ onApply: (from, to) => write(dataTableFilterValues.serializeBoundsValue({ min: from, max: to })),
66
+ ...filter.presets !== void 0 ? { presets: filter.presets } : {},
67
+ timeEnabled: true
68
+ };
65
69
  case "range":
66
70
  return {
67
71
  ...shared,
68
72
  kind: "number",
69
- value: parseBoundsValue(raw),
70
- onChange: (next) => write(serializeBoundsValue(next)),
73
+ value: dataTableFilterValues.parseBoundsValue(raw),
74
+ onChange: (next) => write(dataTableFilterValues.serializeBoundsValue(next)),
71
75
  ...filter.min !== void 0 ? { domainMin: filter.min } : {},
72
76
  ...filter.max !== void 0 ? { domainMax: filter.max } : {},
73
77
  ...filter.step !== void 0 ? { step: filter.step } : {}
@@ -91,7 +95,11 @@ function buildFilter(args) {
91
95
  }
92
96
  }
93
97
  function buildTermsFilter({ filter, options }, shared, raw, write) {
98
+ var _a;
94
99
  const lookupValues = options.lookupValues;
100
+ if (!filter.lookup && (((_a = filter.options) == null ? void 0 : _a.length) ?? 0) === 0) {
101
+ return { ...shared, kind: "text", value: raw, onChange: (next) => write(next) };
102
+ }
95
103
  return {
96
104
  ...shared,
97
105
  kind: "multi",
@@ -115,34 +123,20 @@ function buildTermsFilter({ filter, options }, shared, raw, write) {
115
123
  };
116
124
  }
117
125
  function buildTimeRange(filterKey, filter, values, setValues) {
118
- const bounds = parseBoundsValue(values[filterKey] ?? "");
119
126
  return {
120
- ...bounds.min !== void 0 ? { from: bounds.min } : {},
121
- ...bounds.max !== void 0 ? { to: bounds.max } : {},
127
+ ...boundsToRange(dataTableFilterValues.parseBoundsValue(values[filterKey] ?? "")),
122
128
  onApply: (from, to) => setValues(
123
- (current) => dataTableFilterValues.updateFilterSelection(current, filterKey, serializeBoundsValue({ min: from, max: to }))
129
+ (current) => dataTableFilterValues.updateFilterSelection(current, filterKey, dataTableFilterValues.serializeBoundsValue({ min: from, max: to }))
124
130
  ),
125
131
  ...filter.presets !== void 0 ? { presets: filter.presets } : {},
126
132
  timeEnabled: true
127
133
  };
128
134
  }
129
- function parseBoundsValue(raw) {
130
- const bounds = {};
131
- for (const token of raw.split(",")) {
132
- const trimmed = token.trim();
133
- if (trimmed.startsWith(">")) {
134
- bounds.min = trimmed.replace(/^>=?/, "");
135
- } else if (trimmed.startsWith("<")) {
136
- bounds.max = trimmed.replace(/^<=?/, "");
137
- }
138
- }
139
- return bounds;
140
- }
141
- function serializeBoundsValue(value) {
142
- const tokens = [];
143
- if (value.min) tokens.push(`>=${value.min}`);
144
- if (value.max) tokens.push(`<=${value.max}`);
145
- return tokens.join(",");
135
+ function boundsToRange(bounds) {
136
+ return {
137
+ ...bounds.min !== void 0 ? { from: bounds.min } : {},
138
+ ...bounds.max !== void 0 ? { to: bounds.max } : {}
139
+ };
146
140
  }
147
141
  function toMultiSelectOption(option) {
148
142
  const label = option.label ?? option.value;
@@ -1 +1 @@
1
- {"version":3,"file":"data-table-server-filters.cjs","sources":["../../src/data/data-table-server-filters.ts"],"sourcesContent":["import type { Dispatch, SetStateAction } from \"react\";\nimport type {\n FilterBarFilter,\n FilterBarNumberValue,\n FilterBarRangePreset,\n FilterBarRangeProps,\n} from \"../components/FilterBar\";\nimport type { FilterExtension } from \"../components/filter-bar-utils\";\nimport { applyFilterExtensions } from \"../components/filter-bar-utils\";\nimport type { MultiSelectOption } from \"../components/MultiSelect\";\nimport type { TriState } from \"../components/TriStateToggle\";\nimport type { DataTableColumn, DataTableColumnKind } from \"./DataTable\";\nimport {\n parseMultiFilterValue,\n serializeMultiFilterValue,\n updateFilterSelection,\n type DataTableFilterSelection,\n} from \"./data-table-filter-values\";\nimport { prettifyKey } from \"./data-table-utils\";\n\n/**\n * Which control a filter renders as.\n *\n * Deliberately opaque: \"terms\" is not \"a SQL IN() or an OpenSearch terms\n * query\", it is \"a set of discrete values the user includes or excludes\". The\n * source compiles the selection; nothing about how it does so crosses into the\n * browser.\n */\nexport type DataTableFilterKind = \"terms\" | \"range\" | \"time\" | \"boolean\" | \"text\";\n\nexport type DataTableFilterOption = {\n /** Value written into the selection. */\n value: string;\n /** Display label. Falls back to `value`. */\n label?: string;\n /** How many rows carry this value, shown as a tooltip. */\n count?: number;\n};\n\nexport type DataTableColumnFilter = {\n kind: DataTableFilterKind;\n /** Head of the option set for kind:\"terms\". Empty relies on `lookup`. */\n options?: DataTableFilterOption[];\n /** True when `options` is a capped head of a larger set. */\n truncated?: boolean;\n /** Distinct count behind a truncated head; drives the \"… and N more\" hint. */\n total?: number;\n /** The source can answer a type-ahead for this filter. */\n lookup?: boolean;\n /** Slider domain for kind:\"range\". */\n min?: number;\n max?: number;\n step?: number;\n /** Range presets for kind:\"time\". */\n presets?: FilterBarRangePreset[];\n /** Helper text shown in the filter popover. */\n description?: string;\n disabled?: boolean;\n};\n\n/**\n * A result column as the source describes it: how to render it, and — when the\n * source can narrow on it — which filter parameter it binds to and what control\n * that filter is.\n *\n * `filterKey` need not equal `name`: an analyzed text field filters through an\n * exact-value sibling, and a computed column filters by the alias it was given.\n */\nexport type DataTableServerColumn = {\n /** Field name as the source knows it; also the literal row key. */\n name: string;\n /** Header label. Defaults to a prettified `name`. */\n label?: string;\n /** Backend type string, verbatim (e.g. \"TIMESTAMPTZ\", \"keyword\"). Display only. */\n databaseType?: string;\n /** Cell rendering kind. */\n kind?: DataTableColumnKind;\n /** Filter parameter this column narrows on. Absent means not filterable. */\n filterKey?: string;\n /** The control the filter renders as. Absent means not filterable. */\n filter?: DataTableColumnFilter;\n};\n\n/** Head-set size for a filter value type-ahead. */\nexport const DATA_TABLE_FILTER_LOOKUP_LIMIT = 20;\n\nexport type DataTableFilterLookupRequest = {\n /** Which filter is being searched — the column's `filterKey`. */\n filterKey: string;\n /** What the user typed. Empty asks for the head of the set. */\n search: string;\n /** How many options to return. */\n limit: number;\n};\n\nexport type DataTableFilterLookupResult = {\n options: DataTableFilterOption[];\n};\n\n/**\n * Answers a filter's value type-ahead. Sync or async — a static option source\n * returns an array, a server-backed one a promise.\n */\nexport type DataTableFilterLookup = (\n request: DataTableFilterLookupRequest,\n) => Promise<DataTableFilterLookupResult> | DataTableFilterLookupResult;\n\nexport type ServerFilterBarOptions = {\n /** Answers a terms type-ahead for filters whose `lookup` is set. */\n lookupValues?: DataTableFilterLookup;\n /** Decorators applied to each built filter (icons, relabelling). */\n extensions?: FilterExtension[];\n};\n\nexport type ServerFilterConfig = {\n filters: FilterBarFilter[];\n /** Present when exactly one column declared kind:\"time\". */\n timeRange?: FilterBarRangeProps;\n};\n\n/**\n * Turns the source's column description into DataTable columns.\n *\n * Every column gets a literal `accessor` — a raw result set has empty, dotted\n * and colliding names, none of which survive being read as a path — and\n * `filterable: false`, because a described result is filtered by the source and\n * never by cardinality guessed from one page.\n */\nexport function serverColumnsToDataTableColumns<T extends Record<string, unknown>>(\n columns: DataTableServerColumn[],\n): DataTableColumn<T>[] {\n return columns.map((column, index) => ({\n key: column.name === \"\" ? `column-${index}` : column.name,\n label: column.label ?? prettifyKey(column.name),\n accessor: (row: T) => row[column.name],\n sortable: true,\n filterable: false,\n ...(column.kind !== undefined ? { kind: column.kind } : {}),\n ...(column.filterKey !== undefined ? { filterKey: column.filterKey } : {}),\n }));\n}\n\n/**\n * Builds the FilterBar controls for a described result, already wired to\n * `values`/`setValues`.\n *\n * Pure — it holds no state and fetches nothing; a `lookup` filter closes over\n * the caller's loader. Pass the result as DataTable's `externalFilters`\n * together with `manualFilter`, since the source has already applied it.\n *\n * Throws when a column declares a filter it cannot address: no `filterKey`, a\n * `filterKey` another column already claimed, or a second time range. Each\n * would bind a control to a filter that means something else.\n */\nexport function serverFiltersToFilterBar(\n columns: DataTableServerColumn[],\n values: DataTableFilterSelection,\n setValues: Dispatch<SetStateAction<DataTableFilterSelection>>,\n options: ServerFilterBarOptions = {},\n): ServerFilterConfig {\n const config: ServerFilterConfig = { filters: [] };\n const claimed = new Map<string, string>();\n\n for (const column of columns) {\n const filter = column.filter;\n if (!filter) continue;\n const filterKey = column.filterKey;\n if (!filterKey) {\n throw new Error(`Column ${column.name} declares a filter but no filterKey to send it under`);\n }\n const owner = claimed.get(filterKey);\n if (owner !== undefined) {\n throw new Error(\n `Columns ${owner} and ${column.name} both filter through ${filterKey}; a filter key addresses one column`,\n );\n }\n claimed.set(filterKey, column.name);\n\n const label = column.label ?? prettifyKey(column.name);\n if (filter.kind === \"time\") {\n if (config.timeRange) {\n throw new Error(\n `Columns ${claimed.get(filterKey)} and ${column.name} both declare a time range; the filter bar has one`,\n );\n }\n config.timeRange = buildTimeRange(filterKey, filter, values, setValues);\n continue;\n }\n config.filters.push(\n applyFilterExtensions(\n buildFilter({ column, filterKey, label, filter, values, setValues, options }),\n options.extensions,\n ),\n );\n }\n return config;\n}\n\ntype BuildArgs = {\n column: DataTableServerColumn;\n filterKey: string;\n label: string;\n filter: DataTableColumnFilter;\n values: DataTableFilterSelection;\n setValues: Dispatch<SetStateAction<DataTableFilterSelection>>;\n options: ServerFilterBarOptions;\n};\n\nfunction buildFilter(args: BuildArgs): FilterBarFilter {\n const { filterKey, label, filter, values, setValues } = args;\n const raw = values[filterKey] ?? \"\";\n const write = (serialized: string) =>\n setValues((current) => updateFilterSelection(current, filterKey, serialized));\n const shared = {\n key: filterKey,\n label,\n ...(filter.description !== undefined ? { description: filter.description } : {}),\n ...(filter.disabled !== undefined ? { disabled: filter.disabled } : {}),\n };\n\n switch (filter.kind) {\n case \"range\":\n return {\n ...shared,\n kind: \"number\",\n value: parseBoundsValue(raw),\n onChange: (next: FilterBarNumberValue) => write(serializeBoundsValue(next)),\n ...(filter.min !== undefined ? { domainMin: filter.min } : {}),\n ...(filter.max !== undefined ? { domainMax: filter.max } : {}),\n ...(filter.step !== undefined ? { step: filter.step } : {}),\n };\n case \"boolean\":\n return {\n ...shared,\n kind: \"tristate\",\n value: raw === \"\" ? undefined : raw === \"true\",\n onChange: (next: TriState) => write(next === undefined ? \"\" : String(next)),\n };\n case \"text\":\n return {\n ...shared,\n kind: \"text\",\n value: raw,\n onChange: (next: string) => write(next),\n };\n default:\n return buildTermsFilter(args, shared, raw, write);\n }\n}\n\nfunction buildTermsFilter(\n { filter, options }: BuildArgs,\n shared: { key: string; label: string; description?: string; disabled?: boolean },\n raw: string,\n write: (serialized: string) => void,\n): FilterBarFilter {\n const lookupValues = options.lookupValues;\n return {\n ...shared,\n kind: \"multi\",\n value: parseMultiFilterValue(raw),\n onChange: (next) => write(serializeMultiFilterValue(next)),\n options: (filter.options ?? []).map(toMultiSelectOption),\n ...(filter.truncated !== undefined ? { truncated: filter.truncated } : {}),\n ...(filter.total !== undefined ? { total: filter.total } : {}),\n // The field owns the in-flight flag from the promise this returns, so no\n // `loading` is passed: a second source of truth for it could disagree.\n ...(lookupValues && filter.lookup\n ? {\n onSearch: async (search: string) => {\n const result = await lookupValues({\n filterKey: shared.key,\n search,\n limit: DATA_TABLE_FILTER_LOOKUP_LIMIT,\n });\n return result.options.map(toMultiSelectOption);\n },\n }\n : {}),\n };\n}\n\nfunction buildTimeRange(\n filterKey: string,\n filter: DataTableColumnFilter,\n values: DataTableFilterSelection,\n setValues: Dispatch<SetStateAction<DataTableFilterSelection>>,\n): FilterBarRangeProps {\n const bounds = parseBoundsValue(values[filterKey] ?? \"\");\n return {\n ...(bounds.min !== undefined ? { from: bounds.min } : {}),\n ...(bounds.max !== undefined ? { to: bounds.max } : {}),\n onApply: (from, to) =>\n setValues((current) =>\n updateFilterSelection(current, filterKey, serializeBoundsValue({ min: from, max: to })),\n ),\n ...(filter.presets !== undefined ? { presets: filter.presets } : {}),\n timeEnabled: true,\n };\n}\n\n/**\n * Reads the bounded half of the selection grammar: comma-separated tokens, each\n * carrying its own comparison operator. The bar's controls are inclusive on\n * both edges, so that is what they write back — but a bound typed by hand or\n * arriving in a URL keeps whatever operator it came with.\n */\nfunction parseBoundsValue(raw: string): FilterBarNumberValue {\n const bounds: FilterBarNumberValue = {};\n for (const token of raw.split(\",\")) {\n const trimmed = token.trim();\n if (trimmed.startsWith(\">\")) {\n bounds.min = trimmed.replace(/^>=?/, \"\");\n } else if (trimmed.startsWith(\"<\")) {\n bounds.max = trimmed.replace(/^<=?/, \"\");\n }\n }\n return bounds;\n}\n\nfunction serializeBoundsValue(value: FilterBarNumberValue): string {\n const tokens: string[] = [];\n if (value.min) tokens.push(`>=${value.min}`);\n if (value.max) tokens.push(`<=${value.max}`);\n return tokens.join(\",\");\n}\n\nfunction toMultiSelectOption(option: DataTableFilterOption): MultiSelectOption {\n const label = option.label ?? option.value;\n return {\n value: option.value,\n label,\n ...(option.count !== undefined ? { title: `${label} · ${option.count.toLocaleString()}` } : {}),\n };\n}\n\n/**\n * Refuses a DataTable that would filter twice or offer a control wired to\n * nothing. Both are silent in a running table — rows narrow more than the user\n * asked, or a box swallows what they type — so they are refused at the seam.\n */\nexport function assertDataTableFilterProps(props: {\n autoFilter: boolean;\n manualFilter: boolean;\n showGlobalFilter: boolean;\n globalFilterControlled: boolean;\n hasExternalSearch: boolean;\n}): void {\n if (props.autoFilter && props.manualFilter) {\n throw new Error(\n \"DataTable: autoFilter generates filters that narrow rows locally, which manualFilter then suppresses — the controls would render and do nothing. Pass externalFilters instead.\",\n );\n }\n if (\n props.manualFilter &&\n props.showGlobalFilter &&\n !props.globalFilterControlled &&\n !props.hasExternalSearch\n ) {\n throw new Error(\n \"DataTable: manualFilter suppresses the built-in search's row narrowing, so showGlobalFilter needs globalFilter/onGlobalFilterChange or externalSearch to reach the source.\",\n );\n }\n}\n"],"names":["prettifyKey","applyFilterExtensions","updateFilterSelection","parseMultiFilterValue","serializeMultiFilterValue"],"mappings":"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"}
1
+ {"version":3,"file":"data-table-server-filters.cjs","sources":["../../src/data/data-table-server-filters.ts"],"sourcesContent":["import type { Dispatch, SetStateAction } from \"react\";\nimport type {\n FilterBarFilter,\n FilterBarNumberValue,\n FilterBarRangePreset,\n FilterBarRangeProps,\n} from \"../components/FilterBar\";\nimport type { FilterExtension } from \"../components/filter-bar-utils\";\nimport { applyFilterExtensions } from \"../components/filter-bar-utils\";\nimport type { MultiSelectOption } from \"../components/MultiSelect\";\nimport type { TriState } from \"../components/TriStateToggle\";\nimport type { DataTableColumn, DataTableColumnKind } from \"./DataTable\";\nimport {\n parseBoundsValue,\n parseMultiFilterValue,\n serializeBoundsValue,\n serializeMultiFilterValue,\n updateFilterSelection,\n type DataTableFilterSelection,\n type FilterBoundsValue,\n} from \"./data-table-filter-values\";\nimport { prettifyKey } from \"./data-table-utils\";\n\n/**\n * Which control a filter renders as.\n *\n * Deliberately opaque: \"terms\" is not \"a SQL IN() or an OpenSearch terms\n * query\", it is \"a set of discrete values the user includes or excludes\". The\n * source compiles the selection; nothing about how it does so crosses into the\n * browser.\n */\nexport type DataTableFilterKind = \"terms\" | \"range\" | \"time\" | \"boolean\" | \"text\";\n\nexport type DataTableFilterOption = {\n /** Value written into the selection. */\n value: string;\n /** Display label. Falls back to `value`. */\n label?: string;\n /** How many rows carry this value, shown as a tooltip. */\n count?: number;\n};\n\nexport type DataTableColumnFilter = {\n kind: DataTableFilterKind;\n /** Head of the option set for kind:\"terms\". Empty relies on `lookup`. */\n options?: DataTableFilterOption[];\n /** True when `options` is a capped head of a larger set. */\n truncated?: boolean;\n /** Distinct count behind a truncated head; drives the \"… and N more\" hint. */\n total?: number;\n /** The source can answer a type-ahead for this filter. */\n lookup?: boolean;\n /** Slider domain for kind:\"range\". */\n min?: number;\n max?: number;\n step?: number;\n /** Range presets for kind:\"time\". */\n presets?: FilterBarRangePreset[];\n /** Helper text shown in the filter popover. */\n description?: string;\n disabled?: boolean;\n};\n\n/**\n * A result column as the source describes it: how to render it, and — when the\n * source can narrow on it — which filter parameter it binds to and what control\n * that filter is.\n *\n * `filterKey` need not equal `name`: an analyzed text field filters through an\n * exact-value sibling, and a computed column filters by the alias it was given.\n */\nexport type DataTableServerColumn = {\n /** Field name as the source knows it; also the literal row key. */\n name: string;\n /** Header label. Defaults to a prettified `name`. */\n label?: string;\n /** Backend type string, verbatim (e.g. \"TIMESTAMPTZ\", \"keyword\"). Display only. */\n databaseType?: string;\n /** Cell rendering kind. */\n kind?: DataTableColumnKind;\n /** Filter parameter this column narrows on. Absent means not filterable. */\n filterKey?: string;\n /** The control the filter renders as. Absent means not filterable. */\n filter?: DataTableColumnFilter;\n};\n\n/** Head-set size for a filter value type-ahead. */\nexport const DATA_TABLE_FILTER_LOOKUP_LIMIT = 20;\n\nexport type DataTableFilterLookupRequest = {\n /** Which filter is being searched — the column's `filterKey`. */\n filterKey: string;\n /** What the user typed. Empty asks for the head of the set. */\n search: string;\n /** How many options to return. */\n limit: number;\n};\n\nexport type DataTableFilterLookupResult = {\n options: DataTableFilterOption[];\n};\n\n/**\n * Answers a filter's value type-ahead. Sync or async — a static option source\n * returns an array, a server-backed one a promise.\n */\nexport type DataTableFilterLookup = (\n request: DataTableFilterLookupRequest,\n) => Promise<DataTableFilterLookupResult> | DataTableFilterLookupResult;\n\nexport type ServerFilterBarOptions = {\n /** Answers a terms type-ahead for filters whose `lookup` is set. */\n lookupValues?: DataTableFilterLookup;\n /** Decorators applied to each built filter (icons, relabelling). */\n extensions?: FilterExtension[];\n};\n\nexport type ServerFilterConfig = {\n filters: FilterBarFilter[];\n /** Present when exactly one column declared kind:\"time\". */\n timeRange?: FilterBarRangeProps;\n};\n\n/**\n * Turns the source's column description into DataTable columns.\n *\n * Every column gets a literal `accessor` — a raw result set has empty, dotted\n * and colliding names, none of which survive being read as a path — and\n * `filterable: false`, because a described result is filtered by the source and\n * never by cardinality guessed from one page.\n */\nexport function serverColumnsToDataTableColumns<T extends Record<string, unknown>>(\n columns: DataTableServerColumn[],\n): DataTableColumn<T>[] {\n return columns.map((column, index) => ({\n key: column.name === \"\" ? `column-${index}` : column.name,\n label: column.label ?? prettifyKey(column.name),\n accessor: (row: T) => row[column.name],\n sortable: true,\n filterable: false,\n ...(column.kind !== undefined ? { kind: column.kind } : {}),\n ...(column.filterKey !== undefined ? { filterKey: column.filterKey } : {}),\n }));\n}\n\n/**\n * Builds the FilterBar controls for a described result, already wired to\n * `values`/`setValues`.\n *\n * Pure — it holds no state and fetches nothing; a `lookup` filter closes over\n * the caller's loader. Pass the result as DataTable's `externalFilters`\n * together with `manualFilter`, since the source has already applied it.\n *\n * Throws when a column declares a filter it cannot address: no `filterKey`, a\n * `filterKey` another column already claimed, or a second time range. Each\n * would bind a control to a filter that means something else.\n */\nexport function serverFiltersToFilterBar(\n columns: DataTableServerColumn[],\n values: DataTableFilterSelection,\n setValues: Dispatch<SetStateAction<DataTableFilterSelection>>,\n options: ServerFilterBarOptions = {},\n): ServerFilterConfig {\n const config: ServerFilterConfig = { filters: [] };\n const claimed = new Map<string, string>();\n\n for (const column of columns) {\n const filter = column.filter;\n if (!filter) continue;\n const filterKey = column.filterKey;\n if (!filterKey) {\n throw new Error(`Column ${column.name} declares a filter but no filterKey to send it under`);\n }\n const owner = claimed.get(filterKey);\n if (owner !== undefined) {\n throw new Error(\n `Columns ${owner} and ${column.name} both filter through ${filterKey}; a filter key addresses one column`,\n );\n }\n claimed.set(filterKey, column.name);\n\n const label = column.label ?? prettifyKey(column.name);\n // The bar's own range control is the primary way through a result, and a\n // result has one of those — so the first time column takes it and any\n // others are ranges among the filters. A raw SELECT commonly returns\n // created_at beside updated_at, and refusing the second one cost the whole\n // bar rather than just that column's control.\n if (filter.kind === \"time\" && !config.timeRange) {\n config.timeRange = buildTimeRange(filterKey, filter, values, setValues);\n continue;\n }\n config.filters.push(\n applyFilterExtensions(\n buildFilter({ column, filterKey, label, filter, values, setValues, options }),\n options.extensions,\n ),\n );\n }\n return config;\n}\n\ntype BuildArgs = {\n column: DataTableServerColumn;\n filterKey: string;\n label: string;\n filter: DataTableColumnFilter;\n values: DataTableFilterSelection;\n setValues: Dispatch<SetStateAction<DataTableFilterSelection>>;\n options: ServerFilterBarOptions;\n};\n\nfunction buildFilter(args: BuildArgs): FilterBarFilter {\n const { filterKey, label, filter, values, setValues } = args;\n const raw = values[filterKey] ?? \"\";\n const write = (serialized: string) =>\n setValues((current) => updateFilterSelection(current, filterKey, serialized));\n const shared = {\n key: filterKey,\n label,\n ...(filter.description !== undefined ? { description: filter.description } : {}),\n ...(filter.disabled !== undefined ? { disabled: filter.disabled } : {}),\n };\n\n switch (filter.kind) {\n case \"time\":\n return {\n ...shared,\n kind: \"date-range\",\n ...boundsToRange(parseBoundsValue(raw)),\n onApply: (from: string, to: string) =>\n write(serializeBoundsValue({ min: from, max: to })),\n ...(filter.presets !== undefined ? { presets: filter.presets } : {}),\n timeEnabled: true,\n };\n case \"range\":\n return {\n ...shared,\n kind: \"number\",\n value: parseBoundsValue(raw),\n onChange: (next: FilterBarNumberValue) => write(serializeBoundsValue(next)),\n ...(filter.min !== undefined ? { domainMin: filter.min } : {}),\n ...(filter.max !== undefined ? { domainMax: filter.max } : {}),\n ...(filter.step !== undefined ? { step: filter.step } : {}),\n };\n case \"boolean\":\n return {\n ...shared,\n kind: \"tristate\",\n value: raw === \"\" ? undefined : raw === \"true\",\n onChange: (next: TriState) => write(next === undefined ? \"\" : String(next)),\n };\n case \"text\":\n return {\n ...shared,\n kind: \"text\",\n value: raw,\n onChange: (next: string) => write(next),\n };\n default:\n return buildTermsFilter(args, shared, raw, write);\n }\n}\n\nfunction buildTermsFilter(\n { filter, options }: BuildArgs,\n shared: { key: string; label: string; description?: string; disabled?: boolean },\n raw: string,\n write: (serialized: string) => void,\n): FilterBarFilter {\n const lookupValues = options.lookupValues;\n // A selection with no options and no type-ahead has nothing to select from,\n // and a dropdown that opens empty is a control the user cannot use. The\n // grammar is the wire format either way, so typing \"a,b\" or \"!a\" into the\n // input still means what selecting them would have.\n if (!filter.lookup && (filter.options?.length ?? 0) === 0) {\n return { ...shared, kind: \"text\", value: raw, onChange: (next: string) => write(next) };\n }\n return {\n ...shared,\n kind: \"multi\",\n value: parseMultiFilterValue(raw),\n onChange: (next) => write(serializeMultiFilterValue(next)),\n options: (filter.options ?? []).map(toMultiSelectOption),\n ...(filter.truncated !== undefined ? { truncated: filter.truncated } : {}),\n ...(filter.total !== undefined ? { total: filter.total } : {}),\n // The field owns the in-flight flag from the promise this returns, so no\n // `loading` is passed: a second source of truth for it could disagree.\n ...(lookupValues && filter.lookup\n ? {\n onSearch: async (search: string) => {\n const result = await lookupValues({\n filterKey: shared.key,\n search,\n limit: DATA_TABLE_FILTER_LOOKUP_LIMIT,\n });\n return result.options.map(toMultiSelectOption);\n },\n }\n : {}),\n };\n}\n\nfunction buildTimeRange(\n filterKey: string,\n filter: DataTableColumnFilter,\n values: DataTableFilterSelection,\n setValues: Dispatch<SetStateAction<DataTableFilterSelection>>,\n): FilterBarRangeProps {\n return {\n ...boundsToRange(parseBoundsValue(values[filterKey] ?? \"\")),\n onApply: (from, to) =>\n setValues((current) =>\n updateFilterSelection(current, filterKey, serializeBoundsValue({ min: from, max: to })),\n ),\n ...(filter.presets !== undefined ? { presets: filter.presets } : {}),\n timeEnabled: true,\n };\n}\n\n/** Names a bounded selection's edges the way a range control reads them. */\nfunction boundsToRange(bounds: FilterBoundsValue): { from?: string; to?: string } {\n return {\n ...(bounds.min !== undefined ? { from: bounds.min } : {}),\n ...(bounds.max !== undefined ? { to: bounds.max } : {}),\n };\n}\n\nfunction toMultiSelectOption(option: DataTableFilterOption): MultiSelectOption {\n const label = option.label ?? option.value;\n return {\n value: option.value,\n label,\n ...(option.count !== undefined ? { title: `${label} · ${option.count.toLocaleString()}` } : {}),\n };\n}\n\n/**\n * Refuses a DataTable that would filter twice or offer a control wired to\n * nothing. Both are silent in a running table — rows narrow more than the user\n * asked, or a box swallows what they type — so they are refused at the seam.\n */\nexport function assertDataTableFilterProps(props: {\n autoFilter: boolean;\n manualFilter: boolean;\n showGlobalFilter: boolean;\n globalFilterControlled: boolean;\n hasExternalSearch: boolean;\n}): void {\n if (props.autoFilter && props.manualFilter) {\n throw new Error(\n \"DataTable: autoFilter generates filters that narrow rows locally, which manualFilter then suppresses — the controls would render and do nothing. Pass externalFilters instead.\",\n );\n }\n if (\n props.manualFilter &&\n props.showGlobalFilter &&\n !props.globalFilterControlled &&\n !props.hasExternalSearch\n ) {\n throw new Error(\n \"DataTable: manualFilter suppresses the built-in search's row narrowing, so showGlobalFilter needs globalFilter/onGlobalFilterChange or externalSearch to reach the source.\",\n );\n }\n}\n"],"names":["prettifyKey","applyFilterExtensions","updateFilterSelection","parseBoundsValue","serializeBoundsValue","parseMultiFilterValue","serializeMultiFilterValue"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"data-table-server-filters.d.ts","sourceRoot":"","sources":["../../src/data/data-table-server-filters.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"data-table-server-filters.d.ts","sourceRoot":"","sources":["../../src/data/data-table-server-filters.ts"],"names":[],"mappings":"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"}