@pilotiq/pilotiq 0.24.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 (480) hide show
  1. package/CHANGELOG.md +33 -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/package.json +6 -1
  15. package/.turbo/turbo-build.log +0 -8
  16. package/CLAUDE.md +0 -265
  17. package/src/Cluster.test.ts +0 -283
  18. package/src/Cluster.ts +0 -83
  19. package/src/Column.test.ts +0 -199
  20. package/src/Column.ts +0 -710
  21. package/src/Global.test.ts +0 -367
  22. package/src/Global.ts +0 -169
  23. package/src/Page.test.ts +0 -114
  24. package/src/Page.ts +0 -208
  25. package/src/Pilotiq.perf.test.ts +0 -252
  26. package/src/Pilotiq.test.ts +0 -129
  27. package/src/Pilotiq.ts +0 -1158
  28. package/src/PilotiqRegistry.ts +0 -36
  29. package/src/PilotiqServiceProvider.ts +0 -121
  30. package/src/RelationManager.test.ts +0 -400
  31. package/src/RelationManager.ts +0 -527
  32. package/src/RenderHook.test.ts +0 -252
  33. package/src/RenderHook.ts +0 -242
  34. package/src/Resource.test.ts +0 -284
  35. package/src/Resource.ts +0 -526
  36. package/src/RightPanel.test.ts +0 -202
  37. package/src/RightPanel.ts +0 -132
  38. package/src/Tab.test.ts +0 -91
  39. package/src/Tab.ts +0 -156
  40. package/src/UserMenuItem.ts +0 -145
  41. package/src/actions/Action.test.ts +0 -2526
  42. package/src/actions/Action.ts +0 -1515
  43. package/src/actions/ActionGroup.test.ts +0 -112
  44. package/src/actions/ActionGroup.ts +0 -173
  45. package/src/actions/attachFactory.ts +0 -172
  46. package/src/actions/bulkFactories.ts +0 -168
  47. package/src/actions/crudFactories.ts +0 -220
  48. package/src/actions/exportFactory.ts +0 -225
  49. package/src/actions/factoryHelpers.ts +0 -177
  50. package/src/actions/importFactory.ts +0 -243
  51. package/src/actions/index.ts +0 -17
  52. package/src/actions/m2mFactories.ts +0 -193
  53. package/src/actions/relationFactories.ts +0 -372
  54. package/src/applyPageHooks.test.ts +0 -463
  55. package/src/applyPageHooks.ts +0 -330
  56. package/src/authorization.test.ts +0 -483
  57. package/src/breadcrumbs.test.ts +0 -238
  58. package/src/cells/coerce.test.ts +0 -85
  59. package/src/cells/coerce.ts +0 -84
  60. package/src/clusterPaths.ts +0 -35
  61. package/src/columns/BadgeColumn.test.ts +0 -54
  62. package/src/columns/BadgeColumn.ts +0 -32
  63. package/src/columns/BooleanColumn.test.ts +0 -41
  64. package/src/columns/BooleanColumn.ts +0 -18
  65. package/src/columns/ColorColumn.test.ts +0 -37
  66. package/src/columns/ColorColumn.ts +0 -38
  67. package/src/columns/IconColumn.test.ts +0 -54
  68. package/src/columns/IconColumn.ts +0 -37
  69. package/src/columns/ImageColumn.test.ts +0 -41
  70. package/src/columns/ImageColumn.ts +0 -28
  71. package/src/columns/SelectColumn.ts +0 -98
  72. package/src/columns/TextColumn.test.ts +0 -190
  73. package/src/columns/TextColumn.ts +0 -20
  74. package/src/columns/TextInputColumn.ts +0 -68
  75. package/src/columns/ToggleColumn.ts +0 -46
  76. package/src/columns/editableColumns.test.ts +0 -238
  77. package/src/columns/index.ts +0 -9
  78. package/src/defaultGlobalPages.ts +0 -95
  79. package/src/defaultPages.test.ts +0 -634
  80. package/src/defaultPages.ts +0 -617
  81. package/src/defaultViewPage.test.ts +0 -147
  82. package/src/elements/Form.test.ts +0 -223
  83. package/src/elements/Form.ts +0 -416
  84. package/src/elements/ListTabs.ts +0 -28
  85. package/src/elements/Table.test.ts +0 -422
  86. package/src/elements/Table.ts +0 -850
  87. package/src/elements/TableGroup.test.ts +0 -260
  88. package/src/elements/TableGroup.ts +0 -334
  89. package/src/elements/dispatchAction.test.ts +0 -463
  90. package/src/elements/dispatchAction.ts +0 -355
  91. package/src/elements/dispatchForm.test.ts +0 -477
  92. package/src/elements/dispatchForm.ts +0 -1993
  93. package/src/elements/dispatchTable.test.ts +0 -1514
  94. package/src/elements/dispatchTable.ts +0 -745
  95. package/src/elements/index.ts +0 -21
  96. package/src/entries/BadgeEntry.ts +0 -39
  97. package/src/entries/CodeEntry.test.ts +0 -40
  98. package/src/entries/CodeEntry.ts +0 -52
  99. package/src/entries/ColorEntry.ts +0 -63
  100. package/src/entries/ComponentEntry.test.ts +0 -173
  101. package/src/entries/ComponentEntry.ts +0 -95
  102. package/src/entries/Entry.ts +0 -304
  103. package/src/entries/IconEntry.ts +0 -49
  104. package/src/entries/ImageEntry.ts +0 -61
  105. package/src/entries/KeyValueEntry.ts +0 -47
  106. package/src/entries/RepeatableEntry.test.ts +0 -239
  107. package/src/entries/RepeatableEntry.ts +0 -173
  108. package/src/entries/TextEntry.test.ts +0 -394
  109. package/src/entries/TextEntry.ts +0 -60
  110. package/src/entries/index.ts +0 -12
  111. package/src/entries/leaves.test.ts +0 -306
  112. package/src/entries/registry.ts +0 -54
  113. package/src/fields/BuilderField.test.ts +0 -1188
  114. package/src/fields/BuilderField.ts +0 -605
  115. package/src/fields/BuilderRelationship.test.ts +0 -811
  116. package/src/fields/CheckboxField.test.ts +0 -44
  117. package/src/fields/CheckboxField.ts +0 -27
  118. package/src/fields/CheckboxListField.test.ts +0 -99
  119. package/src/fields/CheckboxListField.ts +0 -66
  120. package/src/fields/ColorPickerField.test.ts +0 -33
  121. package/src/fields/ColorPickerField.ts +0 -25
  122. package/src/fields/DateField.ts +0 -54
  123. package/src/fields/DateTimeField.test.ts +0 -55
  124. package/src/fields/EmailField.ts +0 -16
  125. package/src/fields/Field.test.ts +0 -654
  126. package/src/fields/Field.ts +0 -817
  127. package/src/fields/FileUploadField.test.ts +0 -143
  128. package/src/fields/FileUploadField.ts +0 -159
  129. package/src/fields/HiddenField.test.ts +0 -27
  130. package/src/fields/HiddenField.ts +0 -28
  131. package/src/fields/KeyValueField.test.ts +0 -105
  132. package/src/fields/KeyValueField.ts +0 -55
  133. package/src/fields/MarkdownField.test.ts +0 -167
  134. package/src/fields/MarkdownField.ts +0 -162
  135. package/src/fields/NumberField.ts +0 -33
  136. package/src/fields/RadioField.test.ts +0 -94
  137. package/src/fields/RadioField.ts +0 -67
  138. package/src/fields/RepeaterField.test.ts +0 -1806
  139. package/src/fields/RepeaterField.ts +0 -939
  140. package/src/fields/RepeaterRelationship.test.ts +0 -1923
  141. package/src/fields/RepeaterSimple.test.ts +0 -248
  142. package/src/fields/RowButton.test.ts +0 -219
  143. package/src/fields/RowButton.ts +0 -135
  144. package/src/fields/SelectField.test.ts +0 -192
  145. package/src/fields/SelectField.ts +0 -235
  146. package/src/fields/SliderField.test.ts +0 -50
  147. package/src/fields/SliderField.ts +0 -53
  148. package/src/fields/SlugField.ts +0 -24
  149. package/src/fields/TagsInputField.test.ts +0 -154
  150. package/src/fields/TagsInputField.ts +0 -133
  151. package/src/fields/TextField.test.ts +0 -213
  152. package/src/fields/TextField.ts +0 -177
  153. package/src/fields/TextareaField.test.ts +0 -58
  154. package/src/fields/TextareaField.ts +0 -59
  155. package/src/fields/ToggleButtonsField.test.ts +0 -106
  156. package/src/fields/ToggleButtonsField.ts +0 -59
  157. package/src/fields/ToggleField.ts +0 -16
  158. package/src/fields/disableOptionsWhenSelectedInSiblingRepeaterItems.test.ts +0 -319
  159. package/src/fields/optionsResolver.ts +0 -95
  160. package/src/fields/resolveField.ts +0 -28
  161. package/src/filters/BooleanFilter.ts +0 -35
  162. package/src/filters/DateRangeFilter.test.ts +0 -194
  163. package/src/filters/DateRangeFilter.ts +0 -148
  164. package/src/filters/Filter.test.ts +0 -268
  165. package/src/filters/Filter.ts +0 -184
  166. package/src/filters/FormFilter.test.ts +0 -238
  167. package/src/filters/FormFilter.ts +0 -215
  168. package/src/filters/MultiSelectFilter.test.ts +0 -119
  169. package/src/filters/MultiSelectFilter.ts +0 -78
  170. package/src/filters/QueryBuilderFilter.test.ts +0 -662
  171. package/src/filters/QueryBuilderFilter.ts +0 -398
  172. package/src/filters/SelectFilter.ts +0 -46
  173. package/src/filters/TernaryFilter.test.ts +0 -160
  174. package/src/filters/TernaryFilter.ts +0 -72
  175. package/src/filters/TrashedFilter.test.ts +0 -149
  176. package/src/filters/TrashedFilter.ts +0 -55
  177. package/src/filters/queryBuilder/BooleanConstraint.ts +0 -31
  178. package/src/filters/queryBuilder/Constraint.ts +0 -115
  179. package/src/filters/queryBuilder/DateConstraint.ts +0 -69
  180. package/src/filters/queryBuilder/NumberConstraint.ts +0 -66
  181. package/src/filters/queryBuilder/SelectConstraint.ts +0 -72
  182. package/src/filters/queryBuilder/TextConstraint.ts +0 -64
  183. package/src/filters/queryBuilder/index.ts +0 -12
  184. package/src/icons/index.ts +0 -2
  185. package/src/icons/lucide.ts +0 -204
  186. package/src/icons/registry.test.ts +0 -56
  187. package/src/icons/registry.ts +0 -41
  188. package/src/icons/types.ts +0 -47
  189. package/src/index.ts +0 -525
  190. package/src/io/csv.test.ts +0 -142
  191. package/src/io/csv.ts +0 -170
  192. package/src/nestedRelationManagerData.test.ts +0 -547
  193. package/src/notifications/Notification.test.ts +0 -210
  194. package/src/notifications/Notification.ts +0 -354
  195. package/src/notifications/broadcast.test.ts +0 -110
  196. package/src/notifications/broadcast.ts +0 -95
  197. package/src/notifications/database.test.ts +0 -383
  198. package/src/notifications/database.ts +0 -398
  199. package/src/notifications/databaseNotifications.test.ts +0 -187
  200. package/src/notifications/dispatchNotificationAction.test.ts +0 -341
  201. package/src/notifications/dispatchNotificationAction.ts +0 -142
  202. package/src/notifications/flash.test.ts +0 -89
  203. package/src/notifications/flash.ts +0 -71
  204. package/src/notifications/index.ts +0 -45
  205. package/src/notifications/registerBroadcastAuth.test.ts +0 -134
  206. package/src/notifications/registerBroadcastAuth.ts +0 -100
  207. package/src/notifications/resolveSavedNotification.test.ts +0 -82
  208. package/src/notifications/resolveSavedNotification.ts +0 -59
  209. package/src/notifications/types.ts +0 -93
  210. package/src/orm/m2mAccessor.ts +0 -66
  211. package/src/orm/modelDefaults.test.ts +0 -633
  212. package/src/orm/modelDefaults.ts +0 -666
  213. package/src/pageData/breadcrumbs.ts +0 -288
  214. package/src/pageData/forms.ts +0 -578
  215. package/src/pageData/helpers.ts +0 -857
  216. package/src/pageData/misc.ts +0 -347
  217. package/src/pageData/navigation.ts +0 -842
  218. package/src/pageData/relationPages.ts +0 -1248
  219. package/src/pageData/relationTabs.ts +0 -286
  220. package/src/pageData/resourcePages.ts +0 -609
  221. package/src/pageData.test.ts +0 -1545
  222. package/src/pageData.ts +0 -341
  223. package/src/plugins/index.ts +0 -8
  224. package/src/plugins/themeEditor.test.ts +0 -36
  225. package/src/plugins/themeEditor.ts +0 -45
  226. package/src/react/AppShell.tsx +0 -251
  227. package/src/react/CollabExtensionFactoryRegistry.ts +0 -55
  228. package/src/react/CollabRoomContext.ts +0 -98
  229. package/src/react/CollabTextRendererRegistry.ts +0 -102
  230. package/src/react/CommandPalette.tsx +0 -375
  231. package/src/react/CurrentUserContext.tsx +0 -50
  232. package/src/react/CustomPageWrapperGate.tsx +0 -69
  233. package/src/react/CustomPageWrapperRegistry.ts +0 -45
  234. package/src/react/FieldFocusReporterRegistry.ts +0 -37
  235. package/src/react/FieldLabelSlotRegistry.ts +0 -30
  236. package/src/react/FieldPresenceRegistry.ts +0 -46
  237. package/src/react/FormCollabBindingRegistry.ts +0 -242
  238. package/src/react/FormStateContext.tsx +0 -591
  239. package/src/react/HeadHooks.tsx +0 -126
  240. package/src/react/MarkdownEditorRegistry.test.ts +0 -38
  241. package/src/react/MarkdownEditorRegistry.ts +0 -107
  242. package/src/react/NotificationActionStrip.tsx +0 -263
  243. package/src/react/NotificationBell.tsx +0 -426
  244. package/src/react/PendingSuggestionApplierRegistry.test.ts +0 -97
  245. package/src/react/PendingSuggestionApplierRegistry.ts +0 -98
  246. package/src/react/PendingSuggestionOverlayRegistry.ts +0 -54
  247. package/src/react/PendingSuggestionsContext.tsx +0 -172
  248. package/src/react/RecordWrapperGate.tsx +0 -58
  249. package/src/react/RecordWrapperRegistry.ts +0 -39
  250. package/src/react/RenderHookSlot.tsx +0 -32
  251. package/src/react/RightSidebar.tsx +0 -257
  252. package/src/react/RightSidebarContext.tsx +0 -234
  253. package/src/react/RightSidebarTrigger.tsx +0 -53
  254. package/src/react/RowCoordsContext.tsx +0 -23
  255. package/src/react/SchemaRenderer.tsx +0 -549
  256. package/src/react/SearchTrigger.tsx +0 -46
  257. package/src/react/ThemeProvider.tsx +0 -93
  258. package/src/react/ThemeSettingsPage.tsx +0 -579
  259. package/src/react/ThemeToggle.tsx +0 -20
  260. package/src/react/Toaster.tsx +0 -158
  261. package/src/react/UserMenu.tsx +0 -196
  262. package/src/react/WidgetDataContext.tsx +0 -157
  263. package/src/react/cells/EditableCell.tsx +0 -389
  264. package/src/react/component-slots.test.ts +0 -103
  265. package/src/react/component-slots.ts +0 -116
  266. package/src/react/fieldJsHandler.test.ts +0 -166
  267. package/src/react/fieldJsHandler.ts +0 -79
  268. package/src/react/fields/BuilderInput.tsx +0 -1078
  269. package/src/react/fields/CheckboxInput.tsx +0 -39
  270. package/src/react/fields/CheckboxListInput.tsx +0 -102
  271. package/src/react/fields/ColorInput.tsx +0 -71
  272. package/src/react/fields/DateFieldInput.tsx +0 -70
  273. package/src/react/fields/DateTimeInput.tsx +0 -62
  274. package/src/react/fields/FieldShell.tsx +0 -348
  275. package/src/react/fields/FileUploadInput.tsx +0 -639
  276. package/src/react/fields/HiddenInput.tsx +0 -17
  277. package/src/react/fields/KeyValueInput.tsx +0 -230
  278. package/src/react/fields/MarkdownInput.tsx +0 -560
  279. package/src/react/fields/RadioInput.tsx +0 -81
  280. package/src/react/fields/RepeaterInput.test.ts +0 -116
  281. package/src/react/fields/RepeaterInput.tsx +0 -1420
  282. package/src/react/fields/SelectFieldInput.tsx +0 -280
  283. package/src/react/fields/SliderInput.tsx +0 -81
  284. package/src/react/fields/TagsInput.tsx +0 -283
  285. package/src/react/fields/TextLikeInput.tsx +0 -256
  286. package/src/react/fields/ToggleButtonsInput.tsx +0 -60
  287. package/src/react/fields/ToggleFieldInput.tsx +0 -56
  288. package/src/react/fields/relationshipRenameDispatch.test.ts +0 -106
  289. package/src/react/fields/relationshipRenameDispatch.ts +0 -97
  290. package/src/react/fields/repeaterReconcile.test.ts +0 -114
  291. package/src/react/fields/repeaterReconcile.ts +0 -104
  292. package/src/react/fields/rowChromeButton.tsx +0 -336
  293. package/src/react/fields/rowState.ts +0 -106
  294. package/src/react/fields/syncRowGates.test.ts +0 -202
  295. package/src/react/fields/syncRowGates.ts +0 -66
  296. package/src/react/fields/textInputControls.tsx +0 -238
  297. package/src/react/fields/useRowReorderDnd.ts +0 -78
  298. package/src/react/formStateHelpers.test.ts +0 -508
  299. package/src/react/formStateHelpers.ts +0 -381
  300. package/src/react/hooks/use-mobile.ts +0 -19
  301. package/src/react/icon-context.tsx +0 -60
  302. package/src/react/index.ts +0 -194
  303. package/src/react/layouts/SidebarLayout.tsx +0 -250
  304. package/src/react/layouts/TopbarLayout.tsx +0 -258
  305. package/src/react/navigate.tsx +0 -37
  306. package/src/react/onProviderSynced.test.ts +0 -90
  307. package/src/react/parseRecordEditUrl.test.ts +0 -122
  308. package/src/react/parseRecordEditUrl.ts +0 -94
  309. package/src/react/persistedState.ts +0 -40
  310. package/src/react/registry.ts +0 -48
  311. package/src/react/right-panel-registry.tsx +0 -47
  312. package/src/react/schemaRenderer/AlertRenderer.tsx +0 -112
  313. package/src/react/schemaRenderer/EntryRenderer.tsx +0 -501
  314. package/src/react/schemaRenderer/SectionRenderer.tsx +0 -120
  315. package/src/react/schemaRenderer/SimpleElements.tsx +0 -306
  316. package/src/react/schemaRenderer/TabsRenderer.tsx +0 -62
  317. package/src/react/schemaRenderer/WizardRenderer.tsx +0 -338
  318. package/src/react/schemaRenderer/action/ActionGroupTrigger.tsx +0 -177
  319. package/src/react/schemaRenderer/action/ActionModalDialog.tsx +0 -273
  320. package/src/react/schemaRenderer/action/ConfirmActionDialog.tsx +0 -61
  321. package/src/react/schemaRenderer/action/HandlerActionButton.tsx +0 -43
  322. package/src/react/schemaRenderer/action/MethodActionButton.tsx +0 -64
  323. package/src/react/schemaRenderer/action/buttons.tsx +0 -99
  324. package/src/react/schemaRenderer/action/helpers.ts +0 -140
  325. package/src/react/schemaRenderer/action/renderAction.tsx +0 -245
  326. package/src/react/schemaRenderer/columnFormat.ts +0 -65
  327. package/src/react/schemaRenderer/constants.ts +0 -50
  328. package/src/react/schemaRenderer/form/FormRenderer.tsx +0 -274
  329. package/src/react/schemaRenderer/form/renderField.tsx +0 -511
  330. package/src/react/schemaRenderer/helpers.tsx +0 -81
  331. package/src/react/schemaRenderer/table/CardsLayoutBody.tsx +0 -308
  332. package/src/react/schemaRenderer/table/TableRenderer.tsx +0 -123
  333. package/src/react/schemaRenderer/table/TableRendererBody.tsx +0 -974
  334. package/src/react/schemaRenderer/table/filters.tsx +0 -1233
  335. package/src/react/schemaRenderer/table/formatCell.tsx +0 -264
  336. package/src/react/schemaRenderer/table/links.tsx +0 -112
  337. package/src/react/schemaRenderer/table/renderRowActions.tsx +0 -52
  338. package/src/react/schemaRenderer/table/url.tsx +0 -143
  339. package/src/react/theme-preview/apply.ts +0 -99
  340. package/src/react/theme-preview/build-html.ts +0 -436
  341. package/src/react/ui/button.tsx +0 -51
  342. package/src/react/ui/calendar.tsx +0 -67
  343. package/src/react/ui/checkbox.tsx +0 -29
  344. package/src/react/ui/dialog.tsx +0 -108
  345. package/src/react/ui/dropdown-menu.tsx +0 -97
  346. package/src/react/ui/input.tsx +0 -20
  347. package/src/react/ui/label.tsx +0 -21
  348. package/src/react/ui/popover.tsx +0 -50
  349. package/src/react/ui/select.tsx +0 -169
  350. package/src/react/ui/separator.tsx +0 -25
  351. package/src/react/ui/sheet.tsx +0 -136
  352. package/src/react/ui/sidebar.tsx +0 -723
  353. package/src/react/ui/skeleton.tsx +0 -13
  354. package/src/react/ui/slider.tsx +0 -34
  355. package/src/react/ui/switch.tsx +0 -28
  356. package/src/react/ui/table.tsx +0 -105
  357. package/src/react/ui/tabs.tsx +0 -63
  358. package/src/react/ui/textarea.tsx +0 -18
  359. package/src/react/ui/tooltip.tsx +0 -64
  360. package/src/react/useResizableWidth.ts +0 -139
  361. package/src/react/utils.ts +0 -6
  362. package/src/react/widgetRegistry.test.ts +0 -43
  363. package/src/react/widgetRegistry.ts +0 -50
  364. package/src/react/widgets/StatsOverviewRenderer.tsx +0 -232
  365. package/src/react/widgets/TableWidgetRenderer.tsx +0 -231
  366. package/src/react/widgets/ViewRenderer.tsx +0 -71
  367. package/src/relationManagerData.test.ts +0 -1595
  368. package/src/richtext/index.ts +0 -8
  369. package/src/richtext/registry.ts +0 -89
  370. package/src/routes/globals.ts +0 -148
  371. package/src/routes/guard.test.ts +0 -325
  372. package/src/routes/helpers.ts +0 -704
  373. package/src/routes/pages.ts +0 -175
  374. package/src/routes/panel.ts +0 -204
  375. package/src/routes/relations.ts +0 -1243
  376. package/src/routes/resources.ts +0 -781
  377. package/src/routes/theme.ts +0 -91
  378. package/src/routes-nested-relations.test.ts +0 -676
  379. package/src/routes-relations.test.ts +0 -972
  380. package/src/routes.test.ts +0 -2027
  381. package/src/routes.ts +0 -303
  382. package/src/schema/Alert.test.ts +0 -109
  383. package/src/schema/Alert.ts +0 -131
  384. package/src/schema/Block.ts +0 -169
  385. package/src/schema/Breadcrumbs.ts +0 -40
  386. package/src/schema/Card.ts +0 -35
  387. package/src/schema/Divider.ts +0 -20
  388. package/src/schema/Element.ts +0 -219
  389. package/src/schema/EmptyState.test.ts +0 -37
  390. package/src/schema/EmptyState.ts +0 -63
  391. package/src/schema/Fieldset.ts +0 -43
  392. package/src/schema/Grid.ts +0 -43
  393. package/src/schema/Group.ts +0 -30
  394. package/src/schema/Heading.ts +0 -39
  395. package/src/schema/Html.ts +0 -67
  396. package/src/schema/Icon.ts +0 -54
  397. package/src/schema/Image.ts +0 -57
  398. package/src/schema/LinkTag.ts +0 -41
  399. package/src/schema/Markdown.ts +0 -85
  400. package/src/schema/MetaTag.ts +0 -41
  401. package/src/schema/RelationTabs.ts +0 -71
  402. package/src/schema/ScriptTag.ts +0 -55
  403. package/src/schema/Section.ts +0 -160
  404. package/src/schema/ServerDataElement.test.ts +0 -140
  405. package/src/schema/ServerDataElement.ts +0 -156
  406. package/src/schema/SlotComponent.test.ts +0 -77
  407. package/src/schema/SlotComponent.ts +0 -71
  408. package/src/schema/Split.ts +0 -50
  409. package/src/schema/Stat.test.ts +0 -118
  410. package/src/schema/Stat.ts +0 -154
  411. package/src/schema/StatsOverview.test.ts +0 -141
  412. package/src/schema/StatsOverview.ts +0 -119
  413. package/src/schema/StyleTag.ts +0 -35
  414. package/src/schema/TableWidget.test.ts +0 -297
  415. package/src/schema/TableWidget.ts +0 -289
  416. package/src/schema/Tabs.ts +0 -79
  417. package/src/schema/Text.ts +0 -58
  418. package/src/schema/UnorderedList.ts +0 -49
  419. package/src/schema/View.test.ts +0 -111
  420. package/src/schema/View.ts +0 -127
  421. package/src/schema/Wizard.ts +0 -220
  422. package/src/schema/containers.test.ts +0 -564
  423. package/src/schema/headTags.test.ts +0 -134
  424. package/src/schema/index.ts +0 -40
  425. package/src/schema/primes.test.ts +0 -269
  426. package/src/schema/resolveSchema.test.ts +0 -379
  427. package/src/schema/resolveSchema.ts +0 -917
  428. package/src/schema/sanitize.ts +0 -58
  429. package/src/search.test.ts +0 -446
  430. package/src/search.ts +0 -178
  431. package/src/sessionFilters.test.ts +0 -375
  432. package/src/sessionFilters.ts +0 -143
  433. package/src/slot-components/index.ts +0 -10
  434. package/src/slot-components/registry.ts +0 -56
  435. package/src/styles/file-upload.css +0 -13
  436. package/src/summarizers/Summarizer.test.ts +0 -84
  437. package/src/summarizers/Summarizer.ts +0 -123
  438. package/src/summarizers/index.ts +0 -11
  439. package/src/theme/base-colors.ts +0 -68
  440. package/src/theme/chart-colors.ts +0 -50
  441. package/src/theme/colors.ts +0 -447
  442. package/src/theme/generate-css.test.ts +0 -139
  443. package/src/theme/generate-css.ts +0 -44
  444. package/src/theme/generate-scale.test.ts +0 -106
  445. package/src/theme/generate-scale.ts +0 -97
  446. package/src/theme/icon-map.ts +0 -42
  447. package/src/theme/index.ts +0 -34
  448. package/src/theme/migrate.test.ts +0 -178
  449. package/src/theme/migrate.ts +0 -81
  450. package/src/theme/presets.ts +0 -135
  451. package/src/theme/radius.ts +0 -18
  452. package/src/theme/resolve.test.ts +0 -238
  453. package/src/theme/resolve.ts +0 -96
  454. package/src/theme/spacing.ts +0 -18
  455. package/src/theme/storage.test.ts +0 -126
  456. package/src/theme/storage.ts +0 -106
  457. package/src/theme/theme-colors.ts +0 -88
  458. package/src/theme/types.ts +0 -125
  459. package/src/uploads/UploadAdapter.ts +0 -35
  460. package/src/uploads/index.ts +0 -2
  461. package/src/uploads/localUpload.test.ts +0 -70
  462. package/src/uploads/localUpload.ts +0 -84
  463. package/src/validation/Validator.ts +0 -49
  464. package/src/validation/index.ts +0 -28
  465. package/src/validation/rules.ts +0 -78
  466. package/src/validation/runValidators.ts +0 -435
  467. package/src/validation/uniqueValidator.test.ts +0 -196
  468. package/src/validation/uniqueValidator.ts +0 -133
  469. package/src/validation/validators.test.ts +0 -268
  470. package/src/vite.test.ts +0 -184
  471. package/src/vite.ts +0 -787
  472. package/src/widgets/index.ts +0 -10
  473. package/src/widgets/registry.ts +0 -45
  474. package/src/widgets.test.ts +0 -592
  475. package/tsconfig.build.json +0 -11
  476. package/tsconfig.json +0 -4
  477. package/tsconfig.test.json +0 -10
  478. package/views/react/Dashboard.tsx +0 -27
  479. package/views/react/Resources/Form.tsx +0 -102
  480. 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
- }