@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.
- package/CHANGELOG.md +57 -0
- package/boost/guidelines.md +571 -0
- package/boost/skills/pilotiq-actions/SKILL.md +49 -0
- package/boost/skills/pilotiq-actions/rules/dispatch-modes.md +177 -0
- package/boost/skills/pilotiq-actions/rules/factories.md +130 -0
- package/boost/skills/pilotiq-actions/rules/visibility-and-authorization.md +125 -0
- package/boost/skills/pilotiq-fields/SKILL.md +47 -0
- package/boost/skills/pilotiq-fields/rules/field-catalog.md +288 -0
- package/boost/skills/pilotiq-fields/rules/reactive-fields.md +199 -0
- package/boost/skills/pilotiq-fields/rules/validation.md +198 -0
- package/boost/skills/pilotiq-relations/SKILL.md +47 -0
- package/boost/skills/pilotiq-relations/rules/relation-managers.md +256 -0
- package/boost/skills/pilotiq-relations/rules/repeater-relationship.md +177 -0
- package/boost/skills/pilotiq-resource/SKILL.md +61 -0
- package/boost/skills/pilotiq-resource/rules/authorization.md +242 -0
- package/boost/skills/pilotiq-resource/rules/defining-resources.md +228 -0
- package/boost/skills/pilotiq-resource/rules/page-overrides.md +296 -0
- package/dist/Pilotiq.d.ts +31 -0
- package/dist/Pilotiq.d.ts.map +1 -1
- package/dist/Pilotiq.js +3 -1
- package/dist/Pilotiq.js.map +1 -1
- package/dist/PilotiqRegistry.d.ts +13 -0
- package/dist/PilotiqRegistry.d.ts.map +1 -1
- package/dist/PilotiqRegistry.js +15 -0
- package/dist/PilotiqRegistry.js.map +1 -1
- package/dist/pageData/misc.d.ts.map +1 -1
- package/dist/pageData/misc.js +6 -0
- package/dist/pageData/misc.js.map +1 -1
- package/dist/pageData/navigation.d.ts +1 -0
- package/dist/pageData/navigation.d.ts.map +1 -1
- package/dist/pageData/navigation.js +3 -0
- package/dist/pageData/navigation.js.map +1 -1
- package/dist/pageData/relationPages.d.ts.map +1 -1
- package/dist/pageData/relationPages.js +3 -0
- package/dist/pageData/relationPages.js.map +1 -1
- package/dist/pageData/resourcePages.d.ts.map +1 -1
- package/dist/pageData/resourcePages.js +8 -0
- package/dist/pageData/resourcePages.js.map +1 -1
- package/dist/react/AppShell.d.ts +8 -0
- package/dist/react/AppShell.d.ts.map +1 -1
- package/dist/react/AppShell.js.map +1 -1
- package/dist/react/layouts/SidebarLayout.d.ts.map +1 -1
- package/dist/react/layouts/SidebarLayout.js +10 -2
- package/dist/react/layouts/SidebarLayout.js.map +1 -1
- package/dist/react/widgets/StatsOverviewRenderer.d.ts.map +1 -1
- package/dist/react/widgets/StatsOverviewRenderer.js +32 -18
- package/dist/react/widgets/StatsOverviewRenderer.js.map +1 -1
- package/dist/routes/relations.d.ts.map +1 -1
- package/dist/routes/relations.js +25 -18
- package/dist/routes/relations.js.map +1 -1
- package/dist/routes/resources.js.map +1 -1
- package/package.json +10 -5
- package/.turbo/turbo-build.log +0 -8
- package/CLAUDE.md +0 -265
- package/src/Cluster.test.ts +0 -283
- package/src/Cluster.ts +0 -83
- package/src/Column.test.ts +0 -199
- package/src/Column.ts +0 -710
- package/src/Global.test.ts +0 -367
- package/src/Global.ts +0 -169
- package/src/Page.test.ts +0 -114
- package/src/Page.ts +0 -208
- package/src/Pilotiq.perf.test.ts +0 -252
- package/src/Pilotiq.test.ts +0 -129
- package/src/Pilotiq.ts +0 -1158
- package/src/PilotiqRegistry.ts +0 -36
- package/src/PilotiqServiceProvider.ts +0 -121
- package/src/RelationManager.test.ts +0 -400
- package/src/RelationManager.ts +0 -527
- package/src/RenderHook.test.ts +0 -252
- package/src/RenderHook.ts +0 -242
- package/src/Resource.test.ts +0 -284
- package/src/Resource.ts +0 -526
- package/src/RightPanel.test.ts +0 -202
- package/src/RightPanel.ts +0 -132
- package/src/Tab.test.ts +0 -91
- package/src/Tab.ts +0 -156
- package/src/UserMenuItem.ts +0 -145
- package/src/actions/Action.test.ts +0 -2526
- package/src/actions/Action.ts +0 -1515
- package/src/actions/ActionGroup.test.ts +0 -112
- package/src/actions/ActionGroup.ts +0 -173
- package/src/actions/attachFactory.ts +0 -172
- package/src/actions/bulkFactories.ts +0 -168
- package/src/actions/crudFactories.ts +0 -220
- package/src/actions/exportFactory.ts +0 -225
- package/src/actions/factoryHelpers.ts +0 -177
- package/src/actions/importFactory.ts +0 -243
- package/src/actions/index.ts +0 -17
- package/src/actions/m2mFactories.ts +0 -193
- package/src/actions/relationFactories.ts +0 -372
- package/src/applyPageHooks.test.ts +0 -463
- package/src/applyPageHooks.ts +0 -330
- package/src/authorization.test.ts +0 -483
- package/src/breadcrumbs.test.ts +0 -238
- package/src/cells/coerce.test.ts +0 -85
- package/src/cells/coerce.ts +0 -84
- package/src/clusterPaths.ts +0 -35
- package/src/columns/BadgeColumn.test.ts +0 -54
- package/src/columns/BadgeColumn.ts +0 -32
- package/src/columns/BooleanColumn.test.ts +0 -41
- package/src/columns/BooleanColumn.ts +0 -18
- package/src/columns/ColorColumn.test.ts +0 -37
- package/src/columns/ColorColumn.ts +0 -38
- package/src/columns/IconColumn.test.ts +0 -54
- package/src/columns/IconColumn.ts +0 -37
- package/src/columns/ImageColumn.test.ts +0 -41
- package/src/columns/ImageColumn.ts +0 -28
- package/src/columns/SelectColumn.ts +0 -98
- package/src/columns/TextColumn.test.ts +0 -190
- package/src/columns/TextColumn.ts +0 -20
- package/src/columns/TextInputColumn.ts +0 -68
- package/src/columns/ToggleColumn.ts +0 -46
- package/src/columns/editableColumns.test.ts +0 -238
- package/src/columns/index.ts +0 -9
- package/src/defaultGlobalPages.ts +0 -95
- package/src/defaultPages.test.ts +0 -634
- package/src/defaultPages.ts +0 -617
- package/src/defaultViewPage.test.ts +0 -147
- package/src/elements/Form.test.ts +0 -223
- package/src/elements/Form.ts +0 -416
- package/src/elements/ListTabs.ts +0 -28
- package/src/elements/Table.test.ts +0 -422
- package/src/elements/Table.ts +0 -850
- package/src/elements/TableGroup.test.ts +0 -260
- package/src/elements/TableGroup.ts +0 -334
- package/src/elements/dispatchAction.test.ts +0 -463
- package/src/elements/dispatchAction.ts +0 -355
- package/src/elements/dispatchForm.test.ts +0 -477
- package/src/elements/dispatchForm.ts +0 -1993
- package/src/elements/dispatchTable.test.ts +0 -1514
- package/src/elements/dispatchTable.ts +0 -745
- package/src/elements/index.ts +0 -21
- package/src/entries/BadgeEntry.ts +0 -39
- package/src/entries/CodeEntry.test.ts +0 -40
- package/src/entries/CodeEntry.ts +0 -52
- package/src/entries/ColorEntry.ts +0 -63
- package/src/entries/ComponentEntry.test.ts +0 -173
- package/src/entries/ComponentEntry.ts +0 -95
- package/src/entries/Entry.ts +0 -304
- package/src/entries/IconEntry.ts +0 -49
- package/src/entries/ImageEntry.ts +0 -61
- package/src/entries/KeyValueEntry.ts +0 -47
- package/src/entries/RepeatableEntry.test.ts +0 -239
- package/src/entries/RepeatableEntry.ts +0 -173
- package/src/entries/TextEntry.test.ts +0 -394
- package/src/entries/TextEntry.ts +0 -60
- package/src/entries/index.ts +0 -12
- package/src/entries/leaves.test.ts +0 -306
- package/src/entries/registry.ts +0 -54
- package/src/fields/BuilderField.test.ts +0 -1188
- package/src/fields/BuilderField.ts +0 -605
- package/src/fields/BuilderRelationship.test.ts +0 -811
- package/src/fields/CheckboxField.test.ts +0 -44
- package/src/fields/CheckboxField.ts +0 -27
- package/src/fields/CheckboxListField.test.ts +0 -99
- package/src/fields/CheckboxListField.ts +0 -66
- package/src/fields/ColorPickerField.test.ts +0 -33
- package/src/fields/ColorPickerField.ts +0 -25
- package/src/fields/DateField.ts +0 -54
- package/src/fields/DateTimeField.test.ts +0 -55
- package/src/fields/EmailField.ts +0 -16
- package/src/fields/Field.test.ts +0 -654
- package/src/fields/Field.ts +0 -817
- package/src/fields/FileUploadField.test.ts +0 -143
- package/src/fields/FileUploadField.ts +0 -159
- package/src/fields/HiddenField.test.ts +0 -27
- package/src/fields/HiddenField.ts +0 -28
- package/src/fields/KeyValueField.test.ts +0 -105
- package/src/fields/KeyValueField.ts +0 -55
- package/src/fields/MarkdownField.test.ts +0 -167
- package/src/fields/MarkdownField.ts +0 -162
- package/src/fields/NumberField.ts +0 -33
- package/src/fields/RadioField.test.ts +0 -94
- package/src/fields/RadioField.ts +0 -67
- package/src/fields/RepeaterField.test.ts +0 -1806
- package/src/fields/RepeaterField.ts +0 -939
- package/src/fields/RepeaterRelationship.test.ts +0 -1923
- package/src/fields/RepeaterSimple.test.ts +0 -248
- package/src/fields/RowButton.test.ts +0 -219
- package/src/fields/RowButton.ts +0 -135
- package/src/fields/SelectField.test.ts +0 -192
- package/src/fields/SelectField.ts +0 -235
- package/src/fields/SliderField.test.ts +0 -50
- package/src/fields/SliderField.ts +0 -53
- package/src/fields/SlugField.ts +0 -24
- package/src/fields/TagsInputField.test.ts +0 -154
- package/src/fields/TagsInputField.ts +0 -133
- package/src/fields/TextField.test.ts +0 -213
- package/src/fields/TextField.ts +0 -177
- package/src/fields/TextareaField.test.ts +0 -58
- package/src/fields/TextareaField.ts +0 -59
- package/src/fields/ToggleButtonsField.test.ts +0 -106
- package/src/fields/ToggleButtonsField.ts +0 -59
- package/src/fields/ToggleField.ts +0 -16
- package/src/fields/disableOptionsWhenSelectedInSiblingRepeaterItems.test.ts +0 -319
- package/src/fields/optionsResolver.ts +0 -95
- package/src/fields/resolveField.ts +0 -28
- package/src/filters/BooleanFilter.ts +0 -35
- package/src/filters/DateRangeFilter.test.ts +0 -194
- package/src/filters/DateRangeFilter.ts +0 -148
- package/src/filters/Filter.test.ts +0 -268
- package/src/filters/Filter.ts +0 -184
- package/src/filters/FormFilter.test.ts +0 -238
- package/src/filters/FormFilter.ts +0 -215
- package/src/filters/MultiSelectFilter.test.ts +0 -119
- package/src/filters/MultiSelectFilter.ts +0 -78
- package/src/filters/QueryBuilderFilter.test.ts +0 -662
- package/src/filters/QueryBuilderFilter.ts +0 -398
- package/src/filters/SelectFilter.ts +0 -46
- package/src/filters/TernaryFilter.test.ts +0 -160
- package/src/filters/TernaryFilter.ts +0 -72
- package/src/filters/TrashedFilter.test.ts +0 -149
- package/src/filters/TrashedFilter.ts +0 -55
- package/src/filters/queryBuilder/BooleanConstraint.ts +0 -31
- package/src/filters/queryBuilder/Constraint.ts +0 -115
- package/src/filters/queryBuilder/DateConstraint.ts +0 -69
- package/src/filters/queryBuilder/NumberConstraint.ts +0 -66
- package/src/filters/queryBuilder/SelectConstraint.ts +0 -72
- package/src/filters/queryBuilder/TextConstraint.ts +0 -64
- package/src/filters/queryBuilder/index.ts +0 -12
- package/src/icons/index.ts +0 -2
- package/src/icons/lucide.ts +0 -204
- package/src/icons/registry.test.ts +0 -56
- package/src/icons/registry.ts +0 -41
- package/src/icons/types.ts +0 -47
- package/src/index.ts +0 -525
- package/src/io/csv.test.ts +0 -142
- package/src/io/csv.ts +0 -170
- package/src/nestedRelationManagerData.test.ts +0 -547
- package/src/notifications/Notification.test.ts +0 -210
- package/src/notifications/Notification.ts +0 -354
- package/src/notifications/broadcast.test.ts +0 -110
- package/src/notifications/broadcast.ts +0 -95
- package/src/notifications/database.test.ts +0 -383
- package/src/notifications/database.ts +0 -398
- package/src/notifications/databaseNotifications.test.ts +0 -187
- package/src/notifications/dispatchNotificationAction.test.ts +0 -341
- package/src/notifications/dispatchNotificationAction.ts +0 -142
- package/src/notifications/flash.test.ts +0 -89
- package/src/notifications/flash.ts +0 -71
- package/src/notifications/index.ts +0 -45
- package/src/notifications/registerBroadcastAuth.test.ts +0 -134
- package/src/notifications/registerBroadcastAuth.ts +0 -100
- package/src/notifications/resolveSavedNotification.test.ts +0 -82
- package/src/notifications/resolveSavedNotification.ts +0 -59
- package/src/notifications/types.ts +0 -93
- package/src/orm/m2mAccessor.ts +0 -66
- package/src/orm/modelDefaults.test.ts +0 -633
- package/src/orm/modelDefaults.ts +0 -666
- package/src/pageData/breadcrumbs.ts +0 -288
- package/src/pageData/forms.ts +0 -578
- package/src/pageData/helpers.ts +0 -857
- package/src/pageData/misc.ts +0 -347
- package/src/pageData/navigation.ts +0 -842
- package/src/pageData/relationPages.ts +0 -1248
- package/src/pageData/relationTabs.ts +0 -286
- package/src/pageData/resourcePages.ts +0 -609
- package/src/pageData.test.ts +0 -1545
- package/src/pageData.ts +0 -341
- package/src/plugins/index.ts +0 -8
- package/src/plugins/themeEditor.test.ts +0 -36
- package/src/plugins/themeEditor.ts +0 -45
- package/src/react/AppShell.tsx +0 -251
- package/src/react/CollabExtensionFactoryRegistry.ts +0 -55
- package/src/react/CollabRoomContext.ts +0 -98
- package/src/react/CollabTextRendererRegistry.ts +0 -102
- package/src/react/CommandPalette.tsx +0 -375
- package/src/react/CurrentUserContext.tsx +0 -50
- package/src/react/CustomPageWrapperGate.tsx +0 -69
- package/src/react/CustomPageWrapperRegistry.ts +0 -45
- package/src/react/FieldFocusReporterRegistry.ts +0 -37
- package/src/react/FieldLabelSlotRegistry.ts +0 -30
- package/src/react/FieldPresenceRegistry.ts +0 -46
- package/src/react/FormCollabBindingRegistry.ts +0 -242
- package/src/react/FormStateContext.tsx +0 -591
- package/src/react/HeadHooks.tsx +0 -126
- package/src/react/MarkdownEditorRegistry.test.ts +0 -38
- package/src/react/MarkdownEditorRegistry.ts +0 -107
- package/src/react/NotificationActionStrip.tsx +0 -263
- package/src/react/NotificationBell.tsx +0 -426
- package/src/react/PendingSuggestionApplierRegistry.test.ts +0 -97
- package/src/react/PendingSuggestionApplierRegistry.ts +0 -98
- package/src/react/PendingSuggestionOverlayRegistry.ts +0 -54
- package/src/react/PendingSuggestionsContext.tsx +0 -172
- package/src/react/RecordWrapperGate.tsx +0 -58
- package/src/react/RecordWrapperRegistry.ts +0 -39
- package/src/react/RenderHookSlot.tsx +0 -32
- package/src/react/RightSidebar.tsx +0 -257
- package/src/react/RightSidebarContext.tsx +0 -234
- package/src/react/RightSidebarTrigger.tsx +0 -53
- package/src/react/RowCoordsContext.tsx +0 -23
- package/src/react/SchemaRenderer.tsx +0 -549
- package/src/react/SearchTrigger.tsx +0 -46
- package/src/react/ThemeProvider.tsx +0 -93
- package/src/react/ThemeSettingsPage.tsx +0 -579
- package/src/react/ThemeToggle.tsx +0 -20
- package/src/react/Toaster.tsx +0 -158
- package/src/react/UserMenu.tsx +0 -196
- package/src/react/WidgetDataContext.tsx +0 -157
- package/src/react/cells/EditableCell.tsx +0 -389
- package/src/react/component-slots.test.ts +0 -103
- package/src/react/component-slots.ts +0 -116
- package/src/react/fieldJsHandler.test.ts +0 -166
- package/src/react/fieldJsHandler.ts +0 -79
- package/src/react/fields/BuilderInput.tsx +0 -1078
- package/src/react/fields/CheckboxInput.tsx +0 -39
- package/src/react/fields/CheckboxListInput.tsx +0 -102
- package/src/react/fields/ColorInput.tsx +0 -71
- package/src/react/fields/DateFieldInput.tsx +0 -70
- package/src/react/fields/DateTimeInput.tsx +0 -62
- package/src/react/fields/FieldShell.tsx +0 -348
- package/src/react/fields/FileUploadInput.tsx +0 -639
- package/src/react/fields/HiddenInput.tsx +0 -17
- package/src/react/fields/KeyValueInput.tsx +0 -230
- package/src/react/fields/MarkdownInput.tsx +0 -560
- package/src/react/fields/RadioInput.tsx +0 -81
- package/src/react/fields/RepeaterInput.test.ts +0 -116
- package/src/react/fields/RepeaterInput.tsx +0 -1420
- package/src/react/fields/SelectFieldInput.tsx +0 -280
- package/src/react/fields/SliderInput.tsx +0 -81
- package/src/react/fields/TagsInput.tsx +0 -283
- package/src/react/fields/TextLikeInput.tsx +0 -256
- package/src/react/fields/ToggleButtonsInput.tsx +0 -60
- package/src/react/fields/ToggleFieldInput.tsx +0 -56
- package/src/react/fields/relationshipRenameDispatch.test.ts +0 -106
- package/src/react/fields/relationshipRenameDispatch.ts +0 -97
- package/src/react/fields/repeaterReconcile.test.ts +0 -114
- package/src/react/fields/repeaterReconcile.ts +0 -104
- package/src/react/fields/rowChromeButton.tsx +0 -336
- package/src/react/fields/rowState.ts +0 -106
- package/src/react/fields/syncRowGates.test.ts +0 -202
- package/src/react/fields/syncRowGates.ts +0 -66
- package/src/react/fields/textInputControls.tsx +0 -238
- package/src/react/fields/useRowReorderDnd.ts +0 -78
- package/src/react/formStateHelpers.test.ts +0 -508
- package/src/react/formStateHelpers.ts +0 -381
- package/src/react/hooks/use-mobile.ts +0 -19
- package/src/react/icon-context.tsx +0 -60
- package/src/react/index.ts +0 -194
- package/src/react/layouts/SidebarLayout.tsx +0 -250
- package/src/react/layouts/TopbarLayout.tsx +0 -258
- package/src/react/navigate.tsx +0 -37
- package/src/react/onProviderSynced.test.ts +0 -90
- package/src/react/parseRecordEditUrl.test.ts +0 -122
- package/src/react/parseRecordEditUrl.ts +0 -94
- package/src/react/persistedState.ts +0 -40
- package/src/react/registry.ts +0 -48
- package/src/react/right-panel-registry.tsx +0 -47
- package/src/react/schemaRenderer/AlertRenderer.tsx +0 -112
- package/src/react/schemaRenderer/EntryRenderer.tsx +0 -501
- package/src/react/schemaRenderer/SectionRenderer.tsx +0 -120
- package/src/react/schemaRenderer/SimpleElements.tsx +0 -306
- package/src/react/schemaRenderer/TabsRenderer.tsx +0 -62
- package/src/react/schemaRenderer/WizardRenderer.tsx +0 -338
- package/src/react/schemaRenderer/action/ActionGroupTrigger.tsx +0 -177
- package/src/react/schemaRenderer/action/ActionModalDialog.tsx +0 -273
- package/src/react/schemaRenderer/action/ConfirmActionDialog.tsx +0 -61
- package/src/react/schemaRenderer/action/HandlerActionButton.tsx +0 -43
- package/src/react/schemaRenderer/action/MethodActionButton.tsx +0 -64
- package/src/react/schemaRenderer/action/buttons.tsx +0 -99
- package/src/react/schemaRenderer/action/helpers.ts +0 -140
- package/src/react/schemaRenderer/action/renderAction.tsx +0 -245
- package/src/react/schemaRenderer/columnFormat.ts +0 -65
- package/src/react/schemaRenderer/constants.ts +0 -50
- package/src/react/schemaRenderer/form/FormRenderer.tsx +0 -274
- package/src/react/schemaRenderer/form/renderField.tsx +0 -511
- package/src/react/schemaRenderer/helpers.tsx +0 -81
- package/src/react/schemaRenderer/table/CardsLayoutBody.tsx +0 -308
- package/src/react/schemaRenderer/table/TableRenderer.tsx +0 -123
- package/src/react/schemaRenderer/table/TableRendererBody.tsx +0 -974
- package/src/react/schemaRenderer/table/filters.tsx +0 -1233
- package/src/react/schemaRenderer/table/formatCell.tsx +0 -264
- package/src/react/schemaRenderer/table/links.tsx +0 -112
- package/src/react/schemaRenderer/table/renderRowActions.tsx +0 -52
- package/src/react/schemaRenderer/table/url.tsx +0 -143
- package/src/react/theme-preview/apply.ts +0 -99
- package/src/react/theme-preview/build-html.ts +0 -436
- package/src/react/ui/button.tsx +0 -51
- package/src/react/ui/calendar.tsx +0 -67
- package/src/react/ui/checkbox.tsx +0 -29
- package/src/react/ui/dialog.tsx +0 -108
- package/src/react/ui/dropdown-menu.tsx +0 -97
- package/src/react/ui/input.tsx +0 -20
- package/src/react/ui/label.tsx +0 -21
- package/src/react/ui/popover.tsx +0 -50
- package/src/react/ui/select.tsx +0 -169
- package/src/react/ui/separator.tsx +0 -25
- package/src/react/ui/sheet.tsx +0 -136
- package/src/react/ui/sidebar.tsx +0 -723
- package/src/react/ui/skeleton.tsx +0 -13
- package/src/react/ui/slider.tsx +0 -34
- package/src/react/ui/switch.tsx +0 -28
- package/src/react/ui/table.tsx +0 -105
- package/src/react/ui/tabs.tsx +0 -63
- package/src/react/ui/textarea.tsx +0 -18
- package/src/react/ui/tooltip.tsx +0 -64
- package/src/react/useResizableWidth.ts +0 -139
- package/src/react/utils.ts +0 -6
- package/src/react/widgetRegistry.test.ts +0 -43
- package/src/react/widgetRegistry.ts +0 -50
- package/src/react/widgets/StatsOverviewRenderer.tsx +0 -232
- package/src/react/widgets/TableWidgetRenderer.tsx +0 -231
- package/src/react/widgets/ViewRenderer.tsx +0 -71
- package/src/relationManagerData.test.ts +0 -1595
- package/src/richtext/index.ts +0 -8
- package/src/richtext/registry.ts +0 -89
- package/src/routes/globals.ts +0 -148
- package/src/routes/guard.test.ts +0 -325
- package/src/routes/helpers.ts +0 -704
- package/src/routes/pages.ts +0 -175
- package/src/routes/panel.ts +0 -204
- package/src/routes/relations.ts +0 -1243
- package/src/routes/resources.ts +0 -781
- package/src/routes/theme.ts +0 -91
- package/src/routes-nested-relations.test.ts +0 -676
- package/src/routes-relations.test.ts +0 -972
- package/src/routes.test.ts +0 -2027
- package/src/routes.ts +0 -303
- package/src/schema/Alert.test.ts +0 -109
- package/src/schema/Alert.ts +0 -131
- package/src/schema/Block.ts +0 -169
- package/src/schema/Breadcrumbs.ts +0 -40
- package/src/schema/Card.ts +0 -35
- package/src/schema/Divider.ts +0 -20
- package/src/schema/Element.ts +0 -219
- package/src/schema/EmptyState.test.ts +0 -37
- package/src/schema/EmptyState.ts +0 -63
- package/src/schema/Fieldset.ts +0 -43
- package/src/schema/Grid.ts +0 -43
- package/src/schema/Group.ts +0 -30
- package/src/schema/Heading.ts +0 -39
- package/src/schema/Html.ts +0 -67
- package/src/schema/Icon.ts +0 -54
- package/src/schema/Image.ts +0 -57
- package/src/schema/LinkTag.ts +0 -41
- package/src/schema/Markdown.ts +0 -85
- package/src/schema/MetaTag.ts +0 -41
- package/src/schema/RelationTabs.ts +0 -71
- package/src/schema/ScriptTag.ts +0 -55
- package/src/schema/Section.ts +0 -160
- package/src/schema/ServerDataElement.test.ts +0 -140
- package/src/schema/ServerDataElement.ts +0 -156
- package/src/schema/SlotComponent.test.ts +0 -77
- package/src/schema/SlotComponent.ts +0 -71
- package/src/schema/Split.ts +0 -50
- package/src/schema/Stat.test.ts +0 -118
- package/src/schema/Stat.ts +0 -154
- package/src/schema/StatsOverview.test.ts +0 -141
- package/src/schema/StatsOverview.ts +0 -119
- package/src/schema/StyleTag.ts +0 -35
- package/src/schema/TableWidget.test.ts +0 -297
- package/src/schema/TableWidget.ts +0 -289
- package/src/schema/Tabs.ts +0 -79
- package/src/schema/Text.ts +0 -58
- package/src/schema/UnorderedList.ts +0 -49
- package/src/schema/View.test.ts +0 -111
- package/src/schema/View.ts +0 -127
- package/src/schema/Wizard.ts +0 -220
- package/src/schema/containers.test.ts +0 -564
- package/src/schema/headTags.test.ts +0 -134
- package/src/schema/index.ts +0 -40
- package/src/schema/primes.test.ts +0 -269
- package/src/schema/resolveSchema.test.ts +0 -379
- package/src/schema/resolveSchema.ts +0 -917
- package/src/schema/sanitize.ts +0 -58
- package/src/search.test.ts +0 -446
- package/src/search.ts +0 -178
- package/src/sessionFilters.test.ts +0 -375
- package/src/sessionFilters.ts +0 -143
- package/src/slot-components/index.ts +0 -10
- package/src/slot-components/registry.ts +0 -56
- package/src/styles/file-upload.css +0 -13
- package/src/summarizers/Summarizer.test.ts +0 -84
- package/src/summarizers/Summarizer.ts +0 -123
- package/src/summarizers/index.ts +0 -11
- package/src/theme/base-colors.ts +0 -68
- package/src/theme/chart-colors.ts +0 -50
- package/src/theme/colors.ts +0 -447
- package/src/theme/generate-css.test.ts +0 -139
- package/src/theme/generate-css.ts +0 -44
- package/src/theme/generate-scale.test.ts +0 -106
- package/src/theme/generate-scale.ts +0 -97
- package/src/theme/icon-map.ts +0 -42
- package/src/theme/index.ts +0 -34
- package/src/theme/migrate.test.ts +0 -178
- package/src/theme/migrate.ts +0 -81
- package/src/theme/presets.ts +0 -135
- package/src/theme/radius.ts +0 -18
- package/src/theme/resolve.test.ts +0 -238
- package/src/theme/resolve.ts +0 -96
- package/src/theme/spacing.ts +0 -18
- package/src/theme/storage.test.ts +0 -126
- package/src/theme/storage.ts +0 -106
- package/src/theme/theme-colors.ts +0 -88
- package/src/theme/types.ts +0 -125
- package/src/uploads/UploadAdapter.ts +0 -35
- package/src/uploads/index.ts +0 -2
- package/src/uploads/localUpload.test.ts +0 -70
- package/src/uploads/localUpload.ts +0 -84
- package/src/validation/Validator.ts +0 -49
- package/src/validation/index.ts +0 -28
- package/src/validation/rules.ts +0 -78
- package/src/validation/runValidators.ts +0 -435
- package/src/validation/uniqueValidator.test.ts +0 -196
- package/src/validation/uniqueValidator.ts +0 -133
- package/src/validation/validators.test.ts +0 -268
- package/src/vite.test.ts +0 -184
- package/src/vite.ts +0 -787
- package/src/widgets/index.ts +0 -10
- package/src/widgets/registry.ts +0 -45
- package/src/widgets.test.ts +0 -592
- package/tsconfig.build.json +0 -11
- package/tsconfig.json +0 -4
- package/tsconfig.test.json +0 -10
- package/views/react/Dashboard.tsx +0 -27
- package/views/react/Resources/Form.tsx +0 -102
- package/views/react/Resources/Index.tsx +0 -49
|
@@ -1,564 +0,0 @@
|
|
|
1
|
-
import { describe, it, beforeEach } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
|
|
4
|
-
import { resolveSchema, _resetResolverRegistry } from './resolveSchema.js'
|
|
5
|
-
import { Section } from './Section.js'
|
|
6
|
-
import { Tabs, Tab } from './Tabs.js'
|
|
7
|
-
import { Grid } from './Grid.js'
|
|
8
|
-
import { Card } from './Card.js'
|
|
9
|
-
import { Group } from './Group.js'
|
|
10
|
-
import { Fieldset } from './Fieldset.js'
|
|
11
|
-
import { Split } from './Split.js'
|
|
12
|
-
import { Wizard, Step } from './Wizard.js'
|
|
13
|
-
import { Heading } from './Heading.js'
|
|
14
|
-
import { Text } from './Text.js'
|
|
15
|
-
import { TextField } from '../fields/TextField.js'
|
|
16
|
-
import { SelectField } from '../fields/SelectField.js'
|
|
17
|
-
import { Action } from '../actions/Action.js'
|
|
18
|
-
|
|
19
|
-
beforeEach(() => _resetResolverRegistry())
|
|
20
|
-
|
|
21
|
-
describe('Section', () => {
|
|
22
|
-
it('serializes title, description, and columns', async () => {
|
|
23
|
-
const tree = [
|
|
24
|
-
Section.make('Profile')
|
|
25
|
-
.description('Your account details')
|
|
26
|
-
.columns(2)
|
|
27
|
-
.schema([Heading.make('inside')]),
|
|
28
|
-
]
|
|
29
|
-
const result = await resolveSchema(tree)
|
|
30
|
-
assert.equal(result[0]!.type, 'section')
|
|
31
|
-
assert.equal(result[0]!.title, 'Profile')
|
|
32
|
-
assert.equal(result[0]!.description, 'Your account details')
|
|
33
|
-
assert.equal(result[0]!.columns, 2)
|
|
34
|
-
assert.equal(result[0]!.collapsible, false)
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
it('serializes Plan #8 polish (icon, badge, aside, compact)', async () => {
|
|
38
|
-
const tree = [
|
|
39
|
-
Section.make('Publication')
|
|
40
|
-
.icon('calendar')
|
|
41
|
-
.badge('Draft')
|
|
42
|
-
.aside()
|
|
43
|
-
.compact()
|
|
44
|
-
.schema([]),
|
|
45
|
-
]
|
|
46
|
-
const result = await resolveSchema(tree)
|
|
47
|
-
assert.equal(result[0]!.icon, 'calendar')
|
|
48
|
-
assert.equal(result[0]!.badge, 'Draft')
|
|
49
|
-
assert.equal(result[0]!.aside, true)
|
|
50
|
-
assert.equal(result[0]!.compact, true)
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
it('emits dense flag only when the chainable was called', async () => {
|
|
54
|
-
const off = Section.make('A').schema([])
|
|
55
|
-
const on = Section.make('B').dense().schema([])
|
|
56
|
-
const ra = (await resolveSchema([off]))[0]!
|
|
57
|
-
const rb = (await resolveSchema([on ]))[0]!
|
|
58
|
-
assert.equal(ra['dense'], undefined)
|
|
59
|
-
assert.equal(rb['dense'], true)
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
it('dense composes with compact (orthogonal flags)', async () => {
|
|
63
|
-
const tree = [Section.make('A').compact().dense().schema([])]
|
|
64
|
-
const result = await resolveSchema(tree)
|
|
65
|
-
assert.equal(result[0]!['compact'], true)
|
|
66
|
-
assert.equal(result[0]!['dense'], true)
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
it('emits persistCollapsed only when collapsible is also true', async () => {
|
|
70
|
-
const noColl = Section.make('A').persistCollapsed().schema([])
|
|
71
|
-
const both = Section.make('B').collapsible().persistCollapsed().schema([])
|
|
72
|
-
const ra = (await resolveSchema([noColl]))[0]!
|
|
73
|
-
const rb = (await resolveSchema([both ]))[0]!
|
|
74
|
-
assert.equal(ra['persistCollapsed'], undefined)
|
|
75
|
-
assert.equal(rb['persistCollapsed'], true)
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
it('persistCollapsed honors a custom key', async () => {
|
|
79
|
-
const tree = [
|
|
80
|
-
Section.make('A').collapsible().persistCollapsed('settings.advanced').schema([]),
|
|
81
|
-
]
|
|
82
|
-
const result = await resolveSchema(tree)
|
|
83
|
-
assert.equal(result[0]!['persistKey'], 'settings.advanced')
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
it('emits defaultCollapsed only when collapsible is true', async () => {
|
|
87
|
-
const a = Section.make().defaultCollapsed().schema([])
|
|
88
|
-
const b = Section.make().collapsible().defaultCollapsed().schema([])
|
|
89
|
-
const ra = (await resolveSchema([a]))[0]!
|
|
90
|
-
const rb = (await resolveSchema([b]))[0]!
|
|
91
|
-
assert.equal(ra['defaultCollapsed'], undefined) // collapsible is off → flag suppressed
|
|
92
|
-
assert.equal(rb['defaultCollapsed'], true)
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
it('children resolve recursively via the unified Element resolver', async () => {
|
|
96
|
-
const tree = [
|
|
97
|
-
Section.make('Settings').schema([
|
|
98
|
-
TextField.make('name'),
|
|
99
|
-
Text.make('hint text'),
|
|
100
|
-
]),
|
|
101
|
-
]
|
|
102
|
-
const result = await resolveSchema(tree)
|
|
103
|
-
assert.equal(result[0]!.children?.length, 2)
|
|
104
|
-
assert.equal(result[0]!.children![0]!.type, 'field')
|
|
105
|
-
assert.equal(result[0]!.children![1]!.type, 'text')
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
it('emits secondary flag only when the chainable was called', async () => {
|
|
109
|
-
const off = Section.make('A').schema([])
|
|
110
|
-
const on = Section.make('B').secondary().schema([])
|
|
111
|
-
const ra = (await resolveSchema([off]))[0]!
|
|
112
|
-
const rb = (await resolveSchema([on ]))[0]!
|
|
113
|
-
assert.equal(ra['secondary'], undefined)
|
|
114
|
-
assert.equal(rb['secondary'], true)
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
it('afterHeader([Action…]) resolves Actions through the standard walker', async () => {
|
|
118
|
-
const tree = [
|
|
119
|
-
Section.make('Posts').afterHeader([
|
|
120
|
-
Action.make('refresh').label('Refresh'),
|
|
121
|
-
Action.make('export').label('Export'),
|
|
122
|
-
]).schema([]),
|
|
123
|
-
]
|
|
124
|
-
const result = await resolveSchema(tree)
|
|
125
|
-
const after = result[0]!['afterHeader'] as Array<{ type: string; name: string }> | undefined
|
|
126
|
-
assert.ok(after)
|
|
127
|
-
assert.equal(after.length, 2)
|
|
128
|
-
assert.equal(after[0]!.type, 'action')
|
|
129
|
-
assert.equal(after[0]!.name, 'refresh')
|
|
130
|
-
assert.equal(after[1]!.name, 'export')
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
it('afterHeader is omitted when no actions are passed', async () => {
|
|
134
|
-
const result = await resolveSchema([Section.make('A').schema([])])
|
|
135
|
-
assert.equal(result[0]!['afterHeader'], undefined)
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
it('afterHeader Actions evaluate their .visible() rules', async () => {
|
|
139
|
-
const tree = [
|
|
140
|
-
Section.make('Posts').afterHeader([
|
|
141
|
-
Action.make('shown').label('Shown'),
|
|
142
|
-
Action.make('gone').label('Gone').visible(false),
|
|
143
|
-
]).schema([]),
|
|
144
|
-
]
|
|
145
|
-
const result = await resolveSchema(tree)
|
|
146
|
-
const after = result[0]!['afterHeader'] as Array<{ name: string }> | undefined
|
|
147
|
-
assert.ok(after)
|
|
148
|
-
assert.equal(after.length, 1)
|
|
149
|
-
assert.equal(after[0]!.name, 'shown')
|
|
150
|
-
})
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
describe('Tabs / Tab', () => {
|
|
154
|
-
it('Tabs resolves with each Tab as a child', async () => {
|
|
155
|
-
const tree = [
|
|
156
|
-
Tabs.make().tabs([
|
|
157
|
-
Tab.make('General').schema([TextField.make('name')]),
|
|
158
|
-
Tab.make('SEO').icon('search').schema([TextField.make('seoTitle')]),
|
|
159
|
-
]),
|
|
160
|
-
]
|
|
161
|
-
const result = await resolveSchema(tree)
|
|
162
|
-
assert.equal(result[0]!.type, 'tabs')
|
|
163
|
-
assert.equal(result[0]!.children?.length, 2)
|
|
164
|
-
assert.equal(result[0]!.children![0]!.type, 'tab')
|
|
165
|
-
assert.equal(result[0]!.children![0]!.label, 'General')
|
|
166
|
-
assert.equal(result[0]!.children![1]!.icon, 'search')
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
it('Tab nests its own children that the resolver walks transitively', async () => {
|
|
170
|
-
const tree = [
|
|
171
|
-
Tabs.make().tabs([
|
|
172
|
-
Tab.make('Inputs').schema([
|
|
173
|
-
TextField.make('a'),
|
|
174
|
-
SelectField.make('b').options([{ value: 'x', label: 'X' }]),
|
|
175
|
-
]),
|
|
176
|
-
]),
|
|
177
|
-
]
|
|
178
|
-
const result = await resolveSchema(tree)
|
|
179
|
-
const firstTab = result[0]!.children![0]!
|
|
180
|
-
assert.equal(firstTab.children?.length, 2)
|
|
181
|
-
assert.equal(firstTab.children![1]!['fieldType'], 'select')
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
it('Tabs default variant is pills, .variant("underline") overrides', async () => {
|
|
185
|
-
const pillsTree = [Tabs.make().tabs([Tab.make('A').schema([])])]
|
|
186
|
-
const pills = await resolveSchema(pillsTree)
|
|
187
|
-
assert.equal(pills[0]!['variant'], 'pills')
|
|
188
|
-
|
|
189
|
-
const underlineTree = [
|
|
190
|
-
Tabs.make().variant('underline').tabs([Tab.make('A').schema([])]),
|
|
191
|
-
]
|
|
192
|
-
const underline = await resolveSchema(underlineTree)
|
|
193
|
-
assert.equal(underline[0]!['variant'], 'underline')
|
|
194
|
-
})
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
describe('Grid', () => {
|
|
198
|
-
it('serializes columns and gap when set', async () => {
|
|
199
|
-
const tree = [Grid.make().columns(3).gap(8).schema([])]
|
|
200
|
-
const result = await resolveSchema(tree)
|
|
201
|
-
assert.equal(result[0]!.type, 'grid')
|
|
202
|
-
assert.equal(result[0]!.columns, 3)
|
|
203
|
-
assert.equal(result[0]!.gap, 8)
|
|
204
|
-
})
|
|
205
|
-
|
|
206
|
-
it('omits gap when not set', async () => {
|
|
207
|
-
const tree = [Grid.make().columns(2).schema([])]
|
|
208
|
-
const result = await resolveSchema(tree)
|
|
209
|
-
assert.equal('gap' in result[0]!, false)
|
|
210
|
-
})
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
describe('Field-as-Element (unified resolver)', () => {
|
|
214
|
-
it('Fields resolve through resolveSchema with type=field', async () => {
|
|
215
|
-
const tree = [
|
|
216
|
-
TextField.make('title').required().placeholder('Type here'),
|
|
217
|
-
]
|
|
218
|
-
const result = await resolveSchema(tree)
|
|
219
|
-
assert.equal(result[0]!.type, 'field')
|
|
220
|
-
assert.equal(result[0]!['fieldType'], 'text')
|
|
221
|
-
assert.equal(result[0]!['name'], 'title')
|
|
222
|
-
assert.equal(result[0]!['required'], true)
|
|
223
|
-
assert.equal(result[0]!['placeholder'], 'Type here')
|
|
224
|
-
})
|
|
225
|
-
|
|
226
|
-
it('hidden Fields are dropped from the resolved tree', async () => {
|
|
227
|
-
const tree = [
|
|
228
|
-
TextField.make('a'),
|
|
229
|
-
TextField.make('b').hideFromTable(),
|
|
230
|
-
TextField.make('c'),
|
|
231
|
-
]
|
|
232
|
-
const result = await resolveSchema(tree, { mode: 'table' })
|
|
233
|
-
assert.equal(result.length, 2)
|
|
234
|
-
assert.deepEqual(result.map(r => r['name']), ['a', 'c'])
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
it('Fields hidden by showWhen are dropped recursively inside containers', async () => {
|
|
238
|
-
const tree = [
|
|
239
|
-
Section.make('Settings').schema([
|
|
240
|
-
TextField.make('always'),
|
|
241
|
-
TextField.make('conditional').showWhen(({ record }) => (record as { ok: boolean }).ok),
|
|
242
|
-
]),
|
|
243
|
-
]
|
|
244
|
-
const result = await resolveSchema(tree, { mode: 'edit', record: { ok: false } })
|
|
245
|
-
assert.equal(result[0]!.children?.length, 1)
|
|
246
|
-
assert.equal(result[0]!.children![0]!['name'], 'always')
|
|
247
|
-
})
|
|
248
|
-
|
|
249
|
-
it('Fields disabledWhen evaluates against context.record', async () => {
|
|
250
|
-
const tree = [
|
|
251
|
-
TextField.make('locked').disabledWhen(({ record }) => (record as { locked: boolean }).locked),
|
|
252
|
-
]
|
|
253
|
-
const a = await resolveSchema(tree, { mode: 'edit', record: { locked: false } })
|
|
254
|
-
const b = await resolveSchema(tree, { mode: 'edit', record: { locked: true } })
|
|
255
|
-
assert.equal(a[0]!['disabled'], false)
|
|
256
|
-
assert.equal(b[0]!['disabled'], true)
|
|
257
|
-
})
|
|
258
|
-
})
|
|
259
|
-
|
|
260
|
-
describe('Group (Plan #8)', () => {
|
|
261
|
-
it('serializes type:group with no chrome state', async () => {
|
|
262
|
-
const tree = [Group.make().schema([Text.make('hi')])]
|
|
263
|
-
const result = await resolveSchema(tree)
|
|
264
|
-
assert.equal(result[0]!.type, 'group')
|
|
265
|
-
assert.equal(result[0]!.children?.length, 1)
|
|
266
|
-
})
|
|
267
|
-
|
|
268
|
-
it('inherits visibility from Element', async () => {
|
|
269
|
-
const tree = [
|
|
270
|
-
Group.make().visible(({ values }) => values?.['kind'] === 'a').schema([
|
|
271
|
-
TextField.make('inner'),
|
|
272
|
-
]),
|
|
273
|
-
]
|
|
274
|
-
const shown = await resolveSchema(tree, { values: { kind: 'a' } })
|
|
275
|
-
const hidden = await resolveSchema(tree, { values: { kind: 'b' } })
|
|
276
|
-
assert.equal(shown.length, 1)
|
|
277
|
-
assert.equal(hidden.length, 0)
|
|
278
|
-
})
|
|
279
|
-
|
|
280
|
-
it('inherits columnSpan from Element', async () => {
|
|
281
|
-
const tree = [Group.make().columnSpan(2).schema([])]
|
|
282
|
-
const result = await resolveSchema(tree)
|
|
283
|
-
assert.deepEqual(result[0]!._layout, { columnSpan: 2 })
|
|
284
|
-
})
|
|
285
|
-
})
|
|
286
|
-
|
|
287
|
-
describe('Fieldset (Plan #8)', () => {
|
|
288
|
-
it('serializes label, columns, and resolves children', async () => {
|
|
289
|
-
const tree = [
|
|
290
|
-
Fieldset.make('Address').columns(2).schema([
|
|
291
|
-
TextField.make('street'),
|
|
292
|
-
TextField.make('city'),
|
|
293
|
-
]),
|
|
294
|
-
]
|
|
295
|
-
const result = await resolveSchema(tree)
|
|
296
|
-
assert.equal(result[0]!.type, 'fieldset')
|
|
297
|
-
assert.equal(result[0]!.label, 'Address')
|
|
298
|
-
assert.equal(result[0]!.columns, 2)
|
|
299
|
-
assert.equal(result[0]!.children?.length, 2)
|
|
300
|
-
})
|
|
301
|
-
|
|
302
|
-
it('defaults to single-column layout', async () => {
|
|
303
|
-
const tree = [Fieldset.make('Group').schema([])]
|
|
304
|
-
const result = await resolveSchema(tree)
|
|
305
|
-
assert.equal(result[0]!.columns, 1)
|
|
306
|
-
})
|
|
307
|
-
|
|
308
|
-
it('hidden Fieldsets drop themselves and their children', async () => {
|
|
309
|
-
const tree = [
|
|
310
|
-
Fieldset.make('Optional')
|
|
311
|
-
.visible(({ record }) => Boolean((record as { show?: boolean })?.show))
|
|
312
|
-
.schema([TextField.make('a')]),
|
|
313
|
-
]
|
|
314
|
-
const shown = await resolveSchema(tree, { mode: 'edit', record: { show: true } })
|
|
315
|
-
const hidden = await resolveSchema(tree, { mode: 'edit', record: { show: false } })
|
|
316
|
-
assert.equal(shown.length, 1)
|
|
317
|
-
assert.equal(hidden.length, 0)
|
|
318
|
-
})
|
|
319
|
-
})
|
|
320
|
-
|
|
321
|
-
describe('Split (Plan #8)', () => {
|
|
322
|
-
it('serializes type:split with from:right by default', async () => {
|
|
323
|
-
const tree = [
|
|
324
|
-
Split.make().schema([
|
|
325
|
-
Section.make('Main').schema([TextField.make('a')]),
|
|
326
|
-
Section.make('Aside').aside().schema([TextField.make('b')]),
|
|
327
|
-
]),
|
|
328
|
-
]
|
|
329
|
-
const result = await resolveSchema(tree)
|
|
330
|
-
assert.equal(result[0]!.type, 'split')
|
|
331
|
-
assert.equal(result[0]!.from, 'right')
|
|
332
|
-
assert.equal(result[0]!.gap, 6)
|
|
333
|
-
assert.equal(result[0]!.children?.length, 2)
|
|
334
|
-
})
|
|
335
|
-
|
|
336
|
-
it('from(left) flips the aside side', async () => {
|
|
337
|
-
const tree = [Split.make().from('left').schema([])]
|
|
338
|
-
const result = await resolveSchema(tree)
|
|
339
|
-
assert.equal(result[0]!.from, 'left')
|
|
340
|
-
})
|
|
341
|
-
|
|
342
|
-
it('gap() overrides the default', async () => {
|
|
343
|
-
const tree = [Split.make().gap(8).schema([])]
|
|
344
|
-
const result = await resolveSchema(tree)
|
|
345
|
-
assert.equal(result[0]!.gap, 8)
|
|
346
|
-
})
|
|
347
|
-
|
|
348
|
-
it('inherits visibility from Element', async () => {
|
|
349
|
-
const tree = [Split.make().visible(false).schema([Section.make('hidden').schema([])])]
|
|
350
|
-
const result = await resolveSchema(tree)
|
|
351
|
-
assert.equal(result.length, 0)
|
|
352
|
-
})
|
|
353
|
-
})
|
|
354
|
-
|
|
355
|
-
describe('Wizard / Step (Plan #8)', () => {
|
|
356
|
-
it('serializes type:wizard with default settings', async () => {
|
|
357
|
-
const tree = [
|
|
358
|
-
Wizard.make().steps([
|
|
359
|
-
Step.make('Account').schema([TextField.make('email')]),
|
|
360
|
-
Step.make('Profile').schema([TextField.make('name')]),
|
|
361
|
-
]),
|
|
362
|
-
]
|
|
363
|
-
const result = await resolveSchema(tree)
|
|
364
|
-
assert.equal(result[0]!.type, 'wizard')
|
|
365
|
-
assert.equal(result[0]!['skippable'], false)
|
|
366
|
-
assert.equal(result[0]!['startOnStep'], 0)
|
|
367
|
-
assert.equal(result[0]!['persist'], true)
|
|
368
|
-
assert.equal(result[0]!.children?.length, 2)
|
|
369
|
-
})
|
|
370
|
-
|
|
371
|
-
it('Step serializes label, icon, description', async () => {
|
|
372
|
-
const tree = [
|
|
373
|
-
Wizard.make().steps([
|
|
374
|
-
Step.make('Account').icon('user').description('Login details.').schema([
|
|
375
|
-
TextField.make('email'),
|
|
376
|
-
]),
|
|
377
|
-
]),
|
|
378
|
-
]
|
|
379
|
-
const result = await resolveSchema(tree)
|
|
380
|
-
const step = result[0]!.children![0]!
|
|
381
|
-
assert.equal(step.type, 'step')
|
|
382
|
-
assert.equal(step['label'], 'Account')
|
|
383
|
-
assert.equal(step['icon'], 'user')
|
|
384
|
-
assert.equal(step['description'], 'Login details.')
|
|
385
|
-
assert.equal(step.children?.length, 1)
|
|
386
|
-
})
|
|
387
|
-
|
|
388
|
-
it('skippable + startOnStep + persist setters round-trip', async () => {
|
|
389
|
-
const tree = [
|
|
390
|
-
Wizard.make().skippable().startOnStep(2).persist(false).steps([
|
|
391
|
-
Step.make('a').schema([]),
|
|
392
|
-
Step.make('b').schema([]),
|
|
393
|
-
Step.make('c').schema([]),
|
|
394
|
-
]),
|
|
395
|
-
]
|
|
396
|
-
const result = await resolveSchema(tree)
|
|
397
|
-
assert.equal(result[0]!['skippable'], true)
|
|
398
|
-
assert.equal(result[0]!['startOnStep'], 2)
|
|
399
|
-
assert.equal(result[0]!['persist'], false)
|
|
400
|
-
})
|
|
401
|
-
|
|
402
|
-
describe('Step.beforeValidation / afterValidation', () => {
|
|
403
|
-
it('accessors return undefined when no hooks are set', () => {
|
|
404
|
-
const step = Step.make('x').schema([])
|
|
405
|
-
assert.equal(step.getBeforeValidation(), undefined)
|
|
406
|
-
assert.equal(step.getAfterValidation(), undefined)
|
|
407
|
-
})
|
|
408
|
-
|
|
409
|
-
it('accessors return the registered hook function', () => {
|
|
410
|
-
const before = async () => {}
|
|
411
|
-
const after = () => {}
|
|
412
|
-
const step = Step.make('x').schema([]).beforeValidation(before).afterValidation(after)
|
|
413
|
-
assert.equal(step.getBeforeValidation(), before)
|
|
414
|
-
assert.equal(step.getAfterValidation(), after)
|
|
415
|
-
})
|
|
416
|
-
|
|
417
|
-
it('hooks are not serialized into the wire shape', async () => {
|
|
418
|
-
const tree = [
|
|
419
|
-
Wizard.make().steps([
|
|
420
|
-
Step.make('a').schema([]).beforeValidation(() => {}).afterValidation(() => {}),
|
|
421
|
-
]),
|
|
422
|
-
]
|
|
423
|
-
const result = await resolveSchema(tree)
|
|
424
|
-
const step = result[0]!.children![0]!
|
|
425
|
-
assert.equal(step['beforeValidation'], undefined)
|
|
426
|
-
assert.equal(step['afterValidation'], undefined)
|
|
427
|
-
})
|
|
428
|
-
})
|
|
429
|
-
|
|
430
|
-
describe('persistStepInQueryString', () => {
|
|
431
|
-
it('omits the meta key by default', async () => {
|
|
432
|
-
const tree = [Wizard.make().steps([Step.make('a').schema([])])]
|
|
433
|
-
const result = await resolveSchema(tree)
|
|
434
|
-
assert.equal(result[0]!['persistStepInQueryString'], undefined)
|
|
435
|
-
})
|
|
436
|
-
|
|
437
|
-
it('bare call defaults to "step"', async () => {
|
|
438
|
-
const tree = [
|
|
439
|
-
Wizard.make().persistStepInQueryString().steps([Step.make('a').schema([])]),
|
|
440
|
-
]
|
|
441
|
-
const result = await resolveSchema(tree)
|
|
442
|
-
assert.equal(result[0]!['persistStepInQueryString'], 'step')
|
|
443
|
-
})
|
|
444
|
-
|
|
445
|
-
it('explicit string overrides the key', async () => {
|
|
446
|
-
const tree = [
|
|
447
|
-
Wizard.make().persistStepInQueryString('checkout').steps([Step.make('a').schema([])]),
|
|
448
|
-
]
|
|
449
|
-
const result = await resolveSchema(tree)
|
|
450
|
-
assert.equal(result[0]!['persistStepInQueryString'], 'checkout')
|
|
451
|
-
})
|
|
452
|
-
|
|
453
|
-
it('false clears a previously-set key', async () => {
|
|
454
|
-
const tree = [
|
|
455
|
-
Wizard.make().persistStepInQueryString('foo').persistStepInQueryString(false)
|
|
456
|
-
.steps([Step.make('a').schema([])]),
|
|
457
|
-
]
|
|
458
|
-
const result = await resolveSchema(tree)
|
|
459
|
-
assert.equal(result[0]!['persistStepInQueryString'], undefined)
|
|
460
|
-
})
|
|
461
|
-
})
|
|
462
|
-
|
|
463
|
-
describe('submitAction / nextAction / previousAction customizers', () => {
|
|
464
|
-
it('omits the meta keys when no customizer is set', async () => {
|
|
465
|
-
const tree = [Wizard.make().steps([Step.make('a').schema([])])]
|
|
466
|
-
const result = await resolveSchema(tree)
|
|
467
|
-
assert.equal(result[0]!['submitAction'], undefined)
|
|
468
|
-
assert.equal(result[0]!['nextAction'], undefined)
|
|
469
|
-
assert.equal(result[0]!['previousAction'], undefined)
|
|
470
|
-
})
|
|
471
|
-
|
|
472
|
-
it('customizer receives a default Action with sensible chrome', async () => {
|
|
473
|
-
let receivedSubmit: string | undefined
|
|
474
|
-
let receivedNext: string | undefined
|
|
475
|
-
let receivedPrevious: string | undefined
|
|
476
|
-
const tree = [
|
|
477
|
-
Wizard.make()
|
|
478
|
-
.submitAction(a => { receivedSubmit = a.getLabel(); return a })
|
|
479
|
-
.nextAction(a => { receivedNext = a.getLabel(); return a })
|
|
480
|
-
.previousAction(a => { receivedPrevious = a.getLabel(); return a })
|
|
481
|
-
.steps([Step.make('a').schema([])]),
|
|
482
|
-
]
|
|
483
|
-
await resolveSchema(tree)
|
|
484
|
-
assert.equal(receivedSubmit, 'Submit')
|
|
485
|
-
assert.equal(receivedNext, 'Next')
|
|
486
|
-
assert.equal(receivedPrevious, 'Back')
|
|
487
|
-
})
|
|
488
|
-
|
|
489
|
-
it('customizer chrome flows through to the resolved meta', async () => {
|
|
490
|
-
const tree = [
|
|
491
|
-
Wizard.make()
|
|
492
|
-
.submitAction(a => a.label('Create campaign').size('lg'))
|
|
493
|
-
.nextAction(a => a.label('Continue').icon('arrow-right'))
|
|
494
|
-
.previousAction(Action.make('back').label('Go back').color('ghost'))
|
|
495
|
-
.steps([Step.make('a').schema([])]),
|
|
496
|
-
]
|
|
497
|
-
const result = await resolveSchema(tree)
|
|
498
|
-
const submit = result[0]!['submitAction'] as Record<string, unknown>
|
|
499
|
-
const next = result[0]!['nextAction'] as Record<string, unknown>
|
|
500
|
-
const previous = result[0]!['previousAction'] as Record<string, unknown>
|
|
501
|
-
assert.equal(submit['label'], 'Create campaign')
|
|
502
|
-
assert.equal(submit['size'], 'lg')
|
|
503
|
-
assert.equal(next['label'], 'Continue')
|
|
504
|
-
assert.equal(next['icon'], 'arrow-right')
|
|
505
|
-
assert.equal(previous['label'], 'Go back')
|
|
506
|
-
assert.equal(previous['color'], 'ghost')
|
|
507
|
-
})
|
|
508
|
-
|
|
509
|
-
it('customizer that hides the action drops the slot from meta', async () => {
|
|
510
|
-
const tree = [
|
|
511
|
-
Wizard.make()
|
|
512
|
-
.nextAction(a => a.visible(false))
|
|
513
|
-
.steps([Step.make('a').schema([])]),
|
|
514
|
-
]
|
|
515
|
-
const result = await resolveSchema(tree)
|
|
516
|
-
assert.equal(result[0]!['nextAction'], undefined)
|
|
517
|
-
})
|
|
518
|
-
})
|
|
519
|
-
|
|
520
|
-
it('all step children resolve so cross-step $get works', async () => {
|
|
521
|
-
// Step 2 has a Section that hides based on a value entered in Step 0;
|
|
522
|
-
// both steps must be resolved on every cycle for the predicate to fire.
|
|
523
|
-
const tree = [
|
|
524
|
-
Wizard.make().steps([
|
|
525
|
-
Step.make('a').schema([TextField.make('flag')]),
|
|
526
|
-
Step.make('b').schema([
|
|
527
|
-
Section.make('conditional')
|
|
528
|
-
.visible(({ values }) => values?.['flag'] === 'show')
|
|
529
|
-
.schema([TextField.make('inside')]),
|
|
530
|
-
]),
|
|
531
|
-
]),
|
|
532
|
-
]
|
|
533
|
-
const shown = await resolveSchema(tree, { values: { flag: 'show' } })
|
|
534
|
-
const hidden = await resolveSchema(tree, { values: { flag: 'hide' } })
|
|
535
|
-
const stepBShown = shown[0]!.children![1]!
|
|
536
|
-
const stepBHidden = hidden[0]!.children![1]!
|
|
537
|
-
// Section should appear/disappear inside step b based on the flag.
|
|
538
|
-
assert.equal(stepBShown.children?.length, 1)
|
|
539
|
-
assert.equal(stepBHidden.children?.length, 0)
|
|
540
|
-
})
|
|
541
|
-
})
|
|
542
|
-
|
|
543
|
-
describe('mixing Fields + display elements + containers', () => {
|
|
544
|
-
it('a Card can contain Heading + Field + nested Section', async () => {
|
|
545
|
-
const tree = [
|
|
546
|
-
Card.make('Article').schema([
|
|
547
|
-
Heading.make('Edit your article'),
|
|
548
|
-
TextField.make('title').required(),
|
|
549
|
-
Section.make('SEO').columns(2).schema([
|
|
550
|
-
TextField.make('seoTitle'),
|
|
551
|
-
TextField.make('seoDescription'),
|
|
552
|
-
]),
|
|
553
|
-
]),
|
|
554
|
-
]
|
|
555
|
-
const result = await resolveSchema(tree, { mode: 'edit' })
|
|
556
|
-
|
|
557
|
-
assert.equal(result[0]!.type, 'card')
|
|
558
|
-
assert.equal(result[0]!.children?.length, 3)
|
|
559
|
-
assert.equal(result[0]!.children![0]!.type, 'heading')
|
|
560
|
-
assert.equal(result[0]!.children![1]!.type, 'field')
|
|
561
|
-
assert.equal(result[0]!.children![2]!.type, 'section')
|
|
562
|
-
assert.equal(result[0]!.children![2]!.children?.length, 2)
|
|
563
|
-
})
|
|
564
|
-
})
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import { describe, it, beforeEach } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
|
|
4
|
-
import { resolveSchema, _resetResolverRegistry } from './resolveSchema.js'
|
|
5
|
-
import { MetaTag } from './MetaTag.js'
|
|
6
|
-
import { LinkTag } from './LinkTag.js'
|
|
7
|
-
import { ScriptTag } from './ScriptTag.js'
|
|
8
|
-
import { StyleTag } from './StyleTag.js'
|
|
9
|
-
|
|
10
|
-
beforeEach(() => _resetResolverRegistry())
|
|
11
|
-
|
|
12
|
-
describe('MetaTag head element', () => {
|
|
13
|
-
it('emits name + content', async () => {
|
|
14
|
-
const out = await resolveSchema([MetaTag.make({ name: 'csrf-token', content: 'abc' })])
|
|
15
|
-
assert.equal(out[0]!.type, 'meta')
|
|
16
|
-
assert.equal(out[0]!['name'], 'csrf-token')
|
|
17
|
-
assert.equal(out[0]!['content'], 'abc')
|
|
18
|
-
assert.equal(out[0]!['property'], undefined)
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
it('emits property + content (Open Graph shape)', async () => {
|
|
22
|
-
const out = await resolveSchema([MetaTag.make({ property: 'og:image', content: 'https://x/y.png' })])
|
|
23
|
-
assert.equal(out[0]!['property'], 'og:image')
|
|
24
|
-
assert.equal(out[0]!['content'], 'https://x/y.png')
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
it('emits httpEquiv + charset', async () => {
|
|
28
|
-
const out = await resolveSchema([
|
|
29
|
-
MetaTag.make({ httpEquiv: 'X-UA-Compatible', content: 'IE=edge' }),
|
|
30
|
-
MetaTag.make({ charset: 'utf-8' }),
|
|
31
|
-
])
|
|
32
|
-
assert.equal(out[0]!['httpEquiv'], 'X-UA-Compatible')
|
|
33
|
-
assert.equal(out[1]!['charset'], 'utf-8')
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('honors layout-level visibility', async () => {
|
|
37
|
-
const tree = [
|
|
38
|
-
MetaTag.make({ name: 'env', content: 'prod' }).visible(({ user }) => Boolean(user)),
|
|
39
|
-
MetaTag.make({ name: 'env', content: 'guest' }).visible(({ user }) => !user),
|
|
40
|
-
]
|
|
41
|
-
const out = await resolveSchema(tree, {}) // no user
|
|
42
|
-
assert.equal(out.length, 1)
|
|
43
|
-
assert.equal(out[0]!['content'], 'guest')
|
|
44
|
-
})
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
describe('LinkTag head element', () => {
|
|
48
|
-
it('emits rel + href + mimeType', async () => {
|
|
49
|
-
const out = await resolveSchema([
|
|
50
|
-
LinkTag.make({ rel: 'icon', href: '/favicon.svg', mimeType: 'image/svg+xml' }),
|
|
51
|
-
])
|
|
52
|
-
assert.equal(out[0]!.type, 'link')
|
|
53
|
-
assert.equal(out[0]!['rel'], 'icon')
|
|
54
|
-
assert.equal(out[0]!['href'], '/favicon.svg')
|
|
55
|
-
assert.equal(out[0]!['mimeType'], 'image/svg+xml')
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
it('emits canonical link', async () => {
|
|
59
|
-
const out = await resolveSchema([
|
|
60
|
-
LinkTag.make({ rel: 'canonical', href: 'https://app.example.com/dashboard' }),
|
|
61
|
-
])
|
|
62
|
-
assert.equal(out[0]!['rel'], 'canonical')
|
|
63
|
-
assert.equal(out[0]!['href'], 'https://app.example.com/dashboard')
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
it('rides extra attrs (sizes / integrity / crossOrigin)', async () => {
|
|
67
|
-
const out = await resolveSchema([
|
|
68
|
-
LinkTag.make({
|
|
69
|
-
rel: 'preload',
|
|
70
|
-
href: '/fonts/x.woff2',
|
|
71
|
-
as: 'font',
|
|
72
|
-
mimeType: 'font/woff2',
|
|
73
|
-
crossOrigin: 'anonymous',
|
|
74
|
-
}),
|
|
75
|
-
])
|
|
76
|
-
assert.equal(out[0]!['as'], 'font')
|
|
77
|
-
assert.equal(out[0]!['crossOrigin'], 'anonymous')
|
|
78
|
-
})
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
describe('ScriptTag head element', () => {
|
|
82
|
-
it('emits external src + defer + dataAttributes', async () => {
|
|
83
|
-
const out = await resolveSchema([
|
|
84
|
-
ScriptTag.make({
|
|
85
|
-
src: 'https://plausible.io/js/script.js',
|
|
86
|
-
defer: true,
|
|
87
|
-
dataAttributes: { domain: 'example.com', api: '/proxy/event' },
|
|
88
|
-
}),
|
|
89
|
-
])
|
|
90
|
-
assert.equal(out[0]!.type, 'script')
|
|
91
|
-
assert.equal(out[0]!['src'], 'https://plausible.io/js/script.js')
|
|
92
|
-
assert.equal(out[0]!['defer'], true)
|
|
93
|
-
assert.deepEqual(out[0]!['dataAttributes'], { domain: 'example.com', api: '/proxy/event' })
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
it('emits inline body for window-globals', async () => {
|
|
97
|
-
const out = await resolveSchema([
|
|
98
|
-
ScriptTag.make({ body: 'window.__APP_TENANT__ = "acme"' }),
|
|
99
|
-
])
|
|
100
|
-
assert.equal(out[0]!['body'], 'window.__APP_TENANT__ = "acme"')
|
|
101
|
-
assert.equal(out[0]!['src'], undefined)
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
it('emits async + nonce + integrity', async () => {
|
|
105
|
-
const out = await resolveSchema([
|
|
106
|
-
ScriptTag.make({
|
|
107
|
-
src: 'https://x/y.js',
|
|
108
|
-
async: true,
|
|
109
|
-
nonce: 'abc123',
|
|
110
|
-
integrity: 'sha384-xxx',
|
|
111
|
-
crossOrigin: 'anonymous',
|
|
112
|
-
}),
|
|
113
|
-
])
|
|
114
|
-
assert.equal(out[0]!['async'], true)
|
|
115
|
-
assert.equal(out[0]!['nonce'], 'abc123')
|
|
116
|
-
assert.equal(out[0]!['integrity'], 'sha384-xxx')
|
|
117
|
-
assert.equal(out[0]!['crossOrigin'], 'anonymous')
|
|
118
|
-
})
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
describe('StyleTag head element', () => {
|
|
122
|
-
it('emits inline css', async () => {
|
|
123
|
-
const css = ':root { --pilotiq-brand: #d97757; }'
|
|
124
|
-
const out = await resolveSchema([StyleTag.make(css)])
|
|
125
|
-
assert.equal(out[0]!.type, 'style')
|
|
126
|
-
assert.equal(out[0]!['css'], css)
|
|
127
|
-
assert.equal(out[0]!['nonce'], undefined)
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
it('emits nonce when supplied', async () => {
|
|
131
|
-
const out = await resolveSchema([StyleTag.make('body { color: red }', { nonce: 'n1' })])
|
|
132
|
-
assert.equal(out[0]!['nonce'], 'n1')
|
|
133
|
-
})
|
|
134
|
-
})
|