@kilivi/payloadcms-theme-management 1.1.1 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +48 -31
  2. package/dist/components/ThemeLivePreviewSync.d.ts +11 -0
  3. package/dist/components/ThemeLivePreviewSync.d.ts.map +1 -0
  4. package/dist/components/ThemeLivePreviewSync.js +40 -0
  5. package/dist/components/ThemeLivePreviewSync.js.map +1 -0
  6. package/dist/fields/ThemeColorPickerField.d.ts.map +1 -1
  7. package/dist/fields/ThemeColorPickerField.js +26 -9
  8. package/dist/fields/ThemeColorPickerField.js.map +1 -1
  9. package/dist/fields/ThemePreviewField.d.ts.map +1 -1
  10. package/dist/fields/ThemePreviewField.js +2 -1
  11. package/dist/fields/ThemePreviewField.js.map +1 -1
  12. package/dist/fields/themeConfigurationField.d.ts +1 -0
  13. package/dist/fields/themeConfigurationField.d.ts.map +1 -1
  14. package/dist/fields/themeConfigurationField.js +3 -2
  15. package/dist/fields/themeConfigurationField.js.map +1 -1
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +337 -16
  19. package/dist/index.js.map +1 -1
  20. package/dist/server.d.ts +30 -0
  21. package/dist/server.d.ts.map +1 -1
  22. package/dist/server.js +42 -0
  23. package/dist/server.js.map +1 -1
  24. package/dist/types/color.d.js +2 -0
  25. package/dist/types/color.d.js.map +1 -0
  26. package/dist/types.d.ts +69 -0
  27. package/dist/types.d.ts.map +1 -1
  28. package/dist/types.js.map +1 -1
  29. package/dist/utils/livePreviewRefresh.d.ts +17 -0
  30. package/dist/utils/livePreviewRefresh.d.ts.map +1 -0
  31. package/dist/utils/livePreviewRefresh.js +20 -0
  32. package/dist/utils/livePreviewRefresh.js.map +1 -0
  33. package/dist/utils/livePreviewThemeRuntime.d.ts +7 -0
  34. package/dist/utils/livePreviewThemeRuntime.d.ts.map +1 -0
  35. package/dist/utils/livePreviewThemeRuntime.js +58 -0
  36. package/dist/utils/livePreviewThemeRuntime.js.map +1 -0
  37. package/package.json +1 -1
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { CollectionConfig, Config, Field, GlobalConfig, Plugin, TabsField } from 'payload'\nimport { createThemeConfigurationField } from './fields/themeConfigurationField.js'\nimport type { ThemeTab } from './fields/themeConfigurationField.js'\nimport type { SiteThemeConfiguration } from './payload-types.js'\nimport type { ThemePreset } from './presets.js'\nimport { allThemePresets } from './presets.js'\nimport { getTranslations, translations } from './translations.js'\nimport type { FetchThemeConfigurationOptions, ThemeManagementPluginOptions } from './types.js'\n\nconst THEME_FIELD_NAME = 'themeConfiguration'\n\n/**\n * Removes existing theme configuration from a group field (legacy)\n */\nconst removeExistingThemeField = (fields: Field[] = []): Field[] =>\n fields.filter((field) => {\n const candidate = field as { name?: unknown }\n return candidate?.name !== THEME_FIELD_NAME\n })\n\n/**\n * Finds the tabs field in the collection fields array\n */\nconst findTabsField = (fields: Field[] = []): TabsField | null => {\n for (const field of fields) {\n if (field.type === 'tabs') {\n return field as TabsField\n }\n }\n return null\n}\n\n/**\n * Removes existing Appearance Settings tab if it exists\n */\nconst removeExistingThemeTab = (\n tabs: NonNullable<TabsField['tabs']>,\n): NonNullable<TabsField['tabs']> => {\n const knownLabels = Object.values(translations).map((t) => t.tabLabel)\n return tabs.filter((tab) => {\n // Normalize label to string (support localized object or plain string)\n let labelValues: string[] = []\n if (typeof tab.label === 'object' && tab.label !== null) {\n labelValues = Object.values(tab.label as Record<string, string>)\n } else if (typeof tab.label === 'string') {\n labelValues = [tab.label]\n }\n\n // If any of the label values match a known plugin tab label, remove it\n const matchesKnown = labelValues.some((v) => knownLabels.includes(v))\n\n return !matchesKnown\n })\n}\n\n/**\n * Injects theme tab into existing tabs field\n */\nconst injectThemeTab = (\n fields: Field[] | undefined,\n themeTab: ThemeTab,\n enableLogging: boolean,\n): Field[] => {\n // First, remove any legacy theme field (group-based)\n const sanitizedFields = removeExistingThemeField(fields ?? [])\n\n // Find the tabs field\n const tabsField = findTabsField(sanitizedFields)\n\n if (!tabsField || !tabsField.tabs) {\n if (enableLogging) {\n console.warn(\n '🎨 Theme Management Plugin: No tabs field found. Creating a new tabs structure.',\n )\n }\n\n // If no tabs exist, create a basic tabs structure with just the theme tab\n const newTabsField: TabsField = {\n type: 'tabs',\n tabs: [themeTab],\n }\n\n return [...sanitizedFields, newTabsField]\n }\n\n // Remove existing theme tab if present\n const sanitizedTabs = removeExistingThemeTab(tabsField.tabs)\n\n // Add theme tab to the end\n const updatedTabs = [...sanitizedTabs, themeTab]\n\n if (enableLogging) {\n console.log('🎨 Theme Management Plugin: injecting Appearance Settings tab')\n }\n\n // Update the tabs field\n const updatedTabsField: TabsField = {\n ...tabsField,\n tabs: updatedTabs,\n }\n\n // Replace the old tabs field with the updated one\n return sanitizedFields.map((field) => (field.type === 'tabs' ? updatedTabsField : field))\n}\n\nconst ensureCollectionsArray = (collections: Config['collections']): CollectionConfig[] =>\n Array.isArray(collections) ? collections : []\n\nexport const themeManagementPlugin = (options: ThemeManagementPluginOptions = {}): Plugin => {\n return (config: Config): Config => {\n const {\n enabled = true,\n targetCollection = 'site-settings',\n useStandaloneCollection = false,\n standaloneCollectionSlug = 'appearance-settings',\n // Allow either string or localized object; default comes from plugin translations\n standaloneCollectionLabel = getTranslations().standaloneCollectionLabel,\n themePresets = allThemePresets,\n defaultTheme = 'cool',\n includeColorModeToggle = true,\n includeCustomCSS = true,\n includeBrandIdentity = false,\n enableAdvancedFeatures = true,\n enableLogging = false,\n } = options\n\n if (!enabled) {\n if (enableLogging) {\n console.log('🎨 Theme Management Plugin: disabled via options, skipping.')\n }\n return config\n }\n\n const themeTab = createThemeConfigurationField({\n themePresets,\n defaultTheme,\n includeColorModeToggle,\n includeCustomCSS,\n includeBrandIdentity: includeBrandIdentity ?? false,\n enableAdvancedFeatures,\n })\n\n // If using standalone collection, create a new global\n if (useStandaloneCollection) {\n if (enableLogging) {\n console.log(\n `🎨 Theme Management Plugin: creating standalone global \"${standaloneCollectionSlug}\"`,\n )\n }\n\n // Extract the fields from the tab directly (no wrapping in group)\n const tabFields = (themeTab.fields ?? []) as Field[]\n\n /**\n * Hook to auto-populate lightMode and darkMode colors when theme changes\n */\n type BeforeChangeArgs = {\n data?: {\n themeConfiguration?: {\n theme?: string\n lightMode?: Record<string, unknown>\n darkMode?: Record<string, unknown>\n }\n }\n }\n\n const beforeChangeHook = async (args: BeforeChangeArgs) => {\n const { data } = args\n\n // If theme is being changed, auto-populate color modes\n if (data?.themeConfiguration?.theme) {\n const themeName = data.themeConfiguration.theme\n const selectedPreset = themePresets.find((p) => p.name === themeName)\n\n if (selectedPreset) {\n // Initialize light and dark mode colors from preset if not already set\n if (!data.themeConfiguration.lightMode) {\n data.themeConfiguration.lightMode = {}\n }\n if (!data.themeConfiguration.darkMode) {\n data.themeConfiguration.darkMode = {}\n }\n\n // Only populate if not manually edited (first time or empty)\n const isLightModeEmpty = !data.themeConfiguration.lightMode?.background\n const isDarkModeEmpty = !data.themeConfiguration.darkMode?.background\n\n if (isLightModeEmpty && selectedPreset.lightMode) {\n data.themeConfiguration.lightMode = { ...selectedPreset.lightMode }\n }\n\n if (isDarkModeEmpty && selectedPreset.darkMode) {\n data.themeConfiguration.darkMode = { ...selectedPreset.darkMode }\n }\n }\n }\n\n return data\n }\n\n const standaloneGlobal: GlobalConfig = {\n slug: standaloneCollectionSlug,\n label: standaloneCollectionLabel,\n admin: {\n group: 'Settings',\n },\n // Provide a broad access object but cast to GlobalConfig['access'] to satisfy types\n access: ((): GlobalConfig['access'] => {\n const accessObj = {\n read: () => true,\n create: ({ req }: { req?: { user?: unknown } }) => !!req?.user,\n update: ({ req }: { req?: { user?: unknown } }) => !!req?.user,\n delete: ({ req }: { req?: { user?: unknown } }) => !!req?.user,\n } as unknown as GlobalConfig['access']\n return accessObj\n })(),\n fields: tabFields,\n hooks: {\n beforeChange: [beforeChangeHook],\n afterChange: [\n async ({ doc, req }) => {\n // Invalidate cache after appearance settings change\n if (!req?.context?.disableRevalidate) {\n try {\n const cacheTag = `global_${standaloneCollectionSlug}`\n // Import revalidateTag dynamically to avoid issues in non-Next.js environments\n const { revalidateTag } = await import('next/cache')\n revalidateTag(cacheTag)\n if (enableLogging) {\n req.payload.logger.info(\n `🎨 Theme Management Plugin: cache invalidated for tag \"${cacheTag}\"`,\n )\n }\n } catch (error) {\n if (enableLogging) {\n req.payload.logger.error(\n '🎨 Theme Management Plugin: cache invalidation failed:',\n error,\n )\n }\n }\n }\n return doc\n },\n ],\n },\n }\n\n const globals = Array.isArray(config.globals) ? config.globals : []\n\n // Check if global already exists\n const existingIndex = globals.findIndex((g) => g.slug === standaloneCollectionSlug)\n\n if (existingIndex !== -1) {\n if (enableLogging) {\n console.warn(\n `🎨 Theme Management Plugin: global \"${standaloneCollectionSlug}\" already exists, skipping creation.`,\n )\n }\n return config\n }\n\n return {\n ...config,\n globals: [...globals, standaloneGlobal],\n }\n }\n\n // Otherwise, add as tab to existing collection\n let collectionTouched = false\n\n const collections = ensureCollectionsArray(config.collections).map((collection) => {\n if (collection.slug !== targetCollection) {\n return collection\n }\n\n collectionTouched = true\n\n if (enableLogging) {\n console.log(`🎨 Theme Management Plugin: enhancing collection \"${collection.slug}\"`)\n }\n\n const existingFields = Array.isArray(collection.fields) ? collection.fields : []\n\n const fields = injectThemeTab(existingFields, themeTab, enableLogging)\n\n return {\n ...collection,\n fields,\n }\n })\n\n if (!collectionTouched) {\n if (enableLogging) {\n console.warn(\n `🎨 Theme Management Plugin: collection \"${targetCollection}\" was not found, leaving config untouched.`,\n )\n }\n return config\n }\n\n return {\n ...config,\n collections,\n }\n }\n}\n\ntype FetchOptionsInput = string | FetchThemeConfigurationOptions\n\nexport const fetchThemeConfiguration = async (\n options?: FetchOptionsInput,\n): Promise<SiteThemeConfiguration | null> => {\n const normalizedOptions = typeof options === 'string' ? { tenantSlug: options } : (options ?? {})\n\n const {\n tenantSlug,\n collectionSlug = 'site-settings', // Can be overridden to 'appearance-settings' if using standalone\n depth,\n locale,\n draft,\n queryParams = {},\n useGlobal = false, // Set to true if using standalone global instead of collection\n } = normalizedOptions\n\n try {\n if (useGlobal) {\n // Fetch from global endpoint\n const params = new URLSearchParams()\n\n if (typeof depth === 'number') params.set('depth', String(depth))\n // For globals, keep tenant param for backwards compatibility, and also add where[...] filter\n if (tenantSlug) {\n params.set('tenant', tenantSlug)\n params.set('where[tenant][equals]', String(tenantSlug))\n }\n\n Object.entries(queryParams).forEach(([key, value]) => {\n if (value === undefined) return\n params.set(key, String(value))\n })\n\n const queryString = params.toString()\n const url = `/api/globals/${collectionSlug}${queryString ? `?${queryString}` : ''}`\n\n const response = await fetch(url)\n if (!response.ok) {\n throw new Error(`Failed to fetch theme global (status ${response.status})`)\n }\n\n const data = (await response.json()) as {\n themeConfiguration?: SiteThemeConfiguration\n }\n\n return data?.themeConfiguration ?? null\n } else {\n // Fetch from collection endpoint (legacy/default behavior)\n const params = new URLSearchParams({ limit: '1' })\n\n if (typeof depth === 'number') params.set('depth', String(depth))\n // For collections, use a where[tenant][equals] filter so Payload's find endpoint applies tenant scoping\n if (tenantSlug) params.set('where[tenant][equals]', String(tenantSlug))\n if (locale) params.set('locale', locale)\n if (draft) params.set('draft', 'true')\n\n Object.entries(queryParams).forEach(([key, value]) => {\n if (value === undefined) return\n params.set(key, String(value))\n })\n\n const url = `/api/${collectionSlug}?${params.toString()}`\n\n const response = await fetch(url)\n if (!response.ok) {\n throw new Error(`Failed to fetch theme configuration (status ${response.status})`)\n }\n\n const data = (await response.json()) as {\n docs?: Array<{ themeConfiguration?: SiteThemeConfiguration }>\n }\n\n const doc = data.docs?.[0]\n\n return doc?.themeConfiguration ?? null\n }\n } catch (error) {\n console.warn('Failed to fetch theme configuration:', error)\n return null\n }\n}\n\nexport const getThemePreset = (themeName: string): ThemePreset | null => {\n return allThemePresets.find((preset) => preset.name === themeName) || null\n}\n\nexport const getAvailableThemePresets = (): ThemePreset[] => {\n return allThemePresets\n}\n\nexport { defaultThemePresets, allThemePresets } from './presets.js'\nexport type { ThemePreset, ThemeTypographyPreset } from './presets.js'\nexport type { ThemeTab } from './fields/themeConfigurationField.js'\nexport {\n extendedThemePresets,\n allExtendedThemePresets,\n extendedThemeToCSSVariables,\n} from './extended-presets.js'\nexport type { ExtendedThemePreset, ShadcnColorTokens } from './extended-presets.js'\nexport {\n applyExtendedTheme,\n generateExtendedThemeCSS,\n resetExtendedTheme,\n getExtendedThemeTokens,\n createUseExtendedTheme,\n getTailwindVarReferences,\n} from './utils/extendedThemeHelpers.js'\nexport type { ThemeManagementPluginOptions, FetchThemeConfigurationOptions } from './types.js'\nexport {\n DEFAULT_THEME_CONFIGURATION,\n resolveThemeConfiguration,\n} from './utils/resolveThemeConfiguration.js'\nexport type { ResolvedThemeConfiguration } from './utils/resolveThemeConfiguration.js'\nexport { generateThemeColorsCss, hexToHsl } from './utils/themeColors.js'\nexport { generateThemeCSS, getThemeStyles } from './utils/themeUtils.js'\nexport { getThemeHtmlAttributes } from './utils/themeHtmlAttributes.js'\n\n// Dynamic theme CSS generation\nexport {\n generateThemeCSS as generatePresetCSS,\n generateAllThemesCSS,\n} from './utils/generateThemeCSS.js'\nexport { getThemeDynamicCSS, getAllDynamicThemesCSS } from './utils/themeCSS.js'\n\nexport type { Mode, ThemeDefaults } from './providers/Theme/types.js'\nexport { ThemeProvider } from './providers/Theme/index.js'\n\n// Font loading utilities for Next.js integration\nexport {\n getFontLoaderCode,\n getThemeFontFamilies,\n ThemeFontProvider,\n useThemeFonts,\n FONT_IMPORT_MAP,\n} from './providers/font-loader.js'\n\n// Note: Do NOT re-export client components from the root entry to avoid\n// server-side evaluation during `payload generate:importmap`.\n// If needed, import directly from subpath: `@kilivi/payloadcms-theme-management/fields/ThemeLivePreview`\n\nexport const ThemeManagementPlugin = themeManagementPlugin\n/** @deprecated use {@link themeManagementPlugin} */\nexport const themeConfigurationPlugin = themeManagementPlugin\n\n// Export plugin translations for consumers to merge into their payload translations\nexport {\n translations,\n getTranslations,\n registerTranslations,\n availableLanguages,\n} from './translations.js'\n\nexport default themeManagementPlugin\n"],"names":["createThemeConfigurationField","allThemePresets","getTranslations","translations","THEME_FIELD_NAME","removeExistingThemeField","fields","filter","field","candidate","name","findTabsField","type","removeExistingThemeTab","tabs","knownLabels","Object","values","map","t","tabLabel","tab","labelValues","label","matchesKnown","some","v","includes","injectThemeTab","themeTab","enableLogging","sanitizedFields","tabsField","console","warn","newTabsField","sanitizedTabs","updatedTabs","log","updatedTabsField","ensureCollectionsArray","collections","Array","isArray","themeManagementPlugin","options","config","enabled","targetCollection","useStandaloneCollection","standaloneCollectionSlug","standaloneCollectionLabel","themePresets","defaultTheme","includeColorModeToggle","includeCustomCSS","includeBrandIdentity","enableAdvancedFeatures","tabFields","beforeChangeHook","args","data","themeConfiguration","theme","themeName","selectedPreset","find","p","lightMode","darkMode","isLightModeEmpty","background","isDarkModeEmpty","standaloneGlobal","slug","admin","group","access","accessObj","read","create","req","user","update","delete","hooks","beforeChange","afterChange","doc","context","disableRevalidate","cacheTag","revalidateTag","payload","logger","info","error","globals","existingIndex","findIndex","g","collectionTouched","collection","existingFields","fetchThemeConfiguration","normalizedOptions","tenantSlug","collectionSlug","depth","locale","draft","queryParams","useGlobal","params","URLSearchParams","set","String","entries","forEach","key","value","undefined","queryString","toString","url","response","fetch","ok","Error","status","json","limit","docs","getThemePreset","preset","getAvailableThemePresets","defaultThemePresets","extendedThemePresets","allExtendedThemePresets","extendedThemeToCSSVariables","applyExtendedTheme","generateExtendedThemeCSS","resetExtendedTheme","getExtendedThemeTokens","createUseExtendedTheme","getTailwindVarReferences","DEFAULT_THEME_CONFIGURATION","resolveThemeConfiguration","generateThemeColorsCss","hexToHsl","generateThemeCSS","getThemeStyles","getThemeHtmlAttributes","generatePresetCSS","generateAllThemesCSS","getThemeDynamicCSS","getAllDynamicThemesCSS","ThemeProvider","getFontLoaderCode","getThemeFontFamilies","ThemeFontProvider","useThemeFonts","FONT_IMPORT_MAP","ThemeManagementPlugin","themeConfigurationPlugin","registerTranslations","availableLanguages"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { CollectionConfig, Config, Field, GlobalConfig, Plugin, TabsField } from 'payload'\nimport { createThemeConfigurationField } from './fields/themeConfigurationField.js'\nimport type { ThemeTab } from './fields/themeConfigurationField.js'\nimport type { SiteThemeConfiguration } from './payload-types.js'\nimport type { ThemePreset } from './presets.js'\nimport { allThemePresets } from './presets.js'\nimport { getTranslations, translations } from './translations.js'\nimport type {\n FetchThemeConfigurationOptions,\n ThemeManagementLivePreviewOptions,\n ThemeManagementLivePreviewUrlArgs,\n ThemeManagementPluginOptions,\n} from './types.js'\n\nconst THEME_FIELD_NAME = 'themeConfiguration'\n\n/**\n * Removes existing theme configuration from a group field (legacy)\n */\nconst removeExistingThemeField = (fields: Field[] = []): Field[] =>\n fields.filter((field) => {\n const candidate = field as { name?: unknown }\n return candidate?.name !== THEME_FIELD_NAME\n })\n\n/**\n * Finds the tabs field in the collection fields array\n */\nconst findTabsField = (fields: Field[] = []): TabsField | null => {\n for (const field of fields) {\n if (field.type === 'tabs') {\n return field as TabsField\n }\n }\n return null\n}\n\n/**\n * Removes existing Appearance Settings tab if it exists\n */\nconst removeExistingThemeTab = (\n tabs: NonNullable<TabsField['tabs']>,\n): NonNullable<TabsField['tabs']> => {\n const knownLabels = Object.values(translations).map((t) => t.tabLabel)\n return tabs.filter((tab) => {\n // Normalize label to string (support localized object or plain string)\n let labelValues: string[] = []\n if (typeof tab.label === 'object' && tab.label !== null) {\n labelValues = Object.values(tab.label as Record<string, string>)\n } else if (typeof tab.label === 'string') {\n labelValues = [tab.label]\n }\n\n // If any of the label values match a known plugin tab label, remove it\n const matchesKnown = labelValues.some((v) => knownLabels.includes(v))\n\n return !matchesKnown\n })\n}\n\n/**\n * Injects theme tab into existing tabs field\n */\nconst injectThemeTab = (\n fields: Field[] | undefined,\n themeTab: ThemeTab,\n enableLogging: boolean,\n): Field[] => {\n // First, remove any legacy theme field (group-based)\n const sanitizedFields = removeExistingThemeField(fields ?? [])\n\n // Find the tabs field\n const tabsField = findTabsField(sanitizedFields)\n\n if (!tabsField || !tabsField.tabs) {\n if (enableLogging) {\n console.warn(\n '🎨 Theme Management Plugin: No tabs field found. Creating a new tabs structure.',\n )\n }\n\n // If no tabs exist, create a basic tabs structure with just the theme tab\n const newTabsField: TabsField = {\n type: 'tabs',\n tabs: [themeTab],\n }\n\n return [...sanitizedFields, newTabsField]\n }\n\n // Remove existing theme tab if present\n const sanitizedTabs = removeExistingThemeTab(tabsField.tabs)\n\n // Add theme tab to the end\n const updatedTabs = [...sanitizedTabs, themeTab]\n\n if (enableLogging) {\n console.log('🎨 Theme Management Plugin: injecting Appearance Settings tab')\n }\n\n // Update the tabs field\n const updatedTabsField: TabsField = {\n ...tabsField,\n tabs: updatedTabs,\n }\n\n // Replace the old tabs field with the updated one\n return sanitizedFields.map((field) => (field.type === 'tabs' ? updatedTabsField : field))\n}\n\nconst ensureCollectionsArray = (collections: Config['collections']): CollectionConfig[] =>\n Array.isArray(collections) ? collections : []\n\nconst ensureEndpointsArray = (endpoints: Config['endpoints']): NonNullable<Config['endpoints']> =>\n Array.isArray(endpoints) ? endpoints : []\n\ntype NormalizedLivePreviewOptions = {\n enabled: boolean\n pageCollection: string\n pageSlug: string\n fallbackToFirstPage: boolean\n tenantField: string\n tenantQueryParam: string\n breakpoints?: ThemeManagementLivePreviewOptions['breakpoints']\n url?: ThemeManagementLivePreviewOptions['url']\n}\n\ntype NormalizedCacheRevalidationOptions = {\n enabled: boolean\n injectRoute: boolean\n routePath: string\n secret?: string\n tags: string[]\n paths: string[]\n}\n\ntype MinimalPayloadRequest = ThemeManagementLivePreviewUrlArgs['req']\n\nconst normalizeLivePreviewOptions = (\n livePreview: ThemeManagementPluginOptions['livePreview'],\n): NormalizedLivePreviewOptions => {\n if (livePreview === false) {\n return {\n enabled: false,\n pageCollection: 'pages',\n pageSlug: 'home',\n fallbackToFirstPage: true,\n tenantField: 'tenant',\n tenantQueryParam: 'tenant',\n breakpoints: undefined,\n }\n }\n\n const raw = typeof livePreview === 'object' && livePreview ? livePreview : {}\n\n return {\n enabled: raw.enabled ?? true,\n pageCollection: raw.pageCollection ?? 'pages',\n pageSlug: raw.pageSlug ?? 'home',\n fallbackToFirstPage: raw.fallbackToFirstPage ?? true,\n tenantField: raw.tenantField ?? 'tenant',\n tenantQueryParam: raw.tenantQueryParam ?? 'tenant',\n breakpoints: raw.breakpoints,\n url: raw.url,\n }\n}\n\nconst dedupeStrings = (values: (string | undefined)[]): string[] => [\n ...new Set(\n values.filter((value): value is string => typeof value === 'string' && value.trim().length > 0),\n ),\n]\n\nconst normalizeRoutePath = (path: string | undefined): string => {\n if (!path || !path.trim()) {\n return '/theme/revalidate'\n }\n\n return path.startsWith('/') ? path : `/${path}`\n}\n\nconst normalizeCacheRevalidationOptions = (args: {\n cacheRevalidation: ThemeManagementPluginOptions['cacheRevalidation']\n standaloneCollectionSlug: string\n useStandaloneCollection: boolean\n}): NormalizedCacheRevalidationOptions => {\n const { cacheRevalidation, standaloneCollectionSlug, useStandaloneCollection } = args\n\n if (cacheRevalidation === false) {\n return {\n enabled: false,\n injectRoute: false,\n routePath: '/theme/revalidate',\n tags: [],\n paths: [],\n }\n }\n\n const raw = typeof cacheRevalidation === 'object' && cacheRevalidation ? cacheRevalidation : {}\n const defaultTag = `global_${standaloneCollectionSlug}`\n\n return {\n enabled: raw.enabled ?? useStandaloneCollection,\n injectRoute: raw.injectRoute ?? true,\n routePath: normalizeRoutePath(raw.routePath),\n secret: raw.secret,\n tags: dedupeStrings([defaultTag, ...(raw.tags ?? [])]),\n paths: dedupeStrings(raw.paths ?? []),\n }\n}\n\nconst asRecord = (value: unknown): Record<string, unknown> | undefined => {\n if (value && typeof value === 'object') {\n return value as Record<string, unknown>\n }\n return undefined\n}\n\nconst pickString = (value: unknown): string | undefined => {\n if (typeof value === 'string' && value.trim()) return value\n return undefined\n}\n\nconst extractTenantValue = (value: unknown): string | undefined => {\n if (!value) return undefined\n if (typeof value === 'string') return pickString(value)\n\n const tenantRecord = asRecord(value)\n if (!tenantRecord) return undefined\n\n return (\n pickString(tenantRecord.id) ??\n pickString(tenantRecord.slug) ??\n pickString(tenantRecord.value) ??\n pickString(tenantRecord.tenant)\n )\n}\n\nconst resolveTenantSlug = (\n req: MinimalPayloadRequest,\n tenantField: string,\n data?: Record<string, unknown>,\n): string | undefined => {\n const fromData = extractTenantValue(data?.[tenantField])\n if (fromData) return fromData\n\n const query = req.query\n if (query && typeof URLSearchParams !== 'undefined' && query instanceof URLSearchParams) {\n return (\n pickString(query.get('tenant')) ??\n pickString(query.get('tenantSlug')) ??\n pickString(query.get('tenantId'))\n )\n }\n\n const queryRecord = asRecord(query)\n const fromQuery =\n extractTenantValue(queryRecord?.tenant) ??\n extractTenantValue(queryRecord?.tenantSlug) ??\n extractTenantValue(queryRecord?.tenantId)\n if (fromQuery) return fromQuery\n\n const userRecord = asRecord(req.user)\n const fromUser =\n extractTenantValue(userRecord?.[tenantField]) ??\n extractTenantValue(userRecord?.tenant) ??\n extractTenantValue(userRecord?.tenantSlug)\n if (fromUser) return fromUser\n\n const headers = req.headers\n if (headers && typeof Headers !== 'undefined' && headers instanceof Headers) {\n return (\n pickString(headers.get('x-tenant-id')) ??\n pickString(headers.get('x-tenant')) ??\n pickString(headers.get('payload-tenant'))\n )\n }\n\n const headerRecord = asRecord(headers)\n return (\n extractTenantValue(headerRecord?.['x-tenant-id']) ??\n extractTenantValue(headerRecord?.['x-tenant']) ??\n extractTenantValue(headerRecord?.['payload-tenant'])\n )\n}\n\nconst buildDefaultPreviewPath = (\n pageSlug: string,\n tenantSlug: string | undefined,\n tenantQueryParam: string,\n): string => {\n const normalizedSlug = pageSlug === 'home' ? '' : pageSlug\n const basePath = normalizedSlug ? `/${normalizedSlug}` : '/'\n\n if (!tenantSlug) {\n return basePath\n }\n\n const separator = basePath.includes('?') ? '&' : '?'\n return `${basePath}${separator}${tenantQueryParam}=${encodeURIComponent(tenantSlug)}`\n}\n\nconst resolveLivePreviewUrl = async (args: {\n req: MinimalPayloadRequest\n data?: Record<string, unknown>\n livePreview: NormalizedLivePreviewOptions\n enableLogging: boolean\n}): Promise<string> => {\n const { req, data, livePreview, enableLogging } = args\n\n const tenantSlug = resolveTenantSlug(req, livePreview.tenantField, data)\n\n const tenantWhere = tenantSlug\n ? {\n [livePreview.tenantField]: {\n equals: tenantSlug,\n },\n }\n : undefined\n\n const homeWhere = {\n and: [\n {\n slug: {\n equals: livePreview.pageSlug,\n },\n },\n ...(tenantWhere ? [tenantWhere] : []),\n ],\n }\n\n try {\n const preferredPageResponse = await req.payload.find({\n collection: livePreview.pageCollection,\n where: homeWhere,\n depth: 0,\n draft: true,\n limit: 1,\n overrideAccess: true,\n pagination: false,\n })\n\n let page = preferredPageResponse?.docs?.[0]\n\n if (!page && livePreview.fallbackToFirstPage) {\n const fallbackResponse = await req.payload.find({\n collection: livePreview.pageCollection,\n where: tenantWhere,\n depth: 0,\n draft: true,\n limit: 1,\n overrideAccess: true,\n pagination: false,\n })\n\n page = fallbackResponse?.docs?.[0]\n }\n\n const pageRecord = asRecord(page)\n const resolvedPageSlug = pickString(pageRecord?.slug) ?? livePreview.pageSlug\n\n if (livePreview.url) {\n return await livePreview.url({\n page: pageRecord,\n pageSlug: resolvedPageSlug,\n tenantSlug,\n req,\n })\n }\n\n return buildDefaultPreviewPath(resolvedPageSlug, tenantSlug, livePreview.tenantQueryParam)\n } catch (error) {\n if (enableLogging) {\n req.payload.logger?.warn?.(\n '🎨 Theme Management Plugin: live preview URL fallback used',\n error,\n )\n }\n\n return buildDefaultPreviewPath(livePreview.pageSlug, tenantSlug, livePreview.tenantQueryParam)\n }\n}\n\nconst createPreviewAdminConfig = (\n normalizedLivePreview: NormalizedLivePreviewOptions,\n enableLogging: boolean,\n) => {\n if (!normalizedLivePreview.enabled) {\n return {}\n }\n\n return {\n livePreview: {\n breakpoints: normalizedLivePreview.breakpoints,\n url: ({ data, req }: { data?: unknown; req: unknown }) =>\n resolveLivePreviewUrl({\n req: req as MinimalPayloadRequest,\n data: asRecord(data),\n livePreview: normalizedLivePreview,\n enableLogging,\n }),\n },\n preview: (data: Record<string, unknown>, options: { req?: unknown }) => {\n const req = options?.req\n if (!req) return null\n\n return resolveLivePreviewUrl({\n req: req as MinimalPayloadRequest,\n data,\n livePreview: normalizedLivePreview,\n enableLogging,\n })\n },\n }\n}\n\nconst readSecretFromRequest = async (req: unknown): Promise<string | undefined> => {\n const requestRecord = asRecord(req)\n const headersValue = requestRecord?.headers\n\n if (headersValue && typeof Headers !== 'undefined' && headersValue instanceof Headers) {\n return (\n pickString(headersValue.get('x-theme-revalidate-secret')) ??\n pickString(headersValue.get('x-revalidate-secret'))\n )\n }\n\n const headerRecord = asRecord(headersValue)\n const fromHeaders =\n pickString(headerRecord?.['x-theme-revalidate-secret']) ??\n pickString(headerRecord?.['x-revalidate-secret'])\n if (fromHeaders) {\n return fromHeaders\n }\n\n const requestWithJson = req as { json?: () => Promise<unknown> }\n const body =\n typeof requestWithJson?.json === 'function' ? await requestWithJson.json() : undefined\n const bodyRecord = asRecord(body)\n const fromBody = pickString(bodyRecord?.secret)\n if (fromBody) {\n return fromBody\n }\n\n const queryRecord = asRecord(requestRecord?.query)\n return pickString(queryRecord?.secret)\n}\n\nconst executeThemeRevalidation = async (options: {\n tags: string[]\n paths: string[]\n enableLogging: boolean\n logger?: { info?: (...args: any[]) => void; error?: (...args: any[]) => void }\n}): Promise<{ tags: string[]; paths: string[] }> => {\n const { tags, paths, enableLogging, logger } = options\n\n try {\n const { revalidatePath, revalidateTag } = await import('next/cache')\n\n tags.forEach((tag) => revalidateTag(tag))\n paths.forEach((path) => revalidatePath(path))\n\n if (enableLogging) {\n logger?.info?.(\n `🎨 Theme Management Plugin: revalidated cache tags=[${tags.join(', ')}] paths=[${paths.join(', ')}]`,\n )\n }\n } catch (error) {\n if (enableLogging) {\n logger?.error?.('🎨 Theme Management Plugin: cache invalidation failed:', error)\n }\n throw error\n }\n\n return { tags, paths }\n}\n\nconst createCacheRevalidationEndpoint = (options: {\n cacheRevalidation: NormalizedCacheRevalidationOptions\n enableLogging: boolean\n}) => {\n const { cacheRevalidation, enableLogging } = options\n\n if (!cacheRevalidation.enabled || !cacheRevalidation.injectRoute) {\n return null\n }\n\n return {\n path: cacheRevalidation.routePath,\n method: 'post',\n handler: async (req: unknown) => {\n const reqRecord = asRecord(req)\n const payload = asRecord(reqRecord?.payload)\n const logger = payload?.logger as\n | { info?: (...args: any[]) => void; error?: (...args: any[]) => void }\n | undefined\n\n if (cacheRevalidation.secret) {\n const providedSecret = await readSecretFromRequest(req)\n if (providedSecret !== cacheRevalidation.secret) {\n return jsonResponse({ error: 'Unauthorized' }, 401)\n }\n }\n\n try {\n const result = await executeThemeRevalidation({\n tags: cacheRevalidation.tags,\n paths: cacheRevalidation.paths,\n enableLogging,\n logger,\n })\n\n return jsonResponse({ ok: true, revalidated: result })\n } catch {\n return jsonResponse({ ok: false, error: 'Revalidation failed' }, 500)\n }\n },\n }\n}\n\nconst mergeEndpoint = (\n endpoints: NonNullable<Config['endpoints']>,\n endpoint: ReturnType<typeof createCacheRevalidationEndpoint>,\n): NonNullable<Config['endpoints']> => {\n if (!endpoint) {\n return endpoints\n }\n\n const withoutExisting = endpoints.filter((candidate) => {\n const record = candidate as unknown as { path?: string; method?: string }\n return !(\n record?.path === endpoint.path &&\n typeof record.method === 'string' &&\n record.method.toLowerCase() === endpoint.method\n )\n })\n\n return [...withoutExisting, endpoint as unknown as NonNullable<Config['endpoints']>[number]]\n}\n\nconst jsonResponse = (body: Record<string, unknown>, status = 200): unknown => {\n if (typeof Response !== 'undefined' && typeof Response.json === 'function') {\n return Response.json(body, { status })\n }\n\n return {\n status,\n json: async () => body,\n }\n}\n\nexport const themeManagementPlugin = (options: ThemeManagementPluginOptions = {}): Plugin => {\n return (config: Config): Config => {\n const {\n enabled = true,\n targetCollection = 'site-settings',\n useStandaloneCollection = false,\n standaloneCollectionSlug = 'appearance-settings',\n // Allow either string or localized object; default comes from plugin translations\n standaloneCollectionLabel = getTranslations().standaloneCollectionLabel,\n themePresets = allThemePresets,\n defaultTheme = 'cool',\n includeColorModeToggle = true,\n includeCustomCSS = true,\n includeBrandIdentity = false,\n enableAdvancedFeatures = true,\n enableLogging = false,\n livePreview = true,\n cacheRevalidation,\n } = options\n\n const normalizedLivePreview = normalizeLivePreviewOptions(livePreview)\n const normalizedCacheRevalidation = normalizeCacheRevalidationOptions({\n cacheRevalidation,\n standaloneCollectionSlug,\n useStandaloneCollection,\n })\n\n if (!enabled) {\n if (enableLogging) {\n console.log('🎨 Theme Management Plugin: disabled via options, skipping.')\n }\n return config\n }\n\n const themeTab = createThemeConfigurationField({\n themePresets,\n defaultTheme,\n includeColorModeToggle,\n includeCustomCSS,\n includeBrandIdentity: includeBrandIdentity ?? false,\n enableAdvancedFeatures,\n useThemePreviewField: !normalizedLivePreview.enabled,\n })\n\n // If using standalone collection, create a new global\n if (useStandaloneCollection) {\n if (enableLogging) {\n console.log(\n `🎨 Theme Management Plugin: creating standalone global \"${standaloneCollectionSlug}\"`,\n )\n }\n\n // Extract the fields from the tab directly (no wrapping in group)\n const tabFields = (themeTab.fields ?? []) as Field[]\n\n /**\n * Hook to auto-populate lightMode and darkMode colors when theme changes\n */\n type BeforeChangeArgs = {\n data?: {\n themeConfiguration?: {\n theme?: string\n lightMode?: Record<string, unknown>\n darkMode?: Record<string, unknown>\n }\n }\n }\n\n const beforeChangeHook = async (args: BeforeChangeArgs) => {\n const { data } = args\n\n // If theme is being changed, auto-populate color modes\n if (data?.themeConfiguration?.theme) {\n const themeName = data.themeConfiguration.theme\n const selectedPreset = themePresets.find((p) => p.name === themeName)\n\n if (selectedPreset) {\n // Initialize light and dark mode colors from preset if not already set\n if (!data.themeConfiguration.lightMode) {\n data.themeConfiguration.lightMode = {}\n }\n if (!data.themeConfiguration.darkMode) {\n data.themeConfiguration.darkMode = {}\n }\n\n // Only populate if not manually edited (first time or empty)\n const isLightModeEmpty = !data.themeConfiguration.lightMode?.background\n const isDarkModeEmpty = !data.themeConfiguration.darkMode?.background\n\n if (isLightModeEmpty && selectedPreset.lightMode) {\n data.themeConfiguration.lightMode = { ...selectedPreset.lightMode }\n }\n\n if (isDarkModeEmpty && selectedPreset.darkMode) {\n data.themeConfiguration.darkMode = { ...selectedPreset.darkMode }\n }\n }\n }\n\n return data\n }\n\n const standaloneGlobal: GlobalConfig = {\n slug: standaloneCollectionSlug,\n label: standaloneCollectionLabel,\n admin: {\n group: 'Settings',\n ...createPreviewAdminConfig(normalizedLivePreview, enableLogging),\n },\n // Provide a broad access object but cast to GlobalConfig['access'] to satisfy types\n access: ((): GlobalConfig['access'] => {\n const accessObj = {\n read: () => true,\n create: ({ req }: { req?: { user?: unknown } }) => !!req?.user,\n update: ({ req }: { req?: { user?: unknown } }) => !!req?.user,\n delete: ({ req }: { req?: { user?: unknown } }) => !!req?.user,\n } as unknown as GlobalConfig['access']\n return accessObj\n })(),\n fields: tabFields,\n hooks: {\n beforeChange: [beforeChangeHook],\n afterChange: [\n async ({ doc, req }) => {\n // Invalidate cache after appearance settings change\n if (!req?.context?.disableRevalidate && normalizedCacheRevalidation.enabled) {\n try {\n await executeThemeRevalidation({\n tags: normalizedCacheRevalidation.tags,\n paths: normalizedCacheRevalidation.paths,\n enableLogging,\n logger: req?.payload?.logger,\n })\n } catch {\n // no-op: logging is handled in executeThemeRevalidation\n }\n }\n return doc\n },\n ],\n },\n }\n\n const globals = Array.isArray(config.globals) ? config.globals : []\n\n // Check if global already exists\n const existingIndex = globals.findIndex((g) => g.slug === standaloneCollectionSlug)\n\n if (existingIndex !== -1) {\n if (enableLogging) {\n console.warn(\n `🎨 Theme Management Plugin: global \"${standaloneCollectionSlug}\" already exists, skipping creation.`,\n )\n }\n return config\n }\n\n const currentEndpoints = ensureEndpointsArray(config.endpoints)\n const cacheEndpoint = createCacheRevalidationEndpoint({\n cacheRevalidation: normalizedCacheRevalidation,\n enableLogging,\n })\n const endpoints = mergeEndpoint(currentEndpoints, cacheEndpoint)\n\n return {\n ...config,\n endpoints,\n globals: [...globals, standaloneGlobal],\n }\n }\n\n // Otherwise, add as tab to existing collection\n let collectionTouched = false\n\n const collections = ensureCollectionsArray(config.collections).map((collection) => {\n if (collection.slug !== targetCollection) {\n return collection\n }\n\n collectionTouched = true\n\n if (enableLogging) {\n console.log(`🎨 Theme Management Plugin: enhancing collection \"${collection.slug}\"`)\n }\n\n const existingFields = Array.isArray(collection.fields) ? collection.fields : []\n\n const fields = injectThemeTab(existingFields, themeTab, enableLogging)\n\n const admin = {\n ...collection.admin,\n ...createPreviewAdminConfig(normalizedLivePreview, enableLogging),\n }\n\n return {\n ...collection,\n fields,\n admin,\n }\n })\n\n if (!collectionTouched) {\n if (enableLogging) {\n console.warn(\n `🎨 Theme Management Plugin: collection \"${targetCollection}\" was not found, leaving config untouched.`,\n )\n }\n return config\n }\n\n const currentEndpoints = ensureEndpointsArray(config.endpoints)\n const cacheEndpoint = createCacheRevalidationEndpoint({\n cacheRevalidation: normalizedCacheRevalidation,\n enableLogging,\n })\n const endpoints = mergeEndpoint(currentEndpoints, cacheEndpoint)\n\n return {\n ...config,\n endpoints,\n collections,\n }\n }\n}\n\ntype FetchOptionsInput = string | FetchThemeConfigurationOptions\n\nexport const fetchThemeConfiguration = async (\n options?: FetchOptionsInput,\n): Promise<SiteThemeConfiguration | null> => {\n const normalizedOptions = typeof options === 'string' ? { tenantSlug: options } : (options ?? {})\n\n const {\n tenantSlug,\n collectionSlug = 'site-settings', // Can be overridden to 'appearance-settings' if using standalone\n depth,\n locale,\n draft,\n queryParams = {},\n useGlobal = false, // Set to true if using standalone global instead of collection\n } = normalizedOptions\n\n try {\n if (useGlobal) {\n // Fetch from global endpoint\n const params = new URLSearchParams()\n\n if (typeof depth === 'number') params.set('depth', String(depth))\n // For globals, keep tenant param for backwards compatibility, and also add where[...] filter\n if (tenantSlug) {\n params.set('tenant', tenantSlug)\n params.set('where[tenant][equals]', String(tenantSlug))\n }\n\n Object.entries(queryParams).forEach(([key, value]) => {\n if (value === undefined) return\n params.set(key, String(value))\n })\n\n const queryString = params.toString()\n const url = `/api/globals/${collectionSlug}${queryString ? `?${queryString}` : ''}`\n\n const response = await fetch(url)\n if (!response.ok) {\n throw new Error(`Failed to fetch theme global (status ${response.status})`)\n }\n\n const data = (await response.json()) as {\n themeConfiguration?: SiteThemeConfiguration\n }\n\n return data?.themeConfiguration ?? null\n } else {\n // Fetch from collection endpoint (legacy/default behavior)\n const params = new URLSearchParams({ limit: '1' })\n\n if (typeof depth === 'number') params.set('depth', String(depth))\n // For collections, use a where[tenant][equals] filter so Payload's find endpoint applies tenant scoping\n if (tenantSlug) params.set('where[tenant][equals]', String(tenantSlug))\n if (locale) params.set('locale', locale)\n if (draft) params.set('draft', 'true')\n\n Object.entries(queryParams).forEach(([key, value]) => {\n if (value === undefined) return\n params.set(key, String(value))\n })\n\n const url = `/api/${collectionSlug}?${params.toString()}`\n\n const response = await fetch(url)\n if (!response.ok) {\n throw new Error(`Failed to fetch theme configuration (status ${response.status})`)\n }\n\n const data = (await response.json()) as {\n docs?: Array<{ themeConfiguration?: SiteThemeConfiguration }>\n }\n\n const doc = data.docs?.[0]\n\n return doc?.themeConfiguration ?? null\n }\n } catch (error) {\n console.warn('Failed to fetch theme configuration:', error)\n return null\n }\n}\n\nexport const getThemePreset = (themeName: string): ThemePreset | null => {\n return allThemePresets.find((preset) => preset.name === themeName) || null\n}\n\nexport const getAvailableThemePresets = (): ThemePreset[] => {\n return allThemePresets\n}\n\nexport { defaultThemePresets, allThemePresets } from './presets.js'\nexport type { ThemePreset, ThemeTypographyPreset } from './presets.js'\nexport type { ThemeTab } from './fields/themeConfigurationField.js'\nexport {\n extendedThemePresets,\n allExtendedThemePresets,\n extendedThemeToCSSVariables,\n} from './extended-presets.js'\nexport type { ExtendedThemePreset, ShadcnColorTokens } from './extended-presets.js'\nexport {\n applyExtendedTheme,\n generateExtendedThemeCSS,\n resetExtendedTheme,\n getExtendedThemeTokens,\n createUseExtendedTheme,\n getTailwindVarReferences,\n} from './utils/extendedThemeHelpers.js'\nexport type {\n ThemeManagementPluginOptions,\n ThemeManagementCacheRevalidationOptions,\n FetchThemeConfigurationOptions,\n ThemeManagementLivePreviewOptions,\n ThemeManagementLivePreviewUrlArgs,\n} from './types.js'\nexport {\n DEFAULT_THEME_CONFIGURATION,\n resolveThemeConfiguration,\n} from './utils/resolveThemeConfiguration.js'\nexport type { ResolvedThemeConfiguration } from './utils/resolveThemeConfiguration.js'\nexport { generateThemeColorsCss, hexToHsl } from './utils/themeColors.js'\nexport { generateThemeCSS, getThemeStyles } from './utils/themeUtils.js'\nexport { getThemeHtmlAttributes } from './utils/themeHtmlAttributes.js'\n\n// Dynamic theme CSS generation\nexport {\n generateThemeCSS as generatePresetCSS,\n generateAllThemesCSS,\n} from './utils/generateThemeCSS.js'\nexport { getThemeDynamicCSS, getAllDynamicThemesCSS } from './utils/themeCSS.js'\n\nexport type { Mode, ThemeDefaults } from './providers/Theme/types.js'\nexport { ThemeProvider } from './providers/Theme/index.js'\n\n// Font loading utilities for Next.js integration\nexport {\n getFontLoaderCode,\n getThemeFontFamilies,\n ThemeFontProvider,\n useThemeFonts,\n FONT_IMPORT_MAP,\n} from './providers/font-loader.js'\n\n// Note: Do NOT re-export client components from the root entry to avoid\n// server-side evaluation during `payload generate:importmap`.\n// If needed, import directly from subpath: `@kilivi/payloadcms-theme-management/fields/ThemeLivePreview`\n\nexport const ThemeManagementPlugin = themeManagementPlugin\n/** @deprecated use {@link themeManagementPlugin} */\nexport const themeConfigurationPlugin = themeManagementPlugin\n\n// Export plugin translations for consumers to merge into their payload translations\nexport {\n translations,\n getTranslations,\n registerTranslations,\n availableLanguages,\n} from './translations.js'\n\nexport default themeManagementPlugin\n"],"names":["createThemeConfigurationField","allThemePresets","getTranslations","translations","THEME_FIELD_NAME","removeExistingThemeField","fields","filter","field","candidate","name","findTabsField","type","removeExistingThemeTab","tabs","knownLabels","Object","values","map","t","tabLabel","tab","labelValues","label","matchesKnown","some","v","includes","injectThemeTab","themeTab","enableLogging","sanitizedFields","tabsField","console","warn","newTabsField","sanitizedTabs","updatedTabs","log","updatedTabsField","ensureCollectionsArray","collections","Array","isArray","ensureEndpointsArray","endpoints","normalizeLivePreviewOptions","livePreview","enabled","pageCollection","pageSlug","fallbackToFirstPage","tenantField","tenantQueryParam","breakpoints","undefined","raw","url","dedupeStrings","Set","value","trim","length","normalizeRoutePath","path","startsWith","normalizeCacheRevalidationOptions","args","cacheRevalidation","standaloneCollectionSlug","useStandaloneCollection","injectRoute","routePath","tags","paths","defaultTag","secret","asRecord","pickString","extractTenantValue","tenantRecord","id","slug","tenant","resolveTenantSlug","req","data","fromData","query","URLSearchParams","get","queryRecord","fromQuery","tenantSlug","tenantId","userRecord","user","fromUser","headers","Headers","headerRecord","buildDefaultPreviewPath","normalizedSlug","basePath","separator","encodeURIComponent","resolveLivePreviewUrl","tenantWhere","equals","homeWhere","and","preferredPageResponse","payload","find","collection","where","depth","draft","limit","overrideAccess","pagination","page","docs","fallbackResponse","pageRecord","resolvedPageSlug","error","logger","createPreviewAdminConfig","normalizedLivePreview","preview","options","readSecretFromRequest","requestRecord","headersValue","fromHeaders","requestWithJson","body","json","bodyRecord","fromBody","executeThemeRevalidation","revalidatePath","revalidateTag","forEach","tag","info","join","createCacheRevalidationEndpoint","method","handler","reqRecord","providedSecret","jsonResponse","result","ok","revalidated","mergeEndpoint","endpoint","withoutExisting","record","toLowerCase","status","Response","themeManagementPlugin","config","targetCollection","standaloneCollectionLabel","themePresets","defaultTheme","includeColorModeToggle","includeCustomCSS","includeBrandIdentity","enableAdvancedFeatures","normalizedCacheRevalidation","useThemePreviewField","tabFields","beforeChangeHook","themeConfiguration","theme","themeName","selectedPreset","p","lightMode","darkMode","isLightModeEmpty","background","isDarkModeEmpty","standaloneGlobal","admin","group","access","accessObj","read","create","update","delete","hooks","beforeChange","afterChange","doc","context","disableRevalidate","globals","existingIndex","findIndex","g","currentEndpoints","cacheEndpoint","collectionTouched","existingFields","fetchThemeConfiguration","normalizedOptions","collectionSlug","locale","queryParams","useGlobal","params","set","String","entries","key","queryString","toString","response","fetch","Error","getThemePreset","preset","getAvailableThemePresets","defaultThemePresets","extendedThemePresets","allExtendedThemePresets","extendedThemeToCSSVariables","applyExtendedTheme","generateExtendedThemeCSS","resetExtendedTheme","getExtendedThemeTokens","createUseExtendedTheme","getTailwindVarReferences","DEFAULT_THEME_CONFIGURATION","resolveThemeConfiguration","generateThemeColorsCss","hexToHsl","generateThemeCSS","getThemeStyles","getThemeHtmlAttributes","generatePresetCSS","generateAllThemesCSS","getThemeDynamicCSS","getAllDynamicThemesCSS","ThemeProvider","getFontLoaderCode","getThemeFontFamilies","ThemeFontProvider","useThemeFonts","FONT_IMPORT_MAP","ThemeManagementPlugin","themeConfigurationPlugin","registerTranslations","availableLanguages"],"mappings":"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"}
package/dist/server.d.ts CHANGED
@@ -1,4 +1,34 @@
1
1
  import 'server-only';
2
+ import type { SiteThemeConfiguration } from './payload-types.js';
2
3
  export { ServerThemeInjector } from './components/ServerThemeInjector.js';
3
4
  export { createFallbackCriticalCSS, getThemeCriticalCSS, getThemeCSS, generateThemePreloadLinks, getThemeCSSPath, } from './utils/themeAssets.js';
5
+ export declare const getThemeCacheTag: (globalSlug?: string) => string;
6
+ interface ThemeGlobalLike {
7
+ themeConfiguration?: SiteThemeConfiguration | null;
8
+ }
9
+ interface CreateCachedThemeFetcherOptions {
10
+ /** Function that loads the appearance global document. */
11
+ loadAppearanceSettings: () => Promise<ThemeGlobalLike | null | undefined>;
12
+ /** Optional global slug used for default cache tag and key (default: 'appearance-settings'). */
13
+ globalSlug?: string;
14
+ /** Additional cache key parts passed to unstable_cache. */
15
+ cacheKeyParts?: string[];
16
+ /** Additional tags to include besides the default `global_{slug}` tag. */
17
+ tags?: string[];
18
+ /** Next.js revalidate interval in seconds (default: 3600). */
19
+ revalidate?: number | false;
20
+ }
21
+ export declare const createCachedThemeFetcher: (options: CreateCachedThemeFetcherOptions) => () => Promise<import("./index.js").ResolvedThemeConfiguration>;
22
+ interface RevalidateThemeCacheOptions {
23
+ /** Optional global slug for default tag (default: 'appearance-settings'). */
24
+ globalSlug?: string;
25
+ /** Extra cache tags to invalidate. */
26
+ tags?: string[];
27
+ /** Optional paths to invalidate with revalidatePath. */
28
+ paths?: string[];
29
+ }
30
+ export declare const revalidateThemeCache: (options?: RevalidateThemeCacheOptions) => Promise<{
31
+ tags: string[];
32
+ paths: string[];
33
+ }>;
4
34
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAEpB,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAA;AAEzE,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,WAAW,EACX,yBAAyB,EACzB,eAAe,GAChB,MAAM,wBAAwB,CAAA"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAEpB,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAMhE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAA;AAEzE,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,WAAW,EACX,yBAAyB,EACzB,eAAe,GAChB,MAAM,wBAAwB,CAAA;AAE/B,eAAO,MAAM,gBAAgB,GAAI,mBAAkC,KAAG,MAC9C,CAAA;AAExB,UAAU,eAAe;IACvB,kBAAkB,CAAC,EAAE,sBAAsB,GAAG,IAAI,CAAA;CACnD;AAED,UAAU,+BAA+B;IACvC,0DAA0D;IAC1D,sBAAsB,EAAE,MAAM,OAAO,CAAC,eAAe,GAAG,IAAI,GAAG,SAAS,CAAC,CAAA;IACzE,gGAAgG;IAChG,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,2DAA2D;IAC3D,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;CAC5B;AAED,eAAO,MAAM,wBAAwB,GAAI,SAAS,+BAA+B,mEA0BhF,CAAA;AAED,UAAU,2BAA2B;IACnC,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,sCAAsC;IACtC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;CACjB;AAED,eAAO,MAAM,oBAAoB,GAC/B,UAAS,2BAAgC,KACxC,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAa7C,CAAA"}
package/dist/server.js CHANGED
@@ -1,5 +1,47 @@
1
1
  import 'server-only';
2
+ import { revalidatePath, revalidateTag, unstable_cache } from 'next/cache';
3
+ import { DEFAULT_THEME_CONFIGURATION, resolveThemeConfiguration } from './utils/resolveThemeConfiguration.js';
2
4
  export { ServerThemeInjector } from './components/ServerThemeInjector.js';
3
5
  export { createFallbackCriticalCSS, getThemeCriticalCSS, getThemeCSS, generateThemePreloadLinks, getThemeCSSPath } from './utils/themeAssets.js';
6
+ export const getThemeCacheTag = (globalSlug = 'appearance-settings')=>`global_${globalSlug}`;
7
+ export const createCachedThemeFetcher = (options)=>{
8
+ const { loadAppearanceSettings, globalSlug = 'appearance-settings', cacheKeyParts = [], tags = [], revalidate = 3600 } = options;
9
+ const defaultTag = getThemeCacheTag(globalSlug);
10
+ const cacheKey = [
11
+ `${globalSlug}-theme`,
12
+ ...cacheKeyParts
13
+ ];
14
+ const cacheTags = [
15
+ ...new Set([
16
+ defaultTag,
17
+ ...tags
18
+ ].filter(Boolean))
19
+ ];
20
+ return unstable_cache(async ()=>{
21
+ const appearanceSettings = await loadAppearanceSettings();
22
+ return resolveThemeConfiguration(appearanceSettings?.themeConfiguration ?? DEFAULT_THEME_CONFIGURATION);
23
+ }, cacheKey, {
24
+ tags: cacheTags,
25
+ revalidate
26
+ });
27
+ };
28
+ export const revalidateThemeCache = async (options = {})=>{
29
+ const { globalSlug = 'appearance-settings', tags = [], paths = [] } = options;
30
+ const resolvedTags = [
31
+ ...new Set([
32
+ getThemeCacheTag(globalSlug),
33
+ ...tags
34
+ ].filter(Boolean))
35
+ ];
36
+ const resolvedPaths = [
37
+ ...new Set(paths.filter((value)=>typeof value === 'string' && value))
38
+ ];
39
+ resolvedTags.forEach((tag)=>revalidateTag(tag));
40
+ resolvedPaths.forEach((path)=>revalidatePath(path));
41
+ return {
42
+ tags: resolvedTags,
43
+ paths: resolvedPaths
44
+ };
45
+ };
4
46
 
5
47
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts"],"sourcesContent":["import 'server-only'\n\nexport { ServerThemeInjector } from './components/ServerThemeInjector.js'\n\nexport {\n createFallbackCriticalCSS,\n getThemeCriticalCSS,\n getThemeCSS,\n generateThemePreloadLinks,\n getThemeCSSPath,\n} from './utils/themeAssets.js'\n"],"names":["ServerThemeInjector","createFallbackCriticalCSS","getThemeCriticalCSS","getThemeCSS","generateThemePreloadLinks","getThemeCSSPath"],"mappings":"AAAA,OAAO,cAAa;AAEpB,SAASA,mBAAmB,QAAQ,sCAAqC;AAEzE,SACEC,yBAAyB,EACzBC,mBAAmB,EACnBC,WAAW,EACXC,yBAAyB,EACzBC,eAAe,QACV,yBAAwB"}
1
+ {"version":3,"sources":["../src/server.ts"],"sourcesContent":["import 'server-only'\nimport { revalidatePath, revalidateTag, unstable_cache } from 'next/cache'\nimport type { SiteThemeConfiguration } from './payload-types.js'\nimport {\n DEFAULT_THEME_CONFIGURATION,\n resolveThemeConfiguration,\n} from './utils/resolveThemeConfiguration.js'\n\nexport { ServerThemeInjector } from './components/ServerThemeInjector.js'\n\nexport {\n createFallbackCriticalCSS,\n getThemeCriticalCSS,\n getThemeCSS,\n generateThemePreloadLinks,\n getThemeCSSPath,\n} from './utils/themeAssets.js'\n\nexport const getThemeCacheTag = (globalSlug = 'appearance-settings'): string =>\n `global_${globalSlug}`\n\ninterface ThemeGlobalLike {\n themeConfiguration?: SiteThemeConfiguration | null\n}\n\ninterface CreateCachedThemeFetcherOptions {\n /** Function that loads the appearance global document. */\n loadAppearanceSettings: () => Promise<ThemeGlobalLike | null | undefined>\n /** Optional global slug used for default cache tag and key (default: 'appearance-settings'). */\n globalSlug?: string\n /** Additional cache key parts passed to unstable_cache. */\n cacheKeyParts?: string[]\n /** Additional tags to include besides the default `global_{slug}` tag. */\n tags?: string[]\n /** Next.js revalidate interval in seconds (default: 3600). */\n revalidate?: number | false\n}\n\nexport const createCachedThemeFetcher = (options: CreateCachedThemeFetcherOptions) => {\n const {\n loadAppearanceSettings,\n globalSlug = 'appearance-settings',\n cacheKeyParts = [],\n tags = [],\n revalidate = 3600,\n } = options\n\n const defaultTag = getThemeCacheTag(globalSlug)\n const cacheKey = [`${globalSlug}-theme`, ...cacheKeyParts]\n const cacheTags = [...new Set([defaultTag, ...tags].filter(Boolean))]\n\n return unstable_cache(\n async () => {\n const appearanceSettings = await loadAppearanceSettings()\n return resolveThemeConfiguration(\n appearanceSettings?.themeConfiguration ?? DEFAULT_THEME_CONFIGURATION,\n )\n },\n cacheKey,\n {\n tags: cacheTags,\n revalidate,\n },\n )\n}\n\ninterface RevalidateThemeCacheOptions {\n /** Optional global slug for default tag (default: 'appearance-settings'). */\n globalSlug?: string\n /** Extra cache tags to invalidate. */\n tags?: string[]\n /** Optional paths to invalidate with revalidatePath. */\n paths?: string[]\n}\n\nexport const revalidateThemeCache = async (\n options: RevalidateThemeCacheOptions = {},\n): Promise<{ tags: string[]; paths: string[] }> => {\n const { globalSlug = 'appearance-settings', tags = [], paths = [] } = options\n\n const resolvedTags = [...new Set([getThemeCacheTag(globalSlug), ...tags].filter(Boolean))]\n const resolvedPaths = [...new Set(paths.filter((value) => typeof value === 'string' && value))]\n\n resolvedTags.forEach((tag) => revalidateTag(tag))\n resolvedPaths.forEach((path) => revalidatePath(path))\n\n return {\n tags: resolvedTags,\n paths: resolvedPaths,\n }\n}\n"],"names":["revalidatePath","revalidateTag","unstable_cache","DEFAULT_THEME_CONFIGURATION","resolveThemeConfiguration","ServerThemeInjector","createFallbackCriticalCSS","getThemeCriticalCSS","getThemeCSS","generateThemePreloadLinks","getThemeCSSPath","getThemeCacheTag","globalSlug","createCachedThemeFetcher","options","loadAppearanceSettings","cacheKeyParts","tags","revalidate","defaultTag","cacheKey","cacheTags","Set","filter","Boolean","appearanceSettings","themeConfiguration","revalidateThemeCache","paths","resolvedTags","resolvedPaths","value","forEach","tag","path"],"mappings":"AAAA,OAAO,cAAa;AACpB,SAASA,cAAc,EAAEC,aAAa,EAAEC,cAAc,QAAQ,aAAY;AAE1E,SACEC,2BAA2B,EAC3BC,yBAAyB,QACpB,uCAAsC;AAE7C,SAASC,mBAAmB,QAAQ,sCAAqC;AAEzE,SACEC,yBAAyB,EACzBC,mBAAmB,EACnBC,WAAW,EACXC,yBAAyB,EACzBC,eAAe,QACV,yBAAwB;AAE/B,OAAO,MAAMC,mBAAmB,CAACC,aAAa,qBAAqB,GACjE,CAAC,OAAO,EAAEA,YAAY,CAAA;AAmBxB,OAAO,MAAMC,2BAA2B,CAACC;IACvC,MAAM,EACJC,sBAAsB,EACtBH,aAAa,qBAAqB,EAClCI,gBAAgB,EAAE,EAClBC,OAAO,EAAE,EACTC,aAAa,IAAI,EAClB,GAAGJ;IAEJ,MAAMK,aAAaR,iBAAiBC;IACpC,MAAMQ,WAAW;QAAC,GAAGR,WAAW,MAAM,CAAC;WAAKI;KAAc;IAC1D,MAAMK,YAAY;WAAI,IAAIC,IAAI;YAACH;eAAeF;SAAK,CAACM,MAAM,CAACC;KAAU;IAErE,OAAOtB,eACL;QACE,MAAMuB,qBAAqB,MAAMV;QACjC,OAAOX,0BACLqB,oBAAoBC,sBAAsBvB;IAE9C,GACAiB,UACA;QACEH,MAAMI;QACNH;IACF;AAEJ,EAAC;AAWD,OAAO,MAAMS,uBAAuB,OAClCb,UAAuC,CAAC,CAAC;IAEzC,MAAM,EAAEF,aAAa,qBAAqB,EAAEK,OAAO,EAAE,EAAEW,QAAQ,EAAE,EAAE,GAAGd;IAEtE,MAAMe,eAAe;WAAI,IAAIP,IAAI;YAACX,iBAAiBC;eAAgBK;SAAK,CAACM,MAAM,CAACC;KAAU;IAC1F,MAAMM,gBAAgB;WAAI,IAAIR,IAAIM,MAAML,MAAM,CAAC,CAACQ,QAAU,OAAOA,UAAU,YAAYA;KAAQ;IAE/FF,aAAaG,OAAO,CAAC,CAACC,MAAQhC,cAAcgC;IAC5CH,cAAcE,OAAO,CAAC,CAACE,OAASlC,eAAekC;IAE/C,OAAO;QACLjB,MAAMY;QACND,OAAOE;IACT;AACF,EAAC"}
@@ -0,0 +1,2 @@
1
+
2
+ //# sourceMappingURL=color.d.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/types/color.d.ts"],"names":[],"mappings":""}
package/dist/types.d.ts CHANGED
@@ -1,4 +1,69 @@
1
1
  import type { ThemePreset } from './presets.js';
2
+ export interface ThemeManagementLivePreviewUrlArgs {
3
+ /** Resolved preview page document (if found) */
4
+ page?: Record<string, unknown>;
5
+ /** Resolved preview page slug */
6
+ pageSlug: string;
7
+ /** Inferred tenant identifier (if available) */
8
+ tenantSlug?: string;
9
+ /** Current Payload request */
10
+ req: {
11
+ payload: {
12
+ find: (args: Record<string, unknown>) => Promise<{
13
+ docs?: Array<Record<string, unknown>>;
14
+ }>;
15
+ logger?: {
16
+ warn?: (...args: unknown[]) => void;
17
+ };
18
+ };
19
+ query?: unknown;
20
+ headers?: unknown;
21
+ user?: unknown;
22
+ };
23
+ }
24
+ export interface ThemeManagementLivePreviewOptions {
25
+ /** Enable Payload admin live preview for the target config (default: true) */
26
+ enabled?: boolean;
27
+ /** Collection slug containing preview pages (default: 'pages') */
28
+ pageCollection?: string;
29
+ /** Preferred page slug for preview (default: 'home') */
30
+ pageSlug?: string;
31
+ /** Fallback to first page if preferred slug does not exist (default: true) */
32
+ fallbackToFirstPage?: boolean;
33
+ /** Tenant field name used for filtering in multi-tenant setups (default: 'tenant') */
34
+ tenantField?: string;
35
+ /** Query param name appended to default URL when tenant is resolved (default: 'tenant') */
36
+ tenantQueryParam?: string;
37
+ /**
38
+ * Device breakpoints shown in Payload's Live Preview toolbar (iframe size presets).
39
+ * Use this to make preview sizing more practical for your editors.
40
+ */
41
+ breakpoints?: Array<{
42
+ name: string;
43
+ label: string;
44
+ width: number | string;
45
+ height: number | string;
46
+ }>;
47
+ /**
48
+ * Custom URL resolver for Payload live preview.
49
+ * Defaults to `/${slug}` (or `/` for `home`) with optional tenant query param.
50
+ */
51
+ url?: (args: ThemeManagementLivePreviewUrlArgs) => string | Promise<string>;
52
+ }
53
+ export interface ThemeManagementCacheRevalidationOptions {
54
+ /** Enable cache revalidation support (default: true for standalone mode, false for tab mode) */
55
+ enabled?: boolean;
56
+ /** Inject a Payload endpoint for manual/external revalidation triggers (default: true) */
57
+ injectRoute?: boolean;
58
+ /** Endpoint path under Payload API (default: '/theme/revalidate') */
59
+ routePath?: string;
60
+ /** Optional shared secret checked against header/body/query before revalidation */
61
+ secret?: string;
62
+ /** Additional tags to revalidate together with the default global tag */
63
+ tags?: string[];
64
+ /** Optional paths to revalidate together with tags */
65
+ paths?: string[];
66
+ }
2
67
  export interface ThemeManagementPluginOptions {
3
68
  /** Whether the plugin should register itself */
4
69
  enabled?: boolean;
@@ -24,6 +89,10 @@ export interface ThemeManagementPluginOptions {
24
89
  enableAdvancedFeatures?: boolean;
25
90
  /** Log helpful messages during config mutation */
26
91
  enableLogging?: boolean;
92
+ /** Configure Payload admin live preview URL generation */
93
+ livePreview?: boolean | ThemeManagementLivePreviewOptions;
94
+ /** Configure cache revalidation route and tags for Next.js `unstable_cache` usage */
95
+ cacheRevalidation?: boolean | ThemeManagementCacheRevalidationOptions;
27
96
  }
28
97
  export interface FetchThemeConfigurationOptions {
29
98
  /** Optional tenant identifier if your project is multi-tenant */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE/C,MAAM,WAAW,4BAA4B;IAC3C,gDAAgD;IAChD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,iFAAiF;IACjF,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,iFAAiF;IACjF,uBAAuB,CAAC,EAAE,OAAO,CAAA;IACjC,yEAAyE;IACzE,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,2EAA2E;IAC3E,yBAAyB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3D,yCAAyC;IACzC,YAAY,CAAC,EAAE,WAAW,EAAE,CAAA;IAC5B,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,gEAAgE;IAChE,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,+BAA+B;IAC/B,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,gDAAgD;IAChD,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,uDAAuD;IACvD,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,kDAAkD;IAClD,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED,MAAM,WAAW,8BAA8B;IAC7C,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iEAAiE;IACjE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8BAA8B;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAA;IACvD,oFAAoF;IACpF,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE/C,MAAM,WAAW,iCAAiC;IAChD,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,iCAAiC;IACjC,QAAQ,EAAE,MAAM,CAAA;IAChB,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,8BAA8B;IAC9B,GAAG,EAAE;QACH,OAAO,EAAE;YACP,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;gBAAE,IAAI,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;aAAE,CAAC,CAAA;YAC3F,MAAM,CAAC,EAAE;gBACP,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;aACpC,CAAA;SACF,CAAA;QACD,KAAK,CAAC,EAAE,OAAO,CAAA;QACf,OAAO,CAAC,EAAE,OAAO,CAAA;QACjB,IAAI,CAAC,EAAE,OAAO,CAAA;KACf,CAAA;CACF;AAED,MAAM,WAAW,iCAAiC;IAChD,8EAA8E;IAC9E,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,kEAAkE;IAClE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,8EAA8E;IAC9E,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,sFAAsF;IACtF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,2FAA2F;IAC3F,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;OAGG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC;QAClB,IAAI,EAAE,MAAM,CAAA;QACZ,KAAK,EAAE,MAAM,CAAA;QACb,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;QACtB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAA;KACxB,CAAC,CAAA;IACF;;;OAGG;IACH,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,iCAAiC,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;CAC5E;AAED,MAAM,WAAW,uCAAuC;IACtD,gGAAgG;IAChG,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,0FAA0F;IAC1F,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,yEAAyE;IACzE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;CACjB;AAED,MAAM,WAAW,4BAA4B;IAC3C,gDAAgD;IAChD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,iFAAiF;IACjF,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,iFAAiF;IACjF,uBAAuB,CAAC,EAAE,OAAO,CAAA;IACjC,yEAAyE;IACzE,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,2EAA2E;IAC3E,yBAAyB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3D,yCAAyC;IACzC,YAAY,CAAC,EAAE,WAAW,EAAE,CAAA;IAC5B,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,gEAAgE;IAChE,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,+BAA+B;IAC/B,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,gDAAgD;IAChD,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,uDAAuD;IACvD,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,kDAAkD;IAClD,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,0DAA0D;IAC1D,WAAW,CAAC,EAAE,OAAO,GAAG,iCAAiC,CAAA;IACzD,qFAAqF;IACrF,iBAAiB,CAAC,EAAE,OAAO,GAAG,uCAAuC,CAAA;CACtE;AAED,MAAM,WAAW,8BAA8B;IAC7C,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iEAAiE;IACjE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8BAA8B;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAA;IACvD,oFAAoF;IACpF,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB"}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { ThemePreset } from './presets.js'\n\nexport interface ThemeManagementPluginOptions {\n /** Whether the plugin should register itself */\n enabled?: boolean\n /** Collection slug that stores site-level settings (default: `site-settings`) */\n targetCollection?: string\n /** Create a standalone collection instead of adding as a tab (default: false) */\n useStandaloneCollection?: boolean\n /** Name of the standalone collection (default: 'appearance-settings') */\n standaloneCollectionSlug?: string\n /** Label for the standalone collection (default: 'Appearance Settings') */\n standaloneCollectionLabel?: string | Record<string, string>\n /** Theme presets available to editors */\n themePresets?: ThemePreset[]\n /** Default preset name when no value is stored */\n defaultTheme?: string\n /** Allow editors to toggle between light / dark / auto modes */\n includeColorModeToggle?: boolean\n /** Expose custom CSS editor */\n includeCustomCSS?: boolean\n /** Reserved for future use, keeps API parity */\n includeBrandIdentity?: boolean\n /** Enable advanced controls such as animation level */\n enableAdvancedFeatures?: boolean\n /** Log helpful messages during config mutation */\n enableLogging?: boolean\n}\n\nexport interface FetchThemeConfigurationOptions {\n /** Optional tenant identifier if your project is multi-tenant */\n tenantSlug?: string\n /** Collection/Global slug override (default: `site-settings`) */\n collectionSlug?: string\n /** Depth parameter passed to Payload REST API */\n depth?: number\n /** Locale parameter passed to Payload REST API */\n locale?: string\n /** Include draft documents */\n draft?: boolean\n /** Extra query parameters to append to the request */\n queryParams?: Record<string, string | number | boolean>\n /** Set to true if using standalone global instead of collection (default: false) */\n useGlobal?: boolean\n}\n"],"names":[],"mappings":"AA6BA,WAeC"}
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { ThemePreset } from './presets.js'\n\nexport interface ThemeManagementLivePreviewUrlArgs {\n /** Resolved preview page document (if found) */\n page?: Record<string, unknown>\n /** Resolved preview page slug */\n pageSlug: string\n /** Inferred tenant identifier (if available) */\n tenantSlug?: string\n /** Current Payload request */\n req: {\n payload: {\n find: (args: Record<string, unknown>) => Promise<{ docs?: Array<Record<string, unknown>> }>\n logger?: {\n warn?: (...args: unknown[]) => void\n }\n }\n query?: unknown\n headers?: unknown\n user?: unknown\n }\n}\n\nexport interface ThemeManagementLivePreviewOptions {\n /** Enable Payload admin live preview for the target config (default: true) */\n enabled?: boolean\n /** Collection slug containing preview pages (default: 'pages') */\n pageCollection?: string\n /** Preferred page slug for preview (default: 'home') */\n pageSlug?: string\n /** Fallback to first page if preferred slug does not exist (default: true) */\n fallbackToFirstPage?: boolean\n /** Tenant field name used for filtering in multi-tenant setups (default: 'tenant') */\n tenantField?: string\n /** Query param name appended to default URL when tenant is resolved (default: 'tenant') */\n tenantQueryParam?: string\n /**\n * Device breakpoints shown in Payload's Live Preview toolbar (iframe size presets).\n * Use this to make preview sizing more practical for your editors.\n */\n breakpoints?: Array<{\n name: string\n label: string\n width: number | string\n height: number | string\n }>\n /**\n * Custom URL resolver for Payload live preview.\n * Defaults to `/${slug}` (or `/` for `home`) with optional tenant query param.\n */\n url?: (args: ThemeManagementLivePreviewUrlArgs) => string | Promise<string>\n}\n\nexport interface ThemeManagementCacheRevalidationOptions {\n /** Enable cache revalidation support (default: true for standalone mode, false for tab mode) */\n enabled?: boolean\n /** Inject a Payload endpoint for manual/external revalidation triggers (default: true) */\n injectRoute?: boolean\n /** Endpoint path under Payload API (default: '/theme/revalidate') */\n routePath?: string\n /** Optional shared secret checked against header/body/query before revalidation */\n secret?: string\n /** Additional tags to revalidate together with the default global tag */\n tags?: string[]\n /** Optional paths to revalidate together with tags */\n paths?: string[]\n}\n\nexport interface ThemeManagementPluginOptions {\n /** Whether the plugin should register itself */\n enabled?: boolean\n /** Collection slug that stores site-level settings (default: `site-settings`) */\n targetCollection?: string\n /** Create a standalone collection instead of adding as a tab (default: false) */\n useStandaloneCollection?: boolean\n /** Name of the standalone collection (default: 'appearance-settings') */\n standaloneCollectionSlug?: string\n /** Label for the standalone collection (default: 'Appearance Settings') */\n standaloneCollectionLabel?: string | Record<string, string>\n /** Theme presets available to editors */\n themePresets?: ThemePreset[]\n /** Default preset name when no value is stored */\n defaultTheme?: string\n /** Allow editors to toggle between light / dark / auto modes */\n includeColorModeToggle?: boolean\n /** Expose custom CSS editor */\n includeCustomCSS?: boolean\n /** Reserved for future use, keeps API parity */\n includeBrandIdentity?: boolean\n /** Enable advanced controls such as animation level */\n enableAdvancedFeatures?: boolean\n /** Log helpful messages during config mutation */\n enableLogging?: boolean\n /** Configure Payload admin live preview URL generation */\n livePreview?: boolean | ThemeManagementLivePreviewOptions\n /** Configure cache revalidation route and tags for Next.js `unstable_cache` usage */\n cacheRevalidation?: boolean | ThemeManagementCacheRevalidationOptions\n}\n\nexport interface FetchThemeConfigurationOptions {\n /** Optional tenant identifier if your project is multi-tenant */\n tenantSlug?: string\n /** Collection/Global slug override (default: `site-settings`) */\n collectionSlug?: string\n /** Depth parameter passed to Payload REST API */\n depth?: number\n /** Locale parameter passed to Payload REST API */\n locale?: string\n /** Include draft documents */\n draft?: boolean\n /** Extra query parameters to append to the request */\n queryParams?: Record<string, string | number | boolean>\n /** Set to true if using standalone global instead of collection (default: false) */\n useGlobal?: boolean\n}\n"],"names":[],"mappings":"AAmGA,WAeC"}
@@ -0,0 +1,17 @@
1
+ export interface CreateThemeLivePreviewRefreshOptions {
2
+ /** Endpoint exposed by theme-management plugin for cache revalidation. */
3
+ endpoint?: string;
4
+ /** Optional secret sent as x-theme-revalidate-secret header. */
5
+ secret?: string;
6
+ /** Request credentials mode (default: include). */
7
+ credentials?: RequestCredentials;
8
+ /** Optional callback triggered when revalidation request fails. */
9
+ onError?: (error: unknown) => void;
10
+ /** Optional callback executed after revalidation attempt (typically router.refresh). */
11
+ onAfterRevalidate?: () => void | Promise<void>;
12
+ /** Test hook to override fetch implementation. */
13
+ fetchImpl?: typeof fetch;
14
+ }
15
+ export declare const DEFAULT_THEME_REVALIDATE_ENDPOINT = "/api/theme/revalidate";
16
+ export declare const createThemeLivePreviewRefresh: (options?: CreateThemeLivePreviewRefreshOptions) => (() => Promise<void>);
17
+ //# sourceMappingURL=livePreviewRefresh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"livePreviewRefresh.d.ts","sourceRoot":"","sources":["../../src/utils/livePreviewRefresh.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oCAAoC;IACnD,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,mDAAmD;IACnD,WAAW,CAAC,EAAE,kBAAkB,CAAA;IAChC,mEAAmE;IACnE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAClC,wFAAwF;IACxF,iBAAiB,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9C,kDAAkD;IAClD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CACzB;AAED,eAAO,MAAM,iCAAiC,0BAA0B,CAAA;AAExE,eAAO,MAAM,6BAA6B,GACxC,UAAS,oCAAyC,KACjD,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CA4BtB,CAAA"}
@@ -0,0 +1,20 @@
1
+ export const DEFAULT_THEME_REVALIDATE_ENDPOINT = '/api/theme/revalidate';
2
+ export const createThemeLivePreviewRefresh = (options = {})=>{
3
+ const { endpoint = process.env.NEXT_PUBLIC_THEME_REVALIDATE_ENDPOINT || DEFAULT_THEME_REVALIDATE_ENDPOINT, secret = process.env.NEXT_PUBLIC_THEME_REVALIDATE_SECRET, credentials = 'include', onError, onAfterRevalidate, fetchImpl = fetch } = options;
4
+ return async ()=>{
5
+ try {
6
+ await fetchImpl(endpoint, {
7
+ method: 'POST',
8
+ credentials,
9
+ headers: secret ? {
10
+ 'x-theme-revalidate-secret': secret
11
+ } : undefined
12
+ });
13
+ } catch (error) {
14
+ onError?.(error);
15
+ }
16
+ await onAfterRevalidate?.();
17
+ };
18
+ };
19
+
20
+ //# sourceMappingURL=livePreviewRefresh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/livePreviewRefresh.ts"],"sourcesContent":["export interface CreateThemeLivePreviewRefreshOptions {\n /** Endpoint exposed by theme-management plugin for cache revalidation. */\n endpoint?: string\n /** Optional secret sent as x-theme-revalidate-secret header. */\n secret?: string\n /** Request credentials mode (default: include). */\n credentials?: RequestCredentials\n /** Optional callback triggered when revalidation request fails. */\n onError?: (error: unknown) => void\n /** Optional callback executed after revalidation attempt (typically router.refresh). */\n onAfterRevalidate?: () => void | Promise<void>\n /** Test hook to override fetch implementation. */\n fetchImpl?: typeof fetch\n}\n\nexport const DEFAULT_THEME_REVALIDATE_ENDPOINT = '/api/theme/revalidate'\n\nexport const createThemeLivePreviewRefresh = (\n options: CreateThemeLivePreviewRefreshOptions = {},\n): (() => Promise<void>) => {\n const {\n endpoint = process.env.NEXT_PUBLIC_THEME_REVALIDATE_ENDPOINT ||\n DEFAULT_THEME_REVALIDATE_ENDPOINT,\n secret = process.env.NEXT_PUBLIC_THEME_REVALIDATE_SECRET,\n credentials = 'include',\n onError,\n onAfterRevalidate,\n fetchImpl = fetch,\n } = options\n\n return async () => {\n try {\n await fetchImpl(endpoint, {\n method: 'POST',\n credentials,\n headers: secret\n ? {\n 'x-theme-revalidate-secret': secret,\n }\n : undefined,\n })\n } catch (error) {\n onError?.(error)\n }\n\n await onAfterRevalidate?.()\n }\n}\n"],"names":["DEFAULT_THEME_REVALIDATE_ENDPOINT","createThemeLivePreviewRefresh","options","endpoint","process","env","NEXT_PUBLIC_THEME_REVALIDATE_ENDPOINT","secret","NEXT_PUBLIC_THEME_REVALIDATE_SECRET","credentials","onError","onAfterRevalidate","fetchImpl","fetch","method","headers","undefined","error"],"mappings":"AAeA,OAAO,MAAMA,oCAAoC,wBAAuB;AAExE,OAAO,MAAMC,gCAAgC,CAC3CC,UAAgD,CAAC,CAAC;IAElD,MAAM,EACJC,WAAWC,QAAQC,GAAG,CAACC,qCAAqC,IAC1DN,iCAAiC,EACnCO,SAASH,QAAQC,GAAG,CAACG,mCAAmC,EACxDC,cAAc,SAAS,EACvBC,OAAO,EACPC,iBAAiB,EACjBC,YAAYC,KAAK,EAClB,GAAGX;IAEJ,OAAO;QACL,IAAI;YACF,MAAMU,UAAUT,UAAU;gBACxBW,QAAQ;gBACRL;gBACAM,SAASR,SACL;oBACE,6BAA6BA;gBAC/B,IACAS;YACN;QACF,EAAE,OAAOC,OAAO;YACdP,UAAUO;QACZ;QAEA,MAAMN;IACR;AACF,EAAC"}
@@ -0,0 +1,7 @@
1
+ export declare const extractThemeConfigurationFromLiveData: (liveData: Record<string, unknown>, themeConfigurationKey?: string) => unknown;
2
+ export declare const buildLivePreviewThemeRuntime: (themeConfiguration: unknown) => {
3
+ theme: "cyberpunk" | "minimal" | "retro" | "brutal" | "pastel" | "ocean" | "forest" | "sunset" | "lavender" | "neutral" | "blue" | "green" | "red" | "orange" | "rose" | "violet" | "zinc" | "slate" | "stone" | "gray" | "cool" | "neon" | "solar" | "dealership" | "real-estate" | "real-estate-gold" | "real-estate-neutral";
4
+ mode: "light" | "dark";
5
+ css: string;
6
+ };
7
+ //# sourceMappingURL=livePreviewThemeRuntime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"livePreviewThemeRuntime.d.ts","sourceRoot":"","sources":["../../src/utils/livePreviewThemeRuntime.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,qCAAqC,GAChD,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,8BAA4C,KAC3C,OAOF,CAAA;AAkBD,eAAO,MAAM,4BAA4B,GAAI,oBAAoB,OAAO;;;;CA0CvE,CAAA"}
@@ -0,0 +1,58 @@
1
+ import { getBorderRadiusConfig } from '../providers/Theme/themeConfig.js';
2
+ import { resolveThemeConfiguration } from './resolveThemeConfiguration.js';
3
+ import { generateThemeColorsCss } from './themeColors.js';
4
+ import { generateThemeCSS } from './themeUtils.js';
5
+ export const extractThemeConfigurationFromLiveData = (liveData, themeConfigurationKey = 'themeConfiguration')=>{
6
+ const candidate = liveData?.[themeConfigurationKey];
7
+ if (candidate && typeof candidate === 'object') {
8
+ return candidate;
9
+ }
10
+ return liveData;
11
+ };
12
+ const resolveColorMode = (mode)=>{
13
+ if (mode === 'dark') {
14
+ return 'dark';
15
+ }
16
+ if (mode === 'auto' && globalThis.window !== undefined && typeof globalThis.window.matchMedia === 'function') {
17
+ return globalThis.window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
18
+ }
19
+ return 'light';
20
+ };
21
+ export const buildLivePreviewThemeRuntime = (themeConfiguration)=>{
22
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
23
+ const resolved = resolveThemeConfiguration(themeConfiguration);
24
+ const borderRadiusMap = {
25
+ none: 'none',
26
+ small: 'small',
27
+ medium: 'medium',
28
+ large: 'large',
29
+ xl: 'xl',
30
+ full: 'xl'
31
+ };
32
+ const mappedBorderRadius = borderRadiusMap[resolved.borderRadius ?? 'medium'] ?? 'medium';
33
+ const borderRadiusConfig = getBorderRadiusConfig(mappedBorderRadius);
34
+ const cssRecord = typeof borderRadiusConfig?.css === 'string' ? {
35
+ '--radius-default': borderRadiusConfig.css
36
+ } : borderRadiusConfig?.css ?? {};
37
+ const borderRadiusCSS = Object.entries(cssRecord).map(([property, value])=>` ${property}: ${value};`).join('\n');
38
+ const borderRadiusBlock = borderRadiusCSS ? `:root {\n${borderRadiusCSS}\n}` : '';
39
+ const themeConfigurationCSS = generateThemeCSS(resolved);
40
+ const colorModesCSS = generateThemeColorsCss({
41
+ themeName: resolved.theme,
42
+ lightMode: resolved.lightMode,
43
+ darkMode: resolved.darkMode
44
+ });
45
+ const customCSSBlock = typeof resolved.customCSS === 'string' ? resolved.customCSS.trim() : '';
46
+ return {
47
+ theme: resolved.theme,
48
+ mode: resolveColorMode(resolved.colorMode),
49
+ css: [
50
+ borderRadiusBlock,
51
+ themeConfigurationCSS,
52
+ colorModesCSS,
53
+ customCSSBlock
54
+ ].filter((block)=>Boolean(block?.trim?.().length)).join('\n\n')
55
+ };
56
+ };
57
+
58
+ //# sourceMappingURL=livePreviewThemeRuntime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/livePreviewThemeRuntime.ts"],"sourcesContent":["import { getBorderRadiusConfig } from '../providers/Theme/themeConfig.js'\nimport { resolveThemeConfiguration } from './resolveThemeConfiguration.js'\nimport { generateThemeColorsCss } from './themeColors.js'\nimport { generateThemeCSS } from './themeUtils.js'\n\nexport const extractThemeConfigurationFromLiveData = (\n liveData: Record<string, unknown>,\n themeConfigurationKey = 'themeConfiguration',\n): unknown => {\n const candidate = liveData?.[themeConfigurationKey]\n if (candidate && typeof candidate === 'object') {\n return candidate\n }\n\n return liveData\n}\n\nconst resolveColorMode = (mode: string): 'light' | 'dark' => {\n if (mode === 'dark') {\n return 'dark'\n }\n\n if (\n mode === 'auto' &&\n globalThis.window !== undefined &&\n typeof globalThis.window.matchMedia === 'function'\n ) {\n return globalThis.window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'\n }\n\n return 'light'\n}\n\nexport const buildLivePreviewThemeRuntime = (themeConfiguration: unknown) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const resolved = resolveThemeConfiguration(themeConfiguration as any)\n\n const borderRadiusMap: Record<string, 'none' | 'small' | 'medium' | 'large' | 'xl'> = {\n none: 'none',\n small: 'small',\n medium: 'medium',\n large: 'large',\n xl: 'xl',\n full: 'xl',\n }\n\n const mappedBorderRadius = borderRadiusMap[resolved.borderRadius ?? 'medium'] ?? 'medium'\n const borderRadiusConfig = getBorderRadiusConfig(mappedBorderRadius)\n const cssRecord =\n typeof borderRadiusConfig?.css === 'string'\n ? { '--radius-default': borderRadiusConfig.css }\n : (borderRadiusConfig?.css ?? {})\n\n const borderRadiusCSS = Object.entries(cssRecord)\n .map(([property, value]) => ` ${property}: ${value};`)\n .join('\\n')\n\n const borderRadiusBlock = borderRadiusCSS ? `:root {\\n${borderRadiusCSS}\\n}` : ''\n\n const themeConfigurationCSS = generateThemeCSS(resolved)\n const colorModesCSS = generateThemeColorsCss({\n themeName: resolved.theme,\n lightMode: resolved.lightMode,\n darkMode: resolved.darkMode,\n })\n\n const customCSSBlock = typeof resolved.customCSS === 'string' ? resolved.customCSS.trim() : ''\n\n return {\n theme: resolved.theme,\n mode: resolveColorMode(resolved.colorMode),\n css: [borderRadiusBlock, themeConfigurationCSS, colorModesCSS, customCSSBlock]\n .filter((block) => Boolean(block?.trim?.().length))\n .join('\\n\\n'),\n }\n}\n"],"names":["getBorderRadiusConfig","resolveThemeConfiguration","generateThemeColorsCss","generateThemeCSS","extractThemeConfigurationFromLiveData","liveData","themeConfigurationKey","candidate","resolveColorMode","mode","globalThis","window","undefined","matchMedia","matches","buildLivePreviewThemeRuntime","themeConfiguration","resolved","borderRadiusMap","none","small","medium","large","xl","full","mappedBorderRadius","borderRadius","borderRadiusConfig","cssRecord","css","borderRadiusCSS","Object","entries","map","property","value","join","borderRadiusBlock","themeConfigurationCSS","colorModesCSS","themeName","theme","lightMode","darkMode","customCSSBlock","customCSS","trim","colorMode","filter","block","Boolean","length"],"mappings":"AAAA,SAASA,qBAAqB,QAAQ,oCAAmC;AACzE,SAASC,yBAAyB,QAAQ,iCAAgC;AAC1E,SAASC,sBAAsB,QAAQ,mBAAkB;AACzD,SAASC,gBAAgB,QAAQ,kBAAiB;AAElD,OAAO,MAAMC,wCAAwC,CACnDC,UACAC,wBAAwB,oBAAoB;IAE5C,MAAMC,YAAYF,UAAU,CAACC,sBAAsB;IACnD,IAAIC,aAAa,OAAOA,cAAc,UAAU;QAC9C,OAAOA;IACT;IAEA,OAAOF;AACT,EAAC;AAED,MAAMG,mBAAmB,CAACC;IACxB,IAAIA,SAAS,QAAQ;QACnB,OAAO;IACT;IAEA,IACEA,SAAS,UACTC,WAAWC,MAAM,KAAKC,aACtB,OAAOF,WAAWC,MAAM,CAACE,UAAU,KAAK,YACxC;QACA,OAAOH,WAAWC,MAAM,CAACE,UAAU,CAAC,gCAAgCC,OAAO,GAAG,SAAS;IACzF;IAEA,OAAO;AACT;AAEA,OAAO,MAAMC,+BAA+B,CAACC;IAC3C,8DAA8D;IAC9D,MAAMC,WAAWhB,0BAA0Be;IAE3C,MAAME,kBAAgF;QACpFC,MAAM;QACNC,OAAO;QACPC,QAAQ;QACRC,OAAO;QACPC,IAAI;QACJC,MAAM;IACR;IAEA,MAAMC,qBAAqBP,eAAe,CAACD,SAASS,YAAY,IAAI,SAAS,IAAI;IACjF,MAAMC,qBAAqB3B,sBAAsByB;IACjD,MAAMG,YACJ,OAAOD,oBAAoBE,QAAQ,WAC/B;QAAE,oBAAoBF,mBAAmBE,GAAG;IAAC,IAC5CF,oBAAoBE,OAAO,CAAC;IAEnC,MAAMC,kBAAkBC,OAAOC,OAAO,CAACJ,WACpCK,GAAG,CAAC,CAAC,CAACC,UAAUC,MAAM,GAAK,CAAC,EAAE,EAAED,SAAS,EAAE,EAAEC,MAAM,CAAC,CAAC,EACrDC,IAAI,CAAC;IAER,MAAMC,oBAAoBP,kBAAkB,CAAC,SAAS,EAAEA,gBAAgB,GAAG,CAAC,GAAG;IAE/E,MAAMQ,wBAAwBnC,iBAAiBc;IAC/C,MAAMsB,gBAAgBrC,uBAAuB;QAC3CsC,WAAWvB,SAASwB,KAAK;QACzBC,WAAWzB,SAASyB,SAAS;QAC7BC,UAAU1B,SAAS0B,QAAQ;IAC7B;IAEA,MAAMC,iBAAiB,OAAO3B,SAAS4B,SAAS,KAAK,WAAW5B,SAAS4B,SAAS,CAACC,IAAI,KAAK;IAE5F,OAAO;QACLL,OAAOxB,SAASwB,KAAK;QACrBhC,MAAMD,iBAAiBS,SAAS8B,SAAS;QACzClB,KAAK;YAACQ;YAAmBC;YAAuBC;YAAeK;SAAe,CAC3EI,MAAM,CAAC,CAACC,QAAUC,QAAQD,OAAOH,SAASK,SAC1Cf,IAAI,CAAC;IACV;AACF,EAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kilivi/payloadcms-theme-management",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "Theme configuration plugin for Payload CMS v3 with 60+ professional themes and standalone collection support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",