@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,114 +0,0 @@
|
|
|
1
|
-
import { describe, it, before, after, beforeEach } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
computeReconcilePlan,
|
|
6
|
-
markSubmitForReconcile,
|
|
7
|
-
consumeReconcileFlag,
|
|
8
|
-
} from './repeaterReconcile.js'
|
|
9
|
-
|
|
10
|
-
describe('computeReconcilePlan', () => {
|
|
11
|
-
it('returns empty plan when current and authoritative match', () => {
|
|
12
|
-
const plan = computeReconcilePlan({
|
|
13
|
-
current: ['a', 'b', 'c'],
|
|
14
|
-
authoritative: ['a', 'b', 'c'],
|
|
15
|
-
})
|
|
16
|
-
assert.deepEqual(plan.toRemove, [])
|
|
17
|
-
assert.deepEqual(plan.toAdd, [])
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
it('flags orphan CRDT rows as toRemove (PK-switch happy path)', () => {
|
|
21
|
-
// Submitting tab reloaded — server returned the new DB PK; CRDT
|
|
22
|
-
// still carries the renderer-minted UUID from the just-saved row.
|
|
23
|
-
const plan = computeReconcilePlan({
|
|
24
|
-
current: ['uuid-foo', '42'],
|
|
25
|
-
authoritative: ['42'],
|
|
26
|
-
})
|
|
27
|
-
assert.deepEqual(plan.toRemove, ['uuid-foo'])
|
|
28
|
-
assert.deepEqual(plan.toAdd, [])
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
it('flags missing CRDT rows as toAdd (raw-SQL-seeded record)', () => {
|
|
32
|
-
// First peer to open a record whose DB rows weren't seeded into the
|
|
33
|
-
// Y.Doc (no `seedRowArraysFromRecord` coverage for relationship-
|
|
34
|
-
// backed fields). Reconciler ensures CRDT mirrors initialRows.
|
|
35
|
-
const plan = computeReconcilePlan({
|
|
36
|
-
current: [],
|
|
37
|
-
authoritative: ['42', '43'],
|
|
38
|
-
})
|
|
39
|
-
assert.deepEqual(plan.toRemove, [])
|
|
40
|
-
assert.deepEqual(plan.toAdd, ['42', '43'])
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
it('handles both directions in a single pass', () => {
|
|
44
|
-
const plan = computeReconcilePlan({
|
|
45
|
-
current: ['uuid-foo', 'uuid-bar', '42'],
|
|
46
|
-
authoritative: ['42', '43'],
|
|
47
|
-
})
|
|
48
|
-
assert.deepEqual(plan.toRemove, ['uuid-foo', 'uuid-bar'])
|
|
49
|
-
assert.deepEqual(plan.toAdd, ['43'])
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
it('preserves order from inputs in toRemove / toAdd', () => {
|
|
53
|
-
const plan = computeReconcilePlan({
|
|
54
|
-
current: ['z', 'a', 'm'],
|
|
55
|
-
authoritative: ['a', 'b', 'c'],
|
|
56
|
-
})
|
|
57
|
-
// toRemove walks current in order; toAdd walks authoritative in order.
|
|
58
|
-
// Order-stability matters because reconciler applies them sequentially
|
|
59
|
-
// and we want deterministic test snapshots.
|
|
60
|
-
assert.deepEqual(plan.toRemove, ['z', 'm'])
|
|
61
|
-
assert.deepEqual(plan.toAdd, ['b', 'c'])
|
|
62
|
-
})
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
describe('markSubmitForReconcile / consumeReconcileFlag', () => {
|
|
66
|
-
// Minimal in-memory sessionStorage stub — Node lacks one, and we
|
|
67
|
-
// want to avoid bringing in jsdom for a flag-roundtrip test.
|
|
68
|
-
const realSessionStorage = (globalThis as { sessionStorage?: Storage }).sessionStorage
|
|
69
|
-
const store: Map<string, string> = new Map()
|
|
70
|
-
|
|
71
|
-
before(() => {
|
|
72
|
-
;(globalThis as { sessionStorage?: Storage }).sessionStorage = {
|
|
73
|
-
get length() { return store.size },
|
|
74
|
-
key: (i: number) => Array.from(store.keys())[i] ?? null,
|
|
75
|
-
getItem: (k: string) => store.has(k) ? store.get(k)! : null,
|
|
76
|
-
setItem: (k: string, v: string) => { store.set(k, v) },
|
|
77
|
-
removeItem: (k: string) => { store.delete(k) },
|
|
78
|
-
clear: () => { store.clear() },
|
|
79
|
-
} as Storage
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
after(() => {
|
|
83
|
-
if (realSessionStorage === undefined) {
|
|
84
|
-
delete (globalThis as { sessionStorage?: Storage }).sessionStorage
|
|
85
|
-
} else {
|
|
86
|
-
(globalThis as { sessionStorage?: Storage }).sessionStorage = realSessionStorage
|
|
87
|
-
}
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
beforeEach(() => { store.clear() })
|
|
91
|
-
|
|
92
|
-
it('returns false when no flag has been set', () => {
|
|
93
|
-
assert.equal(consumeReconcileFlag('form-1'), false)
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
it('round-trips a flag and clears on first consume', () => {
|
|
97
|
-
markSubmitForReconcile('form-1')
|
|
98
|
-
assert.equal(consumeReconcileFlag('form-1'), true)
|
|
99
|
-
// Second read: flag was cleared on the first consume.
|
|
100
|
-
assert.equal(consumeReconcileFlag('form-1'), false)
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
it('scopes the flag per formId', () => {
|
|
104
|
-
markSubmitForReconcile('form-1')
|
|
105
|
-
assert.equal(consumeReconcileFlag('form-2'), false)
|
|
106
|
-
assert.equal(consumeReconcileFlag('form-1'), true)
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
it('no-ops on empty formId (mark and consume both)', () => {
|
|
110
|
-
markSubmitForReconcile('')
|
|
111
|
-
assert.equal(store.size, 0)
|
|
112
|
-
assert.equal(consumeReconcileFlag(''), false)
|
|
113
|
-
})
|
|
114
|
-
})
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Phase A of the `Repeater.relationship` PK-switch reconciliation
|
|
3
|
-
* (see `pilotiq-pro/docs/plans/repeater-relationship-pk-switch.md`).
|
|
4
|
-
*
|
|
5
|
-
* When a parent form submit creates new relationship-backed rows, the
|
|
6
|
-
* server assigns each child a DB primary key — but the row's `__id` in
|
|
7
|
-
* the row CRDT is still the renderer-minted UUID from the local session.
|
|
8
|
-
* After redirect, the submitting tab's pageData carries `__id = String(pk)`
|
|
9
|
-
* while CRDT still has the UUID, so the renderer ends up showing the
|
|
10
|
-
* same row twice (DB PK from initialRows + orphan UUID from CRDT).
|
|
11
|
-
*
|
|
12
|
-
* Phase A fix: the submitting tab marks itself for a one-shot CRDT
|
|
13
|
-
* reconcile on the next mount via a per-formId sessionStorage flag.
|
|
14
|
-
* `RepeaterInput` / `BuilderInput` read the flag on mount and, when set,
|
|
15
|
-
* snapshot the row CRDT after a short settle (waiting for WS sync) and
|
|
16
|
-
* reconcile against `initialRows` — removing orphan CRDT rows not in
|
|
17
|
-
* the form's authoritative data, and adding missing CRDT rows (rare,
|
|
18
|
-
* happens when the row was DB-seeded outside the collab session).
|
|
19
|
-
*
|
|
20
|
-
* The flag is scoped per-tab via sessionStorage, so other peers' tabs
|
|
21
|
-
* never run the reconciler — preserving their in-flight edits.
|
|
22
|
-
*
|
|
23
|
-
* Phase B (server-side rename via the @rudderjs/sync Y.Doc seam) will
|
|
24
|
-
* extend this to other peers without requiring them to reload.
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
const STORAGE_PREFIX = 'pilotiq.repeaterReconcile.'
|
|
28
|
-
|
|
29
|
-
function storageKey(formId: string): string {
|
|
30
|
-
return STORAGE_PREFIX + formId
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Called by `FormRenderer` on submit success. Records that this tab
|
|
35
|
-
* has just persisted the form, so the next mount of any Repeater /
|
|
36
|
-
* Builder under the same form runs the PK-switch reconciler. No-op
|
|
37
|
-
* when `formId` is empty or `sessionStorage` is unavailable (SSR).
|
|
38
|
-
*/
|
|
39
|
-
export function markSubmitForReconcile(formId: string): void {
|
|
40
|
-
if (!formId) return
|
|
41
|
-
if (typeof sessionStorage === 'undefined') return
|
|
42
|
-
try {
|
|
43
|
-
sessionStorage.setItem(storageKey(formId), '1')
|
|
44
|
-
} catch {
|
|
45
|
-
// Quota exceeded / disabled — silently skip. Reconciliation is
|
|
46
|
-
// an optimization, not a correctness requirement.
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Called by `RepeaterInput` / `BuilderInput` on mount. Returns `true`
|
|
52
|
-
* iff the form was just submitted in this tab AND clears the flag so
|
|
53
|
-
* subsequent mounts no-op. Idempotent across multiple Repeater/Builder
|
|
54
|
-
* fields on the same form — the FIRST reader clears the flag, so
|
|
55
|
-
* siblings see `false`. To avoid that, both fields call this helper at
|
|
56
|
-
* the same mount tick — for v1 we accept the limitation: only the first
|
|
57
|
-
* Repeater on the form runs the reconciler; siblings don't.
|
|
58
|
-
*
|
|
59
|
-
* If a future need surfaces (multiple relationship-backed Repeaters on
|
|
60
|
-
* the same form), switch to a per-field flag keyed by `formId.fieldName`
|
|
61
|
-
* or have the FormRenderer dispatch a custom event instead.
|
|
62
|
-
*/
|
|
63
|
-
export function consumeReconcileFlag(formId: string): boolean {
|
|
64
|
-
if (!formId) return false
|
|
65
|
-
if (typeof sessionStorage === 'undefined') return false
|
|
66
|
-
try {
|
|
67
|
-
const v = sessionStorage.getItem(storageKey(formId))
|
|
68
|
-
if (v !== '1') return false
|
|
69
|
-
sessionStorage.removeItem(storageKey(formId))
|
|
70
|
-
return true
|
|
71
|
-
} catch {
|
|
72
|
-
return false
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export interface ReconcileInputs {
|
|
77
|
-
/** Current CRDT row id order (post-WS-sync). */
|
|
78
|
-
current: readonly string[]
|
|
79
|
-
/** Authoritative row id list from server-rendered initialRows. */
|
|
80
|
-
authoritative: readonly string[]
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export interface ReconcilePlan {
|
|
84
|
-
/** Row ids present in CRDT but not in initialRows — orphan UUIDs. */
|
|
85
|
-
toRemove: string[]
|
|
86
|
-
/** Row ids present in initialRows but not in CRDT — DB rows not yet
|
|
87
|
-
* in the room (rare; only happens when DB was seeded outside collab). */
|
|
88
|
-
toAdd: string[]
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Pure helper: compute the symmetric difference. Exported separately so
|
|
93
|
-
* unit tests don't need a DOM / sessionStorage shim to verify the
|
|
94
|
-
* reconciliation arithmetic.
|
|
95
|
-
*/
|
|
96
|
-
export function computeReconcilePlan({ current, authoritative }: ReconcileInputs): ReconcilePlan {
|
|
97
|
-
const currentSet = new Set(current)
|
|
98
|
-
const authSet = new Set(authoritative)
|
|
99
|
-
const toRemove: string[] = []
|
|
100
|
-
const toAdd: string[] = []
|
|
101
|
-
for (const id of current) if (!authSet.has(id)) toRemove.push(id)
|
|
102
|
-
for (const id of authoritative) if (!currentSet.has(id)) toAdd.push(id)
|
|
103
|
-
return { toRemove, toAdd }
|
|
104
|
-
}
|
|
@@ -1,336 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import {
|
|
3
|
-
ArrowDownIcon,
|
|
4
|
-
ArrowUpIcon,
|
|
5
|
-
ChevronDownIcon,
|
|
6
|
-
ChevronRightIcon,
|
|
7
|
-
ChevronsDownIcon,
|
|
8
|
-
ChevronsUpIcon,
|
|
9
|
-
CopyIcon,
|
|
10
|
-
GripVerticalIcon,
|
|
11
|
-
Trash2Icon,
|
|
12
|
-
} from 'lucide-react'
|
|
13
|
-
import { getIcon, type IconType } from '../../icons/registry.js'
|
|
14
|
-
import type {
|
|
15
|
-
RowButtonColor,
|
|
16
|
-
RowButtonKind,
|
|
17
|
-
RowButtonMeta,
|
|
18
|
-
RowButtonsMeta,
|
|
19
|
-
} from '../../fields/RowButton.js'
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Foreground color slot → Tailwind class pair. Mirrors `Action.color()`
|
|
23
|
-
* semantics with a softer hover transition since these are
|
|
24
|
-
* icon-only buttons inside a dense row header.
|
|
25
|
-
*/
|
|
26
|
-
const COLOR_CLASS: Record<RowButtonColor, string> = {
|
|
27
|
-
foreground: 'text-muted-foreground hover:text-foreground',
|
|
28
|
-
destructive: 'text-muted-foreground hover:text-destructive',
|
|
29
|
-
primary: 'text-primary hover:text-primary/80',
|
|
30
|
-
success: 'text-emerald-600 hover:text-emerald-700',
|
|
31
|
-
warning: 'text-amber-600 hover:text-amber-700',
|
|
32
|
-
info: 'text-blue-600 hover:text-blue-700',
|
|
33
|
-
muted: 'text-muted-foreground/60 hover:text-muted-foreground',
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
interface ButtonDefaults {
|
|
37
|
-
Icon: IconType
|
|
38
|
-
label: string
|
|
39
|
-
tooltip: string
|
|
40
|
-
/**
|
|
41
|
-
* Default tailwind color class when no `color` override is set. Most
|
|
42
|
-
* row buttons share `text-muted-foreground hover:text-foreground`;
|
|
43
|
-
* the trash slot defaults to `…hover:text-destructive`. Defaults always
|
|
44
|
-
* lose to an explicit `RowButton.color()` call.
|
|
45
|
-
*/
|
|
46
|
-
colorClass: string
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
interface ResolvedChrome {
|
|
50
|
-
Icon: IconType
|
|
51
|
-
label: string
|
|
52
|
-
tooltip: string
|
|
53
|
-
colorClass: string
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Merge a meta override on top of a slot's hardcoded defaults. The
|
|
58
|
-
* override may set any subset of `{ icon, label, color, tooltip }`; missing
|
|
59
|
-
* keys fall through. An overridden `icon` that doesn't resolve in the
|
|
60
|
-
* runtime registry falls back to the default Lucide glyph (matches
|
|
61
|
-
* `useIconFor`'s fail-soft posture).
|
|
62
|
-
*/
|
|
63
|
-
export function resolveRowChrome(
|
|
64
|
-
defaults: ButtonDefaults,
|
|
65
|
-
override: RowButtonMeta | undefined,
|
|
66
|
-
): ResolvedChrome {
|
|
67
|
-
if (override === undefined) return defaults
|
|
68
|
-
const overrideIcon = override.icon !== undefined ? getIcon(override.icon) : undefined
|
|
69
|
-
return {
|
|
70
|
-
Icon: overrideIcon ?? defaults.Icon,
|
|
71
|
-
label: override.label ?? defaults.label,
|
|
72
|
-
tooltip: override.tooltip ?? defaults.tooltip,
|
|
73
|
-
colorClass: override.color !== undefined ? COLOR_CLASS[override.color] : defaults.colorClass,
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Default chrome for each of the seven slots. Centralized here so both
|
|
79
|
-
* Repeater and Builder renderers stay in sync — when a new slot lands,
|
|
80
|
-
* the defaults live in one place. The Icon imports happen at the call
|
|
81
|
-
* site (renderers already import from lucide-react); we accept them as
|
|
82
|
-
* inputs to keep this file React-tree-shake friendly.
|
|
83
|
-
*/
|
|
84
|
-
export type SlotDefaults = Record<RowButtonKind, ButtonDefaults>
|
|
85
|
-
|
|
86
|
-
/** Convenience for renderers — pass a slot kind + the merged buttons meta. */
|
|
87
|
-
export function resolveRowChromeFor(
|
|
88
|
-
kind: RowButtonKind,
|
|
89
|
-
defaults: ButtonDefaults,
|
|
90
|
-
buttons: RowButtonsMeta | undefined,
|
|
91
|
-
): ResolvedChrome {
|
|
92
|
-
return resolveRowChrome(defaults, buttons?.[kind])
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Standard icon-button shell used by every row chrome slot except the
|
|
97
|
-
* grip (which is a draggable `<span>`) and the Add button (which uses
|
|
98
|
-
* the shadcn `<Button>` for outline styling). Centralizes the
|
|
99
|
-
* `disabled` opacity, focus ring, and icon sizing so customizer overrides
|
|
100
|
-
* land consistently across Repeater + Builder.
|
|
101
|
-
*/
|
|
102
|
-
export function RowChromeIconButton({
|
|
103
|
-
defaults,
|
|
104
|
-
override,
|
|
105
|
-
disabled,
|
|
106
|
-
onClick,
|
|
107
|
-
extraClassName = '',
|
|
108
|
-
ariaExpanded,
|
|
109
|
-
}: {
|
|
110
|
-
defaults: ButtonDefaults
|
|
111
|
-
override: RowButtonMeta | undefined
|
|
112
|
-
disabled: boolean
|
|
113
|
-
onClick: () => void
|
|
114
|
-
extraClassName?: string
|
|
115
|
-
ariaExpanded?: boolean
|
|
116
|
-
}): React.ReactElement {
|
|
117
|
-
const { Icon, label, tooltip, colorClass } = resolveRowChrome(defaults, override)
|
|
118
|
-
return (
|
|
119
|
-
<button
|
|
120
|
-
type="button"
|
|
121
|
-
onClick={onClick}
|
|
122
|
-
disabled={disabled}
|
|
123
|
-
aria-label={label}
|
|
124
|
-
title={tooltip}
|
|
125
|
-
{...(ariaExpanded !== undefined ? { 'aria-expanded': ariaExpanded } : {})}
|
|
126
|
-
className={`${colorClass} disabled:opacity-30 ${extraClassName}`.trim()}
|
|
127
|
-
>
|
|
128
|
-
<Icon className="size-4" />
|
|
129
|
-
</button>
|
|
130
|
-
)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Drag grip — a `<span>` not a `<button>`. Honors the `reorderAction`
|
|
135
|
-
* customizer for icon / label / tooltip / color so users can swap the
|
|
136
|
-
* glyph or copy without owning the drag wiring.
|
|
137
|
-
*
|
|
138
|
-
* When `dragHandleProps` is passed, the grip carries `draggable=true` +
|
|
139
|
-
* `onDragStart` and becomes the HTML5 drag source — required for row
|
|
140
|
-
* layouts whose body hosts a contenteditable (Tiptap-backed fields).
|
|
141
|
-
* If `draggable=true` lives on the row container instead, a dragstart
|
|
142
|
-
* that initiates over the contenteditable is absorbed by the text-
|
|
143
|
-
* selection handler and the row drag never fires. Moving the source to
|
|
144
|
-
* the grip sidesteps that. Drop-target handlers (`onDragOver/onDrop/
|
|
145
|
-
* onDragEnd`) stay on the row container — `dragend` bubbles so source-
|
|
146
|
-
* side cleanup still reaches it.
|
|
147
|
-
*/
|
|
148
|
-
export function ReorderGrip({
|
|
149
|
-
disabled,
|
|
150
|
-
buttons,
|
|
151
|
-
dragHandleProps,
|
|
152
|
-
}: {
|
|
153
|
-
disabled: boolean
|
|
154
|
-
buttons: RowButtonsMeta | undefined
|
|
155
|
-
dragHandleProps?: {
|
|
156
|
-
draggable: true
|
|
157
|
-
onDragStart: (e: React.DragEvent<HTMLElement>) => void
|
|
158
|
-
} | undefined
|
|
159
|
-
}): React.ReactElement {
|
|
160
|
-
const { Icon, label, tooltip, colorClass } = resolveRowChromeFor('reorder', DEFAULT_REORDER, buttons)
|
|
161
|
-
return (
|
|
162
|
-
<span
|
|
163
|
-
aria-label={label}
|
|
164
|
-
title={tooltip}
|
|
165
|
-
className={`${colorClass} ${disabled ? 'opacity-30' : 'cursor-grab active:cursor-grabbing'}`}
|
|
166
|
-
{...dragHandleProps}
|
|
167
|
-
>
|
|
168
|
-
<Icon className="size-4" />
|
|
169
|
-
</span>
|
|
170
|
-
)
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Collapse chevron — picks the open/closed glyph from state, then lets
|
|
175
|
-
* customizer overrides take over. When the row is currently collapsed,
|
|
176
|
-
* `expand` (from `expandAction(...)`) wins, falling back to `collapse`
|
|
177
|
-
* (from `collapseAction(...)`) for back-compat with single-override
|
|
178
|
-
* setups. When the row is open, `collapse` is used directly. Authors
|
|
179
|
-
* who want different chrome per state set both `collapseAction` and
|
|
180
|
-
* `expandAction`; authors who want a single uniform override keep
|
|
181
|
-
* setting just `collapseAction`.
|
|
182
|
-
*/
|
|
183
|
-
export function CollapseChevron({
|
|
184
|
-
isCollapsed,
|
|
185
|
-
disabled,
|
|
186
|
-
buttons,
|
|
187
|
-
onToggle,
|
|
188
|
-
}: {
|
|
189
|
-
isCollapsed: boolean
|
|
190
|
-
disabled: boolean
|
|
191
|
-
buttons: RowButtonsMeta | undefined
|
|
192
|
-
onToggle: () => void
|
|
193
|
-
}): React.ReactElement {
|
|
194
|
-
const defaults = {
|
|
195
|
-
Icon: isCollapsed ? ChevronRightIcon : ChevronDownIcon,
|
|
196
|
-
label: isCollapsed ? 'Expand' : 'Collapse',
|
|
197
|
-
tooltip: isCollapsed ? 'Expand' : 'Collapse',
|
|
198
|
-
colorClass: 'text-muted-foreground hover:text-foreground',
|
|
199
|
-
}
|
|
200
|
-
const override = isCollapsed
|
|
201
|
-
? (buttons?.expand ?? buttons?.collapse)
|
|
202
|
-
: buttons?.collapse
|
|
203
|
-
return (
|
|
204
|
-
<RowChromeIconButton
|
|
205
|
-
defaults={defaults}
|
|
206
|
-
override={override}
|
|
207
|
-
disabled={disabled}
|
|
208
|
-
onClick={onToggle}
|
|
209
|
-
ariaExpanded={!isCollapsed}
|
|
210
|
-
/>
|
|
211
|
-
)
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// ─── Per-slot defaults ─────────────────────────────────────
|
|
215
|
-
// Centralized so Repeater + Builder stay in lockstep. When a new slot
|
|
216
|
-
// lands, defaults live in one place. `colorClass` defaults match the
|
|
217
|
-
// historic hardcoded classes — preserves chrome for non-customized fields.
|
|
218
|
-
|
|
219
|
-
export const DEFAULT_MOVE_UP: ButtonDefaults = {
|
|
220
|
-
Icon: ArrowUpIcon,
|
|
221
|
-
label: 'Move up',
|
|
222
|
-
tooltip: 'Move up',
|
|
223
|
-
colorClass: 'text-muted-foreground hover:text-foreground',
|
|
224
|
-
}
|
|
225
|
-
export const DEFAULT_MOVE_DOWN: ButtonDefaults = {
|
|
226
|
-
Icon: ArrowDownIcon,
|
|
227
|
-
label: 'Move down',
|
|
228
|
-
tooltip: 'Move down',
|
|
229
|
-
colorClass: 'text-muted-foreground hover:text-foreground',
|
|
230
|
-
}
|
|
231
|
-
export const DEFAULT_CLONE: ButtonDefaults = {
|
|
232
|
-
Icon: CopyIcon,
|
|
233
|
-
label: 'Duplicate row',
|
|
234
|
-
tooltip: 'Duplicate row',
|
|
235
|
-
colorClass: 'text-muted-foreground hover:text-foreground',
|
|
236
|
-
}
|
|
237
|
-
export const DEFAULT_DELETE: ButtonDefaults = {
|
|
238
|
-
Icon: Trash2Icon,
|
|
239
|
-
label: 'Remove row',
|
|
240
|
-
tooltip: 'Remove row',
|
|
241
|
-
colorClass: 'text-muted-foreground hover:text-destructive',
|
|
242
|
-
}
|
|
243
|
-
export const DEFAULT_REORDER: ButtonDefaults = {
|
|
244
|
-
Icon: GripVerticalIcon,
|
|
245
|
-
label: 'Drag to reorder',
|
|
246
|
-
tooltip: 'Drag to reorder',
|
|
247
|
-
colorClass: 'text-muted-foreground',
|
|
248
|
-
}
|
|
249
|
-
export const DEFAULT_EXPAND_ALL: ButtonDefaults = {
|
|
250
|
-
Icon: ChevronsDownIcon,
|
|
251
|
-
label: 'Expand all',
|
|
252
|
-
tooltip: 'Expand all',
|
|
253
|
-
colorClass: 'text-muted-foreground hover:text-foreground',
|
|
254
|
-
}
|
|
255
|
-
export const DEFAULT_COLLAPSE_ALL: ButtonDefaults = {
|
|
256
|
-
Icon: ChevronsUpIcon,
|
|
257
|
-
label: 'Collapse all',
|
|
258
|
-
tooltip: 'Collapse all',
|
|
259
|
-
colorClass: 'text-muted-foreground hover:text-foreground',
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Field-header strip with bulk Expand-all / Collapse-all chips. Renders
|
|
264
|
-
* only the buttons whose customizer slot is set on `buttons` — the
|
|
265
|
-
* presence of `buttons.expandAll` / `buttons.collapseAll` is what flips
|
|
266
|
-
* the matching button into existence (different from per-row chrome,
|
|
267
|
-
* which always renders when collapsible). Returns `null` when neither
|
|
268
|
-
* slot is configured so callers can mount the strip unconditionally.
|
|
269
|
-
*/
|
|
270
|
-
export function BulkCollapseHeader({
|
|
271
|
-
buttons,
|
|
272
|
-
disabled,
|
|
273
|
-
onExpandAll,
|
|
274
|
-
onCollapseAll,
|
|
275
|
-
}: {
|
|
276
|
-
buttons: RowButtonsMeta | undefined
|
|
277
|
-
disabled: boolean
|
|
278
|
-
onExpandAll: () => void
|
|
279
|
-
onCollapseAll: () => void
|
|
280
|
-
}): React.ReactElement | null {
|
|
281
|
-
const expandAllOverride = buttons?.expandAll
|
|
282
|
-
const collapseAllOverride = buttons?.collapseAll
|
|
283
|
-
if (!expandAllOverride && !collapseAllOverride) return null
|
|
284
|
-
return (
|
|
285
|
-
<div className="flex items-center justify-end gap-1">
|
|
286
|
-
{expandAllOverride && (
|
|
287
|
-
<BulkChromeButton
|
|
288
|
-
defaults={DEFAULT_EXPAND_ALL}
|
|
289
|
-
override={expandAllOverride}
|
|
290
|
-
disabled={disabled}
|
|
291
|
-
onClick={onExpandAll}
|
|
292
|
-
/>
|
|
293
|
-
)}
|
|
294
|
-
{collapseAllOverride && (
|
|
295
|
-
<BulkChromeButton
|
|
296
|
-
defaults={DEFAULT_COLLAPSE_ALL}
|
|
297
|
-
override={collapseAllOverride}
|
|
298
|
-
disabled={disabled}
|
|
299
|
-
onClick={onCollapseAll}
|
|
300
|
-
/>
|
|
301
|
-
)}
|
|
302
|
-
</div>
|
|
303
|
-
)
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* Compact button used by `BulkCollapseHeader` — icon + label, sized to
|
|
308
|
-
* read as a header chip (smaller than a full Action button, larger than
|
|
309
|
-
* the icon-only per-row chrome). Picks up the same `RowButton`
|
|
310
|
-
* override surface as every other slot.
|
|
311
|
-
*/
|
|
312
|
-
function BulkChromeButton({
|
|
313
|
-
defaults,
|
|
314
|
-
override,
|
|
315
|
-
disabled,
|
|
316
|
-
onClick,
|
|
317
|
-
}: {
|
|
318
|
-
defaults: ButtonDefaults
|
|
319
|
-
override: RowButtonMeta | undefined
|
|
320
|
-
disabled: boolean
|
|
321
|
-
onClick: () => void
|
|
322
|
-
}): React.ReactElement {
|
|
323
|
-
const { Icon, label, tooltip, colorClass } = resolveRowChrome(defaults, override)
|
|
324
|
-
return (
|
|
325
|
-
<button
|
|
326
|
-
type="button"
|
|
327
|
-
onClick={onClick}
|
|
328
|
-
disabled={disabled}
|
|
329
|
-
title={tooltip}
|
|
330
|
-
className={`inline-flex items-center gap-1 rounded-md px-2 py-1 text-xs ${colorClass} disabled:opacity-30`}
|
|
331
|
-
>
|
|
332
|
-
<Icon className="size-3.5" />
|
|
333
|
-
{label}
|
|
334
|
-
</button>
|
|
335
|
-
)
|
|
336
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared row-state helpers consumed by both `RepeaterInput` and
|
|
3
|
-
* `BuilderInput`. The two fields keep parallel storage namespaces
|
|
4
|
-
* (`pilotiq.repeater.…` vs `pilotiq.builder.…`) so users with both on
|
|
5
|
-
* the same page can collapse them independently — the namespace is the
|
|
6
|
-
* only thing that varies between the two callers.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
readStoredString, removeStoredString, writeStoredString,
|
|
11
|
-
} from '../persistedState.js'
|
|
12
|
-
|
|
13
|
-
let _rowSeqFallback = 0
|
|
14
|
-
|
|
15
|
-
export function generateRowId(): string {
|
|
16
|
-
type CryptoLike = { randomUUID?: () => string }
|
|
17
|
-
const c = (globalThis as { crypto?: CryptoLike }).crypto
|
|
18
|
-
if (c?.randomUUID) return c.randomUUID()
|
|
19
|
-
return `row-${Date.now()}-${++_rowSeqFallback}`
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export type RowStateNamespace = 'repeater' | 'builder'
|
|
23
|
-
|
|
24
|
-
export interface CollapsedStorage {
|
|
25
|
-
key: (formId: string, name: string, rowId: string) => string
|
|
26
|
-
read: (formId: string, name: string, rowId: string, defaultValue: boolean) => boolean
|
|
27
|
-
write: (formId: string, name: string, rowId: string, value: boolean) => void
|
|
28
|
-
remove: (formId: string, name: string, rowId: string) => void
|
|
29
|
-
seed: (
|
|
30
|
-
rows: { id: string }[],
|
|
31
|
-
formId: string,
|
|
32
|
-
name: string,
|
|
33
|
-
defaultValue: boolean,
|
|
34
|
-
collapsible: boolean,
|
|
35
|
-
) => Record<string, boolean>
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Build a namespaced per-row collapse-state store. Uses `'true'` /
|
|
40
|
-
* `'false'` encoding (predates the `'1'` / `'0'` flag helper — kept for
|
|
41
|
-
* back-compat with already-persisted state).
|
|
42
|
-
*/
|
|
43
|
-
export function makeCollapsedStorage(namespace: RowStateNamespace): CollapsedStorage {
|
|
44
|
-
const key = (formId: string, name: string, rowId: string): string =>
|
|
45
|
-
`pilotiq.${namespace}.${formId}.${name}.${rowId}`
|
|
46
|
-
|
|
47
|
-
const read = (formId: string, name: string, rowId: string, defaultValue: boolean): boolean => {
|
|
48
|
-
const raw = readStoredString(key(formId, name, rowId))
|
|
49
|
-
if (raw === null) return defaultValue
|
|
50
|
-
return raw === 'true'
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const write = (formId: string, name: string, rowId: string, value: boolean): void => {
|
|
54
|
-
writeStoredString(key(formId, name, rowId), String(value))
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const remove = (formId: string, name: string, rowId: string): void => {
|
|
58
|
-
removeStoredString(key(formId, name, rowId))
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const seed = (
|
|
62
|
-
rows: { id: string }[],
|
|
63
|
-
formId: string,
|
|
64
|
-
name: string,
|
|
65
|
-
defaultValue: boolean,
|
|
66
|
-
collapsible: boolean,
|
|
67
|
-
): Record<string, boolean> => {
|
|
68
|
-
if (!collapsible) return {}
|
|
69
|
-
const out: Record<string, boolean> = {}
|
|
70
|
-
for (const row of rows) out[row.id] = read(formId, name, row.id, defaultValue)
|
|
71
|
-
return out
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return { key, read, write, remove, seed }
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export interface AccordionStorage {
|
|
78
|
-
key: (formId: string, name: string) => string
|
|
79
|
-
/**
|
|
80
|
-
* `undefined` = no value stored (caller falls back to default-open
|
|
81
|
-
* heuristic). Empty string = user explicitly closed every row (caller
|
|
82
|
-
* maps to `null` openId). Any other string = the open row id.
|
|
83
|
-
*/
|
|
84
|
-
read: (formId: string, name: string) => string | undefined
|
|
85
|
-
write: (formId: string, name: string, openId: string | null) => void
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Build a namespaced accordion-open-row store. Always one slot per
|
|
90
|
-
* (formId, name) pair regardless of row count.
|
|
91
|
-
*/
|
|
92
|
-
export function makeAccordionStorage(namespace: RowStateNamespace): AccordionStorage {
|
|
93
|
-
const key = (formId: string, name: string): string =>
|
|
94
|
-
`pilotiq.${namespace}.${formId}.${name}.accordion`
|
|
95
|
-
|
|
96
|
-
const read = (formId: string, name: string): string | undefined => {
|
|
97
|
-
const raw = readStoredString(key(formId, name))
|
|
98
|
-
return raw === null ? undefined : raw
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const write = (formId: string, name: string, openId: string | null): void => {
|
|
102
|
-
writeStoredString(key(formId, name), openId ?? '')
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return { key, read, write }
|
|
106
|
-
}
|