@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.
- package/CHANGELOG.md +33 -0
- package/boost/guidelines.md +566 -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/package.json +6 -1
- 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,58 +0,0 @@
|
|
|
1
|
-
import { describe, it } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
|
|
4
|
-
import { TextareaField } from './TextareaField.js'
|
|
5
|
-
|
|
6
|
-
describe('TextareaField', () => {
|
|
7
|
-
it('emits fieldType "textarea" and rows defaulting to 4', () => {
|
|
8
|
-
const meta = TextareaField.make('bio').toMeta()
|
|
9
|
-
assert.equal(meta.fieldType, 'textarea')
|
|
10
|
-
assert.equal(meta['rows'], 4)
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
it('rows(n) overrides the default', () => {
|
|
14
|
-
const meta = TextareaField.make('bio').rows(10).toMeta()
|
|
15
|
-
assert.equal(meta['rows'], 10)
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
it('cols(n) emits cols only when set', () => {
|
|
19
|
-
const off = TextareaField.make('bio').toMeta()
|
|
20
|
-
const on = TextareaField.make('bio').cols(40).toMeta()
|
|
21
|
-
assert.equal(off['cols'], undefined)
|
|
22
|
-
assert.equal(on['cols'], 40)
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
it('autosize() emits the flag only when called', () => {
|
|
26
|
-
const off = TextareaField.make('bio').toMeta()
|
|
27
|
-
const on = TextareaField.make('bio').autosize().toMeta()
|
|
28
|
-
assert.equal(off['autosize'], undefined)
|
|
29
|
-
assert.equal(on['autosize'], true)
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
it('autosize(false) is a no-op default', () => {
|
|
33
|
-
const meta = TextareaField.make('bio').autosize(false).toMeta()
|
|
34
|
-
assert.equal(meta['autosize'], undefined)
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
it('disableGrammarly() emits the flag only when called', () => {
|
|
38
|
-
const off = TextareaField.make('bio').toMeta()
|
|
39
|
-
const on = TextareaField.make('bio').disableGrammarly().toMeta()
|
|
40
|
-
assert.equal(off['disableGrammarly'], undefined)
|
|
41
|
-
assert.equal(on['disableGrammarly'], true)
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
it('the chainables compose with each other and with rows/required', () => {
|
|
45
|
-
const meta = TextareaField.make('bio')
|
|
46
|
-
.rows(8)
|
|
47
|
-
.cols(60)
|
|
48
|
-
.autosize()
|
|
49
|
-
.disableGrammarly()
|
|
50
|
-
.required()
|
|
51
|
-
.toMeta()
|
|
52
|
-
assert.equal(meta['rows'], 8)
|
|
53
|
-
assert.equal(meta['cols'], 60)
|
|
54
|
-
assert.equal(meta['autosize'], true)
|
|
55
|
-
assert.equal(meta['disableGrammarly'], true)
|
|
56
|
-
assert.equal(meta.required, true)
|
|
57
|
-
})
|
|
58
|
-
})
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { Field, type FieldMeta } from './Field.js'
|
|
2
|
-
import type { RenderContext } from '../schema/resolveSchema.js'
|
|
3
|
-
|
|
4
|
-
export class TextareaField extends Field {
|
|
5
|
-
private _rows = 4
|
|
6
|
-
private _cols?: number
|
|
7
|
-
private _autosize = false
|
|
8
|
-
private _disableGrammarly = false
|
|
9
|
-
|
|
10
|
-
private constructor(name: string) {
|
|
11
|
-
super(name, 'textarea')
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
static make(name: string): TextareaField {
|
|
15
|
-
return new TextareaField(name)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
rows(n: number): this { this._rows = n; return this }
|
|
19
|
-
getRows(): number { return this._rows }
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* HTML `cols` attribute on the underlying `<textarea>`. Sets the
|
|
23
|
-
* visible character width independent of the parent column / span.
|
|
24
|
-
* Most apps lean on `rows()` + the field's flex layout instead — pass
|
|
25
|
-
* `cols(n)` only when you need an explicit character-grid width.
|
|
26
|
-
*/
|
|
27
|
-
cols(n: number): this { this._cols = n; return this }
|
|
28
|
-
getCols(): number | undefined { return this._cols }
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Auto-grow the textarea so its height matches the typed content (no
|
|
32
|
-
* scrollbar until `maxHeight`). Implemented in CSS via the existing
|
|
33
|
-
* `field-sizing-content` utility on `<Textarea>` — `autosize()` simply
|
|
34
|
-
* keeps the chrome and unsets the explicit `rows` so the browser can
|
|
35
|
-
* size to content. Off by default to preserve the legacy fixed-height
|
|
36
|
-
* look on bare `TextareaField.make(...)`.
|
|
37
|
-
*/
|
|
38
|
-
autosize(v = true): this { this._autosize = v; return this }
|
|
39
|
-
isAutosize(): boolean { return this._autosize }
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Add `data-gramm="false"` (plus the matching Grammarly extension
|
|
43
|
-
* disable attributes) so the third-party browser overlay doesn't mount
|
|
44
|
-
* on this field. Use for sensitive content (slug source, DB queries,
|
|
45
|
-
* code snippets) where the overlay's UI corrupts cursor placement.
|
|
46
|
-
*/
|
|
47
|
-
disableGrammarly(v = true): this { this._disableGrammarly = v; return this }
|
|
48
|
-
isGrammarlyDisabled(): boolean { return this._disableGrammarly }
|
|
49
|
-
|
|
50
|
-
override toMeta(ctx?: RenderContext): FieldMeta {
|
|
51
|
-
return {
|
|
52
|
-
...this.buildMeta(ctx),
|
|
53
|
-
rows: this._rows,
|
|
54
|
-
...(this._cols !== undefined ? { cols: this._cols } : {}),
|
|
55
|
-
...(this._autosize ? { autosize: true } : {}),
|
|
56
|
-
...(this._disableGrammarly ? { disableGrammarly: true } : {}),
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { describe, it } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
|
|
4
|
-
import { ToggleButtonsField, ToggleButtons } from './ToggleButtonsField.js'
|
|
5
|
-
|
|
6
|
-
describe('ToggleButtonsField', () => {
|
|
7
|
-
it('emits fieldType "toggleButtons"', async () => {
|
|
8
|
-
const meta = await ToggleButtonsField.make('priority').toMeta()
|
|
9
|
-
assert.equal(meta.fieldType, 'toggleButtons')
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
it('exports an alias `ToggleButtons`', () => {
|
|
13
|
-
assert.equal(ToggleButtons, ToggleButtonsField)
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
it('does NOT emit an `inline` flag (chips are always horizontal)', async () => {
|
|
17
|
-
const meta = await ToggleButtonsField.make('x').toMeta()
|
|
18
|
-
assert.equal('inline' in meta, false)
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
describe('options(static array)', () => {
|
|
22
|
-
it('emits options array verbatim', async () => {
|
|
23
|
-
const meta = await ToggleButtonsField.make('priority').options([
|
|
24
|
-
{ value: 'low', label: 'Low' },
|
|
25
|
-
{ value: 'high', label: 'High' },
|
|
26
|
-
]).toMeta()
|
|
27
|
-
assert.deepEqual(meta['options'], [
|
|
28
|
-
{ value: 'low', label: 'Low' },
|
|
29
|
-
{ value: 'high', label: 'High' },
|
|
30
|
-
])
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
it('hasDynamicOptions is false for static arrays', () => {
|
|
34
|
-
const f = ToggleButtonsField.make('priority').options([{ value: 'a', label: 'A' }])
|
|
35
|
-
assert.equal(f.hasDynamicOptions(), false)
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
it('getOptions returns the array', () => {
|
|
39
|
-
const f = ToggleButtonsField.make('priority').options([{ value: 'a', label: 'A' }])
|
|
40
|
-
assert.deepEqual(f.getOptions(), [{ value: 'a', label: 'A' }])
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
it('options default to [] when never configured', async () => {
|
|
44
|
-
const meta = await ToggleButtonsField.make('x').toMeta()
|
|
45
|
-
assert.deepEqual(meta['options'], [])
|
|
46
|
-
})
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
describe('options(resolver function)', () => {
|
|
50
|
-
it('runs the resolver against ctx', async () => {
|
|
51
|
-
const f = ToggleButtonsField.make('plan').options(({ $get }) => {
|
|
52
|
-
const tier = $get?.('tier') as string | undefined
|
|
53
|
-
if (tier === 'pro') return [{ value: 'monthly', label: 'Monthly' }]
|
|
54
|
-
return [{ value: 'free', label: 'Free' }]
|
|
55
|
-
})
|
|
56
|
-
assert.equal(f.hasDynamicOptions(), true)
|
|
57
|
-
const meta = await f.toMeta({
|
|
58
|
-
values: { tier: 'pro' },
|
|
59
|
-
$get: (n) => ({ tier: 'pro' } as Record<string, unknown>)[n],
|
|
60
|
-
})
|
|
61
|
-
assert.deepEqual(meta['options'], [{ value: 'monthly', label: 'Monthly' }])
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
it('async resolver is awaited', async () => {
|
|
65
|
-
const f = ToggleButtonsField.make('items').options(async () => {
|
|
66
|
-
await new Promise(r => setTimeout(r, 1))
|
|
67
|
-
return [{ value: 'a', label: 'A' }]
|
|
68
|
-
})
|
|
69
|
-
const meta = await f.toMeta()
|
|
70
|
-
assert.deepEqual(meta['options'], [{ value: 'a', label: 'A' }])
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
it('thrown resolver returns empty options + console.warn', async () => {
|
|
74
|
-
const original = console.warn
|
|
75
|
-
const calls: unknown[] = []
|
|
76
|
-
console.warn = (...args: unknown[]) => { calls.push(args) }
|
|
77
|
-
try {
|
|
78
|
-
const f = ToggleButtonsField.make('broken').options(() => { throw new Error('boom') })
|
|
79
|
-
const meta = await f.toMeta()
|
|
80
|
-
assert.deepEqual(meta['options'], [])
|
|
81
|
-
assert.equal(calls.length, 1)
|
|
82
|
-
} finally {
|
|
83
|
-
console.warn = original
|
|
84
|
-
}
|
|
85
|
-
})
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
it('participates in cross-field plumbing (default / required / live)', async () => {
|
|
89
|
-
const f = ToggleButtonsField.make('priority')
|
|
90
|
-
.label('Priority')
|
|
91
|
-
.required()
|
|
92
|
-
.default('medium')
|
|
93
|
-
.live()
|
|
94
|
-
.options([
|
|
95
|
-
{ value: 'low', label: 'Low' },
|
|
96
|
-
{ value: 'medium', label: 'Medium' },
|
|
97
|
-
{ value: 'high', label: 'High' },
|
|
98
|
-
])
|
|
99
|
-
const meta = await f.toMeta()
|
|
100
|
-
assert.equal(meta.fieldType, 'toggleButtons')
|
|
101
|
-
assert.equal(meta.required, true)
|
|
102
|
-
assert.equal(meta['defaultValue'], 'medium')
|
|
103
|
-
assert.equal(meta['live'], true)
|
|
104
|
-
assert.equal(meta.label, 'Priority')
|
|
105
|
-
})
|
|
106
|
-
})
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { Field, type FieldMeta } from './Field.js'
|
|
2
|
-
import {
|
|
3
|
-
resolveOptions,
|
|
4
|
-
disableOptionsTakenInSiblings,
|
|
5
|
-
type OptionsResolver,
|
|
6
|
-
type SelectOption,
|
|
7
|
-
} from './optionsResolver.js'
|
|
8
|
-
import type { RenderContext } from '../schema/resolveSchema.js'
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Single-choice field rendered as a horizontal segmented chip group.
|
|
12
|
-
* Sugar over `RadioField` with the same `OptionsResolver` shape; the
|
|
13
|
-
* difference is purely visual — `RadioField` paints a vertical (or
|
|
14
|
-
* `inline:true`) stack of native radios, `ToggleButtonsField` paints
|
|
15
|
-
* a row of pill-shaped buttons styled like a segmented control.
|
|
16
|
-
*
|
|
17
|
-
* Multi-select is intentionally out of scope in v1; reach for
|
|
18
|
-
* `CheckboxListField` for that.
|
|
19
|
-
*/
|
|
20
|
-
export class ToggleButtonsField extends Field {
|
|
21
|
-
private _options: SelectOption[] | OptionsResolver = []
|
|
22
|
-
|
|
23
|
-
private constructor(name: string) {
|
|
24
|
-
super(name, 'toggleButtons')
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
static make(name: string): ToggleButtonsField {
|
|
28
|
-
return new ToggleButtonsField(name)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
options(opts: SelectOption[] | OptionsResolver): this {
|
|
32
|
-
this._options = opts
|
|
33
|
-
return this
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
getOptions(): SelectOption[] {
|
|
37
|
-
return Array.isArray(this._options) ? this._options : []
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
hasDynamicOptions(): boolean {
|
|
41
|
-
return typeof this._options === 'function'
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
override async toMeta(ctx?: RenderContext): Promise<FieldMeta> {
|
|
45
|
-
const base = this.buildMeta(ctx)
|
|
46
|
-
const options = disableOptionsTakenInSiblings(
|
|
47
|
-
await resolveOptions(this._options, ctx, this.name),
|
|
48
|
-
this.shouldDisableOptionsTakenInSiblings(),
|
|
49
|
-
this.name,
|
|
50
|
-
ctx,
|
|
51
|
-
)
|
|
52
|
-
return {
|
|
53
|
-
...base,
|
|
54
|
-
options,
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export const ToggleButtons = ToggleButtonsField
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { Field, type FieldMeta } from './Field.js'
|
|
2
|
-
import type { RenderContext } from '../schema/resolveSchema.js'
|
|
3
|
-
|
|
4
|
-
export class ToggleField extends Field {
|
|
5
|
-
private constructor(name: string) {
|
|
6
|
-
super(name, 'toggle')
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
static make(name: string): ToggleField {
|
|
10
|
-
return new ToggleField(name)
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
override toMeta(ctx?: RenderContext): FieldMeta {
|
|
14
|
-
return this.buildMeta(ctx)
|
|
15
|
-
}
|
|
16
|
-
}
|
|
@@ -1,319 +0,0 @@
|
|
|
1
|
-
import { describe, it } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
|
|
4
|
-
import { SelectField } from './SelectField.js'
|
|
5
|
-
import { RadioField } from './RadioField.js'
|
|
6
|
-
import { CheckboxListField } from './CheckboxListField.js'
|
|
7
|
-
import { ToggleButtonsField } from './ToggleButtonsField.js'
|
|
8
|
-
import { TextField } from './TextField.js'
|
|
9
|
-
import { RepeaterField, type RepeaterFieldMeta } from './RepeaterField.js'
|
|
10
|
-
import { BuilderField, type BuilderFieldMeta } from './BuilderField.js'
|
|
11
|
-
import { Block } from '../schema/Block.js'
|
|
12
|
-
import { resolveSchema } from '../schema/resolveSchema.js'
|
|
13
|
-
import { disableOptionsTakenInSiblings, type SelectOption } from './optionsResolver.js'
|
|
14
|
-
|
|
15
|
-
const colours = [
|
|
16
|
-
{ value: 'red', label: 'Red' },
|
|
17
|
-
{ value: 'green', label: 'Green' },
|
|
18
|
-
{ value: 'blue', label: 'Blue' },
|
|
19
|
-
]
|
|
20
|
-
|
|
21
|
-
function rowOptions(meta: RepeaterFieldMeta | BuilderFieldMeta, rowIdx: number, fieldName: string): SelectOption[] {
|
|
22
|
-
const row = meta.rows[rowIdx]
|
|
23
|
-
if (!row) throw new Error(`row ${rowIdx} missing`)
|
|
24
|
-
const child = row.children.find(c => c['name'] === fieldName)
|
|
25
|
-
if (!child) throw new Error(`field "${fieldName}" missing in row ${rowIdx}`)
|
|
26
|
-
return (child['options'] as SelectOption[]) ?? []
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
describe('disableOptionsWhenSelectedInSiblingRepeaterItems', () => {
|
|
30
|
-
describe('flag plumbing', () => {
|
|
31
|
-
it('default is disabled', () => {
|
|
32
|
-
const f = SelectField.make('color')
|
|
33
|
-
assert.equal(f.shouldDisableOptionsTakenInSiblings(), false)
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('enables flag + auto-arms distinct() and live()', () => {
|
|
37
|
-
const f = SelectField.make('color').disableOptionsWhenSelectedInSiblingRepeaterItems()
|
|
38
|
-
assert.equal(f.shouldDisableOptionsTakenInSiblings(), true)
|
|
39
|
-
assert.notEqual(f.getDistinct(), undefined)
|
|
40
|
-
assert.equal(f.isLive(), true)
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
it('disableOptionsWhenSelectedInSiblingRepeaterItems(false) clears the flag', () => {
|
|
44
|
-
const f = SelectField.make('color').disableOptionsWhenSelectedInSiblingRepeaterItems()
|
|
45
|
-
.disableOptionsWhenSelectedInSiblingRepeaterItems(false)
|
|
46
|
-
assert.equal(f.shouldDisableOptionsTakenInSiblings(), false)
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
it('available on Radio / CheckboxList / ToggleButtons too', () => {
|
|
50
|
-
assert.equal(
|
|
51
|
-
RadioField.make('x').disableOptionsWhenSelectedInSiblingRepeaterItems().shouldDisableOptionsTakenInSiblings(),
|
|
52
|
-
true,
|
|
53
|
-
)
|
|
54
|
-
assert.equal(
|
|
55
|
-
CheckboxListField.make('x').disableOptionsWhenSelectedInSiblingRepeaterItems().shouldDisableOptionsTakenInSiblings(),
|
|
56
|
-
true,
|
|
57
|
-
)
|
|
58
|
-
assert.equal(
|
|
59
|
-
ToggleButtonsField.make('x').disableOptionsWhenSelectedInSiblingRepeaterItems().shouldDisableOptionsTakenInSiblings(),
|
|
60
|
-
true,
|
|
61
|
-
)
|
|
62
|
-
})
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
describe('disableOptionsTakenInSiblings helper', () => {
|
|
66
|
-
it('no-op when disabled', () => {
|
|
67
|
-
const out = disableOptionsTakenInSiblings(colours, false, 'color', { row: { index: 0, $get: () => undefined, $set: () => {}, siblings: [{ color: 'red' }] } })
|
|
68
|
-
assert.deepEqual(out, colours)
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
it('no-op without row.siblings (top-level form)', () => {
|
|
72
|
-
const out = disableOptionsTakenInSiblings(colours, true, 'color', undefined)
|
|
73
|
-
assert.deepEqual(out, colours)
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
it('marks taken values disabled', () => {
|
|
77
|
-
const out = disableOptionsTakenInSiblings(colours, true, 'color', {
|
|
78
|
-
row: { index: 1, $get: () => undefined, $set: () => {}, siblings: [{ color: 'red' }] },
|
|
79
|
-
})
|
|
80
|
-
assert.equal(out[0]?.disabled, true) // red is taken
|
|
81
|
-
assert.equal(out[1]?.disabled, undefined)
|
|
82
|
-
assert.equal(out[2]?.disabled, undefined)
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
it('skips empty / null sibling values', () => {
|
|
86
|
-
const out = disableOptionsTakenInSiblings(colours, true, 'color', {
|
|
87
|
-
row: {
|
|
88
|
-
index: 1,
|
|
89
|
-
$get: () => undefined,
|
|
90
|
-
$set: () => {},
|
|
91
|
-
siblings: [{ color: '' }, { color: null }, { color: undefined }, { other: 'red' }],
|
|
92
|
-
},
|
|
93
|
-
})
|
|
94
|
-
assert.equal(out[0]?.disabled, undefined)
|
|
95
|
-
assert.equal(out[1]?.disabled, undefined)
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
it('unfolds array sibling values (CheckboxList semantics)', () => {
|
|
99
|
-
const out = disableOptionsTakenInSiblings(colours, true, 'tags', {
|
|
100
|
-
row: { index: 1, $get: () => undefined, $set: () => {}, siblings: [{ tags: ['red', 'blue'] }] },
|
|
101
|
-
})
|
|
102
|
-
assert.equal(out[0]?.disabled, true)
|
|
103
|
-
assert.equal(out[1]?.disabled, undefined)
|
|
104
|
-
assert.equal(out[2]?.disabled, true)
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
it('preserves user-set option.disabled (does not toggle it back to undefined)', () => {
|
|
108
|
-
const opts: SelectOption[] = [
|
|
109
|
-
{ value: 'red', label: 'Red', disabled: true },
|
|
110
|
-
{ value: 'green', label: 'Green' },
|
|
111
|
-
]
|
|
112
|
-
const out = disableOptionsTakenInSiblings(opts, true, 'color', {
|
|
113
|
-
row: { index: 1, $get: () => undefined, $set: () => {}, siblings: [{ color: 'green' }] },
|
|
114
|
-
})
|
|
115
|
-
assert.equal(out[0]?.disabled, true) // user-set, untouched
|
|
116
|
-
assert.equal(out[1]?.disabled, true) // newly taken
|
|
117
|
-
})
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
describe('inside Repeater', () => {
|
|
121
|
-
function makeRep() {
|
|
122
|
-
return RepeaterField.make('picks').schema([
|
|
123
|
-
SelectField.make('color')
|
|
124
|
-
.options(colours)
|
|
125
|
-
.disableOptionsWhenSelectedInSiblingRepeaterItems(),
|
|
126
|
-
])
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
it('first row sees all options enabled when no sibling has picked', async () => {
|
|
130
|
-
const [raw] = await resolveSchema([makeRep()], {
|
|
131
|
-
values: { picks: [{ color: '' }, { color: '' }] },
|
|
132
|
-
})
|
|
133
|
-
const m = raw as RepeaterFieldMeta
|
|
134
|
-
assert.equal(rowOptions(m, 0, 'color').every(o => !o.disabled), true)
|
|
135
|
-
assert.equal(rowOptions(m, 1, 'color').every(o => !o.disabled), true)
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
it('when row 0 picks "red", row 1 sees red disabled', async () => {
|
|
139
|
-
const [raw] = await resolveSchema([makeRep()], {
|
|
140
|
-
values: { picks: [{ color: 'red' }, { color: '' }] },
|
|
141
|
-
})
|
|
142
|
-
const m = raw as RepeaterFieldMeta
|
|
143
|
-
const row1 = rowOptions(m, 1, 'color')
|
|
144
|
-
assert.equal(row1.find(o => o.value === 'red')?.disabled, true)
|
|
145
|
-
assert.equal(row1.find(o => o.value === 'green')?.disabled, undefined)
|
|
146
|
-
assert.equal(row1.find(o => o.value === 'blue')?.disabled, undefined)
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
it('the picking row keeps its own pick selectable (not disabled by self)', async () => {
|
|
150
|
-
const [raw] = await resolveSchema([makeRep()], {
|
|
151
|
-
values: { picks: [{ color: 'red' }, { color: 'green' }] },
|
|
152
|
-
})
|
|
153
|
-
const m = raw as RepeaterFieldMeta
|
|
154
|
-
// Row 0 sees its own red as enabled (siblings = [{green}])
|
|
155
|
-
assert.equal(rowOptions(m, 0, 'color').find(o => o.value === 'red')?.disabled, undefined)
|
|
156
|
-
// Row 1 sees its own green as enabled (siblings = [{red}])
|
|
157
|
-
assert.equal(rowOptions(m, 1, 'color').find(o => o.value === 'green')?.disabled, undefined)
|
|
158
|
-
// … but the OTHER row's pick is disabled
|
|
159
|
-
assert.equal(rowOptions(m, 0, 'color').find(o => o.value === 'green')?.disabled, true)
|
|
160
|
-
assert.equal(rowOptions(m, 1, 'color').find(o => o.value === 'red')?.disabled, true)
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
it('flag off → no options ever disabled (sanity check)', async () => {
|
|
164
|
-
const f = RepeaterField.make('picks').schema([
|
|
165
|
-
SelectField.make('color').options(colours), // no disable flag
|
|
166
|
-
])
|
|
167
|
-
const [raw] = await resolveSchema([f], {
|
|
168
|
-
values: { picks: [{ color: 'red' }, { color: '' }] },
|
|
169
|
-
})
|
|
170
|
-
const m = raw as RepeaterFieldMeta
|
|
171
|
-
assert.equal(rowOptions(m, 1, 'color').find(o => o.value === 'red')?.disabled, undefined)
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
it('CheckboxList — sibling array values mark each entry disabled', async () => {
|
|
175
|
-
const f = RepeaterField.make('groups').schema([
|
|
176
|
-
CheckboxListField.make('tags')
|
|
177
|
-
.options(colours)
|
|
178
|
-
.disableOptionsWhenSelectedInSiblingRepeaterItems(),
|
|
179
|
-
])
|
|
180
|
-
const [raw] = await resolveSchema([f], {
|
|
181
|
-
values: { groups: [{ tags: ['red', 'blue'] }, { tags: [] }] },
|
|
182
|
-
})
|
|
183
|
-
const m = raw as RepeaterFieldMeta
|
|
184
|
-
const row1 = rowOptions(m, 1, 'tags')
|
|
185
|
-
assert.equal(row1.find(o => o.value === 'red')?.disabled, true)
|
|
186
|
-
assert.equal(row1.find(o => o.value === 'blue')?.disabled, true)
|
|
187
|
-
assert.equal(row1.find(o => o.value === 'green')?.disabled, undefined)
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
it('Radio + ToggleButtons honor the flag the same way', async () => {
|
|
191
|
-
const f = RepeaterField.make('rows').schema([
|
|
192
|
-
RadioField.make('r').options(colours).disableOptionsWhenSelectedInSiblingRepeaterItems(),
|
|
193
|
-
ToggleButtonsField.make('t').options(colours).disableOptionsWhenSelectedInSiblingRepeaterItems(),
|
|
194
|
-
])
|
|
195
|
-
const [raw] = await resolveSchema([f], {
|
|
196
|
-
values: { rows: [{ r: 'red', t: 'blue' }, { r: '', t: '' }] },
|
|
197
|
-
})
|
|
198
|
-
const m = raw as RepeaterFieldMeta
|
|
199
|
-
assert.equal(rowOptions(m, 1, 'r').find(o => o.value === 'red')?.disabled, true)
|
|
200
|
-
assert.equal(rowOptions(m, 1, 't').find(o => o.value === 'blue')?.disabled, true)
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
it('top-level (non-Repeater) Select with the flag set is a no-op', async () => {
|
|
204
|
-
const top = SelectField.make('color').options(colours).disableOptionsWhenSelectedInSiblingRepeaterItems()
|
|
205
|
-
const [raw] = await resolveSchema([top], { values: { color: 'red' } })
|
|
206
|
-
const opts = (raw?.['options'] as SelectOption[]) ?? []
|
|
207
|
-
assert.equal(opts.every(o => !o.disabled), true)
|
|
208
|
-
})
|
|
209
|
-
|
|
210
|
-
it('zero submitted rows + defaultItems → no errors, options all enabled', async () => {
|
|
211
|
-
const [raw] = await resolveSchema([makeRep().defaultItems(2)])
|
|
212
|
-
const m = raw as RepeaterFieldMeta
|
|
213
|
-
// Two empty default rows; nobody has picked anything yet.
|
|
214
|
-
assert.equal(rowOptions(m, 0, 'color').every(o => !o.disabled), true)
|
|
215
|
-
assert.equal(rowOptions(m, 1, 'color').every(o => !o.disabled), true)
|
|
216
|
-
})
|
|
217
|
-
})
|
|
218
|
-
|
|
219
|
-
describe('inside Builder (per-block-type scoping)', () => {
|
|
220
|
-
function makeBuilder() {
|
|
221
|
-
return BuilderField.make('blocks').blocks([
|
|
222
|
-
Block.make('hero').schema([
|
|
223
|
-
SelectField.make('layout').options([
|
|
224
|
-
{ value: 'left', label: 'Left' },
|
|
225
|
-
{ value: 'right', label: 'Right' },
|
|
226
|
-
]).disableOptionsWhenSelectedInSiblingRepeaterItems(),
|
|
227
|
-
]),
|
|
228
|
-
Block.make('cta').schema([
|
|
229
|
-
// Same field name on a different block type — must NOT shadow.
|
|
230
|
-
SelectField.make('layout').options([
|
|
231
|
-
{ value: 'left', label: 'Left' },
|
|
232
|
-
{ value: 'right', label: 'Right' },
|
|
233
|
-
]).disableOptionsWhenSelectedInSiblingRepeaterItems(),
|
|
234
|
-
]),
|
|
235
|
-
])
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
it('same-type sibling pick disables the option on the next same-type row', async () => {
|
|
239
|
-
const [raw] = await resolveSchema([makeBuilder()], {
|
|
240
|
-
values: { blocks: [
|
|
241
|
-
{ type: 'hero', data: { layout: 'left' } },
|
|
242
|
-
{ type: 'hero', data: { layout: '' } },
|
|
243
|
-
] },
|
|
244
|
-
})
|
|
245
|
-
const m = raw as BuilderFieldMeta
|
|
246
|
-
const row1 = rowOptions(m, 1, 'layout')
|
|
247
|
-
assert.equal(row1.find(o => o.value === 'left')?.disabled, true)
|
|
248
|
-
assert.equal(row1.find(o => o.value === 'right')?.disabled, undefined)
|
|
249
|
-
})
|
|
250
|
-
|
|
251
|
-
it('different block types DO NOT shadow each other (cross-block isolation)', async () => {
|
|
252
|
-
const [raw] = await resolveSchema([makeBuilder()], {
|
|
253
|
-
values: { blocks: [
|
|
254
|
-
{ type: 'hero', data: { layout: 'left' } },
|
|
255
|
-
{ type: 'cta', data: { layout: '' } },
|
|
256
|
-
] },
|
|
257
|
-
})
|
|
258
|
-
const m = raw as BuilderFieldMeta
|
|
259
|
-
// The cta row at index 1 is a different block — its `layout` is its
|
|
260
|
-
// own namespace. None of its options should be disabled by the hero
|
|
261
|
-
// row's pick.
|
|
262
|
-
const row1 = rowOptions(m, 1, 'layout')
|
|
263
|
-
assert.equal(row1.every(o => !o.disabled), true)
|
|
264
|
-
})
|
|
265
|
-
|
|
266
|
-
it('three rows, two same-type → only the third sees both prior picks disabled', async () => {
|
|
267
|
-
const [raw] = await resolveSchema([makeBuilder()], {
|
|
268
|
-
values: { blocks: [
|
|
269
|
-
{ type: 'hero', data: { layout: 'left' } },
|
|
270
|
-
{ type: 'hero', data: { layout: 'right' } },
|
|
271
|
-
{ type: 'hero', data: { layout: '' } },
|
|
272
|
-
] },
|
|
273
|
-
})
|
|
274
|
-
const m = raw as BuilderFieldMeta
|
|
275
|
-
const row2 = rowOptions(m, 2, 'layout')
|
|
276
|
-
assert.equal(row2.find(o => o.value === 'left')?.disabled, true)
|
|
277
|
-
assert.equal(row2.find(o => o.value === 'right')?.disabled, true)
|
|
278
|
-
})
|
|
279
|
-
})
|
|
280
|
-
|
|
281
|
-
describe('static option.disabled is preserved alongside taken-disabled', () => {
|
|
282
|
-
it('user-set disabled stays even when not taken', async () => {
|
|
283
|
-
const f = RepeaterField.make('picks').schema([
|
|
284
|
-
SelectField.make('color')
|
|
285
|
-
.options([
|
|
286
|
-
{ value: 'red', label: 'Red' },
|
|
287
|
-
{ value: 'green', label: 'Green', disabled: true },
|
|
288
|
-
{ value: 'blue', label: 'Blue' },
|
|
289
|
-
])
|
|
290
|
-
.disableOptionsWhenSelectedInSiblingRepeaterItems(),
|
|
291
|
-
])
|
|
292
|
-
const [raw] = await resolveSchema([f], {
|
|
293
|
-
values: { picks: [{ color: 'red' }, { color: '' }] },
|
|
294
|
-
})
|
|
295
|
-
const m = raw as RepeaterFieldMeta
|
|
296
|
-
const row1 = rowOptions(m, 1, 'color')
|
|
297
|
-
assert.equal(row1.find(o => o.value === 'red')?.disabled, true) // taken
|
|
298
|
-
assert.equal(row1.find(o => o.value === 'green')?.disabled, true) // user-set
|
|
299
|
-
assert.equal(row1.find(o => o.value === 'blue')?.disabled, undefined)
|
|
300
|
-
})
|
|
301
|
-
})
|
|
302
|
-
|
|
303
|
-
describe('cross-row interaction with non-option fields', () => {
|
|
304
|
-
it('coexists with sibling fields that are not option-bearing', async () => {
|
|
305
|
-
const f = RepeaterField.make('rows').schema([
|
|
306
|
-
TextField.make('title'),
|
|
307
|
-
SelectField.make('color').options(colours).disableOptionsWhenSelectedInSiblingRepeaterItems(),
|
|
308
|
-
])
|
|
309
|
-
const [raw] = await resolveSchema([f], {
|
|
310
|
-
values: { rows: [
|
|
311
|
-
{ title: 'A', color: 'red' },
|
|
312
|
-
{ title: 'B', color: '' },
|
|
313
|
-
] },
|
|
314
|
-
})
|
|
315
|
-
const m = raw as RepeaterFieldMeta
|
|
316
|
-
assert.equal(rowOptions(m, 1, 'color').find(o => o.value === 'red')?.disabled, true)
|
|
317
|
-
})
|
|
318
|
-
})
|
|
319
|
-
})
|