@questpie/admin 2.0.0 → 3.0.0
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/README.md +119 -122
- package/dist/augmentation.d.mts +110 -11
- package/dist/client/blocks/block-renderer.d.mts +5 -12
- package/dist/client/blocks/block-renderer.mjs +89 -55
- package/dist/client/blocks/index.d.mts +2 -4
- package/dist/client/blocks/types.d.mts +3 -4
- package/dist/client/blocks/types.mjs +1 -2
- package/dist/client/builder/admin-types.d.mts +11 -44
- package/dist/client/builder/admin.d.mts +34 -45
- package/dist/client/builder/admin.mjs +35 -44
- package/dist/client/builder/field/field.d.mts +27 -205
- package/dist/client/builder/field/field.mjs +22 -68
- package/dist/client/builder/index.d.mts +23 -28
- package/dist/client/builder/page/page.d.mts +15 -27
- package/dist/client/builder/page/page.mjs +21 -17
- package/dist/client/builder/registry.d.mts +14 -34
- package/dist/client/builder/types/action-registry.mjs +148 -14
- package/dist/client/builder/types/action-types.d.mts +8 -35
- package/dist/client/builder/types/collection-types.mjs +1 -2
- package/dist/client/builder/types/common.d.mts +6 -20
- package/dist/client/builder/types/field-types.d.mts +4 -5
- package/dist/client/builder/types/field-types.mjs +1 -2
- package/dist/client/builder/types/ui-config.d.mts +3 -5
- package/dist/client/builder/types/widget-types.d.mts +19 -20
- package/dist/client/builder/validation.d.mts +33 -3
- package/dist/client/builder/validation.mjs +169 -150
- package/dist/client/builder/view/view.d.mts +26 -106
- package/dist/client/builder/view/view.mjs +14 -96
- package/dist/client/builder/widget/widget.d.mts +16 -22
- package/dist/client/builder/widget/widget.mjs +11 -16
- package/dist/client/components/actions/action-button.mjs +207 -97
- package/dist/client/components/actions/action-dialog.mjs +471 -176
- package/dist/client/components/actions/confirmation-dialog.mjs +166 -47
- package/dist/client/components/actions/header-actions.mjs +164 -71
- package/dist/client/components/admin-link.d.mts +8 -9
- package/dist/client/components/admin-link.mjs +127 -48
- package/dist/client/components/auth/auth-guard.d.mts +6 -7
- package/dist/client/components/auth/auth-guard.mjs +9 -9
- package/dist/client/components/auth/auth-loading.d.mts +3 -4
- package/dist/client/components/auth/auth-loading.mjs +38 -10
- package/dist/client/components/blocks/block-canvas.mjs +111 -42
- package/dist/client/components/blocks/block-editor-context.mjs +90 -23
- package/dist/client/components/blocks/block-editor-layout.mjs +176 -59
- package/dist/client/components/blocks/block-editor-provider.mjs +219 -139
- package/dist/client/components/blocks/block-fields-renderer.mjs +212 -42
- package/dist/client/components/blocks/block-insert-button.mjs +168 -51
- package/dist/client/components/blocks/block-item-menu.mjs +312 -110
- package/dist/client/components/blocks/block-item.mjs +372 -125
- package/dist/client/components/blocks/block-library-sidebar.mjs +209 -114
- package/dist/client/components/blocks/block-tree.mjs +73 -15
- package/dist/client/components/blocks/block-type-icon.mjs +65 -20
- package/dist/client/components/blocks/utils/tree-utils.mjs +1 -2
- package/dist/client/components/component-renderer.d.mts +11 -22
- package/dist/client/components/component-renderer.mjs +151 -38
- package/dist/client/components/error-boundary.mjs +77 -25
- package/dist/client/components/fields/array-field.mjs +474 -199
- package/dist/client/components/fields/asset-preview-field.mjs +143 -44
- package/dist/client/components/fields/blocks-field/blocks-field.mjs +143 -35
- package/dist/client/components/fields/boolean-field.mjs +62 -32
- package/dist/client/components/fields/date-field.mjs +46 -12
- package/dist/client/components/fields/datetime-field.mjs +42 -11
- package/dist/client/components/fields/email-field.mjs +57 -28
- package/dist/client/components/fields/field-utils.mjs +1 -2
- package/dist/client/components/fields/field-wrapper.mjs +107 -32
- package/dist/client/components/fields/json-field.mjs +323 -110
- package/dist/client/components/fields/locale-badge.mjs +16 -8
- package/dist/client/components/fields/number-field.mjs +63 -30
- package/dist/client/components/fields/object-array-field.mjs +666 -272
- package/dist/client/components/fields/object-field.mjs +656 -98
- package/dist/client/components/fields/relation/displays/cards-display.mjs +225 -111
- package/dist/client/components/fields/relation/displays/chips-display.mjs +150 -77
- package/dist/client/components/fields/relation/displays/grid-display.mjs +186 -91
- package/dist/client/components/fields/relation/displays/list-display.mjs +230 -111
- package/dist/client/components/fields/relation/displays/table-display.mjs +241 -66
- package/dist/client/components/fields/relation/displays/types.mjs +2 -3
- package/dist/client/components/fields/relation/relation-items-display.mjs +131 -35
- package/dist/client/components/fields/relation-field.mjs +70 -15
- package/dist/client/components/fields/relation-picker.mjs +93 -98
- package/dist/client/components/fields/relation-select.mjs +42 -29
- package/dist/client/components/fields/rich-text-editor/bubble-menu.mjs +90 -41
- package/dist/client/components/fields/rich-text-editor/extensions.mjs +33 -7
- package/dist/client/components/fields/rich-text-editor/image-popover.mjs +48 -23
- package/dist/client/components/fields/rich-text-editor/index.mjs +491 -158
- package/dist/client/components/fields/rich-text-editor/link-popover.mjs +13 -14
- package/dist/client/components/fields/rich-text-editor/presets.mjs +1 -2
- package/dist/client/components/fields/rich-text-editor/slash-commands.mjs +96 -53
- package/dist/client/components/fields/rich-text-editor/table-controls.mjs +416 -107
- package/dist/client/components/fields/rich-text-editor/toolbar.mjs +476 -215
- package/dist/client/components/fields/rich-text-editor/types.mjs +1 -2
- package/dist/client/components/fields/rich-text-editor/utils.mjs +1 -2
- package/dist/client/components/fields/rich-text-field.mjs +55 -17
- package/dist/client/components/fields/select-field.mjs +79 -44
- package/dist/client/components/fields/text-field.mjs +62 -29
- package/dist/client/components/fields/textarea-field.mjs +61 -29
- package/dist/client/components/fields/time-field.mjs +39 -11
- package/dist/client/components/fields/upload-field.mjs +253 -129
- package/dist/client/components/filter-builder/columns-tab.mjs +287 -93
- package/dist/client/components/filter-builder/filter-builder-sheet.mjs +437 -138
- package/dist/client/components/filter-builder/filters-tab.mjs +409 -126
- package/dist/client/components/filter-builder/saved-views-tab.mjs +259 -106
- package/dist/client/components/history-sidebar.mjs +496 -0
- package/dist/client/components/layout/field-layout-renderer.mjs +301 -0
- package/dist/client/components/locale-switcher.mjs +231 -108
- package/dist/client/components/media/media-grid.mjs +259 -84
- package/dist/client/components/media/media-picker-dialog.mjs +500 -192
- package/dist/client/components/preview/live-preview-mode.mjs +416 -124
- package/dist/client/components/preview/preview-pane.mjs +353 -144
- package/dist/client/components/primitives/asset-preview.mjs +665 -257
- package/dist/client/components/primitives/checkbox-input.mjs +37 -11
- package/dist/client/components/primitives/date-input.mjs +392 -149
- package/dist/client/components/primitives/dropzone.mjs +314 -185
- package/dist/client/components/primitives/number-input.mjs +14 -10
- package/dist/client/components/primitives/select-multi.mjs +519 -185
- package/dist/client/components/primitives/select-single.mjs +416 -126
- package/dist/client/components/primitives/text-input.mjs +10 -5
- package/dist/client/components/primitives/textarea-input.mjs +10 -5
- package/dist/client/components/primitives/time-input.mjs +118 -45
- package/dist/client/components/primitives/toggle-input.mjs +31 -11
- package/dist/client/components/primitives/types.mjs +1 -2
- package/dist/client/components/sheets/resource-sheet.mjs +72 -64
- package/dist/client/components/ui/accordion.mjs +156 -37
- package/dist/client/components/ui/alert.mjs +70 -17
- package/dist/client/components/ui/badge.mjs +57 -16
- package/dist/client/components/ui/button.mjs +49 -14
- package/dist/client/components/ui/card.mjs +194 -39
- package/dist/client/components/ui/checkbox.mjs +71 -16
- package/dist/client/components/ui/command.mjs +220 -50
- package/dist/client/components/ui/dialog.mjs +265 -52
- package/dist/client/components/ui/drawer.mjs +260 -57
- package/dist/client/components/ui/dropdown-menu.mjs +293 -67
- package/dist/client/components/ui/empty-state.mjs +72 -26
- package/dist/client/components/ui/field.mjs +332 -56
- package/dist/client/components/ui/input-group.mjs +174 -41
- package/dist/client/components/ui/input.mjs +38 -9
- package/dist/client/components/ui/kbd.mjs +37 -8
- package/dist/client/components/ui/label.mjs +38 -8
- package/dist/client/components/ui/popover.mjs +162 -35
- package/dist/client/components/ui/responsive-dialog.mjs +277 -71
- package/dist/client/components/ui/search-input.mjs +101 -36
- package/dist/client/components/ui/select.mjs +297 -57
- package/dist/client/components/ui/separator.mjs +39 -9
- package/dist/client/components/ui/sheet.mjs +253 -51
- package/dist/client/components/ui/sidebar.mjs +700 -182
- package/dist/client/components/ui/skeleton.mjs +33 -8
- package/dist/client/components/ui/sonner.d.mts +2 -3
- package/dist/client/components/ui/sonner.mjs +45 -15
- package/dist/client/components/ui/spinner.mjs +44 -10
- package/dist/client/components/ui/switch.mjs +47 -12
- package/dist/client/components/ui/table.mjs +260 -50
- package/dist/client/components/ui/tabs.mjs +140 -29
- package/dist/client/components/ui/textarea.mjs +33 -8
- package/dist/client/components/ui/toolbar.mjs +105 -23
- package/dist/client/components/ui/tooltip.mjs +130 -29
- package/dist/client/components/widgets/chart-widget.mjs +456 -156
- package/dist/client/components/widgets/progress-widget.mjs +150 -60
- package/dist/client/components/widgets/quick-actions-widget.mjs +175 -87
- package/dist/client/components/widgets/recent-items-widget.mjs +157 -62
- package/dist/client/components/widgets/stats-widget.mjs +153 -42
- package/dist/client/components/widgets/table-widget.mjs +198 -64
- package/dist/client/components/widgets/timeline-widget.mjs +193 -82
- package/dist/client/components/widgets/value-widget.mjs +257 -56
- package/dist/client/components/widgets/widget-skeletons.mjs +390 -108
- package/dist/client/contexts/breadcrumb-context.mjs +44 -16
- package/dist/client/{context → contexts}/focus-context.d.mts +6 -7
- package/dist/client/{context → contexts}/focus-context.mjs +134 -62
- package/dist/client/hooks/typed-hooks.d.mts +38 -12
- package/dist/client/hooks/typed-hooks.mjs +758 -142
- package/dist/client/hooks/use-action.mjs +197 -69
- package/dist/client/hooks/use-admin-config.mjs +39 -10
- package/dist/client/hooks/use-admin-preferences.mjs +118 -15
- package/dist/client/hooks/use-admin-routes.mjs +60 -27
- package/dist/client/hooks/use-audit-history.mjs +157 -0
- package/dist/client/hooks/use-auth.d.mts +14 -15
- package/dist/client/hooks/use-auth.mjs +8 -9
- package/dist/client/hooks/use-collection-fields.mjs +58 -19
- package/dist/client/hooks/use-collection-meta.mjs +45 -13
- package/dist/client/hooks/use-collection-schema.mjs +34 -11
- package/dist/client/hooks/use-collection-validation.mjs +39 -25
- package/dist/client/hooks/use-collection.d.mts +18 -8
- package/dist/client/hooks/use-collection.mjs +560 -101
- package/dist/client/hooks/use-current-user.d.mts +6 -3
- package/dist/client/hooks/use-current-user.mjs +2 -2
- package/dist/client/hooks/use-field-hooks.mjs +73 -65
- package/dist/client/hooks/use-field-options.d.mts +1 -34
- package/dist/client/hooks/use-field-options.mjs +233 -148
- package/dist/client/hooks/use-global-fields.mjs +47 -16
- package/dist/client/hooks/use-global-meta.mjs +57 -11
- package/dist/client/hooks/use-global-schema.mjs +31 -11
- package/dist/client/hooks/use-global.d.mts +13 -2
- package/dist/client/hooks/use-global.mjs +244 -34
- package/dist/client/hooks/use-locks.mjs +331 -124
- package/dist/client/hooks/use-media-query.d.mts +1 -2
- package/dist/client/hooks/use-media-query.mjs +38 -19
- package/dist/client/hooks/use-prefill-params.mjs +2 -2
- package/dist/client/hooks/use-questpie-query-options.mjs +33 -11
- package/dist/client/hooks/use-reactive-fields.d.mts +6 -3
- package/dist/client/hooks/use-reactive-fields.mjs +130 -93
- package/dist/client/hooks/use-realtime-highlight.mjs +115 -53
- package/dist/client/hooks/use-saved-views.mjs +109 -34
- package/dist/client/hooks/use-search-param-toggle.d.mts +12 -0
- package/dist/client/hooks/use-search-param-toggle.mjs +115 -0
- package/dist/client/hooks/use-search.mjs +147 -36
- package/dist/client/hooks/use-server-actions.mjs +191 -0
- package/dist/client/hooks/use-server-validation.mjs +164 -72
- package/dist/client/hooks/use-server-widget-data.d.mts +2 -3
- package/dist/client/hooks/use-server-widget-data.mjs +36 -11
- package/dist/client/hooks/use-setup-status.d.mts +3 -4
- package/dist/client/hooks/use-setup-status.mjs +28 -16
- package/dist/client/hooks/use-sidebar-search-param.d.mts +9 -0
- package/dist/client/hooks/use-sidebar-search-param.mjs +104 -0
- package/dist/client/hooks/use-transition-stage.mjs +125 -0
- package/dist/client/hooks/use-upload-collection.mjs +1 -2
- package/dist/client/hooks/use-upload.mjs +189 -125
- package/dist/client/hooks/use-validation-error-map.mjs +10 -6
- package/dist/client/hooks/use-view-state.mjs +380 -162
- package/dist/client/i18n/hooks.mjs +191 -67
- package/dist/client/i18n/intl-cache.mjs +1 -2
- package/dist/client/i18n/messages.mjs +1 -2
- package/dist/client/i18n/simple.d.mts +1 -2
- package/dist/client/i18n/simple.mjs +1 -2
- package/dist/client/i18n/types.d.mts +1 -2
- package/dist/client/lib/cookies.mjs +9 -0
- package/dist/client/lib/events.mjs +5 -0
- package/dist/client/lib/render-profiler.mjs +51 -0
- package/dist/client/lib/utils.mjs +1 -6
- package/dist/client/preview/block-scope-context.d.mts +5 -6
- package/dist/client/preview/block-scope-context.mjs +50 -27
- package/dist/client/preview/index.d.mts +2 -2
- package/dist/client/preview/preview-banner.d.mts +3 -4
- package/dist/client/preview/preview-banner.mjs +74 -35
- package/dist/client/preview/preview-field.d.mts +9 -10
- package/dist/client/preview/preview-field.mjs +163 -61
- package/dist/client/preview/types.d.mts +1 -2
- package/dist/client/preview/types.mjs +1 -2
- package/dist/client/preview/use-collection-preview.d.mts +1 -2
- package/dist/client/preview/use-collection-preview.mjs +105 -56
- package/dist/client/runtime/content-locales-provider.mjs +87 -36
- package/dist/client/runtime/index.d.mts +1 -3
- package/dist/client/runtime/index.mjs +1 -3
- package/dist/client/runtime/locale-scope.mjs +69 -29
- package/dist/client/runtime/provider.d.mts +18 -9922
- package/dist/client/runtime/provider.mjs +250 -86
- package/dist/client/runtime/routes.d.mts +7 -7
- package/dist/client/runtime/routes.mjs +4 -20
- package/dist/client/runtime/translations-provider.mjs +114 -53
- package/dist/client/scope/picker.d.mts +3 -4
- package/dist/client/scope/picker.mjs +324 -90
- package/dist/client/scope/provider.d.mts +4 -5
- package/dist/client/scope/provider.mjs +30 -22
- package/dist/client/scope/types.d.mts +1 -2
- package/dist/client/styles/index.css +301 -225
- package/dist/client/utils/auto-expand-fields.mjs +23 -5
- package/dist/client/utils/build-field-definitions-from-schema.mjs +10 -7
- package/dist/client/utils/dependency-tracker.mjs +61 -0
- package/dist/client/utils/detect-relations.mjs +1 -2
- package/dist/client/utils/locale-to-flag.d.mts +8 -7
- package/dist/client/utils/locale-to-flag.mjs +1 -2
- package/dist/client/utils/routes.mjs +1 -2
- package/dist/client/views/auth/accept-invite-form.d.mts +3 -4
- package/dist/client/views/auth/accept-invite-form.mjs +414 -121
- package/dist/client/views/auth/auth-layout.d.mts +7 -8
- package/dist/client/views/auth/auth-layout.mjs +93 -30
- package/dist/client/views/auth/forgot-password-form.d.mts +4 -5
- package/dist/client/views/auth/forgot-password-form.mjs +332 -100
- package/dist/client/views/auth/invite-form.mjs +447 -105
- package/dist/client/views/auth/login-form.d.mts +4 -5
- package/dist/client/views/auth/login-form.mjs +340 -120
- package/dist/client/views/auth/reset-password-form.d.mts +4 -5
- package/dist/client/views/auth/reset-password-form.mjs +458 -131
- package/dist/client/views/auth/setup-form.d.mts +4 -5
- package/dist/client/views/auth/setup-form.mjs +481 -141
- package/dist/client/views/collection/auto-form-fields.mjs +686 -266
- package/dist/client/views/collection/bulk-action-toolbar.mjs +392 -203
- package/dist/client/views/collection/cells/complex-cells.mjs +635 -216
- package/dist/client/views/collection/cells/primitive-cells.mjs +332 -102
- package/dist/client/views/collection/cells/relation-cells.mjs +227 -72
- package/dist/client/views/collection/cells/shared/asset-thumbnail.mjs +456 -136
- package/dist/client/views/collection/cells/shared/cell-helpers.mjs +49 -2
- package/dist/client/views/collection/cells/shared/relation-chip.mjs +109 -25
- package/dist/client/views/collection/cells/upload-cells.mjs +16 -8
- package/dist/client/views/collection/columns/build-columns.mjs +51 -12
- package/dist/client/views/collection/columns/column-defaults.mjs +17 -2
- package/dist/client/views/collection/field-context.mjs +10 -11
- package/dist/client/views/collection/field-renderer.mjs +237 -40
- package/dist/client/views/collection/form-view.mjs +1108 -445
- package/dist/client/views/collection/table-view.mjs +300 -163
- package/dist/client/views/collection/view-skeletons.mjs +181 -87
- package/dist/client/views/common/global-search.mjs +557 -233
- package/dist/client/views/dashboard/dashboard-grid.mjs +707 -211
- package/dist/client/views/dashboard/dashboard-widget.mjs +145 -58
- package/dist/client/views/dashboard/widget-card.mjs +315 -102
- package/dist/client/views/globals/global-form-view.mjs +1256 -131
- package/dist/client/views/layout/admin-layout-provider.d.mts +18 -21
- package/dist/client/views/layout/admin-layout-provider.mjs +135 -32
- package/dist/client/views/layout/admin-layout.d.mts +14 -32
- package/dist/client/views/layout/admin-layout.mjs +254 -96
- package/dist/client/views/layout/admin-router.d.mts +10 -42
- package/dist/client/views/layout/admin-router.mjs +1086 -426
- package/dist/client/views/layout/admin-sidebar.d.mts +10 -16
- package/dist/client/views/layout/admin-sidebar.mjs +1211 -382
- package/dist/client/views/layout/admin-topbar.mjs +220 -112
- package/dist/client/views/pages/accept-invite-page.d.mts +5 -6
- package/dist/client/views/pages/accept-invite-page.mjs +302 -96
- package/dist/client/views/pages/dashboard-page.d.mts +7 -16
- package/dist/client/views/pages/dashboard-page.mjs +62 -23
- package/dist/client/views/pages/forgot-password-page.d.mts +7 -10
- package/dist/client/views/pages/forgot-password-page.mjs +112 -40
- package/dist/client/views/pages/invite-page.d.mts +6 -7
- package/dist/client/views/pages/invite-page.mjs +121 -46
- package/dist/client/views/pages/login-page.d.mts +8 -15
- package/dist/client/views/pages/login-page.mjs +152 -57
- package/dist/client/views/pages/reset-password-page.d.mts +7 -10
- package/dist/client/views/pages/reset-password-page.mjs +209 -57
- package/dist/client/views/pages/setup-page.d.mts +7 -10
- package/dist/client/views/pages/setup-page.mjs +108 -43
- package/dist/client-module.d.mts +3 -0
- package/dist/client-module.mjs +3 -0
- package/dist/client.d.mts +55 -48
- package/dist/client.mjs +26 -28
- package/dist/components/rich-text/rich-text-renderer.d.mts +3 -4
- package/dist/components/rich-text/rich-text-renderer.mjs +97 -70
- package/dist/index.d.mts +36 -39
- package/dist/index.mjs +26 -28
- package/dist/plugin.d.mts +2 -0
- package/dist/plugin.mjs +3 -0
- package/dist/server/adapters/nextjs.d.mts +13 -14
- package/dist/server/adapters/nextjs.mjs +12 -13
- package/dist/server/adapters/tanstack.d.mts +10 -11
- package/dist/server/adapters/tanstack.mjs +11 -12
- package/dist/server/augmentation/actions.d.mts +279 -0
- package/dist/server/augmentation/common.d.mts +76 -0
- package/dist/server/augmentation/dashboard.d.mts +547 -0
- package/dist/server/augmentation/form-layout.d.mts +303 -0
- package/dist/server/augmentation/index.d.mts +44 -0
- package/dist/server/augmentation/index.mjs +10 -0
- package/dist/server/augmentation/sidebar.d.mts +181 -0
- package/dist/server/augmentation/views.d.mts +237 -0
- package/dist/server/augmentation.d.mts +7 -1523
- package/dist/server/block/index.d.mts +4 -3
- package/dist/server/codegen/admin-client-template.mjs +93 -0
- package/dist/server/codegen/projection-validator.mjs +67 -0
- package/dist/server/fields/blocks.d.mts +10 -78
- package/dist/server/fields/blocks.mjs +74 -115
- package/dist/server/fields/index.d.mts +6 -39
- package/dist/server/fields/index.mjs +6 -7
- package/dist/server/fields/rich-text.d.mts +10 -77
- package/dist/server/fields/rich-text.mjs +59 -100
- package/dist/server/i18n/index.mjs +8 -9
- package/dist/server/i18n/messages/cs.mjs +3 -3
- package/dist/server/i18n/messages/de.mjs +3 -3
- package/dist/server/i18n/messages/en.mjs +217 -3
- package/dist/server/i18n/messages/es.mjs +3 -3
- package/dist/server/i18n/messages/fr.mjs +3 -3
- package/dist/server/i18n/messages/index.mjs +1 -2
- package/dist/server/i18n/messages/pl.mjs +3 -3
- package/dist/server/i18n/messages/pt.mjs +3 -3
- package/dist/server/i18n/messages/sk.mjs +202 -3
- package/dist/server/modules/admin/.generated/module.d.mts +52 -0
- package/dist/server/modules/admin/.generated/module.mjs +78 -0
- package/dist/server/modules/admin/.generated/registries.d.mts +22 -0
- package/dist/server/{auth-helpers.d.mts → modules/admin/auth-helpers.d.mts} +13 -14
- package/dist/server/{auth-helpers.mjs → modules/admin/auth-helpers.mjs} +15 -16
- package/dist/server/{block → modules/admin/block}/block-builder.d.mts +96 -32
- package/dist/server/{block → modules/admin/block}/block-builder.mjs +113 -15
- package/dist/server/modules/admin/block/index.d.mts +3 -0
- package/dist/server/{block → modules/admin/block}/introspection.d.mts +10 -5
- package/dist/server/{block → modules/admin/block}/introspection.mjs +18 -7
- package/dist/server/{block → modules/admin/block}/prefetch.d.mts +17 -17
- package/dist/server/{block → modules/admin/block}/prefetch.mjs +17 -16
- package/dist/server/modules/admin/client/.generated/module.d.mts +94 -0
- package/dist/server/modules/admin/client/.generated/module.mjs +91 -0
- package/dist/server/modules/admin/client/components/badge.d.mts +1 -0
- package/dist/server/modules/admin/client/components/icon.d.mts +1 -0
- package/dist/server/modules/admin/client/fields/array.d.mts +6 -0
- package/dist/server/modules/admin/client/fields/array.mjs +12 -0
- package/dist/server/modules/admin/client/fields/assetPreview.d.mts +6 -0
- package/dist/server/modules/admin/client/fields/assetPreview.mjs +18 -0
- package/dist/server/modules/admin/client/fields/blocks.d.mts +6 -0
- package/dist/server/modules/admin/client/fields/blocks.mjs +12 -0
- package/dist/server/modules/admin/client/fields/boolean.d.mts +6 -0
- package/dist/server/modules/admin/client/fields/boolean.mjs +12 -0
- package/dist/server/modules/admin/client/fields/date.d.mts +6 -0
- package/dist/server/modules/admin/client/fields/date.mjs +12 -0
- package/dist/server/modules/admin/client/fields/datetime.d.mts +6 -0
- package/dist/server/modules/admin/client/fields/datetime.mjs +12 -0
- package/dist/server/modules/admin/client/fields/email.d.mts +6 -0
- package/dist/server/modules/admin/client/fields/email.mjs +12 -0
- package/dist/server/modules/admin/client/fields/json.d.mts +6 -0
- package/dist/server/modules/admin/client/fields/json.mjs +11 -0
- package/dist/server/modules/admin/client/fields/number.d.mts +6 -0
- package/dist/server/modules/admin/client/fields/number.mjs +12 -0
- package/dist/server/modules/admin/client/fields/object.d.mts +6 -0
- package/dist/server/modules/admin/client/fields/object.mjs +12 -0
- package/dist/server/modules/admin/client/fields/relation.d.mts +6 -0
- package/dist/server/modules/admin/client/fields/relation.mjs +12 -0
- package/dist/server/modules/admin/client/fields/richText.d.mts +6 -0
- package/dist/server/modules/admin/client/fields/richText.mjs +11 -0
- package/dist/server/modules/admin/client/fields/select.d.mts +6 -0
- package/dist/server/modules/admin/client/fields/select.mjs +12 -0
- package/dist/server/modules/admin/client/fields/text.d.mts +6 -0
- package/dist/server/modules/admin/client/fields/text.mjs +12 -0
- package/dist/server/modules/admin/client/fields/textarea.d.mts +6 -0
- package/dist/server/modules/admin/client/fields/textarea.mjs +12 -0
- package/dist/server/modules/admin/client/fields/time.d.mts +6 -0
- package/dist/server/modules/admin/client/fields/time.mjs +12 -0
- package/dist/server/modules/admin/client/fields/upload.d.mts +6 -0
- package/dist/server/modules/admin/client/fields/upload.mjs +12 -0
- package/dist/server/modules/admin/client/fields/url.d.mts +6 -0
- package/dist/server/modules/admin/client/fields/url.mjs +12 -0
- package/dist/server/modules/admin/client/index.d.mts +1 -0
- package/dist/server/modules/admin/client/pages/dashboard.d.mts +6 -0
- package/dist/server/modules/admin/client/pages/dashboard.mjs +11 -0
- package/dist/server/modules/admin/client/pages/forgotPassword.d.mts +6 -0
- package/dist/server/modules/admin/client/pages/forgotPassword.mjs +11 -0
- package/dist/server/modules/admin/client/pages/login.d.mts +6 -0
- package/dist/server/modules/admin/client/pages/login.mjs +11 -0
- package/dist/server/modules/admin/client/pages/resetPassword.d.mts +6 -0
- package/dist/server/modules/admin/client/pages/resetPassword.mjs +11 -0
- package/dist/server/modules/admin/client/pages/setup.d.mts +6 -0
- package/dist/server/modules/admin/client/pages/setup.mjs +11 -0
- package/dist/server/modules/admin/client/views/collection-form.mjs +10 -0
- package/dist/server/modules/admin/client/views/collection-table.mjs +10 -0
- package/dist/server/modules/admin/client/views/global-form.mjs +10 -0
- package/dist/server/modules/admin/client/widgets/chart.d.mts +6 -0
- package/dist/server/modules/admin/client/widgets/chart.mjs +7 -0
- package/dist/server/modules/admin/client/widgets/progress.d.mts +6 -0
- package/dist/server/modules/admin/client/widgets/progress.mjs +7 -0
- package/dist/server/modules/admin/client/widgets/quickActions.d.mts +6 -0
- package/dist/server/modules/admin/client/widgets/quickActions.mjs +7 -0
- package/dist/server/modules/admin/client/widgets/recentItems.d.mts +6 -0
- package/dist/server/modules/admin/client/widgets/recentItems.mjs +7 -0
- package/dist/server/modules/admin/client/widgets/stats.d.mts +6 -0
- package/dist/server/modules/admin/client/widgets/stats.mjs +7 -0
- package/dist/server/modules/admin/client/widgets/table.d.mts +6 -0
- package/dist/server/modules/admin/client/widgets/table.mjs +7 -0
- package/dist/server/modules/admin/client/widgets/timeline.d.mts +6 -0
- package/dist/server/modules/admin/client/widgets/timeline.mjs +7 -0
- package/dist/server/modules/admin/client/widgets/value.d.mts +6 -0
- package/dist/server/modules/admin/client/widgets/value.mjs +7 -0
- package/dist/server/modules/admin/collections/account.d.mts +77 -0
- package/dist/server/modules/admin/collections/account.mjs +23 -0
- package/dist/server/modules/admin/collections/admin-locks.d.mts +90 -0
- package/dist/server/modules/admin/collections/admin-locks.mjs +16 -0
- package/dist/server/modules/admin/collections/admin-preferences.d.mts +69 -0
- package/dist/server/modules/admin/collections/admin-preferences.mjs +16 -0
- package/dist/server/modules/admin/collections/admin-saved-views.d.mts +83 -0
- package/dist/server/modules/admin/collections/admin-saved-views.mjs +16 -0
- package/dist/server/modules/admin/collections/apikey.d.mts +99 -0
- package/dist/server/modules/admin/collections/apikey.mjs +15 -0
- package/dist/server/modules/admin/collections/assets.d.mts +72 -0
- package/dist/server/modules/admin/collections/assets.mjs +71 -0
- package/dist/server/modules/admin/collections/session.d.mts +69 -0
- package/dist/server/modules/admin/collections/session.mjs +15 -0
- package/dist/server/modules/admin/collections/user.d.mts +85 -0
- package/dist/server/modules/admin/collections/user.mjs +204 -0
- package/dist/server/modules/admin/collections/verification.d.mts +63 -0
- package/dist/server/modules/admin/collections/verification.mjs +15 -0
- package/dist/server/modules/admin/components/badge.d.mts +10 -0
- package/dist/server/modules/admin/components/badge.mjs +10 -0
- package/dist/server/modules/admin/components/icon.d.mts +9 -0
- package/dist/server/modules/admin/components/icon.mjs +11 -0
- package/dist/server/modules/admin/config/admin.mjs +34 -0
- package/dist/server/modules/admin/dto/admin-config.dto.mjs +102 -0
- package/dist/server/modules/admin/factories.mjs +172 -0
- package/dist/server/modules/admin/index.d.mts +1060 -16846
- package/dist/server/modules/admin/index.mjs +17 -240
- package/dist/server/modules/admin/modules.mjs +11 -0
- package/dist/server/modules/admin/plugin.mjs +13 -0
- package/dist/server/modules/admin/routes/admin-config.d.mts +28 -0
- package/dist/server/modules/admin/routes/admin-config.mjs +552 -0
- package/dist/server/modules/admin/{functions → routes}/execute-action.d.mts +17 -32
- package/dist/server/modules/admin/{functions → routes}/execute-action.mjs +146 -44
- package/dist/server/modules/admin/routes/locales.d.mts +18 -0
- package/dist/server/modules/admin/routes/locales.mjs +69 -0
- package/dist/server/modules/admin/{functions → routes}/preview.d.mts +25 -15
- package/dist/server/modules/admin/{functions → routes}/preview.mjs +84 -97
- package/dist/server/modules/admin/{functions → routes}/reactive.d.mts +19 -44
- package/dist/server/modules/admin/{functions → routes}/reactive.mjs +89 -117
- package/dist/server/modules/admin/routes/route-helpers.d.mts +23 -0
- package/dist/server/modules/admin/routes/route-helpers.mjs +76 -0
- package/dist/server/modules/admin/{functions → routes}/setup.d.mts +11 -32
- package/dist/server/modules/admin/routes/setup.mjs +114 -0
- package/dist/server/modules/admin/routes/translations.d.mts +26 -0
- package/dist/server/modules/admin/routes/translations.mjs +114 -0
- package/dist/server/modules/admin/routes/widget-data.d.mts +32 -0
- package/dist/server/modules/admin/routes/widget-data.mjs +62 -0
- package/dist/server/modules/admin/views/form.d.mts +8 -0
- package/dist/server/modules/admin/views/form.mjs +7 -0
- package/dist/server/modules/admin/views/global-form.d.mts +8 -0
- package/dist/server/modules/admin/views/global-form.mjs +7 -0
- package/dist/server/modules/admin/views/table.d.mts +8 -0
- package/dist/server/modules/admin/views/table.mjs +7 -0
- package/dist/server/modules/admin-preferences/collections/{admin-preferences.collection.mjs → admin-preferences.mjs} +13 -24
- package/dist/server/modules/admin-preferences/collections/locks.collection.mjs +18 -42
- package/dist/server/modules/admin-preferences/collections/saved-views.d.mts +99 -0
- package/dist/server/modules/admin-preferences/collections/saved-views.mjs +38 -0
- package/dist/server/modules/audit/.generated/module.d.mts +60 -0
- package/dist/server/modules/audit/.generated/module.mjs +30 -0
- package/dist/server/modules/audit/collections/audit-log.d.mts +214 -0
- package/dist/server/modules/audit/collections/audit-log.mjs +107 -0
- package/dist/server/modules/audit/config/admin.mjs +21 -0
- package/dist/server/modules/audit/config/app.mjs +262 -0
- package/dist/server/modules/audit/index.d.mts +2 -0
- package/dist/server/modules/audit/jobs/audit-cleanup.d.mts +13 -0
- package/dist/server/modules/audit/jobs/audit-cleanup.mjs +28 -0
- package/dist/server/plugin.d.mts +26 -0
- package/dist/server/plugin.mjs +385 -0
- package/dist/server/proxy-factories.d.mts +85 -0
- package/dist/server/proxy-factories.mjs +302 -0
- package/dist/server/registry-helpers.d.mts +83 -0
- package/dist/server/registry-helpers.mjs +104 -0
- package/dist/server.d.mts +30 -18
- package/dist/server.mjs +19 -16
- package/dist/shared/preview-utils.d.mts +2 -3
- package/dist/shared/preview-utils.mjs +2 -3
- package/dist/shared/types/saved-views.types.d.mts +2 -2
- package/package.json +50 -40
- package/skills/questpie-admin/SKILL.md +397 -0
- package/skills/questpie-admin/blocks/SKILL.md +305 -0
- package/skills/questpie-admin/custom-ui/SKILL.md +307 -0
- package/skills/questpie-admin/views/SKILL.md +442 -0
- package/dist/_virtual/rolldown_runtime.mjs +0 -18
- package/dist/augmentation.d.mts.map +0 -1
- package/dist/client/blocks/block-registry.d.mts +0 -199
- package/dist/client/blocks/block-registry.d.mts.map +0 -1
- package/dist/client/blocks/block-registry.mjs +0 -88
- package/dist/client/blocks/block-registry.mjs.map +0 -1
- package/dist/client/blocks/block-renderer.d.mts.map +0 -1
- package/dist/client/blocks/block-renderer.mjs.map +0 -1
- package/dist/client/blocks/prefetch.d.mts +0 -45
- package/dist/client/blocks/prefetch.d.mts.map +0 -1
- package/dist/client/blocks/prefetch.mjs +0 -26
- package/dist/client/blocks/prefetch.mjs.map +0 -1
- package/dist/client/blocks/types.d.mts.map +0 -1
- package/dist/client/blocks/types.mjs.map +0 -1
- package/dist/client/builder/admin-builder.d.mts +0 -112
- package/dist/client/builder/admin-builder.d.mts.map +0 -1
- package/dist/client/builder/admin-builder.mjs +0 -185
- package/dist/client/builder/admin-builder.mjs.map +0 -1
- package/dist/client/builder/admin-types.d.mts.map +0 -1
- package/dist/client/builder/admin.d.mts.map +0 -1
- package/dist/client/builder/admin.mjs.map +0 -1
- package/dist/client/builder/defaults/components.mjs +0 -20
- package/dist/client/builder/defaults/components.mjs.map +0 -1
- package/dist/client/builder/defaults/core.d.mts +0 -354
- package/dist/client/builder/defaults/core.d.mts.map +0 -1
- package/dist/client/builder/defaults/core.mjs +0 -49
- package/dist/client/builder/defaults/core.mjs.map +0 -1
- package/dist/client/builder/defaults/fields.mjs +0 -328
- package/dist/client/builder/defaults/fields.mjs.map +0 -1
- package/dist/client/builder/defaults/pages.mjs +0 -58
- package/dist/client/builder/defaults/pages.mjs.map +0 -1
- package/dist/client/builder/defaults/starter.d.mts +0 -351
- package/dist/client/builder/defaults/starter.d.mts.map +0 -1
- package/dist/client/builder/defaults/starter.mjs +0 -28
- package/dist/client/builder/defaults/starter.mjs.map +0 -1
- package/dist/client/builder/defaults/views.mjs +0 -27
- package/dist/client/builder/defaults/views.mjs.map +0 -1
- package/dist/client/builder/defaults/widgets.mjs +0 -31
- package/dist/client/builder/defaults/widgets.mjs.map +0 -1
- package/dist/client/builder/field/field.d.mts.map +0 -1
- package/dist/client/builder/field/field.mjs.map +0 -1
- package/dist/client/builder/index.d.mts.map +0 -1
- package/dist/client/builder/page/page.d.mts.map +0 -1
- package/dist/client/builder/page/page.mjs.map +0 -1
- package/dist/client/builder/proxies.d.mts +0 -2
- package/dist/client/builder/proxies.mjs +0 -24
- package/dist/client/builder/proxies.mjs.map +0 -1
- package/dist/client/builder/qa.d.mts +0 -50
- package/dist/client/builder/qa.d.mts.map +0 -1
- package/dist/client/builder/qa.mjs +0 -42
- package/dist/client/builder/qa.mjs.map +0 -1
- package/dist/client/builder/registry.d.mts.map +0 -1
- package/dist/client/builder/types/action-registry.d.mts +0 -2
- package/dist/client/builder/types/action-registry.mjs.map +0 -1
- package/dist/client/builder/types/action-types.d.mts.map +0 -1
- package/dist/client/builder/types/collection-types.d.mts +0 -199
- package/dist/client/builder/types/collection-types.d.mts.map +0 -1
- package/dist/client/builder/types/collection-types.mjs.map +0 -1
- package/dist/client/builder/types/common.d.mts.map +0 -1
- package/dist/client/builder/types/field-types.d.mts.map +0 -1
- package/dist/client/builder/types/field-types.mjs.map +0 -1
- package/dist/client/builder/types/global-types.d.mts +0 -22
- package/dist/client/builder/types/global-types.d.mts.map +0 -1
- package/dist/client/builder/types/ui-config.d.mts.map +0 -1
- package/dist/client/builder/types/views.d.mts +0 -89
- package/dist/client/builder/types/views.d.mts.map +0 -1
- package/dist/client/builder/types/widget-types.d.mts.map +0 -1
- package/dist/client/builder/validation.mjs.map +0 -1
- package/dist/client/builder/view/view.d.mts.map +0 -1
- package/dist/client/builder/view/view.mjs.map +0 -1
- package/dist/client/builder/widget/widget.d.mts.map +0 -1
- package/dist/client/builder/widget/widget.mjs.map +0 -1
- package/dist/client/components/actions/action-button.d.mts +0 -2
- package/dist/client/components/actions/action-button.mjs.map +0 -1
- package/dist/client/components/actions/action-dialog.d.mts +0 -2
- package/dist/client/components/actions/action-dialog.mjs.map +0 -1
- package/dist/client/components/actions/confirmation-dialog.d.mts +0 -2
- package/dist/client/components/actions/confirmation-dialog.mjs.map +0 -1
- package/dist/client/components/actions/header-actions.d.mts +0 -2
- package/dist/client/components/actions/header-actions.mjs.map +0 -1
- package/dist/client/components/actions/index.d.mts +0 -4
- package/dist/client/components/admin-link.d.mts.map +0 -1
- package/dist/client/components/admin-link.mjs.map +0 -1
- package/dist/client/components/auth/auth-guard.d.mts.map +0 -1
- package/dist/client/components/auth/auth-guard.mjs.map +0 -1
- package/dist/client/components/auth/auth-loading.d.mts.map +0 -1
- package/dist/client/components/auth/auth-loading.mjs.map +0 -1
- package/dist/client/components/auth/index.d.mts +0 -2
- package/dist/client/components/blocks/block-canvas.mjs.map +0 -1
- package/dist/client/components/blocks/block-editor-context.mjs.map +0 -1
- package/dist/client/components/blocks/block-editor-layout.mjs.map +0 -1
- package/dist/client/components/blocks/block-editor-provider.mjs.map +0 -1
- package/dist/client/components/blocks/block-fields-renderer.mjs.map +0 -1
- package/dist/client/components/blocks/block-insert-button.mjs.map +0 -1
- package/dist/client/components/blocks/block-item-menu.mjs.map +0 -1
- package/dist/client/components/blocks/block-item.mjs.map +0 -1
- package/dist/client/components/blocks/block-library-sidebar.mjs.map +0 -1
- package/dist/client/components/blocks/block-tree.mjs.map +0 -1
- package/dist/client/components/blocks/block-type-icon.mjs.map +0 -1
- package/dist/client/components/blocks/utils/tree-utils.mjs.map +0 -1
- package/dist/client/components/component-renderer.d.mts.map +0 -1
- package/dist/client/components/component-renderer.mjs.map +0 -1
- package/dist/client/components/error-boundary.mjs.map +0 -1
- package/dist/client/components/fields/array-field.d.mts +0 -44
- package/dist/client/components/fields/array-field.d.mts.map +0 -1
- package/dist/client/components/fields/array-field.mjs.map +0 -1
- package/dist/client/components/fields/asset-preview-field.d.mts +0 -52
- package/dist/client/components/fields/asset-preview-field.d.mts.map +0 -1
- package/dist/client/components/fields/asset-preview-field.mjs.map +0 -1
- package/dist/client/components/fields/blocks-field/blocks-field.d.mts +0 -41
- package/dist/client/components/fields/blocks-field/blocks-field.d.mts.map +0 -1
- package/dist/client/components/fields/blocks-field/blocks-field.mjs.map +0 -1
- package/dist/client/components/fields/blocks-field/index.d.mts +0 -1
- package/dist/client/components/fields/boolean-field.d.mts +0 -30
- package/dist/client/components/fields/boolean-field.d.mts.map +0 -1
- package/dist/client/components/fields/boolean-field.mjs.map +0 -1
- package/dist/client/components/fields/custom-field.d.mts +0 -3
- package/dist/client/components/fields/date-field.d.mts +0 -22
- package/dist/client/components/fields/date-field.d.mts.map +0 -1
- package/dist/client/components/fields/date-field.mjs.map +0 -1
- package/dist/client/components/fields/datetime-field.d.mts +0 -23
- package/dist/client/components/fields/datetime-field.d.mts.map +0 -1
- package/dist/client/components/fields/datetime-field.mjs.map +0 -1
- package/dist/client/components/fields/email-field.d.mts +0 -19
- package/dist/client/components/fields/email-field.d.mts.map +0 -1
- package/dist/client/components/fields/email-field.mjs.map +0 -1
- package/dist/client/components/fields/embedded-collection.d.mts +0 -3
- package/dist/client/components/fields/field-types.d.mts +0 -571
- package/dist/client/components/fields/field-types.d.mts.map +0 -1
- package/dist/client/components/fields/field-utils.d.mts +0 -1
- package/dist/client/components/fields/field-utils.mjs.map +0 -1
- package/dist/client/components/fields/field-wrapper.d.mts +0 -3
- package/dist/client/components/fields/field-wrapper.mjs.map +0 -1
- package/dist/client/components/fields/index.d.mts +0 -33
- package/dist/client/components/fields/json-field.d.mts +0 -84
- package/dist/client/components/fields/json-field.d.mts.map +0 -1
- package/dist/client/components/fields/json-field.mjs.map +0 -1
- package/dist/client/components/fields/locale-badge.d.mts +0 -1
- package/dist/client/components/fields/locale-badge.mjs.map +0 -1
- package/dist/client/components/fields/number-field.d.mts +0 -23
- package/dist/client/components/fields/number-field.d.mts.map +0 -1
- package/dist/client/components/fields/number-field.mjs.map +0 -1
- package/dist/client/components/fields/object-array-field.d.mts +0 -2
- package/dist/client/components/fields/object-array-field.mjs.map +0 -1
- package/dist/client/components/fields/object-field.d.mts +0 -32
- package/dist/client/components/fields/object-field.d.mts.map +0 -1
- package/dist/client/components/fields/object-field.mjs.map +0 -1
- package/dist/client/components/fields/relation/displays/cards-display.d.mts +0 -2
- package/dist/client/components/fields/relation/displays/cards-display.mjs.map +0 -1
- package/dist/client/components/fields/relation/displays/chips-display.d.mts +0 -2
- package/dist/client/components/fields/relation/displays/chips-display.mjs.map +0 -1
- package/dist/client/components/fields/relation/displays/grid-display.d.mts +0 -2
- package/dist/client/components/fields/relation/displays/grid-display.mjs.map +0 -1
- package/dist/client/components/fields/relation/displays/index.d.mts +0 -6
- package/dist/client/components/fields/relation/displays/list-display.d.mts +0 -2
- package/dist/client/components/fields/relation/displays/list-display.mjs.map +0 -1
- package/dist/client/components/fields/relation/displays/table-display.d.mts +0 -2
- package/dist/client/components/fields/relation/displays/table-display.mjs.map +0 -1
- package/dist/client/components/fields/relation/displays/types.d.mts +0 -22
- package/dist/client/components/fields/relation/displays/types.d.mts.map +0 -1
- package/dist/client/components/fields/relation/displays/types.mjs.map +0 -1
- package/dist/client/components/fields/relation/index.d.mts +0 -3
- package/dist/client/components/fields/relation/relation-items-display.d.mts +0 -5
- package/dist/client/components/fields/relation/relation-items-display.mjs.map +0 -1
- package/dist/client/components/fields/relation-field.d.mts +0 -134
- package/dist/client/components/fields/relation-field.d.mts.map +0 -1
- package/dist/client/components/fields/relation-field.mjs.map +0 -1
- package/dist/client/components/fields/relation-picker.d.mts +0 -4
- package/dist/client/components/fields/relation-picker.mjs.map +0 -1
- package/dist/client/components/fields/relation-select.d.mts +0 -3
- package/dist/client/components/fields/relation-select.mjs.map +0 -1
- package/dist/client/components/fields/reverse-relation-field.d.mts +0 -2
- package/dist/client/components/fields/rich-text-editor/bubble-menu.mjs.map +0 -1
- package/dist/client/components/fields/rich-text-editor/extensions.mjs.map +0 -1
- package/dist/client/components/fields/rich-text-editor/image-popover.mjs.map +0 -1
- package/dist/client/components/fields/rich-text-editor/index.d.mts +0 -4
- package/dist/client/components/fields/rich-text-editor/index.mjs.map +0 -1
- package/dist/client/components/fields/rich-text-editor/link-popover.mjs.map +0 -1
- package/dist/client/components/fields/rich-text-editor/presets.d.mts +0 -11
- package/dist/client/components/fields/rich-text-editor/presets.d.mts.map +0 -1
- package/dist/client/components/fields/rich-text-editor/presets.mjs.map +0 -1
- package/dist/client/components/fields/rich-text-editor/slash-commands.mjs.map +0 -1
- package/dist/client/components/fields/rich-text-editor/table-controls.mjs.map +0 -1
- package/dist/client/components/fields/rich-text-editor/toolbar.mjs.map +0 -1
- package/dist/client/components/fields/rich-text-editor/types.d.mts +0 -78
- package/dist/client/components/fields/rich-text-editor/types.d.mts.map +0 -1
- package/dist/client/components/fields/rich-text-editor/types.mjs.map +0 -1
- package/dist/client/components/fields/rich-text-editor/utils.mjs.map +0 -1
- package/dist/client/components/fields/rich-text-editor/variants.d.mts +0 -2
- package/dist/client/components/fields/rich-text-field.d.mts +0 -14
- package/dist/client/components/fields/rich-text-field.d.mts.map +0 -1
- package/dist/client/components/fields/rich-text-field.mjs.map +0 -1
- package/dist/client/components/fields/select-field.d.mts +0 -25
- package/dist/client/components/fields/select-field.d.mts.map +0 -1
- package/dist/client/components/fields/select-field.mjs.map +0 -1
- package/dist/client/components/fields/status-field.d.mts +0 -2
- package/dist/client/components/fields/text-field.d.mts +0 -22
- package/dist/client/components/fields/text-field.d.mts.map +0 -1
- package/dist/client/components/fields/text-field.mjs.map +0 -1
- package/dist/client/components/fields/textarea-field.d.mts +0 -22
- package/dist/client/components/fields/textarea-field.d.mts.map +0 -1
- package/dist/client/components/fields/textarea-field.mjs.map +0 -1
- package/dist/client/components/fields/time-field.d.mts +0 -20
- package/dist/client/components/fields/time-field.d.mts.map +0 -1
- package/dist/client/components/fields/time-field.mjs.map +0 -1
- package/dist/client/components/fields/upload-field.d.mts +0 -97
- package/dist/client/components/fields/upload-field.d.mts.map +0 -1
- package/dist/client/components/fields/upload-field.mjs.map +0 -1
- package/dist/client/components/filter-builder/columns-tab.d.mts +0 -1
- package/dist/client/components/filter-builder/columns-tab.mjs.map +0 -1
- package/dist/client/components/filter-builder/filter-builder-sheet.d.mts +0 -1
- package/dist/client/components/filter-builder/filter-builder-sheet.mjs.map +0 -1
- package/dist/client/components/filter-builder/filters-tab.d.mts +0 -1
- package/dist/client/components/filter-builder/filters-tab.mjs.map +0 -1
- package/dist/client/components/filter-builder/index.d.mts +0 -5
- package/dist/client/components/filter-builder/saved-views-tab.d.mts +0 -1
- package/dist/client/components/filter-builder/saved-views-tab.mjs.map +0 -1
- package/dist/client/components/index.d.mts +0 -80
- package/dist/client/components/locale-switcher.d.mts +0 -2
- package/dist/client/components/locale-switcher.mjs.map +0 -1
- package/dist/client/components/media/media-grid.mjs.map +0 -1
- package/dist/client/components/media/media-picker-dialog.mjs.map +0 -1
- package/dist/client/components/preview/live-preview-mode.mjs.map +0 -1
- package/dist/client/components/preview/preview-pane.mjs.map +0 -1
- package/dist/client/components/primitives/asset-preview.mjs.map +0 -1
- package/dist/client/components/primitives/checkbox-input.mjs.map +0 -1
- package/dist/client/components/primitives/date-input.mjs.map +0 -1
- package/dist/client/components/primitives/dropzone.mjs.map +0 -1
- package/dist/client/components/primitives/number-input.mjs.map +0 -1
- package/dist/client/components/primitives/select-multi.mjs.map +0 -1
- package/dist/client/components/primitives/select-single.mjs.map +0 -1
- package/dist/client/components/primitives/text-input.mjs.map +0 -1
- package/dist/client/components/primitives/textarea-input.mjs.map +0 -1
- package/dist/client/components/primitives/time-input.mjs.map +0 -1
- package/dist/client/components/primitives/toggle-input.mjs.map +0 -1
- package/dist/client/components/primitives/types.d.mts +0 -14
- package/dist/client/components/primitives/types.d.mts.map +0 -1
- package/dist/client/components/primitives/types.mjs.map +0 -1
- package/dist/client/components/sheets/index.d.mts +0 -1
- package/dist/client/components/sheets/resource-sheet.d.mts +0 -1
- package/dist/client/components/sheets/resource-sheet.mjs.map +0 -1
- package/dist/client/components/ui/accordion.d.mts +0 -2
- package/dist/client/components/ui/accordion.mjs.map +0 -1
- package/dist/client/components/ui/alert.mjs.map +0 -1
- package/dist/client/components/ui/avatar.d.mts +0 -3
- package/dist/client/components/ui/badge.d.mts +0 -3
- package/dist/client/components/ui/badge.mjs.map +0 -1
- package/dist/client/components/ui/button.d.mts +0 -3
- package/dist/client/components/ui/button.mjs.map +0 -1
- package/dist/client/components/ui/card.d.mts +0 -2
- package/dist/client/components/ui/card.mjs.map +0 -1
- package/dist/client/components/ui/checkbox.d.mts +0 -2
- package/dist/client/components/ui/checkbox.mjs.map +0 -1
- package/dist/client/components/ui/combobox.d.mts +0 -3
- package/dist/client/components/ui/command.mjs.map +0 -1
- package/dist/client/components/ui/dialog.d.mts +0 -3
- package/dist/client/components/ui/dialog.mjs.map +0 -1
- package/dist/client/components/ui/drawer.mjs.map +0 -1
- package/dist/client/components/ui/dropdown-menu.d.mts +0 -3
- package/dist/client/components/ui/dropdown-menu.mjs.map +0 -1
- package/dist/client/components/ui/empty-state.mjs.map +0 -1
- package/dist/client/components/ui/field.d.mts +0 -3
- package/dist/client/components/ui/field.mjs.map +0 -1
- package/dist/client/components/ui/input-group.d.mts +0 -4
- package/dist/client/components/ui/input-group.mjs.map +0 -1
- package/dist/client/components/ui/input.d.mts +0 -2
- package/dist/client/components/ui/input.mjs.map +0 -1
- package/dist/client/components/ui/kbd.mjs.map +0 -1
- package/dist/client/components/ui/label.d.mts +0 -2
- package/dist/client/components/ui/label.mjs.map +0 -1
- package/dist/client/components/ui/popover.d.mts +0 -3
- package/dist/client/components/ui/popover.mjs.map +0 -1
- package/dist/client/components/ui/responsive-dialog.mjs.map +0 -1
- package/dist/client/components/ui/scroll-area.d.mts +0 -2
- package/dist/client/components/ui/search-input.mjs.map +0 -1
- package/dist/client/components/ui/select.d.mts +0 -3
- package/dist/client/components/ui/select.mjs.map +0 -1
- package/dist/client/components/ui/separator.d.mts +0 -2
- package/dist/client/components/ui/separator.mjs.map +0 -1
- package/dist/client/components/ui/sheet.d.mts +0 -3
- package/dist/client/components/ui/sheet.mjs.map +0 -1
- package/dist/client/components/ui/sidebar.d.mts +0 -8
- package/dist/client/components/ui/sidebar.mjs.map +0 -1
- package/dist/client/components/ui/skeleton.d.mts +0 -1
- package/dist/client/components/ui/skeleton.mjs.map +0 -1
- package/dist/client/components/ui/sonner.d.mts.map +0 -1
- package/dist/client/components/ui/sonner.mjs.map +0 -1
- package/dist/client/components/ui/spinner.d.mts +0 -1
- package/dist/client/components/ui/spinner.mjs.map +0 -1
- package/dist/client/components/ui/switch.d.mts +0 -2
- package/dist/client/components/ui/switch.mjs.map +0 -1
- package/dist/client/components/ui/table.d.mts +0 -2
- package/dist/client/components/ui/table.mjs.map +0 -1
- package/dist/client/components/ui/tabs.d.mts +0 -3
- package/dist/client/components/ui/tabs.mjs.map +0 -1
- package/dist/client/components/ui/textarea.d.mts +0 -2
- package/dist/client/components/ui/textarea.mjs.map +0 -1
- package/dist/client/components/ui/toolbar.mjs.map +0 -1
- package/dist/client/components/ui/tooltip.d.mts +0 -2
- package/dist/client/components/ui/tooltip.mjs.map +0 -1
- package/dist/client/components/widgets/chart-widget.d.mts +0 -57
- package/dist/client/components/widgets/chart-widget.d.mts.map +0 -1
- package/dist/client/components/widgets/chart-widget.mjs.map +0 -1
- package/dist/client/components/widgets/progress-widget.d.mts +0 -41
- package/dist/client/components/widgets/progress-widget.d.mts.map +0 -1
- package/dist/client/components/widgets/progress-widget.mjs.map +0 -1
- package/dist/client/components/widgets/quick-actions-widget.d.mts +0 -29
- package/dist/client/components/widgets/quick-actions-widget.d.mts.map +0 -1
- package/dist/client/components/widgets/quick-actions-widget.mjs.map +0 -1
- package/dist/client/components/widgets/recent-items-widget.d.mts +0 -51
- package/dist/client/components/widgets/recent-items-widget.d.mts.map +0 -1
- package/dist/client/components/widgets/recent-items-widget.mjs.map +0 -1
- package/dist/client/components/widgets/stats-widget.d.mts +0 -55
- package/dist/client/components/widgets/stats-widget.d.mts.map +0 -1
- package/dist/client/components/widgets/stats-widget.mjs.map +0 -1
- package/dist/client/components/widgets/table-widget.d.mts +0 -31
- package/dist/client/components/widgets/table-widget.d.mts.map +0 -1
- package/dist/client/components/widgets/table-widget.mjs.map +0 -1
- package/dist/client/components/widgets/timeline-widget.d.mts +0 -51
- package/dist/client/components/widgets/timeline-widget.d.mts.map +0 -1
- package/dist/client/components/widgets/timeline-widget.mjs.map +0 -1
- package/dist/client/components/widgets/value-widget.d.mts +0 -39
- package/dist/client/components/widgets/value-widget.d.mts.map +0 -1
- package/dist/client/components/widgets/value-widget.mjs.map +0 -1
- package/dist/client/components/widgets/widget-skeletons.mjs.map +0 -1
- package/dist/client/context/focus-context.d.mts.map +0 -1
- package/dist/client/context/focus-context.mjs.map +0 -1
- package/dist/client/contexts/breadcrumb-context.mjs.map +0 -1
- package/dist/client/hooks/typed-hooks.d.mts.map +0 -1
- package/dist/client/hooks/typed-hooks.mjs.map +0 -1
- package/dist/client/hooks/use-action.mjs.map +0 -1
- package/dist/client/hooks/use-admin-config.mjs.map +0 -1
- package/dist/client/hooks/use-admin-preferences.mjs.map +0 -1
- package/dist/client/hooks/use-admin-routes.mjs.map +0 -1
- package/dist/client/hooks/use-auth.d.mts.map +0 -1
- package/dist/client/hooks/use-auth.mjs.map +0 -1
- package/dist/client/hooks/use-collection-fields.mjs.map +0 -1
- package/dist/client/hooks/use-collection-meta.mjs.map +0 -1
- package/dist/client/hooks/use-collection-schema.mjs.map +0 -1
- package/dist/client/hooks/use-collection-validation.mjs.map +0 -1
- package/dist/client/hooks/use-collection.d.mts.map +0 -1
- package/dist/client/hooks/use-collection.mjs.map +0 -1
- package/dist/client/hooks/use-current-user.d.mts.map +0 -1
- package/dist/client/hooks/use-current-user.mjs.map +0 -1
- package/dist/client/hooks/use-field-hooks.mjs.map +0 -1
- package/dist/client/hooks/use-field-options.d.mts.map +0 -1
- package/dist/client/hooks/use-field-options.mjs.map +0 -1
- package/dist/client/hooks/use-global-fields.mjs.map +0 -1
- package/dist/client/hooks/use-global-meta.mjs.map +0 -1
- package/dist/client/hooks/use-global-schema.mjs.map +0 -1
- package/dist/client/hooks/use-global.d.mts.map +0 -1
- package/dist/client/hooks/use-global.mjs.map +0 -1
- package/dist/client/hooks/use-locks.mjs.map +0 -1
- package/dist/client/hooks/use-media-query.d.mts.map +0 -1
- package/dist/client/hooks/use-media-query.mjs.map +0 -1
- package/dist/client/hooks/use-prefill-params.mjs.map +0 -1
- package/dist/client/hooks/use-questpie-query-options.mjs.map +0 -1
- package/dist/client/hooks/use-reactive-fields.d.mts.map +0 -1
- package/dist/client/hooks/use-reactive-fields.mjs.map +0 -1
- package/dist/client/hooks/use-realtime-highlight.mjs.map +0 -1
- package/dist/client/hooks/use-saved-views.mjs.map +0 -1
- package/dist/client/hooks/use-search.mjs.map +0 -1
- package/dist/client/hooks/use-server-validation.mjs.map +0 -1
- package/dist/client/hooks/use-server-widget-data.d.mts.map +0 -1
- package/dist/client/hooks/use-server-widget-data.mjs.map +0 -1
- package/dist/client/hooks/use-setup-status.d.mts.map +0 -1
- package/dist/client/hooks/use-setup-status.mjs.map +0 -1
- package/dist/client/hooks/use-upload-collection.mjs.map +0 -1
- package/dist/client/hooks/use-upload.d.mts +0 -23
- package/dist/client/hooks/use-upload.d.mts.map +0 -1
- package/dist/client/hooks/use-upload.mjs.map +0 -1
- package/dist/client/hooks/use-validation-error-map.mjs.map +0 -1
- package/dist/client/hooks/use-view-state.mjs.map +0 -1
- package/dist/client/i18n/hooks.mjs.map +0 -1
- package/dist/client/i18n/intl-cache.mjs.map +0 -1
- package/dist/client/i18n/messages.mjs.map +0 -1
- package/dist/client/i18n/simple.d.mts.map +0 -1
- package/dist/client/i18n/simple.mjs.map +0 -1
- package/dist/client/i18n/types.d.mts.map +0 -1
- package/dist/client/lib/utils.d.mts +0 -1
- package/dist/client/lib/utils.mjs.map +0 -1
- package/dist/client/preview/block-scope-context.d.mts.map +0 -1
- package/dist/client/preview/block-scope-context.mjs.map +0 -1
- package/dist/client/preview/preview-banner.d.mts.map +0 -1
- package/dist/client/preview/preview-banner.mjs.map +0 -1
- package/dist/client/preview/preview-field.d.mts.map +0 -1
- package/dist/client/preview/preview-field.mjs.map +0 -1
- package/dist/client/preview/types.d.mts.map +0 -1
- package/dist/client/preview/types.mjs.map +0 -1
- package/dist/client/preview/use-collection-preview.d.mts.map +0 -1
- package/dist/client/preview/use-collection-preview.mjs.map +0 -1
- package/dist/client/runtime/content-locales-provider.mjs.map +0 -1
- package/dist/client/runtime/locale-scope.mjs.map +0 -1
- package/dist/client/runtime/provider.d.mts.map +0 -1
- package/dist/client/runtime/provider.mjs.map +0 -1
- package/dist/client/runtime/routes.d.mts.map +0 -1
- package/dist/client/runtime/routes.mjs.map +0 -1
- package/dist/client/runtime/translations-provider.d.mts +0 -2
- package/dist/client/runtime/translations-provider.mjs.map +0 -1
- package/dist/client/scope/picker.d.mts.map +0 -1
- package/dist/client/scope/picker.mjs.map +0 -1
- package/dist/client/scope/provider.d.mts.map +0 -1
- package/dist/client/scope/provider.mjs.map +0 -1
- package/dist/client/scope/types.d.mts.map +0 -1
- package/dist/client/utils/auto-expand-fields.mjs.map +0 -1
- package/dist/client/utils/build-field-definitions-from-schema.mjs.map +0 -1
- package/dist/client/utils/detect-relations.mjs.map +0 -1
- package/dist/client/utils/locale-to-flag.d.mts.map +0 -1
- package/dist/client/utils/locale-to-flag.mjs.map +0 -1
- package/dist/client/utils/routes.mjs.map +0 -1
- package/dist/client/views/auth/accept-invite-form.d.mts.map +0 -1
- package/dist/client/views/auth/accept-invite-form.mjs.map +0 -1
- package/dist/client/views/auth/auth-layout.d.mts.map +0 -1
- package/dist/client/views/auth/auth-layout.mjs.map +0 -1
- package/dist/client/views/auth/forgot-password-form.d.mts.map +0 -1
- package/dist/client/views/auth/forgot-password-form.mjs.map +0 -1
- package/dist/client/views/auth/index.d.mts +0 -7
- package/dist/client/views/auth/invite-form.d.mts +0 -1
- package/dist/client/views/auth/invite-form.mjs.map +0 -1
- package/dist/client/views/auth/login-form.d.mts.map +0 -1
- package/dist/client/views/auth/login-form.mjs.map +0 -1
- package/dist/client/views/auth/reset-password-form.d.mts.map +0 -1
- package/dist/client/views/auth/reset-password-form.mjs.map +0 -1
- package/dist/client/views/auth/setup-form.d.mts.map +0 -1
- package/dist/client/views/auth/setup-form.mjs.map +0 -1
- package/dist/client/views/collection/auto-form-fields.d.mts +0 -4
- package/dist/client/views/collection/auto-form-fields.mjs.map +0 -1
- package/dist/client/views/collection/bulk-action-toolbar.mjs.map +0 -1
- package/dist/client/views/collection/cells/complex-cells.d.mts +0 -46
- package/dist/client/views/collection/cells/complex-cells.d.mts.map +0 -1
- package/dist/client/views/collection/cells/complex-cells.mjs.map +0 -1
- package/dist/client/views/collection/cells/index.d.mts +0 -7
- package/dist/client/views/collection/cells/primitive-cells.d.mts +0 -76
- package/dist/client/views/collection/cells/primitive-cells.d.mts.map +0 -1
- package/dist/client/views/collection/cells/primitive-cells.mjs.map +0 -1
- package/dist/client/views/collection/cells/relation-cells.d.mts +0 -21
- package/dist/client/views/collection/cells/relation-cells.d.mts.map +0 -1
- package/dist/client/views/collection/cells/relation-cells.mjs.map +0 -1
- package/dist/client/views/collection/cells/shared/asset-thumbnail.d.mts +0 -1
- package/dist/client/views/collection/cells/shared/asset-thumbnail.mjs.map +0 -1
- package/dist/client/views/collection/cells/shared/cell-helpers.d.mts +0 -2
- package/dist/client/views/collection/cells/shared/cell-helpers.mjs.map +0 -1
- package/dist/client/views/collection/cells/shared/relation-chip.d.mts +0 -1
- package/dist/client/views/collection/cells/shared/relation-chip.mjs.map +0 -1
- package/dist/client/views/collection/cells/upload-cells.d.mts +0 -25
- package/dist/client/views/collection/cells/upload-cells.d.mts.map +0 -1
- package/dist/client/views/collection/cells/upload-cells.mjs.map +0 -1
- package/dist/client/views/collection/columns/build-columns.d.mts +0 -2
- package/dist/client/views/collection/columns/build-columns.mjs.map +0 -1
- package/dist/client/views/collection/columns/column-defaults.d.mts +0 -2
- package/dist/client/views/collection/columns/column-defaults.mjs.map +0 -1
- package/dist/client/views/collection/columns/index.d.mts +0 -3
- package/dist/client/views/collection/columns/types.d.mts +0 -2
- package/dist/client/views/collection/field-context.mjs.map +0 -1
- package/dist/client/views/collection/field-renderer.mjs.map +0 -1
- package/dist/client/views/collection/form-view.d.mts +0 -112
- package/dist/client/views/collection/form-view.d.mts.map +0 -1
- package/dist/client/views/collection/form-view.mjs.map +0 -1
- package/dist/client/views/collection/index.d.mts +0 -9
- package/dist/client/views/collection/table-view.d.mts +0 -102
- package/dist/client/views/collection/table-view.d.mts.map +0 -1
- package/dist/client/views/collection/table-view.mjs.map +0 -1
- package/dist/client/views/collection/view-skeletons.mjs.map +0 -1
- package/dist/client/views/common/global-search.d.mts +0 -1
- package/dist/client/views/common/global-search.mjs.map +0 -1
- package/dist/client/views/common/index.d.mts +0 -1
- package/dist/client/views/dashboard/dashboard-grid.mjs.map +0 -1
- package/dist/client/views/dashboard/dashboard-widget.mjs.map +0 -1
- package/dist/client/views/dashboard/widget-card.mjs.map +0 -1
- package/dist/client/views/globals/global-form-view.d.mts +0 -74
- package/dist/client/views/globals/global-form-view.d.mts.map +0 -1
- package/dist/client/views/globals/global-form-view.mjs.map +0 -1
- package/dist/client/views/index.d.mts +0 -28
- package/dist/client/views/layout/admin-layout-provider.d.mts.map +0 -1
- package/dist/client/views/layout/admin-layout-provider.mjs.map +0 -1
- package/dist/client/views/layout/admin-layout.d.mts.map +0 -1
- package/dist/client/views/layout/admin-layout.mjs.map +0 -1
- package/dist/client/views/layout/admin-root.d.mts +0 -7
- package/dist/client/views/layout/admin-router.d.mts.map +0 -1
- package/dist/client/views/layout/admin-router.mjs.map +0 -1
- package/dist/client/views/layout/admin-sidebar.d.mts.map +0 -1
- package/dist/client/views/layout/admin-sidebar.mjs.map +0 -1
- package/dist/client/views/layout/admin-topbar.mjs.map +0 -1
- package/dist/client/views/layout/index.d.mts +0 -5
- package/dist/client/views/pages/accept-invite-page.d.mts.map +0 -1
- package/dist/client/views/pages/accept-invite-page.mjs.map +0 -1
- package/dist/client/views/pages/dashboard-page.d.mts.map +0 -1
- package/dist/client/views/pages/dashboard-page.mjs.map +0 -1
- package/dist/client/views/pages/forgot-password-page.d.mts.map +0 -1
- package/dist/client/views/pages/forgot-password-page.mjs.map +0 -1
- package/dist/client/views/pages/index.d.mts +0 -7
- package/dist/client/views/pages/invite-page.d.mts.map +0 -1
- package/dist/client/views/pages/invite-page.mjs.map +0 -1
- package/dist/client/views/pages/login-page.d.mts.map +0 -1
- package/dist/client/views/pages/login-page.mjs.map +0 -1
- package/dist/client/views/pages/reset-password-page.d.mts.map +0 -1
- package/dist/client/views/pages/reset-password-page.mjs.map +0 -1
- package/dist/client/views/pages/setup-page.d.mts.map +0 -1
- package/dist/client/views/pages/setup-page.mjs.map +0 -1
- package/dist/client.d.mts.map +0 -1
- package/dist/components/rich-text/rich-text-renderer.d.mts.map +0 -1
- package/dist/components/rich-text/rich-text-renderer.mjs.map +0 -1
- package/dist/server/adapters/nextjs.d.mts.map +0 -1
- package/dist/server/adapters/nextjs.mjs.map +0 -1
- package/dist/server/adapters/tanstack.d.mts.map +0 -1
- package/dist/server/adapters/tanstack.mjs.map +0 -1
- package/dist/server/augmentation.d.mts.map +0 -1
- package/dist/server/auth-helpers.d.mts.map +0 -1
- package/dist/server/auth-helpers.mjs.map +0 -1
- package/dist/server/block/block-builder.d.mts.map +0 -1
- package/dist/server/block/block-builder.mjs.map +0 -1
- package/dist/server/block/introspection.d.mts.map +0 -1
- package/dist/server/block/introspection.mjs.map +0 -1
- package/dist/server/block/prefetch.d.mts.map +0 -1
- package/dist/server/block/prefetch.mjs.map +0 -1
- package/dist/server/fields/blocks.d.mts.map +0 -1
- package/dist/server/fields/blocks.mjs.map +0 -1
- package/dist/server/fields/index.d.mts.map +0 -1
- package/dist/server/fields/index.mjs.map +0 -1
- package/dist/server/fields/rich-text.d.mts.map +0 -1
- package/dist/server/fields/rich-text.mjs.map +0 -1
- package/dist/server/i18n/index.d.mts +0 -16
- package/dist/server/i18n/index.d.mts.map +0 -1
- package/dist/server/i18n/index.mjs.map +0 -1
- package/dist/server/i18n/messages/cs.mjs.map +0 -1
- package/dist/server/i18n/messages/de.mjs.map +0 -1
- package/dist/server/i18n/messages/en.mjs.map +0 -1
- package/dist/server/i18n/messages/es.mjs.map +0 -1
- package/dist/server/i18n/messages/fr.mjs.map +0 -1
- package/dist/server/i18n/messages/index.mjs.map +0 -1
- package/dist/server/i18n/messages/pl.mjs.map +0 -1
- package/dist/server/i18n/messages/pt.mjs.map +0 -1
- package/dist/server/i18n/messages/sk.mjs.map +0 -1
- package/dist/server/index.d.mts +0 -20
- package/dist/server/modules/admin/functions/admin-config.mjs +0 -348
- package/dist/server/modules/admin/functions/admin-config.mjs.map +0 -1
- package/dist/server/modules/admin/functions/execute-action.d.mts.map +0 -1
- package/dist/server/modules/admin/functions/execute-action.mjs.map +0 -1
- package/dist/server/modules/admin/functions/locales.mjs +0 -80
- package/dist/server/modules/admin/functions/locales.mjs.map +0 -1
- package/dist/server/modules/admin/functions/preview.d.mts.map +0 -1
- package/dist/server/modules/admin/functions/preview.mjs.map +0 -1
- package/dist/server/modules/admin/functions/reactive.d.mts.map +0 -1
- package/dist/server/modules/admin/functions/reactive.mjs.map +0 -1
- package/dist/server/modules/admin/functions/setup.d.mts.map +0 -1
- package/dist/server/modules/admin/functions/setup.mjs +0 -131
- package/dist/server/modules/admin/functions/setup.mjs.map +0 -1
- package/dist/server/modules/admin/functions/translations.mjs +0 -125
- package/dist/server/modules/admin/functions/translations.mjs.map +0 -1
- package/dist/server/modules/admin/functions/widget-data.d.mts +0 -33
- package/dist/server/modules/admin/functions/widget-data.d.mts.map +0 -1
- package/dist/server/modules/admin/functions/widget-data.mjs +0 -70
- package/dist/server/modules/admin/functions/widget-data.mjs.map +0 -1
- package/dist/server/modules/admin/index.d.mts.map +0 -1
- package/dist/server/modules/admin/index.mjs.map +0 -1
- package/dist/server/modules/admin-preferences/collections/admin-preferences.collection.d.mts +0 -3
- package/dist/server/modules/admin-preferences/collections/admin-preferences.collection.mjs.map +0 -1
- package/dist/server/modules/admin-preferences/collections/locks.collection.d.mts +0 -3
- package/dist/server/modules/admin-preferences/collections/locks.collection.mjs.map +0 -1
- package/dist/server/modules/admin-preferences/collections/saved-views.collection.d.mts +0 -1490
- package/dist/server/modules/admin-preferences/collections/saved-views.collection.d.mts.map +0 -1
- package/dist/server/modules/admin-preferences/collections/saved-views.collection.mjs +0 -57
- package/dist/server/modules/admin-preferences/collections/saved-views.collection.mjs.map +0 -1
- package/dist/server/patch.d.mts +0 -100
- package/dist/server/patch.d.mts.map +0 -1
- package/dist/server/patch.mjs +0 -1062
- package/dist/server/patch.mjs.map +0 -1
- package/dist/shared/preview-utils.d.mts.map +0 -1
- package/dist/shared/preview-utils.mjs.map +0 -1
- package/dist/shared/types/saved-views.types.d.mts.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-reactive-fields.mjs","names":["React","requests: Array<{\n\t\t\tfield: string;\n\t\t\ttype: \"hidden\" | \"readOnly\" | \"disabled\" | \"compute\";\n\t\t\tformData: Record<string, any>;\n\t\t\tsiblingData: Record<string, any> | null;\n\t\t\tprevData: Record<string, any> | null;\n\t\t\tprevSiblingData: Record<string, any> | null;\n\t\t}>","newStates: Record<string, ReactiveFieldState>"],"sources":["../../../src/client/hooks/use-reactive-fields.ts"],"sourcesContent":["/**\n * Reactive Fields Hook\n *\n * Watches form changes and triggers server-side reactive handlers.\n * Supports batched RPC calls with debouncing.\n */\n\nimport type { FieldReactiveSchema } from \"questpie/client\";\nimport * as React from \"react\";\nimport { useFormContext, useWatch } from \"react-hook-form\";\nimport { useAdminStore } from \"../runtime/provider.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Reactive field state\n */\nexport interface ReactiveFieldState {\n\thidden?: boolean;\n\treadOnly?: boolean;\n\tdisabled?: boolean;\n}\n\n/**\n * Reactive field result\n */\nexport interface ReactiveFieldResult {\n\tfield: string;\n\ttype: \"hidden\" | \"readOnly\" | \"disabled\" | \"compute\";\n\tvalue: unknown;\n\terror?: string;\n}\n\n/**\n * Options for useReactiveFields hook\n */\nexport interface UseReactiveFieldsOptions {\n\t/** Collection or global name */\n\tcollection: string;\n\n\t/** Entity type - collection or global */\n\tmode?: \"collection\" | \"global\";\n\n\t/** Map of field paths to their reactive configs */\n\treactiveConfigs: Record<string, FieldReactiveSchema>;\n\n\t/** Debounce delay in ms */\n\tdebounce?: number;\n\n\t/** Whether to enable reactive updates */\n\tenabled?: boolean;\n}\n\n/**\n * Result from useReactiveFields hook\n */\nexport interface UseReactiveFieldsResult {\n\t/** Field states (hidden, readOnly, disabled) by field path */\n\tfieldStates: Record<string, ReactiveFieldState>;\n\n\t/** Whether a reactive update is pending */\n\tisPending: boolean;\n\n\t/** Last error */\n\terror: Error | null;\n\n\t/** Force refresh reactive states */\n\trefresh: () => void;\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Get sibling data for a field path (for fields inside arrays)\n */\nfunction getSiblingData(\n\tvalues: Record<string, any>,\n\tfieldPath: string,\n): Record<string, any> | null {\n\t// Check if field is inside an array (e.g., \"items.0.variant\")\n\tconst parts = fieldPath.split(\".\");\n\tconst numericIndex = parts.findIndex((p) => /^\\d+$/.test(p));\n\n\tif (numericIndex === -1) {\n\t\t// Not in array\n\t\treturn null;\n\t}\n\n\t// Get the array item path (e.g., \"items.0\")\n\tconst arrayItemPath = parts.slice(0, numericIndex + 1).join(\".\");\n\n\t// Navigate to the array item\n\tlet sibling = values;\n\tfor (const part of arrayItemPath.split(\".\")) {\n\t\tif (sibling && typeof sibling === \"object\") {\n\t\t\tsibling = sibling[part];\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\treturn typeof sibling === \"object\" ? sibling : null;\n}\n\n/**\n * Build watch dependencies from reactive configs\n */\nfunction buildWatchDependencies(\n\treactiveConfigs: Record<string, FieldReactiveSchema>,\n): Set<string> {\n\tconst deps = new Set<string>();\n\n\tfor (const config of Object.values(reactiveConfigs)) {\n\t\t// Add deps from hidden, readOnly, disabled, compute\n\t\tfor (const key of [\"hidden\", \"readOnly\", \"disabled\", \"compute\"] as const) {\n\t\t\tconst reactiveConfig = config[key];\n\t\t\tif (reactiveConfig?.watch) {\n\t\t\t\tfor (const dep of reactiveConfig.watch) {\n\t\t\t\t\t// Filter out sibling deps ($sibling.*) for root-level watching\n\t\t\t\t\tif (!dep.startsWith(\"$\")) {\n\t\t\t\t\t\tdeps.add(dep);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn deps;\n}\n\n// ============================================================================\n// Hook Implementation\n// ============================================================================\n\n/**\n * Hook to manage reactive field states.\n * Watches form changes and triggers server-side handlers when dependencies change.\n *\n * @example\n * ```tsx\n * const { fieldStates, isPending } = useReactiveFields({\n * collection: \"posts\",\n * reactiveConfigs: fieldsWithReactive,\n * });\n *\n * // Apply states to fields\n * const isHidden = fieldStates[\"slug\"]?.hidden ?? false;\n * const isReadOnly = fieldStates[\"slug\"]?.readOnly ?? false;\n * ```\n */\nexport function useReactiveFields({\n\tcollection,\n\tmode = \"collection\",\n\treactiveConfigs,\n\tdebounce = 100,\n\tenabled = true,\n}: UseReactiveFieldsOptions): UseReactiveFieldsResult {\n\tconst client = useAdminStore((s) => s.client);\n\tconst form = useFormContext();\n\n\t// State\n\tconst [fieldStates, setFieldStates] = React.useState<\n\t\tRecord<string, ReactiveFieldState>\n\t>({});\n\tconst [isPending, setIsPending] = React.useState(false);\n\tconst [error, setError] = React.useState<Error | null>(null);\n\n\t// Build list of dependencies to watch\n\tconst watchDeps = React.useMemo(\n\t\t() => buildWatchDependencies(reactiveConfigs),\n\t\t[reactiveConfigs],\n\t);\n\n\t// Watch form values\n\tconst watchedValues = useWatch({ control: form.control });\n\tconst formValues = React.useMemo(\n\t\t() => (watchedValues ?? {}) as Record<string, any>,\n\t\t[watchedValues],\n\t);\n\n\t// Previous values ref for change detection\n\tconst prevValuesRef = React.useRef<Record<string, any>>({});\n\n\t// Debounce timer ref\n\tconst debounceTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(\n\t\tnull,\n\t);\n\n\t// Fetch reactive states from server\n\tconst fetchReactiveStates = React.useCallback(async () => {\n\t\tif (!enabled || !client || Object.keys(reactiveConfigs).length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Build batch requests\n\t\tconst requests: Array<{\n\t\t\tfield: string;\n\t\t\ttype: \"hidden\" | \"readOnly\" | \"disabled\" | \"compute\";\n\t\t\tformData: Record<string, any>;\n\t\t\tsiblingData: Record<string, any> | null;\n\t\t\tprevData: Record<string, any> | null;\n\t\t\tprevSiblingData: Record<string, any> | null;\n\t\t}> = [];\n\n\t\tfor (const [fieldPath, config] of Object.entries(reactiveConfigs)) {\n\t\t\tconst siblingData = getSiblingData(formValues, fieldPath);\n\t\t\tconst prevSiblingData = getSiblingData(prevValuesRef.current, fieldPath);\n\n\t\t\t// Add request for each reactive type that has a config\n\t\t\tfor (const type of [\n\t\t\t\t\"hidden\",\n\t\t\t\t\"readOnly\",\n\t\t\t\t\"disabled\",\n\t\t\t\t\"compute\",\n\t\t\t] as const) {\n\t\t\t\tif (config[type]?.watch) {\n\t\t\t\t\trequests.push({\n\t\t\t\t\t\tfield: fieldPath,\n\t\t\t\t\t\ttype,\n\t\t\t\t\t\tformData: formValues,\n\t\t\t\t\t\tsiblingData,\n\t\t\t\t\t\tprevData: prevValuesRef.current,\n\t\t\t\t\t\tprevSiblingData,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (requests.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tsetIsPending(true);\n\t\tsetError(null);\n\n\t\ttry {\n\t\t\tconst response = await (client.rpc as any).batchReactive({\n\t\t\t\tcollection,\n\t\t\t\ttype: mode,\n\t\t\t\trequests,\n\t\t\t});\n\n\t\t\t// Update field states\n\t\t\tconst newStates: Record<string, ReactiveFieldState> = { ...fieldStates };\n\n\t\t\tfor (const result of response.results as ReactiveFieldResult[]) {\n\t\t\t\tif (!newStates[result.field]) {\n\t\t\t\t\tnewStates[result.field] = {};\n\t\t\t\t}\n\n\t\t\t\tif (result.type === \"compute\") {\n\t\t\t\t\t// Apply computed value to form\n\t\t\t\t\tif (result.value !== undefined) {\n\t\t\t\t\t\tform.setValue(result.field, result.value, {\n\t\t\t\t\t\t\tshouldDirty: true,\n\t\t\t\t\t\t\tshouldTouch: false,\n\t\t\t\t\t\t\tshouldValidate: false,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Update field state\n\t\t\t\t\tnewStates[result.field][result.type] = result.value as boolean;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsetFieldStates(newStates);\n\t\t} catch (err) {\n\t\t\tconsole.error(\"Reactive fields error:\", err);\n\t\t\tsetError(err instanceof Error ? err : new Error(String(err)));\n\t\t} finally {\n\t\t\tsetIsPending(false);\n\t\t}\n\t}, [\n\t\tenabled,\n\t\tclient,\n\t\tcollection,\n\t\tmode,\n\t\treactiveConfigs,\n\t\tformValues,\n\t\tfieldStates,\n\t\tform,\n\t]);\n\n\t// Track if we've done initial fetch (to avoid running on empty form data)\n\tconst isInitializedRef = React.useRef(false);\n\n\t// Effect to trigger reactive updates on dep changes\n\t// Also handles initial fetch when form data becomes available (fixes race condition)\n\tReact.useEffect(() => {\n\t\tif (!enabled || watchDeps.size === 0) return;\n\n\t\t// Check if form has actual data (not empty defaults)\n\t\t// This prevents fetching before form data is loaded\n\t\tconst hasFormData = Object.keys(formValues).some(\n\t\t\t(key) => formValues[key] !== undefined && formValues[key] !== null,\n\t\t);\n\t\tif (!hasFormData) return;\n\n\t\t// Initial fetch when data first becomes available\n\t\tif (!isInitializedRef.current) {\n\t\t\tisInitializedRef.current = true;\n\t\t\tprevValuesRef.current = { ...formValues };\n\t\t\tfetchReactiveStates();\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if any watched deps changed\n\t\tlet hasChanges = false;\n\t\tfor (const dep of watchDeps) {\n\t\t\tif (formValues[dep] !== prevValuesRef.current[dep]) {\n\t\t\t\thasChanges = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (!hasChanges) return;\n\n\t\t// Update prev values\n\t\tprevValuesRef.current = { ...formValues };\n\n\t\t// Debounce the fetch\n\t\tif (debounceTimerRef.current) {\n\t\t\tclearTimeout(debounceTimerRef.current);\n\t\t}\n\n\t\tdebounceTimerRef.current = setTimeout(() => {\n\t\t\tfetchReactiveStates();\n\t\t}, debounce);\n\n\t\treturn () => {\n\t\t\tif (debounceTimerRef.current) {\n\t\t\t\tclearTimeout(debounceTimerRef.current);\n\t\t\t}\n\t\t};\n\t}, [enabled, watchDeps, formValues, debounce, fetchReactiveStates]);\n\n\t// Refresh function\n\tconst refresh = React.useCallback(() => {\n\t\tfetchReactiveStates();\n\t}, [fetchReactiveStates]);\n\n\treturn {\n\t\tfieldStates,\n\t\tisPending,\n\t\terror,\n\t\trefresh,\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-realtime-highlight.mjs","names":["changedIds: string[]"],"sources":["../../../src/client/hooks/use-realtime-highlight.ts"],"sourcesContent":["/**\n * Hook to track realtime data changes and highlight affected rows\n *\n * Compares previous data with new data and returns IDs of changed/new items.\n * Used to show visual feedback (pulse animation) when data updates via SSE.\n */\n\nimport { useEffect, useRef, useState } from \"react\";\n\ntype DocWithId = {\n\tid: string;\n\tupdatedAt?: string | Date;\n\t[key: string]: unknown;\n};\n\nexport type UseRealtimeHighlightOptions = {\n\t/** Duration in ms to keep highlight active (default: 1500) */\n\thighlightDuration?: number;\n\t/** Whether realtime is enabled */\n\tenabled?: boolean;\n\t/**\n\t * Duration in ms after initialization to ignore changes (default: 500).\n\t * This prevents false highlights on page refresh when SSE reconnects\n\t * and triggers immediate refetches.\n\t */\n\tinitializationGracePeriod?: number;\n};\n\nexport type UseRealtimeHighlightResult<T extends DocWithId> = {\n\t/** Set of row IDs that should be highlighted (updated/new) */\n\thighlightedIds: Set<string>;\n\t/** Check if a specific row should be highlighted as updated/new */\n\tisHighlighted: (id: string) => boolean;\n};\n\n/**\n * Track realtime changes and return IDs of changed/new rows\n *\n * @example\n * ```tsx\n * const { isHighlighted } = useRealtimeHighlight(data?.docs, { enabled: realtime });\n *\n * {items.map((row) => (\n * <TableRow className={cn(\n * isHighlighted(row.id) && \"animate-realtime-pulse\",\n * )}>\n * ))}\n * ```\n */\nexport function useRealtimeHighlight<T extends DocWithId>(\n\tdocs: T[] | undefined,\n\toptions: UseRealtimeHighlightOptions = {},\n): UseRealtimeHighlightResult<T> {\n\tconst {\n\t\thighlightDuration = 1500,\n\t\tenabled = true,\n\t\tinitializationGracePeriod = 500,\n\t} = options;\n\n\tconst [highlightedIds, setHighlightedIds] = useState<Set<string>>(new Set());\n\n\t// Track previous docs by fingerprint\n\tconst prevDocsRef = useRef<Map<string, string>>(new Map());\n\t// Track if we've seen any data yet (to skip initial highlight)\n\tconst hasInitializedRef = useRef(false);\n\t// Track when initialization happened to implement grace period\n\tconst initializedAtRef = useRef<number>(0);\n\tconst timersRef = useRef<Set<ReturnType<typeof setTimeout>>>(new Set());\n\n\t// Cleanup timers on unmount\n\tuseEffect(() => {\n\t\treturn () => {\n\t\t\tfor (const timer of timersRef.current) {\n\t\t\t\tclearTimeout(timer);\n\t\t\t}\n\t\t};\n\t}, []);\n\n\tuseEffect(() => {\n\t\tif (!enabled || !docs) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Build current fingerprint map\n\t\tconst currentMap = new Map<string, string>();\n\t\tfor (const doc of docs) {\n\t\t\tcurrentMap.set(doc.id, getDocFingerprint(doc));\n\t\t}\n\n\t\t// Skip highlighting on first data load\n\t\tif (!hasInitializedRef.current) {\n\t\t\thasInitializedRef.current = true;\n\t\t\tinitializedAtRef.current = Date.now();\n\t\t\tprevDocsRef.current = currentMap;\n\t\t\treturn;\n\t\t}\n\n\t\t// Skip highlighting during grace period after initialization\n\t\t// This prevents false highlights on page refresh when SSE reconnects\n\t\t// and triggers immediate refetches\n\t\tconst timeSinceInit = Date.now() - initializedAtRef.current;\n\t\tif (timeSinceInit < initializationGracePeriod) {\n\t\t\tprevDocsRef.current = currentMap;\n\t\t\treturn;\n\t\t}\n\n\t\t// Find new and updated docs\n\t\tconst changedIds: string[] = [];\n\t\tfor (const doc of docs) {\n\t\t\tconst prevFingerprint = prevDocsRef.current.get(doc.id);\n\t\t\tconst currentFingerprint = currentMap.get(doc.id)!;\n\n\t\t\tif (!prevFingerprint) {\n\t\t\t\t// New doc\n\t\t\t\tchangedIds.push(doc.id);\n\t\t\t} else if (prevFingerprint !== currentFingerprint) {\n\t\t\t\t// Updated doc\n\t\t\t\tchangedIds.push(doc.id);\n\t\t\t}\n\t\t}\n\n\t\t// Update prev docs map\n\t\tprevDocsRef.current = currentMap;\n\n\t\t// Handle updated/new rows\n\t\tif (changedIds.length > 0) {\n\t\t\tsetHighlightedIds((prev) => {\n\t\t\t\tconst next = new Set(prev);\n\t\t\t\tfor (const id of changedIds) {\n\t\t\t\t\tnext.add(id);\n\t\t\t\t}\n\t\t\t\treturn next;\n\t\t\t});\n\n\t\t\t// Remove highlights after duration\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tsetHighlightedIds((prev) => {\n\t\t\t\t\tconst next = new Set(prev);\n\t\t\t\t\tfor (const id of changedIds) {\n\t\t\t\t\t\tnext.delete(id);\n\t\t\t\t\t}\n\t\t\t\t\treturn next;\n\t\t\t\t});\n\t\t\t\ttimersRef.current.delete(timer);\n\t\t\t}, highlightDuration);\n\t\t\ttimersRef.current.add(timer);\n\t\t}\n\t}, [docs, enabled, highlightDuration, initializationGracePeriod]);\n\n\treturn {\n\t\thighlightedIds,\n\t\tisHighlighted: (id: string) => highlightedIds.has(id),\n\t};\n}\n\n/**\n * Create a fingerprint for a doc to detect changes\n * Uses updatedAt if available, otherwise JSON stringify\n */\nfunction getDocFingerprint(doc: DocWithId): string {\n\tif (doc.updatedAt) {\n\t\treturn `${doc.id}:${String(doc.updatedAt)}`;\n\t}\n\t// Fallback to JSON - less efficient but works\n\treturn JSON.stringify(doc);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAiDA,SAAgB,qBACf,MACA,UAAuC,EAAE,EACT;CAChC,MAAM,EACL,oBAAoB,MACpB,UAAU,MACV,4BAA4B,QACzB;CAEJ,MAAM,CAAC,gBAAgB,qBAAqB,yBAAsB,IAAI,KAAK,CAAC;CAG5E,MAAM,cAAc,uBAA4B,IAAI,KAAK,CAAC;CAE1D,MAAM,oBAAoB,OAAO,MAAM;CAEvC,MAAM,mBAAmB,OAAe,EAAE;CAC1C,MAAM,YAAY,uBAA2C,IAAI,KAAK,CAAC;AAGvE,iBAAgB;AACf,eAAa;AACZ,QAAK,MAAM,SAAS,UAAU,QAC7B,cAAa,MAAM;;IAGnB,EAAE,CAAC;AAEN,iBAAgB;AACf,MAAI,CAAC,WAAW,CAAC,KAChB;EAID,MAAM,6BAAa,IAAI,KAAqB;AAC5C,OAAK,MAAM,OAAO,KACjB,YAAW,IAAI,IAAI,IAAI,kBAAkB,IAAI,CAAC;AAI/C,MAAI,CAAC,kBAAkB,SAAS;AAC/B,qBAAkB,UAAU;AAC5B,oBAAiB,UAAU,KAAK,KAAK;AACrC,eAAY,UAAU;AACtB;;AAOD,MADsB,KAAK,KAAK,GAAG,iBAAiB,UAChC,2BAA2B;AAC9C,eAAY,UAAU;AACtB;;EAID,MAAMA,aAAuB,EAAE;AAC/B,OAAK,MAAM,OAAO,MAAM;GACvB,MAAM,kBAAkB,YAAY,QAAQ,IAAI,IAAI,GAAG;GACvD,MAAM,qBAAqB,WAAW,IAAI,IAAI,GAAG;AAEjD,OAAI,CAAC,gBAEJ,YAAW,KAAK,IAAI,GAAG;YACb,oBAAoB,mBAE9B,YAAW,KAAK,IAAI,GAAG;;AAKzB,cAAY,UAAU;AAGtB,MAAI,WAAW,SAAS,GAAG;AAC1B,sBAAmB,SAAS;IAC3B,MAAM,OAAO,IAAI,IAAI,KAAK;AAC1B,SAAK,MAAM,MAAM,WAChB,MAAK,IAAI,GAAG;AAEb,WAAO;KACN;GAGF,MAAM,QAAQ,iBAAiB;AAC9B,uBAAmB,SAAS;KAC3B,MAAM,OAAO,IAAI,IAAI,KAAK;AAC1B,UAAK,MAAM,MAAM,WAChB,MAAK,OAAO,GAAG;AAEhB,YAAO;MACN;AACF,cAAU,QAAQ,OAAO,MAAM;MAC7B,kBAAkB;AACrB,aAAU,QAAQ,IAAI,MAAM;;IAE3B;EAAC;EAAM;EAAS;EAAmB;EAA0B,CAAC;AAEjE,QAAO;EACN;EACA,gBAAgB,OAAe,eAAe,IAAI,GAAG;EACrD;;;;;;AAOF,SAAS,kBAAkB,KAAwB;AAClD,KAAI,IAAI,UACP,QAAO,GAAG,IAAI,GAAG,GAAG,OAAO,IAAI,UAAU;AAG1C,QAAO,KAAK,UAAU,IAAI"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-saved-views.mjs","names":[],"sources":["../../../src/client/hooks/use-saved-views.ts"],"sourcesContent":["import { useMutation, useQuery, useQueryClient } from \"@tanstack/react-query\";\nimport { useAdminStore } from \"../runtime/provider.js\";\nimport type { SavedView } from \"../components/filter-builder/types.js\";\n\n/**\n * Hook to fetch saved views for a collection\n *\n * Note: This hook requires the adminModule to be used in your CMS setup.\n * If adminSavedViews collection is not available, returns empty array.\n */\nexport function useSavedViews(collectionName: string) {\n const client = useAdminStore((s) => s.client);\n\n return useQuery({\n queryKey: [\"adminSavedViews\", collectionName],\n queryFn: async (): Promise<{ docs: SavedView[] }> => {\n // Check if the collection exists on the client\n const collections = client?.collections as\n | Record<string, any>\n | undefined;\n if (!collections?.adminSavedViews) {\n return { docs: [] };\n }\n\n const result = await collections.adminSavedViews.find({\n where: { collectionName },\n });\n return { docs: (result?.docs ?? []) as SavedView[] };\n },\n enabled: !!client,\n });\n}\n\n/**\n * Hook to save a new view\n */\nexport function useSaveView(collectionName: string) {\n const client = useAdminStore((s) => s.client);\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async (data: {\n name: string;\n configuration: SavedView[\"configuration\"];\n userId?: string;\n }) => {\n const collections = client?.collections as\n | Record<string, any>\n | undefined;\n if (!collections?.adminSavedViews) {\n throw new Error(\n \"adminSavedViews collection not available. Make sure to use adminModule in your CMS setup.\",\n );\n }\n\n return collections.adminSavedViews.create({\n ...data,\n collectionName,\n userId: data.userId || \"anonymous\",\n isDefault: false,\n });\n },\n onSuccess: () => {\n queryClient.invalidateQueries({\n queryKey: [\"adminSavedViews\", collectionName],\n });\n },\n });\n}\n\n/**\n * Hook to update an existing view\n */\nexport function useUpdateSavedView(collectionName: string) {\n const client = useAdminStore((s) => s.client);\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({\n id,\n data,\n }: {\n id: string;\n data: Partial<SavedView>;\n }) => {\n const collections = client?.collections as\n | Record<string, any>\n | undefined;\n if (!collections?.adminSavedViews) {\n throw new Error(\n \"adminSavedViews collection not available. Make sure to use adminModule in your CMS setup.\",\n );\n }\n\n return collections.adminSavedViews.update({ id, data });\n },\n onSuccess: () => {\n queryClient.invalidateQueries({\n queryKey: [\"adminSavedViews\", collectionName],\n });\n },\n });\n}\n\n/**\n * Hook to delete a view\n */\nexport function useDeleteSavedView(collectionName: string) {\n const client = useAdminStore((s) => s.client);\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async (viewId: string) => {\n const collections = client?.collections as\n | Record<string, any>\n | undefined;\n if (!collections?.adminSavedViews) {\n throw new Error(\n \"adminSavedViews collection not available. Make sure to use adminModule in your CMS setup.\",\n );\n }\n\n return collections.adminSavedViews.delete({ id: viewId });\n },\n onSuccess: () => {\n queryClient.invalidateQueries({\n queryKey: [\"adminSavedViews\", collectionName],\n });\n },\n });\n}\n"],"mappings":";;;;;;;;;;AAUA,SAAgB,cAAc,gBAAwB;CACpD,MAAM,SAAS,eAAe,MAAM,EAAE,OAAO;AAE7C,QAAO,SAAS;EACd,UAAU,CAAC,mBAAmB,eAAe;EAC7C,SAAS,YAA4C;GAEnD,MAAM,cAAc,QAAQ;AAG5B,OAAI,CAAC,aAAa,gBAChB,QAAO,EAAE,MAAM,EAAE,EAAE;AAMrB,UAAO,EAAE,OAHM,MAAM,YAAY,gBAAgB,KAAK,EACpD,OAAO,EAAE,gBAAgB,EAC1B,CAAC,GACsB,QAAQ,EAAE,EAAkB;;EAEtD,SAAS,CAAC,CAAC;EACZ,CAAC;;;;;AAMJ,SAAgB,YAAY,gBAAwB;CAClD,MAAM,SAAS,eAAe,MAAM,EAAE,OAAO;CAC7C,MAAM,cAAc,gBAAgB;AAEpC,QAAO,YAAY;EACjB,YAAY,OAAO,SAIb;GACJ,MAAM,cAAc,QAAQ;AAG5B,OAAI,CAAC,aAAa,gBAChB,OAAM,IAAI,MACR,4FACD;AAGH,UAAO,YAAY,gBAAgB,OAAO;IACxC,GAAG;IACH;IACA,QAAQ,KAAK,UAAU;IACvB,WAAW;IACZ,CAAC;;EAEJ,iBAAiB;AACf,eAAY,kBAAkB,EAC5B,UAAU,CAAC,mBAAmB,eAAe,EAC9C,CAAC;;EAEL,CAAC;;;;;AAwCJ,SAAgB,mBAAmB,gBAAwB;CACzD,MAAM,SAAS,eAAe,MAAM,EAAE,OAAO;CAC7C,MAAM,cAAc,gBAAgB;AAEpC,QAAO,YAAY;EACjB,YAAY,OAAO,WAAmB;GACpC,MAAM,cAAc,QAAQ;AAG5B,OAAI,CAAC,aAAa,gBAChB,OAAM,IAAI,MACR,4FACD;AAGH,UAAO,YAAY,gBAAgB,OAAO,EAAE,IAAI,QAAQ,CAAC;;EAE3D,iBAAiB;AACf,eAAY,kBAAkB,EAC5B,UAAU,CAAC,mBAAmB,eAAe,EAC9C,CAAC;;EAEL,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-search.mjs","names":[],"sources":["../../../src/client/hooks/use-search.ts"],"sourcesContent":["/**\n * Search Hook\n *\n * React hook for FTS-powered search using the CMS Search API.\n * Returns full records with search metadata (score, highlights, indexed title).\n */\n\nimport { useQuery, type UseQueryOptions } from \"@tanstack/react-query\";\nimport { useState, useEffect } from \"react\";\nimport { selectClient, useAdminStore, useScopedLocale } from \"../runtime\";\n\n// ============================================================================\n// Debounce Hook\n// ============================================================================\n\n/**\n * Hook to debounce a value\n *\n * @example\n * ```tsx\n * const [searchTerm, setSearchTerm] = useState(\"\");\n * const debouncedSearch = useDebouncedValue(searchTerm, 300);\n * ```\n */\nexport function useDebouncedValue<T>(value: T, delay: number): T {\n const [debouncedValue, setDebouncedValue] = useState<T>(value);\n\n useEffect(() => {\n const timer = setTimeout(() => {\n setDebouncedValue(value);\n }, delay);\n\n return () => {\n clearTimeout(timer);\n };\n }, [value, delay]);\n\n return debouncedValue;\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Facet definition for search queries\n */\nexport interface SearchFacetDefinition {\n field: string;\n limit?: number;\n sortBy?: \"count\" | \"alpha\";\n}\n\n/**\n * Search options for the hook\n */\nexport interface UseSearchOptions {\n /**\n * Collection to search in (required)\n */\n collection: string;\n\n /**\n * Search query string\n */\n query: string;\n\n /**\n * Additional metadata filters\n */\n filters?: Record<string, string | string[]>;\n\n /**\n * Result limit (default: 50)\n */\n limit?: number;\n\n /**\n * Result offset (default: 0)\n */\n offset?: number;\n\n /**\n * Include highlights (default: true)\n */\n highlights?: boolean;\n\n /**\n * Facets to retrieve\n */\n facets?: SearchFacetDefinition[];\n\n /**\n * Whether the query is enabled (default: true if query is non-empty)\n */\n enabled?: boolean;\n}\n\n/**\n * Search metadata attached to each result\n */\nexport interface SearchMeta {\n /** Relevance score from search */\n score: number;\n /** Highlighted snippets with <mark> tags */\n highlights?: {\n title?: string;\n content?: string;\n };\n /** Title as stored in search index */\n indexedTitle: string;\n /** Content preview from search index */\n indexedContent?: string;\n}\n\n/**\n * Populated search result - full record with search metadata\n */\nexport interface PopulatedSearchResult<T = Record<string, any>> {\n /** Full record data (spread at top level) */\n [key: string]: any;\n /** Collection name */\n _collection: string;\n /** Search metadata */\n _search: SearchMeta;\n}\n\n/**\n * Facet value with count\n */\nexport interface SearchFacetValue {\n value: string;\n count: number;\n}\n\n/**\n * Facet result\n */\nexport interface SearchFacetResult {\n field: string;\n values: SearchFacetValue[];\n stats?: {\n min: number;\n max: number;\n };\n}\n\n/**\n * Search response with populated records\n */\nexport interface SearchResponse<T = Record<string, any>> {\n /** Full records with search metadata */\n docs: PopulatedSearchResult<T>[];\n /** Total count (accurate after access filtering) */\n total: number;\n /** Facet results (if requested) */\n facets?: SearchFacetResult[];\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\n/**\n * Hook for FTS-powered collection search\n *\n * Returns full records directly with search metadata attached.\n * No need for a second CRUD fetch - records are populated server-side.\n *\n * @example\n * ```tsx\n * const [searchTerm, setSearchTerm] = useState(\"\");\n * const debouncedSearch = useDebouncedValue(searchTerm, 300);\n *\n * const { data, isLoading } = useSearch({\n * collection: \"posts\",\n * query: debouncedSearch,\n * limit: 50,\n * });\n *\n * // Use docs directly - they're full records!\n * const items = data?.docs ?? [];\n *\n * // Access search metadata\n * items.forEach(item => {\n * console.log(item.title); // Full record field\n * console.log(item._search.score); // Search score\n * console.log(item._search.highlights?.title); // Highlighted title\n * });\n * ```\n */\nexport function useSearch<T = Record<string, any>>(\n options: UseSearchOptions,\n queryOptions?: Omit<\n UseQueryOptions<SearchResponse<T>>,\n \"queryKey\" | \"queryFn\"\n >,\n) {\n const client = useAdminStore(selectClient);\n const { locale: contentLocale } = useScopedLocale();\n\n const {\n collection,\n query,\n filters,\n limit = 50,\n offset = 0,\n highlights = true,\n facets,\n enabled,\n } = options;\n\n // Determine if search should be enabled\n // By default, enabled when query has content (after trimming)\n const isEnabled = enabled ?? query?.trim().length > 0;\n\n return useQuery<SearchResponse<T>>({\n queryKey: [\n \"questpie\",\n \"search\",\n collection,\n query,\n filters,\n limit,\n offset,\n contentLocale,\n ],\n queryFn: async () => {\n // Use the client's search API\n const response = await (client as any).search.search({\n query,\n collections: [collection],\n locale: contentLocale,\n limit,\n offset,\n filters,\n highlights,\n facets,\n });\n return response;\n },\n enabled: isEnabled,\n // Keep previous data while fetching new results for smoother UX\n placeholderData: (prev) => prev,\n // Stale time for search results (30 seconds)\n staleTime: 30 * 1000,\n ...queryOptions,\n });\n}\n\n/**\n * Hook for reindexing a collection\n *\n * @example\n * ```tsx\n * const { reindex } = useReindex();\n * await reindex(\"posts\");\n * ```\n */\nexport function useReindex() {\n const client = useAdminStore(selectClient);\n\n return {\n reindex: async (collection: string) => {\n return (client as any).search.reindex(collection);\n },\n };\n}\n\n// ============================================================================\n// Global Search Hook\n// ============================================================================\n\n/**\n * Search options for global search (across all collections)\n */\nexport interface UseGlobalSearchOptions {\n /**\n * Search query string\n */\n query: string;\n\n /**\n * Result limit (default: 10)\n */\n limit?: number;\n\n /**\n * Include highlights (default: true)\n */\n highlights?: boolean;\n\n /**\n * Whether the query is enabled (default: true if query length >= 2)\n */\n enabled?: boolean;\n}\n\n/**\n * Hook for FTS-powered search across ALL collections\n *\n * Used by the global search (Cmd+K) to find records across the entire CMS.\n *\n * @example\n * ```tsx\n * const [query, setQuery] = useState(\"\");\n * const debouncedQuery = useDebouncedValue(query, 300);\n *\n * const { data, isLoading } = useGlobalSearch({\n * query: debouncedQuery,\n * limit: 10,\n * });\n *\n * // Show results grouped by collection\n * data?.docs.forEach(item => {\n * console.log(`${item._collection}: ${item._search.indexedTitle}`);\n * });\n * ```\n */\nexport function useGlobalSearch<T = Record<string, any>>(\n options: UseGlobalSearchOptions,\n queryOptions?: Omit<\n UseQueryOptions<SearchResponse<T>>,\n \"queryKey\" | \"queryFn\"\n >,\n) {\n const client = useAdminStore(selectClient);\n const { locale: contentLocale } = useScopedLocale();\n\n const { query, limit = 10, highlights = true, enabled } = options;\n\n // Require at least 2 characters by default\n const isEnabled = enabled ?? query?.trim().length >= 2;\n\n return useQuery<SearchResponse<T>>({\n queryKey: [\"questpie\", \"global-search\", query, limit, contentLocale],\n queryFn: async () => {\n // Search across ALL collections (no collections filter)\n const response = await (client as any).search.search({\n query,\n // collections: undefined - search all\n locale: contentLocale,\n limit,\n highlights,\n });\n return response;\n },\n enabled: isEnabled,\n // Keep previous data while fetching for smoother UX\n placeholderData: (prev) => prev,\n // Short stale time for global search\n staleTime: 10 * 1000,\n ...queryOptions,\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,kBAAqB,OAAU,OAAkB;CAC/D,MAAM,CAAC,gBAAgB,qBAAqB,SAAY,MAAM;AAE9D,iBAAgB;EACd,MAAM,QAAQ,iBAAiB;AAC7B,qBAAkB,MAAM;KACvB,MAAM;AAET,eAAa;AACX,gBAAa,MAAM;;IAEpB,CAAC,OAAO,MAAM,CAAC;AAElB,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0JT,SAAgB,UACd,SACA,cAIA;CACA,MAAM,SAAS,cAAc,aAAa;CAC1C,MAAM,EAAE,QAAQ,kBAAkB,iBAAiB;CAEnD,MAAM,EACJ,YACA,OACA,SACA,QAAQ,IACR,SAAS,GACT,aAAa,MACb,QACA,YACE;CAIJ,MAAM,YAAY,WAAW,OAAO,MAAM,CAAC,SAAS;AAEpD,QAAO,SAA4B;EACjC,UAAU;GACR;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACD;EACD,SAAS,YAAY;AAYnB,UAViB,MAAO,OAAe,OAAO,OAAO;IACnD;IACA,aAAa,CAAC,WAAW;IACzB,QAAQ;IACR;IACA;IACA;IACA;IACA;IACD,CAAC;;EAGJ,SAAS;EAET,kBAAkB,SAAS;EAE3B,WAAW,KAAK;EAChB,GAAG;EACJ,CAAC;;;;;;;;;;;;;;;;;;;;;;;AAwEJ,SAAgB,gBACd,SACA,cAIA;CACA,MAAM,SAAS,cAAc,aAAa;CAC1C,MAAM,EAAE,QAAQ,kBAAkB,iBAAiB;CAEnD,MAAM,EAAE,OAAO,QAAQ,IAAI,aAAa,MAAM,YAAY;CAG1D,MAAM,YAAY,WAAW,OAAO,MAAM,CAAC,UAAU;AAErD,QAAO,SAA4B;EACjC,UAAU;GAAC;GAAY;GAAiB;GAAO;GAAO;GAAc;EACpE,SAAS,YAAY;AASnB,UAPiB,MAAO,OAAe,OAAO,OAAO;IACnD;IAEA,QAAQ;IACR;IACA;IACD,CAAC;;EAGJ,SAAS;EAET,kBAAkB,SAAS;EAE3B,WAAW,KAAK;EAChB,GAAG;EACJ,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-server-validation.mjs","names":["props: Record<string, unknown>"],"sources":["../../../src/client/hooks/use-server-validation.ts"],"sourcesContent":["/**\n * useServerValidation Hook\n *\n * Creates a react-hook-form resolver using the server's JSON Schema.\n * Uses AJV for validation, ensuring client-side validation matches server-side exactly.\n *\n * This hook fetches the collection schema from the server and uses the\n * `validation.insert` or `validation.update` JSON Schema for form validation.\n */\n\nimport { ajvResolver } from \"@hookform/resolvers/ajv\";\nimport type { Options as AjvOptions, JSONSchemaType } from \"ajv\";\nimport type { Questpie } from \"questpie\";\nimport { useMemo } from \"react\";\nimport type { FieldValues, Resolver } from \"react-hook-form\";\nimport type {\n\tRegisteredCMS,\n\tRegisteredCollectionNames,\n} from \"../builder/registry\";\nimport { useCollectionSchema } from \"./use-collection-schema\";\nimport { useGlobalSchema } from \"./use-global-schema\";\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Recursively strip `additionalProperties: false` and `$schema` from a JSON Schema.\n *\n * Zod's `z.toJSONSchema()` sets `additionalProperties: false` on every object,\n * which causes AJV to reject form data containing extra fields such as `id`,\n * `createdAt`, `updatedAt`, etc. that are part of the loaded document but not\n * in the validation schema.\n *\n * It also sets `$schema: \"https://json-schema.org/draft/2020-12/schema\"` which\n * is not supported by @hookform/resolvers/ajv out of the box.\n */\nfunction stripAdditionalProperties(schema: unknown): unknown {\n\tif (!schema || typeof schema !== \"object\") return schema;\n\tconst s = { ...(schema as Record<string, unknown>) };\n\tdelete s.additionalProperties;\n\t// Remove $schema as AJV resolver doesn't support draft 2020-12 by default\n\tdelete s.$schema;\n\tif (s.properties && typeof s.properties === \"object\") {\n\t\tconst props: Record<string, unknown> = {};\n\t\tfor (const [k, v] of Object.entries(\n\t\t\ts.properties as Record<string, unknown>,\n\t\t)) {\n\t\t\tprops[k] = stripAdditionalProperties(v);\n\t\t}\n\t\ts.properties = props;\n\t}\n\tif (s.items) {\n\t\ts.items = stripAdditionalProperties(s.items);\n\t}\n\treturn s;\n}\n\n// ============================================================================\n// Type Helpers\n// ============================================================================\n\n/**\n * Resolved collection names (string if not registered)\n */\ntype ResolvedCollectionNames =\n\tRegisteredCMS extends Questpie<any> ? RegisteredCollectionNames : string;\n\n/**\n * Validation mode for the hook\n */\nexport type ValidationMode = \"create\" | \"update\";\n\n/**\n * Options for useServerValidation hook\n */\nexport interface UseServerValidationOptions {\n\t/** Validation mode - determines which JSON Schema to use */\n\tmode?: ValidationMode;\n\t/** Whether to enable validation (defaults to true) */\n\tenabled?: boolean;\n}\n\n/**\n * Result of useServerValidation hook\n */\nexport interface ServerValidationResult<TFieldValues extends FieldValues> {\n\t/** Resolver for react-hook-form, undefined if schema not available */\n\tresolver: Resolver<TFieldValues> | undefined;\n\t/** Whether server validation schema is available */\n\thasServerSchema: boolean;\n\t/** Whether the schema is currently loading */\n\tisLoading: boolean;\n\t/** Any error that occurred while fetching the schema */\n\terror: Error | null;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/**\n * Default AJV options for form validation\n */\nconst DEFAULT_AJV_OPTIONS: AjvOptions = {\n\tallErrors: true,\n\t// Allow additional properties by default (forms may have extra fields)\n\tstrict: false,\n\t// Coerce types for better form compatibility\n\tcoerceTypes: true,\n\t// Use defaults from schema\n\tuseDefaults: true,\n};\n\n// ============================================================================\n// Hook\n// ============================================================================\n\n/**\n * Hook to create a react-hook-form resolver using server's JSON Schema\n *\n * Uses the collection's validation schema from the server for client-side\n * validation, ensuring validation rules are consistent between client and server.\n *\n * @param collection - Collection name\n * @param options - Validation options\n * @returns Server validation result with resolver\n *\n * @example\n * ```tsx\n * function CreatePostForm() {\n * const { resolver, isLoading } = useServerValidation(\"posts\", { mode: \"create\" });\n *\n * const form = useForm({\n * resolver,\n * });\n *\n * if (isLoading) return <Loading />;\n *\n * return <Form {...form}>...</Form>;\n * }\n * ```\n *\n * @example\n * ```tsx\n * // With fallback to client-side validation\n * function PostForm({ isEditing }) {\n * const { resolver: serverResolver, hasServerSchema } = useServerValidation(\n * \"posts\",\n * { mode: isEditing ? \"update\" : \"create\" }\n * );\n * const clientResolver = useCollectionValidation(\"posts\");\n *\n * // Prefer server validation, fall back to client\n * const resolver = hasServerSchema ? serverResolver : clientResolver;\n *\n * const form = useForm({ resolver });\n * }\n * ```\n */\nexport function useServerValidation<\n\tK extends ResolvedCollectionNames,\n\tTFieldValues extends FieldValues = FieldValues,\n>(\n\tcollection: K,\n\toptions: UseServerValidationOptions = {},\n): ServerValidationResult<TFieldValues> {\n\tconst { mode = \"create\", enabled = true } = options;\n\n\tconst {\n\t\tdata: schema,\n\t\tisLoading,\n\t\terror,\n\t} = useCollectionSchema(collection, {\n\t\tenabled,\n\t});\n\n\tconst result = useMemo((): ServerValidationResult<TFieldValues> => {\n\t\t// Get the appropriate JSON Schema based on mode\n\t\tconst rawSchema =\n\t\t\tmode === \"create\"\n\t\t\t\t? schema?.validation?.insert\n\t\t\t\t: schema?.validation?.update;\n\t\tconst jsonSchema = stripAdditionalProperties(rawSchema);\n\n\t\tif (!jsonSchema || typeof jsonSchema !== \"object\") {\n\t\t\treturn {\n\t\t\t\tresolver: undefined,\n\t\t\t\thasServerSchema: false,\n\t\t\t\tisLoading,\n\t\t\t\terror: error ?? null,\n\t\t\t};\n\t\t}\n\n\t\ttry {\n\t\t\t// Create resolver using AJV\n\t\t\tconst resolver = ajvResolver(\n\t\t\t\tjsonSchema as JSONSchemaType<TFieldValues>,\n\t\t\t\t{\n\t\t\t\t\t// Use our pre-configured AJV instance options\n\t\t\t\t\tallErrors: true,\n\t\t\t\t\tstrict: false,\n\t\t\t\t\tcoerceTypes: true,\n\t\t\t\t\tuseDefaults: true,\n\t\t\t\t\t// AJV formats plugin options\n\t\t\t\t\tformats: {},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tmode: \"async\",\n\t\t\t\t},\n\t\t\t);\n\n\t\t\treturn {\n\t\t\t\tresolver,\n\t\t\t\thasServerSchema: true,\n\t\t\t\tisLoading: false,\n\t\t\t\terror: null,\n\t\t\t};\n\t\t} catch (e) {\n\t\t\t// If schema compilation fails, return undefined resolver\n\t\t\tconsole.warn(\n\t\t\t\t`[useServerValidation] Failed to compile JSON Schema for ${collection}:`,\n\t\t\t\te,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tresolver: undefined,\n\t\t\t\thasServerSchema: false,\n\t\t\t\tisLoading: false,\n\t\t\t\terror: e instanceof Error ? e : new Error(String(e)),\n\t\t\t};\n\t\t}\n\t}, [schema, mode, isLoading, error, collection]);\n\n\treturn result;\n}\n\n/**\n * Hook to get a combined resolver that prefers server validation\n *\n * This is a convenience hook that combines server and client validation,\n * preferring server validation when available.\n *\n * @param collection - Collection name\n * @param options - Validation options\n * @param fallbackResolver - Optional client-side resolver to use as fallback\n * @returns Resolver function for react-hook-form\n *\n * @example\n * ```tsx\n * function PostForm({ isEditing }) {\n * const clientResolver = useCollectionValidation(\"posts\");\n * const resolver = usePreferServerValidation(\"posts\", {\n * mode: isEditing ? \"update\" : \"create\"\n * }, clientResolver);\n *\n * const form = useForm({ resolver });\n * }\n * ```\n */\nexport function usePreferServerValidation<\n\tK extends ResolvedCollectionNames,\n\tTFieldValues extends FieldValues = FieldValues,\n>(\n\tcollection: K,\n\toptions: UseServerValidationOptions = {},\n\tfallbackResolver?: Resolver<TFieldValues>,\n): Resolver<TFieldValues> | undefined {\n\tconst { resolver: serverResolver, hasServerSchema } = useServerValidation<\n\t\tK,\n\t\tTFieldValues\n\t>(collection, options);\n\n\treturn hasServerSchema ? serverResolver : fallbackResolver;\n}\n\n// ============================================================================\n// Global Validation Hook\n// ============================================================================\n\n/**\n * Hook to create a react-hook-form resolver for global settings using server's JSON Schema\n *\n * @param globalName - Global name\n * @param options - Validation options (mode is always \"update\" for globals)\n * @returns Server validation result with resolver\n */\nexport function useGlobalServerValidation<\n\tTFieldValues extends FieldValues = FieldValues,\n>(\n\tglobalName: string,\n\toptions: Omit<UseServerValidationOptions, \"mode\"> = {},\n): ServerValidationResult<TFieldValues> {\n\tconst { enabled = true } = options;\n\n\tconst {\n\t\tdata: schema,\n\t\tisLoading,\n\t\terror,\n\t} = useGlobalSchema(globalName, {\n\t\tenabled,\n\t});\n\n\tconst result = useMemo((): ServerValidationResult<TFieldValues> => {\n\t\t// Globals only have update validation\n\t\tconst jsonSchema = stripAdditionalProperties(schema?.validation?.update);\n\n\t\tif (!jsonSchema || typeof jsonSchema !== \"object\") {\n\t\t\treturn {\n\t\t\t\tresolver: undefined,\n\t\t\t\thasServerSchema: false,\n\t\t\t\tisLoading,\n\t\t\t\terror: error ?? null,\n\t\t\t};\n\t\t}\n\n\t\ttry {\n\t\t\tconst resolver = ajvResolver(\n\t\t\t\tjsonSchema as JSONSchemaType<TFieldValues>,\n\t\t\t\t{\n\t\t\t\t\tallErrors: true,\n\t\t\t\t\tstrict: false,\n\t\t\t\t\tcoerceTypes: true,\n\t\t\t\t\tuseDefaults: true,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tmode: \"async\",\n\t\t\t\t},\n\t\t\t);\n\n\t\t\treturn {\n\t\t\t\tresolver,\n\t\t\t\thasServerSchema: true,\n\t\t\t\tisLoading: false,\n\t\t\t\terror: null,\n\t\t\t};\n\t\t} catch (e) {\n\t\t\tconsole.warn(\n\t\t\t\t`[useGlobalServerValidation] Failed to compile JSON Schema for ${globalName}:`,\n\t\t\t\te,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tresolver: undefined,\n\t\t\t\thasServerSchema: false,\n\t\t\t\tisLoading: false,\n\t\t\t\terror: e instanceof Error ? e : new Error(String(e)),\n\t\t\t};\n\t\t}\n\t}, [schema, isLoading, error, globalName]);\n\n\treturn result;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAqCA,SAAS,0BAA0B,QAA0B;AAC5D,KAAI,CAAC,UAAU,OAAO,WAAW,SAAU,QAAO;CAClD,MAAM,IAAI,EAAE,GAAI,QAAoC;AACpD,QAAO,EAAE;AAET,QAAO,EAAE;AACT,KAAI,EAAE,cAAc,OAAO,EAAE,eAAe,UAAU;EACrD,MAAMA,QAAiC,EAAE;AACzC,OAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAC3B,EAAE,WACF,CACA,OAAM,KAAK,0BAA0B,EAAE;AAExC,IAAE,aAAa;;AAEhB,KAAI,EAAE,MACL,GAAE,QAAQ,0BAA0B,EAAE,MAAM;AAE7C,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyGR,SAAgB,oBAIf,YACA,UAAsC,EAAE,EACD;CACvC,MAAM,EAAE,OAAO,UAAU,UAAU,SAAS;CAE5C,MAAM,EACL,MAAM,QACN,WACA,UACG,oBAAoB,YAAY,EACnC,SACA,CAAC;AA0DF,QAxDe,cAAoD;EAMlE,MAAM,aAAa,0BAHlB,SAAS,WACN,QAAQ,YAAY,SACpB,QAAQ,YAAY,OAC+B;AAEvD,MAAI,CAAC,cAAc,OAAO,eAAe,SACxC,QAAO;GACN,UAAU;GACV,iBAAiB;GACjB;GACA,OAAO,SAAS;GAChB;AAGF,MAAI;AAkBH,UAAO;IACN,UAjBgB,YAChB,YACA;KAEC,WAAW;KACX,QAAQ;KACR,aAAa;KACb,aAAa;KAEb,SAAS,EAAE;KACX,EACD,EACC,MAAM,SACN,CACD;IAIA,iBAAiB;IACjB,WAAW;IACX,OAAO;IACP;WACO,GAAG;AAEX,WAAQ,KACP,2DAA2D,WAAW,IACtE,EACA;AACD,UAAO;IACN,UAAU;IACV,iBAAiB;IACjB,WAAW;IACX,OAAO,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,EAAE,CAAC;IACpD;;IAEA;EAAC;EAAQ;EAAM;EAAW;EAAO;EAAW,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;AA4BjD,SAAgB,0BAIf,YACA,UAAsC,EAAE,EACxC,kBACqC;CACrC,MAAM,EAAE,UAAU,gBAAgB,oBAAoB,oBAGpD,YAAY,QAAQ;AAEtB,QAAO,kBAAkB,iBAAiB;;;;;;;;;AAc3C,SAAgB,0BAGf,YACA,UAAoD,EAAE,EACf;CACvC,MAAM,EAAE,UAAU,SAAS;CAE3B,MAAM,EACL,MAAM,QACN,WACA,UACG,gBAAgB,YAAY,EAC/B,SACA,CAAC;AAiDF,QA/Ce,cAAoD;EAElE,MAAM,aAAa,0BAA0B,QAAQ,YAAY,OAAO;AAExE,MAAI,CAAC,cAAc,OAAO,eAAe,SACxC,QAAO;GACN,UAAU;GACV,iBAAiB;GACjB;GACA,OAAO,SAAS;GAChB;AAGF,MAAI;AAcH,UAAO;IACN,UAdgB,YAChB,YACA;KACC,WAAW;KACX,QAAQ;KACR,aAAa;KACb,aAAa;KACb,EACD,EACC,MAAM,SACN,CACD;IAIA,iBAAiB;IACjB,WAAW;IACX,OAAO;IACP;WACO,GAAG;AACX,WAAQ,KACP,iEAAiE,WAAW,IAC5E,EACA;AACD,UAAO;IACN,UAAU;IACV,iBAAiB;IACjB,WAAW;IACX,OAAO,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,EAAE,CAAC;IACpD;;IAEA;EAAC;EAAQ;EAAW;EAAO;EAAW,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-server-widget-data.d.mts","names":[],"sources":["../../../src/client/hooks/use-server-widget-data.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;;;iBAuBgB;;;IAGb,eAAe"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-server-widget-data.mjs","names":[],"sources":["../../../src/client/hooks/use-server-widget-data.ts"],"sourcesContent":["/**\n * Hook for fetching widget data from server via fetchWidgetData RPC.\n * Used when a widget has hasFetchFn=true (server-side fetchFn).\n */\n\nimport { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { selectClient, useAdminStore } from \"../runtime\";\n\n/**\n * Fetches widget data from server via the fetchWidgetData RPC endpoint.\n *\n * @param widgetId - The widget ID to fetch data for\n * @param options - Query options\n * @returns TanStack Query result with the widget data\n *\n * @example\n * ```tsx\n * const { data, isLoading } = useServerWidgetData<{ count: number }>(\n * \"my-widget\",\n * { enabled: config.hasFetchFn }\n * );\n * ```\n */\nexport function useServerWidgetData<T = unknown>(\n widgetId: string,\n options?: { enabled?: boolean; refreshInterval?: number },\n): UseQueryResult<T> {\n const client = useAdminStore(selectClient);\n\n return useQuery<T>({\n queryKey: [\"widget\", \"serverData\", widgetId],\n queryFn: () =>\n (client as any).rpc.fetchWidgetData({ widgetId }) as Promise<T>,\n enabled: options?.enabled ?? true,\n refetchInterval: options?.refreshInterval,\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,oBACd,UACA,SACmB;CACnB,MAAM,SAAS,cAAc,aAAa;AAE1C,QAAO,SAAY;EACjB,UAAU;GAAC;GAAU;GAAc;GAAS;EAC5C,eACG,OAAe,IAAI,gBAAgB,EAAE,UAAU,CAAC;EACnD,SAAS,SAAS,WAAW;EAC7B,iBAAiB,SAAS;EAC3B,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-setup-status.d.mts","names":[],"sources":["../../../src/client/hooks/use-setup-status.ts"],"sourcesContent":[],"mappings":";;;;;;;AAUA;AA0BA;;AAA8B,UA1Bb,WAAA,CA0Ba;EAAA;EAAA,QAAA,EAAA,OAAA;;;;;;;;;;;;;;;;;;;;;;;iBAAd,cAAA,CAAA,GAAc,sBAAA,CAAA,eAAA,aAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-setup-status.mjs","names":[],"sources":["../../../src/client/hooks/use-setup-status.ts"],"sourcesContent":["/**\n * Setup Status Hook\n *\n * Hook to check if the CMS setup is required (no users exist).\n * Useful for redirecting to setup page on first visit.\n */\n\nimport { useQuery } from \"@tanstack/react-query\";\nimport { selectClient, useAdminStore } from \"../runtime/provider\";\n\nexport interface SetupStatus {\n /** Whether setup is required (no users exist) */\n required: boolean;\n}\n\n/**\n * Check if CMS setup is required.\n *\n * Returns `required: true` if no users exist in the system,\n * meaning the setup page should be shown to create the first admin.\n *\n * @example\n * ```tsx\n * function App() {\n * const { data, isLoading } = useSetupStatus();\n *\n * if (isLoading) return <LoadingSpinner />;\n *\n * if (data?.required) {\n * return <Navigate to=\"/admin/setup\" />;\n * }\n *\n * return <AdminPanel />;\n * }\n * ```\n */\nexport function useSetupStatus() {\n const client = useAdminStore(selectClient);\n\n return useQuery<SetupStatus>({\n queryKey: [\"questpie\", \"setup-status\"],\n queryFn: async () => {\n try {\n const result = await (client as any).rpc.isSetupRequired({});\n return { required: result.required };\n } catch {\n // If the function doesn't exist, setup is not required\n return { required: false };\n }\n },\n staleTime: 1000 * 60, // Cache for 1 minute\n retry: false,\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCA,SAAgB,iBAAiB;CAC/B,MAAM,SAAS,cAAc,aAAa;AAE1C,QAAO,SAAsB;EAC3B,UAAU,CAAC,YAAY,eAAe;EACtC,SAAS,YAAY;AACnB,OAAI;AAEF,WAAO,EAAE,WADM,MAAO,OAAe,IAAI,gBAAgB,EAAE,CAAC,EAClC,UAAU;WAC9B;AAEN,WAAO,EAAE,UAAU,OAAO;;;EAG9B,WAAW,MAAO;EAClB,OAAO;EACR,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-upload-collection.mjs","names":[],"sources":["../../../src/client/hooks/use-upload-collection.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport type { AdminConfigResponse } from \"../types/admin-config\";\nimport { useAdminConfig } from \"./use-admin-config\";\n\ntype UploadConfig = AdminConfigResponse[\"uploads\"];\n\nexport type UploadCollectionResolution = {\n\tcollection?: string;\n\tcollections: string[];\n};\n\nfunction normalizeCollectionName(value: unknown): string | undefined {\n\tif (typeof value !== \"string\") return undefined;\n\tconst trimmed = value.trim();\n\treturn trimmed.length > 0 ? trimmed : undefined;\n}\n\nexport function resolveUploadCollection(\n\tpreferred?: string,\n\tuploads?: UploadConfig,\n): string | undefined {\n\tconst preferredCollection = normalizeCollectionName(preferred);\n\tif (preferredCollection) {\n\t\treturn preferredCollection;\n\t}\n\n\tconst defaultCollection = normalizeCollectionName(uploads?.defaultCollection);\n\tif (defaultCollection) {\n\t\treturn defaultCollection;\n\t}\n\n\tif (uploads?.collections?.length === 1) {\n\t\treturn uploads.collections[0];\n\t}\n\n\treturn undefined;\n}\n\nexport function useUploadCollection(\n\tpreferred?: string,\n): UploadCollectionResolution {\n\tconst { data: adminConfig } = useAdminConfig();\n\n\tconst collections = adminConfig?.uploads?.collections ?? [];\n\tconst collectionsKey = collections.join(\"|\");\n\n\treturn useMemo(\n\t\t() => ({\n\t\t\tcollection: resolveUploadCollection(preferred, adminConfig?.uploads),\n\t\t\tcollections,\n\t\t}),\n\t\t[preferred, collectionsKey, adminConfig?.uploads?.defaultCollection],\n\t);\n}\n"],"mappings":";;;;AAWA,SAAS,wBAAwB,OAAoC;AACpE,KAAI,OAAO,UAAU,SAAU,QAAO;CACtC,MAAM,UAAU,MAAM,MAAM;AAC5B,QAAO,QAAQ,SAAS,IAAI,UAAU;;AAGvC,SAAgB,wBACf,WACA,SACqB;CACrB,MAAM,sBAAsB,wBAAwB,UAAU;AAC9D,KAAI,oBACH,QAAO;CAGR,MAAM,oBAAoB,wBAAwB,SAAS,kBAAkB;AAC7E,KAAI,kBACH,QAAO;AAGR,KAAI,SAAS,aAAa,WAAW,EACpC,QAAO,QAAQ,YAAY;;AAM7B,SAAgB,oBACf,WAC6B;CAC7B,MAAM,EAAE,MAAM,gBAAgB,gBAAgB;CAE9C,MAAM,cAAc,aAAa,SAAS,eAAe,EAAE;AAG3D,QAAO,eACC;EACN,YAAY,wBAAwB,WAAW,aAAa,QAAQ;EACpE;EACA,GACD;EAAC;EAPqB,YAAY,KAAK,IAAI;EAOf,aAAa,SAAS;EAAkB,CACpE"}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
//#region src/client/hooks/use-upload.d.ts
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Asset record returned from upload
|
|
5
|
-
*/
|
|
6
|
-
interface Asset {
|
|
7
|
-
id: string;
|
|
8
|
-
key: string;
|
|
9
|
-
filename: string;
|
|
10
|
-
mimeType: string;
|
|
11
|
-
size: number;
|
|
12
|
-
visibility: "public" | "private";
|
|
13
|
-
url?: string;
|
|
14
|
-
width?: number | null;
|
|
15
|
-
height?: number | null;
|
|
16
|
-
alt?: string | null;
|
|
17
|
-
caption?: string | null;
|
|
18
|
-
createdAt?: string;
|
|
19
|
-
updatedAt?: string;
|
|
20
|
-
}
|
|
21
|
-
//#endregion
|
|
22
|
-
export { Asset };
|
|
23
|
-
//# sourceMappingURL=use-upload.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-upload.d.mts","names":[],"sources":["../../../src/client/hooks/use-upload.ts"],"sourcesContent":[],"mappings":";;;;;UA8CiB,KAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-upload.mjs","names":[],"sources":["../../../src/client/hooks/use-upload.ts"],"sourcesContent":["/**\n * useUpload Hook\n *\n * Handles file uploads to the CMS with progress tracking.\n * Uses the QuestpieClient's upload method which uses XMLHttpRequest for progress.\n *\n * @example\n * ```tsx\n * const { upload, uploadMany, isUploading, progress } = useUpload();\n *\n * // Single file upload\n * const asset = await upload(file);\n *\n * // Multiple files upload\n * const assets = await uploadMany(files, {\n * onProgress: (p) => console.log(`${p}%`),\n * });\n * ```\n */\n\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { useCallback, useState } from \"react\";\nimport { selectClient, useAdminStore } from \"../runtime\";\nimport { useUploadCollection } from \"./use-upload-collection\";\n\n/**\n * Upload error with additional context\n */\nexport class UploadError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic readonly status?: number,\n\t\tpublic readonly response?: unknown,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"UploadError\";\n\t}\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Asset record returned from upload\n */\nexport interface Asset {\n\tid: string;\n\tkey: string;\n\tfilename: string;\n\tmimeType: string;\n\tsize: number;\n\tvisibility: \"public\" | \"private\";\n\turl?: string;\n\twidth?: number | null;\n\theight?: number | null;\n\talt?: string | null;\n\tcaption?: string | null;\n\tcreatedAt?: string;\n\tupdatedAt?: string;\n}\n\n/**\n * Options for upload operations\n */\nexport interface UploadOptions {\n\t/**\n\t * Target collection for upload (must have .upload() enabled)\n\t */\n\tto?: string;\n\n\t/**\n\t * Progress callback (0-100)\n\t */\n\tonProgress?: (progress: number) => void;\n\n\t/**\n\t * Abort signal for cancellation\n\t */\n\tsignal?: AbortSignal;\n}\n\n/**\n * Options for uploadMany operation\n */\nexport interface UploadManyOptions extends UploadOptions {\n\t/**\n\t * Progress callback receives overall progress (0-100)\n\t * and optionally individual file progress\n\t */\n\tonProgress?: (progress: number, fileIndex?: number) => void;\n}\n\n/**\n * Return type for useUpload hook\n */\nexport interface UseUploadReturn {\n\t/**\n\t * Upload a single file\n\t */\n\tupload: (file: File, options?: UploadOptions) => Promise<Asset>;\n\n\t/**\n\t * Upload multiple files sequentially\n\t */\n\tuploadMany: (files: File[], options?: UploadManyOptions) => Promise<Asset[]>;\n\n\t/**\n\t * Whether an upload is currently in progress\n\t */\n\tisUploading: boolean;\n\n\t/**\n\t * Current upload progress (0-100)\n\t */\n\tprogress: number;\n\n\t/**\n\t * Current error, if any\n\t */\n\terror: Error | null;\n\n\t/**\n\t * Reset state (clear error, progress)\n\t */\n\treset: () => void;\n}\n\n// ============================================================================\n// Hook Implementation\n// ============================================================================\n\n/**\n * Hook for uploading files to the CMS\n *\n * Uses the QuestpieClient's built-in upload method which provides\n * progress tracking via XMLHttpRequest.\n */\nexport function useUpload(): UseUploadReturn {\n\tconst client = useAdminStore(selectClient);\n\tconst queryClient = useQueryClient();\n\tconst {\n\t\tcollection: defaultUploadCollection,\n\t\tcollections: uploadCollections,\n\t} = useUploadCollection();\n\n\tconst [isUploading, setIsUploading] = useState(false);\n\tconst [progress, setProgress] = useState(0);\n\tconst [error, setError] = useState<Error | null>(null);\n\n\tconst resolveTargetCollection = useCallback(\n\t\t(to?: string): string | undefined => {\n\t\t\tconst explicit = typeof to === \"string\" ? to.trim() : \"\";\n\t\t\tif (explicit.length > 0) {\n\t\t\t\treturn explicit;\n\t\t\t}\n\n\t\t\treturn defaultUploadCollection;\n\t\t},\n\t\t[defaultUploadCollection],\n\t);\n\n\tconst getMissingCollectionMessage = useCallback((): string => {\n\t\tif (uploadCollections.length === 0) {\n\t\t\treturn \"No upload-enabled collection is registered. Configure a collection with .upload() and ensure it is accessible in admin config.\";\n\t\t}\n\n\t\tif (uploadCollections.length > 1) {\n\t\t\treturn `Multiple upload collections are available (${uploadCollections.join(\", \")}). Pass UploadOptions.to to select one.`;\n\t\t}\n\n\t\treturn \"Upload collection is not configured.\";\n\t}, [uploadCollections]);\n\n\t/**\n\t * Upload a single file\n\t */\n\tconst upload = useCallback(\n\t\tasync (file: File, options: UploadOptions = {}): Promise<Asset> => {\n\t\t\tconst { to, onProgress, signal } = options;\n\t\t\tconst targetCollection = resolveTargetCollection(to);\n\n\t\t\tif (!targetCollection) {\n\t\t\t\tconst missingCollectionError = new Error(getMissingCollectionMessage());\n\t\t\t\tsetError(missingCollectionError);\n\t\t\t\tthrow missingCollectionError;\n\t\t\t}\n\n\t\t\tsetIsUploading(true);\n\t\t\tsetProgress(0);\n\t\t\tsetError(null);\n\n\t\t\ttry {\n\t\t\t\t// Get the collection API from client\n\t\t\t\tconst collectionApi = (client.collections as any)[targetCollection];\n\n\t\t\t\tif (!collectionApi?.upload) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Collection \"${targetCollection}\" does not support uploads. Make sure .upload() is enabled on the collection.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconst result = await collectionApi.upload(file, {\n\t\t\t\t\tsignal,\n\t\t\t\t\tonProgress: (p: number) => {\n\t\t\t\t\t\tsetProgress(p);\n\t\t\t\t\t\tonProgress?.(p);\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\t// Invalidate collection queries to refresh lists\n\t\t\t\tqueryClient.invalidateQueries({\n\t\t\t\t\tqueryKey: [\"questpie\", \"collections\", targetCollection],\n\t\t\t\t});\n\n\t\t\t\treturn result as Asset;\n\t\t\t} catch (err) {\n\t\t\t\tconst uploadError =\n\t\t\t\t\terr instanceof Error ? err : new Error(\"Upload failed\");\n\t\t\t\tsetError(uploadError);\n\t\t\t\tthrow uploadError;\n\t\t\t} finally {\n\t\t\t\tsetIsUploading(false);\n\t\t\t}\n\t\t},\n\t\t[client, queryClient, resolveTargetCollection, getMissingCollectionMessage],\n\t);\n\n\t/**\n\t * Upload multiple files sequentially\n\t */\n\tconst uploadMany = useCallback(\n\t\tasync (\n\t\t\tfiles: File[],\n\t\t\toptions: UploadManyOptions = {},\n\t\t): Promise<Asset[]> => {\n\t\t\tconst { to, onProgress, signal } = options;\n\t\t\tconst targetCollection = resolveTargetCollection(to);\n\n\t\t\tif (!targetCollection) {\n\t\t\t\tconst missingCollectionError = new Error(getMissingCollectionMessage());\n\t\t\t\tsetError(missingCollectionError);\n\t\t\t\tthrow missingCollectionError;\n\t\t\t}\n\n\t\t\tif (files.length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tsetIsUploading(true);\n\t\t\tsetProgress(0);\n\t\t\tsetError(null);\n\n\t\t\ttry {\n\t\t\t\t// Get the collection API from client\n\t\t\t\tconst collectionApi = (client.collections as any)[targetCollection];\n\n\t\t\t\tif (!collectionApi?.uploadMany) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Collection \"${targetCollection}\" does not support uploads. Make sure .upload() is enabled on the collection.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconst results = await collectionApi.uploadMany(files, {\n\t\t\t\t\tsignal,\n\t\t\t\t\tonProgress: (p: number, fileIndex?: number) => {\n\t\t\t\t\t\tsetProgress(p);\n\t\t\t\t\t\tonProgress?.(p, fileIndex);\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\t// Invalidate collection queries\n\t\t\t\tqueryClient.invalidateQueries({\n\t\t\t\t\tqueryKey: [\"questpie\", \"collections\", targetCollection],\n\t\t\t\t});\n\n\t\t\t\tsetProgress(100);\n\t\t\t\treturn results as Asset[];\n\t\t\t} catch (err) {\n\t\t\t\tconst uploadError =\n\t\t\t\t\terr instanceof Error ? err : new Error(\"Upload failed\");\n\t\t\t\tsetError(uploadError);\n\t\t\t\tthrow uploadError;\n\t\t\t} finally {\n\t\t\t\tsetIsUploading(false);\n\t\t\t}\n\t\t},\n\t\t[client, queryClient, resolveTargetCollection, getMissingCollectionMessage],\n\t);\n\n\t/**\n\t * Reset hook state\n\t */\n\tconst reset = useCallback(() => {\n\t\tsetIsUploading(false);\n\t\tsetProgress(0);\n\t\tsetError(null);\n\t}, []);\n\n\treturn {\n\t\tupload,\n\t\tuploadMany,\n\t\tisUploading,\n\t\tprogress,\n\t\terror,\n\t\treset,\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-validation-error-map.mjs","names":[],"sources":["../../../src/client/hooks/use-validation-error-map.ts"],"sourcesContent":["/**\n * useValidationErrorMap Hook\n *\n * Creates a Zod error map that uses the admin i18n system\n * for localized validation error messages.\n */\n\nimport { useMemo } from \"react\";\nimport { createZodErrorMap, type ZodErrorMapFn } from \"questpie/shared\";\nimport { useSafeI18n } from \"../i18n/hooks\";\n\n/**\n * Create a Zod error map with i18n support\n *\n * Uses the admin's i18n adapter for translations.\n * Falls back to English messages if no adapter is available.\n *\n * @returns Zod error map function\n *\n * @example\n * ```tsx\n * import { zodResolver } from \"@hookform/resolvers/zod\";\n *\n * function MyForm() {\n * const errorMap = useValidationErrorMap();\n * const schema = useCollectionValidation(\"posts\");\n *\n * const form = useForm({\n * resolver: schema\n * ? zodResolver(schema, { errorMap })\n * : undefined,\n * });\n * }\n * ```\n */\nexport function useValidationErrorMap(): ZodErrorMapFn {\n const i18n = useSafeI18n();\n\n return useMemo(() => {\n // Create translate function that uses admin i18n\n const translate = (\n key: string,\n params?: Record<string, unknown>,\n ): string => {\n if (i18n) {\n return i18n.t(key, params);\n }\n\n // Fallback: return key with interpolated params\n if (!params) return key;\n\n return key.replace(/\\{\\{(\\w+)\\}\\}/g, (_, paramKey) => {\n const value = params[paramKey];\n return value !== undefined ? String(value) : `{{${paramKey}}}`;\n });\n };\n\n return createZodErrorMap(translate);\n }, [i18n]);\n}\n\n/**\n * Create a static error map (for use outside of React components)\n *\n * @param t - Translate function\n * @returns Zod error map function\n */\nexport function createAdminZodErrorMap(\n t: (key: string, params?: Record<string, unknown>) => string,\n): ZodErrorMapFn {\n return createZodErrorMap(t);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA,SAAgB,wBAAuC;CACrD,MAAM,OAAO,aAAa;AAE1B,QAAO,cAAc;EAEnB,MAAM,aACJ,KACA,WACW;AACX,OAAI,KACF,QAAO,KAAK,EAAE,KAAK,OAAO;AAI5B,OAAI,CAAC,OAAQ,QAAO;AAEpB,UAAO,IAAI,QAAQ,mBAAmB,GAAG,aAAa;IACpD,MAAM,QAAQ,OAAO;AACrB,WAAO,UAAU,SAAY,OAAO,MAAM,GAAG,KAAK,SAAS;KAC3D;;AAGJ,SAAO,kBAAkB,UAAU;IAClC,CAAC,KAAK,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-view-state.mjs","names":["EMPTY_CONFIG: ViewConfiguration"],"sources":["../../../src/client/hooks/use-view-state.ts"],"sourcesContent":["import { useQueryClient, useSuspenseQuery } from \"@tanstack/react-query\";\nimport { useCallback, useEffect, useMemo, useRef } from \"react\";\nimport type {\n\tFilterRule,\n\tSortConfig,\n\tViewConfiguration,\n} from \"../components/filter-builder/types.js\";\nimport { useAdminStore } from \"../runtime/provider.js\";\nimport {\n\tgetAdminPreferenceQueryKey,\n\tuseSetAdminPreference,\n} from \"./use-admin-preferences.js\";\n\nconst EMPTY_CONFIG: ViewConfiguration = {\n\tfilters: [],\n\tsortConfig: null,\n\tvisibleColumns: [],\n\trealtime: undefined,\n\tpagination: { page: 1, pageSize: 25 },\n};\n\n/**\n * Get the preference key for a collection's view state\n */\nfunction getPreferenceKey(collectionName: string): string {\n\treturn `viewState:${collectionName}`;\n}\n\n/**\n * Merge stored visible columns with default columns to include new fields\n *\n * When a new field is added to the collection, it should appear in the column picker\n * but not automatically become visible (preserving user's existing preference).\n *\n * The merge logic:\n * 1. Start with stored visible columns (in user's preferred order)\n * 2. New columns that weren't in the previous default set are NOT auto-added to visible\n * (they appear in column picker but hidden by default)\n */\nfunction mergeVisibleColumns(\n\tstoredColumns: string[] | undefined,\n\tdefaultColumns: string[],\n): string[] {\n\t// If no stored columns, use defaults\n\tif (!storedColumns?.length) {\n\t\treturn defaultColumns;\n\t}\n\n\t// Return stored columns as-is\n\t// New columns are available in the column picker but not auto-visible\n\treturn storedColumns;\n}\n\n/**\n * Hook to manage view configuration state with database persistence.\n *\n * Uses Suspense for loading and queryClient for optimistic updates.\n * Must be used within a Suspense boundary.\n *\n * Architecture:\n * - Query data is the single source of truth\n * - Config is derived (useMemo) from query data + defaults\n * - Updates use optimistic mutations via queryClient.setQueryData\n * - Changes are debounced and persisted to DB\n *\n * @param defaultColumns - Default columns to show when no config is set\n * @param initialConfig - Optional initial configuration to start with\n * @param collectionName - Collection name for preference key\n * @param userId - User ID (required - must be available, use inside Suspense after auth)\n *\n * @example\n * ```tsx\n * // Inside Suspense boundary, after user is loaded\n * function TableViewInner({ collection, userId }) {\n * const viewState = useViewState(\n * [\"_title\", \"status\", \"createdAt\"],\n * undefined,\n * collection,\n * userId\n * );\n *\n * // config is guaranteed to be ready\n * const { config, setVisibleColumns, toggleSort } = viewState;\n * }\n * ```\n */\nexport function useViewState(\n\tdefaultColumns: string[],\n\tinitialConfig?: Partial<ViewConfiguration>,\n\tcollectionName?: string,\n\tuserId?: string,\n) {\n\tconst queryClient = useQueryClient();\n\tconst client = useAdminStore((s) => s.client);\n\n\t// Preference key for this collection\n\tconst preferenceKey = collectionName\n\t\t? getPreferenceKey(collectionName)\n\t\t: null;\n\n\t// Query key for cache operations\n\tconst queryKey = getAdminPreferenceQueryKey(userId, preferenceKey ?? \"\");\n\n\t// Fetch stored preference from DB using Suspense\n\t// This will suspend until data is loaded\n\tconst { data: storedConfig } = useSuspenseQuery<ViewConfiguration | null>({\n\t\tqueryKey,\n\t\tqueryFn: async (): Promise<ViewConfiguration | null> => {\n\t\t\tif (!userId || !preferenceKey) return null;\n\n\t\t\tconst result = await client.collections.adminPreferences.findOne({\n\t\t\t\twhere: { userId, key: preferenceKey },\n\t\t\t});\n\n\t\t\treturn (result?.value as unknown as ViewConfiguration) ?? null;\n\t\t},\n\t});\n\n\t// Mutation to save preference\n\tconst { mutate: savePreference } = useSetAdminPreference<ViewConfiguration>(\n\t\tpreferenceKey ?? \"\",\n\t);\n\n\t// DERIVED state from query - no useState needed!\n\t// This is the single source of truth pattern\n\tconst config = useMemo<ViewConfiguration>(() => {\n\t\tif (storedConfig) {\n\t\t\treturn {\n\t\t\t\tfilters: storedConfig.filters ?? [],\n\t\t\t\tsortConfig: storedConfig.sortConfig ?? null,\n\t\t\t\tvisibleColumns: mergeVisibleColumns(\n\t\t\t\t\tstoredConfig.visibleColumns,\n\t\t\t\t\tdefaultColumns,\n\t\t\t\t),\n\t\t\t\trealtime:\n\t\t\t\t\tstoredConfig.realtime !== undefined\n\t\t\t\t\t\t? storedConfig.realtime\n\t\t\t\t\t\t: initialConfig?.realtime,\n\t\t\t\tpagination: storedConfig.pagination ?? { page: 1, pageSize: 25 },\n\t\t\t};\n\t\t}\n\n\t\t// No stored config - use defaults\n\t\treturn {\n\t\t\tfilters: initialConfig?.filters ?? [],\n\t\t\tsortConfig: initialConfig?.sortConfig ?? null,\n\t\t\tvisibleColumns: defaultColumns,\n\t\t\trealtime: initialConfig?.realtime,\n\t\t\tpagination: initialConfig?.pagination ?? { page: 1, pageSize: 25 },\n\t\t};\n\t}, [storedConfig, defaultColumns, initialConfig]);\n\n\t// Debounce ref for save\n\tconst saveTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n\n\t// Cleanup timeout on unmount\n\tuseEffect(() => {\n\t\treturn () => {\n\t\t\tif (saveTimeoutRef.current) {\n\t\t\t\tclearTimeout(saveTimeoutRef.current);\n\t\t\t}\n\t\t};\n\t}, []);\n\n\t// Update config with optimistic update + debounced persist\n\tconst setConfig = useCallback(\n\t\t(\n\t\t\tnewConfig:\n\t\t\t\t| ViewConfiguration\n\t\t\t\t| ((prev: ViewConfiguration) => ViewConfiguration),\n\t\t) => {\n\t\t\tconst next =\n\t\t\t\ttypeof newConfig === \"function\" ? newConfig(config) : newConfig;\n\n\t\t\t// OPTIMISTIC UPDATE - immediately update query cache\n\t\t\t// This makes UI instantly responsive\n\t\t\tif (preferenceKey && userId) {\n\t\t\t\tqueryClient.setQueryData<ViewConfiguration | null>(queryKey, next);\n\t\t\t}\n\n\t\t\t// Debounced persist to DB\n\t\t\tif (saveTimeoutRef.current) {\n\t\t\t\tclearTimeout(saveTimeoutRef.current);\n\t\t\t}\n\n\t\t\tsaveTimeoutRef.current = setTimeout(() => {\n\t\t\t\tif (preferenceKey) {\n\t\t\t\t\tsavePreference(next);\n\t\t\t\t}\n\t\t\t}, 500);\n\t\t},\n\t\t[config, preferenceKey, userId, queryClient, queryKey, savePreference],\n\t);\n\n\t// Add a filter\n\tconst addFilter = useCallback(\n\t\t(filter: FilterRule) => {\n\t\t\tsetConfig((prev) => ({\n\t\t\t\t...prev,\n\t\t\t\tfilters: [...prev.filters, filter],\n\t\t\t}));\n\t\t},\n\t\t[setConfig],\n\t);\n\n\t// Remove a filter by ID\n\tconst removeFilter = useCallback(\n\t\t(filterId: string) => {\n\t\t\tsetConfig((prev) => ({\n\t\t\t\t...prev,\n\t\t\t\tfilters: prev.filters.filter((f) => f.id !== filterId),\n\t\t\t}));\n\t\t},\n\t\t[setConfig],\n\t);\n\n\t// Update a filter by ID\n\tconst updateFilter = useCallback(\n\t\t(filterId: string, updates: Partial<FilterRule>) => {\n\t\t\tsetConfig((prev) => ({\n\t\t\t\t...prev,\n\t\t\t\tfilters: prev.filters.map((f) =>\n\t\t\t\t\tf.id === filterId ? { ...f, ...updates } : f,\n\t\t\t\t),\n\t\t\t}));\n\t\t},\n\t\t[setConfig],\n\t);\n\n\t// Clear all filters\n\tconst clearFilters = useCallback(() => {\n\t\tsetConfig((prev) => ({\n\t\t\t...prev,\n\t\t\tfilters: [],\n\t\t}));\n\t}, [setConfig]);\n\n\t// Set sort configuration\n\tconst setSort = useCallback(\n\t\t(sortConfig: SortConfig | null) => {\n\t\t\tsetConfig((prev) => ({ ...prev, sortConfig }));\n\t\t},\n\t\t[setConfig],\n\t);\n\n\t// Toggle sort on a field\n\tconst toggleSort = useCallback(\n\t\t(field: string) => {\n\t\t\tsetConfig((prev) => {\n\t\t\t\tif (prev.sortConfig?.field === field) {\n\t\t\t\t\tif (prev.sortConfig.direction === \"asc\") {\n\t\t\t\t\t\treturn { ...prev, sortConfig: { field, direction: \"desc\" } };\n\t\t\t\t\t}\n\t\t\t\t\treturn { ...prev, sortConfig: null };\n\t\t\t\t}\n\t\t\t\treturn { ...prev, sortConfig: { field, direction: \"asc\" } };\n\t\t\t});\n\t\t},\n\t\t[setConfig],\n\t);\n\n\t// Set visible columns\n\tconst setVisibleColumns = useCallback(\n\t\t(columns: string[]) => {\n\t\t\tsetConfig((prev) => ({ ...prev, visibleColumns: columns }));\n\t\t},\n\t\t[setConfig],\n\t);\n\n\t// Set page number\n\tconst setPage = useCallback(\n\t\t(page: number) => {\n\t\t\tsetConfig((prev) => ({\n\t\t\t\t...prev,\n\t\t\t\tpagination: { ...prev.pagination!, page },\n\t\t\t}));\n\t\t},\n\t\t[setConfig],\n\t);\n\n\t// Set page size and reset to page 1\n\tconst setPageSize = useCallback(\n\t\t(pageSize: number) => {\n\t\t\tsetConfig((prev) => ({\n\t\t\t\t...prev,\n\t\t\t\tpagination: { page: 1, pageSize },\n\t\t\t}));\n\t\t},\n\t\t[setConfig],\n\t);\n\n\t// Toggle column visibility\n\tconst toggleColumn = useCallback(\n\t\t(column: string) => {\n\t\t\tsetConfig((prev) => {\n\t\t\t\tif (prev.visibleColumns.includes(column)) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...prev,\n\t\t\t\t\t\tvisibleColumns: prev.visibleColumns.filter((c) => c !== column),\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\t...prev,\n\t\t\t\t\tvisibleColumns: [...prev.visibleColumns, column],\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\t\t[setConfig],\n\t);\n\n\t// Load a complete configuration\n\tconst loadConfig = useCallback(\n\t\t(newConfig: ViewConfiguration) => {\n\t\t\tsetConfig(newConfig);\n\t\t},\n\t\t[setConfig],\n\t);\n\n\t// Reset to default configuration\n\tconst resetConfig = useCallback(() => {\n\t\tsetConfig({\n\t\t\t...EMPTY_CONFIG,\n\t\t\tvisibleColumns: defaultColumns,\n\t\t});\n\t}, [setConfig, defaultColumns]);\n\n\t// Check if config has any changes from default\n\tconst hasChanges = useMemo(() => {\n\t\treturn (\n\t\t\tconfig.filters.length > 0 ||\n\t\t\tconfig.sortConfig !== null ||\n\t\t\tconfig.realtime !== initialConfig?.realtime ||\n\t\t\tconfig.pagination?.page !== 1 ||\n\t\t\tconfig.pagination?.pageSize !== 25 ||\n\t\t\tJSON.stringify([...config.visibleColumns].sort()) !==\n\t\t\t\tJSON.stringify([...defaultColumns].sort())\n\t\t);\n\t}, [config, defaultColumns, initialConfig?.realtime]);\n\n\treturn {\n\t\tconfig,\n\t\tsetConfig,\n\t\taddFilter,\n\t\tremoveFilter,\n\t\tupdateFilter,\n\t\tclearFilters,\n\t\tsetSort,\n\t\ttoggleSort,\n\t\tsetVisibleColumns,\n\t\ttoggleColumn,\n\t\tsetPage,\n\t\tsetPageSize,\n\t\tloadConfig,\n\t\tresetConfig,\n\t\thasChanges,\n\t\t// No loading state needed - Suspense handles it\n\t\tisLoading: false,\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.mjs","names":["React"],"sources":["../../../src/client/i18n/hooks.tsx"],"sourcesContent":["/**\n * I18n React Hooks\n *\n * React context and hooks for i18n in the admin UI.\n */\n\nimport { DEFAULT_LOCALE } from \"questpie/shared\";\nimport * as React from \"react\";\nimport { createContext, useCallback, useContext } from \"react\";\nimport type {\n I18nAdapter,\n I18nContext as I18nContextType,\n I18nProviderProps,\n I18nText,\n UseTranslationResult,\n} from \"./types\";\n\n// ============================================================================\n// Context\n// ============================================================================\n\nconst I18nContext = createContext<I18nAdapter | null>(null);\n\n// ============================================================================\n// Provider\n// ============================================================================\n\n/**\n * I18n Provider Component\n *\n * Provides i18n to all child components.\n * The adapter is the source of truth for UI locale.\n *\n * @example\n * ```tsx\n * import { I18nProvider, createSimpleI18n } from \"@questpie/admin/i18n\";\n *\n * const i18n = createSimpleI18n({ ... });\n *\n * <I18nProvider adapter={i18n}>\n * <App />\n * </I18nProvider>\n * ```\n */\nexport function I18nProvider({\n adapter,\n children,\n}: I18nProviderProps): React.ReactElement {\n // Force re-render when locale changes in adapter\n const [, forceUpdate] = React.useReducer((x) => x + 1, 0);\n\n // Subscribe to locale changes from adapter\n React.useEffect(() => {\n return adapter.onLocaleChange(() => {\n forceUpdate();\n });\n }, [adapter]);\n\n // Context value - adapter is source of truth\n // useMemo depends on adapter.locale to create new reference when locale changes\n const contextValue = React.useMemo<I18nAdapter>(\n () => ({\n locale: adapter.locale,\n locales: adapter.locales,\n t: adapter.t.bind(adapter),\n setLocale: adapter.setLocale.bind(adapter),\n onLocaleChange: adapter.onLocaleChange.bind(adapter),\n formatDate: adapter.formatDate.bind(adapter),\n formatNumber: adapter.formatNumber.bind(adapter),\n formatRelative: adapter.formatRelative?.bind(adapter),\n getLocaleName: adapter.getLocaleName.bind(adapter),\n isRTL: adapter.isRTL.bind(adapter),\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [adapter, adapter.locale],\n );\n\n return (\n <I18nContext.Provider value={contextValue}>{children}</I18nContext.Provider>\n );\n}\n\n// ============================================================================\n// Hooks\n// ============================================================================\n\n/**\n * Get the i18n adapter (throws if not in provider)\n */\nexport function useI18n(): I18nAdapter {\n const adapter = useContext(I18nContext);\n if (!adapter) {\n throw new Error(\"useI18n must be used within I18nProvider\");\n }\n return adapter;\n}\n\n/**\n * Get i18n adapter or null (safe version)\n */\nexport function useSafeI18n(): I18nAdapter | null {\n return useContext(I18nContext);\n}\n\n/**\n * Main translation hook\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { t, locale, formatDate } = useTranslation();\n * return <h1>{t(\"dashboard.title\")}</h1>;\n * }\n * ```\n */\nexport function useTranslation(): UseTranslationResult {\n const adapter = useI18n();\n\n return {\n locale: adapter.locale,\n locales: adapter.locales,\n t: adapter.t,\n setLocale: adapter.setLocale,\n formatDate: adapter.formatDate,\n formatNumber: adapter.formatNumber,\n getLocaleName: adapter.getLocaleName,\n isRTL: adapter.isRTL(),\n };\n}\n\n/**\n * Get just the translate function\n */\nexport function useT(): I18nAdapter[\"t\"] {\n return useI18n().t;\n}\n\n/**\n * Get current locale\n */\nexport function useLocale(): string {\n return useI18n().locale;\n}\n\n/**\n * Get locale setter\n */\nexport function useSetLocale(): I18nAdapter[\"setLocale\"] {\n return useI18n().setLocale;\n}\n\n// ============================================================================\n// I18nText Resolver\n// ============================================================================\n\n/**\n * Check if an object is a locale map (has locale codes as keys)\n */\nfunction isLocaleMap(obj: object): obj is Record<string, string> {\n // If it has a \"key\" property, it's a translation key lookup\n if (\"key\" in obj) return false;\n // Check if all values are strings (locale map)\n return Object.values(obj).every((v) => typeof v === \"string\");\n}\n\n/**\n * Resolve locale map to string for given locale\n */\nfunction resolveLocaleMap(\n map: Record<string, string>,\n locale: string,\n fallback: string,\n): string {\n // Try exact locale match\n if (map[locale]) return map[locale];\n // Try language code only (e.g., \"en\" from \"en-US\")\n const lang = locale.split(\"-\")[0];\n if (lang && map[lang]) return map[lang];\n // Try default locale as fallback\n if (map[DEFAULT_LOCALE]) return map[DEFAULT_LOCALE];\n // Return first available value\n const firstValue = Object.values(map)[0];\n return firstValue ?? fallback;\n}\n\n/**\n * Resolve I18nText to string\n *\n * @example\n * ```tsx\n * function Label({ text }: { text: I18nText }) {\n * const resolve = useResolveText();\n * return <span>{resolve(text)}</span>;\n * }\n * ```\n */\nexport function useResolveText(): (\n text: I18nText | ((values: Record<string, any>) => I18nText) | undefined,\n fallback?: string,\n contextValues?: Record<string, any>,\n) => string {\n const adapter = useSafeI18n();\n\n return useCallback(\n (\n text: I18nText | ((values: Record<string, any>) => I18nText) | undefined,\n fallback = \"\",\n contextValues?: Record<string, any>,\n ): string => {\n const resolveValue = (value: I18nText | undefined): string => {\n if (value === undefined || value === null) return fallback;\n\n // Plain string\n if (typeof value === \"string\") return value;\n\n // Function\n if (typeof value === \"function\") {\n if (!adapter && !contextValues) return fallback;\n const i18nCtx = adapter\n ? {\n locale: adapter.locale,\n t: adapter.t,\n formatDate: adapter.formatDate,\n formatNumber: adapter.formatNumber,\n }\n : undefined;\n const ctx = {\n ...(contextValues ?? {}),\n ...(i18nCtx ?? {}),\n } as I18nContextType & Record<string, any>;\n try {\n const result = value(ctx);\n return resolveValue(result as I18nText);\n } catch (error) {\n console.error(\"Failed to resolve dynamic text:\", error);\n return fallback;\n }\n }\n\n // Object with key (translation key lookup)\n if (\n typeof value === \"object\" &&\n \"key\" in value &&\n typeof value.key === \"string\"\n ) {\n const keyObj = value as {\n key: string;\n fallback?: string;\n params?: Record<string, unknown>;\n };\n if (!adapter) return keyObj.fallback ?? fallback;\n const result = adapter.t(keyObj.key, keyObj.params);\n // If t() returns the key (not found), use fallback\n return result === keyObj.key ? (keyObj.fallback ?? result) : result;\n }\n\n // Locale map (inline translations)\n if (typeof value === \"object\" && isLocaleMap(value)) {\n const locale = adapter?.locale ?? DEFAULT_LOCALE;\n return resolveLocaleMap(value, locale, fallback);\n }\n\n return fallback;\n };\n\n return resolveValue(text as I18nText | undefined);\n },\n [adapter],\n );\n}\n\n/**\n * Resolve I18nText synchronously (without adapter)\n * Only works with string and object types, not functions\n *\n * @param locale - Optional locale to use for locale maps (defaults to \"en\")\n */\nexport function resolveTextSync(\n text: I18nText | undefined,\n fallback = \"\",\n locale = DEFAULT_LOCALE,\n): string {\n if (text === undefined || text === null) return fallback;\n if (typeof text === \"string\") return text;\n if (typeof text === \"function\") return fallback;\n if (typeof text === \"object\" && \"key\" in text) {\n return text.fallback ?? fallback;\n }\n // Locale map (inline translations)\n if (typeof text === \"object\" && isLocaleMap(text)) {\n return resolveLocaleMap(text, locale, fallback);\n }\n return fallback;\n}\n\n// ============================================================================\n// Text Component\n// ============================================================================\n\n/**\n * Text component that resolves I18nText to a string\n *\n * Use this when you need to render I18nText in JSX.\n *\n * @example\n * ```tsx\n * <Text text={{ en: \"Hello\", sk: \"Ahoj\" }} />\n * <Text text=\"Static text\" />\n * <Text text={{ key: \"common.save\" }} />\n * ```\n */\nexport function Text({\n text,\n fallback = \"\",\n as: Component = \"span\",\n className,\n}: {\n text: I18nText | undefined;\n fallback?: string;\n as?: React.ElementType;\n className?: string;\n}): React.ReactElement | null {\n const resolve = useResolveText();\n const resolved = resolve(text, fallback);\n if (!resolved) return null;\n return <Component className={className}>{resolved}</Component>;\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"intl-cache.mjs","names":[],"sources":["../../../src/client/i18n/intl-cache.ts"],"sourcesContent":["/**\n * Intl Formatters Cache\n *\n * Caches Intl formatter instances to avoid creating new ones on every call.\n * Intl formatters are expensive to create but cheap to reuse.\n */\n\n// Cache key generator - serializes locale + options\nfunction getCacheKey(locale: string, options?: object): string {\n if (!options || Object.keys(options).length === 0) {\n return locale;\n }\n return `${locale}:${JSON.stringify(options)}`;\n}\n\n// DateTimeFormat cache\nconst dateTimeFormatCache = new Map<string, Intl.DateTimeFormat>();\n\nexport function getDateTimeFormat(\n locale: string,\n options?: Intl.DateTimeFormatOptions,\n): Intl.DateTimeFormat {\n const key = getCacheKey(locale, options);\n let formatter = dateTimeFormatCache.get(key);\n if (!formatter) {\n formatter = new Intl.DateTimeFormat(locale, options);\n dateTimeFormatCache.set(key, formatter);\n }\n return formatter;\n}\n\n// NumberFormat cache\nconst numberFormatCache = new Map<string, Intl.NumberFormat>();\n\nexport function getNumberFormat(\n locale: string,\n options?: Intl.NumberFormatOptions,\n): Intl.NumberFormat {\n const key = getCacheKey(locale, options);\n let formatter = numberFormatCache.get(key);\n if (!formatter) {\n formatter = new Intl.NumberFormat(locale, options);\n numberFormatCache.set(key, formatter);\n }\n return formatter;\n}\n\n// PluralRules cache\nconst pluralRulesCache = new Map<string, Intl.PluralRules>();\n\nexport function getPluralRules(\n locale: string,\n options?: Intl.PluralRulesOptions,\n): Intl.PluralRules {\n const key = getCacheKey(locale, options);\n let rules = pluralRulesCache.get(key);\n if (!rules) {\n rules = new Intl.PluralRules(locale, options);\n pluralRulesCache.set(key, rules);\n }\n return rules;\n}\n\n// RelativeTimeFormat cache\nconst relativeTimeFormatCache = new Map<string, Intl.RelativeTimeFormat>();\n\nexport function getRelativeTimeFormat(\n locale: string,\n options?: Intl.RelativeTimeFormatOptions,\n): Intl.RelativeTimeFormat {\n const key = getCacheKey(locale, options);\n let formatter = relativeTimeFormatCache.get(key);\n if (!formatter) {\n formatter = new Intl.RelativeTimeFormat(locale, options);\n relativeTimeFormatCache.set(key, formatter);\n }\n return formatter;\n}\n\n// DisplayNames cache\nconst displayNamesCache = new Map<string, Intl.DisplayNames>();\n\nexport function getDisplayNames(\n locale: string,\n options: Intl.DisplayNamesOptions,\n): Intl.DisplayNames {\n const key = getCacheKey(locale, options);\n let displayNames = displayNamesCache.get(key);\n if (!displayNames) {\n displayNames = new Intl.DisplayNames([locale], options);\n displayNamesCache.set(key, displayNames);\n }\n return displayNames;\n}\n\n/**\n * Clear all caches - useful for testing or when locale changes significantly\n */\nexport function clearIntlCache(): void {\n dateTimeFormatCache.clear();\n numberFormatCache.clear();\n pluralRulesCache.clear();\n relativeTimeFormatCache.clear();\n displayNamesCache.clear();\n}\n"],"mappings":";;;;;;;AAQA,SAAS,YAAY,QAAgB,SAA0B;AAC7D,KAAI,CAAC,WAAW,OAAO,KAAK,QAAQ,CAAC,WAAW,EAC9C,QAAO;AAET,QAAO,GAAG,OAAO,GAAG,KAAK,UAAU,QAAQ;;AAI7C,MAAM,sCAAsB,IAAI,KAAkC;AAElE,SAAgB,kBACd,QACA,SACqB;CACrB,MAAM,MAAM,YAAY,QAAQ,QAAQ;CACxC,IAAI,YAAY,oBAAoB,IAAI,IAAI;AAC5C,KAAI,CAAC,WAAW;AACd,cAAY,IAAI,KAAK,eAAe,QAAQ,QAAQ;AACpD,sBAAoB,IAAI,KAAK,UAAU;;AAEzC,QAAO;;AAIT,MAAM,oCAAoB,IAAI,KAAgC;AAE9D,SAAgB,gBACd,QACA,SACmB;CACnB,MAAM,MAAM,YAAY,QAAQ,QAAQ;CACxC,IAAI,YAAY,kBAAkB,IAAI,IAAI;AAC1C,KAAI,CAAC,WAAW;AACd,cAAY,IAAI,KAAK,aAAa,QAAQ,QAAQ;AAClD,oBAAkB,IAAI,KAAK,UAAU;;AAEvC,QAAO;;AAIT,MAAM,mCAAmB,IAAI,KAA+B;AAE5D,SAAgB,eACd,QACA,SACkB;CAClB,MAAM,MAAM,YAAY,QAAQ,QAAQ;CACxC,IAAI,QAAQ,iBAAiB,IAAI,IAAI;AACrC,KAAI,CAAC,OAAO;AACV,UAAQ,IAAI,KAAK,YAAY,QAAQ,QAAQ;AAC7C,mBAAiB,IAAI,KAAK,MAAM;;AAElC,QAAO;;AAIT,MAAM,0CAA0B,IAAI,KAAsC;AAE1E,SAAgB,sBACd,QACA,SACyB;CACzB,MAAM,MAAM,YAAY,QAAQ,QAAQ;CACxC,IAAI,YAAY,wBAAwB,IAAI,IAAI;AAChD,KAAI,CAAC,WAAW;AACd,cAAY,IAAI,KAAK,mBAAmB,QAAQ,QAAQ;AACxD,0BAAwB,IAAI,KAAK,UAAU;;AAE7C,QAAO;;AAIT,MAAM,oCAAoB,IAAI,KAAgC;AAE9D,SAAgB,gBACd,QACA,SACmB;CACnB,MAAM,MAAM,YAAY,QAAQ,QAAQ;CACxC,IAAI,eAAe,kBAAkB,IAAI,IAAI;AAC7C,KAAI,CAAC,cAAc;AACjB,iBAAe,IAAI,KAAK,aAAa,CAAC,OAAO,EAAE,QAAQ;AACvD,oBAAkB,IAAI,KAAK,aAAa;;AAE1C,QAAO"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"messages.mjs","names":["adminMessages: SimpleMessages"],"sources":["../../../src/client/i18n/messages.ts"],"sourcesContent":["import type { SimpleMessages } from \"./simple\";\n\n/** @deprecated Bundled messages removed. Use server-fetched translations. */\nexport const adminMessages: SimpleMessages = {};\n"],"mappings":";;AAGA,MAAaA,gBAAgC,EAAE"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"simple.d.mts","names":[],"sources":["../../../src/client/i18n/simple.ts"],"sourcesContent":[],"mappings":";;;;;;;KA6BY,cAAA,GAAiB,wBAAwB;;;;KAKzC,cAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"simple.mjs","names":[],"sources":["../../../src/client/i18n/simple.ts"],"sourcesContent":["/**\n * Simple I18n Implementation\n *\n * A minimal i18n implementation for basic use cases.\n * For full i18n features (pluralization, ICU, etc.), use i18next or react-intl.\n *\n * Features:\n * - Basic key-value translation\n * - Simple interpolation ({{key}})\n * - Uses Intl APIs for formatting\n * - Basic pluralization via Intl.PluralRules\n */\n\nimport {\n getDateTimeFormat,\n getDisplayNames,\n getNumberFormat,\n getPluralRules,\n getRelativeTimeFormat,\n} from \"./intl-cache\";\nimport type { I18nAdapter } from \"./types\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Simple messages format\n */\nexport type SimpleMessages = Record<string, string | PluralMessages>;\n\n/**\n * Plural messages (using Intl.PluralRules categories)\n */\nexport type PluralMessages = {\n zero?: string;\n one: string;\n two?: string;\n few?: string;\n many?: string;\n other: string;\n};\n\n/**\n * Options for createSimpleI18n\n */\nexport interface SimpleI18nOptions {\n /** Initial locale */\n locale: string;\n\n /** Available locales */\n locales: string[];\n\n /** Messages per locale */\n messages: Record<string, SimpleMessages>;\n\n /** Fallback locale (defaults to first in locales) */\n fallbackLocale?: string;\n\n /** Callback when locale changes */\n onLocaleChange?: (locale: string) => void;\n}\n\n// ============================================================================\n// RTL Detection\n// ============================================================================\n\nconst RTL_LOCALES = new Set([\"ar\", \"he\", \"fa\", \"ur\", \"ps\", \"sd\", \"yi\"]);\n\n// ============================================================================\n// Implementation\n// ============================================================================\n\n/**\n * Create a simple i18n adapter\n *\n * @example\n * ```ts\n * const i18n = createSimpleI18n({\n * locale: \"en\",\n * locales: [\"en\", \"de\"],\n * messages: {\n * en: {\n * \"common.save\": \"Save\",\n * \"items.count\": { one: \"{{count}} item\", other: \"{{count}} items\" }\n * },\n * de: {\n * \"common.save\": \"Speichern\",\n * \"items.count\": { one: \"{{count}} Artikel\", other: \"{{count}} Artikel\" }\n * }\n * }\n * });\n * ```\n */\nexport function createSimpleI18n(options: SimpleI18nOptions): I18nAdapter {\n let currentLocale = options.locale;\n const {\n locales,\n messages,\n fallbackLocale = locales[0],\n onLocaleChange: onLocaleChangeCallback,\n } = options;\n\n // Event listeners for locale changes\n const listeners = new Set<(locale: string) => void>();\n\n /**\n * Notify all listeners about locale change\n */\n function notifyListeners(locale: string): void {\n // Call the initial callback if provided\n onLocaleChangeCallback?.(locale);\n // Notify all subscribed listeners\n for (const listener of listeners) {\n listener(locale);\n }\n }\n\n /**\n * Get message for key in locale\n */\n function getMessage(\n key: string,\n locale: string,\n ): string | PluralMessages | undefined {\n return messages[locale]?.[key];\n }\n\n /**\n * Interpolate values into string\n */\n function interpolate(str: string, params?: Record<string, unknown>): string {\n if (!params) return str;\n return str.replace(/\\{\\{(\\w+)\\}\\}/g, (_, key) => {\n const value = params[key];\n return value !== undefined ? String(value) : `{{${key}}}`;\n });\n }\n\n /**\n * Check if value is plural messages\n */\n function isPluralMessages(value: unknown): value is PluralMessages {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"one\" in value &&\n \"other\" in value\n );\n }\n\n /**\n * Get plural form\n */\n function getPluralForm(\n forms: PluralMessages,\n count: number,\n locale: string,\n ): string {\n const rules = getPluralRules(locale);\n const category = rules.select(count);\n\n switch (category) {\n case \"zero\":\n return forms.zero ?? forms.other;\n case \"one\":\n return forms.one;\n case \"two\":\n return forms.two ?? forms.other;\n case \"few\":\n return forms.few ?? forms.other;\n case \"many\":\n return forms.many ?? forms.other;\n default:\n return forms.other;\n }\n }\n\n return {\n get locale() {\n return currentLocale;\n },\n\n get locales() {\n return locales;\n },\n\n t(key: string, params?: Record<string, unknown>): string {\n // Try current locale\n let value = getMessage(key, currentLocale);\n\n // Fallback to fallback locale\n if (value === undefined && currentLocale !== fallbackLocale) {\n value = getMessage(key, fallbackLocale);\n }\n\n // Return key if not found\n if (value === undefined) {\n return key;\n }\n\n // Handle plural forms\n if (isPluralMessages(value)) {\n const count = typeof params?.count === \"number\" ? params.count : 1;\n const form = getPluralForm(value, count, currentLocale);\n return interpolate(form, params);\n }\n\n // Regular string\n return interpolate(value, params);\n },\n\n setLocale(locale: string): void {\n if (locales.includes(locale) && locale !== currentLocale) {\n currentLocale = locale;\n notifyListeners(locale);\n }\n },\n\n onLocaleChange(callback: (locale: string) => void): () => void {\n listeners.add(callback);\n return () => {\n listeners.delete(callback);\n };\n },\n\n formatDate(date: Date | number, opts?: Intl.DateTimeFormatOptions): string {\n const d = typeof date === \"number\" ? new Date(date) : date;\n return getDateTimeFormat(currentLocale, opts).format(d);\n },\n\n formatNumber(value: number, opts?: Intl.NumberFormatOptions): string {\n return getNumberFormat(currentLocale, opts).format(value);\n },\n\n formatRelative(date: Date | number): string {\n const d = typeof date === \"number\" ? new Date(date) : date;\n const now = Date.now();\n const diff = d.getTime() - now;\n const diffSeconds = Math.round(diff / 1000);\n const diffMinutes = Math.round(diff / 60000);\n const diffHours = Math.round(diff / 3600000);\n const diffDays = Math.round(diff / 86400000);\n\n const rtf = getRelativeTimeFormat(currentLocale, {\n numeric: \"auto\",\n });\n\n if (Math.abs(diffSeconds) < 60) {\n return rtf.format(diffSeconds, \"second\");\n }\n if (Math.abs(diffMinutes) < 60) {\n return rtf.format(diffMinutes, \"minute\");\n }\n if (Math.abs(diffHours) < 24) {\n return rtf.format(diffHours, \"hour\");\n }\n return rtf.format(diffDays, \"day\");\n },\n\n getLocaleName(locale: string): string {\n try {\n return (\n getDisplayNames(currentLocale, { type: \"language\" }).of(locale) ??\n locale\n );\n } catch {\n return locale;\n }\n },\n\n isRTL(): boolean {\n return RTL_LOCALES.has(currentLocale);\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.mts","names":[],"sources":["../../../src/client/i18n/types.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;UAwDiB,WAAA;;;;;;;;;;;;;;;0BAiBS;;;;oCAKU;;;;;;;;;;;mBAajB,yBAAyB,IAAA,CAAK;;;;wCAKT,IAAA,CAAK;;;;wBAKrB;;;;;;;;;;;;;;;;;;KAyBZ,aAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;KA4BA,QAAA;;;WAEmC;IAC3C,uBACO;;;;UAKM,WAAA;;KAEZ;cACS;gBACE"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import "clsx";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.mjs","names":[],"sources":["../../../src/client/lib/utils.ts"],"sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n\n/**\n * Format a string for display by converting camelCase/PascalCase to Title Case with spaces.\n *\n * Use this for formatting field names, collection names, column headers, etc.\n *\n * @example\n * formatLabel(\"blogPosts\") // \"Blog Posts\"\n * formatLabel(\"userSettings\") // \"User Settings\"\n * formatLabel(\"firstName\") // \"First Name\"\n */\nexport function formatLabel(str: string): string {\n return str\n .replace(/([A-Z])/g, \" $1\")\n .replace(/^./, (s) => s.toUpperCase())\n .trim();\n}\n\n/**\n * @deprecated Use `formatLabel` instead\n */\nexport const formatCollectionName = formatLabel;\n"],"mappings":";;;;AAGA,SAAgB,GAAG,GAAG,QAA8B;AAClD,QAAO,QAAQ,KAAK,OAAO,CAAC;;;;;;;;;;;;AAa9B,SAAgB,YAAY,KAAqB;AAC/C,QAAO,IACJ,QAAQ,YAAY,MAAM,CAC1B,QAAQ,OAAO,MAAM,EAAE,aAAa,CAAC,CACrC,MAAM;;;;;AAMX,MAAa,uBAAuB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"block-scope-context.d.mts","names":[],"sources":["../../../src/client/preview/block-scope-context.tsx"],"sourcesContent":[],"mappings":";;;;;AA4DE,KA5CU,sBAAA,GA4CV;EACA;EACC,OAAA,EAAA,MAAA;EAAuB;EAAA,WAAA,EAAA,MAAA;AA8C1B,CAAA;AAqBgB,KA9FJ,uBAAA,GA8FuB;;;;;YAzFvB,OAAA,CAAM;;;;;;;;;;;;;;;;;iBAkBF,kBAAA;;;;GAIb,0BAAuB,mBAAA,CAAA,GAAA,CAAA;;;;;;;;;;;;;;;iBA8CV,aAAA,CAAA,GAAiB;;;;;;;;;;;;;;;;;;iBAqBjB,mBAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"block-scope-context.mjs","names":["React"],"sources":["../../../src/client/preview/block-scope-context.tsx"],"sourcesContent":["/**\n * Block Scope Context\n *\n * Provides block context for field path resolution in preview mode.\n * Allows PreviewField components to auto-resolve full scoped paths\n * like \"content._values.{blockId}.title\" from simple field names.\n */\n\n\"use client\";\n\nimport * as React from \"react\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type BlockScopeContextValue = {\n /** Current block ID */\n blockId: string;\n /** Field path prefix (e.g., \"content._values.abc123\") */\n fieldPrefix: string;\n};\n\n// ============================================================================\n// Context\n// ============================================================================\n\nconst BlockScopeContext = React.createContext<BlockScopeContextValue | null>(\n null,\n);\n\n// ============================================================================\n// Provider\n// ============================================================================\n\nexport type BlockScopeProviderProps = {\n /** Block ID for this scope */\n blockId: string;\n /** Base path for blocks field (e.g., \"content._values\") */\n basePath?: string;\n children: React.ReactNode;\n};\n\n/**\n * Provides block scope context for field path resolution.\n *\n * Automatically wraps each block in BlockRenderer to enable\n * PreviewField components to resolve full scoped paths.\n *\n * @example\n * ```tsx\n * <BlockScopeProvider blockId=\"abc123\" basePath=\"content._values\">\n * <PreviewField field=\"title\">\n * {/* Auto-resolves to: content._values.abc123.title *\\/}\n * </PreviewField>\n * </BlockScopeProvider>\n * ```\n */\nexport function BlockScopeProvider({\n blockId,\n basePath = \"content._values\",\n children,\n}: BlockScopeProviderProps) {\n const parentScope = React.useContext(BlockScopeContext);\n\n // Build field prefix based on parent scope\n const fieldPrefix = React.useMemo(() => {\n if (parentScope) {\n // Nested block: append to parent prefix\n return `${parentScope.fieldPrefix}.${blockId}`;\n }\n // Top-level block: use basePath\n return `${basePath}.${blockId}`;\n }, [parentScope, basePath, blockId]);\n\n const value = React.useMemo<BlockScopeContextValue>(\n () => ({\n blockId,\n fieldPrefix,\n }),\n [blockId, fieldPrefix],\n );\n\n return (\n <BlockScopeContext.Provider value={value}>\n {children}\n </BlockScopeContext.Provider>\n );\n}\n\n// ============================================================================\n// Hooks\n// ============================================================================\n\n/**\n * Get current block scope context.\n *\n * Returns null if not inside a BlockScopeProvider.\n *\n * @example\n * ```tsx\n * const scope = useBlockScope();\n * if (scope) {\n * console.log(scope.blockId); // \"abc123\"\n * console.log(scope.fieldPrefix); // \"content._values.abc123\"\n * }\n * ```\n */\nexport function useBlockScope(): BlockScopeContextValue | null {\n return React.useContext(BlockScopeContext);\n}\n\n/**\n * Resolve a field name to its full scoped path.\n *\n * If inside a BlockScopeProvider, prepends the field prefix.\n * Otherwise, returns the field name as-is.\n *\n * @example\n * ```tsx\n * // Inside BlockScopeProvider with blockId=\"abc123\"\n * const fullPath = useResolveFieldPath(\"title\");\n * // Returns: \"content._values.abc123.title\"\n *\n * // Outside BlockScopeProvider\n * const fullPath = useResolveFieldPath(\"title\");\n * // Returns: \"title\"\n * ```\n */\nexport function useResolveFieldPath(fieldName: string): string {\n const scope = useBlockScope();\n\n return React.useMemo(() => {\n if (!scope) {\n return fieldName;\n }\n return `${scope.fieldPrefix}.${fieldName}`;\n }, [scope, fieldName]);\n}\n"],"mappings":";;;;;;;;;;;;;AA2BA,MAAM,oBAAoBA,QAAM,cAC9B,KACD;;;;;;;;;;;;;;;;AA6BD,SAAgB,mBAAmB,EACjC,SACA,WAAW,mBACX,YAC0B;CAC1B,MAAM,cAAcA,QAAM,WAAW,kBAAkB;CAGvD,MAAM,cAAcA,QAAM,cAAc;AACtC,MAAI,YAEF,QAAO,GAAG,YAAY,YAAY,GAAG;AAGvC,SAAO,GAAG,SAAS,GAAG;IACrB;EAAC;EAAa;EAAU;EAAQ,CAAC;CAEpC,MAAM,QAAQA,QAAM,eACX;EACL;EACA;EACD,GACD,CAAC,SAAS,YAAY,CACvB;AAED,QACE,oBAAC,kBAAkB;EAAgB;EAChC;GAC0B;;;;;;;;;;;;;;;;AAsBjC,SAAgB,gBAA+C;AAC7D,QAAOA,QAAM,WAAW,kBAAkB;;;;;;;;;;;;;;;;;;;AAoB5C,SAAgB,oBAAoB,WAA2B;CAC7D,MAAM,QAAQ,eAAe;AAE7B,QAAOA,QAAM,cAAc;AACzB,MAAI,CAAC,MACH,QAAO;AAET,SAAO,GAAG,MAAM,YAAY,GAAG;IAC9B,CAAC,OAAO,UAAU,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"preview-banner.d.mts","names":[],"sources":["../../../src/client/preview/preview-banner.tsx"],"sourcesContent":[],"mappings":";;;;;;;AAeA;AAiCA;;AAEE,KAnCU,kBAAA,GAmCV;EACA;EACC,aAAA,EAAA,OAAA;EAAkB;EAAA,SAAA,CAAA,EAAA,MAAA;;;;;;;;;;;;;;;;;;;;;;;;iBAJL,aAAA;;;;GAIb,qBAAkB,mBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"preview-banner.mjs","names":[],"sources":["../../../src/client/preview/preview-banner.tsx"],"sourcesContent":["/**\n * Preview Banner Component\n *\n * Displayed at the top of preview pages when in draft mode.\n * Allows users to exit preview mode (clear __draft_mode cookie).\n */\n\n\"use client\";\n\nimport * as React from \"react\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type PreviewBannerProps = {\n /** Whether we're in preview mode */\n isPreviewMode: boolean;\n /** Custom class name */\n className?: string;\n /** Custom exit preview URL (default: /api/preview?disable=true) */\n exitPreviewUrl?: string;\n};\n\n// ============================================================================\n// Component\n// ============================================================================\n\n/**\n * Preview mode banner with exit button.\n *\n * Shows a sticky banner at the top of the page when in draft/preview mode.\n * Clicking \"Exit Preview\" clears the draft mode cookie.\n *\n * @example\n * ```tsx\n * export default function RootLayout({ children }) {\n * const { isPreviewMode } = useCollectionPreview({ ... });\n *\n * return (\n * <>\n * <PreviewBanner isPreviewMode={isPreviewMode} />\n * {children}\n * </>\n * );\n * }\n * ```\n */\nexport function PreviewBanner({\n isPreviewMode,\n className,\n exitPreviewUrl = \"/api/preview?disable=true\",\n}: PreviewBannerProps) {\n if (!isPreviewMode) return null;\n\n return (\n <div\n className={className}\n style={{\n position: \"sticky\",\n top: 0,\n left: 0,\n right: 0,\n zIndex: 9999,\n backgroundColor: \"hsl(var(--primary))\",\n color: \"hsl(var(--primary-foreground))\",\n padding: \"0.5rem 1rem\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: \"1rem\",\n fontSize: \"0.875rem\",\n fontWeight: 500,\n boxShadow: \"0 2px 8px rgba(0, 0, 0, 0.1)\",\n }}\n >\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: \"0.5rem\",\n }}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 256 256\"\n fill=\"currentColor\"\n >\n <title>Eye icon</title>\n <path d=\"M247.31,124.76c-.35-.79-8.82-19.58-27.65-38.41C194.57,61.26,162.88,48,128,48S61.43,61.26,36.34,86.35C17.51,105.18,9,124,8.69,124.76a8,8,0,0,0,0,6.5c.35.79,8.82,19.57,27.65,38.4C61.43,194.74,93.12,208,128,208s66.57-13.26,91.66-38.34c18.83-18.83,27.3-37.61,27.65-38.4A8,8,0,0,0,247.31,124.76ZM128,192c-30.78,0-57.67-11.19-79.93-33.25A133.47,133.47,0,0,1,25,128,133.33,133.33,0,0,1,48.07,97.25C70.33,75.19,97.22,64,128,64s57.67,11.19,79.93,33.25A133.46,133.46,0,0,1,231.05,128C223.84,141.46,192.43,192,128,192Zm0-112a48,48,0,1,0,48,48A48.05,48.05,0,0,0,128,80Zm0,80a32,32,0,1,1,32-32A32,32,0,0,1,128,160Z\" />\n </svg>\n <span>Preview Mode</span>\n </div>\n\n <a\n href={exitPreviewUrl}\n style={{\n padding: \"0.25rem 0.75rem\",\n backgroundColor: \"rgba(255, 255, 255, 0.2)\",\n border: \"1px solid rgba(255, 255, 255, 0.3)\",\n borderRadius: \"4px\",\n color: \"inherit\",\n textDecoration: \"none\",\n fontWeight: 600,\n fontSize: \"0.875rem\",\n cursor: \"pointer\",\n transition: \"background-color 0.2s\",\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = \"rgba(255, 255, 255, 0.3)\";\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = \"rgba(255, 255, 255, 0.2)\";\n }}\n >\n Exit Preview\n </a>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDA,SAAgB,cAAc,EAC5B,eACA,WACA,iBAAiB,+BACI;AACrB,KAAI,CAAC,cAAe,QAAO;AAE3B,QACE,qBAAC;EACY;EACX,OAAO;GACL,UAAU;GACV,KAAK;GACL,MAAM;GACN,OAAO;GACP,QAAQ;GACR,iBAAiB;GACjB,OAAO;GACP,SAAS;GACT,SAAS;GACT,YAAY;GACZ,gBAAgB;GAChB,KAAK;GACL,UAAU;GACV,YAAY;GACZ,WAAW;GACZ;aAED,qBAAC;GACC,OAAO;IACL,SAAS;IACT,YAAY;IACZ,KAAK;IACN;cAED,qBAAC;IACC,OAAM;IACN,OAAM;IACN,QAAO;IACP,SAAQ;IACR,MAAK;eAEL,oBAAC,qBAAM,aAAgB,EACvB,oBAAC,UAAK,GAAE,8lBAA8lB;KAClmB,EACN,oBAAC,oBAAK,iBAAmB;IACrB,EAEN,oBAAC;GACC,MAAM;GACN,OAAO;IACL,SAAS;IACT,iBAAiB;IACjB,QAAQ;IACR,cAAc;IACd,OAAO;IACP,gBAAgB;IAChB,YAAY;IACZ,UAAU;IACV,QAAQ;IACR,YAAY;IACb;GACD,eAAe,MAAM;AACnB,MAAE,cAAc,MAAM,kBAAkB;;GAE1C,eAAe,MAAM;AACnB,MAAE,cAAc,MAAM,kBAAkB;;aAE3C;IAEG;GACA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"preview-field.d.mts","names":[],"sources":["../../../src/client/preview/preview-field.tsx"],"sourcesContent":[],"mappings":";;;;;AA6DE,KA5CU,iBAAA,GA4CV;EACA;EACA,KAAA,EAAA,MAAA;EACA;EAWU,SAAM,CAAA,EAAA,SAAA,GAAA,OAAA,GAAA,UAAA;EACjB;EAAA,QAAA,EArDW,OAAA,CAAM,SAqDjB;EAkBe;EAgCA,EAAA,CAAA,EArGT,OAAA,CAAM,WAqGe;EAC1B;EACA,SAAA,CAAA,EAAA,MAAA;EACA;EACI,OAAA,CAAA,EAAA,CAAA,SAAA,EAAA,MAAA,EAAA,OAGH,CAHG,EAAA;IACJ,OAAA,CAAA,EAAA,MAAA;IACA,SAAA,CAAA,EAAA,SAAA,GAAA,OAAA,GAAA,UAAA;EACC,CAAA,EAAA,GAAA,IAAA;CAAiB;KA3Ff,mBAAA,GA2Fe;EAmDJ,aAAA,EAAA,OAAA;EACd,gBAAA,EAAA,CAAA,SAAA,EAAA,MAAA,EAAA,OAGI,CAHJ,EAAA;IACA,OAAA,CAAA,EAAA,MAAA;IACA,SAAA,CAAA,EAAA,SAAA,GAAA,OAAA,GAAA,UAAA;EACI,CAAA,EAAA,GAAA,IAAA;EACJ,YAAA,EAAA,MAAA,GAAA,IAAA;CACA;;;;;AAaD,iBA/Ie,eAAA,CA+If;EAAA,aAAA;EAAA,YAAA;EAAA,YAAA;EAAA;CAAA,EAAA;;;;;;;YAhIW,OAAA,CAAM;IACjB,mBAAA,CAAA,GAAA,CAAA;;;;iBAkBe,iBAAA,CAAA,GAAqB;;;;;;;;;;;;;;;;;;;;;;;;;iBAgCrB,YAAA;;;;MAIV;;;GAGH,oBAAiB,mBAAA,CAAA,GAAA,CAAA;;;;;iBAmDJ,sBAAA;;;;MAIV;;;;;GAKH;;;;;;;IAUF,mBAAA,CAAA,GAAA,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"preview-field.mjs","names":["React"],"sources":["../../../src/client/preview/preview-field.tsx"],"sourcesContent":["/**\n * PreviewField Component\n *\n * Wrapper component that makes fields clickable in preview mode.\n * When clicked, signals to admin to focus that field in the form.\n */\n\n\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../lib/utils.js\";\nimport { useBlockScope, useResolveFieldPath } from \"./block-scope-context.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type PreviewFieldProps = {\n /** Field name (for click-to-focus) - will be resolved with block scope if available */\n field: string;\n /** Field type for routing (regular, block, or relation) */\n fieldType?: \"regular\" | \"block\" | \"relation\";\n /** Content to render */\n children: React.ReactNode;\n /** HTML element type */\n as?: React.ElementType;\n /** Additional class names */\n className?: string;\n /** Click handler (uses context by default) */\n onClick?: (\n fieldPath: string,\n context?: {\n blockId?: string;\n fieldType?: \"regular\" | \"block\" | \"relation\";\n },\n ) => void;\n};\n\n// ============================================================================\n// Context\n// ============================================================================\n\ntype PreviewContextValue = {\n isPreviewMode: boolean;\n handleFieldClick: (\n fieldPath: string,\n context?: {\n blockId?: string;\n fieldType?: \"regular\" | \"block\" | \"relation\";\n },\n ) => void;\n focusedField: string | null;\n};\n\nconst PreviewContext = React.createContext<PreviewContextValue | null>(null);\n\n/**\n * Provider for preview mode context.\n * Use this at the root of your preview page.\n */\nexport function PreviewProvider({\n isPreviewMode,\n focusedField,\n onFieldClick,\n children,\n}: {\n isPreviewMode: boolean;\n focusedField: string | null;\n onFieldClick: (\n fieldPath: string,\n context?: {\n blockId?: string;\n fieldType?: \"regular\" | \"block\" | \"relation\";\n },\n ) => void;\n children: React.ReactNode;\n}) {\n const value = React.useMemo(\n () => ({\n isPreviewMode,\n focusedField,\n handleFieldClick: onFieldClick,\n }),\n [isPreviewMode, focusedField, onFieldClick],\n );\n\n return (\n <PreviewContext.Provider value={value}>{children}</PreviewContext.Provider>\n );\n}\n\n/**\n * Hook to access preview context.\n */\nexport function usePreviewContext(): PreviewContextValue | null {\n return React.useContext(PreviewContext);\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\n/**\n * Wrapper that makes a field clickable in preview mode.\n *\n * When clicked in preview, signals to admin to focus that field in the form.\n * Automatically resolves field paths using block scope context if available.\n *\n * @example\n * ```tsx\n * // Regular field\n * <PreviewField field=\"title\" as=\"h1\" className=\"text-4xl\">\n * {data.title}\n * </PreviewField>\n *\n * // Relation field\n * <PreviewField field=\"author\" fieldType=\"relation\">\n * {data.author.name}\n * </PreviewField>\n *\n * // Inside a block (auto-resolves to content._values.{blockId}.title)\n * <PreviewField field=\"title\">\n * {values.title}\n * </PreviewField>\n * ```\n */\nexport function PreviewField({\n field,\n fieldType = \"regular\",\n children,\n as: Component = \"div\",\n className,\n onClick,\n}: PreviewFieldProps) {\n const context = usePreviewContext();\n const blockScope = useBlockScope();\n const fullPath = useResolveFieldPath(field);\n\n // If no context or not in preview mode, just render normally\n if (!context?.isPreviewMode) {\n return <Component className={className}>{children}</Component>;\n }\n\n const { handleFieldClick, focusedField } = context;\n const isFocused = focusedField === fullPath;\n\n const handleClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (onClick) {\n onClick(fullPath, {\n blockId: blockScope?.blockId,\n fieldType,\n });\n } else {\n handleFieldClick(fullPath, {\n blockId: blockScope?.blockId,\n fieldType,\n });\n }\n };\n\n return (\n <Component\n data-preview-field={fullPath}\n data-block-id={blockScope?.blockId}\n data-field-type={fieldType}\n onClick={handleClick}\n className={cn(\n className,\n \"group relative cursor-pointer transition-all duration-150\",\n \"hover:outline hover:outline-2 hover:outline-dashed hover:outline-primary/60 hover:outline-offset-2 hover:rounded-sm\",\n isFocused &&\n \"outline outline-2 outline-primary outline-offset-2 rounded-sm\",\n )}\n >\n {children}\n </Component>\n );\n}\n\n/**\n * Standalone PreviewField that works without context.\n * Useful when you can't use PreviewProvider.\n */\nexport function StandalonePreviewField({\n field,\n fieldType = \"regular\",\n children,\n as: Component = \"div\",\n className,\n isPreviewMode,\n isFocused,\n onFieldClick,\n}: PreviewFieldProps & {\n isPreviewMode: boolean;\n isFocused?: boolean;\n onFieldClick: (\n fieldPath: string,\n context?: {\n blockId?: string;\n fieldType?: \"regular\" | \"block\" | \"relation\";\n },\n ) => void;\n}) {\n const blockScope = useBlockScope();\n const fullPath = useResolveFieldPath(field);\n\n if (!isPreviewMode) {\n return <Component className={className}>{children}</Component>;\n }\n\n const handleClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n onFieldClick(fullPath, {\n blockId: blockScope?.blockId,\n fieldType,\n });\n };\n\n return (\n <Component\n data-preview-field={fullPath}\n data-block-id={blockScope?.blockId}\n data-field-type={fieldType}\n onClick={handleClick}\n className={cn(\n className,\n \"group relative cursor-pointer transition-all duration-150\",\n \"hover:outline hover:outline-2 hover:outline-dashed hover:outline-primary/60 hover:outline-offset-2 hover:rounded-sm\",\n isFocused &&\n \"outline outline-2 outline-primary outline-offset-2 rounded-sm\",\n )}\n >\n {children}\n </Component>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAsDA,MAAM,iBAAiBA,QAAM,cAA0C,KAAK;;;;;AAM5E,SAAgB,gBAAgB,EAC9B,eACA,cACA,cACA,YAYC;CACD,MAAM,QAAQA,QAAM,eACX;EACL;EACA;EACA,kBAAkB;EACnB,GACD;EAAC;EAAe;EAAc;EAAa,CAC5C;AAED,QACE,oBAAC,eAAe;EAAgB;EAAQ;GAAmC;;;;;AAO/E,SAAgB,oBAAgD;AAC9D,QAAOA,QAAM,WAAW,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BzC,SAAgB,aAAa,EAC3B,OACA,YAAY,WACZ,UACA,IAAI,YAAY,OAChB,WACA,WACoB;CACpB,MAAM,UAAU,mBAAmB;CACnC,MAAM,aAAa,eAAe;CAClC,MAAM,WAAW,oBAAoB,MAAM;AAG3C,KAAI,CAAC,SAAS,cACZ,QAAO,oBAAC;EAAqB;EAAY;GAAqB;CAGhE,MAAM,EAAE,kBAAkB,iBAAiB;CAC3C,MAAM,YAAY,iBAAiB;CAEnC,MAAM,eAAe,MAAwB;AAC3C,IAAE,iBAAiB;AACnB,MAAI,QACF,SAAQ,UAAU;GAChB,SAAS,YAAY;GACrB;GACD,CAAC;MAEF,kBAAiB,UAAU;GACzB,SAAS,YAAY;GACrB;GACD,CAAC;;AAIN,QACE,oBAAC;EACC,sBAAoB;EACpB,iBAAe,YAAY;EAC3B,mBAAiB;EACjB,SAAS;EACT,WAAW,GACT,WACA,6DACA,uHACA,aACE,gEACH;EAEA;GACS;;;;;;AAQhB,SAAgB,uBAAuB,EACrC,OACA,YAAY,WACZ,UACA,IAAI,YAAY,OAChB,WACA,eACA,WACA,gBAWC;CACD,MAAM,aAAa,eAAe;CAClC,MAAM,WAAW,oBAAoB,MAAM;AAE3C,KAAI,CAAC,cACH,QAAO,oBAAC;EAAqB;EAAY;GAAqB;CAGhE,MAAM,eAAe,MAAwB;AAC3C,IAAE,iBAAiB;AACnB,eAAa,UAAU;GACrB,SAAS,YAAY;GACrB;GACD,CAAC;;AAGJ,QACE,oBAAC;EACC,sBAAoB;EACpB,iBAAe,YAAY;EAC3B,mBAAiB;EACjB,SAAS;EACT,WAAW,GACT,WACA,6DACA,uHACA,aACE,gEACH;EAEA;GACS"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.mts","names":[],"sources":["../../../src/client/preview/types.ts"],"sourcesContent":[],"mappings":";;AAcA;AASA;AASA;AASA;;;;;AAYY,KAvCA,qBAAA,GAuCmB;EAOnB,IAAA,EAAA,iBAAmB;EAanB;EAUA,YAAA,CAAA,EAAA,MAAA;AASZ,CAAA;;;;AAII,KAzEQ,kBAAA,GAyER;EAAsB,IAAA,EAAA,cAAA;EASd;EAuCI,OAAA,EAAA,MAAA;AAehB,CAAA;;;;KA/HY,iBAAA;;;;;;;;KASA,qBAAA,GACR,wBACA,qBACA;;;;KASQ,mBAAA;;;;;;KAOA,mBAAA;;;;;;;;;;;;KAaA,mBAAA;;;;;;;;;KAUA,sBAAA;;;;;;;;KASA,qBAAA,GACR,sBACA,sBACA,sBACA;;;;KASQ,aAAA;;;;;gBAKI;;;;;;;;;;;;;;;;;;;;;;;;;iBAkCA,uBAAA,yBAEL;;;;iBAaK,uBAAA,yBAEL"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.mjs","names":[],"sources":["../../../src/client/preview/types.ts"],"sourcesContent":["/**\n * Collection Preview Types\n *\n * PostMessage protocol and types for live preview communication\n * between admin and preview iframe.\n */\n\n// ============================================================================\n// Admin -> Preview Messages\n// ============================================================================\n\n/**\n * Signal preview to refresh (invalidate and re-run loader).\n */\nexport type PreviewRefreshMessage = {\n type: \"PREVIEW_REFRESH\";\n /** Optional hint about which field changed */\n changedField?: string;\n};\n\n/**\n * Select a block in the preview.\n */\nexport type SelectBlockMessage = {\n type: \"SELECT_BLOCK\";\n /** Block ID to select */\n blockId: string;\n};\n\n/**\n * Focus a field in the preview.\n */\nexport type FocusFieldMessage = {\n type: \"FOCUS_FIELD\";\n /** Field path to focus (supports full scoped paths) */\n fieldPath: string;\n};\n\n/**\n * All messages from Admin to Preview.\n */\nexport type AdminToPreviewMessage =\n | PreviewRefreshMessage\n | SelectBlockMessage\n | FocusFieldMessage;\n\n// ============================================================================\n// Preview -> Admin Messages\n// ============================================================================\n\n/**\n * Preview is ready to receive data.\n */\nexport type PreviewReadyMessage = {\n type: \"PREVIEW_READY\";\n};\n\n/**\n * A field was clicked in the preview.\n */\nexport type FieldClickedMessage = {\n type: \"FIELD_CLICKED\";\n /** Full scoped field path */\n fieldPath: string;\n /** Block context hint */\n blockId?: string;\n /** Field type for routing */\n fieldType?: \"regular\" | \"block\" | \"relation\";\n};\n\n/**\n * A block was clicked in the preview.\n */\nexport type BlockClickedMessage = {\n type: \"BLOCK_CLICKED\";\n /** Block ID that was clicked */\n blockId: string;\n};\n\n/**\n * Preview refresh completed.\n * Sent after preview successfully re-runs loader.\n */\nexport type RefreshCompleteMessage = {\n type: \"REFRESH_COMPLETE\";\n /** Timestamp of completion */\n timestamp: number;\n};\n\n/**\n * All messages from Preview to Admin.\n */\nexport type PreviewToAdminMessage =\n | PreviewReadyMessage\n | FieldClickedMessage\n | BlockClickedMessage\n | RefreshCompleteMessage;\n\n// ============================================================================\n// Preview Configuration\n// ============================================================================\n\n/**\n * Preview configuration for a collection.\n */\nexport type PreviewConfig = {\n /**\n * URL builder for preview iframe.\n * Receives current form values and locale.\n */\n url: (values: Record<string, unknown>, locale: string) => string;\n\n /**\n * Enable/disable preview.\n * @default true if url is defined\n */\n enabled?: boolean;\n\n /**\n * Preview pane position.\n * @default \"right\"\n */\n position?: \"right\" | \"bottom\" | \"modal\";\n\n /**\n * Default preview pane size (percentage).\n * @default 50\n */\n defaultSize?: number;\n\n /**\n * Minimum pane size (percentage).\n * @default 30\n */\n minSize?: number;\n};\n\n// ============================================================================\n// Type Guards\n// ============================================================================\n\n/**\n * Check if a message is from admin to preview.\n */\nexport function isAdminToPreviewMessage(\n data: unknown,\n): data is AdminToPreviewMessage {\n if (!data || typeof data !== \"object\") return false;\n const msg = data as { type?: string };\n return (\n msg.type === \"PREVIEW_REFRESH\" ||\n msg.type === \"SELECT_BLOCK\" ||\n msg.type === \"FOCUS_FIELD\"\n );\n}\n\n/**\n * Check if a message is from preview to admin.\n */\nexport function isPreviewToAdminMessage(\n data: unknown,\n): data is PreviewToAdminMessage {\n if (!data || typeof data !== \"object\") return false;\n const msg = data as { type?: string };\n return (\n msg.type === \"PREVIEW_READY\" ||\n msg.type === \"FIELD_CLICKED\" ||\n msg.type === \"BLOCK_CLICKED\" ||\n msg.type === \"REFRESH_COMPLETE\"\n );\n}\n"],"mappings":";;;;AAgJA,SAAgB,wBACd,MAC+B;AAC/B,KAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO;CAC9C,MAAM,MAAM;AACZ,QACE,IAAI,SAAS,qBACb,IAAI,SAAS,kBACb,IAAI,SAAS;;;;;AAOjB,SAAgB,wBACd,MAC+B;AAC/B,KAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO;CAC9C,MAAM,MAAM;AACZ,QACE,IAAI,SAAS,mBACb,IAAI,SAAS,mBACb,IAAI,SAAS,mBACb,IAAI,SAAS"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-collection-preview.d.mts","names":[],"sources":["../../../src/client/preview/use-collection-preview.ts"],"sourcesContent":[],"mappings":";;AAgBA;AAUA;AAwDA;;;AAEE,KApEU,2BAoEV,CAAA,KAAA,CAAA,GAAA;EAC6B;EAA5B,WAAA,EAnEY,KAmEZ;EAAgE;;;;0BA9DzC;;KAGd;;QAEJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsDQ,mCAAmC;;;GAGhD,4BAA4B,SAAS,2BAA2B"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-collection-preview.mjs","names":["React"],"sources":["../../../src/client/preview/use-collection-preview.ts"],"sourcesContent":["/**\n * useCollectionPreview Hook\n *\n * Hook for frontend pages to receive live preview data from admin.\n * Handles postMessage communication with the admin iframe parent.\n */\n\n\"use client\";\n\nimport * as React from \"react\";\nimport type { AdminToPreviewMessage } from \"./types.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type UseCollectionPreviewOptions<TData> = {\n /** Server-loaded data (from loader/SSR) */\n initialData: TData;\n /**\n * Callback to refresh data (e.g., router.invalidate()).\n * Required for preview functionality.\n */\n onRefresh: () => void | Promise<void>;\n};\n\nexport type UseCollectionPreviewResult<TData> = {\n /** Current data (from initialData, refreshed via onRefresh) */\n data: TData;\n /** Whether we're in preview mode (inside admin iframe) */\n isPreviewMode: boolean;\n /** Currently selected block ID */\n selectedBlockId: string | null;\n /** Focused field path */\n focusedField: string | null;\n /** Call when a field is clicked in preview */\n handleFieldClick: (\n fieldPath: string,\n context?: {\n blockId?: string;\n fieldType?: \"regular\" | \"block\" | \"relation\";\n },\n ) => void;\n /** Call when a block is clicked in preview */\n handleBlockClick: (blockId: string) => void;\n};\n\n// ============================================================================\n// Hook\n// ============================================================================\n\n/**\n * Hook for receiving live preview data from admin.\n *\n * Use this in your frontend page components to enable live preview.\n *\n * @example\n * ```tsx\n * function PageRoute() {\n * const loaderData = Route.useLoaderData();\n * const router = useRouter();\n *\n * const { data, isPreviewMode, selectedBlockId, handleBlockClick } =\n * useCollectionPreview({\n * initialData: loaderData.page,\n * onRefresh: () => router.invalidate(),\n * });\n *\n * return (\n * <article>\n * <PreviewField field=\"title\" as=\"h1\">{data.title}</PreviewField>\n * <BlockRenderer\n * content={data.content}\n * blocks={blocks}\n * selectedBlockId={selectedBlockId}\n * onBlockClick={handleBlockClick}\n * />\n * </article>\n * );\n * }\n * ```\n */\nexport function useCollectionPreview<TData extends Record<string, unknown>>({\n initialData,\n onRefresh,\n}: UseCollectionPreviewOptions<TData>): UseCollectionPreviewResult<TData> {\n const [selectedBlockId, setSelectedBlockId] = React.useState<string | null>(\n null,\n );\n const [focusedField, setFocusedField] = React.useState<string | null>(null);\n\n // Check if we're in an iframe (preview mode)\n const isPreviewMode = React.useMemo(() => {\n if (typeof window === \"undefined\") return false;\n try {\n return window.self !== window.top;\n } catch {\n // Cross-origin iframe - assume we're in preview mode\n return true;\n }\n }, []);\n\n // Keep onRefresh in a ref to avoid stale closures while maintaining stable reference\n const onRefreshRef = React.useRef(onRefresh);\n React.useEffect(() => {\n onRefreshRef.current = onRefresh;\n }, [onRefresh]);\n\n // Set up postMessage listener\n React.useEffect(() => {\n if (!isPreviewMode) return;\n\n // Signal that preview is ready\n window.parent.postMessage({ type: \"PREVIEW_READY\" }, \"*\");\n\n const handleMessage = async (\n event: MessageEvent<AdminToPreviewMessage>,\n ) => {\n // In production, validate origin here\n const message = event.data;\n\n if (!message || typeof message !== \"object\" || !message.type) {\n return;\n }\n\n switch (message.type) {\n case \"PREVIEW_REFRESH\": {\n await onRefreshRef.current();\n window.parent.postMessage(\n {\n type: \"REFRESH_COMPLETE\",\n timestamp: Date.now(),\n },\n \"*\",\n );\n break;\n }\n\n case \"SELECT_BLOCK\":\n setSelectedBlockId(message.blockId);\n break;\n\n case \"FOCUS_FIELD\": {\n setFocusedField(message.fieldPath);\n // Scroll field into view (with delay to ensure React render)\n setTimeout(() => {\n const element = document.querySelector(\n `[data-preview-field=\"${message.fieldPath}\"]`,\n );\n if (element) {\n element.scrollIntoView({ behavior: \"smooth\", block: \"center\" });\n }\n }, 150);\n break;\n }\n }\n };\n\n window.addEventListener(\"message\", handleMessage);\n return () => window.removeEventListener(\"message\", handleMessage);\n }, [isPreviewMode]);\n\n // Field click handler\n const handleFieldClick = React.useCallback(\n (\n fieldPath: string,\n context?: {\n blockId?: string;\n fieldType?: \"regular\" | \"block\" | \"relation\";\n },\n ) => {\n if (isPreviewMode) {\n window.parent.postMessage(\n {\n type: \"FIELD_CLICKED\",\n fieldPath,\n blockId: context?.blockId,\n fieldType: context?.fieldType,\n },\n \"*\",\n );\n }\n },\n [isPreviewMode],\n );\n\n // Block click handler\n const handleBlockClick = React.useCallback(\n (blockId: string) => {\n if (isPreviewMode) {\n window.parent.postMessage({ type: \"BLOCK_CLICKED\", blockId }, \"*\");\n }\n },\n [isPreviewMode],\n );\n\n return {\n data: initialData,\n isPreviewMode,\n selectedBlockId,\n focusedField,\n handleFieldClick,\n handleBlockClick,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkFA,SAAgB,qBAA4D,EAC1E,aACA,aACwE;CACxE,MAAM,CAAC,iBAAiB,sBAAsBA,QAAM,SAClD,KACD;CACD,MAAM,CAAC,cAAc,mBAAmBA,QAAM,SAAwB,KAAK;CAG3E,MAAM,gBAAgBA,QAAM,cAAc;AACxC,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,MAAI;AACF,UAAO,OAAO,SAAS,OAAO;UACxB;AAEN,UAAO;;IAER,EAAE,CAAC;CAGN,MAAM,eAAeA,QAAM,OAAO,UAAU;AAC5C,SAAM,gBAAgB;AACpB,eAAa,UAAU;IACtB,CAAC,UAAU,CAAC;AAGf,SAAM,gBAAgB;AACpB,MAAI,CAAC,cAAe;AAGpB,SAAO,OAAO,YAAY,EAAE,MAAM,iBAAiB,EAAE,IAAI;EAEzD,MAAM,gBAAgB,OACpB,UACG;GAEH,MAAM,UAAU,MAAM;AAEtB,OAAI,CAAC,WAAW,OAAO,YAAY,YAAY,CAAC,QAAQ,KACtD;AAGF,WAAQ,QAAQ,MAAhB;IACE,KAAK;AACH,WAAM,aAAa,SAAS;AAC5B,YAAO,OAAO,YACZ;MACE,MAAM;MACN,WAAW,KAAK,KAAK;MACtB,EACD,IACD;AACD;IAGF,KAAK;AACH,wBAAmB,QAAQ,QAAQ;AACnC;IAEF,KAAK;AACH,qBAAgB,QAAQ,UAAU;AAElC,sBAAiB;MACf,MAAM,UAAU,SAAS,cACvB,wBAAwB,QAAQ,UAAU,IAC3C;AACD,UAAI,QACF,SAAQ,eAAe;OAAE,UAAU;OAAU,OAAO;OAAU,CAAC;QAEhE,IAAI;AACP;;;AAKN,SAAO,iBAAiB,WAAW,cAAc;AACjD,eAAa,OAAO,oBAAoB,WAAW,cAAc;IAChE,CAAC,cAAc,CAAC;AAoCnB,QAAO;EACL,MAAM;EACN;EACA;EACA;EACA,kBAtCuBA,QAAM,aAE3B,WACA,YAIG;AACH,OAAI,cACF,QAAO,OAAO,YACZ;IACE,MAAM;IACN;IACA,SAAS,SAAS;IAClB,WAAW,SAAS;IACrB,EACD,IACD;KAGL,CAAC,cAAc,CAChB;EAkBC,kBAfuBA,QAAM,aAC5B,YAAoB;AACnB,OAAI,cACF,QAAO,OAAO,YAAY;IAAE,MAAM;IAAiB;IAAS,EAAE,IAAI;KAGtE,CAAC,cAAc,CAChB;EASA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"content-locales-provider.mjs","names":["DEFAULT_LOCALES: ContentLocalesData","value: ContentLocalesContextValue"],"sources":["../../../src/client/runtime/content-locales-provider.tsx"],"sourcesContent":["/**\n * Content Locales Provider\n *\n * Fetches and provides content locales from the backend CMS configuration.\n * Content locales are different from UI locales - they define which languages\n * are available for content translation.\n */\n\nimport { useQuery } from \"@tanstack/react-query\";\nimport { DEFAULT_LOCALE } from \"questpie/shared\";\nimport {\n createContext,\n type ReactElement,\n type ReactNode,\n useContext,\n} from \"react\";\nimport { selectClient, useAdminStore } from \"./provider\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ContentLocale {\n /** Locale code (e.g. \"en\", \"sk\", \"en-US\") */\n code: string;\n /** Human-readable label (e.g. \"English\", \"Slovenčina\") */\n label?: string;\n /** Is this the fallback locale? */\n fallback?: boolean;\n /** Custom country code for flag display (e.g. \"us\" for \"en\") */\n flagCountryCode?: string;\n}\n\nexport interface ContentLocalesData {\n /** Available content locales */\n locales: ContentLocale[];\n /** Default locale code */\n defaultLocale: string;\n /** Fallback locale mappings (e.g. { \"en-GB\": \"en\" }) */\n fallbacks?: Record<string, string>;\n}\n\nexport interface ContentLocalesContextValue extends ContentLocalesData {\n /** Check if localization is enabled (more than one locale) */\n isLocalized: boolean;\n /** Get the human-readable label for a locale code */\n getLocaleLabel: (code: string) => string;\n /** Check if a locale code is valid */\n isValidLocale: (code: string) => boolean;\n /** Get fallback locale for a given locale */\n getFallbackLocale: (code: string) => string;\n /** Loading state */\n isLoading: boolean;\n /** Error state */\n error: Error | null;\n}\n\n// ============================================================================\n// Context\n// ============================================================================\n\nconst ContentLocalesContext = createContext<ContentLocalesContextValue | null>(\n null,\n);\n\n// ============================================================================\n// Default Values\n// ============================================================================\n\nconst DEFAULT_LOCALES: ContentLocalesData = {\n locales: [{ code: DEFAULT_LOCALE, label: \"English\", fallback: true }],\n defaultLocale: DEFAULT_LOCALE,\n};\n\n// ============================================================================\n// Provider Component\n// ============================================================================\n\nexport interface ContentLocalesProviderProps {\n children: ReactNode;\n}\n\n/**\n * Content Locales Provider\n *\n * Fetches content locales from the backend and provides them to the UI.\n * Must be used inside AdminProvider to access the client.\n *\n * @example\n * ```tsx\n * <AdminProvider admin={admin} client={client}>\n * <ContentLocalesProvider>\n * <App />\n * </ContentLocalesProvider>\n * </AdminProvider>\n * ```\n */\nexport function ContentLocalesProvider({\n children,\n}: ContentLocalesProviderProps): ReactElement {\n const client = useAdminStore(selectClient);\n\n const { data, isLoading, error } = useQuery({\n queryKey: [\"cms\", \"contentLocales\"],\n queryFn: async () => {\n try {\n // Use type assertion since the client type may not include getContentLocales\n // depending on which modules are used\n const result = await (client as any).rpc.getContentLocales({});\n return result as ContentLocalesData;\n } catch {\n // If the function doesn't exist, return default locales\n return DEFAULT_LOCALES;\n }\n },\n staleTime: 5 * 60 * 1000, // Cache for 5 minutes\n gcTime: 10 * 60 * 1000, // Keep in cache for 10 minutes\n });\n\n const localesData = data ?? DEFAULT_LOCALES;\n\n const value: ContentLocalesContextValue = {\n ...localesData,\n isLocalized: localesData.locales.length > 1,\n isLoading,\n error: error as Error | null,\n\n getLocaleLabel: (code: string): string => {\n const locale = localesData.locales.find((l) => l.code === code);\n return locale?.label ?? code.toUpperCase();\n },\n\n isValidLocale: (code: string): boolean => {\n return localesData.locales.some((l) => l.code === code);\n },\n\n getFallbackLocale: (code: string): string => {\n // Check explicit fallbacks first\n if (localesData.fallbacks?.[code]) {\n return localesData.fallbacks[code];\n }\n // Return default locale\n return localesData.defaultLocale;\n },\n };\n\n return (\n <ContentLocalesContext.Provider value={value}>\n {children}\n </ContentLocalesContext.Provider>\n );\n}\n\n// ============================================================================\n// Hooks\n// ============================================================================\n\n/**\n * Get content locales from context.\n *\n * Must be used inside ContentLocalesProvider.\n * Returns locale data, helper functions, and loading state.\n *\n * @example\n * ```tsx\n * function LocaleSwitcher() {\n * const {\n * locales,\n * defaultLocale,\n * isLocalized,\n * getLocaleLabel,\n * } = useContentLocales();\n *\n * if (!isLocalized) return null;\n *\n * return (\n * <select>\n * {locales.map(l => (\n * <option key={l.code} value={l.code}>\n * {getLocaleLabel(l.code)}\n * </option>\n * ))}\n * </select>\n * );\n * }\n * ```\n */\nexport function useContentLocales(): ContentLocalesContextValue {\n const context = useContext(ContentLocalesContext);\n if (!context) {\n throw new Error(\n \"useContentLocales must be used within ContentLocalesProvider. \" +\n \"Wrap your app with <ContentLocalesProvider> inside <AdminProvider>.\",\n );\n }\n return context;\n}\n\n/**\n * Safely get content locales from context.\n * Returns null if not inside provider (useful for optional features).\n */\nexport function useSafeContentLocales(): ContentLocalesContextValue | null {\n return useContext(ContentLocalesContext);\n}\n"],"mappings":";;;;;;;;;;;;;;AA6DA,MAAM,wBAAwB,cAC5B,KACD;AAMD,MAAMA,kBAAsC;CAC1C,SAAS,CAAC;EAAE,MAAM;EAAgB,OAAO;EAAW,UAAU;EAAM,CAAC;CACrE,eAAe;CAChB;;;;;;;;;;;;;;;;AAyBD,SAAgB,uBAAuB,EACrC,YAC4C;CAC5C,MAAM,SAAS,cAAc,aAAa;CAE1C,MAAM,EAAE,MAAM,WAAW,UAAU,SAAS;EAC1C,UAAU,CAAC,OAAO,iBAAiB;EACnC,SAAS,YAAY;AACnB,OAAI;AAIF,WADe,MAAO,OAAe,IAAI,kBAAkB,EAAE,CAAC;WAExD;AAEN,WAAO;;;EAGX,WAAW,MAAS;EACpB,QAAQ,MAAU;EACnB,CAAC;CAEF,MAAM,cAAc,QAAQ;CAE5B,MAAMC,QAAoC;EACxC,GAAG;EACH,aAAa,YAAY,QAAQ,SAAS;EAC1C;EACO;EAEP,iBAAiB,SAAyB;AAExC,UADe,YAAY,QAAQ,MAAM,MAAM,EAAE,SAAS,KAAK,EAChD,SAAS,KAAK,aAAa;;EAG5C,gBAAgB,SAA0B;AACxC,UAAO,YAAY,QAAQ,MAAM,MAAM,EAAE,SAAS,KAAK;;EAGzD,oBAAoB,SAAyB;AAE3C,OAAI,YAAY,YAAY,MAC1B,QAAO,YAAY,UAAU;AAG/B,UAAO,YAAY;;EAEtB;AAED,QACE,oBAAC,sBAAsB;EAAgB;EACpC;GAC8B;;;;;;AAqDrC,SAAgB,wBAA2D;AACzE,QAAO,WAAW,sBAAsB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"locale-scope.mjs","names":["React"],"sources":["../../../src/client/runtime/locale-scope.tsx"],"sourcesContent":["/**\n * LocaleScope Context\n *\n * Provides scoped locale state for nested forms (e.g., ResourceSheet).\n * When a component is wrapped in LocaleScopeProvider, locale changes\n * affect only that scope, not the global content locale.\n *\n * @example\n * ```tsx\n * // In ResourceSheet - creates isolated locale scope\n * <LocaleScopeProvider>\n * <FormView ... />\n * </LocaleScopeProvider>\n *\n * // In FieldWrapper - uses scoped locale if available\n * const { locale, setLocale } = useScopedLocale();\n * ```\n */\n\nimport * as React from \"react\";\nimport {\n selectContentLocale,\n selectSetContentLocale,\n useAdminStore,\n} from \"./index\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\ninterface LocaleScopeContextValue {\n /** Current locale in this scope */\n locale: string;\n /** Set locale for this scope only */\n setLocale: (locale: string) => void;\n /** Whether we're in a scoped context (nested form) */\n isScoped: boolean;\n}\n\n// ============================================================================\n// Context\n// ============================================================================\n\nconst LocaleScopeContext = React.createContext<LocaleScopeContextValue | null>(\n null,\n);\n\n// ============================================================================\n// Provider\n// ============================================================================\n\ninterface LocaleScopeProviderProps {\n children: React.ReactNode;\n /** Initial locale (defaults to current global content locale) */\n initialLocale?: string;\n}\n\n/**\n * Provides an isolated locale scope for nested forms.\n * Locale changes inside this provider don't affect the global state.\n */\nexport function LocaleScopeProvider({\n children,\n initialLocale,\n}: LocaleScopeProviderProps) {\n const globalLocale = useAdminStore(selectContentLocale);\n const [scopedLocale, setScopedLocale] = React.useState(\n initialLocale ?? globalLocale,\n );\n\n // Sync with global locale on mount or when global changes (only if not yet modified)\n const hasModifiedRef = React.useRef(false);\n React.useEffect(() => {\n if (!hasModifiedRef.current) {\n setScopedLocale(globalLocale);\n }\n }, [globalLocale]);\n\n const setLocale = React.useCallback((locale: string) => {\n hasModifiedRef.current = true;\n setScopedLocale(locale);\n }, []);\n\n const value = React.useMemo<LocaleScopeContextValue>(\n () => ({\n locale: scopedLocale,\n setLocale,\n isScoped: true,\n }),\n [scopedLocale, setLocale],\n );\n\n return (\n <LocaleScopeContext.Provider value={value}>\n {children}\n </LocaleScopeContext.Provider>\n );\n}\n\n// ============================================================================\n// Hooks\n// ============================================================================\n\n/**\n * Returns scoped locale if in a LocaleScopeProvider, otherwise global locale.\n * Use this in components that need locale-aware behavior (FieldWrapper, FormView).\n */\nexport function useScopedLocale(): LocaleScopeContextValue {\n const scopedContext = React.useContext(LocaleScopeContext);\n const globalLocale = useAdminStore(selectContentLocale);\n const globalSetLocale = useAdminStore(selectSetContentLocale);\n\n // If we're in a scoped context, use that\n if (scopedContext) {\n return scopedContext;\n }\n\n // Otherwise, use global locale\n return {\n locale: globalLocale,\n setLocale: globalSetLocale,\n isScoped: false,\n };\n}\n\n/**\n * Returns true if we're currently in a scoped locale context (nested form).\n */\nexport function useIsLocaleScopeActive(): boolean {\n const scopedContext = React.useContext(LocaleScopeContext);\n return scopedContext !== null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA2CA,MAAM,qBAAqBA,QAAM,cAC/B,KACD;;;;;AAgBD,SAAgB,oBAAoB,EAClC,UACA,iBAC2B;CAC3B,MAAM,eAAe,cAAc,oBAAoB;CACvD,MAAM,CAAC,cAAc,mBAAmBA,QAAM,SAC5C,iBAAiB,aAClB;CAGD,MAAM,iBAAiBA,QAAM,OAAO,MAAM;AAC1C,SAAM,gBAAgB;AACpB,MAAI,CAAC,eAAe,QAClB,iBAAgB,aAAa;IAE9B,CAAC,aAAa,CAAC;CAElB,MAAM,YAAYA,QAAM,aAAa,WAAmB;AACtD,iBAAe,UAAU;AACzB,kBAAgB,OAAO;IACtB,EAAE,CAAC;CAEN,MAAM,QAAQA,QAAM,eACX;EACL,QAAQ;EACR;EACA,UAAU;EACX,GACD,CAAC,cAAc,UAAU,CAC1B;AAED,QACE,oBAAC,mBAAmB;EAAgB;EACjC;GAC2B;;;;;;AAYlC,SAAgB,kBAA2C;CACzD,MAAM,gBAAgBA,QAAM,WAAW,mBAAmB;CAC1D,MAAM,eAAe,cAAc,oBAAoB;CACvD,MAAM,kBAAkB,cAAc,uBAAuB;AAG7D,KAAI,cACF,QAAO;AAIT,QAAO;EACL,QAAQ;EACR,WAAW;EACX,UAAU;EACX"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.mts","names":[],"sources":["../../../src/client/runtime/provider.tsx"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;UAoFiB,UAAA;SAER;UACC,uBAAuB;;;;;;;;EAHhB,gBAAU,EAAA,CAAA,MAAA,EAAA,MAAA,EAAA,GAAA,IAAA;EAElB,UAAA,EAeK,eAfL,EAAA;EACwB,SAAA,EAAA,MAAA;;AAcnB,KAIF,UAAA,GAAa,UAJX,CAAA,OAI6B,gBAJ7B,CAAA;UAUJ,qBAAA,CAVmB;EAIjB,KAAA,EAOH,KAPG;EAMF,MAAA,EAEA,cAFA,CAAA,GAAqB,CAAA;EAYtB,UAAA,EAAA,GAAA,GAAA,IAAgB;EACvB,QAAA,EAAA,MAAA;EACA,QAAA,EAAA,CAAA,IAAA,EAAA,MAAA,EAAA,GAAA,IAAA;EACA,QAAA,EAAA;IACA,OAAA,EAAA,OAAA;EACA,CAAA;EACA,oBAAA,EAAA,MAAA;;iBANO,gBAAA,CAQN;EAAA,KAAA;EAAA,MAAA;EAAA,UAAA;EAAA,QAAA;EAAA,QAAA;EAAA,QAAA;EAAA;AAAA,CAAA,EAAA,qBAAA,CAAA,EAAqB,QAAA,CAAA,QAArB,CAAqB,UAArB,CAAA;AAAqB,UAsCP,kBAAA,CAtCO;EAAA;;AAsCxB;;EAUU,KAAA,EALD,UAKC,CAAA,GAAA,CAAA;EAiDM;;;EA0CJ,MAAA,EA3FF,cA2FE,CAAA,GAAA,CAAA;EAAS;AA4GrB;;EAEE,UAAA,CAAA,EAAA,GAAA;EACA;;;EAGU,QAAA,CAAA,EAAA,MAAA;EACV;;;;;;;;;AA4JF;;EAAkE,QAAA,CAAA,EAAA,OAAA,GAAA;IAAI,OAAA,CAAA,EAAA,OAAA;EAAC,CAAA;EAsC1D;;;EAA4B,QAAA,CAAA,EAAA,CAAA,IAAA,EAAA,MAAA,EAAA,GAAA,IAAA;EAAA;;;;EAAA,eAAA,CAAA,EAAA,MAAA;EAAA;;;;EAG5B,oBAA0C,CAAA,EAAA,MAAA;EAAvB;;;gBAlWhB;;;;;;gBAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;yBA8BS;;;;YAKb;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4GI,aAAA;SACP;;;;;YAKG;;;eAGG;;;;GAIZ,qBAAqB;;;;;;;;;;;;;;;;;;;iBAsJR,mCAAmC,eAAe,IAAI;;cAsCzD,iBAAkB,eAAU,MAAA,uBAAA,kBAAA,EAAA,sBAAA,EAAA,qBAAA,EAAA,qBAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,kBAAA,EAAA,eAAA;;cAG5B,kBAAmB,eAAU,6BAAA;UAAA,aAAA,CAAA,YAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YA1Z7B,SAAA,QAAA,0BAAA,CAAA,MAAA,EAAA,OAAA,CAAA;YAAA,SAAA,UAAA,0BAAA,CAAA,MAAA,EAAA,OAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;UAyEH,KAAA,EAAA;YAAA,SAAA,EAAA,0BAAA,CAAA,MAAA,EAAA,OAAA,CAAA;YAAA,SAAA,EAAA,0BAAA,CAAA,MAAA,EAAA,OAAA,CAAA;YAAA,SAAA,EAAA,0BAAA,CAAA,MAAA,EAAA,EAAA,OAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAiVgC,EAAA,0BAAA,CAAA,OAAA,EAAA,OAAA,CAAA;cAAA,KAAA,0BAAA,CAAA,OAAA,EAAA,OAAA,CAAA;cAAA,MAAA,0BAAA,CAAA,OAAA,EAAA,OAAA,CAAA;cAMiB,OAAzB,0BAAU,CAAA,OAAA,EAAA,OAAA,CAAA;cAGe,MAAzB,0BAAU,CAAA,OAAA,EAAA,OAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCAna/B;gBAAA,cAAA,CAAA,aAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0EAyEH,sBAAA,aAAA,kBAAA,cAAA,CAAA;;;;;;;;;;;;uBAAA,cAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAuVG,oBAAqB;;cAGrB,oBAAqB"}
|