@pilotiq/pilotiq 0.23.1 → 0.24.2

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 (500) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/boost/guidelines.md +566 -0
  3. package/boost/skills/pilotiq-fields/SKILL.md +47 -0
  4. package/boost/skills/pilotiq-fields/rules/field-catalog.md +288 -0
  5. package/boost/skills/pilotiq-fields/rules/reactive-fields.md +199 -0
  6. package/boost/skills/pilotiq-fields/rules/validation.md +198 -0
  7. package/boost/skills/pilotiq-relations/SKILL.md +47 -0
  8. package/boost/skills/pilotiq-relations/rules/relation-managers.md +256 -0
  9. package/boost/skills/pilotiq-relations/rules/repeater-relationship.md +177 -0
  10. package/boost/skills/pilotiq-resource/SKILL.md +61 -0
  11. package/boost/skills/pilotiq-resource/rules/authorization.md +242 -0
  12. package/boost/skills/pilotiq-resource/rules/defining-resources.md +228 -0
  13. package/boost/skills/pilotiq-resource/rules/page-overrides.md +296 -0
  14. package/dist/actions/exportFactory.d.ts +10 -0
  15. package/dist/actions/exportFactory.d.ts.map +1 -1
  16. package/dist/actions/exportFactory.js +10 -0
  17. package/dist/actions/exportFactory.js.map +1 -1
  18. package/dist/react/CollabRoomContext.d.ts +5 -5
  19. package/dist/react/index.d.ts +0 -1
  20. package/dist/react/index.d.ts.map +1 -1
  21. package/dist/react/index.js +0 -1
  22. package/dist/react/index.js.map +1 -1
  23. package/dist/routes/helpers.d.ts.map +1 -1
  24. package/dist/routes/helpers.js +6 -2
  25. package/dist/routes/helpers.js.map +1 -1
  26. package/dist/routes/relations.d.ts.map +1 -1
  27. package/dist/routes/relations.js +12 -0
  28. package/dist/routes/relations.js.map +1 -1
  29. package/package.json +6 -1
  30. package/.turbo/turbo-build.log +0 -8
  31. package/CLAUDE.md +0 -265
  32. package/dist/react/useCollabSeed.d.ts +0 -23
  33. package/dist/react/useCollabSeed.d.ts.map +0 -1
  34. package/dist/react/useCollabSeed.js +0 -82
  35. package/dist/react/useCollabSeed.js.map +0 -1
  36. package/src/Cluster.test.ts +0 -283
  37. package/src/Cluster.ts +0 -83
  38. package/src/Column.test.ts +0 -199
  39. package/src/Column.ts +0 -710
  40. package/src/Global.test.ts +0 -367
  41. package/src/Global.ts +0 -169
  42. package/src/Page.test.ts +0 -114
  43. package/src/Page.ts +0 -208
  44. package/src/Pilotiq.perf.test.ts +0 -252
  45. package/src/Pilotiq.test.ts +0 -129
  46. package/src/Pilotiq.ts +0 -1158
  47. package/src/PilotiqRegistry.ts +0 -36
  48. package/src/PilotiqServiceProvider.ts +0 -121
  49. package/src/RelationManager.test.ts +0 -400
  50. package/src/RelationManager.ts +0 -527
  51. package/src/RenderHook.test.ts +0 -252
  52. package/src/RenderHook.ts +0 -242
  53. package/src/Resource.test.ts +0 -284
  54. package/src/Resource.ts +0 -526
  55. package/src/RightPanel.test.ts +0 -202
  56. package/src/RightPanel.ts +0 -132
  57. package/src/Tab.test.ts +0 -91
  58. package/src/Tab.ts +0 -156
  59. package/src/UserMenuItem.ts +0 -145
  60. package/src/actions/Action.test.ts +0 -2526
  61. package/src/actions/Action.ts +0 -1515
  62. package/src/actions/ActionGroup.test.ts +0 -112
  63. package/src/actions/ActionGroup.ts +0 -173
  64. package/src/actions/attachFactory.ts +0 -172
  65. package/src/actions/bulkFactories.ts +0 -168
  66. package/src/actions/crudFactories.ts +0 -220
  67. package/src/actions/exportFactory.ts +0 -215
  68. package/src/actions/factoryHelpers.ts +0 -177
  69. package/src/actions/importFactory.ts +0 -243
  70. package/src/actions/index.ts +0 -17
  71. package/src/actions/m2mFactories.ts +0 -193
  72. package/src/actions/relationFactories.ts +0 -372
  73. package/src/applyPageHooks.test.ts +0 -463
  74. package/src/applyPageHooks.ts +0 -330
  75. package/src/authorization.test.ts +0 -483
  76. package/src/breadcrumbs.test.ts +0 -238
  77. package/src/cells/coerce.test.ts +0 -85
  78. package/src/cells/coerce.ts +0 -84
  79. package/src/clusterPaths.ts +0 -35
  80. package/src/columns/BadgeColumn.test.ts +0 -54
  81. package/src/columns/BadgeColumn.ts +0 -32
  82. package/src/columns/BooleanColumn.test.ts +0 -41
  83. package/src/columns/BooleanColumn.ts +0 -18
  84. package/src/columns/ColorColumn.test.ts +0 -37
  85. package/src/columns/ColorColumn.ts +0 -38
  86. package/src/columns/IconColumn.test.ts +0 -54
  87. package/src/columns/IconColumn.ts +0 -37
  88. package/src/columns/ImageColumn.test.ts +0 -41
  89. package/src/columns/ImageColumn.ts +0 -28
  90. package/src/columns/SelectColumn.ts +0 -98
  91. package/src/columns/TextColumn.test.ts +0 -190
  92. package/src/columns/TextColumn.ts +0 -20
  93. package/src/columns/TextInputColumn.ts +0 -68
  94. package/src/columns/ToggleColumn.ts +0 -46
  95. package/src/columns/editableColumns.test.ts +0 -238
  96. package/src/columns/index.ts +0 -9
  97. package/src/defaultGlobalPages.ts +0 -95
  98. package/src/defaultPages.test.ts +0 -634
  99. package/src/defaultPages.ts +0 -617
  100. package/src/defaultViewPage.test.ts +0 -147
  101. package/src/elements/Form.test.ts +0 -223
  102. package/src/elements/Form.ts +0 -416
  103. package/src/elements/ListTabs.ts +0 -28
  104. package/src/elements/Table.test.ts +0 -422
  105. package/src/elements/Table.ts +0 -850
  106. package/src/elements/TableGroup.test.ts +0 -260
  107. package/src/elements/TableGroup.ts +0 -334
  108. package/src/elements/dispatchAction.test.ts +0 -463
  109. package/src/elements/dispatchAction.ts +0 -355
  110. package/src/elements/dispatchForm.test.ts +0 -477
  111. package/src/elements/dispatchForm.ts +0 -1993
  112. package/src/elements/dispatchTable.test.ts +0 -1514
  113. package/src/elements/dispatchTable.ts +0 -745
  114. package/src/elements/index.ts +0 -21
  115. package/src/entries/BadgeEntry.ts +0 -39
  116. package/src/entries/CodeEntry.test.ts +0 -40
  117. package/src/entries/CodeEntry.ts +0 -52
  118. package/src/entries/ColorEntry.ts +0 -63
  119. package/src/entries/ComponentEntry.test.ts +0 -173
  120. package/src/entries/ComponentEntry.ts +0 -95
  121. package/src/entries/Entry.ts +0 -304
  122. package/src/entries/IconEntry.ts +0 -49
  123. package/src/entries/ImageEntry.ts +0 -61
  124. package/src/entries/KeyValueEntry.ts +0 -47
  125. package/src/entries/RepeatableEntry.test.ts +0 -239
  126. package/src/entries/RepeatableEntry.ts +0 -173
  127. package/src/entries/TextEntry.test.ts +0 -394
  128. package/src/entries/TextEntry.ts +0 -60
  129. package/src/entries/index.ts +0 -12
  130. package/src/entries/leaves.test.ts +0 -306
  131. package/src/entries/registry.ts +0 -54
  132. package/src/fields/BuilderField.test.ts +0 -1188
  133. package/src/fields/BuilderField.ts +0 -605
  134. package/src/fields/BuilderRelationship.test.ts +0 -811
  135. package/src/fields/CheckboxField.test.ts +0 -44
  136. package/src/fields/CheckboxField.ts +0 -27
  137. package/src/fields/CheckboxListField.test.ts +0 -99
  138. package/src/fields/CheckboxListField.ts +0 -66
  139. package/src/fields/ColorPickerField.test.ts +0 -33
  140. package/src/fields/ColorPickerField.ts +0 -25
  141. package/src/fields/DateField.ts +0 -54
  142. package/src/fields/DateTimeField.test.ts +0 -55
  143. package/src/fields/EmailField.ts +0 -16
  144. package/src/fields/Field.test.ts +0 -654
  145. package/src/fields/Field.ts +0 -817
  146. package/src/fields/FileUploadField.test.ts +0 -143
  147. package/src/fields/FileUploadField.ts +0 -159
  148. package/src/fields/HiddenField.test.ts +0 -27
  149. package/src/fields/HiddenField.ts +0 -28
  150. package/src/fields/KeyValueField.test.ts +0 -105
  151. package/src/fields/KeyValueField.ts +0 -55
  152. package/src/fields/MarkdownField.test.ts +0 -167
  153. package/src/fields/MarkdownField.ts +0 -162
  154. package/src/fields/NumberField.ts +0 -33
  155. package/src/fields/RadioField.test.ts +0 -94
  156. package/src/fields/RadioField.ts +0 -67
  157. package/src/fields/RepeaterField.test.ts +0 -1806
  158. package/src/fields/RepeaterField.ts +0 -939
  159. package/src/fields/RepeaterRelationship.test.ts +0 -1923
  160. package/src/fields/RepeaterSimple.test.ts +0 -248
  161. package/src/fields/RowButton.test.ts +0 -219
  162. package/src/fields/RowButton.ts +0 -135
  163. package/src/fields/SelectField.test.ts +0 -192
  164. package/src/fields/SelectField.ts +0 -235
  165. package/src/fields/SliderField.test.ts +0 -50
  166. package/src/fields/SliderField.ts +0 -53
  167. package/src/fields/SlugField.ts +0 -24
  168. package/src/fields/TagsInputField.test.ts +0 -154
  169. package/src/fields/TagsInputField.ts +0 -133
  170. package/src/fields/TextField.test.ts +0 -213
  171. package/src/fields/TextField.ts +0 -177
  172. package/src/fields/TextareaField.test.ts +0 -58
  173. package/src/fields/TextareaField.ts +0 -59
  174. package/src/fields/ToggleButtonsField.test.ts +0 -106
  175. package/src/fields/ToggleButtonsField.ts +0 -59
  176. package/src/fields/ToggleField.ts +0 -16
  177. package/src/fields/disableOptionsWhenSelectedInSiblingRepeaterItems.test.ts +0 -319
  178. package/src/fields/optionsResolver.ts +0 -95
  179. package/src/fields/resolveField.ts +0 -28
  180. package/src/filters/BooleanFilter.ts +0 -35
  181. package/src/filters/DateRangeFilter.test.ts +0 -194
  182. package/src/filters/DateRangeFilter.ts +0 -148
  183. package/src/filters/Filter.test.ts +0 -268
  184. package/src/filters/Filter.ts +0 -184
  185. package/src/filters/FormFilter.test.ts +0 -238
  186. package/src/filters/FormFilter.ts +0 -215
  187. package/src/filters/MultiSelectFilter.test.ts +0 -119
  188. package/src/filters/MultiSelectFilter.ts +0 -78
  189. package/src/filters/QueryBuilderFilter.test.ts +0 -662
  190. package/src/filters/QueryBuilderFilter.ts +0 -398
  191. package/src/filters/SelectFilter.ts +0 -46
  192. package/src/filters/TernaryFilter.test.ts +0 -160
  193. package/src/filters/TernaryFilter.ts +0 -72
  194. package/src/filters/TrashedFilter.test.ts +0 -149
  195. package/src/filters/TrashedFilter.ts +0 -55
  196. package/src/filters/queryBuilder/BooleanConstraint.ts +0 -31
  197. package/src/filters/queryBuilder/Constraint.ts +0 -115
  198. package/src/filters/queryBuilder/DateConstraint.ts +0 -69
  199. package/src/filters/queryBuilder/NumberConstraint.ts +0 -66
  200. package/src/filters/queryBuilder/SelectConstraint.ts +0 -72
  201. package/src/filters/queryBuilder/TextConstraint.ts +0 -64
  202. package/src/filters/queryBuilder/index.ts +0 -12
  203. package/src/icons/index.ts +0 -2
  204. package/src/icons/lucide.ts +0 -204
  205. package/src/icons/registry.test.ts +0 -56
  206. package/src/icons/registry.ts +0 -41
  207. package/src/icons/types.ts +0 -47
  208. package/src/index.ts +0 -525
  209. package/src/io/csv.test.ts +0 -142
  210. package/src/io/csv.ts +0 -170
  211. package/src/nestedRelationManagerData.test.ts +0 -547
  212. package/src/notifications/Notification.test.ts +0 -210
  213. package/src/notifications/Notification.ts +0 -354
  214. package/src/notifications/broadcast.test.ts +0 -110
  215. package/src/notifications/broadcast.ts +0 -95
  216. package/src/notifications/database.test.ts +0 -383
  217. package/src/notifications/database.ts +0 -398
  218. package/src/notifications/databaseNotifications.test.ts +0 -187
  219. package/src/notifications/dispatchNotificationAction.test.ts +0 -341
  220. package/src/notifications/dispatchNotificationAction.ts +0 -142
  221. package/src/notifications/flash.test.ts +0 -89
  222. package/src/notifications/flash.ts +0 -71
  223. package/src/notifications/index.ts +0 -45
  224. package/src/notifications/registerBroadcastAuth.test.ts +0 -134
  225. package/src/notifications/registerBroadcastAuth.ts +0 -100
  226. package/src/notifications/resolveSavedNotification.test.ts +0 -82
  227. package/src/notifications/resolveSavedNotification.ts +0 -59
  228. package/src/notifications/types.ts +0 -93
  229. package/src/orm/m2mAccessor.ts +0 -66
  230. package/src/orm/modelDefaults.test.ts +0 -633
  231. package/src/orm/modelDefaults.ts +0 -666
  232. package/src/pageData/breadcrumbs.ts +0 -288
  233. package/src/pageData/forms.ts +0 -578
  234. package/src/pageData/helpers.ts +0 -857
  235. package/src/pageData/misc.ts +0 -347
  236. package/src/pageData/navigation.ts +0 -842
  237. package/src/pageData/relationPages.ts +0 -1248
  238. package/src/pageData/relationTabs.ts +0 -286
  239. package/src/pageData/resourcePages.ts +0 -609
  240. package/src/pageData.test.ts +0 -1545
  241. package/src/pageData.ts +0 -341
  242. package/src/plugins/index.ts +0 -8
  243. package/src/plugins/themeEditor.test.ts +0 -36
  244. package/src/plugins/themeEditor.ts +0 -45
  245. package/src/react/AppShell.tsx +0 -251
  246. package/src/react/CollabExtensionFactoryRegistry.ts +0 -55
  247. package/src/react/CollabRoomContext.ts +0 -98
  248. package/src/react/CollabTextRendererRegistry.ts +0 -102
  249. package/src/react/CommandPalette.tsx +0 -375
  250. package/src/react/CurrentUserContext.tsx +0 -50
  251. package/src/react/CustomPageWrapperGate.tsx +0 -69
  252. package/src/react/CustomPageWrapperRegistry.ts +0 -45
  253. package/src/react/FieldFocusReporterRegistry.ts +0 -37
  254. package/src/react/FieldLabelSlotRegistry.ts +0 -30
  255. package/src/react/FieldPresenceRegistry.ts +0 -46
  256. package/src/react/FormCollabBindingRegistry.ts +0 -242
  257. package/src/react/FormStateContext.tsx +0 -591
  258. package/src/react/HeadHooks.tsx +0 -126
  259. package/src/react/MarkdownEditorRegistry.test.ts +0 -38
  260. package/src/react/MarkdownEditorRegistry.ts +0 -107
  261. package/src/react/NotificationActionStrip.tsx +0 -263
  262. package/src/react/NotificationBell.tsx +0 -426
  263. package/src/react/PendingSuggestionApplierRegistry.test.ts +0 -97
  264. package/src/react/PendingSuggestionApplierRegistry.ts +0 -98
  265. package/src/react/PendingSuggestionOverlayRegistry.ts +0 -54
  266. package/src/react/PendingSuggestionsContext.tsx +0 -172
  267. package/src/react/RecordWrapperGate.tsx +0 -58
  268. package/src/react/RecordWrapperRegistry.ts +0 -39
  269. package/src/react/RenderHookSlot.tsx +0 -32
  270. package/src/react/RightSidebar.tsx +0 -257
  271. package/src/react/RightSidebarContext.tsx +0 -234
  272. package/src/react/RightSidebarTrigger.tsx +0 -53
  273. package/src/react/RowCoordsContext.tsx +0 -23
  274. package/src/react/SchemaRenderer.tsx +0 -549
  275. package/src/react/SearchTrigger.tsx +0 -46
  276. package/src/react/ThemeProvider.tsx +0 -93
  277. package/src/react/ThemeSettingsPage.tsx +0 -579
  278. package/src/react/ThemeToggle.tsx +0 -20
  279. package/src/react/Toaster.tsx +0 -158
  280. package/src/react/UserMenu.tsx +0 -196
  281. package/src/react/WidgetDataContext.tsx +0 -157
  282. package/src/react/cells/EditableCell.tsx +0 -389
  283. package/src/react/component-slots.test.ts +0 -103
  284. package/src/react/component-slots.ts +0 -116
  285. package/src/react/fieldJsHandler.test.ts +0 -166
  286. package/src/react/fieldJsHandler.ts +0 -79
  287. package/src/react/fields/BuilderInput.tsx +0 -1078
  288. package/src/react/fields/CheckboxInput.tsx +0 -39
  289. package/src/react/fields/CheckboxListInput.tsx +0 -102
  290. package/src/react/fields/ColorInput.tsx +0 -71
  291. package/src/react/fields/DateFieldInput.tsx +0 -70
  292. package/src/react/fields/DateTimeInput.tsx +0 -62
  293. package/src/react/fields/FieldShell.tsx +0 -348
  294. package/src/react/fields/FileUploadInput.tsx +0 -639
  295. package/src/react/fields/HiddenInput.tsx +0 -17
  296. package/src/react/fields/KeyValueInput.tsx +0 -230
  297. package/src/react/fields/MarkdownInput.tsx +0 -560
  298. package/src/react/fields/RadioInput.tsx +0 -81
  299. package/src/react/fields/RepeaterInput.test.ts +0 -116
  300. package/src/react/fields/RepeaterInput.tsx +0 -1420
  301. package/src/react/fields/SelectFieldInput.tsx +0 -280
  302. package/src/react/fields/SliderInput.tsx +0 -81
  303. package/src/react/fields/TagsInput.tsx +0 -283
  304. package/src/react/fields/TextLikeInput.tsx +0 -256
  305. package/src/react/fields/ToggleButtonsInput.tsx +0 -60
  306. package/src/react/fields/ToggleFieldInput.tsx +0 -56
  307. package/src/react/fields/relationshipRenameDispatch.test.ts +0 -106
  308. package/src/react/fields/relationshipRenameDispatch.ts +0 -97
  309. package/src/react/fields/repeaterReconcile.test.ts +0 -114
  310. package/src/react/fields/repeaterReconcile.ts +0 -104
  311. package/src/react/fields/rowChromeButton.tsx +0 -336
  312. package/src/react/fields/rowState.ts +0 -106
  313. package/src/react/fields/syncRowGates.test.ts +0 -202
  314. package/src/react/fields/syncRowGates.ts +0 -66
  315. package/src/react/fields/textInputControls.tsx +0 -238
  316. package/src/react/fields/useRowReorderDnd.ts +0 -78
  317. package/src/react/formStateHelpers.test.ts +0 -508
  318. package/src/react/formStateHelpers.ts +0 -381
  319. package/src/react/hooks/use-mobile.ts +0 -19
  320. package/src/react/icon-context.tsx +0 -60
  321. package/src/react/index.ts +0 -195
  322. package/src/react/layouts/SidebarLayout.tsx +0 -250
  323. package/src/react/layouts/TopbarLayout.tsx +0 -258
  324. package/src/react/navigate.tsx +0 -37
  325. package/src/react/onProviderSynced.test.ts +0 -90
  326. package/src/react/parseRecordEditUrl.test.ts +0 -122
  327. package/src/react/parseRecordEditUrl.ts +0 -94
  328. package/src/react/persistedState.ts +0 -40
  329. package/src/react/registry.ts +0 -48
  330. package/src/react/right-panel-registry.tsx +0 -47
  331. package/src/react/schemaRenderer/AlertRenderer.tsx +0 -112
  332. package/src/react/schemaRenderer/EntryRenderer.tsx +0 -501
  333. package/src/react/schemaRenderer/SectionRenderer.tsx +0 -120
  334. package/src/react/schemaRenderer/SimpleElements.tsx +0 -306
  335. package/src/react/schemaRenderer/TabsRenderer.tsx +0 -62
  336. package/src/react/schemaRenderer/WizardRenderer.tsx +0 -338
  337. package/src/react/schemaRenderer/action/ActionGroupTrigger.tsx +0 -177
  338. package/src/react/schemaRenderer/action/ActionModalDialog.tsx +0 -273
  339. package/src/react/schemaRenderer/action/ConfirmActionDialog.tsx +0 -61
  340. package/src/react/schemaRenderer/action/HandlerActionButton.tsx +0 -43
  341. package/src/react/schemaRenderer/action/MethodActionButton.tsx +0 -64
  342. package/src/react/schemaRenderer/action/buttons.tsx +0 -99
  343. package/src/react/schemaRenderer/action/helpers.ts +0 -140
  344. package/src/react/schemaRenderer/action/renderAction.tsx +0 -245
  345. package/src/react/schemaRenderer/columnFormat.ts +0 -65
  346. package/src/react/schemaRenderer/constants.ts +0 -50
  347. package/src/react/schemaRenderer/form/FormRenderer.tsx +0 -274
  348. package/src/react/schemaRenderer/form/renderField.tsx +0 -511
  349. package/src/react/schemaRenderer/helpers.tsx +0 -81
  350. package/src/react/schemaRenderer/table/CardsLayoutBody.tsx +0 -308
  351. package/src/react/schemaRenderer/table/TableRenderer.tsx +0 -123
  352. package/src/react/schemaRenderer/table/TableRendererBody.tsx +0 -974
  353. package/src/react/schemaRenderer/table/filters.tsx +0 -1233
  354. package/src/react/schemaRenderer/table/formatCell.tsx +0 -264
  355. package/src/react/schemaRenderer/table/links.tsx +0 -112
  356. package/src/react/schemaRenderer/table/renderRowActions.tsx +0 -52
  357. package/src/react/schemaRenderer/table/url.tsx +0 -143
  358. package/src/react/theme-preview/apply.ts +0 -99
  359. package/src/react/theme-preview/build-html.ts +0 -436
  360. package/src/react/ui/button.tsx +0 -51
  361. package/src/react/ui/calendar.tsx +0 -67
  362. package/src/react/ui/checkbox.tsx +0 -29
  363. package/src/react/ui/dialog.tsx +0 -108
  364. package/src/react/ui/dropdown-menu.tsx +0 -97
  365. package/src/react/ui/input.tsx +0 -20
  366. package/src/react/ui/label.tsx +0 -21
  367. package/src/react/ui/popover.tsx +0 -50
  368. package/src/react/ui/select.tsx +0 -169
  369. package/src/react/ui/separator.tsx +0 -25
  370. package/src/react/ui/sheet.tsx +0 -136
  371. package/src/react/ui/sidebar.tsx +0 -723
  372. package/src/react/ui/skeleton.tsx +0 -13
  373. package/src/react/ui/slider.tsx +0 -34
  374. package/src/react/ui/switch.tsx +0 -28
  375. package/src/react/ui/table.tsx +0 -105
  376. package/src/react/ui/tabs.tsx +0 -63
  377. package/src/react/ui/textarea.tsx +0 -18
  378. package/src/react/ui/tooltip.tsx +0 -64
  379. package/src/react/useCollabSeed.ts +0 -86
  380. package/src/react/useResizableWidth.ts +0 -139
  381. package/src/react/utils.ts +0 -6
  382. package/src/react/widgetRegistry.test.ts +0 -43
  383. package/src/react/widgetRegistry.ts +0 -50
  384. package/src/react/widgets/StatsOverviewRenderer.tsx +0 -232
  385. package/src/react/widgets/TableWidgetRenderer.tsx +0 -231
  386. package/src/react/widgets/ViewRenderer.tsx +0 -71
  387. package/src/relationManagerData.test.ts +0 -1595
  388. package/src/richtext/index.ts +0 -8
  389. package/src/richtext/registry.ts +0 -89
  390. package/src/routes/globals.ts +0 -148
  391. package/src/routes/guard.test.ts +0 -325
  392. package/src/routes/helpers.ts +0 -700
  393. package/src/routes/pages.ts +0 -175
  394. package/src/routes/panel.ts +0 -204
  395. package/src/routes/relations.ts +0 -1227
  396. package/src/routes/resources.ts +0 -781
  397. package/src/routes/theme.ts +0 -91
  398. package/src/routes-nested-relations.test.ts +0 -676
  399. package/src/routes-relations.test.ts +0 -972
  400. package/src/routes.test.ts +0 -2027
  401. package/src/routes.ts +0 -303
  402. package/src/schema/Alert.test.ts +0 -109
  403. package/src/schema/Alert.ts +0 -131
  404. package/src/schema/Block.ts +0 -169
  405. package/src/schema/Breadcrumbs.ts +0 -40
  406. package/src/schema/Card.ts +0 -35
  407. package/src/schema/Divider.ts +0 -20
  408. package/src/schema/Element.ts +0 -219
  409. package/src/schema/EmptyState.test.ts +0 -37
  410. package/src/schema/EmptyState.ts +0 -63
  411. package/src/schema/Fieldset.ts +0 -43
  412. package/src/schema/Grid.ts +0 -43
  413. package/src/schema/Group.ts +0 -30
  414. package/src/schema/Heading.ts +0 -39
  415. package/src/schema/Html.ts +0 -67
  416. package/src/schema/Icon.ts +0 -54
  417. package/src/schema/Image.ts +0 -57
  418. package/src/schema/LinkTag.ts +0 -41
  419. package/src/schema/Markdown.ts +0 -85
  420. package/src/schema/MetaTag.ts +0 -41
  421. package/src/schema/RelationTabs.ts +0 -71
  422. package/src/schema/ScriptTag.ts +0 -55
  423. package/src/schema/Section.ts +0 -160
  424. package/src/schema/ServerDataElement.test.ts +0 -140
  425. package/src/schema/ServerDataElement.ts +0 -156
  426. package/src/schema/SlotComponent.test.ts +0 -77
  427. package/src/schema/SlotComponent.ts +0 -71
  428. package/src/schema/Split.ts +0 -50
  429. package/src/schema/Stat.test.ts +0 -118
  430. package/src/schema/Stat.ts +0 -154
  431. package/src/schema/StatsOverview.test.ts +0 -141
  432. package/src/schema/StatsOverview.ts +0 -119
  433. package/src/schema/StyleTag.ts +0 -35
  434. package/src/schema/TableWidget.test.ts +0 -297
  435. package/src/schema/TableWidget.ts +0 -289
  436. package/src/schema/Tabs.ts +0 -79
  437. package/src/schema/Text.ts +0 -58
  438. package/src/schema/UnorderedList.ts +0 -49
  439. package/src/schema/View.test.ts +0 -111
  440. package/src/schema/View.ts +0 -127
  441. package/src/schema/Wizard.ts +0 -220
  442. package/src/schema/containers.test.ts +0 -564
  443. package/src/schema/headTags.test.ts +0 -134
  444. package/src/schema/index.ts +0 -40
  445. package/src/schema/primes.test.ts +0 -269
  446. package/src/schema/resolveSchema.test.ts +0 -379
  447. package/src/schema/resolveSchema.ts +0 -917
  448. package/src/schema/sanitize.ts +0 -58
  449. package/src/search.test.ts +0 -446
  450. package/src/search.ts +0 -178
  451. package/src/sessionFilters.test.ts +0 -375
  452. package/src/sessionFilters.ts +0 -143
  453. package/src/slot-components/index.ts +0 -10
  454. package/src/slot-components/registry.ts +0 -56
  455. package/src/styles/file-upload.css +0 -13
  456. package/src/summarizers/Summarizer.test.ts +0 -84
  457. package/src/summarizers/Summarizer.ts +0 -123
  458. package/src/summarizers/index.ts +0 -11
  459. package/src/theme/base-colors.ts +0 -68
  460. package/src/theme/chart-colors.ts +0 -50
  461. package/src/theme/colors.ts +0 -447
  462. package/src/theme/generate-css.test.ts +0 -139
  463. package/src/theme/generate-css.ts +0 -44
  464. package/src/theme/generate-scale.test.ts +0 -106
  465. package/src/theme/generate-scale.ts +0 -97
  466. package/src/theme/icon-map.ts +0 -42
  467. package/src/theme/index.ts +0 -34
  468. package/src/theme/migrate.test.ts +0 -178
  469. package/src/theme/migrate.ts +0 -81
  470. package/src/theme/presets.ts +0 -135
  471. package/src/theme/radius.ts +0 -18
  472. package/src/theme/resolve.test.ts +0 -238
  473. package/src/theme/resolve.ts +0 -96
  474. package/src/theme/spacing.ts +0 -18
  475. package/src/theme/storage.test.ts +0 -126
  476. package/src/theme/storage.ts +0 -106
  477. package/src/theme/theme-colors.ts +0 -88
  478. package/src/theme/types.ts +0 -125
  479. package/src/uploads/UploadAdapter.ts +0 -35
  480. package/src/uploads/index.ts +0 -2
  481. package/src/uploads/localUpload.test.ts +0 -70
  482. package/src/uploads/localUpload.ts +0 -84
  483. package/src/validation/Validator.ts +0 -49
  484. package/src/validation/index.ts +0 -28
  485. package/src/validation/rules.ts +0 -78
  486. package/src/validation/runValidators.ts +0 -435
  487. package/src/validation/uniqueValidator.test.ts +0 -196
  488. package/src/validation/uniqueValidator.ts +0 -133
  489. package/src/validation/validators.test.ts +0 -268
  490. package/src/vite.test.ts +0 -184
  491. package/src/vite.ts +0 -787
  492. package/src/widgets/index.ts +0 -10
  493. package/src/widgets/registry.ts +0 -45
  494. package/src/widgets.test.ts +0 -592
  495. package/tsconfig.build.json +0 -11
  496. package/tsconfig.json +0 -4
  497. package/tsconfig.test.json +0 -10
  498. package/views/react/Dashboard.tsx +0 -27
  499. package/views/react/Resources/Form.tsx +0 -102
  500. package/views/react/Resources/Index.tsx +0 -49
