@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,549 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useRef, useState } from 'react'
|
|
2
|
-
import type { ElementMeta } from '../schema/Element.js'
|
|
3
|
-
import { getFieldRenderer } from './registry.js'
|
|
4
|
-
import { getFieldLabelSlot } from './FieldLabelSlotRegistry.js'
|
|
5
|
-
import { FormStateProvider, useFormState, FormIdContext } from './FormStateContext.js'
|
|
6
|
-
import { CircleIcon } from 'lucide-react'
|
|
7
|
-
import { useNavigate } from './navigate.js'
|
|
8
|
-
import { useIconFor } from './icon-context.js'
|
|
9
|
-
import type { SerializedIcon } from '../icons/types.js'
|
|
10
|
-
import { useToast } from './Toaster.js'
|
|
11
|
-
import { pickEditableCell } from './cells/EditableCell.js'
|
|
12
|
-
import { WidgetDataProvider } from './WidgetDataContext.js'
|
|
13
|
-
import { StatsOverviewRenderer } from './widgets/StatsOverviewRenderer.js'
|
|
14
|
-
import { TableWidgetRenderer } from './widgets/TableWidgetRenderer.js'
|
|
15
|
-
import { ViewRenderer } from './widgets/ViewRenderer.js'
|
|
16
|
-
import { getSlotComponent } from '../slot-components/registry.js'
|
|
17
|
-
import { getWidgetRenderer } from './widgetRegistry.js'
|
|
18
|
-
import type { NotificationMeta } from '../notifications/Notification.js'
|
|
19
|
-
import {
|
|
20
|
-
BADGE_COLOR_CLASSES,
|
|
21
|
-
COLUMN_COLOR_CLASSES,
|
|
22
|
-
COLUMN_WEIGHT_CLASSES,
|
|
23
|
-
} from './schemaRenderer/constants.js'
|
|
24
|
-
import {
|
|
25
|
-
layoutClasses,
|
|
26
|
-
renderChildren,
|
|
27
|
-
resolveIcon,
|
|
28
|
-
withTooltip,
|
|
29
|
-
} from './schemaRenderer/helpers.js'
|
|
30
|
-
import { renderSimpleElement } from './schemaRenderer/SimpleElements.js'
|
|
31
|
-
import { AlertRenderer } from './schemaRenderer/AlertRenderer.js'
|
|
32
|
-
import { SectionRenderer } from './schemaRenderer/SectionRenderer.js'
|
|
33
|
-
import { TabsRenderer } from './schemaRenderer/TabsRenderer.js'
|
|
34
|
-
import { WizardRenderer } from './schemaRenderer/WizardRenderer.js'
|
|
35
|
-
import { renderEntry } from './schemaRenderer/EntryRenderer.js'
|
|
36
|
-
import { applyColumnFormat } from './schemaRenderer/columnFormat.js'
|
|
37
|
-
import type { RenderActionOptions } from './schemaRenderer/action/buttons.js'
|
|
38
|
-
import {
|
|
39
|
-
dispatchHandlerAction as actionDispatchHandlerAction,
|
|
40
|
-
} from './schemaRenderer/action/helpers.js'
|
|
41
|
-
import { renderAction, renderActionLike as renderActionLikeImpl } from './schemaRenderer/action/renderAction.js'
|
|
42
|
-
import { ActionGroupTrigger } from './schemaRenderer/action/ActionGroupTrigger.js'
|
|
43
|
-
import {
|
|
44
|
-
renderField as renderFieldImpl,
|
|
45
|
-
} from './schemaRenderer/form/renderField.js'
|
|
46
|
-
import {
|
|
47
|
-
FormRenderer as FormRendererImpl,
|
|
48
|
-
renderFormChild as renderFormChildImpl,
|
|
49
|
-
} from './schemaRenderer/form/FormRenderer.js'
|
|
50
|
-
import { TableRenderer as TableRendererImpl } from './schemaRenderer/table/TableRenderer.js'
|
|
51
|
-
import type { TableBodyDeps } from './schemaRenderer/table/TableRendererBody.js'
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Re-export `dispatchHandlerAction` from the action helpers so existing
|
|
55
|
-
* consumers (e.g. `RepeaterInput.tsx`) keep working through this barrel.
|
|
56
|
-
* Phase 4 may shift these imports onto the action subpath directly.
|
|
57
|
-
*/
|
|
58
|
-
export const dispatchHandlerAction = actionDispatchHandlerAction
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Render a flat list of resolved field-meta as standalone form inputs,
|
|
62
|
-
* outside any pilotiq Form wrapper. Useful for embedding the schema
|
|
63
|
-
* input layer in custom surfaces (e.g. the rich-text custom-block side
|
|
64
|
-
* panel) where the consumer drives reads/writes directly on a host
|
|
65
|
-
* `<form>` via DOM event delegation.
|
|
66
|
-
*
|
|
67
|
-
* Behavior:
|
|
68
|
-
* - Each field renders through the same `renderField` switch the
|
|
69
|
-
* SchemaRenderer uses for in-form fields, so chrome (label, helper
|
|
70
|
-
* text, prefix/suffix) and field-type coverage stay in lockstep.
|
|
71
|
-
* - `values`, when supplied, overrides each field's `defaultValue`
|
|
72
|
-
* so the consumer can prefill from external state.
|
|
73
|
-
* - Inputs are uncontrolled (`defaultValue`-based) — outside a
|
|
74
|
-
* `FormStateProvider`, `useFieldState` falls back automatically.
|
|
75
|
-
* The host captures changes via container-level event delegation.
|
|
76
|
-
*
|
|
77
|
-
* Not for: container layouts (Card / Tabs / Section / Wizard), Action
|
|
78
|
-
* triggers, or anything beyond a flat field list. Use SchemaRenderer
|
|
79
|
-
* for full pages.
|
|
80
|
-
*/
|
|
81
|
-
export interface FormFieldsProps {
|
|
82
|
-
elements: ElementMeta[]
|
|
83
|
-
values?: Record<string, unknown>
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export function FormFields({ elements, values }: FormFieldsProps): React.ReactElement {
|
|
87
|
-
return (
|
|
88
|
-
<>
|
|
89
|
-
{elements.map((el, i) => {
|
|
90
|
-
if (el['type'] !== 'field') return null
|
|
91
|
-
const name = String(el['name'] ?? '')
|
|
92
|
-
const merged = values && name in values
|
|
93
|
-
? { ...el, defaultValue: values[name] } as ElementMeta
|
|
94
|
-
: el
|
|
95
|
-
return renderField(merged, i)
|
|
96
|
-
})}
|
|
97
|
-
</>
|
|
98
|
-
)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
/** Thin wrapper that binds the renderer-injected deps so call sites
|
|
106
|
-
* inside this file can keep the original three-arg signature. The
|
|
107
|
-
* action layer (Phase 3) lives behind `renderActionLikeImpl`; it needs
|
|
108
|
-
* `renderElement` + `renderFormChild` for nested schemas + modal-form
|
|
109
|
-
* bodies. Both are function declarations so hoisting handles the
|
|
110
|
-
* forward reference cleanly. */
|
|
111
|
-
function renderActionLike(
|
|
112
|
-
el: ElementMeta,
|
|
113
|
-
index: number,
|
|
114
|
-
opts: RenderActionOptions = {},
|
|
115
|
-
): React.ReactNode {
|
|
116
|
-
return renderActionLikeImpl(el, index, opts, { renderElement, renderFormChild })
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/** Thin wrapper around `renderFieldImpl` that pre-binds `renderElement`.
|
|
120
|
-
* Lets `FormFields`, `renderFormChild`, and the renderElement switch
|
|
121
|
-
* call the form-layer field renderer with the original two-arg signature. */
|
|
122
|
-
function renderField(el: ElementMeta, index: number): React.ReactNode {
|
|
123
|
-
return renderFieldImpl(el, index, renderElement)
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/** Re-export the form-layer `renderFormChild` with `renderElement`
|
|
127
|
-
* pre-bound, so external consumers (e.g. `SelectFieldInput.tsx`) keep
|
|
128
|
-
* importing it from `SchemaRenderer.js` with the same four-arg signature.
|
|
129
|
-
* Internal callers (action layer dialogs, ActionGroupTrigger) get the
|
|
130
|
-
* same closure through prop injection. */
|
|
131
|
-
export function renderFormChild(
|
|
132
|
-
child: ElementMeta,
|
|
133
|
-
index: number,
|
|
134
|
-
values: Record<string, unknown>,
|
|
135
|
-
errors: Record<string, string[]>,
|
|
136
|
-
): React.ReactNode {
|
|
137
|
-
return renderFormChildImpl(child, index, values, errors, renderElement)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/** Local wrapper around the form-layer `FormRenderer` that pre-binds
|
|
141
|
-
* `renderElement`. Kept thin so the switch case below stays a one-liner. */
|
|
142
|
-
function FormRenderer({ el }: { el: ElementMeta }) {
|
|
143
|
-
return <FormRendererImpl el={el} renderElement={renderElement} />
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/** Pre-bind the three injected deps that `TableRendererBody` needs:
|
|
147
|
-
* - `renderElement` for column cells holding Element-typed children
|
|
148
|
-
* - `renderActionLike` for row + bulk action dispatch
|
|
149
|
-
* - `renderFormChild` for the inline-edit modal's form schema body */
|
|
150
|
-
const tableBodyDeps: TableBodyDeps = {
|
|
151
|
-
get renderElement() { return renderElement },
|
|
152
|
-
get renderActionLike() { return renderActionLike },
|
|
153
|
-
get renderFormChild() { return renderFormChild },
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/** Local wrapper around the table-layer `TableRenderer` that injects the
|
|
157
|
-
* three renderer deps. The body lives behind a separate import so the
|
|
158
|
-
* module cycle stays clean. */
|
|
159
|
-
function TableRenderer({ el }: { el: ElementMeta }) {
|
|
160
|
-
return <TableRendererImpl el={el} deps={tableBodyDeps} />
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function renderElement(el: ElementMeta, index: number): React.ReactNode {
|
|
164
|
-
// Stateless leaves + layout primitives — text/image/icon/markdown/html/
|
|
165
|
-
// heading/emptyState/divider/unorderedList/card/grid/group/split/fieldset.
|
|
166
|
-
// Returns undefined for unhandled types so the switch below picks them up.
|
|
167
|
-
const simple = renderSimpleElement(el, index, { renderElement, renderActionLike })
|
|
168
|
-
if (simple !== undefined) return simple
|
|
169
|
-
|
|
170
|
-
switch (el.type) {
|
|
171
|
-
case 'alert': {
|
|
172
|
-
const footer = (el.children ?? []).filter(c => c.type === 'action' || c.type === 'actionGroup' || c.type === 'slotComponent')
|
|
173
|
-
return (
|
|
174
|
-
<AlertRenderer
|
|
175
|
-
key={index}
|
|
176
|
-
alertType={String(el['alertType'] ?? 'info')}
|
|
177
|
-
content={String(el['content'] ?? '')}
|
|
178
|
-
{...(el['title'] !== undefined ? { title: String(el['title']) } : {})}
|
|
179
|
-
{...(el['dismissible'] ? { dismissible: Boolean(el['dismissible']) } : {})}
|
|
180
|
-
{...(el['persistDismissal'] !== undefined ? { persistDismissal: String(el['persistDismissal']) } : {})}
|
|
181
|
-
{...(el['iconColor'] !== undefined ? { iconColor: String(el['iconColor']) } : {})}
|
|
182
|
-
{...(el['actionsAlignment'] !== undefined ? { actionsAlignment: String(el['actionsAlignment']) } : {})}
|
|
183
|
-
footer={footer.map((a, i) => renderActionLike(a, i))}
|
|
184
|
-
/>
|
|
185
|
-
)
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
case 'section':
|
|
189
|
-
return <SectionRenderer key={index} el={el} index={index} renderElement={renderElement} />
|
|
190
|
-
|
|
191
|
-
case 'tabs':
|
|
192
|
-
return <TabsRenderer key={index} el={el} index={index} renderElement={renderElement} />
|
|
193
|
-
|
|
194
|
-
case 'tab':
|
|
195
|
-
// Tabs are rendered by their parent `tabs` element; standalone Tab is a no-op.
|
|
196
|
-
return null
|
|
197
|
-
|
|
198
|
-
case 'listTabs':
|
|
199
|
-
return <ListTabsRenderer key={index} el={el} />
|
|
200
|
-
|
|
201
|
-
case 'relation-tabs':
|
|
202
|
-
return <RelationTabsRenderer key={index} el={el} />
|
|
203
|
-
|
|
204
|
-
case 'breadcrumbs':
|
|
205
|
-
return <BreadcrumbsRenderer key={index} el={el} />
|
|
206
|
-
|
|
207
|
-
case 'listTab':
|
|
208
|
-
// List tabs are rendered by their parent `listTabs` strip; standalone is a no-op.
|
|
209
|
-
return null
|
|
210
|
-
|
|
211
|
-
case 'wizard':
|
|
212
|
-
return (
|
|
213
|
-
<WizardRenderer
|
|
214
|
-
key={index}
|
|
215
|
-
el={el}
|
|
216
|
-
index={index}
|
|
217
|
-
deps={{ renderElement }}
|
|
218
|
-
/>
|
|
219
|
-
)
|
|
220
|
-
|
|
221
|
-
case 'step':
|
|
222
|
-
// Steps are rendered by their parent Wizard; standalone Step is a no-op.
|
|
223
|
-
return null
|
|
224
|
-
|
|
225
|
-
case 'field':
|
|
226
|
-
return renderField(el, index)
|
|
227
|
-
|
|
228
|
-
case 'entry':
|
|
229
|
-
return renderEntry(el, index, renderElement)
|
|
230
|
-
|
|
231
|
-
case 'action':
|
|
232
|
-
return renderAction(el, index, {}, { renderElement, renderFormChild })
|
|
233
|
-
|
|
234
|
-
case 'actionGroup':
|
|
235
|
-
return (
|
|
236
|
-
<ActionGroupTrigger
|
|
237
|
-
key={index}
|
|
238
|
-
el={el}
|
|
239
|
-
renderFormChild={renderFormChild}
|
|
240
|
-
renderElement={renderElement}
|
|
241
|
-
/>
|
|
242
|
-
)
|
|
243
|
-
|
|
244
|
-
case 'form': {
|
|
245
|
-
// Key on formId so SPA navigation between pages with different
|
|
246
|
-
// forms (list → edit, edit → edit-of-different-record, etc.)
|
|
247
|
-
// forces a fresh React mount. Form fields are uncontrolled
|
|
248
|
-
// (`defaultValue`), so without remount, prop updates wouldn't
|
|
249
|
-
// propagate into the rendered <input>s — the form would render
|
|
250
|
-
// with stale or empty values.
|
|
251
|
-
const formId = String(el['formId'] ?? index)
|
|
252
|
-
return <FormRenderer key={formId} el={el} />
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
case 'table':
|
|
256
|
-
return <TableRenderer key={index} el={el} />
|
|
257
|
-
|
|
258
|
-
case 'column':
|
|
259
|
-
// Columns are rendered by their parent table; standalone column is a no-op.
|
|
260
|
-
return null
|
|
261
|
-
|
|
262
|
-
case 'stats':
|
|
263
|
-
return <StatsOverviewRenderer key={index} meta={el} />
|
|
264
|
-
|
|
265
|
-
case 'tableWidget':
|
|
266
|
-
return <TableWidgetRenderer key={index} meta={el} />
|
|
267
|
-
|
|
268
|
-
case 'view':
|
|
269
|
-
return <ViewRenderer key={index} meta={el} />
|
|
270
|
-
|
|
271
|
-
case 'slotComponent': {
|
|
272
|
-
const componentName = String(el['component'] ?? '')
|
|
273
|
-
if (!componentName) {
|
|
274
|
-
return (
|
|
275
|
-
<div
|
|
276
|
-
key={index}
|
|
277
|
-
className="rounded-md border border-amber-500/40 bg-amber-50 p-3 text-sm text-amber-800 dark:bg-amber-950/30 dark:text-amber-200"
|
|
278
|
-
role="alert"
|
|
279
|
-
>
|
|
280
|
-
SlotComponent without a registered <code className="font-mono">component</code> name.
|
|
281
|
-
</div>
|
|
282
|
-
)
|
|
283
|
-
}
|
|
284
|
-
const Component = getSlotComponent(componentName)
|
|
285
|
-
if (!Component) {
|
|
286
|
-
return (
|
|
287
|
-
<div
|
|
288
|
-
key={index}
|
|
289
|
-
className="rounded-md border border-amber-500/40 bg-amber-50 p-3 text-sm text-amber-800 dark:bg-amber-950/30 dark:text-amber-200"
|
|
290
|
-
role="alert"
|
|
291
|
-
>
|
|
292
|
-
No slot component registered for <code className="font-mono">{componentName}</code>.
|
|
293
|
-
Call <code className="font-mono">registerSlotComponents({'{ '}{componentName}{' }'})</code> at app boot.
|
|
294
|
-
</div>
|
|
295
|
-
)
|
|
296
|
-
}
|
|
297
|
-
const props = (el['props'] ?? {}) as Record<string, unknown>
|
|
298
|
-
return <Component key={index} {...props} />
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
default: {
|
|
302
|
-
// Plan #15 Phase C — server-data widget elements registered by
|
|
303
|
-
// adapter packages (`@pilotiq/recharts` for `'chart'`, future
|
|
304
|
-
// `@pilotiq/chartjs`, etc.) dispatch through the runtime widget
|
|
305
|
-
// registry. The fallback error message points the consumer at the
|
|
306
|
-
// install command — silent `null` here would let a missing
|
|
307
|
-
// `registerChartRenderer()` slip through.
|
|
308
|
-
if (el['serverData'] === true) {
|
|
309
|
-
const widgetType = String(el.type ?? '')
|
|
310
|
-
const Renderer = getWidgetRenderer(widgetType)
|
|
311
|
-
if (Renderer) return <Renderer key={index} meta={el} />
|
|
312
|
-
return (
|
|
313
|
-
<div
|
|
314
|
-
key={index}
|
|
315
|
-
className="rounded-md border border-amber-500/40 bg-amber-50 p-3 text-sm text-amber-800 dark:bg-amber-950/30 dark:text-amber-200"
|
|
316
|
-
role="alert"
|
|
317
|
-
>
|
|
318
|
-
No renderer registered for widget type <code className="font-mono">{widgetType}</code>.
|
|
319
|
-
{widgetType === 'chart' && (
|
|
320
|
-
<> Install <code className="font-mono">@pilotiq/recharts</code> and
|
|
321
|
-
call <code className="font-mono">registerChartRenderer()</code> at app boot.</>
|
|
322
|
-
)}
|
|
323
|
-
</div>
|
|
324
|
-
)
|
|
325
|
-
}
|
|
326
|
-
return null
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* List-page tab strip — Filament-style query shortcuts above the table
|
|
335
|
-
* ("All / Drafts / Published / Archived"). Each trigger is a real `<a>`
|
|
336
|
-
* (right-click / cmd-click "open in new tab" works); plain left-click is
|
|
337
|
-
* intercepted for SPA navigation. Active tab carries `data-active`.
|
|
338
|
-
*
|
|
339
|
-
* The server stamps `active` + per-tab `url` + resolved badge string on
|
|
340
|
-
* each `listTab` meta entry — this component just renders.
|
|
341
|
-
*/
|
|
342
|
-
function ListTabsRenderer({ el }: { el: ElementMeta }) {
|
|
343
|
-
const navigate = useNavigate()
|
|
344
|
-
const tabs = (el.children ?? []).filter(c => c.type === 'listTab')
|
|
345
|
-
if (tabs.length === 0) return null
|
|
346
|
-
|
|
347
|
-
return (
|
|
348
|
-
<div className="border-b border-border">
|
|
349
|
-
<nav className="flex items-center gap-1 -mb-px overflow-x-auto" role="tablist">
|
|
350
|
-
{tabs.map((t, i) => {
|
|
351
|
-
const name = String(t['name'] ?? '')
|
|
352
|
-
const label = String(t['label'] ?? name)
|
|
353
|
-
const active = Boolean(t['active'])
|
|
354
|
-
const url = String(t['url'] ?? `?tab=${encodeURIComponent(name)}`)
|
|
355
|
-
const iconKey = t['icon'] ? String(t['icon']) : undefined
|
|
356
|
-
const Icon = iconKey ? (resolveIcon(iconKey) ?? CircleIcon) : undefined
|
|
357
|
-
const badge = t['badge'] !== undefined ? String(t['badge']) : undefined
|
|
358
|
-
const badgeKey = t['badgeColor'] ? String(t['badgeColor']) : (active ? 'primary' : 'gray')
|
|
359
|
-
const badgeCls = BADGE_COLOR_CLASSES[badgeKey] ?? BADGE_COLOR_CLASSES['gray']
|
|
360
|
-
|
|
361
|
-
const triggerCls = [
|
|
362
|
-
'inline-flex items-center gap-1.5 px-3 py-2 text-sm border-b-2 transition-colors whitespace-nowrap',
|
|
363
|
-
active
|
|
364
|
-
? 'border-primary text-foreground font-medium'
|
|
365
|
-
: 'border-transparent text-muted-foreground hover:text-foreground hover:border-border',
|
|
366
|
-
].join(' ')
|
|
367
|
-
|
|
368
|
-
const onClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
|
|
369
|
-
if (e.button !== 0) return
|
|
370
|
-
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return
|
|
371
|
-
e.preventDefault()
|
|
372
|
-
void navigate(url)
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
return (
|
|
376
|
-
<a
|
|
377
|
-
key={i}
|
|
378
|
-
href={url}
|
|
379
|
-
onClick={onClick}
|
|
380
|
-
role="tab"
|
|
381
|
-
aria-selected={active}
|
|
382
|
-
data-active={active || undefined}
|
|
383
|
-
className={triggerCls}
|
|
384
|
-
>
|
|
385
|
-
{Icon && <Icon className="size-4" aria-hidden="true" />}
|
|
386
|
-
<span>{label}</span>
|
|
387
|
-
{badge !== undefined && (
|
|
388
|
-
<span className={`ml-1 inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${badgeCls}`}>
|
|
389
|
-
{badge}
|
|
390
|
-
</span>
|
|
391
|
-
)}
|
|
392
|
-
</a>
|
|
393
|
-
)
|
|
394
|
-
})}
|
|
395
|
-
</nav>
|
|
396
|
-
</div>
|
|
397
|
-
)
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
interface RelationTabMetaShape {
|
|
401
|
-
key: string
|
|
402
|
-
label: string
|
|
403
|
-
url: string
|
|
404
|
-
active: boolean
|
|
405
|
-
icon?: unknown
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
interface BreadcrumbItemShape {
|
|
409
|
-
label: string
|
|
410
|
-
url?: string
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
/** Phase C — server-resolved breadcrumb chain rendered above any other
|
|
414
|
-
* top-of-page chrome. The trailing item carries no `url` and renders
|
|
415
|
-
* as plain text + `aria-current="page"`. SPA-navigates on plain
|
|
416
|
-
* left-click; modified clicks fall through. */
|
|
417
|
-
function BreadcrumbsRenderer({ el }: { el: ElementMeta }) {
|
|
418
|
-
const navigate = useNavigate()
|
|
419
|
-
const items = (el['items'] as BreadcrumbItemShape[] | undefined) ?? []
|
|
420
|
-
if (items.length < 2) return null
|
|
421
|
-
|
|
422
|
-
return (
|
|
423
|
-
<nav aria-label="Breadcrumb" className="text-sm text-muted-foreground">
|
|
424
|
-
<ol className="flex flex-wrap items-center gap-1.5">
|
|
425
|
-
{items.map((item, i) => {
|
|
426
|
-
const isLast = i === items.length - 1
|
|
427
|
-
const linkable = !!item.url && !isLast
|
|
428
|
-
|
|
429
|
-
const onClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
|
|
430
|
-
if (e.button !== 0) return
|
|
431
|
-
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return
|
|
432
|
-
if (!item.url) return
|
|
433
|
-
e.preventDefault()
|
|
434
|
-
void navigate(item.url)
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
return (
|
|
438
|
-
<li key={`${i}:${item.label}`} className="inline-flex items-center gap-1.5">
|
|
439
|
-
{linkable
|
|
440
|
-
? (
|
|
441
|
-
<a
|
|
442
|
-
href={item.url}
|
|
443
|
-
onClick={onClick}
|
|
444
|
-
className="hover:text-foreground transition-colors"
|
|
445
|
-
>
|
|
446
|
-
{item.label}
|
|
447
|
-
</a>
|
|
448
|
-
)
|
|
449
|
-
: (
|
|
450
|
-
<span
|
|
451
|
-
aria-current={isLast ? 'page' : undefined}
|
|
452
|
-
className={isLast ? 'text-foreground font-medium' : undefined}
|
|
453
|
-
>
|
|
454
|
-
{item.label}
|
|
455
|
-
</span>
|
|
456
|
-
)}
|
|
457
|
-
{!isLast && (
|
|
458
|
-
<span aria-hidden="true" className="text-muted-foreground/50">/</span>
|
|
459
|
-
)}
|
|
460
|
-
</li>
|
|
461
|
-
)
|
|
462
|
-
})}
|
|
463
|
-
</ol>
|
|
464
|
-
</nav>
|
|
465
|
-
)
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
/** Plan #11 — relation manager nav strip. Renders one anchor per tab;
|
|
469
|
-
* the active tab gets the same border-primary styling as ListTabs.
|
|
470
|
-
* SPA-navigates on plain left-click; cmd/ctrl/shift/middle-click fall
|
|
471
|
-
* through so users can open a manager in a new tab. */
|
|
472
|
-
function RelationTabsRenderer({ el }: { el: ElementMeta }) {
|
|
473
|
-
const navigate = useNavigate()
|
|
474
|
-
const tabs = (el['tabs'] as RelationTabMetaShape[] | undefined) ?? []
|
|
475
|
-
if (tabs.length === 0) return null
|
|
476
|
-
|
|
477
|
-
return (
|
|
478
|
-
<div className="border-b border-border">
|
|
479
|
-
<nav className="flex items-center gap-1 -mb-px overflow-x-auto" role="tablist">
|
|
480
|
-
{tabs.map((t, i) => {
|
|
481
|
-
const triggerCls = [
|
|
482
|
-
'inline-flex items-center gap-1.5 px-3 py-2 text-sm border-b-2 transition-colors whitespace-nowrap',
|
|
483
|
-
t.active
|
|
484
|
-
? 'border-primary text-foreground font-medium'
|
|
485
|
-
: 'border-transparent text-muted-foreground hover:text-foreground hover:border-border',
|
|
486
|
-
].join(' ')
|
|
487
|
-
|
|
488
|
-
const onClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
|
|
489
|
-
if (e.button !== 0) return
|
|
490
|
-
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return
|
|
491
|
-
e.preventDefault()
|
|
492
|
-
void navigate(t.url)
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
return (
|
|
496
|
-
<a
|
|
497
|
-
key={t.key + ':' + i}
|
|
498
|
-
href={t.url}
|
|
499
|
-
onClick={onClick}
|
|
500
|
-
role="tab"
|
|
501
|
-
aria-selected={t.active}
|
|
502
|
-
data-active={t.active || undefined}
|
|
503
|
-
className={triggerCls}
|
|
504
|
-
>
|
|
505
|
-
<RelationTabIcon icon={t.icon} />
|
|
506
|
-
<span>{t.label}</span>
|
|
507
|
-
</a>
|
|
508
|
-
)
|
|
509
|
-
})}
|
|
510
|
-
</nav>
|
|
511
|
-
</div>
|
|
512
|
-
)
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
function RelationTabIcon({ icon }: { icon: unknown }) {
|
|
516
|
-
// SerializedIcon is `string | { class: string }`. Use useIconFor to
|
|
517
|
-
// resolve component-typed icons through the Vite plugin's manifest.
|
|
518
|
-
const Icon = useIconFor(icon as SerializedIcon | undefined)
|
|
519
|
-
if (!Icon) return null
|
|
520
|
-
return <Icon className="size-4 inline" aria-hidden="true" />
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
export interface SchemaRendererProps {
|
|
524
|
-
/** Resolved schema elements (server-side `resolveSchema` output) that
|
|
525
|
-
* the renderer walks recursively. */
|
|
526
|
-
elements: ElementMeta[]
|
|
527
|
-
/**
|
|
528
|
-
* Initial widget data — a record keyed by widget id whose values are
|
|
529
|
-
* stamped onto the SSR pass by `tagWidgetUrls` + `resolveServerDataElements`.
|
|
530
|
-
* Surfaces through `<WidgetDataProvider>` so per-widget components
|
|
531
|
-
* can read their first-paint payload through `useInitialWidgetData`.
|
|
532
|
-
* Optional — pages with no widgets ship `undefined` and the provider
|
|
533
|
-
* is a no-op.
|
|
534
|
-
*/
|
|
535
|
-
widgetData?: Record<string, unknown>
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
export function SchemaRenderer({ elements, widgetData }: SchemaRendererProps) {
|
|
539
|
-
if (!elements || elements.length === 0) return null
|
|
540
|
-
// exactOptionalPropertyTypes: only spread `data` when defined.
|
|
541
|
-
const providerProps = widgetData !== undefined ? { data: widgetData } : {}
|
|
542
|
-
return (
|
|
543
|
-
<WidgetDataProvider {...providerProps}>
|
|
544
|
-
<div className="flex flex-col gap-6">
|
|
545
|
-
{elements.map((el, i) => renderElement(el, i))}
|
|
546
|
-
</div>
|
|
547
|
-
</WidgetDataProvider>
|
|
548
|
-
)
|
|
549
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import * as React from 'react'
|
|
2
|
-
import { useEffect, useState } from 'react'
|
|
3
|
-
import { SearchIcon } from 'lucide-react'
|
|
4
|
-
|
|
5
|
-
import { useCommandPaletteOpener } from './CommandPalette.js'
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Plan #12 — compact "Search… ⌘K" pill that lives in the sidebar /
|
|
9
|
-
* topbar header. Clicking it opens the command palette via the
|
|
10
|
-
* `useCommandPaletteOpener()` context hook (AppShell hosts the
|
|
11
|
-
* provider).
|
|
12
|
-
*
|
|
13
|
-
* Renders nothing when the opener isn't mounted (panel without
|
|
14
|
-
* AppShell — e.g., a custom embedding). The keyboard shortcut hint
|
|
15
|
-
* adapts to platform: ⌘ on macOS, Ctrl elsewhere.
|
|
16
|
-
*/
|
|
17
|
-
export function SearchTrigger(): React.ReactElement | null {
|
|
18
|
-
const open = useCommandPaletteOpener()
|
|
19
|
-
const [isMac, setIsMac] = useState(false)
|
|
20
|
-
|
|
21
|
-
// Detect macOS after mount — server renders with the default ("Ctrl"),
|
|
22
|
-
// client refines after hydration. SSR-stable, no flash on macOS users
|
|
23
|
-
// because the symbol is resolved before the icon paints.
|
|
24
|
-
useEffect(() => {
|
|
25
|
-
if (typeof navigator !== 'undefined') {
|
|
26
|
-
setIsMac(/Mac|iPhone|iPad|iPod/.test(navigator.platform))
|
|
27
|
-
}
|
|
28
|
-
}, [])
|
|
29
|
-
|
|
30
|
-
if (!open) return null
|
|
31
|
-
|
|
32
|
-
return (
|
|
33
|
-
<button
|
|
34
|
-
type="button"
|
|
35
|
-
onClick={open}
|
|
36
|
-
aria-label="Open search"
|
|
37
|
-
className="flex h-8 items-center gap-2 rounded-md border border-border bg-muted/40 px-2.5 text-xs text-muted-foreground hover:bg-muted hover:text-foreground transition"
|
|
38
|
-
>
|
|
39
|
-
<SearchIcon className="size-3.5" aria-hidden="true" />
|
|
40
|
-
<span className="hidden sm:inline">Search…</span>
|
|
41
|
-
<kbd className="hidden sm:inline-flex items-center font-mono text-[10px] text-muted-foreground/80 border border-border/60 rounded px-1 ml-1">
|
|
42
|
-
{isMac ? '⌘K' : 'Ctrl K'}
|
|
43
|
-
</kbd>
|
|
44
|
-
</button>
|
|
45
|
-
)
|
|
46
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { createContext, useContext, useEffect, useState } from 'react'
|
|
4
|
-
import { generateThemeCSS } from '../theme/index.js'
|
|
5
|
-
import type { ThemeMeta } from '../theme/index.js'
|
|
6
|
-
|
|
7
|
-
type Theme = 'light' | 'dark' | 'system'
|
|
8
|
-
|
|
9
|
-
interface ThemeProviderProps {
|
|
10
|
-
children: React.ReactNode
|
|
11
|
-
defaultTheme?: Theme
|
|
12
|
-
storageKey?: string
|
|
13
|
-
/** Resolved theme — injects CSS variables when provided. */
|
|
14
|
-
theme?: ThemeMeta
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
interface ThemeContextValue {
|
|
18
|
-
theme: Theme
|
|
19
|
-
setTheme: (theme: Theme) => void
|
|
20
|
-
resolved: 'light' | 'dark'
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const ThemeContext = createContext<ThemeContextValue>({
|
|
24
|
-
theme: 'system',
|
|
25
|
-
setTheme: () => {},
|
|
26
|
-
resolved: 'light',
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
function getSystemTheme(): 'light' | 'dark' {
|
|
30
|
-
if (typeof window === 'undefined') return 'light'
|
|
31
|
-
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function ThemeProvider({ children, defaultTheme = 'system', storageKey = 'pilotiq-theme', theme: themeMeta }: ThemeProviderProps) {
|
|
35
|
-
const [theme, setThemeState] = useState<Theme>(defaultTheme)
|
|
36
|
-
const [mounted, setMounted] = useState(false)
|
|
37
|
-
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
const stored = localStorage.getItem(storageKey) as Theme | null
|
|
40
|
-
if (stored) setThemeState(stored)
|
|
41
|
-
setMounted(true)
|
|
42
|
-
}, [storageKey])
|
|
43
|
-
|
|
44
|
-
const resolved = theme === 'system' ? getSystemTheme() : theme
|
|
45
|
-
|
|
46
|
-
useEffect(() => {
|
|
47
|
-
if (!mounted) return
|
|
48
|
-
const root = document.documentElement
|
|
49
|
-
root.classList.remove('light', 'dark')
|
|
50
|
-
root.classList.add(resolved)
|
|
51
|
-
}, [resolved, mounted])
|
|
52
|
-
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
if (theme === 'system') {
|
|
55
|
-
const mq = window.matchMedia('(prefers-color-scheme: dark)')
|
|
56
|
-
const handler = () => {
|
|
57
|
-
const r = mq.matches ? 'dark' : 'light'
|
|
58
|
-
document.documentElement.classList.remove('light', 'dark')
|
|
59
|
-
document.documentElement.classList.add(r)
|
|
60
|
-
}
|
|
61
|
-
mq.addEventListener('change', handler)
|
|
62
|
-
return () => mq.removeEventListener('change', handler)
|
|
63
|
-
}
|
|
64
|
-
}, [theme])
|
|
65
|
-
|
|
66
|
-
// Inject theme CSS variables
|
|
67
|
-
useEffect(() => {
|
|
68
|
-
if (!themeMeta) return
|
|
69
|
-
const id = 'pilotiq-theme'
|
|
70
|
-
let style = document.getElementById(id) as HTMLStyleElement | null
|
|
71
|
-
if (!style) {
|
|
72
|
-
style = document.createElement('style')
|
|
73
|
-
style.id = id
|
|
74
|
-
document.head.appendChild(style)
|
|
75
|
-
}
|
|
76
|
-
style.textContent = generateThemeCSS(themeMeta)
|
|
77
|
-
}, [themeMeta])
|
|
78
|
-
|
|
79
|
-
function setTheme(t: Theme) {
|
|
80
|
-
setThemeState(t)
|
|
81
|
-
localStorage.setItem(storageKey, t)
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return (
|
|
85
|
-
<ThemeContext.Provider value={{ theme, setTheme, resolved }}>
|
|
86
|
-
{children}
|
|
87
|
-
</ThemeContext.Provider>
|
|
88
|
-
)
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export function useTheme() {
|
|
92
|
-
return useContext(ThemeContext)
|
|
93
|
-
}
|