@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,154 +0,0 @@
1
- import { describe, it } from 'node:test'
2
- import assert from 'node:assert/strict'
3
-
4
- import { TagsInputField, TagsInput } from './TagsInputField.js'
5
-
6
- describe('TagsInputField', () => {
7
- it('emits fieldType "tagsInput"', async () => {
8
- const meta = await TagsInputField.make('tags').toMeta()
9
- assert.equal(meta.fieldType, 'tagsInput')
10
- })
11
-
12
- it('exports an alias `TagsInput`', () => {
13
- assert.equal(TagsInput, TagsInputField)
14
- })
15
-
16
- it('default suggestions is an empty array', async () => {
17
- const meta = await TagsInputField.make('tags').toMeta()
18
- assert.deepEqual(meta['suggestions'], [])
19
- })
20
-
21
- it('omits separator/splitKeys/reorderable/maxTags by default', async () => {
22
- const meta = await TagsInputField.make('tags').toMeta()
23
- assert.equal('separator' in meta, false)
24
- assert.equal('splitKeys' in meta, false)
25
- assert.equal('reorderable' in meta, false)
26
- assert.equal('maxTags' in meta, false)
27
- })
28
-
29
- describe('suggestions(static array)', () => {
30
- it('emits suggestions verbatim', async () => {
31
- const meta = await TagsInputField.make('tags')
32
- .suggestions(['react', 'vue', 'svelte'])
33
- .toMeta()
34
- assert.deepEqual(meta['suggestions'], ['react', 'vue', 'svelte'])
35
- })
36
-
37
- it('hasDynamicSuggestions is false for static arrays', () => {
38
- const f = TagsInputField.make('tags').suggestions(['a'])
39
- assert.equal(f.hasDynamicSuggestions(), false)
40
- assert.deepEqual(f.getSuggestions(), ['a'])
41
- })
42
- })
43
-
44
- describe('suggestions(resolver function)', () => {
45
- it('runs the resolver against ctx', async () => {
46
- const f = TagsInputField.make('tags').suggestions(({ $get }) => {
47
- const stack = $get?.('stack') as string | undefined
48
- if (stack === 'fe') return ['react', 'vue']
49
- return ['node', 'rails']
50
- })
51
- assert.equal(f.hasDynamicSuggestions(), true)
52
- const meta = await f.toMeta({
53
- values: { stack: 'fe' },
54
- $get: (n) => ({ stack: 'fe' } as Record<string, unknown>)[n],
55
- })
56
- assert.deepEqual(meta['suggestions'], ['react', 'vue'])
57
- })
58
-
59
- it('async resolver is awaited', async () => {
60
- const f = TagsInputField.make('tags').suggestions(async () => {
61
- await new Promise(r => setTimeout(r, 1))
62
- return ['async']
63
- })
64
- const meta = await f.toMeta()
65
- assert.deepEqual(meta['suggestions'], ['async'])
66
- })
67
-
68
- it('thrown resolver returns empty suggestions + console.warn', async () => {
69
- const original = console.warn
70
- const calls: unknown[] = []
71
- console.warn = (...args: unknown[]) => { calls.push(args) }
72
- try {
73
- const f = TagsInputField.make('broken').suggestions(() => { throw new Error('boom') })
74
- const meta = await f.toMeta()
75
- assert.deepEqual(meta['suggestions'], [])
76
- assert.equal(calls.length, 1)
77
- } finally {
78
- console.warn = original
79
- }
80
- })
81
- })
82
-
83
- describe('separator', () => {
84
- it('emits when set to a non-default char', async () => {
85
- const meta = await TagsInputField.make('tags').separator(';').toMeta()
86
- assert.equal(meta['separator'], ';')
87
- })
88
-
89
- it('emits null when explicitly disabled', async () => {
90
- const meta = await TagsInputField.make('tags').separator(null).toMeta()
91
- assert.equal(meta['separator'], null)
92
- })
93
-
94
- it('omits when left at the default ","', async () => {
95
- const meta = await TagsInputField.make('tags').separator(',').toMeta()
96
- assert.equal('separator' in meta, false)
97
- })
98
- })
99
-
100
- describe('splitKeys', () => {
101
- it('emits when overridden', async () => {
102
- const meta = await TagsInputField.make('tags').splitKeys(['Enter', 'Tab']).toMeta()
103
- assert.deepEqual(meta['splitKeys'], ['Enter', 'Tab'])
104
- })
105
-
106
- it('omits when left at the default ["Enter"]', async () => {
107
- const meta = await TagsInputField.make('tags').splitKeys(['Enter']).toMeta()
108
- assert.equal('splitKeys' in meta, false)
109
- })
110
- })
111
-
112
- describe('reorderable', () => {
113
- it('emits true when enabled', async () => {
114
- const meta = await TagsInputField.make('tags').reorderable().toMeta()
115
- assert.equal(meta['reorderable'], true)
116
- })
117
-
118
- it('omits when explicitly disabled', async () => {
119
- const meta = await TagsInputField.make('tags').reorderable(false).toMeta()
120
- assert.equal('reorderable' in meta, false)
121
- })
122
- })
123
-
124
- describe('maxTags', () => {
125
- it('emits when set', async () => {
126
- const meta = await TagsInputField.make('tags').maxTags(5).toMeta()
127
- assert.equal(meta['maxTags'], 5)
128
- })
129
-
130
- it('clamps to >= 1 and floors fractional values', () => {
131
- const a = TagsInputField.make('a').maxTags(0)
132
- const b = TagsInputField.make('b').maxTags(3.7)
133
- assert.equal(a.getMaxTags(), 1)
134
- assert.equal(b.getMaxTags(), 3)
135
- })
136
- })
137
-
138
- it('participates in cross-field plumbing (default / required / live / helperText)', async () => {
139
- const f = TagsInputField.make('tags')
140
- .label('Tags')
141
- .required()
142
- .default(['draft'])
143
- .helperText('Press Enter to add')
144
- .live()
145
- .suggestions(['draft', 'published'])
146
- const meta = await f.toMeta()
147
- assert.equal(meta.fieldType, 'tagsInput')
148
- assert.equal(meta.required, true)
149
- assert.equal(meta.label, 'Tags')
150
- assert.equal(meta['helperText'], 'Press Enter to add')
151
- assert.equal(meta['live'], true)
152
- assert.deepEqual(meta['defaultValue'], ['draft'])
153
- })
154
- })
@@ -1,133 +0,0 @@
1
- import { Field, type FieldMeta } from './Field.js'
2
- import type { RenderContext } from '../schema/resolveSchema.js'
3
-
4
- /**
5
- * Suggestions resolver. Simpler shape than `OptionsResolver` because
6
- * a tag is its own label — the suggestion list is `string[]`, not
7
- * `{value,label}[]`. Layer SelectOption-shaped suggestions later if
8
- * a real consumer needs label / value to diverge.
9
- */
10
- export type TagsSuggestionsResolver = (ctx: {
11
- $get?: (name: string) => unknown
12
- values?: Record<string, unknown>
13
- record?: unknown
14
- user?: unknown
15
- }) => string[] | Promise<string[]>
16
-
17
- async function resolveSuggestions(
18
- source: string[] | TagsSuggestionsResolver,
19
- ctx: RenderContext | undefined,
20
- fieldName: string,
21
- ): Promise<string[]> {
22
- if (Array.isArray(source)) return source
23
- try {
24
- return await source({
25
- ...(ctx?.$get ? { $get: ctx.$get } : {}),
26
- ...(ctx?.values ? { values: ctx.values } : {}),
27
- ...(ctx?.record !== undefined ? { record: ctx.record } : {}),
28
- ...(ctx?.user !== undefined ? { user: ctx.user } : {}),
29
- })
30
- } catch (err) {
31
- console.warn(`[pilotiq] suggestions() resolver for "${fieldName}" threw:`, err)
32
- return []
33
- }
34
- }
35
-
36
- /**
37
- * Free-text multi-tag input. Value is `string[]`. The client renders
38
- * pill-shaped chips per committed tag plus a single inline text input;
39
- * pressing Enter (or any of `splitKeys`) commits the current draft to
40
- * the chip set. Pasting a string containing `separator` splits into
41
- * multiple chips at once. Backspace on an empty draft removes the last
42
- * chip.
43
- *
44
- * Wire format mirrors `KeyValue` — the client serializes the chip set
45
- * as a JSON string in a single hidden input and `coerceFormValues`
46
- * parses it back into `string[]`. Avoids the multi-input-with-same-name
47
- * footguns across `application/x-www-form-urlencoded` and
48
- * `multipart/form-data` bodies.
49
- */
50
- export class TagsInputField extends Field {
51
- private _suggestions: string[] | TagsSuggestionsResolver = []
52
- private _separator: string | null = ','
53
- private _splitKeys: string[] = ['Enter']
54
- private _reorderable = false
55
- private _maxTags: number | null = null
56
-
57
- private constructor(name: string) {
58
- super(name, 'tagsInput')
59
- }
60
-
61
- static make(name: string): TagsInputField {
62
- return new TagsInputField(name)
63
- }
64
-
65
- suggestions(opts: string[] | TagsSuggestionsResolver): this {
66
- this._suggestions = opts
67
- return this
68
- }
69
-
70
- /**
71
- * Single character that splits a pasted string into multiple tags.
72
- * Pass `null` to disable paste-splitting; only `splitKeys` then
73
- * commits a draft.
74
- */
75
- separator(char: string | null): this {
76
- this._separator = char
77
- return this
78
- }
79
-
80
- /**
81
- * Keys that commit the current draft to the chip set. Defaults to
82
- * `['Enter']`. Common addition: `['Enter', 'Tab', ',']`. The
83
- * separator char is automatically treated as a split key as well.
84
- */
85
- splitKeys(keys: string[]): this {
86
- this._splitKeys = keys
87
- return this
88
- }
89
-
90
- /** Allow chip reorder via native HTML5 drag-and-drop. Off by default — most
91
- * tag sets are insertion-ordered or alphabetized, and the chip strip is small
92
- * enough that drag affordances are noisy when unused. */
93
- reorderable(value: boolean = true): this {
94
- this._reorderable = value
95
- return this
96
- }
97
-
98
- /** Cap the chip count. Surfaces to validation-renderer + client guard. */
99
- maxTags(n: number): this {
100
- this._maxTags = Math.max(1, Math.floor(n))
101
- return this
102
- }
103
-
104
- hasDynamicSuggestions(): boolean {
105
- return typeof this._suggestions === 'function'
106
- }
107
-
108
- getSuggestions(): string[] {
109
- return Array.isArray(this._suggestions) ? this._suggestions : []
110
- }
111
-
112
- getSeparator(): string | null { return this._separator }
113
- getSplitKeys(): string[] { return this._splitKeys }
114
- isReorderable(): boolean { return this._reorderable }
115
- getMaxTags(): number | null { return this._maxTags }
116
-
117
- override async toMeta(ctx?: RenderContext): Promise<FieldMeta> {
118
- const base = this.buildMeta(ctx)
119
- const suggestions = await resolveSuggestions(this._suggestions, ctx, this.name)
120
- return {
121
- ...base,
122
- suggestions,
123
- ...(this._separator !== ',' ? { separator: this._separator } : {}),
124
- ...(this._splitKeys.length !== 1 || this._splitKeys[0] !== 'Enter'
125
- ? { splitKeys: this._splitKeys }
126
- : {}),
127
- ...(this._reorderable ? { reorderable: true } : {}),
128
- ...(this._maxTags ? { maxTags: this._maxTags } : {}),
129
- }
130
- }
131
- }
132
-
133
- export const TagsInput = TagsInputField
@@ -1,213 +0,0 @@
1
- import { describe, it } from 'node:test'
2
- import assert from 'node:assert/strict'
3
-
4
- import { TextField } from './TextField.js'
5
- import { Action } from '../actions/Action.js'
6
- import { resolveSchema } from '../schema/resolveSchema.js'
7
- import { coerceFormValues } from '../elements/dispatchForm.js'
8
- import { formatWithMask } from '../react/fields/textInputControls.js'
9
-
10
- describe('TextField rich affordances (audit gap #3)', () => {
11
- describe('password / revealable', () => {
12
- it('emits password + revealable flags only when set', () => {
13
- const a = TextField.make('p').password().revealable().toMeta()
14
- assert.equal(a['password'], true)
15
- assert.equal(a['revealable'], true)
16
-
17
- const b = TextField.make('p').toMeta()
18
- assert.equal(b['password'], undefined)
19
- assert.equal(b['revealable'], undefined)
20
- })
21
-
22
- it('disarms with explicit false', () => {
23
- const a = TextField.make('p').password(false).toMeta()
24
- assert.equal(a['password'], undefined)
25
- })
26
- })
27
-
28
- describe('copyable', () => {
29
- it('flag emits and message defaults are sparse', () => {
30
- const a = TextField.make('x').copyable().toMeta()
31
- assert.equal(a['copyable'], true)
32
- assert.equal(a['copyMessage'], undefined)
33
-
34
- const b = TextField.make('x').copyable('Got it').toMeta()
35
- assert.equal(b['copyable'], true)
36
- assert.equal(b['copyMessage'], 'Got it')
37
- })
38
- })
39
-
40
- describe('mask', () => {
41
- it('emits the pattern verbatim', () => {
42
- const a = TextField.make('phone').mask('(999) 999-9999').toMeta()
43
- assert.equal(a['mask'], '(999) 999-9999')
44
- })
45
- })
46
-
47
- describe('datalist', () => {
48
- it('emits a defensive copy of the values array', () => {
49
- const values = ['gmail.com', 'outlook.com']
50
- const a = TextField.make('email').datalist(values).toMeta()
51
- const out = a['datalist'] as string[]
52
- assert.deepEqual(out, values)
53
- // Mutating the original after the fact must not leak in.
54
- values.push('yahoo.com')
55
- assert.deepEqual(a['datalist'], ['gmail.com', 'outlook.com'])
56
- })
57
- })
58
-
59
- describe('stripCharacters', () => {
60
- it('accepts a string of single chars', () => {
61
- const a = TextField.make('phone').stripCharacters('()- ').toMeta()
62
- assert.deepEqual(a['stripCharacters'], ['(', ')', '-', ' '])
63
- })
64
-
65
- it('accepts an explicit array', () => {
66
- const a = TextField.make('phone').stripCharacters(['(', ')']).toMeta()
67
- assert.deepEqual(a['stripCharacters'], ['(', ')'])
68
- })
69
-
70
- it('omits when empty', () => {
71
- const a = TextField.make('x').stripCharacters('').toMeta()
72
- assert.equal(a['stripCharacters'], undefined)
73
- })
74
-
75
- it('strips configured chars during coerce', () => {
76
- const f = TextField.make('phone').stripCharacters('()- ')
77
- const out = coerceFormValues([f], { phone: '(415) 555-1212' })
78
- assert.equal(out['phone'], '4155551212')
79
- })
80
-
81
- it('coerce no-ops when not configured', () => {
82
- const f = TextField.make('plain')
83
- const out = coerceFormValues([f], { plain: 'a-b-c' })
84
- assert.equal(out['plain'], 'a-b-c')
85
- })
86
-
87
- it('coerce skips non-string values', () => {
88
- const f = TextField.make('plain').stripCharacters('-')
89
- const out = coerceFormValues([f], { plain: 42 as unknown as string })
90
- assert.equal(out['plain'], 42)
91
- })
92
- })
93
-
94
- describe('trim', () => {
95
- it('emits the flag only when set', () => {
96
- const a = TextField.make('x').trim().toMeta()
97
- assert.equal(a['trim'], true)
98
-
99
- const b = TextField.make('x').toMeta()
100
- assert.equal(b['trim'], undefined)
101
- })
102
-
103
- it('disarms with explicit false', () => {
104
- const a = TextField.make('x').trim(false).toMeta()
105
- assert.equal(a['trim'], undefined)
106
- })
107
-
108
- it('strips leading and trailing whitespace during coerce', () => {
109
- const f = TextField.make('email').trim()
110
- const out = coerceFormValues([f], { email: ' user@example.com\n' })
111
- assert.equal(out['email'], 'user@example.com')
112
- })
113
-
114
- it('coerce no-ops when not configured', () => {
115
- const f = TextField.make('plain')
116
- const out = coerceFormValues([f], { plain: ' spaced ' })
117
- assert.equal(out['plain'], ' spaced ')
118
- })
119
-
120
- it('coerce skips non-string values', () => {
121
- const f = TextField.make('x').trim()
122
- const out = coerceFormValues([f], { x: 42 as unknown as string })
123
- assert.equal(out['x'], 42)
124
- })
125
-
126
- it('runs before stripCharacters when both are set', () => {
127
- const f = TextField.make('phone').trim().stripCharacters('()- ')
128
- const out = coerceFormValues([f], { phone: ' (415) 555-1212 ' })
129
- assert.equal(out['phone'], '4155551212')
130
- })
131
-
132
- it('preserves empty strings', () => {
133
- const f = TextField.make('x').trim()
134
- const out = coerceFormValues([f], { x: ' ' })
135
- assert.equal(out['x'], '')
136
- })
137
- })
138
-
139
- describe('inputMode + autocapitalize', () => {
140
- it('emits each attribute when set', () => {
141
- const a = TextField.make('q').inputMode('search').autocapitalize('off').toMeta()
142
- assert.equal(a['inputMode'], 'search')
143
- assert.equal(a['autocapitalize'], 'off')
144
- })
145
-
146
- it('omits each attribute when unset', () => {
147
- const a = TextField.make('q').toMeta()
148
- assert.equal(a['inputMode'], undefined)
149
- assert.equal(a['autocapitalize'], undefined)
150
- })
151
- })
152
-
153
- describe('prefixAction / suffixAction', () => {
154
- it('resolves bound Actions through resolveSchema as ActionMetas', async () => {
155
- const result = await resolveSchema([
156
- TextField.make('apiKey')
157
- .prefixAction(Action.make('generate').icon('plus'))
158
- .suffixAction(Action.make('rotate').icon('refresh')),
159
- ])
160
- const meta = result[0]!
161
- const pre = meta['prefixAction'] as Record<string, unknown> | undefined
162
- const suf = meta['suffixAction'] as Record<string, unknown> | undefined
163
- assert.equal(pre?.['type'], 'action')
164
- assert.equal(pre?.['name'], 'generate')
165
- assert.equal(suf?.['type'], 'action')
166
- assert.equal(suf?.['name'], 'rotate')
167
- })
168
-
169
- it('drops a hidden Action from the slot', async () => {
170
- const result = await resolveSchema([
171
- TextField.make('q').prefixAction(Action.make('hide').visible(false)),
172
- ])
173
- assert.equal(result[0]!['prefixAction'], undefined)
174
- })
175
-
176
- it('omits the slots when not configured', async () => {
177
- const result = await resolveSchema([TextField.make('q')])
178
- assert.equal(result[0]!['prefixAction'], undefined)
179
- assert.equal(result[0]!['suffixAction'], undefined)
180
- })
181
- })
182
- })
183
-
184
- describe('formatWithMask (client mask helper)', () => {
185
- it('formats a US phone via the documented alphabet', () => {
186
- assert.equal(formatWithMask('4155551212', '(999) 999-9999'), '(415) 555-1212')
187
- })
188
-
189
- it('emits literals even with no remaining input', () => {
190
- assert.equal(formatWithMask('415', '(999) 999-9999'), '(415) ')
191
- })
192
-
193
- it('skips characters that do not match the token kind', () => {
194
- assert.equal(formatWithMask('a4b1c5', '999'), '415')
195
- })
196
-
197
- it('handles alpha tokens', () => {
198
- assert.equal(formatWithMask('xy12', 'aa-99'), 'xy-12')
199
- })
200
-
201
- it('any-token (*) accepts any character', () => {
202
- assert.equal(formatWithMask('a1b2', '****'), 'a1b2')
203
- })
204
-
205
- it('does NOT double-emit literals already typed by the user', () => {
206
- assert.equal(formatWithMask('(415)5551212', '(999) 999-9999'), '(415) 555-1212')
207
- })
208
-
209
- it('returns input unchanged when mask is empty', () => {
210
- assert.equal(formatWithMask('hello', ''), '')
211
- })
212
- })
213
-
@@ -1,177 +0,0 @@
1
- import { Field, type FieldMeta } from './Field.js'
2
- import type { RenderContext } from '../schema/resolveSchema.js'
3
- import type { Action } from '../actions/Action.js'
4
-
5
- /**
6
- * HTML5 `inputmode` values — drive the on-screen keyboard mobile browsers
7
- * pop up. `'text'` is the default; the others map 1:1 to spec values.
8
- */
9
- export type TextInputMode =
10
- | 'none' | 'text' | 'numeric' | 'tel' | 'email' | 'decimal' | 'search' | 'url'
11
-
12
- /**
13
- * HTML5 `autocapitalize` values — control which characters mobile virtual
14
- * keyboards capitalize automatically. `'off'` and `'none'` are aliases per
15
- * spec; we surface only `'off'` for clarity.
16
- */
17
- export type TextAutocapitalize = 'off' | 'sentences' | 'words' | 'characters'
18
-
19
- /**
20
- * Mask alphabet documented for `mask(pattern)`:
21
- * `9` — digit (0-9)
22
- * `a` — alpha (A-Za-z)
23
- * `*` — alphanumeric or any character
24
- * anything else — literal (rendered verbatim, skipped on input)
25
- *
26
- * Examples: `'(999) 999-9999'` (US phone), `'9999-9999-9999-9999'` (card),
27
- * `'aaa-9999'` (custom). The renderer formats values keystroke-by-keystroke
28
- * and strips literals from the submitted value so the persisted column
29
- * stores the raw digits/letters.
30
- */
31
-
32
- export class TextField extends Field {
33
- private _maxLength?: number
34
- private _password = false
35
- private _revealable = false
36
- private _copyable = false
37
- private _copyMessage?: string
38
- private _mask?: string
39
- private _datalist?: string[]
40
- private _stripCharacters?: string[]
41
- private _trim = false
42
- private _inputMode?: TextInputMode
43
- private _autocapitalize?: TextAutocapitalize
44
- private _prefixAction?: Action
45
- private _suffixAction?: Action
46
-
47
- private constructor(name: string) {
48
- super(name, 'text')
49
- }
50
-
51
- static make(name: string): TextField {
52
- return new TextField(name)
53
- }
54
-
55
- maxLength(n: number): this { this._maxLength = n; return this }
56
- getMaxLength(): number | undefined { return this._maxLength }
57
-
58
- /**
59
- * Render the input as `type="password"`. Pair with `revealable()` to
60
- * surface an eye-icon toggle. Pure presentation — the column type +
61
- * value handling stays string-shaped.
62
- */
63
- password(v: boolean = true): this { this._password = v; return this }
64
-
65
- /**
66
- * Mount an eye-icon toggle in the suffix slot that flips the input
67
- * type between `password` and `text`. No-op when the field is not in
68
- * `password()` mode (the toggle hides itself client-side so a stray
69
- * `revealable()` on a non-password input doesn't render a useless
70
- * button).
71
- */
72
- revealable(v: boolean = true): this { this._revealable = v; return this }
73
-
74
- /**
75
- * Mount a copy button in the suffix slot that writes the current input
76
- * value to the clipboard. The optional message overrides the default
77
- * `'Copied!'` toast text — same convention as
78
- * `Column.copyMessage()`.
79
- */
80
- copyable(message?: string): this {
81
- this._copyable = true
82
- if (message !== undefined) this._copyMessage = message
83
- return this
84
- }
85
-
86
- /**
87
- * Format the input keystroke-by-keystroke against the supplied mask
88
- * pattern. See `TextField` doc-block for the alphabet (`9` = digit,
89
- * `a` = alpha, `*` = any, literals passthrough). Submitted values are
90
- * stripped of literal characters before the form body lands on the
91
- * server — the persisted column stores the raw chars only.
92
- */
93
- mask(pattern: string): this { this._mask = pattern; return this }
94
-
95
- /**
96
- * Suggest values via a native HTML5 `<datalist>` attached to the
97
- * input. Browsers render an autocomplete dropdown; users can still
98
- * type a value not on the list. Useful for canonical-but-not-exclusive
99
- * sets (countries, departments, common email domains).
100
- */
101
- datalist(values: string[]): this { this._datalist = values.slice(); return this }
102
-
103
- /**
104
- * Strip the listed characters from the submitted value before
105
- * validation runs. Pass a single string (each char becomes a strip
106
- * token) or an array of strings. Useful for input-mask-style fields
107
- * where the persisted column should not carry the mask literals
108
- * (`'(' / ')' / '-' / ' '` for phone numbers, `' '` for credit cards).
109
- * The strip applies on both create and edit — server-side authority,
110
- * so a tampered client still gets cleaned values.
111
- */
112
- stripCharacters(chars: string | string[]): this {
113
- const list = typeof chars === 'string' ? Array.from(chars) : [...chars]
114
- if (list.length === 0) delete this._stripCharacters
115
- else this._stripCharacters = list
116
- return this
117
- }
118
-
119
- getStripCharacters(): string[] | undefined { return this._stripCharacters }
120
-
121
- /**
122
- * Strip leading and trailing whitespace from the submitted value
123
- * before validation runs. Mirrors Laravel's `TrimStrings` middleware
124
- * — server-side authority, so a tampered client still gets trimmed
125
- * values. Composes with `stripCharacters()` (trim runs first). Empty
126
- * strings remain empty; non-string values pass through.
127
- */
128
- trim(v: boolean = true): this { this._trim = v; return this }
129
-
130
- getTrim(): boolean { return this._trim }
131
-
132
- /**
133
- * Set the HTML `inputmode` attribute — drives the virtual-keyboard
134
- * layout on mobile. Distinct from `type=` (a `text` field with
135
- * `inputMode('numeric')` still accepts non-digit pastes; for strict
136
- * numeric-only, use `NumberField` instead).
137
- */
138
- inputMode(mode: TextInputMode): this { this._inputMode = mode; return this }
139
-
140
- /** Set the HTML `autocapitalize` attribute. */
141
- autocapitalize(mode: TextAutocapitalize): this { this._autocapitalize = mode; return this }
142
-
143
- /**
144
- * Mount a clickable Action button in the prefix slot of the input
145
- * shell. Distinct from the passive `prefix()` decoration (which is a
146
- * string or icon descriptor only). Use this for an in-input affordance
147
- * — e.g. an OAuth-style "Generate" button next to an API key field.
148
- * The Action retains its full chrome (`.icon() / .color() / .visible()
149
- * / .modal*()`); visibility rules evaluate through the standard schema
150
- * walker the same way they do anywhere else.
151
- */
152
- prefixAction(action: Action): this { this._prefixAction = action; return this }
153
-
154
- /** Suffix-slot variant of `prefixAction`. Same semantics. */
155
- suffixAction(action: Action): this { this._suffixAction = action; return this }
156
-
157
- /** Read-only access for the resolver. */
158
- getPrefixAction(): Action | undefined { return this._prefixAction }
159
- getSuffixAction(): Action | undefined { return this._suffixAction }
160
-
161
- override toMeta(ctx?: RenderContext): FieldMeta {
162
- return {
163
- ...this.buildMeta(ctx),
164
- ...(this._maxLength !== undefined ? { maxLength: this._maxLength } : {}),
165
- ...(this._password ? { password: true } : {}),
166
- ...(this._revealable ? { revealable: true } : {}),
167
- ...(this._copyable ? { copyable: true } : {}),
168
- ...(this._copyMessage !== undefined ? { copyMessage: this._copyMessage } : {}),
169
- ...(this._mask !== undefined ? { mask: this._mask } : {}),
170
- ...(this._datalist !== undefined ? { datalist: this._datalist } : {}),
171
- ...(this._stripCharacters!== undefined ? { stripCharacters:this._stripCharacters} : {}),
172
- ...(this._trim ? { trim: true } : {}),
173
- ...(this._inputMode !== undefined ? { inputMode: this._inputMode } : {}),
174
- ...(this._autocapitalize !== undefined ? { autocapitalize: this._autocapitalize } : {}),
175
- }
176
- }
177
- }