@@ -1,264 +0,0 @@
1
- import React, { useState } from 'react'
2
- import { CheckIcon, CircleIcon, CopyIcon } from 'lucide-react'
3
- import type { ElementMeta } from '../../../schema/Element.js'
4
- import {
5
- BADGE_COLOR_CLASSES,
6
- COLUMN_COLOR_CLASSES,
7
- COLUMN_WEIGHT_CLASSES,
8
- } from '../constants.js'
9
- import { resolveIcon } from '../helpers.js'
10
- import { applyColumnFormat } from '../columnFormat.js'
11
-
12
- // ─── Table cell rendering ───────────────────────────────────
13
- //
14
- // `formatCell` is the column-type dispatch (text / badge / icon /
15
- // image / color + array variants). `wrapCell` and `wrapCellList`
16
- // apply the shared text chrome (color / weight / tooltip / line-clamp /
17
- // wrap / copy-to-clipboard) so every column-type path stays consistent.
18
-
19
- /** Render a cell. Honors the column's `columnType` (badge/icon/boolean/
20
- * image), built-in `format` spec, and per-row `_formatted[name]`
21
- * overrides from server-side `formatStateUsing` callbacks. */
22
- export function formatCell(
23
- value: unknown,
24
- col?: ElementMeta,
25
- row?: Record<string, unknown>,
26
- ): React.ReactNode {
27
- if (col === undefined) {
28
- // Legacy raw-value fallback for non-column callsites.
29
- if (value === null || value === undefined) return <span className="text-muted-foreground">—</span>
30
- if (value instanceof Date) return value.toLocaleString(undefined, { dateStyle: 'medium', timeStyle: 'short' })
31
- if (typeof value === 'boolean') return value ? 'Yes' : 'No'
32
- if (typeof value === 'object') return JSON.stringify(value)
33
- return String(value)
34
- }
35
-
36
- const columnType = String(col['columnType'] ?? 'text')
37
- const fallback = (col['default'] as string | undefined)
38
-
39
- // Per-row server-eval result wins over everything.
40
- const colName = String(col['name'] ?? '')
41
- const formatted = (row?.['_formatted'] as Record<string, string> | undefined)?.[colName]
42
- const richtext = (row?.['_richtextCells'] as Record<string, true> | undefined)?.[colName] === true
43
- const isBlank = value === null || value === undefined || value === ''
44
-
45
- if (formatted !== undefined && formatted !== '') {
46
- return wrapCell(formatted, col, richtext)
47
- }
48
- if (isBlank) {
49
- return <span className="text-muted-foreground">{fallback ?? '—'}</span>
50
- }
51
-
52
- switch (columnType) {
53
- case 'badge': {
54
- const map = (col['badgeColors'] as Record<string, string> | undefined) ?? {}
55
- const color = map[String(value)] ?? 'gray'
56
- const cls = BADGE_COLOR_CLASSES[color] ?? BADGE_COLOR_CLASSES['gray']
57
- return (
58
- <span className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${cls}`}>
59
- {String(value)}
60
- </span>
61
- )
62
- }
63
- case 'icon':
64
- case 'boolean': {
65
- const map = (col['iconOptions'] as Record<string, { icon: string; color?: string }> | undefined) ?? {}
66
- const opt = map[String(value)]
67
- if (!opt) return <span className="text-muted-foreground">—</span>
68
- const Icon = resolveIcon(opt.icon) ?? CircleIcon
69
- const colorClass = opt.color ? (COLUMN_COLOR_CLASSES[opt.color] ?? '') : ''
70
- return <Icon className={`size-4 inline ${colorClass}`} aria-label={String(value)} />
71
- }
72
- case 'image': {
73
- const url = String(value)
74
- const size = (col['imageSize'] as number | undefined) ?? 32
75
- const shape = col['imageShape'] === 'circle' ? 'rounded-full' : 'rounded-md'
76
- return (
77
- <img
78
- src={url}
79
- alt=""
80
- width={size}
81
- height={size}
82
- className={`${shape} object-cover`}
83
- />
84
- )
85
- }
86
- case 'color': {
87
- const css = String(value)
88
- const shape = col['colorShape'] as 'rounded' | 'square' | 'circle' | undefined
89
- const shapeClass =
90
- shape === 'circle' ? 'rounded-full' :
91
- shape === 'square' ? 'rounded-none' : 'rounded'
92
- const hideValue = col['colorHideValue'] === true
93
- return (
94
- <span className="inline-flex items-center gap-2">
95
- <span
96
- className={`size-4 border border-border ${shapeClass}`}
97
- style={{ backgroundColor: css }}
98
- aria-hidden="true"
99
- />
100
- {!hideValue && <span className="text-sm">{css}</span>}
101
- </span>
102
- )
103
- }
104
- default: {
105
- // Array-valued cells — `bulleted()` wins over `listWithLineBreaks()`
106
- // when both are set. Falls through to the standard string path for
107
- // non-array values so the per-cell formatters keep working.
108
- if (Array.isArray(value)) {
109
- const items = value.map(v => String(v))
110
- if (col['bulleted'] === true) {
111
- return wrapCellList(items, col, 'bulleted')
112
- }
113
- if (col['listWithLineBreaks'] === true) {
114
- return wrapCellList(items, col, 'lines')
115
- }
116
- // Bare array — comma-join (matches the existing legacy fallback).
117
- return wrapCell(items.join(', '), col)
118
- }
119
- // Text column — apply built-in format, then wrapper.
120
- const fmt = col['format'] as { kind: string; [k: string]: unknown } | undefined
121
- const display = fmt ? applyColumnFormat(value, fmt) : String(value)
122
- return wrapCell(display, col)
123
- }
124
- }
125
- }
126
-
127
- /** Apply text-rendering chrome (color, weight, line-clamp, wrap, tooltip)
128
- * to a stringified cell value. Used by the text and per-row formatter
129
- * paths so styling stays consistent. When `asHtml` is true the content
130
- * is server-rendered HTML (e.g. from the registered richtext renderer)
131
- * and gets injected via `dangerouslySetInnerHTML`. */
132
- function wrapCell(content: string, col: ElementMeta, asHtml = false): React.ReactNode {
133
- const color = col['color'] as string | undefined
134
- const weight = col['weight'] as string | undefined
135
- const tooltip = col['tooltip'] as string | undefined
136
- const wrapping = Boolean(col['wrap'])
137
- const clamp = col['lineClamp'] as number | undefined
138
- const copyMsg = col['copyMessage'] as string | undefined
139
-
140
- const colorCls = color ? (COLUMN_COLOR_CLASSES[color] ?? '') : ''
141
- const weightCls = weight ? (COLUMN_WEIGHT_CLASSES[weight] ?? '') : ''
142
- const wrapCls = wrapping ? 'whitespace-normal' : ''
143
- const clampStyle = clamp !== undefined
144
- ? { display: '-webkit-box', WebkitLineClamp: String(clamp), WebkitBoxOrient: 'vertical' as const, overflow: 'hidden' }
145
- : undefined
146
-
147
- const valueNode = asHtml
148
- ? (
149
- <span
150
- className={`prose prose-sm max-w-none dark:prose-invert ${colorCls} ${weightCls} ${wrapCls}`.trim()}
151
- title={tooltip}
152
- style={clampStyle}
153
- dangerouslySetInnerHTML={{ __html: content }}
154
- />
155
- )
156
- : (
157
- <span
158
- className={`${colorCls} ${weightCls} ${wrapCls}`.trim()}
159
- title={tooltip}
160
- style={clampStyle}
161
- >
162
- {content}
163
- </span>
164
- )
165
-
166
- if (copyMsg === undefined) return valueNode
167
-
168
- // Copy-to-clipboard trigger — copies the rendered text. For richtext
169
- // cells the underlying source isn't separately stamped on the wire
170
- // (would double the row payload), so the rendered HTML is what gets
171
- // copied; admins comfortable with HTML still get something usable.
172
- return (
173
- <span className="inline-flex items-center gap-1.5">
174
- {valueNode}
175
- <CellCopyButton text={content} label={copyMsg} />
176
- </span>
177
- )
178
- }
179
-
180
- /** Tabular-list rendering used by `Column.bulleted()` /
181
- * `Column.listWithLineBreaks()`. `mode='bulleted'` mounts a `<ul>` with
182
- * bullet markers; `mode='lines'` separates entries with `<br>`. Both
183
- * inherit the same color / weight / wrap / tooltip / clamp chrome as
184
- * the text path. Empty arrays fall through to the muted dash. */
185
- function wrapCellList(
186
- items: string[],
187
- col: ElementMeta,
188
- mode: 'bulleted' | 'lines',
189
- ): React.ReactNode {
190
- if (items.length === 0) {
191
- const fallback = (col['default'] as string | undefined) ?? '—'
192
- return <span className="text-muted-foreground">{fallback}</span>
193
- }
194
- const color = col['color'] as string | undefined
195
- const weight = col['weight'] as string | undefined
196
- const tooltip = col['tooltip'] as string | undefined
197
-
198
- const colorCls = color ? (COLUMN_COLOR_CLASSES[color] ?? '') : ''
199
- const weightCls = weight ? (COLUMN_WEIGHT_CLASSES[weight] ?? '') : ''
200
-
201
- if (mode === 'bulleted') {
202
- return (
203
- <ul
204
- className={`list-disc pl-4 space-y-0.5 ${colorCls} ${weightCls}`.trim()}
205
- title={tooltip}
206
- >
207
- {items.map((s, i) => <li key={i}>{s}</li>)}
208
- </ul>
209
- )
210
- }
211
- return (
212
- <span
213
- className={`${colorCls} ${weightCls}`.trim()}
214
- title={tooltip}
215
- >
216
- {items.map((s, i) => (
217
- <React.Fragment key={i}>
218
- {i > 0 && <br />}
219
- {s}
220
- </React.Fragment>
221
- ))}
222
- </span>
223
- )
224
- }
225
-
226
- /** Slim copy-to-clipboard button used by `Column.copyMessage()`. The
227
- * label doubles as the toast text. Mirrors `EntryCopyButton`'s shape
228
- * but compact enough to live inline next to a cell value. */
229
- function CellCopyButton({ text, label }: { text: string; label: string }): React.ReactNode {
230
- const [copied, setCopied] = useState(false)
231
- const handleClick = (e: React.MouseEvent) => {
232
- e.stopPropagation()
233
- e.preventDefault()
234
- if (typeof navigator !== 'undefined' && navigator.clipboard) {
235
- navigator.clipboard.writeText(text).then(() => {
236
- setCopied(true)
237
- setTimeout(() => setCopied(false), 1500)
238
- }).catch(() => { /* ignore — older browser / permission denied */ })
239
- }
240
- }
241
- return (
242
- <button
243
- type="button"
244
- onClick={handleClick}
245
- aria-label={copied ? label : 'Copy'}
246
- title={copied ? label : 'Copy'}
247
- data-no-row-nav
248
- className="inline-flex h-5 w-5 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-muted"
249
- >
250
- {copied ? <CheckIcon className="size-3" /> : <CopyIcon className="size-3" />}
251
- </button>
252
- )
253
- }
254
-
255
- /** Resolve a stable row identifier — prefers the row's `id` field, falls
256
- * back to the row index for rows missing one. Used as the React key
257
- * in table bodies and as the `:id` substitution for row actions. */
258
- export function rowId(row: unknown, index: number): string {
259
- if (row && typeof row === 'object' && 'id' in row) {
260
- const id = (row as { id?: unknown }).id
261
- if (id !== undefined && id !== null) return String(id)
262
- }
263
- return String(index)
264
- }
@@ -1,112 +0,0 @@
1
- import React from 'react'
2
- import type { NavigateFn } from '../../navigate.js'
3
-
4
- // ─── Inline link chrome ─────────────────────────────────────
5
- //
6
- // Three small chrome components used by the table body:
7
- // - RecordCellLink wraps each row-data cell in a real <a href> so
8
- // cmd-click / right-click "open in new tab" works; plain clicks
9
- // SPA-nav via useNavigate.
10
- // - ActiveGroupKeyChip surfaces the current `?groupKey=` drill-in
11
- // state above the table with an × that clears it.
12
- // - GroupHeadingLink turns a banded group's heading into a clickable
13
- // drill-in trigger when the group is scopable.
14
-
15
- /**
16
- * Modifier-aware SPA-nav click handler. Plain left-click intercepts to
17
- * `navigate(href)`; cmd / ctrl / shift / alt-click and middle-click
18
- * fall through to the browser so "open in new tab" / "save link as"
19
- * semantics keep working on every real `<a href>` in the table body.
20
- */
21
- export function useSpaNavClick(
22
- href: string,
23
- navigate: NavigateFn,
24
- ): (e: React.MouseEvent<HTMLAnchorElement>) => void {
25
- return (e) => {
26
- if (e.button !== 0) return
27
- if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return
28
- e.preventDefault()
29
- void navigate(href)
30
- }
31
- }
32
-
33
- export function RecordCellLink({
34
- href, navigate, children,
35
- }: {
36
- href: string
37
- navigate: NavigateFn
38
- children: React.ReactNode
39
- }) {
40
- const onClick = useSpaNavClick(href, navigate)
41
- return (
42
- <a
43
- href={href}
44
- onClick={onClick}
45
- className="block px-2 py-2 text-inherit no-underline hover:text-inherit focus:outline-none focus-visible:ring-2 focus-visible:ring-ring rounded"
46
- >
47
- {children}
48
- </a>
49
- )
50
- }
51
-
52
- /**
53
- * "Drilled into <Label>: <Value>" chip above the table when a group
54
- * heading has been clicked. The × clears `?<prefix>groupKey=`, returning
55
- * the table to its banded view. Real `<a href>` with `useNavigate()`
56
- * intercept on plain left-click so cmd-click / middle-click open a
57
- * fresh tab (rare but valid for sharing the banded view URL).
58
- */
59
- export function ActiveGroupKeyChip({
60
- label, value, displayValue, clearHref, navigate,
61
- }: {
62
- label: string
63
- value: string
64
- displayValue: string
65
- clearHref: string
66
- navigate: NavigateFn
67
- }) {
68
- const onClick = useSpaNavClick(clearHref, navigate)
69
- return (
70
- <div className="flex items-center gap-2 rounded-md border bg-muted/40 px-3 py-2 text-sm">
71
- <span className="text-muted-foreground">Drilled into</span>
72
- <span className="font-medium text-foreground">
73
- {label ? `${label}: ` : ''}{displayValue || value}
74
- </span>
75
- <a
76
- href={clearHref}
77
- onClick={onClick}
78
- aria-label="Clear drill-in"
79
- className="ms-auto text-muted-foreground hover:text-foreground"
80
- >
81
- ×
82
- </a>
83
- </div>
84
- )
85
- }
86
-
87
- /**
88
- * Group-heading text wrapped in a real `<a href>` that SPA-navs into the
89
- * drilled-in URL. Plain left-click intercepts for `useNavigate()`;
90
- * cmd/ctrl/shift-click + middle-click fall through to the browser so
91
- * "open in new tab" semantics work. Visually inherits the heading
92
- * styling — the link adds underline-on-hover affordance without
93
- * disturbing the surrounding text-transform / size.
94
- */
95
- export function GroupHeadingLink({
96
- href, navigate, children,
97
- }: {
98
- href: string
99
- navigate: NavigateFn
100
- children: React.ReactNode
101
- }) {
102
- const onClick = useSpaNavClick(href, navigate)
103
- return (
104
- <a
105
- href={href}
106
- onClick={onClick}
107
- className="inline-flex items-center gap-1 text-inherit no-underline hover:underline focus:outline-none focus-visible:ring-2 focus-visible:ring-ring rounded"
108
- >
109
- {children}
110
- </a>
111
- )
112
- }
@@ -1,52 +0,0 @@
1
- import React from 'react'
2
- import type { ElementMeta } from '../../../schema/Element.js'
3
- import type { RenderActionOptions } from '../action/buttons.js'
4
-
5
- // ─── Row-action chrome ──────────────────────────────────────
6
- //
7
- // Inline action strip mounted in the trailing cell of each table row.
8
- // Per-row visibility and disabled state come from the server-side eval
9
- // inside `dispatchTable` (`_visibleActions` / `_disabledActions` keys on
10
- // the row); we just consume the stamped allow/disallow sets here.
11
- //
12
- // The dispatch (link / fetch+JSON / modal / confirm) lives on the
13
- // action layer — `renderActionLike` is injected to keep the cycle
14
- // between this module and `SchemaRenderer.tsx`'s top-level dispatch
15
- // clean.
16
-
17
- type RenderActionLike = (el: ElementMeta, index: number, opts?: RenderActionOptions) => React.ReactNode
18
-
19
- /**
20
- * Render row actions inline. Each Action becomes a small button next to
21
- * the others; an `ActionGroup` placed in row position keeps its dropdown
22
- * via `ActionGroupTrigger` (the dropdown UX is opt-in via grouping, not
23
- * a default). The `:id` substitution comes from `opts.ids = [rowId]`.
24
- */
25
- export function renderRowActions(
26
- rowId: string,
27
- rowRecord: Record<string, unknown> | undefined,
28
- actions: ElementMeta[],
29
- renderActionLike: RenderActionLike,
30
- ): React.ReactNode {
31
- const rowVisibleSet = new Set((rowRecord?.['_visibleActions'] as string[] | undefined) ?? [])
32
- const rowDisabledSet = new Set((rowRecord?.['_disabledActions'] as string[] | undefined) ?? [])
33
-
34
- const visible = actions.filter(a => {
35
- if (!a['conditional']) return true
36
- return rowVisibleSet.has(String(a['name'] ?? ''))
37
- })
38
-
39
- const decorate = (a: ElementMeta): ElementMeta => {
40
- const name = String(a['name'] ?? '')
41
- if (rowDisabledSet.has(name)) {
42
- return { ...a, disabled: true }
43
- }
44
- return a
45
- }
46
-
47
- return (
48
- <div className="flex items-center justify-end gap-1">
49
- {visible.map((a, i) => renderActionLike(decorate(a), i, { ids: [rowId], size: 'sm' }))}
50
- </div>
51
- )
52
- }
@@ -1,143 +0,0 @@
1
- import React from 'react'
2
- import type { NavigateFn } from '../../navigate.js'
3
-
4
- // ─── Table URL helpers ──────────────────────────────────────
5
- //
6
- // The table renderer mirrors its current sort / search / page / group
7
- // state to the URL query string. These helpers build / parse / dedupe
8
- // that slice without dragging the server-side dispatcher into the
9
- // client bundle.
10
-
11
- export interface TableUrlState {
12
- search?: string
13
- sort?: { column: string; direction: 'asc' | 'desc' }
14
- page?: number
15
- /** Active group column for `?group=`. Empty string means an explicit
16
- * "no grouping" override (set on the URL when the user picks "None"
17
- * in the dropdown to override `defaultGroup`); `undefined` omits the
18
- * key entirely so the configured default takes over. */
19
- group?: string
20
- /** Drilled-in group key for `?groupKey=`. `undefined` omits — the
21
- * heading is banded (or no group at all); empty string explicitly
22
- * clears (used by the chip's × so a stale URL value doesn't return
23
- * via foreign-param round-trip). */
24
- groupKey?: string
25
- }
26
-
27
- // Mirror of `prefixedKey` in `elements/dispatchTable.ts`. Kept inline so
28
- // SchemaRenderer doesn't drag the server-side dispatcher into the client
29
- // bundle.
30
- export function prefixK(prefix: string | undefined, key: string): string {
31
- return prefix === undefined || prefix === '' ? key : `${prefix}_${key}`
32
- }
33
-
34
- let cachedSearchString: string | null = null
35
- let cachedSearchParams: URLSearchParams | null = null
36
-
37
- export function getCurrentSearchParams(): URLSearchParams | null {
38
- if (typeof window === 'undefined') return null
39
- const s = window.location.search
40
- if (s === cachedSearchString && cachedSearchParams) return cachedSearchParams
41
- cachedSearchString = s
42
- cachedSearchParams = new URLSearchParams(s)
43
- return cachedSearchParams
44
- }
45
-
46
- export function SearchFormHiddenInputs({ prefix }: { prefix: string | undefined }): React.ReactElement {
47
- const sp = getCurrentSearchParams()
48
- if (!sp) return <></>
49
- const searchKey = prefixK(prefix, 'search')
50
- const pageKey = prefixK(prefix, 'page')
51
- const inputs: React.ReactElement[] = []
52
- let i = 0
53
- for (const [k, v] of sp) {
54
- if (k === searchKey || k === pageKey) continue
55
- inputs.push(<input key={i++} type="hidden" name={k} value={v} />)
56
- }
57
- return <>{inputs}</>
58
- }
59
-
60
- export function buildTableQuery(
61
- state: TableUrlState,
62
- override: TableUrlState,
63
- pathname: string,
64
- filterValues: Record<string, string> = {},
65
- prefix?: string,
66
- ): string {
67
- const merged: TableUrlState = { ...state, ...override }
68
- const params = new URLSearchParams()
69
- // Foreign URL params (other tables' state, app-level params) round-trip
70
- // verbatim so this builder only ever rewrites its own slice.
71
- const currentParams = getCurrentSearchParams()
72
- if (currentParams) {
73
- const ours = new Set([
74
- prefixK(prefix, 'search'),
75
- prefixK(prefix, 'sort'),
76
- prefixK(prefix, 'page'),
77
- prefixK(prefix, 'perPage'),
78
- prefixK(prefix, 'group'),
79
- prefixK(prefix, 'groupKey'),
80
- ...Object.keys(filterValues).map(n => prefixK(prefix, n)),
81
- ])
82
- for (const [k, v] of currentParams) {
83
- if (ours.has(k)) continue
84
- params.set(k, v)
85
- }
86
- }
87
- // Carry forward active filter values so sort/pagination links don't
88
- // accidentally clear them. Filter names can't collide with reserved
89
- // keys (search/sort/page/perPage/group) — that's enforced upstream.
90
- for (const [name, val] of Object.entries(filterValues)) {
91
- if (val) params.set(prefixK(prefix, name), val)
92
- }
93
- if (merged.search) params.set(prefixK(prefix, 'search'), merged.search)
94
- if (merged.sort) params.set(prefixK(prefix, 'sort'), `${merged.sort.column}:${merged.sort.direction}`)
95
- if (merged.page && merged.page > 1) params.set(prefixK(prefix, 'page'), String(merged.page))
96
- if (merged.group !== undefined) params.set(prefixK(prefix, 'group'), merged.group)
97
- // groupKey is sparse — only writes when the override sets a non-empty
98
- // value. Drill-out (chip ×) passes `''` to clear; the foreign-param
99
- // dedupe set above already filtered the stale value out, so an empty
100
- // override produces a URL without the key.
101
- if (merged.groupKey) params.set(prefixK(prefix, 'groupKey'), merged.groupKey)
102
- const qs = params.toString()
103
- // Always anchor to a real pathname — Vike's client-side router treats
104
- // a bare `?qs` href as a fresh URL with empty pathname, which routes
105
- // to the dashboard and blanks the page during SPA navigation.
106
- const base = pathname || (typeof window !== 'undefined' ? window.location.pathname : '')
107
- return qs ? `${base}?${qs}` : (base || '#')
108
- }
109
-
110
- /**
111
- * SPA-navigate to the current URL with the filter slice patched in
112
- * place. `null` or empty-string values delete the key; non-empty values
113
- * set it. The accompanying `?page` is always cleared so users land on
114
- * the first page of the relaxed / tightened set. No-op on SSR.
115
- *
116
- * Used by every filter widget's "apply" / "clear" path (FilterSelect /
117
- * MultiSelect / DateRange / Form / QueryBuilder + ActiveFiltersBar).
118
- */
119
- export function patchFilterUrl(
120
- navigate: NavigateFn,
121
- prefix: string | undefined,
122
- patches: Record<string, string | null>,
123
- ): void {
124
- if (typeof window === 'undefined') return
125
- const url = new URL(window.location.href)
126
- for (const [name, value] of Object.entries(patches)) {
127
- const k = prefixK(prefix, name)
128
- if (value === null || value === '') url.searchParams.delete(k)
129
- else url.searchParams.set(k, value)
130
- }
131
- url.searchParams.delete(prefixK(prefix, 'page'))
132
- void navigate(url.pathname + url.search)
133
- }
134
-
135
- export function nextSortDir(
136
- current: TableUrlState['sort'],
137
- column: string,
138
- ): { column: string; direction: 'asc' | 'desc' } {
139
- if (current?.column === column) {
140
- return { column, direction: current.direction === 'asc' ? 'desc' : 'asc' }
141
- }
142
- return { column, direction: 'asc' }
143
- }
@@ -1,99 +0,0 @@
1
- import { resolveTheme } from '../../theme/resolve.js'
2
- import { generateThemeCSS } from '../../theme/generate-css.js'
3
- import type { ThemeConfig } from '../../theme/types.js'
4
-
5
- const cap = (s: string) => s.charAt(0).toUpperCase() + s.slice(1)
6
-
7
- // Fontshare overrides for fonts not on Google Fonts.
8
- const FONTSHARE_URLS: Record<string, string> = {
9
- Satoshi: 'https://api.fontshare.com/v2/css?f[]=satoshi@300,500,700&display=swap',
10
- }
11
-
12
- export function fontStylesheetUrl(family: string): string {
13
- return FONTSHARE_URLS[family]
14
- ?? `https://fonts.googleapis.com/css2?family=${family.replace(/ /g, '+')}:wght@400;500;600;700&display=swap`
15
- }
16
-
17
- /** Apply theme to parent page immediately — updates the <style> tag AND inline styles. */
18
- export function applyToParent(config: Partial<ThemeConfig>) {
19
- const merged: ThemeConfig = { preset: 'vega', ...config }
20
- const resolved = resolveTheme(merged)
21
- const css = generateThemeCSS(resolved)
22
-
23
- // Update the ThemeProvider's <style> tag so both light and dark mode vars are current
24
- const id = 'pilotiq-theme'
25
- let style = document.getElementById(id) as HTMLStyleElement | null
26
- if (!style) {
27
- style = document.createElement('style')
28
- style.id = id
29
- document.head.appendChild(style)
30
- }
31
- style.textContent = css
32
-
33
- // Also set inline styles for immediate visual feedback (overrides @layer)
34
- const root = document.documentElement
35
- const isDark = root.classList.contains('dark')
36
- const vars = isDark ? resolved.dark : resolved.light
37
-
38
- for (const [key, value] of Object.entries(vars)) {
39
- root.style.setProperty(key, value)
40
- }
41
- root.style.setProperty('--radius', resolved.radius)
42
- root.style.setProperty('--spacing', resolved.spacing)
43
- if (resolved.fontFamily?.body) {
44
- root.style.setProperty('--font-sans', resolved.fontFamily.body)
45
- root.style.setProperty('--default-font-family', resolved.fontFamily.body)
46
- }
47
- if (resolved.fontFamily?.heading) {
48
- root.style.setProperty('--font-heading', resolved.fontFamily.heading)
49
- }
50
- }
51
-
52
- /**
53
- * Apply config changes to a live preview document — patches CSS vars, font
54
- * links, mode class, and preset fingerprint text WITHOUT reloading the iframe.
55
- * Called on every config/mode change so the user's scroll position survives.
56
- */
57
- export function applyConfigToDoc(doc: Document, config: Partial<ThemeConfig>, mode: 'light' | 'dark') {
58
- const merged: ThemeConfig = { preset: 'vega', ...config }
59
- const resolved = resolveTheme(merged)
60
- const themeCSS = generateThemeCSS(resolved)
61
-
62
- // Light/dark switch — generateThemeCSS emits `.dark { ... }`, so toggling
63
- // the class on <html> picks up the right var set without a re-render.
64
- doc.documentElement.className = mode
65
-
66
- // Theme CSS — single <style id="pilotiq-theme"> we keep refilling.
67
- let style = doc.getElementById('pilotiq-theme') as HTMLStyleElement | null
68
- if (!style) {
69
- style = doc.createElement('style')
70
- style.id = 'pilotiq-theme'
71
- doc.head.appendChild(style)
72
- }
73
- style.textContent = themeCSS
74
-
75
- // Font links — diff against current set so the browser doesn't re-fetch
76
- // already-loaded stylesheets (avoids the brief FOIT on every config change).
77
- const wanted = new Set<string>()
78
- if (resolved.fonts?.body) wanted.add(resolved.fonts.body)
79
- if (resolved.fonts?.heading) wanted.add(resolved.fonts.heading)
80
- const existing = doc.querySelectorAll<HTMLLinkElement>('link[data-pilotiq-font]')
81
- const haveSet = new Set<string>()
82
- existing.forEach(link => {
83
- const family = link.dataset.pilotiqFont ?? ''
84
- if (!wanted.has(family)) link.remove()
85
- else haveSet.add(family)
86
- })
87
- for (const family of wanted) {
88
- if (haveSet.has(family)) continue
89
- const link = doc.createElement('link')
90
- link.rel = 'stylesheet'
91
- link.href = fontStylesheetUrl(family)
92
- link.dataset.pilotiqFont = family
93
- doc.head.appendChild(link)
94
- }
95
-
96
- // Preset fingerprint heading — only piece of body text that depends on config.
97
- const fp = doc.getElementById('preset-fingerprint')
98
- if (fp) fp.textContent = `${cap(config.preset ?? 'vega')} - ${resolved.fonts?.heading ?? 'System'}`
99
- }