@pilotiq/pilotiq 0.24.1 → 0.24.2

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