@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,55 +0,0 @@
1
- /**
2
- * Module-level registry slot for the Tiptap extension factory that turns
3
- * a collab room into editor-attachable extensions (`Collaboration` +
4
- * `CollaborationCursor`).
5
- *
6
- * Wiring posture (mirrors `PendingSuggestionOverlayRegistry`):
7
- * - `@pilotiq-pro/collab`'s plugin calls `registerCollabExtensions(...)`
8
- * once at boot from inside `register(panel)`. The factory closes over
9
- * the `@tiptap/extension-collaboration` + `-cursor` imports, so pilotiq
10
- * core (and `@pilotiq/tiptap`) never carry those as peer deps.
11
- * - `@pilotiq/tiptap`'s `TiptapEditor` calls `getCollabExtensions()` at
12
- * mount; if non-null AND a `useCollabRoom()` value is present, it calls
13
- * the factory and spreads the returned array into the editor's
14
- * `extensions` slot. If either is missing, plain Tiptap + History runs.
15
- *
16
- * `unknown[]` return type is deliberate — pilotiq core has zero `@tiptap/*`
17
- * imports and treats the returned values as opaque editor-extension refs.
18
- * The Tiptap host trusts them and spreads them in.
19
- */
20
- export interface CollabExtensionFactoryArgs {
21
- /** `Y.Doc` for the surrounding record. Opaque to pilotiq core. */
22
- ydoc: unknown
23
- /** `WebsocketProvider` for the same room. Opaque to pilotiq core. */
24
- provider: unknown
25
- /**
26
- * Field name — becomes the `Y.XmlFragment` selector
27
- * (`Collaboration.configure({ field: fieldName })`) so multiple
28
- * collab editors on the same record write to distinct fragments
29
- * inside one shared ydoc.
30
- */
31
- fieldName: string
32
- /** Presence info forwarded to `CollaborationCursor`. Sparse. */
33
- user?: {
34
- name?: string
35
- color?: string
36
- }
37
- }
38
-
39
- export type CollabExtensionFactory = (args: CollabExtensionFactoryArgs) => unknown[]
40
-
41
- let _factory: CollabExtensionFactory | null = null
42
-
43
- /**
44
- * Register the factory that builds collab extensions for one field +
45
- * room. Called once at boot by `@pilotiq-pro/collab`'s plugin. No-op when
46
- * no plugin registers — Tiptap renderers fall back to plain editing.
47
- */
48
- export function registerCollabExtensions(factory: CollabExtensionFactory): void {
49
- _factory = factory
50
- }
51
-
52
- /** Returns the registered factory, or `null`. */
53
- export function getCollabExtensions(): CollabExtensionFactory | null {
54
- return _factory
55
- }
@@ -1,98 +0,0 @@
1
- import { createContext, useContext } from 'react'
2
-
3
- /**
4
- * Per-record realtime-collab room — a Y.Doc plus its WebsocketProvider,
5
- * shared across every collaborative field in the same form. Mirrors the
6
- * Tiptap "Collaborative Fields" pattern: one ydoc per record, each editor
7
- * scopes itself to its own `Y.XmlFragment` via the field's `name`.
8
- *
9
- * Pilotiq core does NOT instantiate the room — implementation lives in
10
- * `@pilotiq-pro/collab`, which mounts the context with real Yjs values
11
- * via `<RecordCollabRoom>`. Core just owns the shape so any field
12
- * renderer (Tiptap, in-house, third-party) can subscribe through one
13
- * open-core seam without taking a hard peer dep on Yjs.
14
- *
15
- * `ydoc` and `provider` are typed `unknown` deliberately — the consumer
16
- * (typically `@pilotiq/tiptap`) hands them straight to a registered
17
- * `CollabExtensionFactory` and never touches them directly, so pilotiq
18
- * core stays Yjs-free.
19
- */
20
- export interface CollabRoom {
21
- /** `Y.Doc` instance. Opaque to pilotiq core. */
22
- ydoc: unknown
23
- /** `WebsocketProvider` instance. Opaque to pilotiq core. */
24
- provider: unknown
25
- /**
26
- * Resolves on the provider's first sync. Present when the room is
27
- * wired through `@rudderjs/sync/react`'s `useCollabRoom` (which is
28
- * what `@pilotiq-pro/collab@>=0.2`'s `<RecordCollabRoom>` does);
29
- * absent for legacy / hand-rolled providers. Threaded into the
30
- * framework's `useCollabSeed` / `useCollabSeedText` (from
31
- * `@rudderjs/sync/react`) so adapters can gate seed callbacks on
32
- * first sync without calling `onProviderSynced` directly.
33
- */
34
- synced?: Promise<void>
35
- /** IndexedDB persistence handle, when the room wraps `y-indexeddb`. Opaque. */
36
- persistence?: unknown
37
- /** Presence info for cursors / avatars. Forwarded to the extension factory. */
38
- user?: {
39
- name?: string
40
- color?: string
41
- }
42
- }
43
-
44
- /**
45
- * `null` default — fields read the context, and a null result means
46
- * "no collab room mounted, fall back to local-only editing." This is
47
- * the 99% case (collab plugin not installed).
48
- */
49
- export const CollabRoomContext = createContext<CollabRoom | null>(null)
50
-
51
- /** Read the active collab room for the surrounding record, or `null`. */
52
- export function useCollabRoom(): CollabRoom | null {
53
- return useContext(CollabRoomContext)
54
- }
55
-
56
- /**
57
- * Minimal structural shape every collab provider exposes for the
58
- * "initial room state has streamed in" signal. Kept structural so callers
59
- * (`@pilotiq/tiptap`, `@pilotiq/codemirror`, future adapters) can pass
60
- * `provider as unknown as SyncedProviderLike` without taking a hard peer
61
- * dep on yjs / y-websocket / y-webrtc.
62
- */
63
- export interface SyncedProviderLike {
64
- synced?: boolean
65
- once?(event: 'synced', fn: () => void): void
66
- off?(event: 'synced', fn: () => void): void
67
- }
68
-
69
- const NOOP_CLEANUP = (): void => {}
70
-
71
- /**
72
- * Run `fn` once the collab provider's initial room state has streamed in.
73
- * If the provider is already synced, `fn` fires synchronously; otherwise
74
- * it's registered via `provider.once('synced', fn)`. The returned cleanup
75
- * unregisters the once handler safely (idempotent + try/catch) so callers
76
- * can wire it directly into a React effect's cleanup return.
77
- *
78
- * Useful for the brand-new-record seed pattern: editors mounting against
79
- * a freshly-created record want to push the SSR-rendered default into
80
- * the empty `Y.Text` / `Y.XmlFragment` exactly once after sync, before
81
- * the user types. Race caveat: two peers simultaneously mounting against
82
- * a brand-new record can both see `length === 0` and both seed —
83
- * accepted today across every adapter's seed path.
84
- */
85
- export function onProviderSynced(
86
- provider: SyncedProviderLike | null | undefined,
87
- fn: () => void,
88
- ): () => void {
89
- if (!provider) return NOOP_CLEANUP
90
- if (provider.synced) {
91
- fn()
92
- return NOOP_CLEANUP
93
- }
94
- provider.once?.('synced', fn)
95
- return () => {
96
- try { provider.off?.('synced', fn) } catch { /* ignore */ }
97
- }
98
- }
@@ -1,102 +0,0 @@
1
- import type { ComponentType } from 'react'
2
-
3
- /**
4
- * Module-level registry slot for the collab-aware plain-text editor renderer.
5
- *
6
- * Wiring posture (mirrors `CollabExtensionFactoryRegistry` /
7
- * `FormCollabBindingRegistry`):
8
- * - `@pilotiq/tiptap`'s `registerTiptap(...)` calls `registerCollabTextRenderer(...)`
9
- * once at boot. The registered component closes over `@tiptap/*` imports so
10
- * pilotiq core stays free of any tiptap peer dep — same posture as the
11
- * existing rich-text renderer registry.
12
- * - `TextLikeInput` checks for the registered component when a `<RecordCollabRoom>`
13
- * is mounted up-tree AND the field hasn't opted out via `.collab(false)` AND
14
- * the field has no `.mask()`. If present, the legacy `BoundTextInput`
15
- * (Y.Text + `computeDelta` + heuristic `preserveCursor`) is bypassed in
16
- * favour of a y-prosemirror-backed Tiptap editor that anchors selections to
17
- * `Yjs.RelativePosition` — the architectural fix for the cursor-jump and
18
- * two-peer concurrent-insert races documented in
19
- * `docs/plans/text-fields-tiptap-backed-collab.md`.
20
- *
21
- * Wire props are deliberately framework-agnostic — the renderer doesn't take a
22
- * `binding` since it consumes the room's `ydoc` directly via the existing
23
- * `useCollabRoom()` + `getCollabExtensions()` plumbing on its own side. Core
24
- * keeps the seam narrow: handler callbacks + DOM chrome only.
25
- */
26
- export interface CollabTextRendererProps {
27
- /**
28
- * Field name — drives the FormData hidden input AND the routing key
29
- * for AI suggestion delivery (chip widget, applier registry). For
30
- * Repeater / Builder row leaves this is the dotted positional path
31
- * (`items.0.title`).
32
- */
33
- name: string
34
- /**
35
- * Collab-stable identifier for the `Y.XmlFragment` selector. When
36
- * present, the renderer binds its collab fragment under this key
37
- * instead of `name`. Row leaves pass a row-id-anchored composite
38
- * (`items.<rowId>.title`) so the fragment survives reorders even
39
- * as the dotted positional `name` shifts. Top-level fields omit
40
- * it — `name` is stable on its own.
41
- *
42
- * AI suggestion routing continues to use `name` regardless. Tool
43
- * calls reference fields by their positional FormData name, not
44
- * the collab-stable composite.
45
- */
46
- fragmentKey?: string
47
- /** `true` for textarea-like (multiple paragraphs); `false` for input-like. */
48
- multiline: boolean
49
- /**
50
- * Server-rendered default value. The renderer is expected to seed the
51
- * `Y.XmlFragment` from this on first connect when the room has no
52
- * persisted state for this field (i.e. brand-new record).
53
- */
54
- defaultValue: string
55
- /** Optional placeholder hint. */
56
- placeholder?: string
57
- /** Disabled / read-only state. */
58
- disabled?: boolean
59
- /** Fired on every editor `update` with the editor's current plain text. */
60
- onChange: (text: string) => void
61
- /** Fired on editor blur — host wires this to live-onBlur trigger semantics. */
62
- onBlur: () => void
63
- /**
64
- * Single-line submit — fired when `multiline: false` AND the user presses
65
- * Enter. The renderer is expected to blur the editor after invoking this.
66
- * Multiline mode ignores it (Enter inserts a paragraph instead).
67
- */
68
- onSubmit?: () => void
69
- /**
70
- * Tailwind className applied to the editor's contenteditable wrapper so the
71
- * rendered editor matches the native `<input>` / `<textarea>` chrome it
72
- * replaces. The host owns the styling — the adapter just forwards.
73
- */
74
- className?: string
75
- /**
76
- * Additional DOM attributes for the editor's contenteditable wrapper —
77
- * typically `id`, `aria-*`, `autocomplete`, etc.
78
- */
79
- editorAttributes?: Record<string, string>
80
- }
81
-
82
- export type CollabTextRenderer = ComponentType<CollabTextRendererProps>
83
-
84
- let _renderer: CollabTextRenderer | null = null
85
-
86
- /**
87
- * Register the collab plain-text editor component. Called once at boot by
88
- * `@pilotiq/tiptap`'s `registerTiptap()` (or directly by an app that imports
89
- * the renderer). Calling with `null` clears the registry — useful for tests.
90
- *
91
- * No-op behaviour when no renderer is registered: `TextLikeInput` falls back
92
- * to the legacy `BoundTextInput` path (or the plain controlled / uncontrolled
93
- * input when no collab room is mounted).
94
- */
95
- export function registerCollabTextRenderer(component: CollabTextRenderer | null): void {
96
- _renderer = component
97
- }
98
-
99
- /** Returns the registered component, or `null` when no adapter is installed. */
100
- export function getCollabTextRenderer(): CollabTextRenderer | null {
101
- return _renderer
102
- }
@@ -1,375 +0,0 @@
1
- import * as React from 'react'
2
- import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'
3
- import { SearchIcon, CornerDownLeftIcon, ArrowUpDownIcon } from 'lucide-react'
4
-
5
- import { Dialog, DialogContent } from './ui/dialog.js'
6
- import { useNavigate } from './navigate.js'
7
- import { useIconFor } from './icon-context.js'
8
- import { RenderHookSlot } from './RenderHookSlot.js'
9
- import type { GlobalSearchResult } from '../search.js'
10
- import type { NavItem } from '../pageData.js'
11
- import type { SerializedIcon } from '../icons/types.js'
12
- import type { RenderHookMap } from '../RenderHook.js'
13
-
14
- /**
15
- * Context exposing the palette's open setter. AppShell hosts the
16
- * provider; trigger pills (sidebar + topbar headers) call
17
- * `useCommandPaletteOpener()` to open the palette from anywhere in the
18
- * tree without prop-drilling.
19
- */
20
- const CommandPaletteContext = createContext<((open: boolean) => void) | null>(null)
21
-
22
- export function CommandPaletteProvider({
23
- children,
24
- setOpen,
25
- }: {
26
- children: React.ReactNode
27
- setOpen: (open: boolean) => void
28
- }): React.ReactElement {
29
- return (
30
- <CommandPaletteContext.Provider value={setOpen}>
31
- {children}
32
- </CommandPaletteContext.Provider>
33
- )
34
- }
35
-
36
- export function useCommandPaletteOpener(): (() => void) | null {
37
- const setOpen = useContext(CommandPaletteContext)
38
- return setOpen ? () => setOpen(true) : null
39
- }
40
-
41
- /**
42
- * Plan #12 — Cmd+K palette. Hand-rolled on the existing Dialog primitive
43
- * (no `cmdk` dep yet). Listens for Cmd/Ctrl+K globally; renders an input
44
- * + grouped result list; debounced fetch with in-flight cancellation
45
- * (same pattern as Plan #5 FormStateContext).
46
- *
47
- * Empty input shows the panel navigation entries — Cmd+K becomes a fast
48
- * resource picker. Typing replaces the list with search results grouped
49
- * by resource.
50
- */
51
-
52
- const DEBOUNCE_MS = 150
53
- const MIN_QUERY_LENGTH = 2
54
-
55
- interface SearchResponse {
56
- ok: boolean
57
- results: GlobalSearchResult[]
58
- renderHooks?: RenderHookMap
59
- error?: string
60
- }
61
-
62
- export interface CommandPaletteProps {
63
- basePath: string
64
- navigation?: NavItem[]
65
- /** Controlled open state. AppShell hosts; the palette + the trigger
66
- * pill share via context. */
67
- open: boolean
68
- onOpenChange: (open: boolean) => void
69
- /** Test seam — defaults to `globalThis.fetch`. */
70
- fetchImpl?: typeof fetch
71
- /** Test seam — defaults to `useNavigate()`. */
72
- navigateOverride?: (url: string) => void
73
- }
74
-
75
- interface PaletteEntry {
76
- /** `'result'` rows are search hits; `'nav'` rows are nav-entry shortcuts. */
77
- kind: 'result' | 'nav'
78
- /** Group header label (resource label for results, group name for nav). */
79
- group: string
80
- title: string
81
- subtitle?: string
82
- url: string
83
- icon?: SerializedIcon
84
- /** Stable key for keyboard nav. */
85
- key: string
86
- }
87
-
88
- export function CommandPalette({
89
- basePath,
90
- navigation,
91
- open,
92
- onOpenChange,
93
- fetchImpl,
94
- navigateOverride,
95
- }: CommandPaletteProps): React.ReactElement {
96
- const navigate = useNavigate()
97
- const go = navigateOverride ?? navigate
98
-
99
- const setOpen = onOpenChange
100
- const [query, setQuery] = useState('')
101
- const [results, setResults] = useState<GlobalSearchResult[]>([])
102
- const [renderHooks, setRenderHooks] = useState<RenderHookMap | undefined>(undefined)
103
- const [active, setActive] = useState(0)
104
- const [loading, setLoading] = useState(false)
105
-
106
- // ─── Cmd+K global listener ───────────────────────────
107
- useEffect(() => {
108
- function onKey(e: KeyboardEvent) {
109
- const isCmdK = (e.metaKey || e.ctrlKey) && (e.key === 'k' || e.key === 'K')
110
- if (!isCmdK) return
111
- e.preventDefault()
112
- setOpen(!open)
113
- }
114
- document.addEventListener('keydown', onKey)
115
- return () => document.removeEventListener('keydown', onKey)
116
- }, [open, setOpen])
117
-
118
- // Reset query + active row whenever the palette closes.
119
- useEffect(() => {
120
- if (!open) {
121
- setQuery('')
122
- setResults([])
123
- setRenderHooks(undefined)
124
- setActive(0)
125
- }
126
- }, [open])
127
-
128
- // ─── Fetch with debounce + in-flight seq ─────────────
129
- // Mirrors Plan #5 FormStateContext: refs (not state) for the seq
130
- // counters so React StrictMode dev double-invokes don't produce
131
- // stale closures.
132
- const requestSeqRef = useRef(0)
133
- const latestSeenRef = useRef(0)
134
- const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null)
135
-
136
- const runFetch = useCallback(async (q: string) => {
137
- if (q.trim().length < MIN_QUERY_LENGTH) {
138
- setResults([])
139
- setRenderHooks(undefined)
140
- setLoading(false)
141
- return
142
- }
143
- const seq = ++requestSeqRef.current
144
- const doFetch = fetchImpl ?? fetch
145
- setLoading(true)
146
- try {
147
- const url = `${basePath}/_search?q=${encodeURIComponent(q)}`
148
- const res = await doFetch(url, {
149
- method: 'GET',
150
- headers: { 'Accept': 'application/json' },
151
- })
152
- if (seq < latestSeenRef.current) return
153
- latestSeenRef.current = seq
154
- if (!res.ok) {
155
- setResults([])
156
- setRenderHooks(undefined)
157
- return
158
- }
159
- const data = await res.json().catch(() => null) as SearchResponse | null
160
- if (!data?.ok) {
161
- setResults([])
162
- setRenderHooks(undefined)
163
- return
164
- }
165
- setResults(data.results ?? [])
166
- setRenderHooks(data.renderHooks)
167
- setActive(0)
168
- } catch {
169
- setResults([])
170
- setRenderHooks(undefined)
171
- } finally {
172
- // Only flip loading off when this is the latest in-flight.
173
- if (seq === requestSeqRef.current) setLoading(false)
174
- }
175
- }, [basePath, fetchImpl])
176
-
177
- // Debounce on query change.
178
- useEffect(() => {
179
- if (debounceRef.current) clearTimeout(debounceRef.current)
180
- if (!open) return
181
- debounceRef.current = setTimeout(() => {
182
- void runFetch(query)
183
- }, DEBOUNCE_MS)
184
- return () => {
185
- if (debounceRef.current) clearTimeout(debounceRef.current)
186
- }
187
- }, [query, open, runFetch])
188
-
189
- // ─── Compose the entry list shown in the palette ─────
190
- const entries = useMemo<PaletteEntry[]>(() => {
191
- if (query.trim().length >= MIN_QUERY_LENGTH) {
192
- return results.map((r, i) => {
193
- const entry: PaletteEntry = {
194
- kind: 'result',
195
- group: r.resourceLabel,
196
- title: r.title,
197
- url: r.url,
198
- key: `${r.resource}:${r.id}:${i}`,
199
- }
200
- if (r.subtitle !== undefined) entry.subtitle = r.subtitle
201
- if (r.icon !== undefined) entry.icon = r.icon
202
- return entry
203
- })
204
- }
205
- // Empty-input state: flatten navigation tree.
206
- return flattenNavigation(navigation ?? [])
207
- }, [query, results, navigation])
208
-
209
- // ─── Keyboard navigation ─────────────────────────────
210
- const onKeyDown = useCallback((e: React.KeyboardEvent<HTMLInputElement>) => {
211
- if (e.key === 'ArrowDown') {
212
- e.preventDefault()
213
- setActive((i) => Math.min(i + 1, Math.max(0, entries.length - 1)))
214
- } else if (e.key === 'ArrowUp') {
215
- e.preventDefault()
216
- setActive((i) => Math.max(i - 1, 0))
217
- } else if (e.key === 'Enter') {
218
- e.preventDefault()
219
- const entry = entries[active]
220
- if (entry) {
221
- setOpen(false)
222
- // Defer the navigate so the close transition fires first.
223
- Promise.resolve().then(() => go(entry.url))
224
- }
225
- } else if (e.key === 'Escape') {
226
- setOpen(false)
227
- }
228
- }, [entries, active, go])
229
-
230
- // Hooks render only when the user is actively searching (>= MIN_QUERY_LENGTH);
231
- // empty-input nav state stays clean — chrome / nav slots cover that elsewhere.
232
- const showHooks = query.trim().length >= MIN_QUERY_LENGTH
233
-
234
- // ─── Group entries for rendering ─────────────────────
235
- const grouped = useMemo(() => {
236
- const map = new Map<string, PaletteEntry[]>()
237
- for (const e of entries) {
238
- const arr = map.get(e.group) ?? []
239
- arr.push(e)
240
- map.set(e.group, arr)
241
- }
242
- return [...map.entries()]
243
- }, [entries])
244
-
245
- return (
246
- <Dialog open={open} onOpenChange={setOpen}>
247
- <DialogContent className="max-w-xl p-0 gap-0 overflow-hidden">
248
- <div className="flex items-center gap-2 border-b border-border px-4 py-3">
249
- <SearchIcon className="size-4 text-muted-foreground" aria-hidden="true" />
250
- <input
251
- type="text"
252
- autoFocus
253
- placeholder="Search resources, records, or pages…"
254
- value={query}
255
- onChange={(e) => setQuery(e.target.value)}
256
- onKeyDown={onKeyDown}
257
- className="flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
258
- aria-label="Search"
259
- />
260
- {loading && <span className="text-xs text-muted-foreground">…</span>}
261
- <kbd className="text-[10px] font-mono text-muted-foreground border border-border rounded px-1 py-0.5">esc</kbd>
262
- </div>
263
-
264
- <div className="max-h-96 overflow-y-auto py-1">
265
- {showHooks && renderHooks?.['panels::global-search.results.before'] && (
266
- <div className="px-4 py-2">
267
- <RenderHookSlot name="panels::global-search.results.before" hooks={renderHooks} />
268
- </div>
269
- )}
270
- {entries.length === 0 && (
271
- <p className="px-4 py-6 text-center text-sm text-muted-foreground">
272
- {query.trim().length < MIN_QUERY_LENGTH
273
- ? 'Type to search…'
274
- : loading
275
- ? 'Searching…'
276
- : 'No results.'}
277
- </p>
278
- )}
279
- {grouped.map(([group, rows]) => (
280
- <div key={group}>
281
- <div className="px-4 pt-3 pb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground">
282
- {group}
283
- </div>
284
- <ul role="listbox">
285
- {rows.map((entry) => {
286
- const flatIdx = entries.indexOf(entry)
287
- const isActive = flatIdx === active
288
- return (
289
- <li key={entry.key}>
290
- <button
291
- type="button"
292
- role="option"
293
- aria-selected={isActive}
294
- onMouseEnter={() => setActive(flatIdx)}
295
- onClick={() => {
296
- setOpen(false)
297
- Promise.resolve().then(() => go(entry.url))
298
- }}
299
- className={[
300
- 'flex w-full items-center gap-3 px-4 py-2 text-left text-sm transition',
301
- isActive ? 'bg-accent text-accent-foreground' : 'hover:bg-muted',
302
- ].join(' ')}
303
- >
304
- <PaletteIcon icon={entry.icon} />
305
- <div className="min-w-0 flex-1">
306
- <div className="truncate font-medium">{entry.title}</div>
307
- {entry.subtitle && (
308
- <div className="truncate text-xs text-muted-foreground">{entry.subtitle}</div>
309
- )}
310
- </div>
311
- {isActive && (
312
- <CornerDownLeftIcon className="size-3 text-muted-foreground" aria-hidden="true" />
313
- )}
314
- </button>
315
- </li>
316
- )
317
- })}
318
- </ul>
319
- </div>
320
- ))}
321
- {showHooks && renderHooks?.['panels::global-search.results.after'] && (
322
- <div className="px-4 py-2">
323
- <RenderHookSlot name="panels::global-search.results.after" hooks={renderHooks} />
324
- </div>
325
- )}
326
- </div>
327
-
328
- <div className="flex items-center justify-between border-t border-border px-4 py-2 text-[10px] text-muted-foreground">
329
- <span className="flex items-center gap-1">
330
- <ArrowUpDownIcon className="size-3" aria-hidden="true" />
331
- navigate
332
- </span>
333
- <span className="flex items-center gap-1">
334
- <CornerDownLeftIcon className="size-3" aria-hidden="true" />
335
- open
336
- </span>
337
- </div>
338
- </DialogContent>
339
- </Dialog>
340
- )
341
- }
342
-
343
- function PaletteIcon({ icon }: { icon: SerializedIcon | undefined }) {
344
- const Icon = useIconFor(icon)
345
- if (!Icon) {
346
- return <span className="size-4 rounded bg-muted" aria-hidden="true" />
347
- }
348
- return <Icon className="size-4 text-muted-foreground" aria-hidden="true" />
349
- }
350
-
351
- /**
352
- * Flatten the navigation tree (nested children) into a single PaletteEntry
353
- * list. Used for the empty-input quick-nav state. Group label is the
354
- * NavItem's `group` (or `'Navigation'` when unset).
355
- */
356
- function flattenNavigation(items: NavItem[]): PaletteEntry[] {
357
- const out: PaletteEntry[] = []
358
- const walk = (nodes: NavItem[], inheritedGroup?: string) => {
359
- for (const n of nodes) {
360
- const group = n.group ?? inheritedGroup ?? 'Navigation'
361
- const entry: PaletteEntry = {
362
- kind: 'nav',
363
- group,
364
- title: n.label,
365
- url: n.url,
366
- key: `nav:${n.name}:${n.url}`,
367
- }
368
- if (n.icon !== undefined) entry.icon = n.icon
369
- out.push(entry)
370
- if (n.children && n.children.length > 0) walk(n.children, group)
371
- }
372
- }
373
- walk(items)
374
- return out
375
- }
@@ -1,50 +0,0 @@
1
- import { createContext, useContext, type ReactNode } from 'react'
2
-
3
- /**
4
- * Resolved identity of the user driving the current page. Mirrors the
5
- * `UserMenuMeta.user` shape that `panelInfo()` ships to the renderer —
6
- * whichever fields the `Pilotiq.user(req => …)` resolver populated.
7
- *
8
- * `null` is the no-user state: either the panel never wired a resolver,
9
- * or the resolver returned `null` for this request. Consumers should
10
- * gracefully fall back (no avatar, no presence label, etc.) rather than
11
- * treating absence as an error.
12
- */
13
- export interface CurrentUser {
14
- name?: string
15
- email?: string
16
- avatar?: string
17
- }
18
-
19
- const CurrentUserContext = createContext<CurrentUser | null>(null)
20
-
21
- /**
22
- * Mounted by `AppShell` around the layout-provider chain so plugins
23
- * (collab user presence, audit-trail attribution, analytics
24
- * client-side opt-outs, …) can read the active user via
25
- * `useCurrentUser()` without prop-drilling through `panel`.
26
- *
27
- * Value source is `viewProps.panel.userMenu?.user` — the same shape the
28
- * top-right dropdown renders. The provider sits OUTSIDE
29
- * `layoutProviderRegistry` so plugin-registered layout providers can
30
- * subscribe.
31
- */
32
- export function CurrentUserProvider({
33
- value,
34
- children,
35
- }: {
36
- value: CurrentUser | null
37
- children: ReactNode
38
- }): ReactNode {
39
- return <CurrentUserContext.Provider value={value}>{children}</CurrentUserContext.Provider>
40
- }
41
-
42
- /**
43
- * Read the active user inside any descendant of `<AppShell>`. Returns
44
- * `null` outside an `AppShell` mount (defensive — keeps storybook /
45
- * isolated-render tests from throwing) and when no user resolved for
46
- * the request.
47
- */
48
- export function useCurrentUser(): CurrentUser | null {
49
- return useContext(CurrentUserContext)
50
- }