@nextsparkjs/core 0.1.0-beta.187 → 0.1.0-beta.189
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/dist/components/api/keys/ApiKeyDisplay.js +19 -19
- package/dist/components/api/keys/CreateApiKeyDialog.js +21 -21
- package/dist/components/app/layouts/PublicNavbar.d.ts.map +1 -1
- package/dist/components/app/layouts/PublicNavbar.js +34 -16
- package/dist/components/app/misc/ThemeToggle.d.ts.map +1 -1
- package/dist/components/app/misc/ThemeToggle.js +3 -4
- package/dist/components/auth/SessionCookieRefresher.d.ts +5 -0
- package/dist/components/auth/SessionCookieRefresher.d.ts.map +1 -1
- package/dist/components/auth/SessionCookieRefresher.js +7 -1
- package/dist/components/auth/forms/LoginForm.d.ts.map +1 -1
- package/dist/components/auth/forms/LoginForm.js +49 -12
- package/dist/components/auth/forms/SignupForm.d.ts.map +1 -1
- package/dist/components/auth/forms/SignupForm.js +4 -3
- package/dist/components/dashboard/block-editor/block-settings-panel.js +1 -1
- package/dist/components/dashboard/block-editor/floating-block-toolbar.js +1 -1
- package/dist/components/dashboard/block-editor/sortable-block.js +1 -1
- package/dist/components/dashboard/layouts/Sidebar.d.ts.map +1 -1
- package/dist/components/dashboard/layouts/Sidebar.js +8 -6
- package/dist/components/dashboard/layouts/TopNavbar.d.ts.map +1 -1
- package/dist/components/dashboard/layouts/TopNavbar.js +51 -54
- package/dist/components/dashboard/misc/NotificationsDropdown.d.ts.map +1 -1
- package/dist/components/dashboard/misc/NotificationsDropdown.js +17 -15
- package/dist/components/dashboard/misc/SearchDropdown.d.ts.map +1 -1
- package/dist/components/dashboard/misc/SearchDropdown.js +19 -22
- package/dist/components/dashboard/mobile/MobileBottomNav.js +1 -1
- package/dist/components/dashboard/mobile/MobileTopBar.d.ts +10 -1
- package/dist/components/dashboard/mobile/MobileTopBar.d.ts.map +1 -1
- package/dist/components/dashboard/mobile/MobileTopBar.js +4 -3
- package/dist/components/dashboard/navigation/DynamicNavigation.js +5 -5
- package/dist/components/devtools/BlockDetailViewer.js +1 -1
- package/dist/components/devtools/BlocksViewer.js +1 -1
- package/dist/components/entities/EntityChildManager.js +5 -5
- package/dist/components/entities/EntityDetailPage.d.ts.map +1 -1
- package/dist/components/entities/EntityDetailPage.js +16 -15
- package/dist/components/entities/EntityFieldRenderer.d.ts.map +1 -1
- package/dist/components/entities/EntityFieldRenderer.js +12 -7
- package/dist/components/entities/EntityPageHeader.js +5 -5
- package/dist/components/entities/ErrorBoundary.d.ts.map +1 -1
- package/dist/components/entities/ErrorBoundary.js +20 -21
- package/dist/components/entities/wrappers/EntityDetailWrapper.js +5 -5
- package/dist/components/entities/wrappers/EntityFormWrapper.js +2 -2
- package/dist/components/entities/wrappers/EntityListWrapper.js +3 -3
- package/dist/components/permissions/NoPermission.js +10 -10
- package/dist/components/public/pageBuilder/PageRenderer.d.ts.map +1 -1
- package/dist/components/public/pageBuilder/PageRenderer.js +2 -1
- package/dist/components/settings/SettingsPageSkeleton.js +4 -4
- package/dist/components/settings/layouts/SettingsSidebar.js +6 -6
- package/dist/components/shared/MultiSelectFilter.d.ts +3 -1
- package/dist/components/shared/MultiSelectFilter.d.ts.map +1 -1
- package/dist/components/shared/MultiSelectFilter.js +7 -3
- package/dist/components/shared/SearchInput.d.ts +2 -0
- package/dist/components/shared/SearchInput.d.ts.map +1 -1
- package/dist/components/shared/SearchInput.js +64 -6
- package/dist/components/ui/address-input.js +18 -18
- package/dist/components/ui/audio-upload.js +9 -9
- package/dist/components/ui/combobox.d.ts.map +1 -1
- package/dist/components/ui/combobox.js +4 -4
- package/dist/components/ui/country-select.d.ts.map +1 -1
- package/dist/components/ui/country-select.js +3 -3
- package/dist/components/ui/currency-select.d.ts.map +1 -1
- package/dist/components/ui/currency-select.js +3 -3
- package/dist/components/ui/dynamic-icon.d.ts.map +1 -1
- package/dist/components/ui/dynamic-icon.js +3 -2
- package/dist/components/ui/file-upload.js +7 -7
- package/dist/components/ui/image-upload.js +8 -8
- package/dist/components/ui/multi-select.d.ts +2 -1
- package/dist/components/ui/multi-select.d.ts.map +1 -1
- package/dist/components/ui/multi-select.js +4 -3
- package/dist/components/ui/phone-input.d.ts.map +1 -1
- package/dist/components/ui/phone-input.js +3 -3
- package/dist/components/ui/relation-display.js +1 -1
- package/dist/components/ui/simple-relation-select.d.ts +2 -1
- package/dist/components/ui/simple-relation-select.d.ts.map +1 -1
- package/dist/components/ui/simple-relation-select.js +7 -6
- package/dist/components/ui/tags-input.d.ts.map +1 -1
- package/dist/components/ui/tags-input.js +1 -1
- package/dist/components/ui/timezone-select.d.ts.map +1 -1
- package/dist/components/ui/timezone-select.js +3 -3
- package/dist/components/ui/user-display.js +4 -4
- package/dist/components/ui/user-select.d.ts.map +1 -1
- package/dist/components/ui/user-select.js +9 -9
- package/dist/components/ui/video-upload.js +9 -9
- package/dist/contexts/SubscriptionContext.d.ts.map +1 -1
- package/dist/contexts/SubscriptionContext.js +5 -1
- package/dist/contexts/TeamContext.d.ts.map +1 -1
- package/dist/contexts/TeamContext.js +83 -26
- package/dist/emails/otp-verification.d.ts.map +1 -1
- package/dist/emails/otp-verification.js +3 -2
- package/dist/hooks/useAccountPreferencesSync.d.ts +13 -0
- package/dist/hooks/useAccountPreferencesSync.d.ts.map +1 -0
- package/dist/hooks/useAccountPreferencesSync.js +95 -0
- package/dist/hooks/useAuth.d.ts +202 -15
- package/dist/hooks/useAuth.d.ts.map +1 -1
- package/dist/hooks/useAuth.js +49 -13
- package/dist/hooks/useEntityConfig.js +2 -2
- package/dist/hooks/useEntitySearch.js +10 -10
- package/dist/hooks/useNotifications.js +12 -12
- package/dist/hooks/usePrefetch.d.ts.map +1 -1
- package/dist/hooks/usePrefetch.js +6 -2
- package/dist/hooks/useSearch.js +15 -15
- package/dist/hooks/useSessionCookieRefresh.d.ts +18 -1
- package/dist/hooks/useSessionCookieRefresh.d.ts.map +1 -1
- package/dist/hooks/useSessionCookieRefresh.js +17 -4
- package/dist/hooks/useSessionHint.d.ts +12 -0
- package/dist/hooks/useSessionHint.d.ts.map +1 -0
- package/dist/hooks/useSessionHint.js +15 -0
- package/dist/hooks/useTranslationPreload.js +6 -6
- package/dist/i18n.d.ts +13 -0
- package/dist/i18n.d.ts.map +1 -1
- package/dist/i18n.js +2 -27
- package/dist/lib/actions/entity.actions.d.ts.map +1 -1
- package/dist/lib/actions/entity.actions.js +3 -2
- package/dist/lib/api/auth/dual-auth.d.ts +4 -1
- package/dist/lib/api/auth/dual-auth.d.ts.map +1 -1
- package/dist/lib/api/auth/dual-auth.js +5 -16
- package/dist/lib/api/entities.js +33 -33
- package/dist/lib/api/keys.d.ts +27 -27
- package/dist/lib/api/keys.js +27 -27
- package/dist/lib/auth/callback-url.d.ts +11 -0
- package/dist/lib/auth/callback-url.d.ts.map +1 -0
- package/dist/lib/auth/callback-url.js +14 -0
- package/dist/lib/auth/otp-config.d.ts +55 -0
- package/dist/lib/auth/otp-config.d.ts.map +1 -0
- package/dist/lib/auth/otp-config.js +48 -0
- package/dist/lib/auth/registration-helpers.d.ts.map +1 -1
- package/dist/lib/auth/registration-helpers.js +3 -1
- package/dist/lib/auth/session-hint.d.ts +31 -0
- package/dist/lib/auth/session-hint.d.ts.map +1 -0
- package/dist/lib/auth/session-hint.js +37 -0
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/auth.js +6 -4
- package/dist/lib/blocks/loader.d.ts +3 -11
- package/dist/lib/blocks/loader.d.ts.map +1 -1
- package/dist/lib/blocks/loader.js +1 -9
- package/dist/lib/blocks/loader.server.d.ts +18 -0
- package/dist/lib/blocks/loader.server.d.ts.map +1 -0
- package/dist/lib/blocks/loader.server.js +11 -0
- package/dist/lib/blocks/sanitize-html.d.ts +31 -0
- package/dist/lib/blocks/sanitize-html.d.ts.map +1 -0
- package/dist/lib/blocks/sanitize-html.js +60 -0
- package/dist/lib/config/config-sync.d.ts +1 -0
- package/dist/lib/config/config-sync.d.ts.map +1 -1
- package/dist/lib/config/config-sync.js +4 -1
- package/dist/lib/config/types.d.ts +48 -0
- package/dist/lib/config/types.d.ts.map +1 -1
- package/dist/lib/email/types.d.ts +6 -0
- package/dist/lib/email/types.d.ts.map +1 -1
- package/dist/lib/entities/serialization.d.ts.map +1 -1
- package/dist/lib/entities/serialization.js +3 -6
- package/dist/lib/icons.d.ts +12 -0
- package/dist/lib/icons.d.ts.map +1 -0
- package/dist/lib/icons.js +30 -0
- package/dist/lib/locale.d.ts +25 -1
- package/dist/lib/locale.d.ts.map +1 -1
- package/dist/lib/locale.js +49 -35
- package/dist/lib/mcp/engine.js +1 -1
- package/dist/lib/mcp/errors.js +17 -17
- package/dist/lib/mcp/schema-builder.js +16 -16
- package/dist/lib/mcp/tool-generator.js +18 -18
- package/dist/lib/search-highlighting.d.ts +7 -0
- package/dist/lib/search-highlighting.d.ts.map +1 -1
- package/dist/lib/search-highlighting.js +6 -2
- package/dist/lib/selectors/core-selectors.d.ts +2 -0
- package/dist/lib/selectors/core-selectors.d.ts.map +1 -1
- package/dist/lib/selectors/domains/auth.selectors.d.ts +1 -0
- package/dist/lib/selectors/domains/auth.selectors.d.ts.map +1 -1
- package/dist/lib/selectors/domains/auth.selectors.js +1 -0
- package/dist/lib/selectors/domains/entities.selectors.d.ts +2 -0
- package/dist/lib/selectors/domains/entities.selectors.d.ts.map +1 -1
- package/dist/lib/selectors/domains/entities.selectors.js +2 -0
- package/dist/lib/selectors/selectors.d.ts +4 -0
- package/dist/lib/selectors/selectors.d.ts.map +1 -1
- package/dist/lib/services/block.service.js +1 -1
- package/dist/lib/teams/active-team-cookie.d.ts +24 -0
- package/dist/lib/teams/active-team-cookie.d.ts.map +1 -0
- package/dist/lib/teams/active-team-cookie.js +17 -0
- package/dist/lib/teams/dashboard-team.d.ts +20 -0
- package/dist/lib/teams/dashboard-team.d.ts.map +1 -0
- package/dist/lib/teams/dashboard-team.js +38 -0
- package/dist/lib/teams/schema.d.ts.map +1 -1
- package/dist/lib/teams/schema.js +1 -1
- package/dist/lib/template-resolver.d.ts.map +1 -1
- package/dist/lib/template-resolver.js +0 -1
- package/dist/lib/theme/get-default-theme-mode.d.ts +7 -4
- package/dist/lib/theme/get-default-theme-mode.d.ts.map +1 -1
- package/dist/lib/theme/get-default-theme-mode.js +2 -44
- package/dist/messages/de/auth.json +4 -2
- package/dist/messages/de/common.json +83 -3
- package/dist/messages/de/email.json +1 -1
- package/dist/messages/de/index.d.ts +87 -0
- package/dist/messages/de/index.d.ts.map +1 -1
- package/dist/messages/de/settings.json +5 -0
- package/dist/messages/en/auth.json +4 -2
- package/dist/messages/en/common.json +83 -3
- package/dist/messages/en/email.json +1 -1
- package/dist/messages/en/index.d.ts +86 -0
- package/dist/messages/en/index.d.ts.map +1 -1
- package/dist/messages/en/settings.json +4 -0
- package/dist/messages/es/auth.json +4 -2
- package/dist/messages/es/common.json +83 -3
- package/dist/messages/es/email.json +1 -1
- package/dist/messages/es/index.d.ts +86 -0
- package/dist/messages/es/index.d.ts.map +1 -1
- package/dist/messages/es/settings.json +4 -0
- package/dist/messages/fr/auth.json +4 -2
- package/dist/messages/fr/common.json +83 -3
- package/dist/messages/fr/email.json +1 -1
- package/dist/messages/fr/index.d.ts +87 -0
- package/dist/messages/fr/index.d.ts.map +1 -1
- package/dist/messages/fr/settings.json +5 -0
- package/dist/messages/it/auth.json +4 -2
- package/dist/messages/it/common.json +83 -3
- package/dist/messages/it/email.json +1 -1
- package/dist/messages/it/index.d.ts +87 -0
- package/dist/messages/it/index.d.ts.map +1 -1
- package/dist/messages/it/settings.json +5 -0
- package/dist/messages/pt/auth.json +4 -2
- package/dist/messages/pt/common.json +83 -3
- package/dist/messages/pt/email.json +1 -1
- package/dist/messages/pt/index.d.ts +87 -0
- package/dist/messages/pt/index.d.ts.map +1 -1
- package/dist/messages/pt/settings.json +5 -0
- package/dist/nextspark-registries.d.ts +54 -0
- package/dist/providers/DashboardProviders.d.ts +13 -10
- package/dist/providers/DashboardProviders.d.ts.map +1 -1
- package/dist/providers/DashboardProviders.js +7 -1
- package/dist/templates/app/(auth)/forgot-password/page.tsx +2 -2
- package/dist/templates/app/(auth)/reset-password/page.tsx +6 -6
- package/dist/templates/app/403/page.tsx +6 -6
- package/dist/templates/app/api/v1/teams/switch/route.ts +24 -5
- package/dist/templates/app/dashboard/(main)/[entity]/layout.tsx +9 -7
- package/dist/templates/app/dashboard/(main)/layout.tsx +4 -3
- package/dist/templates/app/dashboard/settings/api-keys/page.tsx +36 -34
- package/dist/templates/app/dashboard/settings/profile/page.tsx +7 -6
- package/dist/templates/app/dashboard/settings/security/page.tsx +5 -4
- package/dist/templates/app/layout.ppr.tsx +8 -8
- package/dist/templates/app/layout.tsx +12 -17
- package/dist/templates/blocks/cta-section/component.tsx +5 -2
- package/dist/templates/blocks/cta-section/config.ts +3 -2
- package/dist/templates/blocks/cta-section/fields.ts +2 -2
- package/dist/templates/blocks/cta-section/schema.ts +2 -2
- package/dist/templates/blocks/features-grid/component.tsx +10 -2
- package/dist/templates/blocks/features-grid/config.ts +3 -2
- package/dist/templates/blocks/features-grid/fields.ts +2 -2
- package/dist/templates/blocks/features-grid/schema.ts +2 -2
- package/dist/templates/blocks/hero/component.tsx +6 -3
- package/dist/templates/blocks/hero/config.ts +3 -2
- package/dist/templates/blocks/hero/fields.ts +2 -2
- package/dist/templates/blocks/hero/schema.ts +2 -2
- package/dist/templates/blocks/testimonials/component.tsx +6 -3
- package/dist/templates/blocks/testimonials/config.ts +3 -2
- package/dist/templates/blocks/testimonials/fields.ts +2 -2
- package/dist/templates/blocks/testimonials/schema.ts +2 -2
- package/dist/templates/blocks/text-content/component.tsx +7 -3
- package/dist/templates/blocks/text-content/config.ts +3 -2
- package/dist/templates/blocks/text-content/fields.ts +2 -2
- package/dist/templates/blocks/text-content/schema.ts +2 -2
- package/dist/templates/contents/themes/starter/blocks/cta-section/component.tsx +102 -0
- package/dist/templates/contents/themes/starter/blocks/cta-section/config.ts +11 -0
- package/dist/templates/contents/themes/starter/blocks/cta-section/fields.ts +89 -0
- package/dist/templates/contents/themes/starter/blocks/cta-section/index.ts +6 -0
- package/dist/templates/contents/themes/starter/blocks/cta-section/schema.ts +32 -0
- package/dist/templates/contents/themes/starter/blocks/cta-section/thumbnail.png +0 -0
- package/dist/templates/contents/themes/starter/blocks/features-grid/component.tsx +119 -0
- package/dist/templates/contents/themes/starter/blocks/features-grid/config.ts +11 -0
- package/dist/templates/contents/themes/starter/blocks/features-grid/fields.ts +97 -0
- package/dist/templates/contents/themes/starter/blocks/features-grid/index.ts +6 -0
- package/dist/templates/contents/themes/starter/blocks/features-grid/schema.ts +40 -0
- package/dist/templates/contents/themes/starter/blocks/features-grid/thumbnail.png +0 -0
- package/dist/templates/contents/themes/starter/blocks/hero/component.tsx +105 -0
- package/dist/templates/contents/themes/starter/blocks/hero/config.ts +11 -0
- package/dist/templates/contents/themes/starter/blocks/hero/fields.ts +60 -0
- package/dist/templates/contents/themes/starter/blocks/hero/index.ts +6 -0
- package/dist/templates/contents/themes/starter/blocks/hero/schema.ts +33 -0
- package/dist/templates/contents/themes/starter/blocks/hero/thumbnail.png +0 -0
- package/dist/templates/contents/themes/starter/blocks/testimonials/component.tsx +116 -0
- package/dist/templates/contents/themes/starter/blocks/testimonials/config.ts +11 -0
- package/dist/templates/contents/themes/starter/blocks/testimonials/fields.ts +105 -0
- package/dist/templates/contents/themes/starter/blocks/testimonials/index.ts +6 -0
- package/dist/templates/contents/themes/starter/blocks/testimonials/schema.ts +41 -0
- package/dist/templates/contents/themes/starter/blocks/testimonials/thumbnail.png +0 -0
- package/dist/templates/contents/themes/starter/blocks/text-content/component.tsx +100 -0
- package/dist/templates/contents/themes/starter/blocks/text-content/config.ts +11 -0
- package/dist/templates/contents/themes/starter/blocks/text-content/fields.ts +88 -0
- package/dist/templates/contents/themes/starter/blocks/text-content/index.ts +6 -0
- package/dist/templates/contents/themes/starter/blocks/text-content/schema.ts +30 -0
- package/dist/templates/contents/themes/starter/blocks/text-content/thumbnail.png +0 -0
- package/dist/templates/contents/themes/starter/config/app.config.ts +8 -0
- package/dist/templates/contents/themes/starter/entities/tasks/tasks.config.ts +7 -0
- package/dist/templates/contents/themes/starter/tests/cypress/e2e/_utils/devtools/access.cy.ts +9 -1
- package/dist/templates/contents/themes/starter/tests/cypress/e2e/api/entities/tasks/TaskAPIController.js +2 -2
- package/dist/templates/contents/themes/starter/tests/cypress/e2e/uat/entities/tasks/tasks-crud.cy.ts +45 -38
- package/dist/templates/contents/themes/starter/tests/cypress/fixtures/entities.json +16 -0
- package/dist/templates/contents/themes/starter/tests/cypress/src/components/DevKeyringPOM.ts +3 -1
- package/dist/templates/contents/themes/starter/tests/cypress/src/core/BlockEditorBasePOM.ts +3 -3
- package/dist/templates/contents/themes/starter/tests/cypress/src/entities/PagesPOM.ts +137 -0
- package/dist/templates/contents/themes/starter/tests/cypress/src/entities/index.ts +2 -0
- package/dist/templates/contents/themes/starter/tests/cypress/src/index.ts +1 -0
- package/dist/templates/contents/themes/starter/tests/cypress/src/session-helpers.ts +42 -11
- package/dist/templates/contents/themes/starter/tests/cypress/support/commands.ts +29 -18
- package/dist/templates/features/blog/blocks/post-content/component.tsx +5 -1
- package/dist/templates/features/blog/blocks/post-content/schema.ts +1 -1
- package/dist/templates/features/pages/blocks/hero/component.tsx +3 -0
- package/dist/templates/features/pages/blocks/hero/schema.ts +1 -1
- package/dist/templates/proxy.ts +138 -53
- package/dist/types/blocks.d.ts.map +1 -1
- package/dist/types/blocks.js +1 -1
- package/dist/types/task.types.d.ts +1 -1
- package/dist/types/task.types.js +7 -7
- package/dist/utils/dev/TranslationDebugger.js +2 -2
- package/package.json +14 -5
- package/scripts/build/registry/__tests__/block-registry.test.mjs +73 -0
- package/scripts/build/registry/__tests__/icons-discovery.test.mjs +130 -0
- package/scripts/build/registry/__tests__/identifier.test.mjs +65 -0
- package/scripts/build/registry/__tests__/page-generator.test.mjs +430 -0
- package/scripts/build/registry/__tests__/scheduled-actions-registry.test.mjs +41 -0
- package/scripts/build/registry/__tests__/template-registry.test.mjs +89 -0
- package/scripts/build/registry/discovery/icons.mjs +275 -0
- package/scripts/build/registry/discovery/index.mjs +1 -0
- package/scripts/build/registry/generators/block-registry.mjs +203 -55
- package/scripts/build/registry/generators/feature-registry.mjs +9 -2
- package/scripts/build/registry/generators/icon-registry.mjs +56 -0
- package/scripts/build/registry/generators/identifier.mjs +28 -0
- package/scripts/build/registry/generators/index.mjs +1 -0
- package/scripts/build/registry/generators/plugin-registry.mjs +4 -3
- package/scripts/build/registry/generators/scheduled-actions-registry.mjs +4 -2
- package/scripts/build/registry/generators/template-registry.mjs +49 -41
- package/scripts/build/registry/generators/theme-registry.mjs +6 -7
- package/scripts/build/registry/post-build/page-generator.mjs +380 -59
- package/scripts/build/registry.mjs +9 -1
- package/templates/app/(auth)/forgot-password/page.tsx +2 -2
- package/templates/app/(auth)/reset-password/page.tsx +6 -6
- package/templates/app/403/page.tsx +6 -6
- package/templates/app/api/v1/teams/switch/route.ts +24 -5
- package/templates/app/dashboard/(main)/[entity]/layout.tsx +9 -7
- package/templates/app/dashboard/(main)/layout.tsx +4 -3
- package/templates/app/dashboard/settings/api-keys/page.tsx +36 -34
- package/templates/app/dashboard/settings/profile/page.tsx +7 -6
- package/templates/app/dashboard/settings/security/page.tsx +5 -4
- package/templates/app/layout.ppr.tsx +8 -8
- package/templates/app/layout.tsx +12 -17
- package/templates/blocks/cta-section/component.tsx +5 -2
- package/templates/blocks/cta-section/config.ts +3 -2
- package/templates/blocks/cta-section/fields.ts +2 -2
- package/templates/blocks/cta-section/schema.ts +2 -2
- package/templates/blocks/features-grid/component.tsx +10 -2
- package/templates/blocks/features-grid/config.ts +3 -2
- package/templates/blocks/features-grid/fields.ts +2 -2
- package/templates/blocks/features-grid/schema.ts +2 -2
- package/templates/blocks/hero/component.tsx +6 -3
- package/templates/blocks/hero/config.ts +3 -2
- package/templates/blocks/hero/fields.ts +2 -2
- package/templates/blocks/hero/schema.ts +2 -2
- package/templates/blocks/testimonials/component.tsx +6 -3
- package/templates/blocks/testimonials/config.ts +3 -2
- package/templates/blocks/testimonials/fields.ts +2 -2
- package/templates/blocks/testimonials/schema.ts +2 -2
- package/templates/blocks/text-content/component.tsx +7 -3
- package/templates/blocks/text-content/config.ts +3 -2
- package/templates/blocks/text-content/fields.ts +2 -2
- package/templates/blocks/text-content/schema.ts +2 -2
- package/templates/contents/themes/starter/blocks/cta-section/component.tsx +102 -0
- package/templates/contents/themes/starter/blocks/cta-section/config.ts +11 -0
- package/templates/contents/themes/starter/blocks/cta-section/fields.ts +89 -0
- package/templates/contents/themes/starter/blocks/cta-section/index.ts +6 -0
- package/templates/contents/themes/starter/blocks/cta-section/schema.ts +32 -0
- package/templates/contents/themes/starter/blocks/cta-section/thumbnail.png +0 -0
- package/templates/contents/themes/starter/blocks/features-grid/component.tsx +119 -0
- package/templates/contents/themes/starter/blocks/features-grid/config.ts +11 -0
- package/templates/contents/themes/starter/blocks/features-grid/fields.ts +97 -0
- package/templates/contents/themes/starter/blocks/features-grid/index.ts +6 -0
- package/templates/contents/themes/starter/blocks/features-grid/schema.ts +40 -0
- package/templates/contents/themes/starter/blocks/features-grid/thumbnail.png +0 -0
- package/templates/contents/themes/starter/blocks/hero/component.tsx +105 -0
- package/templates/contents/themes/starter/blocks/hero/config.ts +11 -0
- package/templates/contents/themes/starter/blocks/hero/fields.ts +60 -0
- package/templates/contents/themes/starter/blocks/hero/index.ts +6 -0
- package/templates/contents/themes/starter/blocks/hero/schema.ts +33 -0
- package/templates/contents/themes/starter/blocks/hero/thumbnail.png +0 -0
- package/templates/contents/themes/starter/blocks/testimonials/component.tsx +116 -0
- package/templates/contents/themes/starter/blocks/testimonials/config.ts +11 -0
- package/templates/contents/themes/starter/blocks/testimonials/fields.ts +105 -0
- package/templates/contents/themes/starter/blocks/testimonials/index.ts +6 -0
- package/templates/contents/themes/starter/blocks/testimonials/schema.ts +41 -0
- package/templates/contents/themes/starter/blocks/testimonials/thumbnail.png +0 -0
- package/templates/contents/themes/starter/blocks/text-content/component.tsx +100 -0
- package/templates/contents/themes/starter/blocks/text-content/config.ts +11 -0
- package/templates/contents/themes/starter/blocks/text-content/fields.ts +88 -0
- package/templates/contents/themes/starter/blocks/text-content/index.ts +6 -0
- package/templates/contents/themes/starter/blocks/text-content/schema.ts +30 -0
- package/templates/contents/themes/starter/blocks/text-content/thumbnail.png +0 -0
- package/templates/contents/themes/starter/config/app.config.ts +8 -0
- package/templates/contents/themes/starter/entities/tasks/tasks.config.ts +7 -0
- package/templates/contents/themes/starter/tests/cypress/e2e/_utils/devtools/access.cy.ts +9 -1
- package/templates/contents/themes/starter/tests/cypress/e2e/api/entities/tasks/TaskAPIController.js +2 -2
- package/templates/contents/themes/starter/tests/cypress/e2e/uat/entities/tasks/tasks-crud.cy.ts +45 -38
- package/templates/contents/themes/starter/tests/cypress/fixtures/entities.json +16 -0
- package/templates/contents/themes/starter/tests/cypress/src/components/DevKeyringPOM.ts +3 -1
- package/templates/contents/themes/starter/tests/cypress/src/core/BlockEditorBasePOM.ts +3 -3
- package/templates/contents/themes/starter/tests/cypress/src/entities/PagesPOM.ts +137 -0
- package/templates/contents/themes/starter/tests/cypress/src/entities/index.ts +2 -0
- package/templates/contents/themes/starter/tests/cypress/src/index.ts +1 -0
- package/templates/contents/themes/starter/tests/cypress/src/session-helpers.ts +42 -11
- package/templates/contents/themes/starter/tests/cypress/support/commands.ts +29 -18
- package/templates/features/blog/blocks/post-content/component.tsx +5 -1
- package/templates/features/blog/blocks/post-content/schema.ts +1 -1
- package/templates/features/pages/blocks/hero/component.tsx +3 -0
- package/templates/features/pages/blocks/hero/schema.ts +1 -1
- package/templates/proxy.ts +138 -53
- package/tests/jest/__mocks__/@nextsparkjs/registries/block-registry.client.ts +9 -0
- package/tests/jest/__mocks__/@nextsparkjs/registries/block-registry.lazy.ts +5 -0
- package/tests/jest/__mocks__/@nextsparkjs/registries/icon-registry.ts +42 -0
- package/tests/jest/__mocks__/next-intl-server.js +85 -5
- package/tests/jest/__mocks__/next-server.js +32 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Icon Discovery
|
|
3
|
+
*
|
|
4
|
+
* Collects every lucide-react icon name the app can ask for by string at
|
|
5
|
+
* runtime, so the generated icon registry can import exactly those and let
|
|
6
|
+
* the bundler drop the rest of the icon set.
|
|
7
|
+
*
|
|
8
|
+
* Sources are exactly what resolveIcon can be handed, and all of them are
|
|
9
|
+
* source files (never the database):
|
|
10
|
+
* - entity configs (`icon: Users` — an identifier imported from lucide-react)
|
|
11
|
+
* - a theme's app.config (`customSidebarSections[].icon` — a string)
|
|
12
|
+
* - block configs (`icon: 'Grid'` — the block's own icon in the editor)
|
|
13
|
+
*
|
|
14
|
+
* What a block RENDERS is not here: page content names those icons in the page
|
|
15
|
+
* builder, so they live in the database. Those blocks keep resolving through
|
|
16
|
+
* the lucide namespace — deliberately, see themes' features-grid component.
|
|
17
|
+
*
|
|
18
|
+
* @module core/scripts/build/registry/discovery/icons
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { readdir, readFile } from 'fs/promises'
|
|
22
|
+
import { existsSync } from 'fs'
|
|
23
|
+
import { createRequire } from 'module'
|
|
24
|
+
import { join, dirname } from 'path'
|
|
25
|
+
|
|
26
|
+
import { verbose, log } from '../../../utils/index.mjs'
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Icons the resolver falls back to when a name doesn't resolve. They are
|
|
30
|
+
* referenced from core components, not from any config, so nothing would
|
|
31
|
+
* discover them.
|
|
32
|
+
*/
|
|
33
|
+
const FALLBACK_ICONS = ['Box', 'Circle', 'Folder', 'LayoutGrid']
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Names lucide-react actually exports, read from its own barrel.
|
|
37
|
+
* A name that isn't there would become a broken named import in the
|
|
38
|
+
* generated registry, so unknown names are dropped with a warning instead.
|
|
39
|
+
* @param {object} config
|
|
40
|
+
* @returns {Set<string>|null} null when lucide-react can't be resolved
|
|
41
|
+
*/
|
|
42
|
+
async function readLucideExportNames(config) {
|
|
43
|
+
try {
|
|
44
|
+
const requireFromProject = createRequire(join(config.projectRoot, 'package.json'))
|
|
45
|
+
const pkgPath = requireFromProject.resolve('lucide-react/package.json')
|
|
46
|
+
const barrelPath = join(dirname(pkgPath), 'dist/esm/lucide-react.js')
|
|
47
|
+
|
|
48
|
+
if (!existsSync(barrelPath)) {
|
|
49
|
+
return null
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const barrel = await readFile(barrelPath, 'utf8')
|
|
53
|
+
const names = new Set()
|
|
54
|
+
for (const match of barrel.matchAll(/default as ([A-Za-z_$][\w$]*)/g)) {
|
|
55
|
+
names.add(match[1])
|
|
56
|
+
}
|
|
57
|
+
return names.size > 0 ? names : null
|
|
58
|
+
} catch {
|
|
59
|
+
return null
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Which config files hold icons resolveIcon can be handed. Exported for tests.
|
|
65
|
+
*
|
|
66
|
+
* Separators are normalised first: the generator also runs on Windows, where
|
|
67
|
+
* join() produces '\\' and a '/'-shaped match would silently find nothing —
|
|
68
|
+
* leaving a registry with only its fallbacks, and every entity icon rendering
|
|
69
|
+
* as a Box.
|
|
70
|
+
*/
|
|
71
|
+
export function isIconSourcePath(filePath) {
|
|
72
|
+
const normalised = filePath.replace(/\\/g, '/')
|
|
73
|
+
return (
|
|
74
|
+
(normalised.includes('/entities/') && normalised.endsWith('.config.ts')) ||
|
|
75
|
+
(normalised.includes('/blocks/') && normalised.endsWith('/config.ts')) ||
|
|
76
|
+
normalised.endsWith('/config/app.config.ts')
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Map of local name -> exported lucide name for a file's lucide imports.
|
|
82
|
+
* `import { Home as HouseIcon }` means the config's `icon: HouseIcon` is
|
|
83
|
+
* lucide's `Home`.
|
|
84
|
+
*/
|
|
85
|
+
function parseLucideImports(content) {
|
|
86
|
+
const imports = new Map()
|
|
87
|
+
|
|
88
|
+
for (const match of content.matchAll(/import\s*(?:type\s*)?\{([^}]*)\}\s*from\s*['"]lucide-react['"]/g)) {
|
|
89
|
+
for (const specifier of match[1].split(',')) {
|
|
90
|
+
const parts = specifier.trim().replace(/^type\s+/, '').split(/\s+as\s+/)
|
|
91
|
+
const exported = parts[0]?.trim()
|
|
92
|
+
const local = (parts[1] || parts[0])?.trim()
|
|
93
|
+
if (exported && local) {
|
|
94
|
+
imports.set(local, exported)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return imports
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Icon names referenced by a single config file. Exported for tests.
|
|
104
|
+
*/
|
|
105
|
+
export function extractIconNames(content) {
|
|
106
|
+
const lucideImports = parseLucideImports(content)
|
|
107
|
+
const names = []
|
|
108
|
+
|
|
109
|
+
// `icon: Users` or `'icon': Users` — only counts when the identifier came
|
|
110
|
+
// from lucide-react
|
|
111
|
+
for (const match of content.matchAll(/(?:\bicon|['"]icon['"])\s*:\s*([A-Za-z_$][\w$]*)/g)) {
|
|
112
|
+
const exported = lucideImports.get(match[1])
|
|
113
|
+
if (exported) {
|
|
114
|
+
names.push(exported)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// `icon: 'Users'` or `icon: 'pie-chart'` — a theme's sidebar sections and
|
|
119
|
+
// block configs use both spellings; the caller folds kebab-case into the
|
|
120
|
+
// lucide export name and validates the result against lucide's export list.
|
|
121
|
+
for (const match of content.matchAll(/(?:\bicon|['"]icon['"])\s*:\s*['"]([A-Za-z][\w$-]*)['"]/g)) {
|
|
122
|
+
names.push(match[1])
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return names
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Icon references in a config file that this build cannot turn into a name.
|
|
130
|
+
* Exported for tests.
|
|
131
|
+
*
|
|
132
|
+
* Only a direct named import of lucide-react and a string literal reach the
|
|
133
|
+
* registry. Anything else — a namespace access (`I.Users`), an identifier
|
|
134
|
+
* aliased through another module, a component of the project's own — is not
|
|
135
|
+
* resolvable by reading this file, so it never enters the registry and
|
|
136
|
+
* resolveIcon falls back. That is silent, hence the warning.
|
|
137
|
+
*/
|
|
138
|
+
export function findUnresolvedIconRefs(content) {
|
|
139
|
+
const lucideImports = parseLucideImports(content)
|
|
140
|
+
const unresolved = []
|
|
141
|
+
|
|
142
|
+
for (const match of content.matchAll(/(?:\bicon|['"]icon['"])\s*:\s*([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)/g)) {
|
|
143
|
+
const reference = match[1]
|
|
144
|
+
const isMember = reference.includes('.')
|
|
145
|
+
|
|
146
|
+
if (isMember || !lucideImports.has(reference)) {
|
|
147
|
+
unresolved.push(reference)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return unresolved
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async function collectConfigFiles(dir, matcher, found = []) {
|
|
155
|
+
if (!existsSync(dir)) {
|
|
156
|
+
return found
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
let entries
|
|
160
|
+
try {
|
|
161
|
+
entries = await readdir(dir, { withFileTypes: true })
|
|
162
|
+
} catch {
|
|
163
|
+
return found
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
for (const entry of entries) {
|
|
167
|
+
const entryPath = join(dir, entry.name)
|
|
168
|
+
if (entry.isDirectory()) {
|
|
169
|
+
if (entry.name === 'node_modules' || entry.name.startsWith('.')) continue
|
|
170
|
+
await collectConfigFiles(entryPath, matcher, found)
|
|
171
|
+
} else if (matcher(entryPath)) {
|
|
172
|
+
found.push(entryPath)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return found
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function coreEntitiesDir(config) {
|
|
180
|
+
if (config.isNpmMode) {
|
|
181
|
+
return join(config.projectRoot, 'node_modules/@nextsparkjs/core/src/entities')
|
|
182
|
+
}
|
|
183
|
+
if (config.isMonorepoMode && config.monorepoRoot) {
|
|
184
|
+
return join(config.monorepoRoot, 'packages/core/src/entities')
|
|
185
|
+
}
|
|
186
|
+
return join(config.projectRoot, 'packages/core/src/entities')
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Discover every icon name the runtime can look up by string.
|
|
191
|
+
* @param {Array} blocks - Blocks from block discovery (each with an `icon` name)
|
|
192
|
+
* @param {object} config - Configuration object from getConfig()
|
|
193
|
+
* @returns {Promise<string[]>} Sorted, de-duplicated, validated icon names
|
|
194
|
+
*/
|
|
195
|
+
export async function discoverIcons(blocks, config) {
|
|
196
|
+
const candidates = new Set(FALLBACK_ICONS)
|
|
197
|
+
|
|
198
|
+
// Only the configs whose icons reach resolveIcon. Widening this would put
|
|
199
|
+
// icons in the dashboard bundle that nothing can ask for.
|
|
200
|
+
const iconSources = [
|
|
201
|
+
...(await collectConfigFiles(coreEntitiesDir(config), isIconSourcePath)),
|
|
202
|
+
...(await collectConfigFiles(config.themesDir, isIconSourcePath)),
|
|
203
|
+
...(await collectConfigFiles(config.pluginsDir, isIconSourcePath))
|
|
204
|
+
]
|
|
205
|
+
|
|
206
|
+
const unresolved = []
|
|
207
|
+
|
|
208
|
+
for (const configPath of iconSources) {
|
|
209
|
+
try {
|
|
210
|
+
const content = await readFile(configPath, 'utf8')
|
|
211
|
+
for (const name of extractIconNames(content)) {
|
|
212
|
+
candidates.add(name)
|
|
213
|
+
}
|
|
214
|
+
for (const reference of findUnresolvedIconRefs(content)) {
|
|
215
|
+
unresolved.push({ configPath, reference })
|
|
216
|
+
}
|
|
217
|
+
} catch {
|
|
218
|
+
verbose(`[icons] Could not read ${configPath}`)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
for (const { configPath, reference } of unresolved) {
|
|
223
|
+
log(
|
|
224
|
+
`[icons] ${configPath.replace(config.projectRoot, '')}: cannot resolve \`icon: ${reference}\` at build time, so it is not in the registry and will render the fallback. Name it with a string, or import it directly from lucide-react.`,
|
|
225
|
+
'warning'
|
|
226
|
+
)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
for (const block of blocks || []) {
|
|
230
|
+
if (block.icon) {
|
|
231
|
+
candidates.add(block.icon)
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const known = await readLucideExportNames(config)
|
|
236
|
+
if (!known) {
|
|
237
|
+
// Every name becomes a named import, so a kebab-case one would emit
|
|
238
|
+
// `import { pie-chart }` and break the build. Without lucide's list there
|
|
239
|
+
// is nothing to fold them against, so they are dropped instead.
|
|
240
|
+
const importable = [...candidates].filter(name => /^[A-Za-z_$][\w$]*$/.test(name))
|
|
241
|
+
log('Could not read lucide-react exports; icon registry will include every importable name found', 'warning')
|
|
242
|
+
return importable.sort()
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Configs spell icons both ways: `CheckSquare` in entity configs, `pie-chart`
|
|
246
|
+
// in a theme's sidebar and block configs. The registry is keyed by the export
|
|
247
|
+
// name, so kebab-case names are folded into it rather than dropped.
|
|
248
|
+
const toPascalCase = name =>
|
|
249
|
+
name
|
|
250
|
+
.split(/[-_\s]+/)
|
|
251
|
+
.map(part => part.charAt(0).toUpperCase() + part.slice(1))
|
|
252
|
+
.join('')
|
|
253
|
+
|
|
254
|
+
const valid = []
|
|
255
|
+
const unknown = []
|
|
256
|
+
for (const name of candidates) {
|
|
257
|
+
if (known.has(name)) {
|
|
258
|
+
valid.push(name)
|
|
259
|
+
continue
|
|
260
|
+
}
|
|
261
|
+
const pascalCased = toPascalCase(name)
|
|
262
|
+
if (known.has(pascalCased)) {
|
|
263
|
+
valid.push(pascalCased)
|
|
264
|
+
continue
|
|
265
|
+
}
|
|
266
|
+
unknown.push(name)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (unknown.length > 0) {
|
|
270
|
+
log(`Icons not exported by lucide-react, skipped: ${[...new Set(unknown)].sort().join(', ')}`, 'warning')
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
verbose(`[icons] ${valid.length} icon(s) referenced by name`)
|
|
274
|
+
return [...new Set(valid)].sort()
|
|
275
|
+
}
|
|
@@ -13,6 +13,7 @@ export { discoverCoreEntities } from './core-entities.mjs'
|
|
|
13
13
|
export { discoverThemes, discoverThemeRouteFiles } from './themes.mjs'
|
|
14
14
|
export { discoverTemplates, discoverThemeTemplates } from './templates.mjs'
|
|
15
15
|
export { discoverBlocks } from './blocks.mjs'
|
|
16
|
+
export { discoverIcons } from './icons.mjs'
|
|
16
17
|
export { discoverMiddlewares } from './middlewares.mjs'
|
|
17
18
|
export { discoverPermissionsConfig } from './permissions.mjs'
|
|
18
19
|
export { discoverAuthConfig } from './auth.mjs'
|
|
@@ -1,14 +1,61 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Block Registry Generator
|
|
3
3
|
*
|
|
4
|
-
* Generates block-registry.ts
|
|
4
|
+
* Generates block-registry.ts, block-registry.client.ts and block-registry.lazy.ts
|
|
5
|
+
*
|
|
6
|
+
* The split is what keeps block components out of the browser bundle. A block
|
|
7
|
+
* component is a server component and may import server-only code; the editor,
|
|
8
|
+
* the picker and the devtools viewers are client components that only ever read
|
|
9
|
+
* the configs. Importing both from one module drags every component — and
|
|
10
|
+
* whatever it imports — into the client build, which fails outright when one of
|
|
11
|
+
* them is server-only.
|
|
5
12
|
*
|
|
6
13
|
* @module core/scripts/build/registry/generators/block-registry
|
|
7
14
|
*/
|
|
8
15
|
|
|
9
16
|
import { join } from 'path'
|
|
17
|
+
import { toSafeIdentifier } from './identifier.mjs'
|
|
10
18
|
import { convertCorePath } from '../config.mjs'
|
|
11
19
|
|
|
20
|
+
/**
|
|
21
|
+
* The registry entries both halves emit, so the configs cannot drift apart.
|
|
22
|
+
*
|
|
23
|
+
* @param {Array} blocks - Discovered blocks
|
|
24
|
+
* @returns {string} The entries, ready to sit inside the object literal
|
|
25
|
+
*/
|
|
26
|
+
function buildRegistryEntries(blocks) {
|
|
27
|
+
return blocks.map(block => {
|
|
28
|
+
|
|
29
|
+
const slugVar = toSafeIdentifier(block.slug)
|
|
30
|
+
const scopeValue = block.scope
|
|
31
|
+
? `[${block.scope.map(s => `'${s}'`).join(', ')}]`
|
|
32
|
+
: 'undefined'
|
|
33
|
+
const examplesValue = block.hasExamples ? `${slugVar}_examples` : '[]'
|
|
34
|
+
const allowInPatternsValue = block.allowInPatterns !== undefined
|
|
35
|
+
? block.allowInPatterns.toString()
|
|
36
|
+
: 'undefined'
|
|
37
|
+
|
|
38
|
+
return ` '${block.slug}': {
|
|
39
|
+
slug: '${block.slug}',
|
|
40
|
+
name: '${block.name}',
|
|
41
|
+
description: '${block.description}',
|
|
42
|
+
category: '${block.category}' as BlockCategory,
|
|
43
|
+
icon: '${block.icon}',
|
|
44
|
+
componentPath: '${block.paths.component}',
|
|
45
|
+
schemaPath: '${block.paths.schema}',
|
|
46
|
+
fieldsPath: '${block.paths.fields}',
|
|
47
|
+
thumbnail: ${block.paths.thumbnail ? `'${block.paths.thumbnail}'` : 'undefined'},
|
|
48
|
+
fieldDefinitions: ${slugVar}_fields,
|
|
49
|
+
examples: ${examplesValue},
|
|
50
|
+
scope: ${scopeValue},
|
|
51
|
+
allowInPatterns: ${allowInPatternsValue},
|
|
52
|
+
isCore: false,
|
|
53
|
+
source: 'theme' as const,
|
|
54
|
+
sourceId: '${block.themeName}'
|
|
55
|
+
}`
|
|
56
|
+
}).join(',\n')
|
|
57
|
+
}
|
|
58
|
+
|
|
12
59
|
/**
|
|
13
60
|
* Generate the block registry file
|
|
14
61
|
* @param {Array} blocks - Discovered blocks
|
|
@@ -56,11 +103,8 @@ type BlockConfig = {
|
|
|
56
103
|
replacedBy?: string
|
|
57
104
|
}
|
|
58
105
|
|
|
59
|
-
export
|
|
60
|
-
|
|
61
|
-
export const BLOCK_CATEGORIES: string[] = []
|
|
62
|
-
|
|
63
|
-
export const BLOCK_COMPONENTS: Record<string, React.LazyExoticComponent<React.ComponentType<unknown>>> = {}
|
|
106
|
+
export * from './block-registry.client'
|
|
107
|
+
export { BLOCK_COMPONENTS } from './block-registry.lazy'
|
|
64
108
|
|
|
65
109
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
66
110
|
export const BLOCK_COMPONENTS_SSR: Record<string, React.ComponentType<any>> = {}
|
|
@@ -80,7 +124,7 @@ export const BLOCK_METADATA = {
|
|
|
80
124
|
const ssrImports = []
|
|
81
125
|
|
|
82
126
|
blocks.forEach(block => {
|
|
83
|
-
const slugVar = block.slug
|
|
127
|
+
const slugVar = toSafeIdentifier(block.slug)
|
|
84
128
|
|
|
85
129
|
imports.push(`import { fieldDefinitions as ${slugVar}_fields } from '${block.paths.fields}'`)
|
|
86
130
|
ssrImports.push(`import { default as ${slugVar}_component } from '${block.paths.component}'`)
|
|
@@ -93,35 +137,7 @@ export const BLOCK_METADATA = {
|
|
|
93
137
|
const fieldImports = imports.join('\n')
|
|
94
138
|
const ssrComponentImports = ssrImports.join('\n')
|
|
95
139
|
|
|
96
|
-
const registryEntries = blocks
|
|
97
|
-
const slugVar = block.slug.replace(/-/g, '_')
|
|
98
|
-
const scopeValue = block.scope
|
|
99
|
-
? `[${block.scope.map(s => `'${s}'`).join(', ')}]`
|
|
100
|
-
: 'undefined'
|
|
101
|
-
const examplesValue = block.hasExamples ? `${slugVar}_examples` : '[]'
|
|
102
|
-
const allowInPatternsValue = block.allowInPatterns !== undefined
|
|
103
|
-
? block.allowInPatterns.toString()
|
|
104
|
-
: 'undefined'
|
|
105
|
-
|
|
106
|
-
return ` '${block.slug}': {
|
|
107
|
-
slug: '${block.slug}',
|
|
108
|
-
name: '${block.name}',
|
|
109
|
-
description: '${block.description}',
|
|
110
|
-
category: '${block.category}' as BlockCategory,
|
|
111
|
-
icon: '${block.icon}',
|
|
112
|
-
componentPath: '${block.paths.component}',
|
|
113
|
-
schemaPath: '${block.paths.schema}',
|
|
114
|
-
fieldsPath: '${block.paths.fields}',
|
|
115
|
-
thumbnail: ${block.paths.thumbnail ? `'${block.paths.thumbnail}'` : 'undefined'},
|
|
116
|
-
fieldDefinitions: ${slugVar}_fields,
|
|
117
|
-
examples: ${examplesValue},
|
|
118
|
-
scope: ${scopeValue},
|
|
119
|
-
allowInPatterns: ${allowInPatternsValue},
|
|
120
|
-
isCore: false,
|
|
121
|
-
source: 'theme' as const,
|
|
122
|
-
sourceId: '${block.themeName}'
|
|
123
|
-
}`
|
|
124
|
-
}).join(',\n')
|
|
140
|
+
const registryEntries = buildRegistryEntries(blocks)
|
|
125
141
|
|
|
126
142
|
const categories = [...new Set(blocks.map(b => b.category))]
|
|
127
143
|
|
|
@@ -139,29 +155,17 @@ export const BLOCK_METADATA = {
|
|
|
139
155
|
*/
|
|
140
156
|
|
|
141
157
|
import React from 'react'
|
|
142
|
-
import type { BlockConfig, BlockCategory } from '${convertCorePath('@/core/types', outputFilePath, config)}'
|
|
143
158
|
|
|
144
|
-
|
|
159
|
+
// Configs live in the client half so a client component can read them without
|
|
160
|
+
// pulling in a single block component.
|
|
161
|
+
export * from './block-registry.client'
|
|
162
|
+
// Lazy components live in their own module, which a client component can import
|
|
163
|
+
// without the static imports below.
|
|
164
|
+
export { BLOCK_COMPONENTS } from './block-registry.lazy'
|
|
145
165
|
|
|
146
166
|
// Direct component imports for SSR — zero CLS, synchronous hydration
|
|
147
167
|
${ssrComponentImports}
|
|
148
168
|
|
|
149
|
-
export const BLOCK_REGISTRY: Record<string, BlockConfig> = {
|
|
150
|
-
${registryEntries}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export const BLOCK_CATEGORIES: BlockCategory[] = [${categories.map(c => `'${c}'`).join(', ')}]
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Lazy-loaded block components for client-side rendering (admin UI, block picker).
|
|
157
|
-
* Each component is wrapped with React.lazy for code-splitting.
|
|
158
|
-
*/
|
|
159
|
-
export const BLOCK_COMPONENTS: Record<string, React.LazyExoticComponent<React.ComponentType<any>>> = {
|
|
160
|
-
${blocks.map(block => {
|
|
161
|
-
return ` '${block.slug}': React.lazy(() => import('${block.paths.component}').then(mod => ({ default: Object.values(mod)[0] as React.ComponentType<any> })))`
|
|
162
|
-
}).join(',\n')}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
169
|
/**
|
|
166
170
|
* Direct-imported block components for SSR rendering.
|
|
167
171
|
* Static imports ensure synchronous hydration — zero CLS.
|
|
@@ -170,7 +174,7 @@ ${blocks.map(block => {
|
|
|
170
174
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
171
175
|
export const BLOCK_COMPONENTS_SSR: Record<string, React.ComponentType<any>> = {
|
|
172
176
|
${blocks.map(block => {
|
|
173
|
-
const slugVar = block.slug
|
|
177
|
+
const slugVar = toSafeIdentifier(block.slug)
|
|
174
178
|
return ` '${block.slug}': ${slugVar}_component`
|
|
175
179
|
}).join(',\n')}
|
|
176
180
|
}
|
|
@@ -192,3 +196,147 @@ ${categories.map(cat => {
|
|
|
192
196
|
}
|
|
193
197
|
`
|
|
194
198
|
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Generate the client-safe half: block configs, with no component imports.
|
|
202
|
+
*
|
|
203
|
+
* This is what a client component reads. Keeping it free of component imports
|
|
204
|
+
* is the whole point — a block component is a server component, and pulling one
|
|
205
|
+
* into the client build fails the build when it imports server-only code.
|
|
206
|
+
*
|
|
207
|
+
* @param {Array} blocks - Discovered blocks
|
|
208
|
+
* @param {object} config - Configuration object from getConfig()
|
|
209
|
+
* @returns {string} Generated TypeScript content
|
|
210
|
+
*/
|
|
211
|
+
export function generateBlockRegistryClient(blocks, config) {
|
|
212
|
+
const outputFilePath = join(config.outputDir, 'block-registry.client.ts')
|
|
213
|
+
const header = `/**
|
|
214
|
+
* Auto-generated Block Registry (client-safe)
|
|
215
|
+
*
|
|
216
|
+
* Generated at: ${new Date().toISOString()}
|
|
217
|
+
* Blocks discovered: ${blocks.length}
|
|
218
|
+
*
|
|
219
|
+
* Block configs only: no component imports, so a client component can read the
|
|
220
|
+
* registry without the block components reaching the browser bundle.
|
|
221
|
+
*
|
|
222
|
+
* DO NOT EDIT - This file is auto-generated by scripts/build-registry.mjs
|
|
223
|
+
*/
|
|
224
|
+
`
|
|
225
|
+
|
|
226
|
+
if (blocks.length === 0) {
|
|
227
|
+
return `${header}
|
|
228
|
+
// Inline type definition for empty registry (avoids import issues in npm mode)
|
|
229
|
+
type BlockConfig = {
|
|
230
|
+
slug: string
|
|
231
|
+
name: string
|
|
232
|
+
description?: string
|
|
233
|
+
category: string
|
|
234
|
+
icon?: string
|
|
235
|
+
componentPath?: string
|
|
236
|
+
schemaPath?: string
|
|
237
|
+
fieldsPath?: string
|
|
238
|
+
thumbnail?: string
|
|
239
|
+
fieldDefinitions: unknown[]
|
|
240
|
+
examples: unknown[]
|
|
241
|
+
scope?: string[]
|
|
242
|
+
allowInPatterns?: boolean
|
|
243
|
+
schemaType?: string
|
|
244
|
+
tags?: string[]
|
|
245
|
+
isCore?: boolean
|
|
246
|
+
source?: string
|
|
247
|
+
sourceId?: string
|
|
248
|
+
version?: string
|
|
249
|
+
deprecated?: boolean
|
|
250
|
+
replacedBy?: string
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export const BLOCK_REGISTRY: Record<string, BlockConfig> = {}
|
|
254
|
+
|
|
255
|
+
export const BLOCK_CATEGORIES: string[] = []
|
|
256
|
+
|
|
257
|
+
export const BLOCK_METADATA = {
|
|
258
|
+
totalBlocks: 0,
|
|
259
|
+
categories: [],
|
|
260
|
+
blocksByCategory: {},
|
|
261
|
+
generatedAt: '${new Date().toISOString()}',
|
|
262
|
+
blocks: []
|
|
263
|
+
}
|
|
264
|
+
`
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const imports = []
|
|
268
|
+
blocks.forEach(block => {
|
|
269
|
+
const slugVar = toSafeIdentifier(block.slug)
|
|
270
|
+
imports.push(`import { fieldDefinitions as ${slugVar}_fields } from '${block.paths.fields}'`)
|
|
271
|
+
if (block.hasExamples) {
|
|
272
|
+
imports.push(`import { examples as ${slugVar}_examples } from '${block.paths.examples}'`)
|
|
273
|
+
}
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
const registryEntries = buildRegistryEntries(blocks)
|
|
277
|
+
const categories = [...new Set(blocks.map(b => b.category))]
|
|
278
|
+
|
|
279
|
+
return `${header}
|
|
280
|
+
import type { BlockConfig, BlockCategory } from '${convertCorePath('@/core/types', outputFilePath, config)}'
|
|
281
|
+
|
|
282
|
+
${imports.join('\n')}
|
|
283
|
+
|
|
284
|
+
export const BLOCK_REGISTRY: Record<string, BlockConfig> = {
|
|
285
|
+
${registryEntries}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export const BLOCK_CATEGORIES: BlockCategory[] = [${categories.map(c => `'${c}'`).join(', ')}]
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Block registry metadata
|
|
292
|
+
*/
|
|
293
|
+
export const BLOCK_METADATA = {
|
|
294
|
+
totalBlocks: ${blocks.length},
|
|
295
|
+
categories: [${categories.map(c => `'${c}'`).join(', ')}],
|
|
296
|
+
blocksByCategory: {
|
|
297
|
+
${categories.map(cat => ` '${cat}': ${blocks.filter(b => b.category === cat).length}`).join(',\n')}
|
|
298
|
+
},
|
|
299
|
+
generatedAt: '${new Date().toISOString()}',
|
|
300
|
+
blocks: [${blocks.map(b => `'${b.slug}'`).join(', ')}]
|
|
301
|
+
}
|
|
302
|
+
`
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Generate the lazy half: every block component behind React.lazy, and no
|
|
307
|
+
* static import.
|
|
308
|
+
*
|
|
309
|
+
* Client components that render blocks (the editor canvas, pattern previews,
|
|
310
|
+
* devtools) read this, so each block stays in a chunk of its own and loads
|
|
311
|
+
* when it is shown. Reaching the components through block-registry.ts instead
|
|
312
|
+
* carries its static SSR imports along, and with them every block and all a
|
|
313
|
+
* block imports, into that client component's bundle.
|
|
314
|
+
*
|
|
315
|
+
* @param {Array} blocks - Discovered blocks
|
|
316
|
+
* @returns {string} Generated TypeScript content
|
|
317
|
+
*/
|
|
318
|
+
export function generateBlockRegistryLazy(blocks) {
|
|
319
|
+
const entries = blocks.map(block =>
|
|
320
|
+
` '${block.slug}': React.lazy(() => import('${block.paths.component}').then(mod => ({ default: Object.values(mod)[0] as React.ComponentType<any> })))`
|
|
321
|
+
).join(',\n')
|
|
322
|
+
|
|
323
|
+
return `/**
|
|
324
|
+
* Auto-generated Block Registry (lazy components)
|
|
325
|
+
*
|
|
326
|
+
* Generated at: ${new Date().toISOString()}
|
|
327
|
+
* Blocks discovered: ${blocks.length}
|
|
328
|
+
*
|
|
329
|
+
* Block components behind React.lazy and nothing imported statically, so a
|
|
330
|
+
* client component can render blocks while each one stays in its own chunk.
|
|
331
|
+
*
|
|
332
|
+
* DO NOT EDIT - This file is auto-generated by scripts/build-registry.mjs
|
|
333
|
+
*/
|
|
334
|
+
|
|
335
|
+
import React from 'react'
|
|
336
|
+
|
|
337
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
338
|
+
export const BLOCK_COMPONENTS: Record<string, React.LazyExoticComponent<React.ComponentType<any>>> = {
|
|
339
|
+
${entries}
|
|
340
|
+
}
|
|
341
|
+
`
|
|
342
|
+
}
|
|
@@ -58,8 +58,15 @@ function stringifyWithIndent(obj, baseIndent = 2) {
|
|
|
58
58
|
* @returns {Object} Map of slug -> { slug, name }
|
|
59
59
|
*/
|
|
60
60
|
function loadBlockSlugs(registryDir) {
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
// The entries live in the client half; the server one re-exports them. The
|
|
62
|
+
// fallback is for a project generated before the split, whose server file
|
|
63
|
+
// still holds them inline.
|
|
64
|
+
const registryPath = [
|
|
65
|
+
join(registryDir, 'block-registry.client.ts'),
|
|
66
|
+
join(registryDir, 'block-registry.ts'),
|
|
67
|
+
].find(existsSync)
|
|
68
|
+
|
|
69
|
+
if (!registryPath) {
|
|
63
70
|
return {}
|
|
64
71
|
}
|
|
65
72
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Icon Registry Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates icon-registry.ts: a name -> component map holding only the
|
|
5
|
+
* lucide-react icons the app can look up by string.
|
|
6
|
+
*
|
|
7
|
+
* Named imports are what makes this work. `import * as Icons from
|
|
8
|
+
* 'lucide-react'` forces the bundler to keep the whole icon set — ~500 KB
|
|
9
|
+
* that ships to every route, including public ones that render none of it —
|
|
10
|
+
* because it can't prove which members are used. The set of names is known
|
|
11
|
+
* at build time (see discovery/icons.mjs), so it is spelled out here.
|
|
12
|
+
*
|
|
13
|
+
* @module core/scripts/build/registry/generators/icon-registry
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Generate the icon registry file
|
|
18
|
+
* @param {string[]} iconNames - Icon names discovered by discoverIcons()
|
|
19
|
+
* @param {object} config - Configuration object from getConfig()
|
|
20
|
+
* @returns {string} Generated TypeScript content
|
|
21
|
+
*/
|
|
22
|
+
export function generateIconRegistry(iconNames, config) {
|
|
23
|
+
const names = [...new Set(iconNames)].sort()
|
|
24
|
+
const importList = names.map(name => ` ${name}`).join(',\n')
|
|
25
|
+
const entryList = names.map(name => ` ${name}`).join(',\n')
|
|
26
|
+
|
|
27
|
+
return `/**
|
|
28
|
+
* Auto-generated Icon Registry
|
|
29
|
+
*
|
|
30
|
+
* Generated at: ${new Date().toISOString()}
|
|
31
|
+
* Icons referenced by name: ${names.length}
|
|
32
|
+
*
|
|
33
|
+
* DO NOT EDIT - This file is auto-generated by scripts/build-registry.mjs
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import type { LucideIcon } from 'lucide-react'
|
|
37
|
+
import {
|
|
38
|
+
${importList}
|
|
39
|
+
} from 'lucide-react'
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Every icon the app can resolve from a configured string name.
|
|
43
|
+
* Anything outside this map falls back to the caller's default icon.
|
|
44
|
+
*/
|
|
45
|
+
export const ICON_REGISTRY: Record<string, LucideIcon> = {
|
|
46
|
+
${entryList}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export type IconName = keyof typeof ICON_REGISTRY
|
|
50
|
+
|
|
51
|
+
export const ICON_METADATA = {
|
|
52
|
+
totalIcons: ${names.length},
|
|
53
|
+
generatedAt: '${new Date().toISOString()}'
|
|
54
|
+
}
|
|
55
|
+
`
|
|
56
|
+
}
|