@kilivi/payloadcms-theme-management 2.1.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 +37 -7
- package/dist/components/ServerThemeInjector.d.ts +13 -1
- package/dist/components/ServerThemeInjector.d.ts.map +1 -1
- package/dist/components/ServerThemeInjector.js +24 -1
- package/dist/components/ServerThemeInjector.js.map +1 -1
- package/dist/components/ThemeLivePreviewSync.d.ts +3 -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/typographyPreviewUtils.d.ts +5 -0
- package/dist/components/typographyPreviewUtils.d.ts.map +1 -1
- package/dist/components/typographyPreviewUtils.js +16 -10
- package/dist/components/typographyPreviewUtils.js.map +1 -1
- 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/fields/AppearancePreviewField.d.ts.map +1 -1
- package/dist/fields/AppearancePreviewField.js +196 -133
- package/dist/fields/AppearancePreviewField.js.map +1 -1
- package/dist/fields/FontSelectField.css +155 -0
- package/dist/fields/FontSelectField.d.ts +4 -2
- package/dist/fields/FontSelectField.d.ts.map +1 -1
- package/dist/fields/FontSelectField.js +80 -118
- package/dist/fields/FontSelectField.js.map +1 -1
- package/dist/fields/StylePresetField.d.ts.map +1 -1
- package/dist/fields/StylePresetField.js +31 -30
- package/dist/fields/StylePresetField.js.map +1 -1
- package/dist/fields/ThemePreviewField.css +63 -1
- package/dist/fields/ThemePreviewField.d.ts.map +1 -1
- package/dist/fields/ThemePreviewField.js +2 -5
- package/dist/fields/ThemePreviewField.js.map +1 -1
- package/dist/fields/themeConfigurationField.d.ts.map +1 -1
- package/dist/fields/themeConfigurationField.js +320 -271
- package/dist/fields/themeConfigurationField.js.map +1 -1
- 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/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- 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 +10 -6
- package/dist/payload-types.d.ts.map +1 -1
- package/dist/payload-types.js.map +1 -1
- package/dist/presets.d.ts +6 -0
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js.map +1 -1
- package/dist/style-presets.d.ts +27 -18
- package/dist/style-presets.d.ts.map +1 -1
- package/dist/style-presets.js +399 -217
- package/dist/style-presets.js.map +1 -1
- package/dist/translations.d.ts +5 -0
- package/dist/translations.d.ts.map +1 -1
- package/dist/translations.js +10 -0
- package/dist/translations.js.map +1 -1
- package/dist/utils/livePreviewThemeRuntime.d.ts +6 -1
- package/dist/utils/livePreviewThemeRuntime.d.ts.map +1 -1
- package/dist/utils/livePreviewThemeRuntime.js +11 -1
- package/dist/utils/livePreviewThemeRuntime.js.map +1 -1
- package/dist/utils/resolveThemeConfiguration.d.ts +15 -0
- package/dist/utils/resolveThemeConfiguration.d.ts.map +1 -1
- package/dist/utils/resolveThemeConfiguration.js +41 -8
- package/dist/utils/resolveThemeConfiguration.js.map +1 -1
- package/dist/utils/themeUtils.d.ts.map +1 -1
- package/dist/utils/themeUtils.js +60 -2
- package/dist/utils/themeUtils.js.map +1 -1
- package/package.json +5 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getFontCatalogEntry, LETTER_SPACING_TO_CSS, toFontSizeCss } from '../constants/themeFonts.js';
|
|
2
2
|
import { allThemePresets } from '../presets.js';
|
|
3
3
|
import { themeIsValid } from '../providers/Theme/types.js';
|
|
4
4
|
const BORDER_RADIUS_VALUES = [
|
|
@@ -21,6 +21,10 @@ const SPACING_VALUES = [
|
|
|
21
21
|
'medium',
|
|
22
22
|
'spacious'
|
|
23
23
|
];
|
|
24
|
+
// Earlier versions stored the roomiest spacing option as 'comfortable'.
|
|
25
|
+
const LEGACY_SPACING_ALIASES = {
|
|
26
|
+
comfortable: 'spacious'
|
|
27
|
+
};
|
|
24
28
|
const ANIMATION_LEVEL_VALUES = [
|
|
25
29
|
'none',
|
|
26
30
|
'reduced',
|
|
@@ -94,7 +98,7 @@ export function resolveThemeConfiguration(themeConfiguration) {
|
|
|
94
98
|
const resolvedMode = isMode(colorMode) ? colorMode : DEFAULT_THEME_CONFIGURATION.colorMode;
|
|
95
99
|
const resolvedBorderRadius = resolveBorderRadius(borderRadius);
|
|
96
100
|
const resolvedFontScale = isFontScale(fontScale) ? fontScale : DEFAULT_THEME_CONFIGURATION.fontScale;
|
|
97
|
-
const resolvedSpacing = isSpacing(spacing) ? spacing : DEFAULT_THEME_CONFIGURATION.spacing;
|
|
101
|
+
const resolvedSpacing = isSpacing(spacing) ? spacing : typeof spacing === 'string' && LEGACY_SPACING_ALIASES[spacing] || DEFAULT_THEME_CONFIGURATION.spacing;
|
|
98
102
|
const resolvedAnimationLevel = resolveAnimationLevel(animationLevel);
|
|
99
103
|
const resolvedAllowToggle = typeof allowColorModeToggle === 'boolean' ? allowColorModeToggle : DEFAULT_THEME_CONFIGURATION.allowColorModeToggle;
|
|
100
104
|
const resolvedCustomCSS = typeof customCSS === 'string' ? customCSS : null;
|
|
@@ -103,7 +107,23 @@ export function resolveThemeConfiguration(themeConfiguration) {
|
|
|
103
107
|
const baseDarkMode = preset?.darkMode ?? DEFAULT_THEME_CONFIGURATION.darkMode;
|
|
104
108
|
const resolvedLightMode = mergeColorModes(baseLightMode, lightMode);
|
|
105
109
|
const resolvedDarkMode = mergeColorModes(baseDarkMode, darkMode);
|
|
106
|
-
|
|
110
|
+
// Accept an already-resolved configuration too (callers often resolve once and
|
|
111
|
+
// pass the result to several helpers): its typography is final, keep it as is.
|
|
112
|
+
const typographyIsResolved = typography !== null && typeof typography === 'object' && typeof typography.fontFamily === 'string';
|
|
113
|
+
const resolvedTypography = typographyIsResolved ? typography : mergeTypography(preset?.typography, typography) ?? preset?.typography ?? null;
|
|
114
|
+
const isSet = (value)=>typeof value === 'string' && value !== '' && value !== 'preset';
|
|
115
|
+
const typographyOverridden = typographyIsResolved ? cfg.typographyOverridden === true : Boolean(typography && [
|
|
116
|
+
typography.bodyFont,
|
|
117
|
+
typography.headingFont,
|
|
118
|
+
typography.baseFontSize,
|
|
119
|
+
typography.lineHeight,
|
|
120
|
+
typography.headingWeight,
|
|
121
|
+
typography.letterSpacing
|
|
122
|
+
].some(isSet));
|
|
123
|
+
const fontSelections = typographyIsResolved ? cfg.fontSelections ?? [] : [
|
|
124
|
+
typography?.bodyFont,
|
|
125
|
+
typography?.headingFont
|
|
126
|
+
].filter((value)=>typeof value === 'string' && value !== 'preset' && value !== 'custom');
|
|
107
127
|
// Pass visualEffects and componentStyles through as-is (no normalization needed)
|
|
108
128
|
const resolvedVisualEffects = visualEffects ?? null;
|
|
109
129
|
const resolvedComponentStyles = componentStyles ?? null;
|
|
@@ -119,6 +139,8 @@ export function resolveThemeConfiguration(themeConfiguration) {
|
|
|
119
139
|
lightMode: resolvedLightMode,
|
|
120
140
|
darkMode: resolvedDarkMode,
|
|
121
141
|
typography: resolvedTypography,
|
|
142
|
+
fontSelections,
|
|
143
|
+
typographyOverridden,
|
|
122
144
|
visualEffects: resolvedVisualEffects,
|
|
123
145
|
componentStyles: resolvedComponentStyles
|
|
124
146
|
};
|
|
@@ -150,8 +172,11 @@ function mergeTypography(base, overrides) {
|
|
|
150
172
|
const result = {
|
|
151
173
|
fontFamily: base?.fontFamily ?? 'var(--font-inter, var(--font-geist-sans), system-ui, sans-serif)',
|
|
152
174
|
headingFamily: base?.headingFamily ?? 'var(--font-outfit, var(--font-geist-sans), system-ui, sans-serif)',
|
|
153
|
-
baseFontSize: base?.baseFontSize ?? '16px',
|
|
175
|
+
baseFontSize: toFontSizeCss(base?.baseFontSize) ?? '16px',
|
|
154
176
|
lineHeight: base?.lineHeight ?? '1.6',
|
|
177
|
+
headingWeight: base?.headingWeight,
|
|
178
|
+
headingLetterSpacing: base?.headingLetterSpacing,
|
|
179
|
+
headingTransform: base?.headingTransform,
|
|
155
180
|
fontWeights: {
|
|
156
181
|
...base?.fontWeights ?? {}
|
|
157
182
|
},
|
|
@@ -168,12 +193,21 @@ function mergeTypography(base, overrides) {
|
|
|
168
193
|
if (resolvedHeadingFont) {
|
|
169
194
|
result.headingFamily = resolvedHeadingFont;
|
|
170
195
|
}
|
|
171
|
-
|
|
172
|
-
|
|
196
|
+
const baseFontSize = toFontSizeCss(overrides.baseFontSize);
|
|
197
|
+
if (baseFontSize) {
|
|
198
|
+
result.baseFontSize = baseFontSize;
|
|
173
199
|
}
|
|
174
200
|
if (overrides.lineHeight && overrides.lineHeight !== 'preset') {
|
|
175
201
|
result.lineHeight = overrides.lineHeight;
|
|
176
202
|
}
|
|
203
|
+
if (overrides.headingWeight && overrides.headingWeight !== 'preset') {
|
|
204
|
+
result.headingWeight = overrides.headingWeight;
|
|
205
|
+
}
|
|
206
|
+
const tracking = overrides.letterSpacing ? LETTER_SPACING_TO_CSS[overrides.letterSpacing] : undefined;
|
|
207
|
+
if (tracking !== undefined) {
|
|
208
|
+
result.headingLetterSpacing = tracking;
|
|
209
|
+
result.headingTransform = overrides.letterSpacing === 'wider' ? 'uppercase' : 'none';
|
|
210
|
+
}
|
|
177
211
|
}
|
|
178
212
|
return result;
|
|
179
213
|
}
|
|
@@ -185,8 +219,7 @@ function resolveFontSelection(selection, custom, fallback) {
|
|
|
185
219
|
const trimmed = custom?.trim();
|
|
186
220
|
return trimmed && trimmed.length > 0 ? trimmed : fallback ?? null;
|
|
187
221
|
}
|
|
188
|
-
|
|
189
|
-
return mapped ?? fallback ?? null;
|
|
222
|
+
return getFontCatalogEntry(selection)?.fontFamily ?? fallback ?? null;
|
|
190
223
|
}
|
|
191
224
|
|
|
192
225
|
//# sourceMappingURL=resolveThemeConfiguration.js.map
|
|
@@ -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 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\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 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) ? 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 // 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 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: 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","cfg","Array","isArray","visualEffects","componentStyles","resolvedTheme","resolvedMode","resolvedBorderRadius","resolvedFontScale","resolvedSpacing","resolvedAnimationLevel","resolvedAllowToggle","resolvedCustomCSS","candidate","baseLightMode","baseDarkMode","resolvedLightMode","mergeColorModes","resolvedDarkMode","resolvedTypography","mergeTypography","resolvedVisualEffects","resolvedComponentStyles","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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"}
|
|
@@ -1 +1 @@
|
|
|
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,
|
|
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"}
|
package/dist/utils/themeUtils.js
CHANGED
|
@@ -17,6 +17,7 @@ import { borderRadiusPresets } from '../providers/Theme/themeConfig.js';
|
|
|
17
17
|
applyComponentStyleCSSVars(cssRules, config);
|
|
18
18
|
cssRules.push('}');
|
|
19
19
|
// ── Element-level effect rules (outside :root) ──────────────────────────
|
|
20
|
+
applyTypographyBaseRules(cssRules, config);
|
|
20
21
|
applyEffectElementRules(cssRules, config);
|
|
21
22
|
// ── Color mode overrides ────────────────────────────────────────────────
|
|
22
23
|
applyDarkModeOverrides(cssRules, config, customization, themeSelector);
|
|
@@ -113,6 +114,10 @@ function applySpacingRule(rules, config) {
|
|
|
113
114
|
const multiplier = spacingMultipliers[config.spacing] ?? '1';
|
|
114
115
|
rules.push(` --spacing-scale: ${multiplier};`);
|
|
115
116
|
rules.push(` --theme-spacing: ${multiplier};`);
|
|
117
|
+
// Ready-to-use rhythm tokens so the spacing choice is visible without extra math.
|
|
118
|
+
rules.push(` --section-spacing: calc(clamp(3rem, 8vw, 6rem) * ${multiplier});`);
|
|
119
|
+
rules.push(` --card-padding: calc(1.5rem * ${multiplier});`);
|
|
120
|
+
rules.push(` --stack-gap: calc(1rem * ${multiplier});`);
|
|
116
121
|
}
|
|
117
122
|
function applyAnimationRule(rules, config) {
|
|
118
123
|
if (!config.animationLevel) return;
|
|
@@ -174,6 +179,36 @@ function applyTypographyRules(rules, config) {
|
|
|
174
179
|
}
|
|
175
180
|
});
|
|
176
181
|
}
|
|
182
|
+
if (typography.headingWeight) {
|
|
183
|
+
rules.push(` --typography-headingWeight: ${typography.headingWeight};`);
|
|
184
|
+
}
|
|
185
|
+
if (typography.headingLetterSpacing) {
|
|
186
|
+
rules.push(` --typography-headingLetterSpacing: ${typography.headingLetterSpacing};`);
|
|
187
|
+
}
|
|
188
|
+
if (typography.headingTransform) {
|
|
189
|
+
rules.push(` --typography-headingTransform: ${typography.headingTransform};`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Zero-specificity base rules (`:where()`), so the chosen fonts show up on a site
|
|
194
|
+
* that has no typography CSS of its own, while any rule the site does have wins.
|
|
195
|
+
*/ function applyTypographyBaseRules(rules, config) {
|
|
196
|
+
// Only when the editor chose typography explicitly: sites that never touched it
|
|
197
|
+
// keep rendering exactly as before.
|
|
198
|
+
if (!config.typography || !config.typographyOverridden) return;
|
|
199
|
+
rules.push('');
|
|
200
|
+
rules.push('/* ── Typography base (zero specificity — site CSS always wins) ── */');
|
|
201
|
+
rules.push(':where(html[data-theme]) :where(body) {');
|
|
202
|
+
rules.push(' font-family: var(--typography-fontFamily, system-ui, sans-serif);');
|
|
203
|
+
rules.push(' font-size: calc(var(--typography-baseFontSize, 16px) * var(--theme-font-scale, 1));');
|
|
204
|
+
rules.push(' line-height: var(--typography-lineHeight, 1.6);');
|
|
205
|
+
rules.push('}');
|
|
206
|
+
rules.push(':where(html[data-theme]) :where(h1, h2, h3, h4, h5, h6) {');
|
|
207
|
+
rules.push(' font-family: var(--typography-headingFamily, var(--typography-fontFamily, inherit));');
|
|
208
|
+
rules.push(' font-weight: var(--typography-headingWeight, var(--typography-fontWeights-bold, 700));');
|
|
209
|
+
rules.push(' letter-spacing: var(--typography-headingLetterSpacing, normal);');
|
|
210
|
+
rules.push(' text-transform: var(--typography-headingTransform, none);');
|
|
211
|
+
rules.push('}');
|
|
177
212
|
}
|
|
178
213
|
function getVE(config) {
|
|
179
214
|
return config.visualEffects ?? null;
|
|
@@ -264,6 +299,15 @@ const BLUR_PX_MAP = {
|
|
|
264
299
|
if (!ve && !cs) return;
|
|
265
300
|
rules.push('');
|
|
266
301
|
rules.push('/* ── Effect element overrides ── */');
|
|
302
|
+
// ── Card border style / width (effect rules below may still replace it) ──
|
|
303
|
+
// Skipped for the field defaults (solid / 1px) so existing cards are unchanged.
|
|
304
|
+
if (ve?.borderStyle && (ve.borderStyle !== 'solid' || (ve.borderWidth ?? '1px') !== '1px')) {
|
|
305
|
+
rules.push(`html[data-border-style] [data-card] {`);
|
|
306
|
+
rules.push(` border-style: var(--border-style, solid);`);
|
|
307
|
+
rules.push(` border-width: var(--border-width, 1px);`);
|
|
308
|
+
rules.push(` border-color: var(--border);`);
|
|
309
|
+
rules.push(`}`);
|
|
310
|
+
}
|
|
267
311
|
// ── Glass effect ──────────────────────────────────────────────────────
|
|
268
312
|
// NOTE: All effect-style blocks are ALWAYS emitted regardless of the saved
|
|
269
313
|
// effectStyle value. The CSS selectors are scoped by html[data-effect-style='X']
|
|
@@ -453,13 +497,27 @@ const BLUR_PX_MAP = {
|
|
|
453
497
|
rules.push(` border-radius: 9999px !important;`);
|
|
454
498
|
rules.push(`}`);
|
|
455
499
|
}
|
|
456
|
-
// ── Button
|
|
500
|
+
// ── Button variants: outlined / ghost ──────────────────────────────────
|
|
457
501
|
if (cs?.buttonVariant === 'outlined') {
|
|
458
502
|
rules.push(`html[data-button-variant='outlined'] [data-btn] {`);
|
|
459
503
|
rules.push(` background-color: transparent !important;`);
|
|
460
|
-
rules.push(`
|
|
504
|
+
rules.push(` color: var(--primary) !important;`);
|
|
505
|
+
rules.push(` border: 1.5px solid var(--primary) !important;`);
|
|
461
506
|
rules.push(` box-shadow: none !important;`);
|
|
462
507
|
rules.push(`}`);
|
|
508
|
+
rules.push(`html[data-button-variant='outlined'] [data-btn]:hover {`);
|
|
509
|
+
rules.push(` background-color: color-mix(in srgb, var(--primary) 10%, transparent) !important;`);
|
|
510
|
+
rules.push(`}`);
|
|
511
|
+
} else if (cs?.buttonVariant === 'ghost') {
|
|
512
|
+
rules.push(`html[data-button-variant='ghost'] [data-btn] {`);
|
|
513
|
+
rules.push(` background-color: transparent !important;`);
|
|
514
|
+
rules.push(` color: var(--primary) !important;`);
|
|
515
|
+
rules.push(` border-color: transparent !important;`);
|
|
516
|
+
rules.push(` box-shadow: none !important;`);
|
|
517
|
+
rules.push(`}`);
|
|
518
|
+
rules.push(`html[data-button-variant='ghost'] [data-btn]:hover {`);
|
|
519
|
+
rules.push(` background-color: color-mix(in srgb, var(--primary) 10%, transparent) !important;`);
|
|
520
|
+
rules.push(`}`);
|
|
463
521
|
}
|
|
464
522
|
// ── Card hover effects ─────────────────────────────────────────────────
|
|
465
523
|
if (cs?.cardHoverEffect === 'lift') {
|