@pilotiq/pilotiq 0.23.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 +91 -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/dist/actions/exportFactory.d.ts +10 -0
- package/dist/actions/exportFactory.d.ts.map +1 -1
- package/dist/actions/exportFactory.js +10 -0
- package/dist/actions/exportFactory.js.map +1 -1
- package/dist/react/CollabRoomContext.d.ts +5 -5
- package/dist/react/index.d.ts +0 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +0 -1
- package/dist/react/index.js.map +1 -1
- package/dist/routes/helpers.d.ts.map +1 -1
- package/dist/routes/helpers.js +6 -2
- package/dist/routes/helpers.js.map +1 -1
- package/dist/routes/relations.d.ts.map +1 -1
- package/dist/routes/relations.js +12 -0
- package/dist/routes/relations.js.map +1 -1
- package/package.json +6 -1
- package/.turbo/turbo-build.log +0 -8
- package/CLAUDE.md +0 -265
- package/dist/react/useCollabSeed.d.ts +0 -23
- package/dist/react/useCollabSeed.d.ts.map +0 -1
- package/dist/react/useCollabSeed.js +0 -82
- package/dist/react/useCollabSeed.js.map +0 -1
- 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 -215
- 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 -195
- 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/useCollabSeed.ts +0 -86
- 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 -700
- package/src/routes/pages.ts +0 -175
- package/src/routes/panel.ts +0 -204
- package/src/routes/relations.ts +0 -1227
- 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,202 +0,0 @@
|
|
|
1
|
-
import { describe, it } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
|
|
4
|
-
import { syncRowGates, type RowGateMeta } from './syncRowGates.js'
|
|
5
|
-
|
|
6
|
-
interface TestRow extends RowGateMeta {
|
|
7
|
-
// Local-only fields the helper must preserve verbatim.
|
|
8
|
-
children?: unknown[]
|
|
9
|
-
type?: string
|
|
10
|
-
unknownType?: boolean
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function row(id: string, extras: Partial<TestRow> = {}): TestRow {
|
|
14
|
-
return { id, ...extras }
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
describe('syncRowGates', () => {
|
|
18
|
-
it('returns the same reference when every row already matches', () => {
|
|
19
|
-
const prev = [row('a'), row('b')]
|
|
20
|
-
const out = syncRowGates(prev, [{ id: 'a' }, { id: 'b' }])
|
|
21
|
-
assert.equal(out, prev)
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
it('stamps `hidden: true` when fresh meta hides a previously-visible row', () => {
|
|
25
|
-
const prev = [row('a'), row('b')]
|
|
26
|
-
const out = syncRowGates(prev, [{ id: 'a' }, { id: 'b', hidden: true }])
|
|
27
|
-
assert.notEqual(out, prev)
|
|
28
|
-
assert.equal(out[0]?.hidden, undefined)
|
|
29
|
-
assert.equal(out[1]?.hidden, true)
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
it('clears `hidden` when fresh meta drops the flag', () => {
|
|
33
|
-
const prev: TestRow[] = [row('a', { hidden: true })]
|
|
34
|
-
const out = syncRowGates(prev, [{ id: 'a' }])
|
|
35
|
-
assert.notEqual(out, prev)
|
|
36
|
-
assert.equal(out[0]?.hidden, undefined)
|
|
37
|
-
assert.ok(!('hidden' in (out[0] ?? {})))
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
it('toggles each capability flag independently', () => {
|
|
41
|
-
const prev: TestRow[] = [row('a', { canDelete: false }), row('b', { canClone: false }), row('c', { canReorder: false })]
|
|
42
|
-
const out = syncRowGates(prev, [
|
|
43
|
-
{ id: 'a' }, // canDelete cleared
|
|
44
|
-
{ id: 'b', canClone: false }, // canClone unchanged
|
|
45
|
-
{ id: 'c', canDelete: false }, // canReorder cleared, canDelete set
|
|
46
|
-
])
|
|
47
|
-
assert.notEqual(out, prev)
|
|
48
|
-
assert.equal(out[0]?.canDelete, undefined)
|
|
49
|
-
assert.equal(out[1]?.canClone, false)
|
|
50
|
-
assert.equal(out[1]?.canDelete, undefined)
|
|
51
|
-
assert.equal(out[2]?.canReorder, undefined)
|
|
52
|
-
assert.equal(out[2]?.canDelete, false)
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
it('preserves local-only fields (children / type / unknownType) — never echoed back from server', () => {
|
|
56
|
-
const children = [{ kind: 'placeholder' }]
|
|
57
|
-
const prev: TestRow[] = [
|
|
58
|
-
row('a', { children, type: 'heading', unknownType: false }),
|
|
59
|
-
row('b', { children, type: 'paragraph' }),
|
|
60
|
-
]
|
|
61
|
-
const out = syncRowGates(prev, [{ id: 'a', hidden: true }, { id: 'b' }])
|
|
62
|
-
assert.equal(out[0]?.children, children)
|
|
63
|
-
assert.equal(out[0]?.type, 'heading')
|
|
64
|
-
assert.equal(out[0]?.unknownType, false)
|
|
65
|
-
assert.equal(out[0]?.hidden, true)
|
|
66
|
-
assert.equal(out[1]?.children, children)
|
|
67
|
-
assert.equal(out[1]?.type, 'paragraph')
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
it('leaves rows whose ids aren\'t in the fresh list untouched (client added a row mid-flight)', () => {
|
|
71
|
-
const prev = [row('a', { hidden: true }), row('b'), row('c-local-only')]
|
|
72
|
-
const out = syncRowGates(prev, [{ id: 'a' }, { id: 'b' }])
|
|
73
|
-
// a's hidden flag cleared because fresh has it, b unchanged, c left alone.
|
|
74
|
-
assert.equal(out[0]?.hidden, undefined)
|
|
75
|
-
assert.equal(out[1]?.hidden, undefined)
|
|
76
|
-
assert.equal(out[2]?.id, 'c-local-only')
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
it('preserves row order — never reorders or appends', () => {
|
|
80
|
-
const prev = [row('a'), row('b'), row('c')]
|
|
81
|
-
const out = syncRowGates(prev, [{ id: 'b' }, { id: 'a' }, { id: 'c', hidden: true }])
|
|
82
|
-
assert.equal(out[0]?.id, 'a')
|
|
83
|
-
assert.equal(out[1]?.id, 'b')
|
|
84
|
-
assert.equal(out[2]?.id, 'c')
|
|
85
|
-
assert.equal(out[2]?.hidden, true)
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
it('does not mutate input rows', () => {
|
|
89
|
-
const a: TestRow = row('a')
|
|
90
|
-
const b: TestRow = row('b', { hidden: true })
|
|
91
|
-
syncRowGates([a, b], [{ id: 'a', hidden: true }, { id: 'b' }])
|
|
92
|
-
assert.equal(a.hidden, undefined)
|
|
93
|
-
assert.equal(b.hidden, true)
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
it('returns the same reference when fresh is empty (no row meta to sync)', () => {
|
|
97
|
-
const prev = [row('a'), row('b')]
|
|
98
|
-
const out = syncRowGates(prev, [])
|
|
99
|
-
assert.equal(out, prev)
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
it('treats `hidden: false` and missing `hidden` as equivalent (no-op)', () => {
|
|
103
|
-
const prev = [row('a')]
|
|
104
|
-
const out = syncRowGates(prev, [{ id: 'a', hidden: false }])
|
|
105
|
-
assert.equal(out, prev)
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
it('combines all four flag transitions in a single sync', () => {
|
|
109
|
-
const prev: TestRow[] = [
|
|
110
|
-
row('a', { hidden: true, canDelete: false, canClone: false, canReorder: false }),
|
|
111
|
-
]
|
|
112
|
-
const out = syncRowGates(prev, [{ id: 'a' }])
|
|
113
|
-
assert.notEqual(out, prev)
|
|
114
|
-
assert.equal(out[0]?.hidden, undefined)
|
|
115
|
-
assert.equal(out[0]?.canDelete, undefined)
|
|
116
|
-
assert.equal(out[0]?.canClone, undefined)
|
|
117
|
-
assert.equal(out[0]?.canReorder, undefined)
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
describe('itemLabel sync', () => {
|
|
121
|
-
it('updates itemLabel when fresh meta carries a different string', () => {
|
|
122
|
-
const prev: TestRow[] = [row('a', { itemLabel: 'Apple' })]
|
|
123
|
-
const out = syncRowGates(prev, [{ id: 'a', itemLabel: 'Apricot' }])
|
|
124
|
-
assert.notEqual(out, prev)
|
|
125
|
-
assert.equal(out[0]?.itemLabel, 'Apricot')
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
it('clears itemLabel when fresh meta drops it (label fn returned non-string this resolve)', () => {
|
|
129
|
-
const prev: TestRow[] = [row('a', { itemLabel: 'Apple' })]
|
|
130
|
-
const out = syncRowGates(prev, [{ id: 'a' }])
|
|
131
|
-
assert.notEqual(out, prev)
|
|
132
|
-
assert.equal(out[0]?.itemLabel, undefined)
|
|
133
|
-
assert.ok(!('itemLabel' in (out[0] ?? {})))
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
it('stamps itemLabel when fresh meta adds it (was missing on prev)', () => {
|
|
137
|
-
const prev: TestRow[] = [row('a')]
|
|
138
|
-
const out = syncRowGates(prev, [{ id: 'a', itemLabel: 'Apple' }])
|
|
139
|
-
assert.notEqual(out, prev)
|
|
140
|
-
assert.equal(out[0]?.itemLabel, 'Apple')
|
|
141
|
-
})
|
|
142
|
-
|
|
143
|
-
it('keeps reference identity when itemLabel is byte-identical across resolves', () => {
|
|
144
|
-
const prev: TestRow[] = [row('a', { itemLabel: 'Apple' })]
|
|
145
|
-
const out = syncRowGates(prev, [{ id: 'a', itemLabel: 'Apple' }])
|
|
146
|
-
assert.equal(out, prev)
|
|
147
|
-
})
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
describe('extraActions sync', () => {
|
|
151
|
-
it('updates extraActions when the action list changes shape', () => {
|
|
152
|
-
const prevActions = [{ name: 'send', label: 'Send' }]
|
|
153
|
-
const freshActions = [{ name: 'send', label: 'Send' }, { name: 'archive', label: 'Archive' }]
|
|
154
|
-
const prev: TestRow[] = [row('a', { extraActions: prevActions })]
|
|
155
|
-
const out = syncRowGates(prev, [{ id: 'a', extraActions: freshActions }])
|
|
156
|
-
assert.notEqual(out, prev)
|
|
157
|
-
assert.equal(out[0]?.extraActions, freshActions)
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
it('updates extraActions when an action toggles disabled mid-form (visibility re-resolved)', () => {
|
|
161
|
-
const prevActions = [{ name: 'send', label: 'Send', disabled: false }]
|
|
162
|
-
const freshActions = [{ name: 'send', label: 'Send', disabled: true }]
|
|
163
|
-
const prev: TestRow[] = [row('a', { extraActions: prevActions })]
|
|
164
|
-
const out = syncRowGates(prev, [{ id: 'a', extraActions: freshActions }])
|
|
165
|
-
assert.notEqual(out, prev)
|
|
166
|
-
assert.equal(out[0]?.extraActions, freshActions)
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
it('clears extraActions when fresh meta drops them (every action failed visibility)', () => {
|
|
170
|
-
const prev: TestRow[] = [row('a', { extraActions: [{ name: 'send' }] })]
|
|
171
|
-
const out = syncRowGates(prev, [{ id: 'a' }])
|
|
172
|
-
assert.notEqual(out, prev)
|
|
173
|
-
assert.equal(out[0]?.extraActions, undefined)
|
|
174
|
-
assert.ok(!('extraActions' in (out[0] ?? {})))
|
|
175
|
-
})
|
|
176
|
-
|
|
177
|
-
it('treats fresh empty array same as undefined (clears prev)', () => {
|
|
178
|
-
const prev: TestRow[] = [row('a', { extraActions: [{ name: 'send' }] })]
|
|
179
|
-
const out = syncRowGates(prev, [{ id: 'a', extraActions: [] }])
|
|
180
|
-
assert.notEqual(out, prev)
|
|
181
|
-
assert.equal(out[0]?.extraActions, undefined)
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
it('keeps reference identity when extraActions are byte-identical across resolves', () => {
|
|
185
|
-
const actions = [{ name: 'send', label: 'Send' }]
|
|
186
|
-
const prev: TestRow[] = [row('a', { extraActions: actions })]
|
|
187
|
-
const out = syncRowGates(prev, [{ id: 'a', extraActions: [{ name: 'send', label: 'Send' }] }])
|
|
188
|
-
assert.equal(out, prev)
|
|
189
|
-
})
|
|
190
|
-
})
|
|
191
|
-
|
|
192
|
-
it('combines flag + itemLabel + extraActions transitions in a single sync', () => {
|
|
193
|
-
const prev: TestRow[] = [
|
|
194
|
-
row('a', { hidden: true, itemLabel: 'Old', extraActions: [{ name: 'a' }] }),
|
|
195
|
-
]
|
|
196
|
-
const out = syncRowGates(prev, [{ id: 'a', itemLabel: 'New', extraActions: [{ name: 'b' }] }])
|
|
197
|
-
assert.notEqual(out, prev)
|
|
198
|
-
assert.equal(out[0]?.hidden, undefined)
|
|
199
|
-
assert.equal(out[0]?.itemLabel, 'New')
|
|
200
|
-
assert.deepEqual(out[0]?.extraActions, [{ name: 'b' }])
|
|
201
|
-
})
|
|
202
|
-
})
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
// Match by `id`: rows in `fresh` come from server re-resolve of whatever
|
|
2
|
-
// rows the client posted, so any row missing from `fresh` (a client-added
|
|
3
|
-
// row that arrived after the live() request fired) is left untouched.
|
|
4
|
-
// Returns `prev` reference unchanged when nothing differs — caller's
|
|
5
|
-
// `setRows` then no-ops, avoiding a render cascade on idempotent responses.
|
|
6
|
-
export interface RowGateMeta {
|
|
7
|
-
id: string
|
|
8
|
-
hidden?: boolean
|
|
9
|
-
canDelete?: false
|
|
10
|
-
canClone?: false
|
|
11
|
-
canReorder?: false
|
|
12
|
-
itemLabel?: string
|
|
13
|
-
extraActions?: readonly unknown[]
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function syncRowGates<R extends RowGateMeta>(
|
|
17
|
-
prev: R[],
|
|
18
|
-
fresh: ReadonlyArray<RowGateMeta>,
|
|
19
|
-
): R[] {
|
|
20
|
-
const byId = new Map<string, RowGateMeta>()
|
|
21
|
-
for (const r of fresh) byId.set(r.id, r)
|
|
22
|
-
|
|
23
|
-
let changed = false
|
|
24
|
-
const next = prev.map((row): R => {
|
|
25
|
-
const m = byId.get(row.id)
|
|
26
|
-
if (!m) return row
|
|
27
|
-
|
|
28
|
-
const targetHidden = m.hidden === true
|
|
29
|
-
const targetCanDelete = m.canDelete === false ? (false as const) : undefined
|
|
30
|
-
const targetCanClone = m.canClone === false ? (false as const) : undefined
|
|
31
|
-
const targetCanReorder = m.canReorder === false ? (false as const) : undefined
|
|
32
|
-
const targetItemLabel = typeof m.itemLabel === 'string' ? m.itemLabel : undefined
|
|
33
|
-
const targetExtra = m.extraActions && m.extraActions.length > 0 ? m.extraActions : undefined
|
|
34
|
-
|
|
35
|
-
const extraDiffers =
|
|
36
|
-
(row.extraActions?.length ?? 0) !== (targetExtra?.length ?? 0)
|
|
37
|
-
|| (targetExtra !== undefined && JSON.stringify(row.extraActions) !== JSON.stringify(targetExtra))
|
|
38
|
-
|
|
39
|
-
if (
|
|
40
|
-
Boolean(row.hidden) === targetHidden &&
|
|
41
|
-
row.canDelete === targetCanDelete &&
|
|
42
|
-
row.canClone === targetCanClone &&
|
|
43
|
-
row.canReorder === targetCanReorder &&
|
|
44
|
-
row.itemLabel === targetItemLabel &&
|
|
45
|
-
!extraDiffers
|
|
46
|
-
) return row
|
|
47
|
-
|
|
48
|
-
changed = true
|
|
49
|
-
const updated = { ...row }
|
|
50
|
-
if (targetHidden) updated.hidden = true
|
|
51
|
-
else delete updated.hidden
|
|
52
|
-
if (targetCanDelete === false) updated.canDelete = false
|
|
53
|
-
else delete updated.canDelete
|
|
54
|
-
if (targetCanClone === false) updated.canClone = false
|
|
55
|
-
else delete updated.canClone
|
|
56
|
-
if (targetCanReorder === false) updated.canReorder = false
|
|
57
|
-
else delete updated.canReorder
|
|
58
|
-
if (targetItemLabel !== undefined) updated.itemLabel = targetItemLabel
|
|
59
|
-
else delete updated.itemLabel
|
|
60
|
-
if (targetExtra !== undefined) updated.extraActions = targetExtra
|
|
61
|
-
else delete updated.extraActions
|
|
62
|
-
return updated
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
return changed ? next : prev
|
|
66
|
-
}
|
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
import React, { useState, useCallback } from 'react'
|
|
2
|
-
import type { ElementMeta } from '../../schema/Element.js'
|
|
3
|
-
import { useToast } from '../Toaster.js'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* TextField rich affordances live in this file (audit gap #3):
|
|
7
|
-
* - `revealable()` — eye-icon toggle that flips `type="password"` ↔ `text`
|
|
8
|
-
* - `copyable(message?)` — copy-to-clipboard button + toast
|
|
9
|
-
* - `prefixAction(Action) / suffixAction(Action)` — embedded Action buttons
|
|
10
|
-
* - `mask(pattern)` — keystroke-by-keystroke pattern formatter
|
|
11
|
-
*
|
|
12
|
-
* The components export a `useTextInputControls(el, name)` hook that
|
|
13
|
-
* returns `{ before, after, type, applyMask }` so the calling renderer
|
|
14
|
-
* can mount the controls inside `FieldShell`'s `before / after` slots
|
|
15
|
-
* and feed the masked value back through the controlled-input bridge.
|
|
16
|
-
*
|
|
17
|
-
* Mask alphabet:
|
|
18
|
-
* `9` — digit (0-9)
|
|
19
|
-
* `a` — alpha (A-Za-z)
|
|
20
|
-
* `*` — alphanumeric or any character
|
|
21
|
-
* anything else — literal (rendered verbatim)
|
|
22
|
-
*
|
|
23
|
-
* Submitted values are stripped of mask literals via `stripCharacters`
|
|
24
|
-
* (server-side coerce); the client also strips on input so what the user
|
|
25
|
-
* sees in the DOM matches what gets posted.
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
export interface TextInputControlsResult {
|
|
29
|
-
before: React.ReactNode
|
|
30
|
-
after: React.ReactNode
|
|
31
|
-
/** Effective `type` attribute — `'password'` when password+!revealed,
|
|
32
|
-
* `'text'` otherwise. Pass through to the rendered `<input>`. */
|
|
33
|
-
type: string
|
|
34
|
-
/** When the field has `mask(pattern)` set, format `value` against the
|
|
35
|
-
* pattern. Returns the formatted string. Skips when no mask. */
|
|
36
|
-
applyMask: (value: string) => string
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/** `renderAction(meta)` is supplied by the caller (SchemaRenderer's
|
|
40
|
-
* `renderElement`) to avoid an import cycle between the controls
|
|
41
|
-
* module and the main schema renderer. */
|
|
42
|
-
export function useTextInputControls(
|
|
43
|
-
el: ElementMeta,
|
|
44
|
-
name: string,
|
|
45
|
-
renderAction: (meta: ElementMeta) => React.ReactNode,
|
|
46
|
-
): TextInputControlsResult {
|
|
47
|
-
const isPassword = el['password'] === true
|
|
48
|
-
const isRevealable= el['revealable'] === true
|
|
49
|
-
const isCopyable = el['copyable'] === true
|
|
50
|
-
const copyMessage = (el['copyMessage'] as string | undefined) ?? 'Copied!'
|
|
51
|
-
const mask = el['mask'] as string | undefined
|
|
52
|
-
const prefixAct = el['prefixAction'] as ElementMeta | undefined
|
|
53
|
-
const suffixAct = el['suffixAction'] as ElementMeta | undefined
|
|
54
|
-
|
|
55
|
-
const [revealed, setRevealed] = useState(false)
|
|
56
|
-
const inputId = name
|
|
57
|
-
|
|
58
|
-
const onCopy = useCopyHandler(inputId, copyMessage)
|
|
59
|
-
|
|
60
|
-
const type = isPassword && !revealed ? 'password' : 'text'
|
|
61
|
-
|
|
62
|
-
const beforeNodes: React.ReactNode[] = []
|
|
63
|
-
if (prefixAct) beforeNodes.push(
|
|
64
|
-
<div key="pre-act" className="shrink-0">{renderAction(prefixAct)}</div>
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
const afterNodes: React.ReactNode[] = []
|
|
68
|
-
if (isCopyable) afterNodes.push(<CopyButton key="copy" onCopy={onCopy} />)
|
|
69
|
-
if (isRevealable && isPassword) {
|
|
70
|
-
afterNodes.push(
|
|
71
|
-
<RevealToggle
|
|
72
|
-
key="reveal"
|
|
73
|
-
revealed={revealed}
|
|
74
|
-
onToggle={() => setRevealed(v => !v)}
|
|
75
|
-
/>
|
|
76
|
-
)
|
|
77
|
-
}
|
|
78
|
-
if (suffixAct) afterNodes.push(
|
|
79
|
-
<div key="suf-act" className="shrink-0">{renderAction(suffixAct)}</div>
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
const applyMask = useCallback((value: string): string => {
|
|
83
|
-
if (!mask) return value
|
|
84
|
-
return formatWithMask(value, mask)
|
|
85
|
-
}, [mask])
|
|
86
|
-
|
|
87
|
-
return {
|
|
88
|
-
before: beforeNodes.length > 0 ? <>{beforeNodes}</> : null,
|
|
89
|
-
after: afterNodes.length > 0 ? <>{afterNodes}</> : null,
|
|
90
|
-
type,
|
|
91
|
-
applyMask,
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Format `raw` against `mask` using the documented alphabet. Literals
|
|
97
|
-
* in the mask render verbatim and consume no source character; pattern
|
|
98
|
-
* tokens consume the next matching source character (skipping
|
|
99
|
-
* mismatches so the user can paste an already-formatted value and have
|
|
100
|
-
* it re-format cleanly).
|
|
101
|
-
*/
|
|
102
|
-
export function formatWithMask(raw: string, mask: string): string {
|
|
103
|
-
let out = ''
|
|
104
|
-
let r = 0
|
|
105
|
-
for (let m = 0; m < mask.length; m++) {
|
|
106
|
-
const token = mask[m]!
|
|
107
|
-
const isPattern = token === '9' || token === 'a' || token === '*'
|
|
108
|
-
if (isPattern) {
|
|
109
|
-
if (r >= raw.length) break
|
|
110
|
-
// Advance through `raw` until we find a matching character.
|
|
111
|
-
while (r < raw.length) {
|
|
112
|
-
const ch = raw[r]!
|
|
113
|
-
const ok = token === '9'
|
|
114
|
-
? /[0-9]/.test(ch)
|
|
115
|
-
: token === 'a'
|
|
116
|
-
? /[A-Za-z]/.test(ch)
|
|
117
|
-
: true
|
|
118
|
-
r++
|
|
119
|
-
if (ok) { out += ch; break }
|
|
120
|
-
}
|
|
121
|
-
} else {
|
|
122
|
-
// Literal character — emit even when raw is exhausted, so a
|
|
123
|
-
// partially-typed value still shows the upcoming chrome
|
|
124
|
-
// (e.g. `(415) ` after the user types three digits). Consume the
|
|
125
|
-
// matching raw char if present so a paste of the already-formatted
|
|
126
|
-
// value doesn't double up.
|
|
127
|
-
out += token
|
|
128
|
-
if (raw[r] === token) r++
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return out
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function useCopyHandler(
|
|
135
|
-
inputId: string,
|
|
136
|
-
message: string,
|
|
137
|
-
): () => void {
|
|
138
|
-
const { notify } = useToast()
|
|
139
|
-
return () => {
|
|
140
|
-
if (typeof document === 'undefined') return
|
|
141
|
-
const el = document.getElementById(inputId) as HTMLInputElement | HTMLTextAreaElement | null
|
|
142
|
-
if (!el) return
|
|
143
|
-
const value = el.value
|
|
144
|
-
const writeText = navigator?.clipboard?.writeText?.bind(navigator.clipboard)
|
|
145
|
-
if (writeText) {
|
|
146
|
-
writeText(value).then(
|
|
147
|
-
() => notify({ type: 'success', title: message, duration: 2000 }),
|
|
148
|
-
() => notify({ type: 'error', title: 'Copy failed' }),
|
|
149
|
-
)
|
|
150
|
-
} else {
|
|
151
|
-
// Fallback: select + execCommand. Modern browsers all expose
|
|
152
|
-
// navigator.clipboard, so this is rare-path.
|
|
153
|
-
el.select()
|
|
154
|
-
try {
|
|
155
|
-
document.execCommand('copy')
|
|
156
|
-
notify({ type: 'success', title: message, duration: 2000 })
|
|
157
|
-
} catch {
|
|
158
|
-
notify({ type: 'error', title: 'Copy failed' })
|
|
159
|
-
}
|
|
160
|
-
el.setSelectionRange?.(0, 0)
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
function ChromeButton({ onClick, ariaLabel, children, autoFocus }: {
|
|
166
|
-
onClick: (e: React.MouseEvent) => void
|
|
167
|
-
ariaLabel: string
|
|
168
|
-
children: React.ReactNode
|
|
169
|
-
autoFocus?: boolean
|
|
170
|
-
}): React.ReactElement {
|
|
171
|
-
return (
|
|
172
|
-
<button
|
|
173
|
-
type="button"
|
|
174
|
-
tabIndex={-1}
|
|
175
|
-
onClick={(e) => { e.preventDefault(); onClick(e) }}
|
|
176
|
-
aria-label={ariaLabel}
|
|
177
|
-
className="inline-flex items-center justify-center rounded-md size-8 text-muted-foreground hover:bg-accent hover:text-accent-foreground shrink-0"
|
|
178
|
-
autoFocus={autoFocus}
|
|
179
|
-
>
|
|
180
|
-
{children}
|
|
181
|
-
</button>
|
|
182
|
-
)
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function CopyButton({ onCopy }: { onCopy: () => void }): React.ReactElement {
|
|
186
|
-
return (
|
|
187
|
-
<ChromeButton onClick={onCopy} ariaLabel="Copy">
|
|
188
|
-
<CopyIcon className="size-4" />
|
|
189
|
-
</ChromeButton>
|
|
190
|
-
)
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
function RevealToggle({ revealed, onToggle }: {
|
|
194
|
-
revealed: boolean
|
|
195
|
-
onToggle: () => void
|
|
196
|
-
}): React.ReactElement {
|
|
197
|
-
return (
|
|
198
|
-
<ChromeButton
|
|
199
|
-
onClick={onToggle}
|
|
200
|
-
ariaLabel={revealed ? 'Hide value' : 'Show value'}
|
|
201
|
-
>
|
|
202
|
-
{revealed ? <EyeOffIcon className="size-4" /> : <EyeIcon className="size-4" />}
|
|
203
|
-
</ChromeButton>
|
|
204
|
-
)
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// ─── Inline icon SVGs (avoids pulling lucide-react import into this file
|
|
208
|
-
// without checking it's already a dep — keeps the bundle stable). ────
|
|
209
|
-
|
|
210
|
-
function CopyIcon(props: React.SVGProps<SVGSVGElement>): React.ReactElement {
|
|
211
|
-
return (
|
|
212
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}>
|
|
213
|
-
<rect width="14" height="14" x="8" y="8" rx="2" ry="2" />
|
|
214
|
-
<path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" />
|
|
215
|
-
</svg>
|
|
216
|
-
)
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function EyeIcon(props: React.SVGProps<SVGSVGElement>): React.ReactElement {
|
|
220
|
-
return (
|
|
221
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}>
|
|
222
|
-
<path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z" />
|
|
223
|
-
<circle cx="12" cy="12" r="3" />
|
|
224
|
-
</svg>
|
|
225
|
-
)
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function EyeOffIcon(props: React.SVGProps<SVGSVGElement>): React.ReactElement {
|
|
229
|
-
return (
|
|
230
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}>
|
|
231
|
-
<path d="M9.88 9.88a3 3 0 1 0 4.24 4.24" />
|
|
232
|
-
<path d="M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68" />
|
|
233
|
-
<path d="M6.61 6.61A13.526 13.526 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61" />
|
|
234
|
-
<line x1="2" x2="22" y1="2" y2="22" />
|
|
235
|
-
</svg>
|
|
236
|
-
)
|
|
237
|
-
}
|
|
238
|
-
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Shared HTML5 drag-and-drop wiring for any list of rows that the user
|
|
5
|
-
* can reorder. Consumed by `TableRendererBody` (POSTs the new order
|
|
6
|
-
* to the server with rollback), `RepeaterInput`, and `BuilderInput`
|
|
7
|
-
* (both mutate local row state in place).
|
|
8
|
-
*
|
|
9
|
-
* Generic on `HTMLElement` so the same handlers wire onto a `<div>`
|
|
10
|
-
* row (card / grid layouts) AND a `<tr>` row (table layout) — the
|
|
11
|
-
* consumer cast happens at the JSX boundary.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
export interface RowReorderDnd {
|
|
15
|
-
dragId: string | null
|
|
16
|
-
/** The boundary slot the cursor is over (0..rows.length); null when no drag is active. */
|
|
17
|
-
dropAt: number | null
|
|
18
|
-
onDragStart: (id: string) => (e: React.DragEvent<HTMLElement>) => void
|
|
19
|
-
onDragOver: (idx: number) => (e: React.DragEvent<HTMLElement>) => void
|
|
20
|
-
onDrop: (e: React.DragEvent<HTMLElement>) => void
|
|
21
|
-
onDragEnd: () => void
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface UseRowReorderDndOptions {
|
|
25
|
-
/** When false, every handler short-circuits without firing `onDrop`. */
|
|
26
|
-
enabled: boolean
|
|
27
|
-
/** Fires once per successful drop, after the hook has cleared its drag state. */
|
|
28
|
-
onDrop: (fromId: string, dropAt: number) => void | Promise<void>
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function useRowReorderDnd({
|
|
32
|
-
enabled,
|
|
33
|
-
onDrop,
|
|
34
|
-
}: UseRowReorderDndOptions): RowReorderDnd {
|
|
35
|
-
const [dragId, setDragId] = useState<string | null>(null)
|
|
36
|
-
const [dropAt, setDropAt] = useState<number | null>(null)
|
|
37
|
-
|
|
38
|
-
const handleDragStart = (id: string) => (e: React.DragEvent<HTMLElement>): void => {
|
|
39
|
-
if (!enabled) return
|
|
40
|
-
setDragId(id)
|
|
41
|
-
// dataTransfer needs *something* to register the drag in Firefox.
|
|
42
|
-
e.dataTransfer.effectAllowed = 'move'
|
|
43
|
-
try { e.dataTransfer.setData('text/plain', id) } catch { /* IE quirk; ignore */ }
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const handleDragOver = (idx: number) => (e: React.DragEvent<HTMLElement>): void => {
|
|
47
|
-
if (!enabled || dragId === null) return
|
|
48
|
-
e.preventDefault()
|
|
49
|
-
e.dataTransfer.dropEffect = 'move'
|
|
50
|
-
// Drop above this row when cursor is in its top half, below when in its bottom half.
|
|
51
|
-
const rect = e.currentTarget.getBoundingClientRect()
|
|
52
|
-
const aboveHalf = e.clientY < rect.top + rect.height / 2
|
|
53
|
-
setDropAt(aboveHalf ? idx : idx + 1)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const handleDrop = (e: React.DragEvent<HTMLElement>): void => {
|
|
57
|
-
if (!enabled || dragId === null || dropAt === null) {
|
|
58
|
-
setDragId(null); setDropAt(null); return
|
|
59
|
-
}
|
|
60
|
-
e.preventDefault()
|
|
61
|
-
const fromId = dragId
|
|
62
|
-
const at = dropAt
|
|
63
|
-
setDragId(null); setDropAt(null)
|
|
64
|
-
void onDrop(fromId, at)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const handleDragEnd = (): void => {
|
|
68
|
-
setDragId(null); setDropAt(null)
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return {
|
|
72
|
-
dragId, dropAt,
|
|
73
|
-
onDragStart: handleDragStart,
|
|
74
|
-
onDragOver: handleDragOver,
|
|
75
|
-
onDrop: handleDrop,
|
|
76
|
-
onDragEnd: handleDragEnd,
|
|
77
|
-
}
|
|
78
|
-
}
|