@pilotiq/pilotiq 0.24.1 → 0.24.3

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 (518) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/boost/guidelines.md +571 -0
  3. package/boost/skills/pilotiq-actions/SKILL.md +49 -0
  4. package/boost/skills/pilotiq-actions/rules/dispatch-modes.md +177 -0
  5. package/boost/skills/pilotiq-actions/rules/factories.md +130 -0
  6. package/boost/skills/pilotiq-actions/rules/visibility-and-authorization.md +125 -0
  7. package/boost/skills/pilotiq-fields/SKILL.md +47 -0
  8. package/boost/skills/pilotiq-fields/rules/field-catalog.md +288 -0
  9. package/boost/skills/pilotiq-fields/rules/reactive-fields.md +199 -0
  10. package/boost/skills/pilotiq-fields/rules/validation.md +198 -0
  11. package/boost/skills/pilotiq-relations/SKILL.md +47 -0
  12. package/boost/skills/pilotiq-relations/rules/relation-managers.md +256 -0
  13. package/boost/skills/pilotiq-relations/rules/repeater-relationship.md +177 -0
  14. package/boost/skills/pilotiq-resource/SKILL.md +61 -0
  15. package/boost/skills/pilotiq-resource/rules/authorization.md +242 -0
  16. package/boost/skills/pilotiq-resource/rules/defining-resources.md +228 -0
  17. package/boost/skills/pilotiq-resource/rules/page-overrides.md +296 -0
  18. package/dist/Pilotiq.d.ts +31 -0
  19. package/dist/Pilotiq.d.ts.map +1 -1
  20. package/dist/Pilotiq.js +3 -1
  21. package/dist/Pilotiq.js.map +1 -1
  22. package/dist/PilotiqRegistry.d.ts +13 -0
  23. package/dist/PilotiqRegistry.d.ts.map +1 -1
  24. package/dist/PilotiqRegistry.js +15 -0
  25. package/dist/PilotiqRegistry.js.map +1 -1
  26. package/dist/pageData/misc.d.ts.map +1 -1
  27. package/dist/pageData/misc.js +6 -0
  28. package/dist/pageData/misc.js.map +1 -1
  29. package/dist/pageData/navigation.d.ts +1 -0
  30. package/dist/pageData/navigation.d.ts.map +1 -1
  31. package/dist/pageData/navigation.js +3 -0
  32. package/dist/pageData/navigation.js.map +1 -1
  33. package/dist/pageData/relationPages.d.ts.map +1 -1
  34. package/dist/pageData/relationPages.js +3 -0
  35. package/dist/pageData/relationPages.js.map +1 -1
  36. package/dist/pageData/resourcePages.d.ts.map +1 -1
  37. package/dist/pageData/resourcePages.js +8 -0
  38. package/dist/pageData/resourcePages.js.map +1 -1
  39. package/dist/react/AppShell.d.ts +8 -0
  40. package/dist/react/AppShell.d.ts.map +1 -1
  41. package/dist/react/AppShell.js.map +1 -1
  42. package/dist/react/layouts/SidebarLayout.d.ts.map +1 -1
  43. package/dist/react/layouts/SidebarLayout.js +10 -2
  44. package/dist/react/layouts/SidebarLayout.js.map +1 -1
  45. package/dist/react/widgets/StatsOverviewRenderer.d.ts.map +1 -1
  46. package/dist/react/widgets/StatsOverviewRenderer.js +32 -18
  47. package/dist/react/widgets/StatsOverviewRenderer.js.map +1 -1
  48. package/dist/routes/relations.d.ts.map +1 -1
  49. package/dist/routes/relations.js +25 -18
  50. package/dist/routes/relations.js.map +1 -1
  51. package/dist/routes/resources.js.map +1 -1
  52. package/package.json +10 -5
  53. package/.turbo/turbo-build.log +0 -8
  54. package/CLAUDE.md +0 -265
  55. package/src/Cluster.test.ts +0 -283
  56. package/src/Cluster.ts +0 -83
  57. package/src/Column.test.ts +0 -199
  58. package/src/Column.ts +0 -710
  59. package/src/Global.test.ts +0 -367
  60. package/src/Global.ts +0 -169
  61. package/src/Page.test.ts +0 -114
  62. package/src/Page.ts +0 -208
  63. package/src/Pilotiq.perf.test.ts +0 -252
  64. package/src/Pilotiq.test.ts +0 -129
  65. package/src/Pilotiq.ts +0 -1158
  66. package/src/PilotiqRegistry.ts +0 -36
  67. package/src/PilotiqServiceProvider.ts +0 -121
  68. package/src/RelationManager.test.ts +0 -400
  69. package/src/RelationManager.ts +0 -527
  70. package/src/RenderHook.test.ts +0 -252
  71. package/src/RenderHook.ts +0 -242
  72. package/src/Resource.test.ts +0 -284
  73. package/src/Resource.ts +0 -526
  74. package/src/RightPanel.test.ts +0 -202
  75. package/src/RightPanel.ts +0 -132
  76. package/src/Tab.test.ts +0 -91
  77. package/src/Tab.ts +0 -156
  78. package/src/UserMenuItem.ts +0 -145
  79. package/src/actions/Action.test.ts +0 -2526
  80. package/src/actions/Action.ts +0 -1515
  81. package/src/actions/ActionGroup.test.ts +0 -112
  82. package/src/actions/ActionGroup.ts +0 -173
  83. package/src/actions/attachFactory.ts +0 -172
  84. package/src/actions/bulkFactories.ts +0 -168
  85. package/src/actions/crudFactories.ts +0 -220
  86. package/src/actions/exportFactory.ts +0 -225
  87. package/src/actions/factoryHelpers.ts +0 -177
  88. package/src/actions/importFactory.ts +0 -243
  89. package/src/actions/index.ts +0 -17
  90. package/src/actions/m2mFactories.ts +0 -193
  91. package/src/actions/relationFactories.ts +0 -372
  92. package/src/applyPageHooks.test.ts +0 -463
  93. package/src/applyPageHooks.ts +0 -330
  94. package/src/authorization.test.ts +0 -483
  95. package/src/breadcrumbs.test.ts +0 -238
  96. package/src/cells/coerce.test.ts +0 -85
  97. package/src/cells/coerce.ts +0 -84
  98. package/src/clusterPaths.ts +0 -35
  99. package/src/columns/BadgeColumn.test.ts +0 -54
  100. package/src/columns/BadgeColumn.ts +0 -32
  101. package/src/columns/BooleanColumn.test.ts +0 -41
  102. package/src/columns/BooleanColumn.ts +0 -18
  103. package/src/columns/ColorColumn.test.ts +0 -37
  104. package/src/columns/ColorColumn.ts +0 -38
  105. package/src/columns/IconColumn.test.ts +0 -54
  106. package/src/columns/IconColumn.ts +0 -37
  107. package/src/columns/ImageColumn.test.ts +0 -41
  108. package/src/columns/ImageColumn.ts +0 -28
  109. package/src/columns/SelectColumn.ts +0 -98
  110. package/src/columns/TextColumn.test.ts +0 -190
  111. package/src/columns/TextColumn.ts +0 -20
  112. package/src/columns/TextInputColumn.ts +0 -68
  113. package/src/columns/ToggleColumn.ts +0 -46
  114. package/src/columns/editableColumns.test.ts +0 -238
  115. package/src/columns/index.ts +0 -9
  116. package/src/defaultGlobalPages.ts +0 -95
  117. package/src/defaultPages.test.ts +0 -634
  118. package/src/defaultPages.ts +0 -617
  119. package/src/defaultViewPage.test.ts +0 -147
  120. package/src/elements/Form.test.ts +0 -223
  121. package/src/elements/Form.ts +0 -416
  122. package/src/elements/ListTabs.ts +0 -28
  123. package/src/elements/Table.test.ts +0 -422
  124. package/src/elements/Table.ts +0 -850
  125. package/src/elements/TableGroup.test.ts +0 -260
  126. package/src/elements/TableGroup.ts +0 -334
  127. package/src/elements/dispatchAction.test.ts +0 -463
  128. package/src/elements/dispatchAction.ts +0 -355
  129. package/src/elements/dispatchForm.test.ts +0 -477
  130. package/src/elements/dispatchForm.ts +0 -1993
  131. package/src/elements/dispatchTable.test.ts +0 -1514
  132. package/src/elements/dispatchTable.ts +0 -745
  133. package/src/elements/index.ts +0 -21
  134. package/src/entries/BadgeEntry.ts +0 -39
  135. package/src/entries/CodeEntry.test.ts +0 -40
  136. package/src/entries/CodeEntry.ts +0 -52
  137. package/src/entries/ColorEntry.ts +0 -63
  138. package/src/entries/ComponentEntry.test.ts +0 -173
  139. package/src/entries/ComponentEntry.ts +0 -95
  140. package/src/entries/Entry.ts +0 -304
  141. package/src/entries/IconEntry.ts +0 -49
  142. package/src/entries/ImageEntry.ts +0 -61
  143. package/src/entries/KeyValueEntry.ts +0 -47
  144. package/src/entries/RepeatableEntry.test.ts +0 -239
  145. package/src/entries/RepeatableEntry.ts +0 -173
  146. package/src/entries/TextEntry.test.ts +0 -394
  147. package/src/entries/TextEntry.ts +0 -60
  148. package/src/entries/index.ts +0 -12
  149. package/src/entries/leaves.test.ts +0 -306
  150. package/src/entries/registry.ts +0 -54
  151. package/src/fields/BuilderField.test.ts +0 -1188
  152. package/src/fields/BuilderField.ts +0 -605
  153. package/src/fields/BuilderRelationship.test.ts +0 -811
  154. package/src/fields/CheckboxField.test.ts +0 -44
  155. package/src/fields/CheckboxField.ts +0 -27
  156. package/src/fields/CheckboxListField.test.ts +0 -99
  157. package/src/fields/CheckboxListField.ts +0 -66
  158. package/src/fields/ColorPickerField.test.ts +0 -33
  159. package/src/fields/ColorPickerField.ts +0 -25
  160. package/src/fields/DateField.ts +0 -54
  161. package/src/fields/DateTimeField.test.ts +0 -55
  162. package/src/fields/EmailField.ts +0 -16
  163. package/src/fields/Field.test.ts +0 -654
  164. package/src/fields/Field.ts +0 -817
  165. package/src/fields/FileUploadField.test.ts +0 -143
  166. package/src/fields/FileUploadField.ts +0 -159
  167. package/src/fields/HiddenField.test.ts +0 -27
  168. package/src/fields/HiddenField.ts +0 -28
  169. package/src/fields/KeyValueField.test.ts +0 -105
  170. package/src/fields/KeyValueField.ts +0 -55
  171. package/src/fields/MarkdownField.test.ts +0 -167
  172. package/src/fields/MarkdownField.ts +0 -162
  173. package/src/fields/NumberField.ts +0 -33
  174. package/src/fields/RadioField.test.ts +0 -94
  175. package/src/fields/RadioField.ts +0 -67
  176. package/src/fields/RepeaterField.test.ts +0 -1806
  177. package/src/fields/RepeaterField.ts +0 -939
  178. package/src/fields/RepeaterRelationship.test.ts +0 -1923
  179. package/src/fields/RepeaterSimple.test.ts +0 -248
  180. package/src/fields/RowButton.test.ts +0 -219
  181. package/src/fields/RowButton.ts +0 -135
  182. package/src/fields/SelectField.test.ts +0 -192
  183. package/src/fields/SelectField.ts +0 -235
  184. package/src/fields/SliderField.test.ts +0 -50
  185. package/src/fields/SliderField.ts +0 -53
  186. package/src/fields/SlugField.ts +0 -24
  187. package/src/fields/TagsInputField.test.ts +0 -154
  188. package/src/fields/TagsInputField.ts +0 -133
  189. package/src/fields/TextField.test.ts +0 -213
  190. package/src/fields/TextField.ts +0 -177
  191. package/src/fields/TextareaField.test.ts +0 -58
  192. package/src/fields/TextareaField.ts +0 -59
  193. package/src/fields/ToggleButtonsField.test.ts +0 -106
  194. package/src/fields/ToggleButtonsField.ts +0 -59
  195. package/src/fields/ToggleField.ts +0 -16
  196. package/src/fields/disableOptionsWhenSelectedInSiblingRepeaterItems.test.ts +0 -319
  197. package/src/fields/optionsResolver.ts +0 -95
  198. package/src/fields/resolveField.ts +0 -28
  199. package/src/filters/BooleanFilter.ts +0 -35
  200. package/src/filters/DateRangeFilter.test.ts +0 -194
  201. package/src/filters/DateRangeFilter.ts +0 -148
  202. package/src/filters/Filter.test.ts +0 -268
  203. package/src/filters/Filter.ts +0 -184
  204. package/src/filters/FormFilter.test.ts +0 -238
  205. package/src/filters/FormFilter.ts +0 -215
  206. package/src/filters/MultiSelectFilter.test.ts +0 -119
  207. package/src/filters/MultiSelectFilter.ts +0 -78
  208. package/src/filters/QueryBuilderFilter.test.ts +0 -662
  209. package/src/filters/QueryBuilderFilter.ts +0 -398
  210. package/src/filters/SelectFilter.ts +0 -46
  211. package/src/filters/TernaryFilter.test.ts +0 -160
  212. package/src/filters/TernaryFilter.ts +0 -72
  213. package/src/filters/TrashedFilter.test.ts +0 -149
  214. package/src/filters/TrashedFilter.ts +0 -55
  215. package/src/filters/queryBuilder/BooleanConstraint.ts +0 -31
  216. package/src/filters/queryBuilder/Constraint.ts +0 -115
  217. package/src/filters/queryBuilder/DateConstraint.ts +0 -69
  218. package/src/filters/queryBuilder/NumberConstraint.ts +0 -66
  219. package/src/filters/queryBuilder/SelectConstraint.ts +0 -72
  220. package/src/filters/queryBuilder/TextConstraint.ts +0 -64
  221. package/src/filters/queryBuilder/index.ts +0 -12
  222. package/src/icons/index.ts +0 -2
  223. package/src/icons/lucide.ts +0 -204
  224. package/src/icons/registry.test.ts +0 -56
  225. package/src/icons/registry.ts +0 -41
  226. package/src/icons/types.ts +0 -47
  227. package/src/index.ts +0 -525
  228. package/src/io/csv.test.ts +0 -142
  229. package/src/io/csv.ts +0 -170
  230. package/src/nestedRelationManagerData.test.ts +0 -547
  231. package/src/notifications/Notification.test.ts +0 -210
  232. package/src/notifications/Notification.ts +0 -354
  233. package/src/notifications/broadcast.test.ts +0 -110
  234. package/src/notifications/broadcast.ts +0 -95
  235. package/src/notifications/database.test.ts +0 -383
  236. package/src/notifications/database.ts +0 -398
  237. package/src/notifications/databaseNotifications.test.ts +0 -187
  238. package/src/notifications/dispatchNotificationAction.test.ts +0 -341
  239. package/src/notifications/dispatchNotificationAction.ts +0 -142
  240. package/src/notifications/flash.test.ts +0 -89
  241. package/src/notifications/flash.ts +0 -71
  242. package/src/notifications/index.ts +0 -45
  243. package/src/notifications/registerBroadcastAuth.test.ts +0 -134
  244. package/src/notifications/registerBroadcastAuth.ts +0 -100
  245. package/src/notifications/resolveSavedNotification.test.ts +0 -82
  246. package/src/notifications/resolveSavedNotification.ts +0 -59
  247. package/src/notifications/types.ts +0 -93
  248. package/src/orm/m2mAccessor.ts +0 -66
  249. package/src/orm/modelDefaults.test.ts +0 -633
  250. package/src/orm/modelDefaults.ts +0 -666
  251. package/src/pageData/breadcrumbs.ts +0 -288
  252. package/src/pageData/forms.ts +0 -578
  253. package/src/pageData/helpers.ts +0 -857
  254. package/src/pageData/misc.ts +0 -347
  255. package/src/pageData/navigation.ts +0 -842
  256. package/src/pageData/relationPages.ts +0 -1248
  257. package/src/pageData/relationTabs.ts +0 -286
  258. package/src/pageData/resourcePages.ts +0 -609
  259. package/src/pageData.test.ts +0 -1545
  260. package/src/pageData.ts +0 -341
  261. package/src/plugins/index.ts +0 -8
  262. package/src/plugins/themeEditor.test.ts +0 -36
  263. package/src/plugins/themeEditor.ts +0 -45
  264. package/src/react/AppShell.tsx +0 -251
  265. package/src/react/CollabExtensionFactoryRegistry.ts +0 -55
  266. package/src/react/CollabRoomContext.ts +0 -98
  267. package/src/react/CollabTextRendererRegistry.ts +0 -102
  268. package/src/react/CommandPalette.tsx +0 -375
  269. package/src/react/CurrentUserContext.tsx +0 -50
  270. package/src/react/CustomPageWrapperGate.tsx +0 -69
  271. package/src/react/CustomPageWrapperRegistry.ts +0 -45
  272. package/src/react/FieldFocusReporterRegistry.ts +0 -37
  273. package/src/react/FieldLabelSlotRegistry.ts +0 -30
  274. package/src/react/FieldPresenceRegistry.ts +0 -46
  275. package/src/react/FormCollabBindingRegistry.ts +0 -242
  276. package/src/react/FormStateContext.tsx +0 -591
  277. package/src/react/HeadHooks.tsx +0 -126
  278. package/src/react/MarkdownEditorRegistry.test.ts +0 -38
  279. package/src/react/MarkdownEditorRegistry.ts +0 -107
  280. package/src/react/NotificationActionStrip.tsx +0 -263
  281. package/src/react/NotificationBell.tsx +0 -426
  282. package/src/react/PendingSuggestionApplierRegistry.test.ts +0 -97
  283. package/src/react/PendingSuggestionApplierRegistry.ts +0 -98
  284. package/src/react/PendingSuggestionOverlayRegistry.ts +0 -54
  285. package/src/react/PendingSuggestionsContext.tsx +0 -172
  286. package/src/react/RecordWrapperGate.tsx +0 -58
  287. package/src/react/RecordWrapperRegistry.ts +0 -39
  288. package/src/react/RenderHookSlot.tsx +0 -32
  289. package/src/react/RightSidebar.tsx +0 -257
  290. package/src/react/RightSidebarContext.tsx +0 -234
  291. package/src/react/RightSidebarTrigger.tsx +0 -53
  292. package/src/react/RowCoordsContext.tsx +0 -23
  293. package/src/react/SchemaRenderer.tsx +0 -549
  294. package/src/react/SearchTrigger.tsx +0 -46
  295. package/src/react/ThemeProvider.tsx +0 -93
  296. package/src/react/ThemeSettingsPage.tsx +0 -579
  297. package/src/react/ThemeToggle.tsx +0 -20
  298. package/src/react/Toaster.tsx +0 -158
  299. package/src/react/UserMenu.tsx +0 -196
  300. package/src/react/WidgetDataContext.tsx +0 -157
  301. package/src/react/cells/EditableCell.tsx +0 -389
  302. package/src/react/component-slots.test.ts +0 -103
  303. package/src/react/component-slots.ts +0 -116
  304. package/src/react/fieldJsHandler.test.ts +0 -166
  305. package/src/react/fieldJsHandler.ts +0 -79
  306. package/src/react/fields/BuilderInput.tsx +0 -1078
  307. package/src/react/fields/CheckboxInput.tsx +0 -39
  308. package/src/react/fields/CheckboxListInput.tsx +0 -102
  309. package/src/react/fields/ColorInput.tsx +0 -71
  310. package/src/react/fields/DateFieldInput.tsx +0 -70
  311. package/src/react/fields/DateTimeInput.tsx +0 -62
  312. package/src/react/fields/FieldShell.tsx +0 -348
  313. package/src/react/fields/FileUploadInput.tsx +0 -639
  314. package/src/react/fields/HiddenInput.tsx +0 -17
  315. package/src/react/fields/KeyValueInput.tsx +0 -230
  316. package/src/react/fields/MarkdownInput.tsx +0 -560
  317. package/src/react/fields/RadioInput.tsx +0 -81
  318. package/src/react/fields/RepeaterInput.test.ts +0 -116
  319. package/src/react/fields/RepeaterInput.tsx +0 -1420
  320. package/src/react/fields/SelectFieldInput.tsx +0 -280
  321. package/src/react/fields/SliderInput.tsx +0 -81
  322. package/src/react/fields/TagsInput.tsx +0 -283
  323. package/src/react/fields/TextLikeInput.tsx +0 -256
  324. package/src/react/fields/ToggleButtonsInput.tsx +0 -60
  325. package/src/react/fields/ToggleFieldInput.tsx +0 -56
  326. package/src/react/fields/relationshipRenameDispatch.test.ts +0 -106
  327. package/src/react/fields/relationshipRenameDispatch.ts +0 -97
  328. package/src/react/fields/repeaterReconcile.test.ts +0 -114
  329. package/src/react/fields/repeaterReconcile.ts +0 -104
  330. package/src/react/fields/rowChromeButton.tsx +0 -336
  331. package/src/react/fields/rowState.ts +0 -106
  332. package/src/react/fields/syncRowGates.test.ts +0 -202
  333. package/src/react/fields/syncRowGates.ts +0 -66
  334. package/src/react/fields/textInputControls.tsx +0 -238
  335. package/src/react/fields/useRowReorderDnd.ts +0 -78
  336. package/src/react/formStateHelpers.test.ts +0 -508
  337. package/src/react/formStateHelpers.ts +0 -381
  338. package/src/react/hooks/use-mobile.ts +0 -19
  339. package/src/react/icon-context.tsx +0 -60
  340. package/src/react/index.ts +0 -194
  341. package/src/react/layouts/SidebarLayout.tsx +0 -250
  342. package/src/react/layouts/TopbarLayout.tsx +0 -258
  343. package/src/react/navigate.tsx +0 -37
  344. package/src/react/onProviderSynced.test.ts +0 -90
  345. package/src/react/parseRecordEditUrl.test.ts +0 -122
  346. package/src/react/parseRecordEditUrl.ts +0 -94
  347. package/src/react/persistedState.ts +0 -40
  348. package/src/react/registry.ts +0 -48
  349. package/src/react/right-panel-registry.tsx +0 -47
  350. package/src/react/schemaRenderer/AlertRenderer.tsx +0 -112
  351. package/src/react/schemaRenderer/EntryRenderer.tsx +0 -501
  352. package/src/react/schemaRenderer/SectionRenderer.tsx +0 -120
  353. package/src/react/schemaRenderer/SimpleElements.tsx +0 -306
  354. package/src/react/schemaRenderer/TabsRenderer.tsx +0 -62
  355. package/src/react/schemaRenderer/WizardRenderer.tsx +0 -338
  356. package/src/react/schemaRenderer/action/ActionGroupTrigger.tsx +0 -177
  357. package/src/react/schemaRenderer/action/ActionModalDialog.tsx +0 -273
  358. package/src/react/schemaRenderer/action/ConfirmActionDialog.tsx +0 -61
  359. package/src/react/schemaRenderer/action/HandlerActionButton.tsx +0 -43
  360. package/src/react/schemaRenderer/action/MethodActionButton.tsx +0 -64
  361. package/src/react/schemaRenderer/action/buttons.tsx +0 -99
  362. package/src/react/schemaRenderer/action/helpers.ts +0 -140
  363. package/src/react/schemaRenderer/action/renderAction.tsx +0 -245
  364. package/src/react/schemaRenderer/columnFormat.ts +0 -65
  365. package/src/react/schemaRenderer/constants.ts +0 -50
  366. package/src/react/schemaRenderer/form/FormRenderer.tsx +0 -274
  367. package/src/react/schemaRenderer/form/renderField.tsx +0 -511
  368. package/src/react/schemaRenderer/helpers.tsx +0 -81
  369. package/src/react/schemaRenderer/table/CardsLayoutBody.tsx +0 -308
  370. package/src/react/schemaRenderer/table/TableRenderer.tsx +0 -123
  371. package/src/react/schemaRenderer/table/TableRendererBody.tsx +0 -974
  372. package/src/react/schemaRenderer/table/filters.tsx +0 -1233
  373. package/src/react/schemaRenderer/table/formatCell.tsx +0 -264
  374. package/src/react/schemaRenderer/table/links.tsx +0 -112
  375. package/src/react/schemaRenderer/table/renderRowActions.tsx +0 -52
  376. package/src/react/schemaRenderer/table/url.tsx +0 -143
  377. package/src/react/theme-preview/apply.ts +0 -99
  378. package/src/react/theme-preview/build-html.ts +0 -436
  379. package/src/react/ui/button.tsx +0 -51
  380. package/src/react/ui/calendar.tsx +0 -67
  381. package/src/react/ui/checkbox.tsx +0 -29
  382. package/src/react/ui/dialog.tsx +0 -108
  383. package/src/react/ui/dropdown-menu.tsx +0 -97
  384. package/src/react/ui/input.tsx +0 -20
  385. package/src/react/ui/label.tsx +0 -21
  386. package/src/react/ui/popover.tsx +0 -50
  387. package/src/react/ui/select.tsx +0 -169
  388. package/src/react/ui/separator.tsx +0 -25
  389. package/src/react/ui/sheet.tsx +0 -136
  390. package/src/react/ui/sidebar.tsx +0 -723
  391. package/src/react/ui/skeleton.tsx +0 -13
  392. package/src/react/ui/slider.tsx +0 -34
  393. package/src/react/ui/switch.tsx +0 -28
  394. package/src/react/ui/table.tsx +0 -105
  395. package/src/react/ui/tabs.tsx +0 -63
  396. package/src/react/ui/textarea.tsx +0 -18
  397. package/src/react/ui/tooltip.tsx +0 -64
  398. package/src/react/useResizableWidth.ts +0 -139
  399. package/src/react/utils.ts +0 -6
  400. package/src/react/widgetRegistry.test.ts +0 -43
  401. package/src/react/widgetRegistry.ts +0 -50
  402. package/src/react/widgets/StatsOverviewRenderer.tsx +0 -232
  403. package/src/react/widgets/TableWidgetRenderer.tsx +0 -231
  404. package/src/react/widgets/ViewRenderer.tsx +0 -71
  405. package/src/relationManagerData.test.ts +0 -1595
  406. package/src/richtext/index.ts +0 -8
  407. package/src/richtext/registry.ts +0 -89
  408. package/src/routes/globals.ts +0 -148
  409. package/src/routes/guard.test.ts +0 -325
  410. package/src/routes/helpers.ts +0 -704
  411. package/src/routes/pages.ts +0 -175
  412. package/src/routes/panel.ts +0 -204
  413. package/src/routes/relations.ts +0 -1243
  414. package/src/routes/resources.ts +0 -781
  415. package/src/routes/theme.ts +0 -91
  416. package/src/routes-nested-relations.test.ts +0 -676
  417. package/src/routes-relations.test.ts +0 -972
  418. package/src/routes.test.ts +0 -2027
  419. package/src/routes.ts +0 -303
  420. package/src/schema/Alert.test.ts +0 -109
  421. package/src/schema/Alert.ts +0 -131
  422. package/src/schema/Block.ts +0 -169
  423. package/src/schema/Breadcrumbs.ts +0 -40
  424. package/src/schema/Card.ts +0 -35
  425. package/src/schema/Divider.ts +0 -20
  426. package/src/schema/Element.ts +0 -219
  427. package/src/schema/EmptyState.test.ts +0 -37
  428. package/src/schema/EmptyState.ts +0 -63
  429. package/src/schema/Fieldset.ts +0 -43
  430. package/src/schema/Grid.ts +0 -43
  431. package/src/schema/Group.ts +0 -30
  432. package/src/schema/Heading.ts +0 -39
  433. package/src/schema/Html.ts +0 -67
  434. package/src/schema/Icon.ts +0 -54
  435. package/src/schema/Image.ts +0 -57
  436. package/src/schema/LinkTag.ts +0 -41
  437. package/src/schema/Markdown.ts +0 -85
  438. package/src/schema/MetaTag.ts +0 -41
  439. package/src/schema/RelationTabs.ts +0 -71
  440. package/src/schema/ScriptTag.ts +0 -55
  441. package/src/schema/Section.ts +0 -160
  442. package/src/schema/ServerDataElement.test.ts +0 -140
  443. package/src/schema/ServerDataElement.ts +0 -156
  444. package/src/schema/SlotComponent.test.ts +0 -77
  445. package/src/schema/SlotComponent.ts +0 -71
  446. package/src/schema/Split.ts +0 -50
  447. package/src/schema/Stat.test.ts +0 -118
  448. package/src/schema/Stat.ts +0 -154
  449. package/src/schema/StatsOverview.test.ts +0 -141
  450. package/src/schema/StatsOverview.ts +0 -119
  451. package/src/schema/StyleTag.ts +0 -35
  452. package/src/schema/TableWidget.test.ts +0 -297
  453. package/src/schema/TableWidget.ts +0 -289
  454. package/src/schema/Tabs.ts +0 -79
  455. package/src/schema/Text.ts +0 -58
  456. package/src/schema/UnorderedList.ts +0 -49
  457. package/src/schema/View.test.ts +0 -111
  458. package/src/schema/View.ts +0 -127
  459. package/src/schema/Wizard.ts +0 -220
  460. package/src/schema/containers.test.ts +0 -564
  461. package/src/schema/headTags.test.ts +0 -134
  462. package/src/schema/index.ts +0 -40
  463. package/src/schema/primes.test.ts +0 -269
  464. package/src/schema/resolveSchema.test.ts +0 -379
  465. package/src/schema/resolveSchema.ts +0 -917
  466. package/src/schema/sanitize.ts +0 -58
  467. package/src/search.test.ts +0 -446
  468. package/src/search.ts +0 -178
  469. package/src/sessionFilters.test.ts +0 -375
  470. package/src/sessionFilters.ts +0 -143
  471. package/src/slot-components/index.ts +0 -10
  472. package/src/slot-components/registry.ts +0 -56
  473. package/src/styles/file-upload.css +0 -13
  474. package/src/summarizers/Summarizer.test.ts +0 -84
  475. package/src/summarizers/Summarizer.ts +0 -123
  476. package/src/summarizers/index.ts +0 -11
  477. package/src/theme/base-colors.ts +0 -68
  478. package/src/theme/chart-colors.ts +0 -50
  479. package/src/theme/colors.ts +0 -447
  480. package/src/theme/generate-css.test.ts +0 -139
  481. package/src/theme/generate-css.ts +0 -44
  482. package/src/theme/generate-scale.test.ts +0 -106
  483. package/src/theme/generate-scale.ts +0 -97
  484. package/src/theme/icon-map.ts +0 -42
  485. package/src/theme/index.ts +0 -34
  486. package/src/theme/migrate.test.ts +0 -178
  487. package/src/theme/migrate.ts +0 -81
  488. package/src/theme/presets.ts +0 -135
  489. package/src/theme/radius.ts +0 -18
  490. package/src/theme/resolve.test.ts +0 -238
  491. package/src/theme/resolve.ts +0 -96
  492. package/src/theme/spacing.ts +0 -18
  493. package/src/theme/storage.test.ts +0 -126
  494. package/src/theme/storage.ts +0 -106
  495. package/src/theme/theme-colors.ts +0 -88
  496. package/src/theme/types.ts +0 -125
  497. package/src/uploads/UploadAdapter.ts +0 -35
  498. package/src/uploads/index.ts +0 -2
  499. package/src/uploads/localUpload.test.ts +0 -70
  500. package/src/uploads/localUpload.ts +0 -84
  501. package/src/validation/Validator.ts +0 -49
  502. package/src/validation/index.ts +0 -28
  503. package/src/validation/rules.ts +0 -78
  504. package/src/validation/runValidators.ts +0 -435
  505. package/src/validation/uniqueValidator.test.ts +0 -196
  506. package/src/validation/uniqueValidator.ts +0 -133
  507. package/src/validation/validators.test.ts +0 -268
  508. package/src/vite.test.ts +0 -184
  509. package/src/vite.ts +0 -787
  510. package/src/widgets/index.ts +0 -10
  511. package/src/widgets/registry.ts +0 -45
  512. package/src/widgets.test.ts +0 -592
  513. package/tsconfig.build.json +0 -11
  514. package/tsconfig.json +0 -4
  515. package/tsconfig.test.json +0 -10
  516. package/views/react/Dashboard.tsx +0 -27
  517. package/views/react/Resources/Form.tsx +0 -102
  518. package/views/react/Resources/Index.tsx +0 -49
