@kilivi/payloadcms-theme-management 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +346 -845
- package/dist/components/AppearanceSessionControls.d.ts +15 -0
- package/dist/components/AppearanceSessionControls.d.ts.map +1 -0
- package/dist/components/AppearanceSessionControls.js +152 -0
- package/dist/components/AppearanceSessionControls.js.map +1 -0
- package/dist/components/ColorModeToggle.css +42 -0
- package/dist/components/ColorModeToggle.d.ts +40 -0
- package/dist/components/ColorModeToggle.d.ts.map +1 -0
- package/dist/components/ColorModeToggle.js +111 -0
- package/dist/components/ColorModeToggle.js.map +1 -0
- package/dist/components/ServerThemeInjector.d.ts +13 -1
- package/dist/components/ServerThemeInjector.d.ts.map +1 -1
- package/dist/components/ServerThemeInjector.js +65 -15
- package/dist/components/ServerThemeInjector.js.map +1 -1
- package/dist/components/ThemeLivePreviewSync.d.ts +4 -0
- package/dist/components/ThemeLivePreviewSync.d.ts.map +1 -1
- package/dist/components/ThemeLivePreviewSync.js +28 -4
- package/dist/components/ThemeLivePreviewSync.js.map +1 -1
- package/dist/components/ThemeSwitcher.d.ts +36 -0
- package/dist/components/ThemeSwitcher.d.ts.map +1 -0
- package/dist/components/ThemeSwitcher.js +89 -0
- package/dist/components/ThemeSwitcher.js.map +1 -0
- package/dist/components/typographyPreviewUtils.d.ts +5 -0
- package/dist/components/typographyPreviewUtils.d.ts.map +1 -1
- package/dist/components/typographyPreviewUtils.js +24 -11
- package/dist/components/typographyPreviewUtils.js.map +1 -1
- package/dist/constants/devicePreviews.d.ts +35 -0
- package/dist/constants/devicePreviews.d.ts.map +1 -0
- package/dist/constants/devicePreviews.js +43 -0
- package/dist/constants/devicePreviews.js.map +1 -0
- package/dist/constants/themeFonts.d.ts +94 -168
- package/dist/constants/themeFonts.d.ts.map +1 -1
- package/dist/constants/themeFonts.js +260 -140
- package/dist/constants/themeFonts.js.map +1 -1
- package/dist/endpoints/themeFonts.d.ts +5 -0
- package/dist/endpoints/themeFonts.d.ts.map +1 -0
- package/dist/endpoints/themeFonts.js +138 -0
- package/dist/endpoints/themeFonts.js.map +1 -0
- package/dist/extended-presets.d.ts +0 -4
- package/dist/extended-presets.d.ts.map +1 -1
- package/dist/extended-presets.js +1 -18
- package/dist/extended-presets.js.map +1 -1
- package/dist/extended-themes.d.ts.map +1 -1
- package/dist/extended-themes.js +428 -0
- package/dist/extended-themes.js.map +1 -1
- package/dist/fields/AccessibilityAuditField.d.ts +2 -0
- package/dist/fields/AccessibilityAuditField.d.ts.map +1 -0
- package/dist/fields/AccessibilityAuditField.js +303 -0
- package/dist/fields/AccessibilityAuditField.js.map +1 -0
- package/dist/fields/AppearancePreviewField.d.ts +2 -0
- package/dist/fields/AppearancePreviewField.d.ts.map +1 -0
- package/dist/fields/AppearancePreviewField.js +826 -0
- package/dist/fields/AppearancePreviewField.js.map +1 -0
- package/dist/fields/ColorPickerField.d.ts.map +1 -1
- package/dist/fields/ColorPickerField.js +89 -85
- package/dist/fields/ColorPickerField.js.map +1 -1
- package/dist/fields/FontSelectField.css +155 -0
- package/dist/fields/FontSelectField.d.ts +8 -0
- package/dist/fields/FontSelectField.d.ts.map +1 -1
- package/dist/fields/FontSelectField.js +223 -188
- package/dist/fields/FontSelectField.js.map +1 -1
- package/dist/fields/PaletteGeneratorField.d.ts +7 -0
- package/dist/fields/PaletteGeneratorField.d.ts.map +1 -0
- package/dist/fields/PaletteGeneratorField.js +327 -0
- package/dist/fields/PaletteGeneratorField.js.map +1 -0
- package/dist/fields/StylePresetField.d.ts +3 -0
- package/dist/fields/StylePresetField.d.ts.map +1 -0
- package/dist/fields/StylePresetField.js +463 -0
- package/dist/fields/StylePresetField.js.map +1 -0
- package/dist/fields/ThemeColorPickerField.css +115 -35
- package/dist/fields/ThemeColorPickerField.d.ts.map +1 -1
- package/dist/fields/ThemeColorPickerField.js +204 -70
- package/dist/fields/ThemeColorPickerField.js.map +1 -1
- package/dist/fields/ThemeExportField.d.ts +6 -0
- package/dist/fields/ThemeExportField.d.ts.map +1 -0
- package/dist/fields/ThemeExportField.js +202 -0
- package/dist/fields/ThemeExportField.js.map +1 -0
- package/dist/fields/ThemePresetImportField.d.ts.map +1 -1
- package/dist/fields/ThemePresetImportField.js +56 -25
- package/dist/fields/ThemePresetImportField.js.map +1 -1
- package/dist/fields/ThemePreviewField.css +444 -5
- package/dist/fields/ThemePreviewField.d.ts.map +1 -1
- package/dist/fields/ThemePreviewField.js +265 -170
- package/dist/fields/ThemePreviewField.js.map +1 -1
- package/dist/fields/ThemeTokenSelectField.d.ts.map +1 -1
- package/dist/fields/ThemeTokenSelectField.js +278 -80
- package/dist/fields/ThemeTokenSelectField.js.map +1 -1
- package/dist/fields/colorFieldHelpers.d.ts +90 -0
- package/dist/fields/colorFieldHelpers.d.ts.map +1 -0
- package/dist/fields/colorFieldHelpers.js +133 -0
- package/dist/fields/colorFieldHelpers.js.map +1 -0
- package/dist/fields/colorModeFields.d.ts +1 -1
- package/dist/fields/colorModeFields.d.ts.map +1 -1
- package/dist/fields/colorModeFields.js +49 -7
- package/dist/fields/colorModeFields.js.map +1 -1
- package/dist/fields/themeConfigurationField.d.ts +8 -1
- package/dist/fields/themeConfigurationField.d.ts.map +1 -1
- package/dist/fields/themeConfigurationField.js +1209 -228
- package/dist/fields/themeConfigurationField.js.map +1 -1
- package/dist/globals/ThemeSettings/FontPicker/FontPreview.d.ts.map +1 -1
- package/dist/globals/ThemeSettings/FontPicker/FontPreview.js +8 -4
- package/dist/globals/ThemeSettings/FontPicker/FontPreview.js.map +1 -1
- package/dist/globals/ThemeSettings/FontPicker/index.d.ts.map +1 -1
- package/dist/globals/ThemeSettings/FontPicker/index.js +81 -26
- package/dist/globals/ThemeSettings/FontPicker/index.js.map +1 -1
- package/dist/globals/ThemeSettings/FontPicker/styles.css +98 -41
- package/dist/globals/ThemeSettings/FontPicker/translations.d.ts +6 -0
- package/dist/globals/ThemeSettings/FontPicker/translations.d.ts.map +1 -1
- package/dist/globals/ThemeSettings/FontPicker/translations.js +14 -2
- package/dist/globals/ThemeSettings/FontPicker/translations.js.map +1 -1
- package/dist/globals/ThemeSettings/config.d.ts.map +1 -1
- package/dist/globals/ThemeSettings/config.js +76 -79
- package/dist/globals/ThemeSettings/config.js.map +1 -1
- package/dist/globals/ThemeSettings/fields/FontLoadingGuideField.d.ts.map +1 -1
- package/dist/globals/ThemeSettings/fields/FontLoadingGuideField.js +63 -62
- package/dist/globals/ThemeSettings/fields/FontLoadingGuideField.js.map +1 -1
- package/dist/globals/ThemeSettings/fields/TypographyInfoField.d.ts.map +1 -1
- package/dist/globals/ThemeSettings/fields/TypographyInfoField.js +22 -25
- package/dist/globals/ThemeSettings/fields/TypographyInfoField.js.map +1 -1
- package/dist/hooks/useAppearanceSession.d.ts +50 -0
- package/dist/hooks/useAppearanceSession.d.ts.map +1 -0
- package/dist/hooks/useAppearanceSession.js +91 -0
- package/dist/hooks/useAppearanceSession.js.map +1 -0
- package/dist/hooks/useNativeLivePreview.d.ts +15 -0
- package/dist/hooks/useNativeLivePreview.d.ts.map +1 -0
- package/dist/hooks/useNativeLivePreview.js +18 -0
- package/dist/hooks/useNativeLivePreview.js.map +1 -0
- package/dist/hooks/useThemeFonts.d.ts +10 -0
- package/dist/hooks/useThemeFonts.d.ts.map +1 -0
- package/dist/hooks/useThemeFonts.js +36 -0
- package/dist/hooks/useThemeFonts.js.map +1 -0
- package/dist/hooks/useThemeTranslations.d.ts +13 -0
- package/dist/hooks/useThemeTranslations.d.ts.map +1 -0
- package/dist/hooks/useThemeTranslations.js +22 -0
- package/dist/hooks/useThemeTranslations.js.map +1 -0
- package/dist/i18n.d.ts +53 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +53 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +13 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +59 -29
- package/dist/index.js.map +1 -1
- package/dist/next-fonts.d.ts +3 -0
- package/dist/next-fonts.d.ts.map +1 -0
- package/dist/next-fonts.js +360 -0
- package/dist/next-fonts.js.map +1 -0
- package/dist/payload-types.d.ts +34 -6
- package/dist/payload-types.d.ts.map +1 -1
- package/dist/payload-types.js.map +1 -1
- package/dist/presets.d.ts +14 -0
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js.map +1 -1
- package/dist/providers/Theme/index.d.ts.map +1 -1
- package/dist/providers/Theme/index.js +75 -11
- package/dist/providers/Theme/index.js.map +1 -1
- package/dist/providers/Theme/themeConfig.d.ts.map +1 -1
- package/dist/providers/Theme/themeConfig.js +104 -0
- package/dist/providers/Theme/themeConfig.js.map +1 -1
- package/dist/providers/Theme/types.d.ts +1 -1
- package/dist/providers/Theme/types.d.ts.map +1 -1
- package/dist/providers/Theme/types.js +10 -1
- package/dist/providers/Theme/types.js.map +1 -1
- package/dist/style-presets.d.ts +75 -0
- package/dist/style-presets.d.ts.map +1 -0
- package/dist/style-presets.js +738 -0
- package/dist/style-presets.js.map +1 -0
- package/dist/translations.d.ts +164 -1
- package/dist/translations.d.ts.map +1 -1
- package/dist/translations.js +320 -9
- package/dist/translations.js.map +1 -1
- package/dist/tweakcn-special-themes.d.ts.map +1 -1
- package/dist/tweakcn-special-themes.js +585 -9
- package/dist/tweakcn-special-themes.js.map +1 -1
- package/dist/types/css.d.js +3 -0
- package/dist/types/css.d.js.map +1 -0
- package/dist/types.d.ts +26 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utilities/getThemeSettings.d.ts.map +1 -1
- package/dist/utilities/getThemeSettings.js +2 -14
- package/dist/utilities/getThemeSettings.js.map +1 -1
- package/dist/utils/contrast.d.ts +63 -0
- package/dist/utils/contrast.d.ts.map +1 -0
- package/dist/utils/contrast.js +158 -0
- package/dist/utils/contrast.js.map +1 -0
- package/dist/utils/exportTokens.d.ts +30 -0
- package/dist/utils/exportTokens.d.ts.map +1 -0
- package/dist/utils/exportTokens.js +183 -0
- package/dist/utils/exportTokens.js.map +1 -0
- package/dist/utils/generatePalette.d.ts +46 -0
- package/dist/utils/generatePalette.d.ts.map +1 -0
- package/dist/utils/generatePalette.js +127 -0
- package/dist/utils/generatePalette.js.map +1 -0
- package/dist/utils/generateThemeCSS.d.ts.map +1 -1
- package/dist/utils/generateThemeCSS.js +2 -40
- package/dist/utils/generateThemeCSS.js.map +1 -1
- package/dist/utils/livePreviewThemeRuntime.d.ts +22 -3
- package/dist/utils/livePreviewThemeRuntime.d.ts.map +1 -1
- package/dist/utils/livePreviewThemeRuntime.js +48 -15
- package/dist/utils/livePreviewThemeRuntime.js.map +1 -1
- package/dist/utils/localizedText.d.ts +8 -0
- package/dist/utils/localizedText.d.ts.map +1 -0
- package/dist/utils/localizedText.js +21 -0
- package/dist/utils/localizedText.js.map +1 -0
- package/dist/utils/resolveThemeConfiguration.d.ts +60 -1
- package/dist/utils/resolveThemeConfiguration.d.ts.map +1 -1
- package/dist/utils/resolveThemeConfiguration.js +53 -13
- package/dist/utils/resolveThemeConfiguration.js.map +1 -1
- package/dist/utils/themeColors.d.ts +3 -0
- package/dist/utils/themeColors.d.ts.map +1 -1
- package/dist/utils/themeColors.js +30 -1
- package/dist/utils/themeColors.js.map +1 -1
- package/dist/utils/themeHtmlAttributes.d.ts +32 -12
- package/dist/utils/themeHtmlAttributes.d.ts.map +1 -1
- package/dist/utils/themeHtmlAttributes.js +38 -5
- package/dist/utils/themeHtmlAttributes.js.map +1 -1
- package/dist/utils/themeUtils.d.ts +3 -5
- package/dist/utils/themeUtils.d.ts.map +1 -1
- package/dist/utils/themeUtils.js +474 -6
- package/dist/utils/themeUtils.js.map +1 -1
- package/dist/utils/tweakcnConverter.d.ts +1 -3
- package/dist/utils/tweakcnConverter.d.ts.map +1 -1
- package/dist/utils/tweakcnConverter.js +1 -3
- package/dist/utils/tweakcnConverter.js.map +1 -1
- package/package.json +15 -5
- package/dist/components/ThemePreview.d.ts +0 -3
- package/dist/components/ThemePreview.d.ts.map +0 -1
- package/dist/components/ThemePreview.js +0 -321
- package/dist/components/ThemePreview.js.map +0 -1
- package/dist/plugin.d.ts +0 -2
- package/dist/plugin.d.ts.map +0 -1
- package/dist/plugin.js +0 -3
- package/dist/plugin.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/resolveThemeConfiguration.ts"],"sourcesContent":["import { FONT_VALUE_TO_CSS } from '../constants/themeFonts.js'\nimport type { ThemeTypographyPreset } from '../presets.js'\nimport { allThemePresets } from '../presets.js'\nimport type { Mode, ThemeDefaults } from '../providers/Theme/types.js'\nimport { themeIsValid } from '../providers/Theme/types.js'\n\n/**\n * Generic theme configuration structure that matches Payload's generated types\n * without depending on specific payload-types versions\n */\ninterface ThemeTypographyOverride {\n bodyFont?: string | null\n headingFont?: string | null\n bodyFontCustom?: string | null\n headingFontCustom?: string | null\n baseFontSize?: string | null\n lineHeight?: string | null\n}\n\n/**\n * Generic theme configuration interface that accepts any compatible structure\n * This avoids type conflicts between different versions of payload-types\n */\ninterface GenericThemeConfiguration {\n theme?: string | null\n colorMode?: string | null\n allowColorModeToggle?: boolean | null\n borderRadius?: string | null\n fontScale?: string | null\n spacing?: string | null\n animationLevel?: string | null\n customCSS?: string | null\n lightMode?: {\n primary?: string | null\n secondary?: string | null\n accent?: string | null\n neutral?: string | null\n success?: string | null\n warning?: string | null\n error?: string | null\n info?: string | null\n } | null\n darkMode?: {\n primary?: string | null\n secondary?: string | null\n accent?: string | null\n neutral?: string | null\n success?: string | null\n warning?: string | null\n error?: string | null\n info?: string | null\n } | null\n typography?: ThemeTypographyOverride | null\n}\n\nconst BORDER_RADIUS_VALUES = ['none', 'small', 'medium', 'large', 'xl'] as const\nconst LEGACY_BORDER_RADIUS_ALIASES: Record<string, (typeof BORDER_RADIUS_VALUES)[number]> = {\n full: 'xl',\n}\nconst FONT_SCALE_VALUES = ['small', 'medium', 'large'] as const\nconst SPACING_VALUES = ['compact', 'medium', 'spacious'] as const\nconst ANIMATION_LEVEL_VALUES = ['none', 'reduced', 'medium', 'high'] as const\nconst LEGACY_ANIMATION_ALIASES: Record<string, (typeof ANIMATION_LEVEL_VALUES)[number]> = {\n full: 'high',\n}\nconst MODE_VALUES = ['auto', 'light', 'dark'] as const\n\ntype BorderRadiusOption = (typeof BORDER_RADIUS_VALUES)[number]\ntype FontScaleOption = (typeof FONT_SCALE_VALUES)[number]\ntype SpacingOption = (typeof SPACING_VALUES)[number]\ntype AnimationLevelOption = (typeof ANIMATION_LEVEL_VALUES)[number]\n\ntype ThemeModeOption = (typeof MODE_VALUES)[number]\n\ntype ThemeColorConfiguration = NonNullable<GenericThemeConfiguration['lightMode']>\n\nconst DEFAULT_THEME_NAME: ThemeDefaults = 'cool'\nconst DEFAULT_THEME_PRESET = allThemePresets.find((preset) => preset.name === DEFAULT_THEME_NAME)\n\nexport interface ResolvedThemeConfiguration {\n theme: ThemeDefaults\n colorMode: Mode\n allowColorModeToggle: boolean\n borderRadius: BorderRadiusOption\n fontScale: FontScaleOption\n spacing: SpacingOption\n animationLevel: AnimationLevelOption\n customCSS: string | null\n lightMode?: ThemeColorConfiguration\n darkMode?: ThemeColorConfiguration\n typography: ThemeTypographyPreset | null\n}\n\nexport const DEFAULT_THEME_CONFIGURATION: ResolvedThemeConfiguration = {\n theme: DEFAULT_THEME_NAME,\n colorMode: 'auto',\n allowColorModeToggle: true,\n borderRadius: 'medium',\n fontScale: 'medium',\n spacing: 'medium',\n animationLevel: 'medium',\n customCSS: null,\n lightMode: DEFAULT_THEME_PRESET?.lightMode,\n darkMode: DEFAULT_THEME_PRESET?.darkMode,\n typography: DEFAULT_THEME_PRESET?.typography ?? null,\n}\n\nfunction resolveBorderRadius(value: unknown): BorderRadiusOption {\n if (typeof value === 'string') {\n if (BORDER_RADIUS_VALUES.includes(value as BorderRadiusOption)) {\n return value as BorderRadiusOption\n }\n\n const legacyMatch = LEGACY_BORDER_RADIUS_ALIASES[value]\n if (legacyMatch) {\n return legacyMatch\n }\n }\n\n return DEFAULT_THEME_CONFIGURATION.borderRadius\n}\n\nfunction isFontScale(value: unknown): value is FontScaleOption {\n return typeof value === 'string' && FONT_SCALE_VALUES.includes(value as FontScaleOption)\n}\n\nfunction isSpacing(value: unknown): value is SpacingOption {\n return typeof value === 'string' && SPACING_VALUES.includes(value as SpacingOption)\n}\n\nfunction resolveAnimationLevel(value: unknown): AnimationLevelOption {\n if (typeof value === 'string') {\n if (ANIMATION_LEVEL_VALUES.includes(value as AnimationLevelOption)) {\n return value as AnimationLevelOption\n }\n\n const legacyMatch = LEGACY_ANIMATION_ALIASES[value]\n if (legacyMatch) {\n return legacyMatch\n }\n }\n\n return DEFAULT_THEME_CONFIGURATION.animationLevel\n}\n\nfunction isMode(value: unknown): value is ThemeModeOption {\n return typeof value === 'string' && MODE_VALUES.includes(value as ThemeModeOption)\n}\n\nexport function resolveThemeConfiguration(\n themeConfiguration?: GenericThemeConfiguration | null,\n): ResolvedThemeConfiguration {\n if (!themeConfiguration) {\n return DEFAULT_THEME_CONFIGURATION\n }\n\n const {\n theme,\n colorMode,\n allowColorModeToggle,\n borderRadius,\n fontScale,\n spacing,\n animationLevel,\n customCSS,\n lightMode,\n darkMode,\n typography,\n } = themeConfiguration\n\n const resolvedTheme =\n typeof theme === 'string' && themeIsValid(theme)\n ? (theme as ThemeDefaults)\n : DEFAULT_THEME_CONFIGURATION.theme\n const resolvedMode = isMode(colorMode)\n ? (colorMode as Mode)\n : DEFAULT_THEME_CONFIGURATION.colorMode\n const resolvedBorderRadius = resolveBorderRadius(borderRadius)\n const resolvedFontScale = isFontScale(fontScale)\n ? fontScale\n : DEFAULT_THEME_CONFIGURATION.fontScale\n const resolvedSpacing = isSpacing(spacing) ? spacing : DEFAULT_THEME_CONFIGURATION.spacing\n const resolvedAnimationLevel = resolveAnimationLevel(animationLevel)\n const resolvedAllowToggle =\n typeof allowColorModeToggle === 'boolean'\n ? allowColorModeToggle\n : DEFAULT_THEME_CONFIGURATION.allowColorModeToggle\n const resolvedCustomCSS = typeof customCSS === 'string' ? customCSS : null\n const preset = allThemePresets.find((candidate) => candidate.name === resolvedTheme)\n const baseLightMode = preset?.lightMode ?? DEFAULT_THEME_CONFIGURATION.lightMode\n const baseDarkMode = preset?.darkMode ?? DEFAULT_THEME_CONFIGURATION.darkMode\n const resolvedLightMode = mergeColorModes(baseLightMode, lightMode)\n const resolvedDarkMode = mergeColorModes(baseDarkMode, darkMode)\n const resolvedTypography =\n mergeTypography(preset?.typography, typography) ?? preset?.typography ?? null\n\n return {\n theme: resolvedTheme,\n colorMode: resolvedMode,\n allowColorModeToggle: resolvedAllowToggle,\n borderRadius: resolvedBorderRadius,\n fontScale: resolvedFontScale,\n spacing: resolvedSpacing,\n animationLevel: resolvedAnimationLevel,\n customCSS: resolvedCustomCSS,\n lightMode: resolvedLightMode,\n darkMode: resolvedDarkMode,\n typography: resolvedTypography,\n }\n}\n\nfunction mergeColorModes(\n base?: ThemeColorConfiguration,\n overrides?: GenericThemeConfiguration['lightMode'],\n): ThemeColorConfiguration | undefined {\n const merged: Record<string, string> = {}\n\n if (base) {\n Object.entries(base).forEach(([key, value]) => {\n if (typeof value === 'string' && value.trim().length > 0) {\n merged[key] = value\n }\n })\n }\n\n if (overrides) {\n Object.entries(overrides).forEach(([key, value]) => {\n if (typeof value === 'string' && value.trim().length > 0) {\n merged[key] = value\n } else if (value === null) {\n delete merged[key]\n }\n })\n }\n\n return Object.keys(merged).length > 0 ? (merged as ThemeColorConfiguration) : undefined\n}\n\nfunction mergeTypography(\n base?: ThemeTypographyPreset | null,\n overrides?: ThemeTypographyOverride | null,\n): ThemeTypographyPreset | null {\n if (!base && !overrides) {\n return base ?? null\n }\n\n const result: ThemeTypographyPreset = {\n fontFamily: base?.fontFamily ?? 'var(--font-geist-sans)',\n headingFamily: base?.headingFamily ?? 'var(--font-geist-sans)',\n baseFontSize: base?.baseFontSize ?? '16px',\n lineHeight: base?.lineHeight ?? '1.6',\n fontWeights: { ...(base?.fontWeights ?? {}) },\n letterSpacing: { ...(base?.letterSpacing ?? {}) },\n }\n\n if (overrides) {\n const resolvedBodyFont = resolveFontSelection(\n overrides.bodyFont,\n overrides.bodyFontCustom,\n base?.fontFamily,\n )\n if (resolvedBodyFont) {\n result.fontFamily = resolvedBodyFont\n }\n\n const resolvedHeadingFont = resolveFontSelection(\n overrides.headingFont,\n overrides.headingFontCustom,\n base?.headingFamily,\n )\n if (resolvedHeadingFont) {\n result.headingFamily = resolvedHeadingFont\n }\n\n if (overrides.baseFontSize && overrides.baseFontSize !== 'preset') {\n result.baseFontSize = overrides.baseFontSize\n }\n\n if (overrides.lineHeight && overrides.lineHeight !== 'preset') {\n result.lineHeight = overrides.lineHeight\n }\n }\n\n return result\n}\n\nfunction resolveFontSelection(\n selection?: string | null,\n custom?: string | null,\n fallback?: string | null,\n): string | null {\n if (!selection || selection === 'preset') {\n return fallback ?? null\n }\n\n if (selection === 'custom') {\n const trimmed = custom?.trim()\n return trimmed && trimmed.length > 0 ? trimmed : (fallback ?? null)\n }\n\n const mapped = FONT_VALUE_TO_CSS[selection]\n return mapped ?? fallback ?? null\n}\n"],"names":["FONT_VALUE_TO_CSS","allThemePresets","themeIsValid","BORDER_RADIUS_VALUES","LEGACY_BORDER_RADIUS_ALIASES","full","FONT_SCALE_VALUES","SPACING_VALUES","ANIMATION_LEVEL_VALUES","LEGACY_ANIMATION_ALIASES","MODE_VALUES","DEFAULT_THEME_NAME","DEFAULT_THEME_PRESET","find","preset","name","DEFAULT_THEME_CONFIGURATION","theme","colorMode","allowColorModeToggle","borderRadius","fontScale","spacing","animationLevel","customCSS","lightMode","darkMode","typography","resolveBorderRadius","value","includes","legacyMatch","isFontScale","isSpacing","resolveAnimationLevel","isMode","resolveThemeConfiguration","themeConfiguration","resolvedTheme","resolvedMode","resolvedBorderRadius","resolvedFontScale","resolvedSpacing","resolvedAnimationLevel","resolvedAllowToggle","resolvedCustomCSS","candidate","baseLightMode","baseDarkMode","resolvedLightMode","mergeColorModes","resolvedDarkMode","resolvedTypography","mergeTypography","base","overrides","merged","Object","entries","forEach","key","trim","length","keys","undefined","result","fontFamily","headingFamily","baseFontSize","lineHeight","fontWeights","letterSpacing","resolvedBodyFont","resolveFontSelection","bodyFont","bodyFontCustom","resolvedHeadingFont","headingFont","headingFontCustom","selection","custom","fallback","trimmed","mapped"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/resolveThemeConfiguration.ts"],"sourcesContent":["import {\n getFontCatalogEntry,\n LETTER_SPACING_TO_CSS,\n toFontSizeCss,\n} from '../constants/themeFonts.js'\nimport type { ThemeTypographyPreset } from '../presets.js'\nimport { allThemePresets } from '../presets.js'\nimport type { Mode, ThemeDefaults } from '../providers/Theme/types.js'\nimport { themeIsValid } from '../providers/Theme/types.js'\n\n/**\n * Generic theme configuration structure that matches Payload's generated types\n * without depending on specific payload-types versions\n */\ninterface ThemeTypographyOverride {\n bodyFont?: string | null\n headingFont?: string | null\n bodyFontCustom?: string | null\n headingFontCustom?: string | null\n baseFontSize?: string | null\n lineHeight?: string | null\n headingWeight?: string | null\n letterSpacing?: string | null\n}\n\n/**\n * Generic theme configuration interface that accepts any compatible structure\n * This avoids type conflicts between different versions of payload-types\n */\ninterface GenericThemeConfiguration {\n theme?: string | null\n colorMode?: string | null\n allowColorModeToggle?: boolean | null\n borderRadius?: string | null\n fontScale?: string | null\n spacing?: string | null\n animationLevel?: string | null\n customCSS?: string | null\n lightMode?: {\n primary?: string | null\n secondary?: string | null\n accent?: string | null\n neutral?: string | null\n success?: string | null\n warning?: string | null\n error?: string | null\n info?: string | null\n } | null\n darkMode?: {\n primary?: string | null\n secondary?: string | null\n accent?: string | null\n neutral?: string | null\n success?: string | null\n warning?: string | null\n error?: string | null\n info?: string | null\n } | null\n typography?: ThemeTypographyOverride | null\n fontSelections?: string[] | null\n typographyOverridden?: boolean | null\n visualEffects?: {\n effectStyle?: string | null\n shadowIntensity?: string | null\n backdropBlur?: string | null\n borderStyle?: string | null\n borderWidth?: string | null\n glassOpacity?: number | null\n } | null\n componentStyles?: {\n buttonVariant?: string | null\n buttonSize?: string | null\n cardStyle?: string | null\n cardHoverEffect?: string | null\n imageStyle?: string | null\n iconSet?: string | null\n navbarStyle?: string | null\n footerStyle?: string | null\n linkStyle?: string | null\n enableScrollReveal?: boolean | null\n enableHoverAnimations?: boolean | null\n } | null\n}\n\nconst BORDER_RADIUS_VALUES = ['none', 'small', 'medium', 'large', 'xl'] as const\nconst LEGACY_BORDER_RADIUS_ALIASES: Record<string, (typeof BORDER_RADIUS_VALUES)[number]> = {\n full: 'xl',\n}\nconst FONT_SCALE_VALUES = ['small', 'medium', 'large'] as const\nconst SPACING_VALUES = ['compact', 'medium', 'spacious'] as const\n// Earlier versions stored the roomiest spacing option as 'comfortable'.\nconst LEGACY_SPACING_ALIASES: Record<string, (typeof SPACING_VALUES)[number]> = {\n comfortable: 'spacious',\n}\nconst ANIMATION_LEVEL_VALUES = ['none', 'reduced', 'medium', 'high'] as const\nconst LEGACY_ANIMATION_ALIASES: Record<string, (typeof ANIMATION_LEVEL_VALUES)[number]> = {\n full: 'high',\n}\nconst MODE_VALUES = ['auto', 'light', 'dark'] as const\n\ntype BorderRadiusOption = (typeof BORDER_RADIUS_VALUES)[number]\ntype FontScaleOption = (typeof FONT_SCALE_VALUES)[number]\ntype SpacingOption = (typeof SPACING_VALUES)[number]\ntype AnimationLevelOption = (typeof ANIMATION_LEVEL_VALUES)[number]\n\ntype ThemeModeOption = (typeof MODE_VALUES)[number]\n\ntype ThemeColorConfiguration = NonNullable<GenericThemeConfiguration['lightMode']>\n\nconst DEFAULT_THEME_NAME: ThemeDefaults = 'cool'\nconst DEFAULT_THEME_PRESET = allThemePresets.find((preset) => preset.name === DEFAULT_THEME_NAME)\n\nexport interface ResolvedVisualEffects {\n effectStyle?: string | null\n shadowIntensity?: string | null\n backdropBlur?: string | null\n borderStyle?: string | null\n borderWidth?: string | null\n glassOpacity?: number | null\n}\n\nexport interface ResolvedComponentStyles {\n buttonVariant?: string | null\n buttonSize?: string | null\n cardStyle?: string | null\n cardHoverEffect?: string | null\n imageStyle?: string | null\n iconSet?: string | null\n navbarStyle?: string | null\n footerStyle?: string | null\n linkStyle?: string | null\n enableScrollReveal?: boolean | null\n enableHoverAnimations?: boolean | null\n}\n\nexport interface ResolvedThemeConfiguration {\n theme: ThemeDefaults\n colorMode: Mode\n allowColorModeToggle: boolean\n borderRadius: BorderRadiusOption\n fontScale: FontScaleOption\n spacing: SpacingOption\n animationLevel: AnimationLevelOption\n customCSS: string | null\n lightMode?: ThemeColorConfiguration\n darkMode?: ThemeColorConfiguration\n typography: ThemeTypographyPreset | null\n /**\n * The body / heading font values picked in the admin ('Inter', 'Lora' …),\n * kept so the font files can be requested (see `ServerThemeInjector`).\n */\n fontSelections?: string[]\n /**\n * True when the editor picked something in Typography (a font, size, line\n * height, heading weight or tracking) instead of \"Use theme preset\". Base\n * typography rules are only emitted then, so untouched sites render as before.\n */\n typographyOverridden?: boolean\n visualEffects?: ResolvedVisualEffects | null\n componentStyles?: ResolvedComponentStyles | null\n}\n\nexport const DEFAULT_THEME_CONFIGURATION: ResolvedThemeConfiguration = {\n theme: DEFAULT_THEME_NAME,\n colorMode: 'auto',\n allowColorModeToggle: true,\n borderRadius: 'medium',\n fontScale: 'medium',\n spacing: 'medium',\n animationLevel: 'medium',\n customCSS: null,\n lightMode: DEFAULT_THEME_PRESET?.lightMode,\n darkMode: DEFAULT_THEME_PRESET?.darkMode,\n typography: DEFAULT_THEME_PRESET?.typography ?? null,\n}\n\nfunction resolveBorderRadius(value: unknown): BorderRadiusOption {\n if (typeof value === 'string') {\n if (BORDER_RADIUS_VALUES.includes(value as BorderRadiusOption)) {\n return value as BorderRadiusOption\n }\n\n const legacyMatch = LEGACY_BORDER_RADIUS_ALIASES[value]\n if (legacyMatch) {\n return legacyMatch\n }\n }\n\n return DEFAULT_THEME_CONFIGURATION.borderRadius\n}\n\nfunction isFontScale(value: unknown): value is FontScaleOption {\n return typeof value === 'string' && FONT_SCALE_VALUES.includes(value as FontScaleOption)\n}\n\nfunction isSpacing(value: unknown): value is SpacingOption {\n return typeof value === 'string' && SPACING_VALUES.includes(value as SpacingOption)\n}\n\nfunction resolveAnimationLevel(value: unknown): AnimationLevelOption {\n if (typeof value === 'string') {\n if (ANIMATION_LEVEL_VALUES.includes(value as AnimationLevelOption)) {\n return value as AnimationLevelOption\n }\n\n const legacyMatch = LEGACY_ANIMATION_ALIASES[value]\n if (legacyMatch) {\n return legacyMatch\n }\n }\n\n return DEFAULT_THEME_CONFIGURATION.animationLevel\n}\n\nfunction isMode(value: unknown): value is ThemeModeOption {\n return typeof value === 'string' && MODE_VALUES.includes(value as ThemeModeOption)\n}\n\nexport function resolveThemeConfiguration(\n themeConfiguration?: unknown,\n): ResolvedThemeConfiguration {\n // Accept `unknown` so callers don't need to cast from app-specific payload-types\n const cfg =\n themeConfiguration !== null &&\n typeof themeConfiguration === 'object' &&\n !Array.isArray(themeConfiguration)\n ? (themeConfiguration as GenericThemeConfiguration)\n : null\n\n if (!cfg) {\n return DEFAULT_THEME_CONFIGURATION\n }\n\n const {\n theme,\n colorMode,\n allowColorModeToggle,\n borderRadius,\n fontScale,\n spacing,\n animationLevel,\n customCSS,\n lightMode,\n darkMode,\n typography,\n visualEffects,\n componentStyles,\n } = cfg\n\n const resolvedTheme =\n typeof theme === 'string' && themeIsValid(theme)\n ? (theme as ThemeDefaults)\n : DEFAULT_THEME_CONFIGURATION.theme\n const resolvedMode = isMode(colorMode)\n ? (colorMode as Mode)\n : DEFAULT_THEME_CONFIGURATION.colorMode\n const resolvedBorderRadius = resolveBorderRadius(borderRadius)\n const resolvedFontScale = isFontScale(fontScale)\n ? fontScale\n : DEFAULT_THEME_CONFIGURATION.fontScale\n const resolvedSpacing = isSpacing(spacing)\n ? spacing\n : ((typeof spacing === 'string' && LEGACY_SPACING_ALIASES[spacing]) ||\n DEFAULT_THEME_CONFIGURATION.spacing)\n const resolvedAnimationLevel = resolveAnimationLevel(animationLevel)\n const resolvedAllowToggle =\n typeof allowColorModeToggle === 'boolean'\n ? allowColorModeToggle\n : DEFAULT_THEME_CONFIGURATION.allowColorModeToggle\n const resolvedCustomCSS = typeof customCSS === 'string' ? customCSS : null\n const preset = allThemePresets.find((candidate) => candidate.name === resolvedTheme)\n const baseLightMode = preset?.lightMode ?? DEFAULT_THEME_CONFIGURATION.lightMode\n const baseDarkMode = preset?.darkMode ?? DEFAULT_THEME_CONFIGURATION.darkMode\n const resolvedLightMode = mergeColorModes(baseLightMode, lightMode)\n const resolvedDarkMode = mergeColorModes(baseDarkMode, darkMode)\n // Accept an already-resolved configuration too (callers often resolve once and\n // pass the result to several helpers): its typography is final, keep it as is.\n const typographyIsResolved =\n typography !== null &&\n typeof typography === 'object' &&\n typeof (typography as { fontFamily?: unknown }).fontFamily === 'string'\n const resolvedTypography = typographyIsResolved\n ? (typography as unknown as ThemeTypographyPreset)\n : (mergeTypography(preset?.typography, typography) ?? preset?.typography ?? null)\n const isSet = (value: unknown) => typeof value === 'string' && value !== '' && value !== 'preset'\n const typographyOverridden = typographyIsResolved\n ? cfg.typographyOverridden === true\n : Boolean(\n typography &&\n [\n typography.bodyFont,\n typography.headingFont,\n typography.baseFontSize,\n typography.lineHeight,\n typography.headingWeight,\n typography.letterSpacing,\n ].some(isSet),\n )\n const fontSelections = typographyIsResolved\n ? (cfg.fontSelections ?? [])\n : [typography?.bodyFont, typography?.headingFont].filter(\n (value): value is string =>\n typeof value === 'string' && value !== 'preset' && value !== 'custom',\n )\n\n // Pass visualEffects and componentStyles through as-is (no normalization needed)\n const resolvedVisualEffects = visualEffects ?? null\n const resolvedComponentStyles = componentStyles ?? null\n\n return {\n theme: resolvedTheme,\n colorMode: resolvedMode,\n allowColorModeToggle: resolvedAllowToggle,\n borderRadius: resolvedBorderRadius,\n fontScale: resolvedFontScale,\n spacing: resolvedSpacing,\n animationLevel: resolvedAnimationLevel,\n customCSS: resolvedCustomCSS,\n lightMode: resolvedLightMode,\n darkMode: resolvedDarkMode,\n typography: resolvedTypography,\n fontSelections,\n typographyOverridden,\n visualEffects: resolvedVisualEffects,\n componentStyles: resolvedComponentStyles,\n }\n}\n\nfunction mergeColorModes(\n base?: ThemeColorConfiguration,\n overrides?: GenericThemeConfiguration['lightMode'],\n): ThemeColorConfiguration | undefined {\n const merged: Record<string, string> = {}\n\n if (base) {\n Object.entries(base).forEach(([key, value]) => {\n if (typeof value === 'string' && value.trim().length > 0) {\n merged[key] = value\n }\n })\n }\n\n if (overrides) {\n Object.entries(overrides).forEach(([key, value]) => {\n if (typeof value === 'string' && value.trim().length > 0) {\n merged[key] = value\n } else if (value === null) {\n delete merged[key]\n }\n })\n }\n\n return Object.keys(merged).length > 0 ? (merged as ThemeColorConfiguration) : undefined\n}\n\nfunction mergeTypography(\n base?: ThemeTypographyPreset | null,\n overrides?: ThemeTypographyOverride | null,\n): ThemeTypographyPreset | null {\n if (!base && !overrides) {\n return base ?? null\n }\n\n const result: ThemeTypographyPreset = {\n fontFamily:\n base?.fontFamily ?? 'var(--font-inter, var(--font-geist-sans), system-ui, sans-serif)',\n headingFamily:\n base?.headingFamily ?? 'var(--font-outfit, var(--font-geist-sans), system-ui, sans-serif)',\n baseFontSize: toFontSizeCss(base?.baseFontSize) ?? '16px',\n lineHeight: base?.lineHeight ?? '1.6',\n headingWeight: base?.headingWeight,\n headingLetterSpacing: base?.headingLetterSpacing,\n headingTransform: base?.headingTransform,\n fontWeights: { ...(base?.fontWeights ?? {}) },\n letterSpacing: { ...(base?.letterSpacing ?? {}) },\n }\n\n if (overrides) {\n const resolvedBodyFont = resolveFontSelection(\n overrides.bodyFont,\n overrides.bodyFontCustom,\n base?.fontFamily,\n )\n if (resolvedBodyFont) {\n result.fontFamily = resolvedBodyFont\n }\n\n const resolvedHeadingFont = resolveFontSelection(\n overrides.headingFont,\n overrides.headingFontCustom,\n base?.headingFamily,\n )\n if (resolvedHeadingFont) {\n result.headingFamily = resolvedHeadingFont\n }\n\n const baseFontSize = toFontSizeCss(overrides.baseFontSize)\n if (baseFontSize) {\n result.baseFontSize = baseFontSize\n }\n\n if (overrides.lineHeight && overrides.lineHeight !== 'preset') {\n result.lineHeight = overrides.lineHeight\n }\n\n if (overrides.headingWeight && overrides.headingWeight !== 'preset') {\n result.headingWeight = overrides.headingWeight\n }\n\n const tracking = overrides.letterSpacing ? LETTER_SPACING_TO_CSS[overrides.letterSpacing] : undefined\n if (tracking !== undefined) {\n result.headingLetterSpacing = tracking\n result.headingTransform = overrides.letterSpacing === 'wider' ? 'uppercase' : 'none'\n }\n }\n\n return result\n}\n\nfunction resolveFontSelection(\n selection?: string | null,\n custom?: string | null,\n fallback?: string | null,\n): string | null {\n if (!selection || selection === 'preset') {\n return fallback ?? null\n }\n\n if (selection === 'custom') {\n const trimmed = custom?.trim()\n return trimmed && trimmed.length > 0 ? trimmed : (fallback ?? null)\n }\n\n return getFontCatalogEntry(selection)?.fontFamily ?? fallback ?? null\n}\n"],"names":["getFontCatalogEntry","LETTER_SPACING_TO_CSS","toFontSizeCss","allThemePresets","themeIsValid","BORDER_RADIUS_VALUES","LEGACY_BORDER_RADIUS_ALIASES","full","FONT_SCALE_VALUES","SPACING_VALUES","LEGACY_SPACING_ALIASES","comfortable","ANIMATION_LEVEL_VALUES","LEGACY_ANIMATION_ALIASES","MODE_VALUES","DEFAULT_THEME_NAME","DEFAULT_THEME_PRESET","find","preset","name","DEFAULT_THEME_CONFIGURATION","theme","colorMode","allowColorModeToggle","borderRadius","fontScale","spacing","animationLevel","customCSS","lightMode","darkMode","typography","resolveBorderRadius","value","includes","legacyMatch","isFontScale","isSpacing","resolveAnimationLevel","isMode","resolveThemeConfiguration","themeConfiguration","cfg","Array","isArray","visualEffects","componentStyles","resolvedTheme","resolvedMode","resolvedBorderRadius","resolvedFontScale","resolvedSpacing","resolvedAnimationLevel","resolvedAllowToggle","resolvedCustomCSS","candidate","baseLightMode","baseDarkMode","resolvedLightMode","mergeColorModes","resolvedDarkMode","typographyIsResolved","fontFamily","resolvedTypography","mergeTypography","isSet","typographyOverridden","Boolean","bodyFont","headingFont","baseFontSize","lineHeight","headingWeight","letterSpacing","some","fontSelections","filter","resolvedVisualEffects","resolvedComponentStyles","base","overrides","merged","Object","entries","forEach","key","trim","length","keys","undefined","result","headingFamily","headingLetterSpacing","headingTransform","fontWeights","resolvedBodyFont","resolveFontSelection","bodyFontCustom","resolvedHeadingFont","headingFontCustom","tracking","selection","custom","fallback","trimmed"],"mappings":"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"}
|
|
@@ -18,6 +18,9 @@ interface ColorMode {
|
|
|
18
18
|
border?: string | null;
|
|
19
19
|
input?: string | null;
|
|
20
20
|
ring?: string | null;
|
|
21
|
+
gradientFrom?: string | null;
|
|
22
|
+
gradientVia?: string | null;
|
|
23
|
+
gradientTo?: string | null;
|
|
21
24
|
}
|
|
22
25
|
export interface ThemeColors {
|
|
23
26
|
lightMode?: ColorMode;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"themeColors.d.ts","sourceRoot":"","sources":["../../src/utils/themeColors.ts"],"names":[],"mappings":"AAAA,UAAU,SAAS;IACjB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,qBAAqB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"themeColors.d.ts","sourceRoot":"","sources":["../../src/utils/themeColors.ts"],"names":[],"mappings":"AAAA,UAAU,SAAS;IACjB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,qBAAqB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,QAAQ,CAAC,EAAE,SAAS,CAAA;CACrB;AAED,UAAU,0BAA2B,SAAQ,WAAW;IACtD,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AA2BD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA4C5C;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EACjB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACrD,MAAM,CAkBR;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,0BAA0B,GAAG,MAAM,CAelF"}
|
|
@@ -74,6 +74,18 @@ const COLOR_VARIABLE_MAP = [
|
|
|
74
74
|
{
|
|
75
75
|
key: 'ring',
|
|
76
76
|
variable: '--ring'
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
key: 'gradientFrom',
|
|
80
|
+
variable: '--gradient-from'
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
key: 'gradientVia',
|
|
84
|
+
variable: '--gradient-via'
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
key: 'gradientTo',
|
|
88
|
+
variable: '--gradient-to'
|
|
77
89
|
}
|
|
78
90
|
];
|
|
79
91
|
export function hexToHsl(hex) {
|
|
@@ -116,7 +128,7 @@ export function generateColorModeCss(colors, options = {}) {
|
|
|
116
128
|
const cssVariables = COLOR_VARIABLE_MAP.reduce((acc, { key, variable })=>{
|
|
117
129
|
const value = normalizeColor(colors[key]);
|
|
118
130
|
if (!value) return acc;
|
|
119
|
-
acc.push(`${variable}:
|
|
131
|
+
acc.push(`${variable}: ${normalizeToCssColor(value)};`);
|
|
120
132
|
return acc;
|
|
121
133
|
}, []);
|
|
122
134
|
if (cssVariables.length === 0) return '';
|
|
@@ -161,5 +173,22 @@ function normalizeColor(value) {
|
|
|
161
173
|
const trimmed = value.trim();
|
|
162
174
|
return trimmed.length === 0 ? null : trimmed;
|
|
163
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* Convert any color value to a valid CSS color string.
|
|
178
|
+
* - oklch(...), hsl(...), rgb(...), etc. → pass through as-is
|
|
179
|
+
* - var(...) CSS variable references → pass through as-is
|
|
180
|
+
* - Hex (#rgb, #rrggbb) → convert to hsl(H S% L%)
|
|
181
|
+
*/ function normalizeToCssColor(value) {
|
|
182
|
+
// Already a complete CSS color function — pass through unchanged
|
|
183
|
+
if (/^(hsl|hsla|rgb|rgba|oklch|oklab|lch|lab|color|hwb)\s*\(/i.test(value)) {
|
|
184
|
+
return value;
|
|
185
|
+
}
|
|
186
|
+
// CSS variable reference — pass through
|
|
187
|
+
if (/^var\s*\(/i.test(value)) {
|
|
188
|
+
return value;
|
|
189
|
+
}
|
|
190
|
+
// Hex color (#rgb or #rrggbb) — convert to hsl()
|
|
191
|
+
return `hsl(${hexToHsl(value)})`;
|
|
192
|
+
}
|
|
164
193
|
|
|
165
194
|
//# sourceMappingURL=themeColors.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/themeColors.ts"],"sourcesContent":["interface ColorMode {\n background?: string | null\n foreground?: string | null\n card?: string | null\n cardForeground?: string | null\n popover?: string | null\n popoverForeground?: string | null\n primary?: string | null\n primaryForeground?: string | null\n secondary?: string | null\n secondaryForeground?: string | null\n muted?: string | null\n mutedForeground?: string | null\n accent?: string | null\n accentForeground?: string | null\n destructive?: string | null\n destructiveForeground?: string | null\n border?: string | null\n input?: string | null\n ring?: string | null\n}\n\nexport interface ThemeColors {\n lightMode?: ColorMode\n darkMode?: ColorMode\n}\n\ninterface GenerateThemeColorsOptions extends ThemeColors {\n themeName?: string\n}\n\nconst COLOR_VARIABLE_MAP: Array<{ key: keyof ColorMode; variable: string }> = [\n { key: 'background', variable: '--background' },\n { key: 'foreground', variable: '--foreground' },\n { key: 'card', variable: '--card' },\n { key: 'cardForeground', variable: '--card-foreground' },\n { key: 'popover', variable: '--popover' },\n { key: 'popoverForeground', variable: '--popover-foreground' },\n { key: 'primary', variable: '--primary' },\n { key: 'primaryForeground', variable: '--primary-foreground' },\n { key: 'secondary', variable: '--secondary' },\n { key: 'secondaryForeground', variable: '--secondary-foreground' },\n { key: 'muted', variable: '--muted' },\n { key: 'mutedForeground', variable: '--muted-foreground' },\n { key: 'accent', variable: '--accent' },\n { key: 'accentForeground', variable: '--accent-foreground' },\n { key: 'destructive', variable: '--destructive' },\n { key: 'destructiveForeground', variable: '--destructive-foreground' },\n { key: 'border', variable: '--border' },\n { key: 'input', variable: '--input' },\n { key: 'ring', variable: '--ring' },\n]\n\nexport function hexToHsl(hex: string): string {\n if (!hex) return '0 0% 0%'\n\n hex = hex.replace('#', '')\n\n if (hex.length === 3) {\n hex = hex\n .split('')\n .map((char) => char + char)\n .join('')\n }\n\n const r = Number.parseInt(hex.substring(0, 2), 16) / 255\n const g = Number.parseInt(hex.substring(2, 4), 16) / 255\n const b = Number.parseInt(hex.substring(4, 6), 16) / 255\n\n const max = Math.max(r, g, b)\n const min = Math.min(r, g, b)\n let h = 0\n let s = 0\n const l = (max + min) / 2\n\n if (max !== min) {\n const d = max - min\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min)\n\n switch (max) {\n case r:\n h = ((g - b) / d + (g < b ? 6 : 0)) / 6\n break\n case g:\n h = ((b - r) / d + 2) / 6\n break\n case b:\n h = ((r - g) / d + 4) / 6\n break\n }\n }\n\n h = Math.round(h * 360)\n s = Math.round(s * 100)\n const lRounded = Math.round(l * 100)\n\n return `${h} ${s}% ${lRounded}%`\n}\n\nexport function generateColorModeCss(\n colors: ColorMode,\n options: { themeName?: string; isDark?: boolean } = {},\n): string {\n if (!colors) return ''\n\n const { themeName, isDark = false } = options\n\n const cssVariables = COLOR_VARIABLE_MAP.reduce<string[]>((acc, { key, variable }) => {\n const value = normalizeColor(colors[key])\n if (!value) return acc\n acc.push(`${variable}:
|
|
1
|
+
{"version":3,"sources":["../../src/utils/themeColors.ts"],"sourcesContent":["interface ColorMode {\n background?: string | null\n foreground?: string | null\n card?: string | null\n cardForeground?: string | null\n popover?: string | null\n popoverForeground?: string | null\n primary?: string | null\n primaryForeground?: string | null\n secondary?: string | null\n secondaryForeground?: string | null\n muted?: string | null\n mutedForeground?: string | null\n accent?: string | null\n accentForeground?: string | null\n destructive?: string | null\n destructiveForeground?: string | null\n border?: string | null\n input?: string | null\n ring?: string | null\n gradientFrom?: string | null\n gradientVia?: string | null\n gradientTo?: string | null\n}\n\nexport interface ThemeColors {\n lightMode?: ColorMode\n darkMode?: ColorMode\n}\n\ninterface GenerateThemeColorsOptions extends ThemeColors {\n themeName?: string\n}\n\nconst COLOR_VARIABLE_MAP: Array<{ key: keyof ColorMode; variable: string }> = [\n { key: 'background', variable: '--background' },\n { key: 'foreground', variable: '--foreground' },\n { key: 'card', variable: '--card' },\n { key: 'cardForeground', variable: '--card-foreground' },\n { key: 'popover', variable: '--popover' },\n { key: 'popoverForeground', variable: '--popover-foreground' },\n { key: 'primary', variable: '--primary' },\n { key: 'primaryForeground', variable: '--primary-foreground' },\n { key: 'secondary', variable: '--secondary' },\n { key: 'secondaryForeground', variable: '--secondary-foreground' },\n { key: 'muted', variable: '--muted' },\n { key: 'mutedForeground', variable: '--muted-foreground' },\n { key: 'accent', variable: '--accent' },\n { key: 'accentForeground', variable: '--accent-foreground' },\n { key: 'destructive', variable: '--destructive' },\n { key: 'destructiveForeground', variable: '--destructive-foreground' },\n { key: 'border', variable: '--border' },\n { key: 'input', variable: '--input' },\n { key: 'ring', variable: '--ring' },\n { key: 'gradientFrom', variable: '--gradient-from' },\n { key: 'gradientVia', variable: '--gradient-via' },\n { key: 'gradientTo', variable: '--gradient-to' },\n]\n\nexport function hexToHsl(hex: string): string {\n if (!hex) return '0 0% 0%'\n\n hex = hex.replace('#', '')\n\n if (hex.length === 3) {\n hex = hex\n .split('')\n .map((char) => char + char)\n .join('')\n }\n\n const r = Number.parseInt(hex.substring(0, 2), 16) / 255\n const g = Number.parseInt(hex.substring(2, 4), 16) / 255\n const b = Number.parseInt(hex.substring(4, 6), 16) / 255\n\n const max = Math.max(r, g, b)\n const min = Math.min(r, g, b)\n let h = 0\n let s = 0\n const l = (max + min) / 2\n\n if (max !== min) {\n const d = max - min\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min)\n\n switch (max) {\n case r:\n h = ((g - b) / d + (g < b ? 6 : 0)) / 6\n break\n case g:\n h = ((b - r) / d + 2) / 6\n break\n case b:\n h = ((r - g) / d + 4) / 6\n break\n }\n }\n\n h = Math.round(h * 360)\n s = Math.round(s * 100)\n const lRounded = Math.round(l * 100)\n\n return `${h} ${s}% ${lRounded}%`\n}\n\nexport function generateColorModeCss(\n colors: ColorMode,\n options: { themeName?: string; isDark?: boolean } = {},\n): string {\n if (!colors) return ''\n\n const { themeName, isDark = false } = options\n\n const cssVariables = COLOR_VARIABLE_MAP.reduce<string[]>((acc, { key, variable }) => {\n const value = normalizeColor(colors[key])\n if (!value) return acc\n acc.push(`${variable}: ${normalizeToCssColor(value)};`)\n return acc\n }, [])\n\n if (cssVariables.length === 0) return ''\n\n const selector = buildSelector(themeName, isDark)\n return `${selector} {\n ${cssVariables.join('\\n ')}\n}`\n}\n\nexport function generateThemeColorsCss(options: GenerateThemeColorsOptions): string {\n const cssBlocks: string[] = []\n const { themeName, lightMode, darkMode } = options\n\n if (lightMode) {\n const lightModeCss = generateColorModeCss(lightMode, { themeName, isDark: false })\n if (lightModeCss) cssBlocks.push(lightModeCss)\n }\n\n if (darkMode) {\n const darkModeCss = generateColorModeCss(darkMode, { themeName, isDark: true })\n if (darkModeCss) cssBlocks.push(darkModeCss)\n }\n\n return cssBlocks.join('\\n\\n')\n}\n\nfunction buildSelector(themeName: string | undefined, isDark: boolean): string {\n if (themeName) {\n if (isDark) {\n return `:root[data-theme='${themeName}'][data-theme-mode='dark'], .dark[data-theme='${themeName}']`\n }\n return `:root[data-theme='${themeName}']`\n }\n\n if (isDark) {\n return \":root[data-theme-mode='dark'], .dark\"\n }\n\n return ':root'\n}\n\nfunction normalizeColor(value: string | null | undefined): string | null {\n if (typeof value !== 'string') return null\n const trimmed = value.trim()\n return trimmed.length === 0 ? null : trimmed\n}\n\n/**\n * Convert any color value to a valid CSS color string.\n * - oklch(...), hsl(...), rgb(...), etc. → pass through as-is\n * - var(...) CSS variable references → pass through as-is\n * - Hex (#rgb, #rrggbb) → convert to hsl(H S% L%)\n */\nfunction normalizeToCssColor(value: string): string {\n // Already a complete CSS color function — pass through unchanged\n if (/^(hsl|hsla|rgb|rgba|oklch|oklab|lch|lab|color|hwb)\\s*\\(/i.test(value)) {\n return value\n }\n // CSS variable reference — pass through\n if (/^var\\s*\\(/i.test(value)) {\n return value\n }\n // Hex color (#rgb or #rrggbb) — convert to hsl()\n return `hsl(${hexToHsl(value)})`\n}\n"],"names":["COLOR_VARIABLE_MAP","key","variable","hexToHsl","hex","replace","length","split","map","char","join","r","Number","parseInt","substring","g","b","max","Math","min","h","s","l","d","round","lRounded","generateColorModeCss","colors","options","themeName","isDark","cssVariables","reduce","acc","value","normalizeColor","push","normalizeToCssColor","selector","buildSelector","generateThemeColorsCss","cssBlocks","lightMode","darkMode","lightModeCss","darkModeCss","trimmed","trim","test"],"mappings":"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"}
|
|
@@ -1,7 +1,35 @@
|
|
|
1
1
|
import type { ResolvedThemeConfiguration } from './resolveThemeConfiguration.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
|
|
3
|
+
* Stable base attributes that are always present on the <html> element.
|
|
4
|
+
*/
|
|
5
|
+
interface BaseThemeHtmlAttributes {
|
|
6
|
+
'data-theme': string;
|
|
7
|
+
'data-theme-mode': string;
|
|
8
|
+
'data-border-radius': string;
|
|
9
|
+
'data-font-scale': string;
|
|
10
|
+
'data-spacing': string;
|
|
11
|
+
'data-animation-level': string;
|
|
12
|
+
'data-allow-color-mode-toggle': string;
|
|
13
|
+
suppressHydrationWarning: true;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Full attribute map: base attributes plus any visual-effect / component-style
|
|
17
|
+
* attributes that were configured. Optional keys are only present when the
|
|
18
|
+
* corresponding value is set, so callers can spread the whole object onto
|
|
19
|
+
* `<html>` without emitting empty attributes.
|
|
20
|
+
*/
|
|
21
|
+
export type ThemeHtmlAttributes = BaseThemeHtmlAttributes & Record<string, string | true>;
|
|
22
|
+
/**
|
|
23
|
+
* Generates HTML attributes for the <html> element based on theme configuration.
|
|
24
|
+
*
|
|
25
|
+
* This ensures the theme is applied before React hydration to prevent FOUC.
|
|
26
|
+
* Crucially, it also emits the `data-effect-style`, `data-card-style`,
|
|
27
|
+
* `data-button-variant`, `data-navbar-style`, `data-card-hover`,
|
|
28
|
+
* `data-border-*`, `data-button-size`, `data-footer-style`, `data-image-style`
|
|
29
|
+
* and `data-link-style` attributes that the CSS produced by `generateThemeCSS`
|
|
30
|
+
* targets. Without them, the visual-effect and component-style rules only
|
|
31
|
+
* activate after client hydration (the `ThemeProvider` syncs them from CSS
|
|
32
|
+
* variables), causing a flash of unstyled content on server-rendered pages.
|
|
5
33
|
*
|
|
6
34
|
* @example
|
|
7
35
|
* ```tsx
|
|
@@ -12,14 +40,6 @@ import type { ResolvedThemeConfiguration } from './resolveThemeConfiguration.js'
|
|
|
12
40
|
* <html {...htmlAttrs} className={yourClassName}>
|
|
13
41
|
* ```
|
|
14
42
|
*/
|
|
15
|
-
export declare function getThemeHtmlAttributes(config: ResolvedThemeConfiguration):
|
|
16
|
-
|
|
17
|
-
'data-theme-mode': string;
|
|
18
|
-
'data-border-radius': string;
|
|
19
|
-
'data-font-scale': string;
|
|
20
|
-
'data-spacing': string;
|
|
21
|
-
'data-animation-level': string;
|
|
22
|
-
'data-allow-color-mode-toggle': string;
|
|
23
|
-
suppressHydrationWarning: true;
|
|
24
|
-
};
|
|
43
|
+
export declare function getThemeHtmlAttributes(config: ResolvedThemeConfiguration): ThemeHtmlAttributes;
|
|
44
|
+
export {};
|
|
25
45
|
//# sourceMappingURL=themeHtmlAttributes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"themeHtmlAttributes.d.ts","sourceRoot":"","sources":["../../src/utils/themeHtmlAttributes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,gCAAgC,CAAA;AAEhF
|
|
1
|
+
{"version":3,"file":"themeHtmlAttributes.d.ts","sourceRoot":"","sources":["../../src/utils/themeHtmlAttributes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,gCAAgC,CAAA;AAEhF;;GAEG;AACH,UAAU,uBAAuB;IAC/B,YAAY,EAAE,MAAM,CAAA;IACpB,iBAAiB,EAAE,MAAM,CAAA;IACzB,oBAAoB,EAAE,MAAM,CAAA;IAC5B,iBAAiB,EAAE,MAAM,CAAA;IACzB,cAAc,EAAE,MAAM,CAAA;IACtB,sBAAsB,EAAE,MAAM,CAAA;IAC9B,8BAA8B,EAAE,MAAM,CAAA;IACtC,wBAAwB,EAAE,IAAI,CAAA;CAC/B;AAED;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,GAAG,uBAAuB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAA;AAKzF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,0BAA0B,GAAG,mBAAmB,CAuC9F"}
|
|
@@ -1,17 +1,26 @@
|
|
|
1
|
+
const isNonEmptyString = (value)=>typeof value === 'string' && value.trim().length > 0;
|
|
1
2
|
/**
|
|
2
|
-
* Generates HTML attributes for the <html> element based on theme configuration
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* Generates HTML attributes for the <html> element based on theme configuration.
|
|
4
|
+
*
|
|
5
|
+
* This ensures the theme is applied before React hydration to prevent FOUC.
|
|
6
|
+
* Crucially, it also emits the `data-effect-style`, `data-card-style`,
|
|
7
|
+
* `data-button-variant`, `data-navbar-style`, `data-card-hover`,
|
|
8
|
+
* `data-border-*`, `data-button-size`, `data-footer-style`, `data-image-style`
|
|
9
|
+
* and `data-link-style` attributes that the CSS produced by `generateThemeCSS`
|
|
10
|
+
* targets. Without them, the visual-effect and component-style rules only
|
|
11
|
+
* activate after client hydration (the `ThemeProvider` syncs them from CSS
|
|
12
|
+
* variables), causing a flash of unstyled content on server-rendered pages.
|
|
13
|
+
*
|
|
5
14
|
* @example
|
|
6
15
|
* ```tsx
|
|
7
16
|
* const siteSettings = await payload.findGlobal({ slug: 'site-settings' })
|
|
8
17
|
* const themeConfig = resolveThemeConfiguration(siteSettings?.themeConfiguration)
|
|
9
18
|
* const htmlAttrs = getThemeHtmlAttributes(themeConfig)
|
|
10
|
-
*
|
|
19
|
+
*
|
|
11
20
|
* <html {...htmlAttrs} className={yourClassName}>
|
|
12
21
|
* ```
|
|
13
22
|
*/ export function getThemeHtmlAttributes(config) {
|
|
14
|
-
|
|
23
|
+
const attributes = {
|
|
15
24
|
'data-theme': config.theme,
|
|
16
25
|
'data-theme-mode': config.colorMode,
|
|
17
26
|
'data-border-radius': config.borderRadius,
|
|
@@ -21,6 +30,30 @@
|
|
|
21
30
|
'data-allow-color-mode-toggle': config.allowColorModeToggle ? 'true' : 'false',
|
|
22
31
|
suppressHydrationWarning: true
|
|
23
32
|
};
|
|
33
|
+
const ve = config.visualEffects;
|
|
34
|
+
if (ve) {
|
|
35
|
+
if (isNonEmptyString(ve.effectStyle)) attributes['data-effect-style'] = ve.effectStyle;
|
|
36
|
+
if (isNonEmptyString(ve.shadowIntensity)) attributes['data-shadow-intensity'] = ve.shadowIntensity;
|
|
37
|
+
if (isNonEmptyString(ve.backdropBlur)) attributes['data-backdrop-blur'] = ve.backdropBlur;
|
|
38
|
+
if (isNonEmptyString(ve.borderStyle)) attributes['data-border-style'] = ve.borderStyle;
|
|
39
|
+
if (isNonEmptyString(ve.borderWidth)) attributes['data-border-width'] = ve.borderWidth;
|
|
40
|
+
}
|
|
41
|
+
const cs = config.componentStyles;
|
|
42
|
+
if (cs) {
|
|
43
|
+
if (isNonEmptyString(cs.buttonVariant)) attributes['data-button-variant'] = cs.buttonVariant;
|
|
44
|
+
if (isNonEmptyString(cs.buttonSize)) attributes['data-button-size'] = cs.buttonSize;
|
|
45
|
+
if (isNonEmptyString(cs.cardStyle)) attributes['data-card-style'] = cs.cardStyle;
|
|
46
|
+
if (isNonEmptyString(cs.cardHoverEffect)) attributes['data-card-hover'] = cs.cardHoverEffect;
|
|
47
|
+
if (isNonEmptyString(cs.imageStyle)) attributes['data-image-style'] = cs.imageStyle;
|
|
48
|
+
if (isNonEmptyString(cs.navbarStyle)) attributes['data-navbar-style'] = cs.navbarStyle;
|
|
49
|
+
if (isNonEmptyString(cs.footerStyle)) attributes['data-footer-style'] = cs.footerStyle;
|
|
50
|
+
if (isNonEmptyString(cs.linkStyle)) attributes['data-link-style'] = cs.linkStyle;
|
|
51
|
+
// Booleans: only emit the attribute when explicitly disabled (defaults are "on"),
|
|
52
|
+
// keeping the DOM clean while still letting CSS / consumer JS react to opt-outs.
|
|
53
|
+
if (cs.enableHoverAnimations === false) attributes['data-hover-animations'] = 'off';
|
|
54
|
+
if (cs.enableScrollReveal === false) attributes['data-scroll-reveal'] = 'off';
|
|
55
|
+
}
|
|
56
|
+
return attributes;
|
|
24
57
|
}
|
|
25
58
|
|
|
26
59
|
//# sourceMappingURL=themeHtmlAttributes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/themeHtmlAttributes.ts"],"sourcesContent":["import type { ResolvedThemeConfiguration } from './resolveThemeConfiguration.js'\n\n/**\n * Generates HTML attributes for the <html> element based on theme configuration
|
|
1
|
+
{"version":3,"sources":["../../src/utils/themeHtmlAttributes.ts"],"sourcesContent":["import type { ResolvedThemeConfiguration } from './resolveThemeConfiguration.js'\n\n/**\n * Stable base attributes that are always present on the <html> element.\n */\ninterface BaseThemeHtmlAttributes {\n 'data-theme': string\n 'data-theme-mode': string\n 'data-border-radius': string\n 'data-font-scale': string\n 'data-spacing': string\n 'data-animation-level': string\n 'data-allow-color-mode-toggle': string\n suppressHydrationWarning: true\n}\n\n/**\n * Full attribute map: base attributes plus any visual-effect / component-style\n * attributes that were configured. Optional keys are only present when the\n * corresponding value is set, so callers can spread the whole object onto\n * `<html>` without emitting empty attributes.\n */\nexport type ThemeHtmlAttributes = BaseThemeHtmlAttributes & Record<string, string | true>\n\nconst isNonEmptyString = (value: unknown): value is string =>\n typeof value === 'string' && value.trim().length > 0\n\n/**\n * Generates HTML attributes for the <html> element based on theme configuration.\n *\n * This ensures the theme is applied before React hydration to prevent FOUC.\n * Crucially, it also emits the `data-effect-style`, `data-card-style`,\n * `data-button-variant`, `data-navbar-style`, `data-card-hover`,\n * `data-border-*`, `data-button-size`, `data-footer-style`, `data-image-style`\n * and `data-link-style` attributes that the CSS produced by `generateThemeCSS`\n * targets. Without them, the visual-effect and component-style rules only\n * activate after client hydration (the `ThemeProvider` syncs them from CSS\n * variables), causing a flash of unstyled content on server-rendered pages.\n *\n * @example\n * ```tsx\n * const siteSettings = await payload.findGlobal({ slug: 'site-settings' })\n * const themeConfig = resolveThemeConfiguration(siteSettings?.themeConfiguration)\n * const htmlAttrs = getThemeHtmlAttributes(themeConfig)\n *\n * <html {...htmlAttrs} className={yourClassName}>\n * ```\n */\nexport function getThemeHtmlAttributes(config: ResolvedThemeConfiguration): ThemeHtmlAttributes {\n const attributes: ThemeHtmlAttributes = {\n 'data-theme': config.theme,\n 'data-theme-mode': config.colorMode,\n 'data-border-radius': config.borderRadius,\n 'data-font-scale': config.fontScale,\n 'data-spacing': config.spacing,\n 'data-animation-level': config.animationLevel,\n 'data-allow-color-mode-toggle': config.allowColorModeToggle ? 'true' : 'false',\n suppressHydrationWarning: true,\n }\n\n const ve = config.visualEffects\n if (ve) {\n if (isNonEmptyString(ve.effectStyle)) attributes['data-effect-style'] = ve.effectStyle\n if (isNonEmptyString(ve.shadowIntensity))\n attributes['data-shadow-intensity'] = ve.shadowIntensity\n if (isNonEmptyString(ve.backdropBlur)) attributes['data-backdrop-blur'] = ve.backdropBlur\n if (isNonEmptyString(ve.borderStyle)) attributes['data-border-style'] = ve.borderStyle\n if (isNonEmptyString(ve.borderWidth)) attributes['data-border-width'] = ve.borderWidth\n }\n\n const cs = config.componentStyles\n if (cs) {\n if (isNonEmptyString(cs.buttonVariant)) attributes['data-button-variant'] = cs.buttonVariant\n if (isNonEmptyString(cs.buttonSize)) attributes['data-button-size'] = cs.buttonSize\n if (isNonEmptyString(cs.cardStyle)) attributes['data-card-style'] = cs.cardStyle\n if (isNonEmptyString(cs.cardHoverEffect)) attributes['data-card-hover'] = cs.cardHoverEffect\n if (isNonEmptyString(cs.imageStyle)) attributes['data-image-style'] = cs.imageStyle\n if (isNonEmptyString(cs.navbarStyle)) attributes['data-navbar-style'] = cs.navbarStyle\n if (isNonEmptyString(cs.footerStyle)) attributes['data-footer-style'] = cs.footerStyle\n if (isNonEmptyString(cs.linkStyle)) attributes['data-link-style'] = cs.linkStyle\n // Booleans: only emit the attribute when explicitly disabled (defaults are \"on\"),\n // keeping the DOM clean while still letting CSS / consumer JS react to opt-outs.\n if (cs.enableHoverAnimations === false) attributes['data-hover-animations'] = 'off'\n if (cs.enableScrollReveal === false) attributes['data-scroll-reveal'] = 'off'\n }\n\n return attributes\n}\n"],"names":["isNonEmptyString","value","trim","length","getThemeHtmlAttributes","config","attributes","theme","colorMode","borderRadius","fontScale","spacing","animationLevel","allowColorModeToggle","suppressHydrationWarning","ve","visualEffects","effectStyle","shadowIntensity","backdropBlur","borderStyle","borderWidth","cs","componentStyles","buttonVariant","buttonSize","cardStyle","cardHoverEffect","imageStyle","navbarStyle","footerStyle","linkStyle","enableHoverAnimations","enableScrollReveal"],"mappings":"AAwBA,MAAMA,mBAAmB,CAACC,QACxB,OAAOA,UAAU,YAAYA,MAAMC,IAAI,GAAGC,MAAM,GAAG;AAErD;;;;;;;;;;;;;;;;;;;;CAoBC,GACD,OAAO,SAASC,uBAAuBC,MAAkC;IACvE,MAAMC,aAAkC;QACtC,cAAcD,OAAOE,KAAK;QAC1B,mBAAmBF,OAAOG,SAAS;QACnC,sBAAsBH,OAAOI,YAAY;QACzC,mBAAmBJ,OAAOK,SAAS;QACnC,gBAAgBL,OAAOM,OAAO;QAC9B,wBAAwBN,OAAOO,cAAc;QAC7C,gCAAgCP,OAAOQ,oBAAoB,GAAG,SAAS;QACvEC,0BAA0B;IAC5B;IAEA,MAAMC,KAAKV,OAAOW,aAAa;IAC/B,IAAID,IAAI;QACN,IAAIf,iBAAiBe,GAAGE,WAAW,GAAGX,UAAU,CAAC,oBAAoB,GAAGS,GAAGE,WAAW;QACtF,IAAIjB,iBAAiBe,GAAGG,eAAe,GACrCZ,UAAU,CAAC,wBAAwB,GAAGS,GAAGG,eAAe;QAC1D,IAAIlB,iBAAiBe,GAAGI,YAAY,GAAGb,UAAU,CAAC,qBAAqB,GAAGS,GAAGI,YAAY;QACzF,IAAInB,iBAAiBe,GAAGK,WAAW,GAAGd,UAAU,CAAC,oBAAoB,GAAGS,GAAGK,WAAW;QACtF,IAAIpB,iBAAiBe,GAAGM,WAAW,GAAGf,UAAU,CAAC,oBAAoB,GAAGS,GAAGM,WAAW;IACxF;IAEA,MAAMC,KAAKjB,OAAOkB,eAAe;IACjC,IAAID,IAAI;QACN,IAAItB,iBAAiBsB,GAAGE,aAAa,GAAGlB,UAAU,CAAC,sBAAsB,GAAGgB,GAAGE,aAAa;QAC5F,IAAIxB,iBAAiBsB,GAAGG,UAAU,GAAGnB,UAAU,CAAC,mBAAmB,GAAGgB,GAAGG,UAAU;QACnF,IAAIzB,iBAAiBsB,GAAGI,SAAS,GAAGpB,UAAU,CAAC,kBAAkB,GAAGgB,GAAGI,SAAS;QAChF,IAAI1B,iBAAiBsB,GAAGK,eAAe,GAAGrB,UAAU,CAAC,kBAAkB,GAAGgB,GAAGK,eAAe;QAC5F,IAAI3B,iBAAiBsB,GAAGM,UAAU,GAAGtB,UAAU,CAAC,mBAAmB,GAAGgB,GAAGM,UAAU;QACnF,IAAI5B,iBAAiBsB,GAAGO,WAAW,GAAGvB,UAAU,CAAC,oBAAoB,GAAGgB,GAAGO,WAAW;QACtF,IAAI7B,iBAAiBsB,GAAGQ,WAAW,GAAGxB,UAAU,CAAC,oBAAoB,GAAGgB,GAAGQ,WAAW;QACtF,IAAI9B,iBAAiBsB,GAAGS,SAAS,GAAGzB,UAAU,CAAC,kBAAkB,GAAGgB,GAAGS,SAAS;QAChF,kFAAkF;QAClF,iFAAiF;QACjF,IAAIT,GAAGU,qBAAqB,KAAK,OAAO1B,UAAU,CAAC,wBAAwB,GAAG;QAC9E,IAAIgB,GAAGW,kBAAkB,KAAK,OAAO3B,UAAU,CAAC,qBAAqB,GAAG;IAC1E;IAEA,OAAOA;AACT"}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
typography?: ThemeTypographyPreset | null;
|
|
1
|
+
import type { ResolvedThemeConfiguration } from './resolveThemeConfiguration.js';
|
|
2
|
+
type ThemeConfiguration = Omit<ResolvedThemeConfiguration, 'typography'> & {
|
|
3
|
+
typography?: ResolvedThemeConfiguration['typography'];
|
|
5
4
|
};
|
|
6
|
-
type ThemeConfiguration = Omit<NonNullable<SiteSetting['themeConfiguration']>, 'typography'> & ThemeTypographyConfiguration;
|
|
7
5
|
/**
|
|
8
6
|
* Generates CSS custom properties from theme configuration
|
|
9
7
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"themeUtils.d.ts","sourceRoot":"","sources":["../../src/utils/themeUtils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"themeUtils.d.ts","sourceRoot":"","sources":["../../src/utils/themeUtils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,gCAAgC,CAAA;AAEhF,KAAK,kBAAkB,GAAG,IAAI,CAAC,0BAA0B,EAAE,YAAY,CAAC,GAAG;IACzE,UAAU,CAAC,EAAE,0BAA0B,CAAC,YAAY,CAAC,CAAA;CACtD,CAAA;AAaD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CA+BnE;AAiBD;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,kBAAkB,0BAQxD"}
|