@@ -1,256 +0,0 @@
1
- import React, { useCallback, useEffect, useRef, useState } from 'react'
2
- import type { ElementMeta } from '../../schema/Element.js'
3
- import { useFieldState } from '../FormStateContext.js'
4
- import { useCollabRoom } from '../CollabRoomContext.js'
5
- import { getCollabTextRenderer, type CollabTextRenderer } from '../CollabTextRendererRegistry.js'
6
- import { useRowCoords } from '../RowCoordsContext.js'
7
- import { parseRowFieldPath } from '../formStateHelpers.js'
8
- import { Input } from '../ui/input.js'
9
- import { Textarea } from '../ui/textarea.js'
10
-
11
- /**
12
- * Bridge between controlled (FormStateProvider) and uncontrolled
13
- * (defaultValue) modes for text-style inputs. When inside a form with
14
- * `live()` fields, the input is bound to the context's values map and
15
- * fires the live trigger on change/blur according to the field's `live`
16
- * config. Outside a controlled form, falls back to plain `defaultValue`.
17
- *
18
- * **Collab branch — Tiptap-backed `Y.XmlFragment`.** When a
19
- * `<RecordCollabRoom>` is mounted up-tree AND `@pilotiq/tiptap`'s
20
- * `registerTiptap()` registered a collab text renderer, the input
21
- * mounts the Tiptap-backed editor against a `Y.XmlFragment` keyed by
22
- * either the bare field name (top-level) or
23
- * `${arrayName}.${rowId}.${fieldName}` (Repeater / Builder row leaves
24
- * via `useRowCoords()`). Selections anchor to `Y.RelativePosition` via
25
- * y-prosemirror, so cursors survive both mid-word remote edits and
26
- * concurrent inserts. Masked fields fall through to the legacy
27
- * whole-string LWW path (mask + character-level CRDT is incompatible
28
- * — peers would see raw keystrokes desynced from the rendered mask).
29
- */
30
- export function TextLikeInput({
31
- el, name, common, type, extraProps, multiline, applyMask,
32
- }: {
33
- el: ElementMeta
34
- name: string
35
- common: Record<string, unknown>
36
- type: string
37
- extraProps: Record<string, unknown>
38
- multiline: boolean
39
- /** Optional keystroke formatter — `TextField.mask(pattern)`. When
40
- * set, every change runs the value through this fn before it lands
41
- * in state / the DOM. Defaults to identity. */
42
- applyMask?: (value: string) => string
43
- }): React.ReactElement {
44
- const fs = useFieldState(name)
45
- const room = useCollabRoom()
46
- const collabRenderer = getCollabTextRenderer()
47
- const rowCoords = useRowCoords()
48
- const liveCfg = el['live']
49
- const liveOpts = (typeof liveCfg === 'object' && liveCfg !== null
50
- ? liveCfg as { onBlur?: boolean; debounce?: number }
51
- : {})
52
- const onBlurMode = liveOpts.onBlur === true
53
- const mask = applyMask ?? identity
54
-
55
- // Masking is mutually exclusive with character-level CRDT (peers would
56
- // see raw keystrokes diverged from the local mask render); masked
57
- // fields fall through to LWW. We read the mask from the field meta
58
- // directly — `applyMask` is a `useCallback`-wrapped fn that's *always*
59
- // defined (identity when no mask), so its truthiness can't gate the
60
- // branch.
61
- const hasMask = typeof el['mask'] === 'string'
62
-
63
- // Collab branch — Tiptap-backed plain-text editor. Top-level fields
64
- // use the bare `name` as the fragment-key; Repeater / Builder row
65
- // leaves compose `${arrayName}.${rowId}.${fieldName}` from
66
- // `useRowCoords()` so the Y.XmlFragment survives row reorders (keyed
67
- // by the stable rowId, not the array index). The hidden FormData
68
- // input keeps the original dotted path so submission lands on the
69
- // server at the right slot.
70
- //
71
- // Dotted paths that don't match a row shape (no rowCoords OR
72
- // `parseRowFieldPath` returns null — nested row arrays, malformed
73
- // names) skip the collab path and fall through to the controlled /
74
- // uncontrolled branches below.
75
- const fieldCollab = el['collab'] as boolean | undefined
76
- // Auto-upgrade to the Tiptap-backed editor whenever the field has AI
77
- // agents attached, even outside collab — the inline-diff chip widget
78
- // (red strikethrough on the current value + green chip with the suggested
79
- // text + ✓/✕) needs a real ProseMirror surface to render. The renderer
80
- // handles `useCollabRoom() === null` cleanly (mounts the editor without
81
- // the Yjs Collaboration extension), so this widening doesn't force a
82
- // collab room.
83
- //
84
- // `field.ai([…])` from `@pilotiq-pro/ai` lands on `FieldMeta.aiActions`
85
- // as a resolved `PilotiqAgentMeta[]`. Read the array; non-empty means
86
- // "this field has AI surfaces wired".
87
- const aiActions = el['aiActions']
88
- const hasAi = Array.isArray(aiActions) && aiActions.length > 0
89
- const fragmentKey: string | null = (() => {
90
- if (!name.includes('.')) return name
91
- if (!rowCoords) return null
92
- const parsed = parseRowFieldPath(name)
93
- if (!parsed) return null
94
- if (parsed.arrayName !== rowCoords.arrayName) return null
95
- if (parsed.index !== rowCoords.rowIndex) return null
96
- return `${rowCoords.arrayName}.${rowCoords.rowId}.${parsed.fieldName}`
97
- })()
98
- if (
99
- (room || hasAi) &&
100
- collabRenderer &&
101
- fieldCollab !== false &&
102
- !hasMask &&
103
- fragmentKey !== null
104
- ) {
105
- return (
106
- <CollabTextField
107
- Renderer={collabRenderer}
108
- fragmentKey={fragmentKey}
109
- hiddenInputName={name}
110
- multiline={multiline}
111
- defaultValue={stringValue(common['defaultValue'])}
112
- {...(common['placeholder'] !== undefined ? { placeholder: String(common['placeholder']) } : {})}
113
- disabled={Boolean(common['disabled'])}
114
- triggerLive={fs.triggerLive}
115
- setValue={fs.setValue}
116
- controlled={fs.controlled}
117
- onBlurMode={onBlurMode}
118
- />
119
- )
120
- }
121
-
122
- if (fs.controlled) {
123
- const ctxValue = fs.value !== undefined && fs.value !== null ? String(fs.value) : ''
124
- const onChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>): void => {
125
- const formatted = mask(e.target.value)
126
- fs.setValue(formatted)
127
- if (!onBlurMode) fs.triggerLive()
128
- }
129
- const onBlur = (): void => {
130
- if (onBlurMode) fs.triggerLive()
131
- }
132
- const props = {
133
- ...common,
134
- ...extraProps,
135
- defaultValue: undefined,
136
- value: ctxValue,
137
- onChange,
138
- onBlur,
139
- }
140
- if (multiline) return <Textarea {...(props as React.ComponentProps<typeof Textarea>)} />
141
- return <Input {...(props as React.ComponentProps<typeof Input>)} type={type} />
142
- }
143
-
144
- // Uncontrolled path with mask: wire onInput so the user sees the
145
- // formatted value as they type. Without `applyMask`, fall through to
146
- // the legacy bare-defaultValue render so the DOM stays unchanged.
147
- if (applyMask) {
148
- const onInput = (e: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>): void => {
149
- const target = e.currentTarget
150
- target.value = mask(target.value)
151
- }
152
- if (multiline) return <Textarea {...(common as React.ComponentProps<typeof Textarea>)} {...extraProps} onInput={onInput} />
153
- return <Input {...(common as React.ComponentProps<typeof Input>)} type={type} {...extraProps} onInput={onInput} />
154
- }
155
-
156
- if (multiline) return <Textarea {...(common as React.ComponentProps<typeof Textarea>)} {...extraProps} />
157
- return <Input {...(common as React.ComponentProps<typeof Input>)} type={type} {...extraProps} />
158
- }
159
-
160
- /**
161
- * Wrapper around the registered Tiptap-backed collab editor.
162
- * Owns the local text mirror so the hidden `<input>` always carries the
163
- * editor's current value for FormData submission. When `FormStateProvider`
164
- * is mounted up-tree, also mirrors every update into the values map via
165
- * `fs.setValue` so `$get/$set` computations and any Y.Map LWW path (kept
166
- * for non-text consumers) stay in sync.
167
- *
168
- * No IME / cursor-preservation gymnastics in here — the underlying Tiptap
169
- * editor handles composition natively and y-prosemirror anchors selections
170
- * to `Yjs.RelativePosition`, so the cursor survives concurrent + mid-word
171
- * remote edits without any client-side bookkeeping.
172
- *
173
- * `fragmentKey` and `hiddenInputName` diverge for row-text leaves (Phase
174
- * 1 of collab-row-text-tiptap-backed.md): the renderer's Y.XmlFragment is
175
- * keyed by `${arrayName}.${rowId}.${fieldName}` so it survives row
176
- * reorders, while the hidden FormData input keeps the dotted path
177
- * (`items.0.title`) so submission lands at the right server-side slot.
178
- * For top-level fields the two are identical.
179
- */
180
- function CollabTextField({
181
- Renderer, fragmentKey, hiddenInputName, multiline, defaultValue, placeholder, disabled,
182
- triggerLive, setValue, controlled, onBlurMode,
183
- }: {
184
- Renderer: CollabTextRenderer
185
- fragmentKey: string
186
- hiddenInputName: string
187
- multiline: boolean
188
- defaultValue: string
189
- placeholder?: string
190
- disabled: boolean
191
- triggerLive: (valueOverride?: unknown) => void
192
- setValue: (v: unknown) => void
193
- controlled: boolean
194
- onBlurMode: boolean
195
- }): React.ReactElement {
196
- const [text, setText] = useState<string>(defaultValue)
197
- const textRef = useRef(text)
198
- useEffect(() => { textRef.current = text }, [text])
199
-
200
- const handleChange = useCallback((next: string): void => {
201
- setText(next)
202
- if (controlled) setValue(next)
203
- if (!onBlurMode) triggerLive(next)
204
- }, [controlled, onBlurMode, setValue, triggerLive])
205
-
206
- const handleBlur = useCallback((): void => {
207
- if (onBlurMode) triggerLive(textRef.current)
208
- }, [onBlurMode, triggerLive])
209
-
210
- // Match the visual chrome of `<Input>` / `<Textarea>` so the editor reads
211
- // as a drop-in replacement. The adapter forwards this class to its
212
- // contenteditable wrapper; `whitespace-nowrap` on the single-line variant
213
- // keeps the editor from wrapping into a second line if a stray paragraph
214
- // split somehow makes it through.
215
- //
216
- // `overflow-x-clip` (not `auto`) on the single-line variant matters for
217
- // `CollaborationCaret` presence labels: per the CSS overflow spec, setting
218
- // either axis to a non-visible / non-clip value (`auto` / `scroll` /
219
- // `hidden`) forces the other axis to compute as `auto` too — so
220
- // `overflow-x-auto` would clip the caret's user-name label, which renders
221
- // `-1.4em` above the line. `clip` is the one non-visible value that does
222
- // NOT force the other axis, so `overflow-y` stays `visible` and the label
223
- // escapes the chrome upward as designed. Trade-off: long text gets clipped
224
- // on the right rather than horizontally scrollable (native `<input>`
225
- // semantics) — acceptable for plain-text fields, where typing past the
226
- // visible width is rare and the caret presence label is the higher-value
227
- // affordance.
228
- const className = multiline
229
- ? 'flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm whitespace-pre-wrap break-words'
230
- : 'flex h-9 w-full items-center rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm whitespace-nowrap overflow-x-clip'
231
-
232
- return (
233
- <>
234
- <input type="hidden" name={hiddenInputName} value={text} />
235
- <Renderer
236
- name={hiddenInputName}
237
- {...(fragmentKey !== hiddenInputName ? { fragmentKey } : {})}
238
- multiline={multiline}
239
- defaultValue={defaultValue}
240
- {...(placeholder !== undefined ? { placeholder } : {})}
241
- disabled={disabled}
242
- onChange={handleChange}
243
- onBlur={handleBlur}
244
- className={className}
245
- />
246
- </>
247
- )
248
- }
249
-
250
- function identity(v: string): string { return v }
251
-
252
- function stringValue(v: unknown): string {
253
- if (v === undefined || v === null) return ''
254
- if (typeof v === 'string') return v
255
- return String(v)
256
- }
@@ -1,60 +0,0 @@
1
- import React, { useState } from 'react'
2
- import { useFieldState } from '../FormStateContext.js'
3
-
4
- /**
5
- * Single-choice field rendered as a horizontal row of pill-shaped
6
- * buttons styled like a segmented control. Submits via a hidden input
7
- * carrying the active value (form submission contract identical to
8
- * `RadioInput`).
9
- *
10
- * Controlled when inside a `FormStateProvider`, uncontrolled otherwise.
11
- */
12
- export function ToggleButtonsInput({
13
- name, defaultValue, disabled, options,
14
- }: {
15
- name: string
16
- defaultValue: string | undefined
17
- disabled: boolean
18
- options: Array<{ value: string; label: string; disabled?: boolean }>
19
- }): React.ReactElement {
20
- const fs = useFieldState(name)
21
- const [localValue, setLocalValue] = useState<string>(defaultValue ?? '')
22
- const value = fs.controlled
23
- ? (fs.value !== undefined && fs.value !== null ? String(fs.value) : '')
24
- : localValue
25
- const onPick = (next: string): void => {
26
- if (disabled) return
27
- if (fs.controlled) { fs.setValue(next); fs.triggerLive(next) }
28
- else { setLocalValue(next); fs.triggerLive(next) }
29
- }
30
- return (
31
- <div role="radiogroup" className="inline-flex flex-wrap rounded-md border border-input bg-background overflow-hidden">
32
- <input type="hidden" name={name} value={value} />
33
- {options.map((o, i) => {
34
- const active = value === o.value
35
- const optDisabled = disabled || Boolean(o.disabled)
36
- return (
37
- <button
38
- key={o.value}
39
- type="button"
40
- role="radio"
41
- aria-checked={active}
42
- disabled={optDisabled}
43
- data-state={active ? 'on' : 'off'}
44
- onClick={() => { if (!optDisabled) onPick(o.value) }}
45
- className={
46
- 'px-3 py-1.5 text-sm transition-colors focus:outline-none focus:ring-2 focus:ring-ring ' +
47
- (i > 0 ? 'border-l border-input ' : '') +
48
- (active
49
- ? 'bg-primary text-primary-foreground hover:bg-primary/90 '
50
- : 'bg-transparent hover:bg-accent hover:text-accent-foreground ') +
51
- (optDisabled ? 'opacity-50 cursor-not-allowed ' : 'cursor-pointer ')
52
- }
53
- >
54
- {o.label}
55
- </button>
56
- )
57
- })}
58
- </div>
59
- )
60
- }
@@ -1,56 +0,0 @@
1
- import React, { useContext, useEffect, useRef, useState } from 'react'
2
- import { useFieldState, FormIdContext } from '../FormStateContext.js'
3
- import { registerPendingSuggestionApplier, type PendingSuggestionApplier } from '../PendingSuggestionApplierRegistry.js'
4
- import { Switch } from '../ui/switch.js'
5
-
6
- export function ToggleFieldInput({
7
- name, defaultChecked, disabled,
8
- }: { name: string; defaultChecked: boolean; disabled: boolean }): React.ReactElement {
9
- const fs = useFieldState(name)
10
- const [localChecked, setLocalChecked] = useState(defaultChecked)
11
- const checked = fs.controlled
12
- ? (fs.value === true || fs.value === 'true' || fs.value === 1 || fs.value === '1')
13
- : localChecked
14
- // Base UI Switch's onCheckedChange callback does NOT dispatch a native
15
- // bubbling change event, so RepeaterInput's container-level delegate
16
- // can't pick up inner-row live() triggers. Call triggerLive explicitly
17
- // in BOTH paths — the function is a no-op outside FormStateProvider
18
- // and when the field has no `live` config, so it's safe to fire
19
- // unconditionally. The value is passed as a `valueOverride` so
20
- // dotted-path inner-Repeater fields pass through correctly.
21
- const onChange = (next: boolean): void => {
22
- if (fs.controlled) { fs.setValue(next); fs.triggerLive(next) }
23
- else { setLocalChecked(next); fs.triggerLive(next) }
24
- }
25
-
26
- // Cross-tree applier — Switch state lives in React, not in the hidden
27
- // mirror input below. FieldShell's generic DOM-write applier would
28
- // dispatch a change on the hidden input, but the visible Switch has
29
- // no listener for it, so the toggle wouldn't flip. FieldShell skips
30
- // its generic registration for fieldType === 'toggle'.
31
- const fsRef = useRef(fs)
32
- useEffect(() => { fsRef.current = fs }, [fs])
33
- const formId = useContext(FormIdContext) || undefined
34
- useEffect(() => {
35
- if (name.includes('.')) return
36
- const applier: PendingSuggestionApplier = (suggestion) => {
37
- const v = suggestion.suggestedValue
38
- const next = v === true || v === 'true' || v === 1 || v === '1'
39
- const cur = fsRef.current
40
- if (cur.controlled) { cur.setValue(next); cur.triggerLive(next) }
41
- else { setLocalChecked(next); cur.triggerLive(next) }
42
- }
43
- return registerPendingSuggestionApplier(formId, name, applier)
44
- }, [name, formId])
45
- return (
46
- <div className="flex items-center gap-2">
47
- <input type="hidden" name={name} value={checked ? 'true' : 'false'} />
48
- <Switch
49
- id={name}
50
- checked={checked}
51
- onCheckedChange={onChange}
52
- disabled={disabled}
53
- />
54
- </div>
55
- )
56
- }
@@ -1,106 +0,0 @@
1
- import { describe, it, beforeEach } from 'node:test'
2
- import assert from 'node:assert/strict'
3
-
4
- import {
5
- applyRelationshipRenames,
6
- registerRelationshipRenameHandler,
7
- _resetRelationshipRenameRegistryForTests,
8
- type RelationshipRenameEntry,
9
- type RelationshipRenameHandler,
10
- } from './relationshipRenameDispatch.js'
11
-
12
- describe('relationshipRenameDispatch', () => {
13
- beforeEach(() => {
14
- _resetRelationshipRenameRegistryForTests()
15
- })
16
-
17
- it('routes a rename through the registered handler for its formId', () => {
18
- const seen: ReadonlyArray<RelationshipRenameEntry>[] = []
19
- registerRelationshipRenameHandler('form-1', (renames) => { seen.push(renames) })
20
-
21
- applyRelationshipRenames('form-1', [
22
- { field: 'comments', old: 'uuid-foo', new: '42' },
23
- ])
24
-
25
- assert.equal(seen.length, 1)
26
- assert.deepEqual(seen[0], [{ field: 'comments', old: 'uuid-foo', new: '42' }])
27
- })
28
-
29
- it('isolates handlers across formIds — multi-form pages do not cross-fire', () => {
30
- const a: RelationshipRenameEntry[][] = []
31
- const b: RelationshipRenameEntry[][] = []
32
- registerRelationshipRenameHandler('form-a', (r) => { a.push([...r]) })
33
- registerRelationshipRenameHandler('form-b', (r) => { b.push([...r]) })
34
-
35
- applyRelationshipRenames('form-a', [{ field: 'x', old: 'u', new: '1' }])
36
-
37
- assert.equal(a.length, 1)
38
- assert.equal(b.length, 0)
39
- })
40
-
41
- it('cleanup unregisters the handler', () => {
42
- let calls = 0
43
- const off = registerRelationshipRenameHandler('form-1', () => { calls += 1 })
44
- off()
45
- applyRelationshipRenames('form-1', [{ field: 'x', old: 'u', new: '1' }])
46
- assert.equal(calls, 0)
47
- })
48
-
49
- it("cleanup does NOT wipe a handler that another caller replaced (StrictMode-safe)", () => {
50
- // StrictMode dev double-mount: provider A mounts, registers fn1; React
51
- // schedules cleanup; provider A's effect re-runs and registers fn2; THEN
52
- // the cleanup of the first effect fires. fn2 must survive.
53
- let calls1 = 0
54
- let calls2 = 0
55
- const fn1: RelationshipRenameHandler = () => { calls1 += 1 }
56
- const fn2: RelationshipRenameHandler = () => { calls2 += 1 }
57
-
58
- const off1 = registerRelationshipRenameHandler('form-1', fn1)
59
- registerRelationshipRenameHandler('form-1', fn2)
60
- off1()
61
-
62
- applyRelationshipRenames('form-1', [{ field: 'x', old: 'u', new: '1' }])
63
- assert.equal(calls1, 0)
64
- assert.equal(calls2, 1, 'second registration survived the first cleanup')
65
- })
66
-
67
- it('apply with no handler registered is a silent no-op', () => {
68
- // The success path always fires apply; consumers without a collab
69
- // plugin shouldn't see any error.
70
- assert.doesNotThrow(() => {
71
- applyRelationshipRenames('form-unknown', [{ field: 'x', old: 'u', new: '1' }])
72
- })
73
- })
74
-
75
- it('apply with empty or undefined rename list short-circuits', () => {
76
- let calls = 0
77
- registerRelationshipRenameHandler('form-1', () => { calls += 1 })
78
-
79
- applyRelationshipRenames('form-1', [])
80
- applyRelationshipRenames('form-1', undefined)
81
-
82
- assert.equal(calls, 0)
83
- })
84
-
85
- it('apply with empty formId is a no-op', () => {
86
- let calls = 0
87
- registerRelationshipRenameHandler('', () => { calls += 1 })
88
- applyRelationshipRenames('', [{ field: 'x', old: 'u', new: '1' }])
89
- assert.equal(calls, 0)
90
- })
91
-
92
- it('register returns a stub cleanup when formId is empty (no crash)', () => {
93
- const off = registerRelationshipRenameHandler('', () => {})
94
- assert.doesNotThrow(off)
95
- })
96
-
97
- it('handler errors propagate so FormRenderer can surface a save-failed toast', () => {
98
- registerRelationshipRenameHandler('form-1', () => {
99
- throw new Error('binding wedged')
100
- })
101
- assert.throws(
102
- () => applyRelationshipRenames('form-1', [{ field: 'x', old: 'u', new: '1' }]),
103
- /binding wedged/,
104
- )
105
- })
106
- })
@@ -1,97 +0,0 @@
1
- /**
2
- * PK-switch Phase B — client-side dispatcher.
3
- *
4
- * The pilotiq server returns `relationshipRenames: { field, old, new }[]`
5
- * in the JSON form-submit response whenever a `Repeater.relationship` /
6
- * `Builder.relationship` create persisted under a DB-assigned PK that
7
- * differs from the submitter's pre-assigned `__id` (see
8
- * `pilotiq-pro/docs/plans/repeater-relationship-pk-switch.md`,
9
- * `pilotiq/src/elements/dispatchForm.ts` for the wire shape).
10
- *
11
- * The renames need to land on the form's collab binding so other peers
12
- * see the CRDT row re-keyed from UUID → PK without reloading. But the
13
- * binding lives inside `FormStateProvider` (it owns `bindingRef`), while
14
- * the JSON success path lives in `FormRenderer`'s `onSubmit` — a sibling
15
- * component, not a context consumer. We bridge them with a per-`formId`
16
- * module-level registry: `FormStateProvider` registers a handler when
17
- * its binding mounts; `FormRenderer` dispatches against it after a
18
- * successful submit.
19
- *
20
- * Pattern parallels `repeaterReconcile.ts`'s sessionStorage flag — same
21
- * formId-keyed seam, different storage. SessionStorage was right for
22
- * Phase A (the flag has to survive a navigation between submit and
23
- * next mount); Phase B has to fire BEFORE the navigation, so a plain
24
- * in-memory Map is the right shape (no SSR / cross-tab concerns).
25
- *
26
- * No-op when no handler is registered (consumer has no collab plugin,
27
- * or the active binding doesn't implement `renameRow`).
28
- */
29
-
30
- /**
31
- * One UUID → PK rename emitted by the server. Shape mirrors
32
- * `pilotiq/src/elements/dispatchForm.ts` `RelationshipRename`; we
33
- * duplicate the shape here so this module stays free of server-only
34
- * imports (would otherwise pull the form-submit pipeline into the
35
- * client bundle).
36
- */
37
- export interface RelationshipRenameEntry {
38
- field: string
39
- old: string
40
- new: string
41
- }
42
-
43
- export type RelationshipRenameHandler = (
44
- renames: ReadonlyArray<RelationshipRenameEntry>,
45
- ) => void
46
-
47
- const handlers = new Map<string, RelationshipRenameHandler>()
48
-
49
- /**
50
- * Called by `FormStateProvider` when its `FormCollabBinding` mounts AND
51
- * implements `renameRow`. Returns the unsubscribe fn to call on
52
- * unmount. Idempotent under re-registration on the same `formId` —
53
- * later writers replace earlier handlers (Forms only mount one
54
- * provider per id; a second mount means the first unmounted without
55
- * firing its cleanup, which is acceptable to overwrite).
56
- */
57
- export function registerRelationshipRenameHandler(
58
- formId: string,
59
- fn: RelationshipRenameHandler,
60
- ): () => void {
61
- if (!formId) return () => {}
62
- handlers.set(formId, fn)
63
- return () => {
64
- // Only clear when the current handler is still ours — protects
65
- // against StrictMode dev double-mount where the cleanup of the
66
- // first mount fires AFTER the second mount has installed its
67
- // handler. Without this guard, the second mount's handler would
68
- // be wiped before any submit completes.
69
- if (handlers.get(formId) === fn) handlers.delete(formId)
70
- }
71
- }
72
-
73
- /**
74
- * Called by `FormRenderer`'s `onSubmit` success path. Invokes the
75
- * formId's registered handler with the rename list, or no-ops when
76
- * either side is empty.
77
- *
78
- * Errors thrown by the handler propagate — pilotiq's submit path
79
- * already catches in a `try`, so a misbehaving binding fails the
80
- * navigate cleanly with a toast rather than wedging the form.
81
- */
82
- export function applyRelationshipRenames(
83
- formId: string,
84
- renames: ReadonlyArray<RelationshipRenameEntry> | undefined,
85
- ): void {
86
- if (!formId) return
87
- if (!renames || renames.length === 0) return
88
- const fn = handlers.get(formId)
89
- if (!fn) return
90
- fn(renames)
91
- }
92
-
93
- /** Test seam — drop every registered handler. Not exported from the
94
- * react barrel. */
95
- export function _resetRelationshipRenameRegistryForTests(): void {
96
- handlers.clear()
97
- }