@kilivi/payloadcms-theme-management 1.1.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +48 -31
  2. package/dist/components/ThemeLivePreviewSync.d.ts +11 -0
  3. package/dist/components/ThemeLivePreviewSync.d.ts.map +1 -0
  4. package/dist/components/ThemeLivePreviewSync.js +40 -0
  5. package/dist/components/ThemeLivePreviewSync.js.map +1 -0
  6. package/dist/fields/ThemeColorPickerField.d.ts.map +1 -1
  7. package/dist/fields/ThemeColorPickerField.js +26 -9
  8. package/dist/fields/ThemeColorPickerField.js.map +1 -1
  9. package/dist/fields/ThemePreviewField.d.ts.map +1 -1
  10. package/dist/fields/ThemePreviewField.js +2 -1
  11. package/dist/fields/ThemePreviewField.js.map +1 -1
  12. package/dist/fields/themeConfigurationField.d.ts +1 -0
  13. package/dist/fields/themeConfigurationField.d.ts.map +1 -1
  14. package/dist/fields/themeConfigurationField.js +3 -2
  15. package/dist/fields/themeConfigurationField.js.map +1 -1
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +414 -16
  19. package/dist/index.js.map +1 -1
  20. package/dist/server.d.ts +30 -0
  21. package/dist/server.d.ts.map +1 -1
  22. package/dist/server.js +42 -0
  23. package/dist/server.js.map +1 -1
  24. package/dist/types/color.d.js +2 -0
  25. package/dist/types/color.d.js.map +1 -0
  26. package/dist/types.d.ts +73 -0
  27. package/dist/types.d.ts.map +1 -1
  28. package/dist/types.js.map +1 -1
  29. package/dist/utils/livePreviewRefresh.d.ts +17 -0
  30. package/dist/utils/livePreviewRefresh.d.ts.map +1 -0
  31. package/dist/utils/livePreviewRefresh.js +20 -0
  32. package/dist/utils/livePreviewRefresh.js.map +1 -0
  33. package/dist/utils/livePreviewThemeRuntime.d.ts +7 -0
  34. package/dist/utils/livePreviewThemeRuntime.d.ts.map +1 -0
  35. package/dist/utils/livePreviewThemeRuntime.js +58 -0
  36. package/dist/utils/livePreviewThemeRuntime.js.map +1 -0
  37. package/package.json +1 -1
package/README.md CHANGED
@@ -162,34 +162,31 @@ export default async function RootLayout({ children }: { children: React.ReactNo
162
162
  }
163
163
  ```
164
164
 
165
- #### Cache Optimization with Next.js
165
+ #### Cache Optimization with Next.js (Out of the Box)
166
166
 
167
167
  When using standalone global, the plugin automatically invalidates cache after saving appearance settings using the tag `global_appearance-settings` (or `global_{your-slug}` if you use a custom slug).
168
168
 
169
- You can optimize your theme fetching by adding cache tags to your layout:
169
+ You can optimize your theme fetching by using the built-in server helper:
170
170
 
171
171
  ```tsx
172
172
  // app/layout.tsx
173
- import { ServerThemeInjector } from '@kilivi/payloadcms-theme-management/server'
173
+ import {
174
+ createCachedThemeFetcher,
175
+ ServerThemeInjector,
176
+ } from '@kilivi/payloadcms-theme-management/server'
174
177
  import configPromise from '@payload-config'
175
178
  import { getPayload } from 'payload'
176
- import { unstable_cache } from 'next/cache'
177
179
 
178
- // Create cached theme fetcher with automatic invalidation
179
- const getCachedTheme = unstable_cache(
180
- async () => {
180
+ const getCachedTheme = createCachedThemeFetcher({
181
+ globalSlug: 'appearance-settings',
182
+ revalidate: 3600,
183
+ loadAppearanceSettings: async () => {
181
184
  const payload = await getPayload({ config: configPromise })
182
- const appearanceSettings = await payload.findGlobal({
185
+ return payload.findGlobal({
183
186
  slug: 'appearance-settings',
184
187
  })
185
- return appearanceSettings?.themeConfiguration
186
188
  },
187
- ['appearance-settings-theme'],
188
- {
189
- tags: ['global_appearance-settings'], // Matches the auto-invalidation tag from plugin
190
- revalidate: 3600, // Optional: revalidate every hour as fallback
191
- },
192
- )
189
+ })
193
190
 
194
191
  export default async function RootLayout({ children }: { children: React.ReactNode }) {
195
192
  const themeConfiguration = await getCachedTheme()
@@ -216,6 +213,24 @@ export default async function RootLayout({ children }: { children: React.ReactNo
216
213
  - Default: `global_appearance-settings`
217
214
  - Custom slug: `global_{standaloneCollectionSlug}`
218
215
 
216
+ #### Injected Revalidation Route
217
+
218
+ The plugin now injects a Payload endpoint (default: `POST /api/theme/revalidate`) that triggers the same tag/path invalidation logic used by live preview saves.
219
+
220
+ ```ts
221
+ themeManagementPlugin({
222
+ useStandaloneCollection: true,
223
+ cacheRevalidation: {
224
+ routePath: '/theme/revalidate',
225
+ secret: process.env.THEME_REVALIDATE_SECRET,
226
+ tags: ['tenant:default'],
227
+ paths: ['/'],
228
+ },
229
+ })
230
+ ```
231
+
232
+ Set `cacheRevalidation.injectRoute` to `false` if you want to keep only automatic hook-based invalidation.
233
+
219
234
  > **Note:** The cache invalidation hook is only available for standalone global mode. When using the tab mode (default), implement your own caching strategy based on your collection structure.
220
235
 
221
236
  ### 3. Use Theme Variables in Your CSS
@@ -239,22 +254,24 @@ Or with Tailwind CSS:
239
254
 
240
255
  ## Plugin Configuration Options
241
256
 
242
- | Option | Type | Default | Description |
243
- | --------------------------- | ---------------------------------- | ----------------------- | ----------------------------------------------------------------- |
244
- | `enabled` | `boolean` | `true` | Enable/disable the plugin |
245
- | `targetCollection` | `string` | `'site-settings'` | Collection slug to add theme field to (when not using standalone) |
246
- | `useStandaloneCollection` | `boolean` | `false` | Create a separate global instead of adding as a tab |
247
- | `standaloneCollectionSlug` | `string` | `'appearance-settings'` | Slug for the standalone global |
248
- | `standaloneCollectionLabel` | `string \| Record<string, string>` | `'Appearance Settings'` | Label for the standalone global (supports i18n) |
249
- | `themePresets` | `ThemePreset[]` | Built-in presets | Custom theme presets |
250
- | `defaultTheme` | `string` | `'cool'` | Default theme preset name |
251
- | `includeColorModeToggle` | `boolean` | `true` | Show light/dark mode toggle |
252
- | `includeCustomCSS` | `boolean` | `true` | Allow custom CSS injection |
253
- | `includeBrandIdentity` | `boolean` | `false` | Show brand identity fields |
254
- | `enableAdvancedFeatures` | `boolean` | `true` | Enable advanced customization |
255
- | `enableLogging` | `boolean` | `false` | Log plugin actions to console (includes cache invalidation logs) |
256
-
257
- **Cache Invalidation Note:** When using `useStandaloneCollection: true`, the plugin automatically invalidates the cache tag `global_{standaloneCollectionSlug}` after saving appearance settings. Use `unstable_cache` with matching tags for optimal performance.
257
+ | Option | Type | Default | Description |
258
+ | --------------------------- | ------------------------------------- | ----------------------- | -------------------------------------------------------------------- |
259
+ | `enabled` | `boolean` | `true` | Enable/disable the plugin |
260
+ | `targetCollection` | `string` | `'site-settings'` | Collection slug to add theme field to (when not using standalone) |
261
+ | `useStandaloneCollection` | `boolean` | `false` | Create a separate global instead of adding as a tab |
262
+ | `standaloneCollectionSlug` | `string` | `'appearance-settings'` | Slug for the standalone global |
263
+ | `standaloneCollectionLabel` | `string \| Record<string, string>` | `'Appearance Settings'` | Label for the standalone global (supports i18n) |
264
+ | `themePresets` | `ThemePreset[]` | Built-in presets | Custom theme presets |
265
+ | `defaultTheme` | `string` | `'cool'` | Default theme preset name |
266
+ | `includeColorModeToggle` | `boolean` | `true` | Show light/dark mode toggle |
267
+ | `includeCustomCSS` | `boolean` | `true` | Allow custom CSS injection |
268
+ | `includeBrandIdentity` | `boolean` | `false` | Show brand identity fields |
269
+ | `enableAdvancedFeatures` | `boolean` | `true` | Enable advanced customization |
270
+ | `enableLogging` | `boolean` | `false` | Log plugin actions to console (includes cache invalidation logs) |
271
+ | `livePreview` | `boolean \| LivePreviewOptions` | `true` | Enable/administer live preview URL resolution (`home` → fallback) |
272
+ | `cacheRevalidation` | `boolean \| CacheRevalidationOptions` | `standalone: true` | Configure injected route + tags/paths for Next.js cache invalidation |
273
+
274
+ **Cache Invalidation Note:** In standalone mode, the plugin revalidates `global_{standaloneCollectionSlug}` automatically and injects `POST /api/theme/revalidate` by default. Pair it with `createCachedThemeFetcher` from `@kilivi/payloadcms-theme-management/server` for a zero-boilerplate setup.
258
275
 
259
276
  ## Available Theme Presets
260
277
 
@@ -0,0 +1,11 @@
1
+ interface ThemeLivePreviewSyncProps {
2
+ initialData: Record<string, unknown>;
3
+ serverURL: string;
4
+ apiRoute?: string;
5
+ depth?: number;
6
+ themeConfigurationKey?: string;
7
+ styleElementId?: string;
8
+ }
9
+ export declare const ThemeLivePreviewSync: React.FC<ThemeLivePreviewSyncProps>;
10
+ export {};
11
+ //# sourceMappingURL=ThemeLivePreviewSync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ThemeLivePreviewSync.d.ts","sourceRoot":"","sources":["../../src/components/ThemeLivePreviewSync.tsx"],"names":[],"mappings":"AASA,UAAU,yBAAyB;IACjC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACpC,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CA4CpE,CAAA"}
@@ -0,0 +1,40 @@
1
+ 'use client';
2
+ import { useLivePreview } from '@payloadcms/live-preview-react';
3
+ import { useEffect, useMemo } from 'react';
4
+ import { buildLivePreviewThemeRuntime, extractThemeConfigurationFromLiveData } from '../utils/livePreviewThemeRuntime.js';
5
+ export const ThemeLivePreviewSync = ({ initialData, serverURL, apiRoute, depth, themeConfigurationKey = 'themeConfiguration', styleElementId = 'theme-live-preview-css' })=>{
6
+ const { data } = useLivePreview({
7
+ apiRoute,
8
+ depth,
9
+ initialData,
10
+ serverURL
11
+ });
12
+ const themeConfiguration = useMemo(()=>extractThemeConfigurationFromLiveData(data, themeConfigurationKey), [
13
+ data,
14
+ themeConfigurationKey
15
+ ]);
16
+ useEffect(()=>{
17
+ if (typeof document === 'undefined' || !themeConfiguration) {
18
+ return;
19
+ }
20
+ const runtime = buildLivePreviewThemeRuntime(themeConfiguration);
21
+ let styleElement = document.getElementById(styleElementId);
22
+ if (!styleElement) {
23
+ styleElement = document.createElement('style');
24
+ styleElement.id = styleElementId;
25
+ document.head.appendChild(styleElement);
26
+ }
27
+ styleElement.innerHTML = runtime.css;
28
+ document.documentElement.dataset.theme = runtime.theme;
29
+ document.documentElement.dataset.colorMode = runtime.mode;
30
+ document.documentElement.dataset.themeMode = runtime.mode;
31
+ document.documentElement.classList.remove('light', 'dark', 'auto');
32
+ document.documentElement.classList.add(runtime.mode);
33
+ }, [
34
+ themeConfiguration,
35
+ styleElementId
36
+ ]);
37
+ return null;
38
+ };
39
+
40
+ //# sourceMappingURL=ThemeLivePreviewSync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/ThemeLivePreviewSync.tsx"],"sourcesContent":["'use client'\n\nimport { useLivePreview } from '@payloadcms/live-preview-react'\nimport { useEffect, useMemo } from 'react'\nimport {\n buildLivePreviewThemeRuntime,\n extractThemeConfigurationFromLiveData,\n} from '../utils/livePreviewThemeRuntime.js'\n\ninterface ThemeLivePreviewSyncProps {\n initialData: Record<string, unknown>\n serverURL: string\n apiRoute?: string\n depth?: number\n themeConfigurationKey?: string\n styleElementId?: string\n}\n\nexport const ThemeLivePreviewSync: React.FC<ThemeLivePreviewSyncProps> = ({\n initialData,\n serverURL,\n apiRoute,\n depth,\n themeConfigurationKey = 'themeConfiguration',\n styleElementId = 'theme-live-preview-css',\n}) => {\n const { data } = useLivePreview<Record<string, unknown>>({\n apiRoute,\n depth,\n initialData,\n serverURL,\n })\n\n const themeConfiguration = useMemo(\n () => extractThemeConfigurationFromLiveData(data, themeConfigurationKey),\n [data, themeConfigurationKey],\n )\n\n useEffect(() => {\n if (typeof document === 'undefined' || !themeConfiguration) {\n return\n }\n\n const runtime = buildLivePreviewThemeRuntime(themeConfiguration)\n\n let styleElement = document.getElementById(styleElementId) as HTMLStyleElement | null\n if (!styleElement) {\n styleElement = document.createElement('style')\n styleElement.id = styleElementId\n document.head.appendChild(styleElement)\n }\n\n styleElement.innerHTML = runtime.css\n\n document.documentElement.dataset.theme = runtime.theme\n document.documentElement.dataset.colorMode = runtime.mode\n document.documentElement.dataset.themeMode = runtime.mode\n document.documentElement.classList.remove('light', 'dark', 'auto')\n document.documentElement.classList.add(runtime.mode)\n }, [themeConfiguration, styleElementId])\n\n return null\n}\n"],"names":["useLivePreview","useEffect","useMemo","buildLivePreviewThemeRuntime","extractThemeConfigurationFromLiveData","ThemeLivePreviewSync","initialData","serverURL","apiRoute","depth","themeConfigurationKey","styleElementId","data","themeConfiguration","document","runtime","styleElement","getElementById","createElement","id","head","appendChild","innerHTML","css","documentElement","dataset","theme","colorMode","mode","themeMode","classList","remove","add"],"mappings":"AAAA;AAEA,SAASA,cAAc,QAAQ,iCAAgC;AAC/D,SAASC,SAAS,EAAEC,OAAO,QAAQ,QAAO;AAC1C,SACEC,4BAA4B,EAC5BC,qCAAqC,QAChC,sCAAqC;AAW5C,OAAO,MAAMC,uBAA4D,CAAC,EACxEC,WAAW,EACXC,SAAS,EACTC,QAAQ,EACRC,KAAK,EACLC,wBAAwB,oBAAoB,EAC5CC,iBAAiB,wBAAwB,EAC1C;IACC,MAAM,EAAEC,IAAI,EAAE,GAAGZ,eAAwC;QACvDQ;QACAC;QACAH;QACAC;IACF;IAEA,MAAMM,qBAAqBX,QACzB,IAAME,sCAAsCQ,MAAMF,wBAClD;QAACE;QAAMF;KAAsB;IAG/BT,UAAU;QACR,IAAI,OAAOa,aAAa,eAAe,CAACD,oBAAoB;YAC1D;QACF;QAEA,MAAME,UAAUZ,6BAA6BU;QAE7C,IAAIG,eAAeF,SAASG,cAAc,CAACN;QAC3C,IAAI,CAACK,cAAc;YACjBA,eAAeF,SAASI,aAAa,CAAC;YACtCF,aAAaG,EAAE,GAAGR;YAClBG,SAASM,IAAI,CAACC,WAAW,CAACL;QAC5B;QAEAA,aAAaM,SAAS,GAAGP,QAAQQ,GAAG;QAEpCT,SAASU,eAAe,CAACC,OAAO,CAACC,KAAK,GAAGX,QAAQW,KAAK;QACtDZ,SAASU,eAAe,CAACC,OAAO,CAACE,SAAS,GAAGZ,QAAQa,IAAI;QACzDd,SAASU,eAAe,CAACC,OAAO,CAACI,SAAS,GAAGd,QAAQa,IAAI;QACzDd,SAASU,eAAe,CAACM,SAAS,CAACC,MAAM,CAAC,SAAS,QAAQ;QAC3DjB,SAASU,eAAe,CAACM,SAAS,CAACE,GAAG,CAACjB,QAAQa,IAAI;IACrD,GAAG;QAACf;QAAoBF;KAAe;IAEvC,OAAO;AACT,EAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ThemeColorPickerField.d.ts","sourceRoot":"","sources":["../../src/fields/ThemeColorPickerField.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAA;AAmCvD,QAAA,MAAM,qBAAqB,EAAE,wBAsI5B,CAAA;AAED,eAAe,qBAAqB,CAAA"}
1
+ {"version":3,"file":"ThemeColorPickerField.d.ts","sourceRoot":"","sources":["../../src/fields/ThemeColorPickerField.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAA;AAmCvD,QAAA,MAAM,qBAAqB,EAAE,wBAuJ5B,CAAA;AAED,eAAe,qBAAqB,CAAA"}
@@ -35,6 +35,7 @@ const ThemeColorPickerField = ({ field, path })=>{
35
35
  const [localValue, setLocalValue] = useState(value || '');
36
36
  const [showPicker, setShowPicker] = useState(false);
37
37
  const [hexValue, setHexValue] = useState(toHex(value || ''));
38
+ const [isDragging, setIsDragging] = useState(false);
38
39
  const pickerRef = useRef(null);
39
40
  useEffect(()=>{
40
41
  setLocalValue(value || '');
@@ -56,20 +57,30 @@ const ThemeColorPickerField = ({ field, path })=>{
56
57
  }, [
57
58
  showPicker
58
59
  ]);
59
- const handleHexChange = useCallback((hex)=>{
60
- setHexValue(hex);
61
- setLocalValue(hex);
62
- setValue(hex);
60
+ // Only update parent setValue when drag completes
61
+ useEffect(()=>{
62
+ if (!isDragging) {
63
+ setValue(localValue);
64
+ }
63
65
  }, [
66
+ isDragging,
67
+ localValue,
64
68
  setValue
65
69
  ]);
70
+ const handleHexChange = useCallback((hex)=>{
71
+ setHexValue(hex);
72
+ setLocalValue(hex);
73
+ }, []);
66
74
  const handleTextChange = useCallback((nextValue)=>{
67
75
  setLocalValue(nextValue);
68
- setValue(nextValue);
69
76
  setHexValue(toHex(nextValue));
70
- }, [
71
- setValue
72
- ]);
77
+ }, []);
78
+ const handlePickerMouseDown = useCallback(()=>{
79
+ setIsDragging(true);
80
+ }, []);
81
+ const handlePickerMouseUp = useCallback(()=>{
82
+ setIsDragging(false);
83
+ }, []);
73
84
  const fieldName = path.split('.').pop() || '';
74
85
  const label = resolveLocalizedValue(field.label, fieldName);
75
86
  const description = resolveLocalizedValue(field.admin?.description, '');
@@ -117,6 +128,9 @@ const ThemeColorPickerField = ({ field, path })=>{
117
128
  showPicker && /*#__PURE__*/ _jsxs("div", {
118
129
  ref: pickerRef,
119
130
  className: "color-picker-popover",
131
+ onMouseDown: handlePickerMouseDown,
132
+ onMouseUp: handlePickerMouseUp,
133
+ onMouseLeave: handlePickerMouseUp,
120
134
  children: [
121
135
  /*#__PURE__*/ _jsxs("div", {
122
136
  className: "picker-header",
@@ -173,7 +187,10 @@ const ThemeColorPickerField = ({ field, path })=>{
173
187
  '#ffffff'
174
188
  ].map((color)=>/*#__PURE__*/ _jsx("button", {
175
189
  type: "button",
176
- onClick: ()=>handleHexChange(color),
190
+ onClick: ()=>{
191
+ handleHexChange(color);
192
+ setValue(color);
193
+ },
177
194
  className: `swatch-btn ${hexValue.toLowerCase() === color.toLowerCase() ? 'selected' : ''}`,
178
195
  style: {
179
196
  backgroundColor: color
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/fields/ThemeColorPickerField.tsx"],"sourcesContent":["'use client'\n\nimport { useField } from '@payloadcms/ui'\nimport Color from 'color'\nimport type { TextFieldClientComponent } from 'payload'\nimport { HexColorInput, HexColorPicker } from 'react-colorful'\nimport { useCallback, useEffect, useRef, useState } from 'react'\n\n// Import CSS for styling\nif (typeof window !== 'undefined') {\n // @ts-expect-error - Dynamic CSS import\n import('./ThemeColorPickerField.css').catch(() => {})\n}\n\nfunction resolveLocalizedValue(value: unknown, fallback: string) {\n if (typeof value === 'string') {\n return value\n }\n\n if (typeof value === 'object' && value !== null) {\n const localized = value as Record<string, unknown>\n const resolved = localized.en ?? localized.cs ?? localized['']\n if (typeof resolved === 'string') {\n return resolved\n }\n }\n\n return fallback\n}\n\n/**\n * Convert various color formats to HEX for the color picker\n */\nfunction toHex(color: string): string {\n if (!color) return '#000000'\n\n return Color(color).hex().toString()\n}\n\nconst ThemeColorPickerField: TextFieldClientComponent = ({ field, path }) => {\n const { value, setValue } = useField<string>({ path })\n const [localValue, setLocalValue] = useState(value || '')\n const [showPicker, setShowPicker] = useState(false)\n const [hexValue, setHexValue] = useState(toHex(value || ''))\n const pickerRef = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n setLocalValue(value || '')\n setHexValue(toHex(value || ''))\n }, [value])\n\n // Close picker when clicking outside\n useEffect(() => {\n function handleClickOutside(event: MouseEvent) {\n if (pickerRef.current && !pickerRef.current.contains(event.target as Node)) {\n setShowPicker(false)\n }\n }\n\n if (showPicker) {\n document.addEventListener('mousedown', handleClickOutside)\n return () => document.removeEventListener('mousedown', handleClickOutside)\n }\n }, [showPicker])\n\n const handleHexChange = useCallback(\n (hex: string) => {\n setHexValue(hex)\n setLocalValue(hex)\n setValue(hex)\n },\n [setValue],\n )\n\n const handleTextChange = useCallback(\n (nextValue: string) => {\n setLocalValue(nextValue)\n setValue(nextValue)\n setHexValue(toHex(nextValue))\n },\n [setValue],\n )\n\n const fieldName = path.split('.').pop() || ''\n const label = resolveLocalizedValue(field.label, fieldName)\n const description = resolveLocalizedValue(field.admin?.description, '')\n\n return (\n <div className=\"theme-color-picker-field\">\n <div className=\"field-header\">\n <label className=\"field-label\">{label}</label>\n {description && <div className=\"field-description\">{description}</div>}\n </div>\n\n <div className=\"color-picker-container\">\n <div className=\"color-input-row\">\n <button\n type=\"button\"\n className=\"color-swatch-btn\"\n style={{ backgroundColor: hexValue }}\n onClick={() => setShowPicker(!showPicker)}\n aria-label=\"Open color picker\"\n title={hexValue}\n />\n <input\n type=\"text\"\n value={localValue || ''}\n onChange={(event) => handleTextChange(event.target.value)}\n placeholder=\"oklch(...) or #hex\"\n className=\"color-text-input\"\n />\n </div>\n\n {showPicker && (\n <div ref={pickerRef} className=\"color-picker-popover\">\n <div className=\"picker-header\">\n <span className=\"picker-title\">Color Picker</span>\n <button\n type=\"button\"\n onClick={() => setShowPicker(false)}\n className=\"picker-close-btn\"\n aria-label=\"Close\"\n >\n ✕\n </button>\n </div>\n\n <HexColorPicker color={hexValue} onChange={handleHexChange} className=\"hex-picker\" />\n\n <div className=\"hex-input-row\">\n <HexColorInput\n color={hexValue}\n onChange={handleHexChange}\n prefixed\n placeholder=\"#000000\"\n className=\"hex-input\"\n />\n </div>\n\n <div className=\"color-swatches\">\n <div className=\"swatches-label\">Quick Colors</div>\n <div className=\"swatches-grid\">\n {[\n '#ef4444',\n '#f97316',\n '#f59e0b',\n '#84cc16',\n '#10b981',\n '#06b6d4',\n '#3b82f6',\n '#8b5cf6',\n '#ec4899',\n '#64748b',\n '#000000',\n '#ffffff',\n ].map((color) => (\n <button\n key={color}\n type=\"button\"\n onClick={() => handleHexChange(color)}\n className={`swatch-btn ${hexValue.toLowerCase() === color.toLowerCase() ? 'selected' : ''}`}\n style={{ backgroundColor: color }}\n aria-label={`Select ${color}`}\n title={color}\n />\n ))}\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n )\n}\n\nexport default ThemeColorPickerField\n"],"names":["useField","Color","HexColorInput","HexColorPicker","useCallback","useEffect","useRef","useState","window","catch","resolveLocalizedValue","value","fallback","localized","resolved","en","cs","toHex","color","hex","toString","ThemeColorPickerField","field","path","setValue","localValue","setLocalValue","showPicker","setShowPicker","hexValue","setHexValue","pickerRef","handleClickOutside","event","current","contains","target","document","addEventListener","removeEventListener","handleHexChange","handleTextChange","nextValue","fieldName","split","pop","label","description","admin","div","className","button","type","style","backgroundColor","onClick","aria-label","title","input","onChange","placeholder","ref","span","prefixed","map","toLowerCase"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/fields/ThemeColorPickerField.tsx"],"sourcesContent":["'use client'\n\nimport { useField } from '@payloadcms/ui'\nimport Color from 'color'\nimport type { TextFieldClientComponent } from 'payload'\nimport { HexColorInput, HexColorPicker } from 'react-colorful'\nimport { useCallback, useEffect, useRef, useState } from 'react'\n\n// Import CSS for styling\nif (typeof window !== 'undefined') {\n // @ts-expect-error - Dynamic CSS import\n import('./ThemeColorPickerField.css').catch(() => {})\n}\n\nfunction resolveLocalizedValue(value: unknown, fallback: string) {\n if (typeof value === 'string') {\n return value\n }\n\n if (typeof value === 'object' && value !== null) {\n const localized = value as Record<string, unknown>\n const resolved = localized.en ?? localized.cs ?? localized['']\n if (typeof resolved === 'string') {\n return resolved\n }\n }\n\n return fallback\n}\n\n/**\n * Convert various color formats to HEX for the color picker\n */\nfunction toHex(color: string): string {\n if (!color) return '#000000'\n\n return Color(color).hex().toString()\n}\n\nconst ThemeColorPickerField: TextFieldClientComponent = ({ field, path }) => {\n const { value, setValue } = useField<string>({ path })\n const [localValue, setLocalValue] = useState(value || '')\n const [showPicker, setShowPicker] = useState(false)\n const [hexValue, setHexValue] = useState(toHex(value || ''))\n const [isDragging, setIsDragging] = useState(false)\n const pickerRef = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n setLocalValue(value || '')\n setHexValue(toHex(value || ''))\n }, [value])\n\n // Close picker when clicking outside\n useEffect(() => {\n function handleClickOutside(event: MouseEvent) {\n if (pickerRef.current && !pickerRef.current.contains(event.target as Node)) {\n setShowPicker(false)\n }\n }\n\n if (showPicker) {\n document.addEventListener('mousedown', handleClickOutside)\n return () => document.removeEventListener('mousedown', handleClickOutside)\n }\n }, [showPicker])\n\n // Only update parent setValue when drag completes\n useEffect(() => {\n if (!isDragging) {\n setValue(localValue)\n }\n }, [isDragging, localValue, setValue])\n\n const handleHexChange = useCallback((hex: string) => {\n setHexValue(hex)\n setLocalValue(hex)\n }, [])\n\n const handleTextChange = useCallback((nextValue: string) => {\n setLocalValue(nextValue)\n setHexValue(toHex(nextValue))\n }, [])\n\n const handlePickerMouseDown = useCallback(() => {\n setIsDragging(true)\n }, [])\n\n const handlePickerMouseUp = useCallback(() => {\n setIsDragging(false)\n }, [])\n\n const fieldName = path.split('.').pop() || ''\n const label = resolveLocalizedValue(field.label, fieldName)\n const description = resolveLocalizedValue(field.admin?.description, '')\n\n return (\n <div className=\"theme-color-picker-field\">\n <div className=\"field-header\">\n <label className=\"field-label\">{label}</label>\n {description && <div className=\"field-description\">{description}</div>}\n </div>\n\n <div className=\"color-picker-container\">\n <div className=\"color-input-row\">\n <button\n type=\"button\"\n className=\"color-swatch-btn\"\n style={{ backgroundColor: hexValue }}\n onClick={() => setShowPicker(!showPicker)}\n aria-label=\"Open color picker\"\n title={hexValue}\n />\n <input\n type=\"text\"\n value={localValue || ''}\n onChange={(event) => handleTextChange(event.target.value)}\n placeholder=\"oklch(...) or #hex\"\n className=\"color-text-input\"\n />\n </div>\n\n {showPicker && (\n <div\n ref={pickerRef}\n className=\"color-picker-popover\"\n onMouseDown={handlePickerMouseDown}\n onMouseUp={handlePickerMouseUp}\n onMouseLeave={handlePickerMouseUp}\n >\n <div className=\"picker-header\">\n <span className=\"picker-title\">Color Picker</span>\n <button\n type=\"button\"\n onClick={() => setShowPicker(false)}\n className=\"picker-close-btn\"\n aria-label=\"Close\"\n >\n ✕\n </button>\n </div>\n\n <HexColorPicker color={hexValue} onChange={handleHexChange} className=\"hex-picker\" />\n\n <div className=\"hex-input-row\">\n <HexColorInput\n color={hexValue}\n onChange={handleHexChange}\n prefixed\n placeholder=\"#000000\"\n className=\"hex-input\"\n />\n </div>\n\n <div className=\"color-swatches\">\n <div className=\"swatches-label\">Quick Colors</div>\n <div className=\"swatches-grid\">\n {[\n '#ef4444',\n '#f97316',\n '#f59e0b',\n '#84cc16',\n '#10b981',\n '#06b6d4',\n '#3b82f6',\n '#8b5cf6',\n '#ec4899',\n '#64748b',\n '#000000',\n '#ffffff',\n ].map((color) => (\n <button\n key={color}\n type=\"button\"\n onClick={() => {\n handleHexChange(color)\n setValue(color)\n }}\n className={`swatch-btn ${hexValue.toLowerCase() === color.toLowerCase() ? 'selected' : ''}`}\n style={{ backgroundColor: color }}\n aria-label={`Select ${color}`}\n title={color}\n />\n ))}\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n )\n}\n\nexport default ThemeColorPickerField\n"],"names":["useField","Color","HexColorInput","HexColorPicker","useCallback","useEffect","useRef","useState","window","catch","resolveLocalizedValue","value","fallback","localized","resolved","en","cs","toHex","color","hex","toString","ThemeColorPickerField","field","path","setValue","localValue","setLocalValue","showPicker","setShowPicker","hexValue","setHexValue","isDragging","setIsDragging","pickerRef","handleClickOutside","event","current","contains","target","document","addEventListener","removeEventListener","handleHexChange","handleTextChange","nextValue","handlePickerMouseDown","handlePickerMouseUp","fieldName","split","pop","label","description","admin","div","className","button","type","style","backgroundColor","onClick","aria-label","title","input","onChange","placeholder","ref","onMouseDown","onMouseUp","onMouseLeave","span","prefixed","map","toLowerCase"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ThemePreviewField.d.ts","sourceRoot":"","sources":["../../src/fields/ThemePreviewField.tsx"],"names":[],"mappings":"AAEA,OAAO,yBAAyB,CAAA;AAEhC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAA;AAwPrD,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,+BAqatE"}
1
+ {"version":3,"file":"ThemePreviewField.d.ts","sourceRoot":"","sources":["../../src/fields/ThemePreviewField.tsx"],"names":[],"mappings":"AAEA,OAAO,yBAAyB,CAAA;AAEhC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAA;AAwPrD,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,+BA0atE"}
@@ -220,6 +220,7 @@ function ModePreview({ icon, title, colors, typography, radius }) {
220
220
  }
221
221
  export default function ThemePreviewField(props) {
222
222
  const { field, path } = props;
223
+ const showPreviewPanel = field?.admin?.custom?.useThemePreviewField ?? true;
223
224
  // If the plugin provided theme presets via admin config, prefer those;
224
225
  // support both `field.admin.themePresets` (legacy) and `field.admin.custom.themePresets`
225
226
  // otherwise fallback to `allThemePresets`.
@@ -575,7 +576,7 @@ export default function ThemePreviewField(props) {
575
576
  })
576
577
  ]
577
578
  }),
578
- /*#__PURE__*/ _jsx("div", {
579
+ showPreviewPanel && /*#__PURE__*/ _jsx("div", {
579
580
  style: {
580
581
  flex: '1 1 420px',
581
582
  minWidth: '320px',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/fields/ThemePreviewField.tsx"],"sourcesContent":["'use client'\n\nimport './ThemePreviewField.css'\nimport { useField, useForm, useFormFields } from '@payloadcms/ui'\nimport type { SelectFieldClientProps } from 'payload'\nimport { useCallback, useEffect, useMemo, useRef } from 'react'\nimport type {\n ResolvedTypographyPreview,\n TypographySelection,\n} from '../components/typographyPreviewUtils.js'\nimport { resolveTypographyPreview } from '../components/typographyPreviewUtils.js'\nimport { allThemePresets } from '../index.js'\nimport type { ThemePreset, ThemeTypographyPreset } from '../presets.js'\nimport { borderRadiusPresets } from '../providers/Theme/themeConfig.js'\nimport { getTranslations } from '../translations.js'\nimport { getAdminLanguage } from '../utils/getAdminLanguage.js'\nimport { darkModeDefaults, lightModeDefaults } from './colorModeFields.js'\n\ninterface ColorModeColors {\n background?: string\n foreground?: string\n card?: string\n cardForeground?: string\n popover?: string\n popoverForeground?: string\n primary?: string\n primaryForeground?: string\n secondary?: string\n secondaryForeground?: string\n muted?: string\n mutedForeground?: string\n accent?: string\n accentForeground?: string\n destructive?: string\n destructiveForeground?: string\n border?: string\n input?: string\n ring?: string\n}\n\ninterface ThemePresetDefinition {\n label: string\n lightMode: ColorModeColors\n darkMode: ColorModeColors\n typography?: ThemeTypographyPreset\n borderRadius: 'none' | 'small' | 'medium' | 'large' | 'xl'\n}\n\n// FALLBACK_THEME and runtime theme presets are computed inside the component\n\nconst colorKeys = Object.keys(lightModeDefaults) as (keyof ColorModeColors)[]\n\n// translations and swatches will be computed inside the component to respect admin language at runtime\n\ninterface ModePreviewProps {\n icon: string\n title: string\n colors: ColorModeColors\n typography: ResolvedTypographyPreview\n radius: {\n card: string\n chip: string\n pill: string\n }\n}\n\nfunction ModePreview({ icon, title, colors, typography, radius }: Readonly<ModePreviewProps>) {\n const t = getTranslations(getAdminLanguage())\n const background = colors.background ?? '#ffffff'\n const foreground = colors.foreground ?? '#0a0a0a'\n const borderColor = colors.border ?? 'rgba(148, 163, 184, 0.35)'\n const cardBackground = colors.card ?? background\n const cardForeground = colors.cardForeground ?? foreground\n const primary = colors.primary ?? foreground\n const primaryForeground = colors.primaryForeground ?? background\n const secondary = colors.secondary ?? '#f4f4f5'\n const secondaryForeground = colors.secondaryForeground ?? foreground\n const muted = colors.muted ?? secondary\n const mutedForeground = colors.mutedForeground ?? secondaryForeground\n const accent = colors.accent ?? secondary\n const accentForeground = colors.accentForeground ?? secondaryForeground\n const headingFont = typography.headingFont\n const bodyFont = typography.bodyFont\n const baseFontSize = typography.baseFontSize\n const lineHeight = typography.lineHeight\n\n return (\n <div\n style={{\n display: 'grid',\n gap: '16px',\n padding: '18px',\n borderRadius: '12px',\n backgroundColor: background,\n color: foreground,\n border: `1px solid ${borderColor}`,\n boxShadow: '0 8px 20px rgba(15, 23, 42, 0.08)',\n fontFamily: bodyFont,\n }}\n >\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n fontSize: '12px',\n fontWeight: 600,\n letterSpacing: '0.08em',\n textTransform: 'uppercase',\n opacity: 0.7,\n }}\n >\n <span>\n {icon} {title}\n </span>\n <span style={{ fontFamily: 'monospace', fontSize: '11px' }}>\n {background.toUpperCase()}\n </span>\n </div>\n\n <div\n style={{\n backgroundColor: cardBackground,\n color: cardForeground,\n borderRadius: radius.card,\n border: `1px solid ${borderColor}`,\n padding: '16px',\n display: 'flex',\n gap: '12px',\n flexWrap: 'wrap',\n }}\n >\n <button\n type=\"button\"\n style={{\n padding: '10px 18px',\n borderRadius: radius.pill,\n border: 'none',\n cursor: 'pointer',\n fontSize: '12px',\n fontWeight: 600,\n letterSpacing: '0.02em',\n backgroundColor: primary,\n color: primaryForeground,\n boxShadow: '0 6px 14px rgba(15, 23, 42, 0.15)',\n }}\n >\n {t.ui.primaryAction}\n </button>\n <button\n type=\"button\"\n style={{\n padding: '10px 18px',\n borderRadius: radius.chip,\n border: '1px solid transparent',\n cursor: 'pointer',\n fontSize: '12px',\n fontWeight: 600,\n letterSpacing: '0.02em',\n backgroundColor: secondary,\n color: secondaryForeground,\n boxShadow: 'inset 0 0 0 1px rgba(15, 23, 42, 0.08)',\n }}\n >\n {t.ui.secondaryAction}\n </button>\n </div>\n\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(auto-fit, minmax(120px, 1fr))',\n gap: '10px',\n }}\n >\n <div\n style={{\n borderRadius: radius.chip,\n padding: '10px 12px',\n fontSize: '12px',\n fontWeight: 500,\n backgroundColor: muted,\n color: mutedForeground,\n }}\n >\n Muted Card\n </div>\n <div\n style={{\n borderRadius: radius.chip,\n padding: '10px 12px',\n fontSize: '12px',\n fontWeight: 500,\n backgroundColor: accent,\n color: accentForeground,\n }}\n >\n Accent Tag\n </div>\n </div>\n\n <div\n style={{\n display: 'grid',\n gap: '8px',\n borderRadius: '10px',\n border: `1px dashed ${borderColor}`,\n padding: '14px',\n backgroundColor: 'rgba(148, 163, 184, 0.08)',\n }}\n >\n <div\n style={{\n fontFamily: headingFont,\n fontSize: 'clamp(24px, 3vw, 32px)',\n fontWeight: 600,\n lineHeight: 1.2,\n }}\n >\n Nadpis / Heading preview\n </div>\n <p\n style={{\n margin: 0,\n fontFamily: bodyFont,\n fontSize: baseFontSize,\n lineHeight,\n color: foreground,\n opacity: 0.85,\n }}\n >\n Sphinx of black quartz, judge my vow. Příliš žluťoučký kůň úpěl ďábelské ódy.\n </p>\n <div\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: '10px',\n fontSize: '11px',\n color: 'rgba(15, 23, 42, 0.7)',\n }}\n >\n <span>Body: {typography.bodyLabel}</span>\n <span>Heading: {typography.headingLabel}</span>\n <span>Base size: {baseFontSize}</span>\n <span>Line height: {lineHeight}</span>\n </div>\n </div>\n </div>\n )\n}\n\nexport default function ThemePreviewField(props: SelectFieldClientProps) {\n const { field, path } = props\n // If the plugin provided theme presets via admin config, prefer those;\n // support both `field.admin.themePresets` (legacy) and `field.admin.custom.themePresets`\n // otherwise fallback to `allThemePresets`.\n // Prefer presets passed via `admin.custom.themePresets` (set by the field factory / plugin).\n // Fall back to legacy `admin.themePresets` for backwards compatibility, then to `allThemePresets`.\n const baseThemePresets =\n (field?.admin?.custom as unknown as { themePresets?: ThemePreset[] })?.themePresets ??\n (field?.admin as unknown as { themePresets?: ThemePreset[] })?.themePresets ??\n allThemePresets\n const runtimeThemePresets = useMemo(() => {\n return (baseThemePresets as ThemePreset[]).reduce<Record<string, ThemePresetDefinition>>(\n (acc, preset) => {\n acc[preset.name] = {\n label: preset.label,\n lightMode: { ...lightModeDefaults, ...(preset.lightMode ?? {}) },\n darkMode: { ...darkModeDefaults, ...(preset.darkMode ?? {}) },\n typography: preset.typography,\n borderRadius: preset.borderRadius,\n }\n return acc\n },\n {},\n )\n }, [baseThemePresets])\n const fallbackTheme = baseThemePresets[0]?.name ?? 'cool'\n const { value: selectedTheme, setValue } = useField<string>({ path })\n const { dispatchFields } = useForm()\n const formFields = useFormFields(([formState]: any) => formState)\n const hasAppliedInitialPresetRef = useRef(false)\n\n const applyPreset = useCallback(\n (presetName: string) => {\n const preset = runtimeThemePresets[presetName]\n if (!preset) {\n return\n }\n\n colorKeys.forEach((key) => {\n const lightValue = preset.lightMode[key]\n const darkValue = preset.darkMode[key]\n\n if (lightValue) {\n dispatchFields({\n type: 'UPDATE',\n path: `themeConfiguration.lightMode.${key}`,\n value: lightValue,\n })\n }\n\n if (darkValue) {\n dispatchFields({\n type: 'UPDATE',\n path: `themeConfiguration.darkMode.${key}`,\n value: darkValue,\n })\n }\n })\n },\n [dispatchFields],\n )\n\n const handleThemeSelect = useCallback(\n (value: string) => {\n setValue(value)\n\n if (!value) {\n return\n }\n\n hasAppliedInitialPresetRef.current = true\n applyPreset(value)\n },\n [applyPreset, setValue],\n )\n\n useEffect(() => {\n if (!selectedTheme) {\n return\n }\n\n if (runtimeThemePresets[selectedTheme]) {\n return\n }\n\n hasAppliedInitialPresetRef.current = false\n setValue(fallbackTheme)\n }, [selectedTheme, setValue])\n\n useEffect(() => {\n if (hasAppliedInitialPresetRef.current) {\n return\n }\n\n if (!selectedTheme) {\n return\n }\n\n if (!formFields) {\n return\n }\n\n const preset = runtimeThemePresets[selectedTheme]\n if (!preset) {\n hasAppliedInitialPresetRef.current = true\n return\n }\n\n const hasExistingValues = colorKeys.some((key) => {\n const lightField = formFields[`themeConfiguration.lightMode.${key}`]\n const darkField = formFields[`themeConfiguration.darkMode.${key}`]\n\n const lightValue = typeof lightField?.value === 'string' && lightField.value.trim().length > 0\n const darkValue = typeof darkField?.value === 'string' && darkField.value.trim().length > 0\n\n return lightValue || darkValue\n })\n\n if (hasExistingValues) {\n hasAppliedInitialPresetRef.current = true\n return\n }\n\n applyPreset(selectedTheme)\n hasAppliedInitialPresetRef.current = true\n }, [selectedTheme, formFields, applyPreset])\n\n const lightModeColors = useMemo(() => {\n const presetLightMode = selectedTheme\n ? runtimeThemePresets[selectedTheme]?.lightMode\n : undefined\n\n return colorKeys.reduce<ColorModeColors>((acc, key) => {\n const fieldState = formFields?.[`themeConfiguration.lightMode.${key}`]\n const rawValue =\n typeof fieldState?.value === 'string' && fieldState.value.trim().length > 0\n ? fieldState.value\n : undefined\n\n acc[key] = rawValue ?? presetLightMode?.[key] ?? lightModeDefaults[key]\n return acc\n }, {} as ColorModeColors)\n }, [formFields, selectedTheme])\n\n const darkModeColors = useMemo(() => {\n const presetDarkMode = selectedTheme ? runtimeThemePresets[selectedTheme]?.darkMode : undefined\n\n return colorKeys.reduce<ColorModeColors>((acc, key) => {\n const fieldState = formFields?.[`themeConfiguration.darkMode.${key}`]\n const rawValue =\n typeof fieldState?.value === 'string' && fieldState.value.trim().length > 0\n ? fieldState.value\n : undefined\n\n acc[key] = rawValue ?? presetDarkMode?.[key] ?? darkModeDefaults[key]\n return acc\n }, {} as ColorModeColors)\n }, [formFields, selectedTheme])\n\n const activePreset = selectedTheme ? runtimeThemePresets[selectedTheme] : undefined\n const formTypographySelection = useMemo<TypographySelection | null>(() => {\n if (!formFields) {\n return null\n }\n\n const getValue = (key: string) => formFields[`themeConfiguration.typography.${key}`]?.value\n\n return {\n bodyFont: (getValue('bodyFont') as string | undefined) ?? undefined,\n headingFont: (getValue('headingFont') as string | undefined) ?? undefined,\n bodyFontCustom: (getValue('bodyFontCustom') as string | undefined) ?? undefined,\n headingFontCustom: (getValue('headingFontCustom') as string | undefined) ?? undefined,\n baseFontSize: (getValue('baseFontSize') as string | undefined) ?? undefined,\n lineHeight: (getValue('lineHeight') as string | undefined) ?? undefined,\n }\n }, [formFields])\n\n const previewTypography = useMemo<ResolvedTypographyPreview>(() => {\n return resolveTypographyPreview(formTypographySelection, selectedTheme)\n }, [formTypographySelection, selectedTheme])\n\n const borderRadiusValue = formFields?.['themeConfiguration.borderRadius']?.value\n const presetRadius = activePreset?.borderRadius ?? 'medium'\n const resolvedBorderRadius = (\n typeof borderRadiusValue === 'string' && borderRadiusValue.length\n ? borderRadiusValue\n : presetRadius\n ) as keyof typeof borderRadiusPresets\n const borderRadiusPreset = borderRadiusPresets[resolvedBorderRadius] ?? borderRadiusPresets.medium\n const borderRadiusCSS =\n typeof borderRadiusPreset.css === 'string'\n ? { '--radius-default': borderRadiusPreset.css }\n : (borderRadiusPreset.css as Record<string, string>)\n const previewRadius = {\n card: borderRadiusCSS['--radius-large'] ?? '1rem',\n chip: borderRadiusCSS['--radius-default'] ?? '0.75rem',\n pill: borderRadiusCSS['--radius-xl'] ?? borderRadiusCSS['--radius-large'] ?? '999px',\n }\n\n // Translate labels at runtime based on admin language\n const t = getTranslations(getAdminLanguage())\n // Explicitly type keys as `keyof ColorModeColors` to satisfy TypeScript when indexing `lightMode`/`darkMode`\n const highlightSwatches: { key: keyof ColorModeColors; label: string }[] = [\n { key: 'primary', label: t.colors.primary },\n { key: 'secondary', label: t.colors.secondary },\n { key: 'accent', label: t.colors.accent },\n { key: 'background', label: t.colors.background },\n { key: 'foreground', label: t.colors.foreground },\n ]\n\n const fieldLabel =\n typeof field.label === 'string' ? field.label : field.label?.en || field.label?.cs || 'Theme'\n\n return (\n <div style={{ marginBottom: '24px' }}>\n <label\n style={{\n display: 'block',\n marginBottom: '10px',\n fontSize: '13px',\n fontWeight: 600,\n color: 'var(--theme-elevation-800)',\n }}\n >\n {fieldLabel}\n </label>\n\n <div\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: '24px',\n alignItems: 'flex-start',\n }}\n >\n <div\n style={{\n flex: '0 0 320px',\n minWidth: '260px',\n maxWidth: '420px',\n display: 'grid',\n gap: '12px',\n }}\n >\n <div className=\"theme-preset-list\">\n {Object.entries(runtimeThemePresets).map(([key, preset]) => {\n const isSelected = key === selectedTheme\n const swatches = highlightSwatches\n .map(({ key: colorKey }) => preset.lightMode[colorKey] as string | undefined)\n .filter((v): v is string => typeof v === 'string' && v.trim().length > 0)\n\n return (\n <button\n key={key}\n type=\"button\"\n onClick={() => handleThemeSelect(key)}\n className={`theme-preset-button ${isSelected ? 'selected' : ''}`}\n >\n <div className=\"theme-info\">\n <span className=\"theme-label\">{preset.label}</span>\n <span className=\"theme-name\">{key}</span>\n </div>\n <div className=\"theme-swatches\" aria-hidden=\"true\">\n {swatches.map((color, index) => (\n <span\n key={`${key}-swatch-${color}-${index}`}\n className=\"color-swatch\"\n style={{ backgroundColor: color }}\n />\n ))}\n </div>\n </button>\n )\n })}\n </div>\n\n {activePreset && (\n <div\n style={{\n padding: '12px',\n borderRadius: '10px',\n border: '1px solid var(--theme-elevation-200)',\n backgroundColor: 'var(--theme-elevation-50)',\n display: 'grid',\n gap: '8px',\n fontSize: '12px',\n color: 'var(--theme-elevation-600)',\n }}\n >\n <div style={{ fontWeight: 600, color: 'var(--theme-elevation-800)' }}>\n {activePreset.label}\n </div>\n <div>Primary color: {activePreset.lightMode.primary}</div>\n <div>Accent color: {activePreset.lightMode.accent}</div>\n <div\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: '12px',\n marginTop: '4px',\n }}\n >\n {highlightSwatches.map(({ key, label }) => {\n const swatchValue = activePreset.lightMode[key]\n\n if (!swatchValue) {\n return null\n }\n\n return (\n <div\n key={key}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n minWidth: 'fit-content',\n }}\n >\n <span\n style={{\n width: '22px',\n height: '22px',\n borderRadius: '999px',\n border: '1px solid rgba(15, 23, 42, 0.12)',\n backgroundColor: swatchValue,\n boxShadow: 'inset 0 1px 2px rgba(15, 23, 42, 0.08)',\n }}\n aria-hidden=\"true\"\n />\n <span style={{ fontSize: '11px', color: 'var(--theme-elevation-700)' }}>\n {label}\n </span>\n </div>\n )\n })}\n </div>\n </div>\n )}\n\n {field.admin?.description && (\n <div\n style={{\n fontSize: '12px',\n color: 'var(--theme-elevation-600)',\n lineHeight: 1.5,\n }}\n >\n {typeof field.admin.description === 'string'\n ? field.admin.description\n : field.admin.description?.en || field.admin.description?.cs || ''}\n </div>\n )}\n </div>\n\n <div\n style={{\n flex: '1 1 420px',\n minWidth: '320px',\n position: 'sticky',\n top: '96px',\n alignSelf: 'flex-start',\n }}\n >\n <div\n style={{\n width: '100%',\n borderRadius: '16px',\n border: '1px solid var(--theme-elevation-200)',\n backgroundColor: 'var(--theme-elevation-25)',\n padding: '20px',\n display: 'grid',\n gap: '18px',\n maxHeight: 'calc(100vh - 140px)',\n overflowY: 'auto',\n }}\n >\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n fontWeight: 600,\n fontSize: '13px',\n color: 'var(--theme-elevation-800)',\n }}\n >\n {/* safe translations for preview header */}\n <span>{getTranslations('en').livePreview.smallTitle}</span>\n <span style={{ fontSize: '12px', color: 'var(--theme-elevation-600)' }}>\n {activePreset ? activePreset.label : getTranslations('en').preview.customPalette}\n </span>\n </div>\n\n <div\n style={{\n display: 'grid',\n gap: '16px',\n }}\n >\n <ModePreview\n icon=\"☀️\"\n title={getTranslations('en').ui.lightMode}\n colors={lightModeColors}\n typography={previewTypography}\n radius={previewRadius}\n />\n <ModePreview\n icon=\"🌙\"\n title={getTranslations('en').ui.darkMode}\n colors={darkModeColors}\n typography={previewTypography}\n radius={previewRadius}\n />\n </div>\n </div>\n </div>\n </div>\n </div>\n )\n}\n"],"names":["useField","useForm","useFormFields","useCallback","useEffect","useMemo","useRef","resolveTypographyPreview","allThemePresets","borderRadiusPresets","getTranslations","getAdminLanguage","darkModeDefaults","lightModeDefaults","colorKeys","Object","keys","ModePreview","icon","title","colors","typography","radius","t","background","foreground","borderColor","border","cardBackground","card","cardForeground","primary","primaryForeground","secondary","secondaryForeground","muted","mutedForeground","accent","accentForeground","headingFont","bodyFont","baseFontSize","lineHeight","div","style","display","gap","padding","borderRadius","backgroundColor","color","boxShadow","fontFamily","alignItems","justifyContent","fontSize","fontWeight","letterSpacing","textTransform","opacity","span","toUpperCase","flexWrap","button","type","pill","cursor","ui","primaryAction","chip","secondaryAction","gridTemplateColumns","p","margin","bodyLabel","headingLabel","ThemePreviewField","props","field","path","baseThemePresets","admin","custom","themePresets","runtimeThemePresets","reduce","acc","preset","name","label","lightMode","darkMode","fallbackTheme","value","selectedTheme","setValue","dispatchFields","formFields","formState","hasAppliedInitialPresetRef","applyPreset","presetName","forEach","key","lightValue","darkValue","handleThemeSelect","current","hasExistingValues","some","lightField","darkField","trim","length","lightModeColors","presetLightMode","undefined","fieldState","rawValue","darkModeColors","presetDarkMode","activePreset","formTypographySelection","getValue","bodyFontCustom","headingFontCustom","previewTypography","borderRadiusValue","presetRadius","resolvedBorderRadius","borderRadiusPreset","medium","borderRadiusCSS","css","previewRadius","highlightSwatches","fieldLabel","en","cs","marginBottom","flex","minWidth","maxWidth","className","entries","map","isSelected","swatches","colorKey","filter","v","onClick","aria-hidden","index","marginTop","swatchValue","width","height","description","position","top","alignSelf","maxHeight","overflowY","livePreview","smallTitle","preview","customPalette"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/fields/ThemePreviewField.tsx"],"sourcesContent":["'use client'\n\nimport './ThemePreviewField.css'\nimport { useField, useForm, useFormFields } from '@payloadcms/ui'\nimport type { SelectFieldClientProps } from 'payload'\nimport { useCallback, useEffect, useMemo, useRef } from 'react'\nimport type {\n ResolvedTypographyPreview,\n TypographySelection,\n} from '../components/typographyPreviewUtils.js'\nimport { resolveTypographyPreview } from '../components/typographyPreviewUtils.js'\nimport { allThemePresets } from '../index.js'\nimport type { ThemePreset, ThemeTypographyPreset } from '../presets.js'\nimport { borderRadiusPresets } from '../providers/Theme/themeConfig.js'\nimport { getTranslations } from '../translations.js'\nimport { getAdminLanguage } from '../utils/getAdminLanguage.js'\nimport { darkModeDefaults, lightModeDefaults } from './colorModeFields.js'\n\ninterface ColorModeColors {\n background?: string\n foreground?: string\n card?: string\n cardForeground?: string\n popover?: string\n popoverForeground?: string\n primary?: string\n primaryForeground?: string\n secondary?: string\n secondaryForeground?: string\n muted?: string\n mutedForeground?: string\n accent?: string\n accentForeground?: string\n destructive?: string\n destructiveForeground?: string\n border?: string\n input?: string\n ring?: string\n}\n\ninterface ThemePresetDefinition {\n label: string\n lightMode: ColorModeColors\n darkMode: ColorModeColors\n typography?: ThemeTypographyPreset\n borderRadius: 'none' | 'small' | 'medium' | 'large' | 'xl'\n}\n\n// FALLBACK_THEME and runtime theme presets are computed inside the component\n\nconst colorKeys = Object.keys(lightModeDefaults) as (keyof ColorModeColors)[]\n\n// translations and swatches will be computed inside the component to respect admin language at runtime\n\ninterface ModePreviewProps {\n icon: string\n title: string\n colors: ColorModeColors\n typography: ResolvedTypographyPreview\n radius: {\n card: string\n chip: string\n pill: string\n }\n}\n\nfunction ModePreview({ icon, title, colors, typography, radius }: Readonly<ModePreviewProps>) {\n const t = getTranslations(getAdminLanguage())\n const background = colors.background ?? '#ffffff'\n const foreground = colors.foreground ?? '#0a0a0a'\n const borderColor = colors.border ?? 'rgba(148, 163, 184, 0.35)'\n const cardBackground = colors.card ?? background\n const cardForeground = colors.cardForeground ?? foreground\n const primary = colors.primary ?? foreground\n const primaryForeground = colors.primaryForeground ?? background\n const secondary = colors.secondary ?? '#f4f4f5'\n const secondaryForeground = colors.secondaryForeground ?? foreground\n const muted = colors.muted ?? secondary\n const mutedForeground = colors.mutedForeground ?? secondaryForeground\n const accent = colors.accent ?? secondary\n const accentForeground = colors.accentForeground ?? secondaryForeground\n const headingFont = typography.headingFont\n const bodyFont = typography.bodyFont\n const baseFontSize = typography.baseFontSize\n const lineHeight = typography.lineHeight\n\n return (\n <div\n style={{\n display: 'grid',\n gap: '16px',\n padding: '18px',\n borderRadius: '12px',\n backgroundColor: background,\n color: foreground,\n border: `1px solid ${borderColor}`,\n boxShadow: '0 8px 20px rgba(15, 23, 42, 0.08)',\n fontFamily: bodyFont,\n }}\n >\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n fontSize: '12px',\n fontWeight: 600,\n letterSpacing: '0.08em',\n textTransform: 'uppercase',\n opacity: 0.7,\n }}\n >\n <span>\n {icon} {title}\n </span>\n <span style={{ fontFamily: 'monospace', fontSize: '11px' }}>\n {background.toUpperCase()}\n </span>\n </div>\n\n <div\n style={{\n backgroundColor: cardBackground,\n color: cardForeground,\n borderRadius: radius.card,\n border: `1px solid ${borderColor}`,\n padding: '16px',\n display: 'flex',\n gap: '12px',\n flexWrap: 'wrap',\n }}\n >\n <button\n type=\"button\"\n style={{\n padding: '10px 18px',\n borderRadius: radius.pill,\n border: 'none',\n cursor: 'pointer',\n fontSize: '12px',\n fontWeight: 600,\n letterSpacing: '0.02em',\n backgroundColor: primary,\n color: primaryForeground,\n boxShadow: '0 6px 14px rgba(15, 23, 42, 0.15)',\n }}\n >\n {t.ui.primaryAction}\n </button>\n <button\n type=\"button\"\n style={{\n padding: '10px 18px',\n borderRadius: radius.chip,\n border: '1px solid transparent',\n cursor: 'pointer',\n fontSize: '12px',\n fontWeight: 600,\n letterSpacing: '0.02em',\n backgroundColor: secondary,\n color: secondaryForeground,\n boxShadow: 'inset 0 0 0 1px rgba(15, 23, 42, 0.08)',\n }}\n >\n {t.ui.secondaryAction}\n </button>\n </div>\n\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(auto-fit, minmax(120px, 1fr))',\n gap: '10px',\n }}\n >\n <div\n style={{\n borderRadius: radius.chip,\n padding: '10px 12px',\n fontSize: '12px',\n fontWeight: 500,\n backgroundColor: muted,\n color: mutedForeground,\n }}\n >\n Muted Card\n </div>\n <div\n style={{\n borderRadius: radius.chip,\n padding: '10px 12px',\n fontSize: '12px',\n fontWeight: 500,\n backgroundColor: accent,\n color: accentForeground,\n }}\n >\n Accent Tag\n </div>\n </div>\n\n <div\n style={{\n display: 'grid',\n gap: '8px',\n borderRadius: '10px',\n border: `1px dashed ${borderColor}`,\n padding: '14px',\n backgroundColor: 'rgba(148, 163, 184, 0.08)',\n }}\n >\n <div\n style={{\n fontFamily: headingFont,\n fontSize: 'clamp(24px, 3vw, 32px)',\n fontWeight: 600,\n lineHeight: 1.2,\n }}\n >\n Nadpis / Heading preview\n </div>\n <p\n style={{\n margin: 0,\n fontFamily: bodyFont,\n fontSize: baseFontSize,\n lineHeight,\n color: foreground,\n opacity: 0.85,\n }}\n >\n Sphinx of black quartz, judge my vow. Příliš žluťoučký kůň úpěl ďábelské ódy.\n </p>\n <div\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: '10px',\n fontSize: '11px',\n color: 'rgba(15, 23, 42, 0.7)',\n }}\n >\n <span>Body: {typography.bodyLabel}</span>\n <span>Heading: {typography.headingLabel}</span>\n <span>Base size: {baseFontSize}</span>\n <span>Line height: {lineHeight}</span>\n </div>\n </div>\n </div>\n )\n}\n\nexport default function ThemePreviewField(props: SelectFieldClientProps) {\n const { field, path } = props\n const showPreviewPanel =\n (field?.admin?.custom as unknown as { useThemePreviewField?: boolean })?.useThemePreviewField ??\n true\n // If the plugin provided theme presets via admin config, prefer those;\n // support both `field.admin.themePresets` (legacy) and `field.admin.custom.themePresets`\n // otherwise fallback to `allThemePresets`.\n // Prefer presets passed via `admin.custom.themePresets` (set by the field factory / plugin).\n // Fall back to legacy `admin.themePresets` for backwards compatibility, then to `allThemePresets`.\n const baseThemePresets =\n (field?.admin?.custom as unknown as { themePresets?: ThemePreset[] })?.themePresets ??\n (field?.admin as unknown as { themePresets?: ThemePreset[] })?.themePresets ??\n allThemePresets\n const runtimeThemePresets = useMemo(() => {\n return (baseThemePresets as ThemePreset[]).reduce<Record<string, ThemePresetDefinition>>(\n (acc, preset) => {\n acc[preset.name] = {\n label: preset.label,\n lightMode: { ...lightModeDefaults, ...(preset.lightMode ?? {}) },\n darkMode: { ...darkModeDefaults, ...(preset.darkMode ?? {}) },\n typography: preset.typography,\n borderRadius: preset.borderRadius,\n }\n return acc\n },\n {},\n )\n }, [baseThemePresets])\n const fallbackTheme = baseThemePresets[0]?.name ?? 'cool'\n const { value: selectedTheme, setValue } = useField<string>({ path })\n const { dispatchFields } = useForm()\n const formFields = useFormFields(([formState]: any) => formState)\n const hasAppliedInitialPresetRef = useRef(false)\n\n const applyPreset = useCallback(\n (presetName: string) => {\n const preset = runtimeThemePresets[presetName]\n if (!preset) {\n return\n }\n\n colorKeys.forEach((key) => {\n const lightValue = preset.lightMode[key]\n const darkValue = preset.darkMode[key]\n\n if (lightValue) {\n dispatchFields({\n type: 'UPDATE',\n path: `themeConfiguration.lightMode.${key}`,\n value: lightValue,\n })\n }\n\n if (darkValue) {\n dispatchFields({\n type: 'UPDATE',\n path: `themeConfiguration.darkMode.${key}`,\n value: darkValue,\n })\n }\n })\n },\n [dispatchFields],\n )\n\n const handleThemeSelect = useCallback(\n (value: string) => {\n setValue(value)\n\n if (!value) {\n return\n }\n\n hasAppliedInitialPresetRef.current = true\n applyPreset(value)\n },\n [applyPreset, setValue],\n )\n\n useEffect(() => {\n if (!selectedTheme) {\n return\n }\n\n if (runtimeThemePresets[selectedTheme]) {\n return\n }\n\n hasAppliedInitialPresetRef.current = false\n setValue(fallbackTheme)\n }, [selectedTheme, setValue])\n\n useEffect(() => {\n if (hasAppliedInitialPresetRef.current) {\n return\n }\n\n if (!selectedTheme) {\n return\n }\n\n if (!formFields) {\n return\n }\n\n const preset = runtimeThemePresets[selectedTheme]\n if (!preset) {\n hasAppliedInitialPresetRef.current = true\n return\n }\n\n const hasExistingValues = colorKeys.some((key) => {\n const lightField = formFields[`themeConfiguration.lightMode.${key}`]\n const darkField = formFields[`themeConfiguration.darkMode.${key}`]\n\n const lightValue = typeof lightField?.value === 'string' && lightField.value.trim().length > 0\n const darkValue = typeof darkField?.value === 'string' && darkField.value.trim().length > 0\n\n return lightValue || darkValue\n })\n\n if (hasExistingValues) {\n hasAppliedInitialPresetRef.current = true\n return\n }\n\n applyPreset(selectedTheme)\n hasAppliedInitialPresetRef.current = true\n }, [selectedTheme, formFields, applyPreset])\n\n const lightModeColors = useMemo(() => {\n const presetLightMode = selectedTheme\n ? runtimeThemePresets[selectedTheme]?.lightMode\n : undefined\n\n return colorKeys.reduce<ColorModeColors>((acc, key) => {\n const fieldState = formFields?.[`themeConfiguration.lightMode.${key}`]\n const rawValue =\n typeof fieldState?.value === 'string' && fieldState.value.trim().length > 0\n ? fieldState.value\n : undefined\n\n acc[key] = rawValue ?? presetLightMode?.[key] ?? lightModeDefaults[key]\n return acc\n }, {} as ColorModeColors)\n }, [formFields, selectedTheme])\n\n const darkModeColors = useMemo(() => {\n const presetDarkMode = selectedTheme ? runtimeThemePresets[selectedTheme]?.darkMode : undefined\n\n return colorKeys.reduce<ColorModeColors>((acc, key) => {\n const fieldState = formFields?.[`themeConfiguration.darkMode.${key}`]\n const rawValue =\n typeof fieldState?.value === 'string' && fieldState.value.trim().length > 0\n ? fieldState.value\n : undefined\n\n acc[key] = rawValue ?? presetDarkMode?.[key] ?? darkModeDefaults[key]\n return acc\n }, {} as ColorModeColors)\n }, [formFields, selectedTheme])\n\n const activePreset = selectedTheme ? runtimeThemePresets[selectedTheme] : undefined\n const formTypographySelection = useMemo<TypographySelection | null>(() => {\n if (!formFields) {\n return null\n }\n\n const getValue = (key: string) => formFields[`themeConfiguration.typography.${key}`]?.value\n\n return {\n bodyFont: (getValue('bodyFont') as string | undefined) ?? undefined,\n headingFont: (getValue('headingFont') as string | undefined) ?? undefined,\n bodyFontCustom: (getValue('bodyFontCustom') as string | undefined) ?? undefined,\n headingFontCustom: (getValue('headingFontCustom') as string | undefined) ?? undefined,\n baseFontSize: (getValue('baseFontSize') as string | undefined) ?? undefined,\n lineHeight: (getValue('lineHeight') as string | undefined) ?? undefined,\n }\n }, [formFields])\n\n const previewTypography = useMemo<ResolvedTypographyPreview>(() => {\n return resolveTypographyPreview(formTypographySelection, selectedTheme)\n }, [formTypographySelection, selectedTheme])\n\n const borderRadiusValue = formFields?.['themeConfiguration.borderRadius']?.value\n const presetRadius = activePreset?.borderRadius ?? 'medium'\n const resolvedBorderRadius = (\n typeof borderRadiusValue === 'string' && borderRadiusValue.length\n ? borderRadiusValue\n : presetRadius\n ) as keyof typeof borderRadiusPresets\n const borderRadiusPreset = borderRadiusPresets[resolvedBorderRadius] ?? borderRadiusPresets.medium\n const borderRadiusCSS =\n typeof borderRadiusPreset.css === 'string'\n ? { '--radius-default': borderRadiusPreset.css }\n : (borderRadiusPreset.css as Record<string, string>)\n const previewRadius = {\n card: borderRadiusCSS['--radius-large'] ?? '1rem',\n chip: borderRadiusCSS['--radius-default'] ?? '0.75rem',\n pill: borderRadiusCSS['--radius-xl'] ?? borderRadiusCSS['--radius-large'] ?? '999px',\n }\n\n // Translate labels at runtime based on admin language\n const t = getTranslations(getAdminLanguage())\n // Explicitly type keys as `keyof ColorModeColors` to satisfy TypeScript when indexing `lightMode`/`darkMode`\n const highlightSwatches: { key: keyof ColorModeColors; label: string }[] = [\n { key: 'primary', label: t.colors.primary },\n { key: 'secondary', label: t.colors.secondary },\n { key: 'accent', label: t.colors.accent },\n { key: 'background', label: t.colors.background },\n { key: 'foreground', label: t.colors.foreground },\n ]\n\n const fieldLabel =\n typeof field.label === 'string' ? field.label : field.label?.en || field.label?.cs || 'Theme'\n\n return (\n <div style={{ marginBottom: '24px' }}>\n <label\n style={{\n display: 'block',\n marginBottom: '10px',\n fontSize: '13px',\n fontWeight: 600,\n color: 'var(--theme-elevation-800)',\n }}\n >\n {fieldLabel}\n </label>\n\n <div\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: '24px',\n alignItems: 'flex-start',\n }}\n >\n <div\n style={{\n flex: '0 0 320px',\n minWidth: '260px',\n maxWidth: '420px',\n display: 'grid',\n gap: '12px',\n }}\n >\n <div className=\"theme-preset-list\">\n {Object.entries(runtimeThemePresets).map(([key, preset]) => {\n const isSelected = key === selectedTheme\n const swatches = highlightSwatches\n .map(({ key: colorKey }) => preset.lightMode[colorKey] as string | undefined)\n .filter((v): v is string => typeof v === 'string' && v.trim().length > 0)\n\n return (\n <button\n key={key}\n type=\"button\"\n onClick={() => handleThemeSelect(key)}\n className={`theme-preset-button ${isSelected ? 'selected' : ''}`}\n >\n <div className=\"theme-info\">\n <span className=\"theme-label\">{preset.label}</span>\n <span className=\"theme-name\">{key}</span>\n </div>\n <div className=\"theme-swatches\" aria-hidden=\"true\">\n {swatches.map((color, index) => (\n <span\n key={`${key}-swatch-${color}-${index}`}\n className=\"color-swatch\"\n style={{ backgroundColor: color }}\n />\n ))}\n </div>\n </button>\n )\n })}\n </div>\n\n {activePreset && (\n <div\n style={{\n padding: '12px',\n borderRadius: '10px',\n border: '1px solid var(--theme-elevation-200)',\n backgroundColor: 'var(--theme-elevation-50)',\n display: 'grid',\n gap: '8px',\n fontSize: '12px',\n color: 'var(--theme-elevation-600)',\n }}\n >\n <div style={{ fontWeight: 600, color: 'var(--theme-elevation-800)' }}>\n {activePreset.label}\n </div>\n <div>Primary color: {activePreset.lightMode.primary}</div>\n <div>Accent color: {activePreset.lightMode.accent}</div>\n <div\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: '12px',\n marginTop: '4px',\n }}\n >\n {highlightSwatches.map(({ key, label }) => {\n const swatchValue = activePreset.lightMode[key]\n\n if (!swatchValue) {\n return null\n }\n\n return (\n <div\n key={key}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n minWidth: 'fit-content',\n }}\n >\n <span\n style={{\n width: '22px',\n height: '22px',\n borderRadius: '999px',\n border: '1px solid rgba(15, 23, 42, 0.12)',\n backgroundColor: swatchValue,\n boxShadow: 'inset 0 1px 2px rgba(15, 23, 42, 0.08)',\n }}\n aria-hidden=\"true\"\n />\n <span style={{ fontSize: '11px', color: 'var(--theme-elevation-700)' }}>\n {label}\n </span>\n </div>\n )\n })}\n </div>\n </div>\n )}\n\n {field.admin?.description && (\n <div\n style={{\n fontSize: '12px',\n color: 'var(--theme-elevation-600)',\n lineHeight: 1.5,\n }}\n >\n {typeof field.admin.description === 'string'\n ? field.admin.description\n : field.admin.description?.en || field.admin.description?.cs || ''}\n </div>\n )}\n </div>\n\n {showPreviewPanel && (\n <div\n style={{\n flex: '1 1 420px',\n minWidth: '320px',\n position: 'sticky',\n top: '96px',\n alignSelf: 'flex-start',\n }}\n >\n <div\n style={{\n width: '100%',\n borderRadius: '16px',\n border: '1px solid var(--theme-elevation-200)',\n backgroundColor: 'var(--theme-elevation-25)',\n padding: '20px',\n display: 'grid',\n gap: '18px',\n maxHeight: 'calc(100vh - 140px)',\n overflowY: 'auto',\n }}\n >\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n fontWeight: 600,\n fontSize: '13px',\n color: 'var(--theme-elevation-800)',\n }}\n >\n {/* safe translations for preview header */}\n <span>{getTranslations('en').livePreview.smallTitle}</span>\n <span style={{ fontSize: '12px', color: 'var(--theme-elevation-600)' }}>\n {activePreset ? activePreset.label : getTranslations('en').preview.customPalette}\n </span>\n </div>\n\n <div\n style={{\n display: 'grid',\n gap: '16px',\n }}\n >\n <ModePreview\n icon=\"☀️\"\n title={getTranslations('en').ui.lightMode}\n colors={lightModeColors}\n typography={previewTypography}\n radius={previewRadius}\n />\n <ModePreview\n icon=\"🌙\"\n title={getTranslations('en').ui.darkMode}\n colors={darkModeColors}\n typography={previewTypography}\n radius={previewRadius}\n />\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n )\n}\n"],"names":["useField","useForm","useFormFields","useCallback","useEffect","useMemo","useRef","resolveTypographyPreview","allThemePresets","borderRadiusPresets","getTranslations","getAdminLanguage","darkModeDefaults","lightModeDefaults","colorKeys","Object","keys","ModePreview","icon","title","colors","typography","radius","t","background","foreground","borderColor","border","cardBackground","card","cardForeground","primary","primaryForeground","secondary","secondaryForeground","muted","mutedForeground","accent","accentForeground","headingFont","bodyFont","baseFontSize","lineHeight","div","style","display","gap","padding","borderRadius","backgroundColor","color","boxShadow","fontFamily","alignItems","justifyContent","fontSize","fontWeight","letterSpacing","textTransform","opacity","span","toUpperCase","flexWrap","button","type","pill","cursor","ui","primaryAction","chip","secondaryAction","gridTemplateColumns","p","margin","bodyLabel","headingLabel","ThemePreviewField","props","field","path","showPreviewPanel","admin","custom","useThemePreviewField","baseThemePresets","themePresets","runtimeThemePresets","reduce","acc","preset","name","label","lightMode","darkMode","fallbackTheme","value","selectedTheme","setValue","dispatchFields","formFields","formState","hasAppliedInitialPresetRef","applyPreset","presetName","forEach","key","lightValue","darkValue","handleThemeSelect","current","hasExistingValues","some","lightField","darkField","trim","length","lightModeColors","presetLightMode","undefined","fieldState","rawValue","darkModeColors","presetDarkMode","activePreset","formTypographySelection","getValue","bodyFontCustom","headingFontCustom","previewTypography","borderRadiusValue","presetRadius","resolvedBorderRadius","borderRadiusPreset","medium","borderRadiusCSS","css","previewRadius","highlightSwatches","fieldLabel","en","cs","marginBottom","flex","minWidth","maxWidth","className","entries","map","isSelected","swatches","colorKey","filter","v","onClick","aria-hidden","index","marginTop","swatchValue","width","height","description","position","top","alignSelf","maxHeight","overflowY","livePreview","smallTitle","preview","customPalette"],"mappings":"AAAA;;AAEA,OAAO,0BAAyB;AAChC,SAASA,QAAQ,EAAEC,OAAO,EAAEC,aAAa,QAAQ,iBAAgB;AAEjE,SAASC,WAAW,EAAEC,SAAS,EAAEC,OAAO,EAAEC,MAAM,QAAQ,QAAO;AAK/D,SAASC,wBAAwB,QAAQ,0CAAyC;AAClF,SAASC,eAAe,QAAQ,cAAa;AAE7C,SAASC,mBAAmB,QAAQ,oCAAmC;AACvE,SAASC,eAAe,QAAQ,qBAAoB;AACpD,SAASC,gBAAgB,QAAQ,+BAA8B;AAC/D,SAASC,gBAAgB,EAAEC,iBAAiB,QAAQ,uBAAsB;AAgC1E,6EAA6E;AAE7E,MAAMC,YAAYC,OAAOC,IAAI,CAACH;AAgB9B,SAASI,YAAY,EAAEC,IAAI,EAAEC,KAAK,EAAEC,MAAM,EAAEC,UAAU,EAAEC,MAAM,EAA8B;IAC1F,MAAMC,IAAIb,gBAAgBC;IAC1B,MAAMa,aAAaJ,OAAOI,UAAU,IAAI;IACxC,MAAMC,aAAaL,OAAOK,UAAU,IAAI;IACxC,MAAMC,cAAcN,OAAOO,MAAM,IAAI;IACrC,MAAMC,iBAAiBR,OAAOS,IAAI,IAAIL;IACtC,MAAMM,iBAAiBV,OAAOU,cAAc,IAAIL;IAChD,MAAMM,UAAUX,OAAOW,OAAO,IAAIN;IAClC,MAAMO,oBAAoBZ,OAAOY,iBAAiB,IAAIR;IACtD,MAAMS,YAAYb,OAAOa,SAAS,IAAI;IACtC,MAAMC,sBAAsBd,OAAOc,mBAAmB,IAAIT;IAC1D,MAAMU,QAAQf,OAAOe,KAAK,IAAIF;IAC9B,MAAMG,kBAAkBhB,OAAOgB,eAAe,IAAIF;IAClD,MAAMG,SAASjB,OAAOiB,MAAM,IAAIJ;IAChC,MAAMK,mBAAmBlB,OAAOkB,gBAAgB,IAAIJ;IACpD,MAAMK,cAAclB,WAAWkB,WAAW;IAC1C,MAAMC,WAAWnB,WAAWmB,QAAQ;IACpC,MAAMC,eAAepB,WAAWoB,YAAY;IAC5C,MAAMC,aAAarB,WAAWqB,UAAU;IAExC,qBACE,MAACC;QACCC,OAAO;YACLC,SAAS;YACTC,KAAK;YACLC,SAAS;YACTC,cAAc;YACdC,iBAAiBzB;YACjB0B,OAAOzB;YACPE,QAAQ,CAAC,UAAU,EAAED,aAAa;YAClCyB,WAAW;YACXC,YAAYZ;QACd;;0BAEA,MAACG;gBACCC,OAAO;oBACLC,SAAS;oBACTQ,YAAY;oBACZC,gBAAgB;oBAChBC,UAAU;oBACVC,YAAY;oBACZC,eAAe;oBACfC,eAAe;oBACfC,SAAS;gBACX;;kCAEA,MAACC;;4BACE1C;4BAAK;4BAAEC;;;kCAEV,KAACyC;wBAAKhB,OAAO;4BAAEQ,YAAY;4BAAaG,UAAU;wBAAO;kCACtD/B,WAAWqC,WAAW;;;;0BAI3B,MAAClB;gBACCC,OAAO;oBACLK,iBAAiBrB;oBACjBsB,OAAOpB;oBACPkB,cAAc1B,OAAOO,IAAI;oBACzBF,QAAQ,CAAC,UAAU,EAAED,aAAa;oBAClCqB,SAAS;oBACTF,SAAS;oBACTC,KAAK;oBACLgB,UAAU;gBACZ;;kCAEA,KAACC;wBACCC,MAAK;wBACLpB,OAAO;4BACLG,SAAS;4BACTC,cAAc1B,OAAO2C,IAAI;4BACzBtC,QAAQ;4BACRuC,QAAQ;4BACRX,UAAU;4BACVC,YAAY;4BACZC,eAAe;4BACfR,iBAAiBlB;4BACjBmB,OAAOlB;4BACPmB,WAAW;wBACb;kCAEC5B,EAAE4C,EAAE,CAACC,aAAa;;kCAErB,KAACL;wBACCC,MAAK;wBACLpB,OAAO;4BACLG,SAAS;4BACTC,cAAc1B,OAAO+C,IAAI;4BACzB1C,QAAQ;4BACRuC,QAAQ;4BACRX,UAAU;4BACVC,YAAY;4BACZC,eAAe;4BACfR,iBAAiBhB;4BACjBiB,OAAOhB;4BACPiB,WAAW;wBACb;kCAEC5B,EAAE4C,EAAE,CAACG,eAAe;;;;0BAIzB,MAAC3B;gBACCC,OAAO;oBACLC,SAAS;oBACT0B,qBAAqB;oBACrBzB,KAAK;gBACP;;kCAEA,KAACH;wBACCC,OAAO;4BACLI,cAAc1B,OAAO+C,IAAI;4BACzBtB,SAAS;4BACTQ,UAAU;4BACVC,YAAY;4BACZP,iBAAiBd;4BACjBe,OAAOd;wBACT;kCACD;;kCAGD,KAACO;wBACCC,OAAO;4BACLI,cAAc1B,OAAO+C,IAAI;4BACzBtB,SAAS;4BACTQ,UAAU;4BACVC,YAAY;4BACZP,iBAAiBZ;4BACjBa,OAAOZ;wBACT;kCACD;;;;0BAKH,MAACK;gBACCC,OAAO;oBACLC,SAAS;oBACTC,KAAK;oBACLE,cAAc;oBACdrB,QAAQ,CAAC,WAAW,EAAED,aAAa;oBACnCqB,SAAS;oBACTE,iBAAiB;gBACnB;;kCAEA,KAACN;wBACCC,OAAO;4BACLQ,YAAYb;4BACZgB,UAAU;4BACVC,YAAY;4BACZd,YAAY;wBACd;kCACD;;kCAGD,KAAC8B;wBACC5B,OAAO;4BACL6B,QAAQ;4BACRrB,YAAYZ;4BACZe,UAAUd;4BACVC;4BACAQ,OAAOzB;4BACPkC,SAAS;wBACX;kCACD;;kCAGD,MAAChB;wBACCC,OAAO;4BACLC,SAAS;4BACTiB,UAAU;4BACVhB,KAAK;4BACLS,UAAU;4BACVL,OAAO;wBACT;;0CAEA,MAACU;;oCAAK;oCAAOvC,WAAWqD,SAAS;;;0CACjC,MAACd;;oCAAK;oCAAUvC,WAAWsD,YAAY;;;0CACvC,MAACf;;oCAAK;oCAAYnB;;;0CAClB,MAACmB;;oCAAK;oCAAclB;;;;;;;;;AAK9B;AAEA,eAAe,SAASkC,kBAAkBC,KAA6B;IACrE,MAAM,EAAEC,KAAK,EAAEC,IAAI,EAAE,GAAGF;IACxB,MAAMG,mBACJ,AAACF,OAAOG,OAAOC,QAA0DC,wBACzE;IACF,uEAAuE;IACvE,yFAAyF;IACzF,2CAA2C;IAC3C,6FAA6F;IAC7F,mGAAmG;IACnG,MAAMC,mBACJ,AAACN,OAAOG,OAAOC,QAAwDG,gBACtEP,OAAOG,OAAuDI,gBAC/D7E;IACF,MAAM8E,sBAAsBjF,QAAQ;QAClC,OAAO,AAAC+E,iBAAmCG,MAAM,CAC/C,CAACC,KAAKC;YACJD,GAAG,CAACC,OAAOC,IAAI,CAAC,GAAG;gBACjBC,OAAOF,OAAOE,KAAK;gBACnBC,WAAW;oBAAE,GAAG/E,iBAAiB;oBAAE,GAAI4E,OAAOG,SAAS,IAAI,CAAC,CAAC;gBAAE;gBAC/DC,UAAU;oBAAE,GAAGjF,gBAAgB;oBAAE,GAAI6E,OAAOI,QAAQ,IAAI,CAAC,CAAC;gBAAE;gBAC5DxE,YAAYoE,OAAOpE,UAAU;gBAC7B2B,cAAcyC,OAAOzC,YAAY;YACnC;YACA,OAAOwC;QACT,GACA,CAAC;IAEL,GAAG;QAACJ;KAAiB;IACrB,MAAMU,gBAAgBV,gBAAgB,CAAC,EAAE,EAAEM,QAAQ;IACnD,MAAM,EAAEK,OAAOC,aAAa,EAAEC,QAAQ,EAAE,GAAGjG,SAAiB;QAAE+E;IAAK;IACnE,MAAM,EAAEmB,cAAc,EAAE,GAAGjG;IAC3B,MAAMkG,aAAajG,cAAc,CAAC,CAACkG,UAAe,GAAKA;IACvD,MAAMC,6BAA6B/F,OAAO;IAE1C,MAAMgG,cAAcnG,YAClB,CAACoG;QACC,MAAMd,SAASH,mBAAmB,CAACiB,WAAW;QAC9C,IAAI,CAACd,QAAQ;YACX;QACF;QAEA3E,UAAU0F,OAAO,CAAC,CAACC;YACjB,MAAMC,aAAajB,OAAOG,SAAS,CAACa,IAAI;YACxC,MAAME,YAAYlB,OAAOI,QAAQ,CAACY,IAAI;YAEtC,IAAIC,YAAY;gBACdR,eAAe;oBACblC,MAAM;oBACNe,MAAM,CAAC,6BAA6B,EAAE0B,KAAK;oBAC3CV,OAAOW;gBACT;YACF;YAEA,IAAIC,WAAW;gBACbT,eAAe;oBACblC,MAAM;oBACNe,MAAM,CAAC,4BAA4B,EAAE0B,KAAK;oBAC1CV,OAAOY;gBACT;YACF;QACF;IACF,GACA;QAACT;KAAe;IAGlB,MAAMU,oBAAoBzG,YACxB,CAAC4F;QACCE,SAASF;QAET,IAAI,CAACA,OAAO;YACV;QACF;QAEAM,2BAA2BQ,OAAO,GAAG;QACrCP,YAAYP;IACd,GACA;QAACO;QAAaL;KAAS;IAGzB7F,UAAU;QACR,IAAI,CAAC4F,eAAe;YAClB;QACF;QAEA,IAAIV,mBAAmB,CAACU,cAAc,EAAE;YACtC;QACF;QAEAK,2BAA2BQ,OAAO,GAAG;QACrCZ,SAASH;IACX,GAAG;QAACE;QAAeC;KAAS;IAE5B7F,UAAU;QACR,IAAIiG,2BAA2BQ,OAAO,EAAE;YACtC;QACF;QAEA,IAAI,CAACb,eAAe;YAClB;QACF;QAEA,IAAI,CAACG,YAAY;YACf;QACF;QAEA,MAAMV,SAASH,mBAAmB,CAACU,cAAc;QACjD,IAAI,CAACP,QAAQ;YACXY,2BAA2BQ,OAAO,GAAG;YACrC;QACF;QAEA,MAAMC,oBAAoBhG,UAAUiG,IAAI,CAAC,CAACN;YACxC,MAAMO,aAAab,UAAU,CAAC,CAAC,6BAA6B,EAAEM,KAAK,CAAC;YACpE,MAAMQ,YAAYd,UAAU,CAAC,CAAC,4BAA4B,EAAEM,KAAK,CAAC;YAElE,MAAMC,aAAa,OAAOM,YAAYjB,UAAU,YAAYiB,WAAWjB,KAAK,CAACmB,IAAI,GAAGC,MAAM,GAAG;YAC7F,MAAMR,YAAY,OAAOM,WAAWlB,UAAU,YAAYkB,UAAUlB,KAAK,CAACmB,IAAI,GAAGC,MAAM,GAAG;YAE1F,OAAOT,cAAcC;QACvB;QAEA,IAAIG,mBAAmB;YACrBT,2BAA2BQ,OAAO,GAAG;YACrC;QACF;QAEAP,YAAYN;QACZK,2BAA2BQ,OAAO,GAAG;IACvC,GAAG;QAACb;QAAeG;QAAYG;KAAY;IAE3C,MAAMc,kBAAkB/G,QAAQ;QAC9B,MAAMgH,kBAAkBrB,gBACpBV,mBAAmB,CAACU,cAAc,EAAEJ,YACpC0B;QAEJ,OAAOxG,UAAUyE,MAAM,CAAkB,CAACC,KAAKiB;YAC7C,MAAMc,aAAapB,YAAY,CAAC,CAAC,6BAA6B,EAAEM,KAAK,CAAC;YACtE,MAAMe,WACJ,OAAOD,YAAYxB,UAAU,YAAYwB,WAAWxB,KAAK,CAACmB,IAAI,GAAGC,MAAM,GAAG,IACtEI,WAAWxB,KAAK,GAChBuB;YAEN9B,GAAG,CAACiB,IAAI,GAAGe,YAAYH,iBAAiB,CAACZ,IAAI,IAAI5F,iBAAiB,CAAC4F,IAAI;YACvE,OAAOjB;QACT,GAAG,CAAC;IACN,GAAG;QAACW;QAAYH;KAAc;IAE9B,MAAMyB,iBAAiBpH,QAAQ;QAC7B,MAAMqH,iBAAiB1B,gBAAgBV,mBAAmB,CAACU,cAAc,EAAEH,WAAWyB;QAEtF,OAAOxG,UAAUyE,MAAM,CAAkB,CAACC,KAAKiB;YAC7C,MAAMc,aAAapB,YAAY,CAAC,CAAC,4BAA4B,EAAEM,KAAK,CAAC;YACrE,MAAMe,WACJ,OAAOD,YAAYxB,UAAU,YAAYwB,WAAWxB,KAAK,CAACmB,IAAI,GAAGC,MAAM,GAAG,IACtEI,WAAWxB,KAAK,GAChBuB;YAEN9B,GAAG,CAACiB,IAAI,GAAGe,YAAYE,gBAAgB,CAACjB,IAAI,IAAI7F,gBAAgB,CAAC6F,IAAI;YACrE,OAAOjB;QACT,GAAG,CAAC;IACN,GAAG;QAACW;QAAYH;KAAc;IAE9B,MAAM2B,eAAe3B,gBAAgBV,mBAAmB,CAACU,cAAc,GAAGsB;IAC1E,MAAMM,0BAA0BvH,QAAoC;QAClE,IAAI,CAAC8F,YAAY;YACf,OAAO;QACT;QAEA,MAAM0B,WAAW,CAACpB,MAAgBN,UAAU,CAAC,CAAC,8BAA8B,EAAEM,KAAK,CAAC,EAAEV;QAEtF,OAAO;YACLvD,UAAU,AAACqF,SAAS,eAAsCP;YAC1D/E,aAAa,AAACsF,SAAS,kBAAyCP;YAChEQ,gBAAgB,AAACD,SAAS,qBAA4CP;YACtES,mBAAmB,AAACF,SAAS,wBAA+CP;YAC5E7E,cAAc,AAACoF,SAAS,mBAA0CP;YAClE5E,YAAY,AAACmF,SAAS,iBAAwCP;QAChE;IACF,GAAG;QAACnB;KAAW;IAEf,MAAM6B,oBAAoB3H,QAAmC;QAC3D,OAAOE,yBAAyBqH,yBAAyB5B;IAC3D,GAAG;QAAC4B;QAAyB5B;KAAc;IAE3C,MAAMiC,oBAAoB9B,YAAY,CAAC,kCAAkC,EAAEJ;IAC3E,MAAMmC,eAAeP,cAAc3E,gBAAgB;IACnD,MAAMmF,uBACJ,OAAOF,sBAAsB,YAAYA,kBAAkBd,MAAM,GAC7Dc,oBACAC;IAEN,MAAME,qBAAqB3H,mBAAmB,CAAC0H,qBAAqB,IAAI1H,oBAAoB4H,MAAM;IAClG,MAAMC,kBACJ,OAAOF,mBAAmBG,GAAG,KAAK,WAC9B;QAAE,oBAAoBH,mBAAmBG,GAAG;IAAC,IAC5CH,mBAAmBG,GAAG;IAC7B,MAAMC,gBAAgB;QACpB3G,MAAMyG,eAAe,CAAC,iBAAiB,IAAI;QAC3CjE,MAAMiE,eAAe,CAAC,mBAAmB,IAAI;QAC7CrE,MAAMqE,eAAe,CAAC,cAAc,IAAIA,eAAe,CAAC,iBAAiB,IAAI;IAC/E;IAEA,sDAAsD;IACtD,MAAM/G,IAAIb,gBAAgBC;IAC1B,6GAA6G;IAC7G,MAAM8H,oBAAqE;QACzE;YAAEhC,KAAK;YAAWd,OAAOpE,EAAEH,MAAM,CAACW,OAAO;QAAC;QAC1C;YAAE0E,KAAK;YAAad,OAAOpE,EAAEH,MAAM,CAACa,SAAS;QAAC;QAC9C;YAAEwE,KAAK;YAAUd,OAAOpE,EAAEH,MAAM,CAACiB,MAAM;QAAC;QACxC;YAAEoE,KAAK;YAAcd,OAAOpE,EAAEH,MAAM,CAACI,UAAU;QAAC;QAChD;YAAEiF,KAAK;YAAcd,OAAOpE,EAAEH,MAAM,CAACK,UAAU;QAAC;KACjD;IAED,MAAMiH,aACJ,OAAO5D,MAAMa,KAAK,KAAK,WAAWb,MAAMa,KAAK,GAAGb,MAAMa,KAAK,EAAEgD,MAAM7D,MAAMa,KAAK,EAAEiD,MAAM;IAExF,qBACE,MAACjG;QAAIC,OAAO;YAAEiG,cAAc;QAAO;;0BACjC,KAAClD;gBACC/C,OAAO;oBACLC,SAAS;oBACTgG,cAAc;oBACdtF,UAAU;oBACVC,YAAY;oBACZN,OAAO;gBACT;0BAECwF;;0BAGH,MAAC/F;gBACCC,OAAO;oBACLC,SAAS;oBACTiB,UAAU;oBACVhB,KAAK;oBACLO,YAAY;gBACd;;kCAEA,MAACV;wBACCC,OAAO;4BACLkG,MAAM;4BACNC,UAAU;4BACVC,UAAU;4BACVnG,SAAS;4BACTC,KAAK;wBACP;;0CAEA,KAACH;gCAAIsG,WAAU;0CACZlI,OAAOmI,OAAO,CAAC5D,qBAAqB6D,GAAG,CAAC,CAAC,CAAC1C,KAAKhB,OAAO;oCACrD,MAAM2D,aAAa3C,QAAQT;oCAC3B,MAAMqD,WAAWZ,kBACdU,GAAG,CAAC,CAAC,EAAE1C,KAAK6C,QAAQ,EAAE,GAAK7D,OAAOG,SAAS,CAAC0D,SAAS,EACrDC,MAAM,CAAC,CAACC,IAAmB,OAAOA,MAAM,YAAYA,EAAEtC,IAAI,GAAGC,MAAM,GAAG;oCAEzE,qBACE,MAACpD;wCAECC,MAAK;wCACLyF,SAAS,IAAM7C,kBAAkBH;wCACjCwC,WAAW,CAAC,oBAAoB,EAAEG,aAAa,aAAa,IAAI;;0DAEhE,MAACzG;gDAAIsG,WAAU;;kEACb,KAACrF;wDAAKqF,WAAU;kEAAexD,OAAOE,KAAK;;kEAC3C,KAAC/B;wDAAKqF,WAAU;kEAAcxC;;;;0DAEhC,KAAC9D;gDAAIsG,WAAU;gDAAiBS,eAAY;0DACzCL,SAASF,GAAG,CAAC,CAACjG,OAAOyG,sBACpB,KAAC/F;wDAECqF,WAAU;wDACVrG,OAAO;4DAAEK,iBAAiBC;wDAAM;uDAF3B,GAAGuD,IAAI,QAAQ,EAAEvD,MAAM,CAAC,EAAEyG,OAAO;;;uCAZvClD;gCAoBX;;4BAGDkB,8BACC,MAAChF;gCACCC,OAAO;oCACLG,SAAS;oCACTC,cAAc;oCACdrB,QAAQ;oCACRsB,iBAAiB;oCACjBJ,SAAS;oCACTC,KAAK;oCACLS,UAAU;oCACVL,OAAO;gCACT;;kDAEA,KAACP;wCAAIC,OAAO;4CAAEY,YAAY;4CAAKN,OAAO;wCAA6B;kDAChEyE,aAAahC,KAAK;;kDAErB,MAAChD;;4CAAI;4CAAgBgF,aAAa/B,SAAS,CAAC7D,OAAO;;;kDACnD,MAACY;;4CAAI;4CAAegF,aAAa/B,SAAS,CAACvD,MAAM;;;kDACjD,KAACM;wCACCC,OAAO;4CACLC,SAAS;4CACTiB,UAAU;4CACVhB,KAAK;4CACL8G,WAAW;wCACb;kDAECnB,kBAAkBU,GAAG,CAAC,CAAC,EAAE1C,GAAG,EAAEd,KAAK,EAAE;4CACpC,MAAMkE,cAAclC,aAAa/B,SAAS,CAACa,IAAI;4CAE/C,IAAI,CAACoD,aAAa;gDAChB,OAAO;4CACT;4CAEA,qBACE,MAAClH;gDAECC,OAAO;oDACLC,SAAS;oDACTQ,YAAY;oDACZP,KAAK;oDACLiG,UAAU;gDACZ;;kEAEA,KAACnF;wDACChB,OAAO;4DACLkH,OAAO;4DACPC,QAAQ;4DACR/G,cAAc;4DACdrB,QAAQ;4DACRsB,iBAAiB4G;4DACjB1G,WAAW;wDACb;wDACAuG,eAAY;;kEAEd,KAAC9F;wDAAKhB,OAAO;4DAAEW,UAAU;4DAAQL,OAAO;wDAA6B;kEAClEyC;;;+CApBEc;wCAwBX;;;;4BAKL3B,MAAMG,KAAK,EAAE+E,6BACZ,KAACrH;gCACCC,OAAO;oCACLW,UAAU;oCACVL,OAAO;oCACPR,YAAY;gCACd;0CAEC,OAAOoC,MAAMG,KAAK,CAAC+E,WAAW,KAAK,WAChClF,MAAMG,KAAK,CAAC+E,WAAW,GACvBlF,MAAMG,KAAK,CAAC+E,WAAW,EAAErB,MAAM7D,MAAMG,KAAK,CAAC+E,WAAW,EAAEpB,MAAM;;;;oBAKvE5D,kCACC,KAACrC;wBACCC,OAAO;4BACLkG,MAAM;4BACNC,UAAU;4BACVkB,UAAU;4BACVC,KAAK;4BACLC,WAAW;wBACb;kCAEA,cAAA,MAACxH;4BACCC,OAAO;gCACLkH,OAAO;gCACP9G,cAAc;gCACdrB,QAAQ;gCACRsB,iBAAiB;gCACjBF,SAAS;gCACTF,SAAS;gCACTC,KAAK;gCACLsH,WAAW;gCACXC,WAAW;4BACb;;8CAEA,MAAC1H;oCACCC,OAAO;wCACLC,SAAS;wCACTQ,YAAY;wCACZC,gBAAgB;wCAChBE,YAAY;wCACZD,UAAU;wCACVL,OAAO;oCACT;;sDAGA,KAACU;sDAAMlD,gBAAgB,MAAM4J,WAAW,CAACC,UAAU;;sDACnD,KAAC3G;4CAAKhB,OAAO;gDAAEW,UAAU;gDAAQL,OAAO;4CAA6B;sDAClEyE,eAAeA,aAAahC,KAAK,GAAGjF,gBAAgB,MAAM8J,OAAO,CAACC,aAAa;;;;8CAIpF,MAAC9H;oCACCC,OAAO;wCACLC,SAAS;wCACTC,KAAK;oCACP;;sDAEA,KAAC7B;4CACCC,MAAK;4CACLC,OAAOT,gBAAgB,MAAMyD,EAAE,CAACyB,SAAS;4CACzCxE,QAAQgG;4CACR/F,YAAY2G;4CACZ1G,QAAQkH;;sDAEV,KAACvH;4CACCC,MAAK;4CACLC,OAAOT,gBAAgB,MAAMyD,EAAE,CAAC0B,QAAQ;4CACxCzE,QAAQqG;4CACRpG,YAAY2G;4CACZ1G,QAAQkH;;;;;;;;;;;AAS1B"}
@@ -7,6 +7,7 @@ interface ThemeConfigurationFieldOptions {
7
7
  includeCustomCSS: boolean;
8
8
  includeBrandIdentity: boolean;
9
9
  enableAdvancedFeatures?: boolean;
10
+ useThemePreviewField?: boolean;
10
11
  }
11
12
  export type ThemeTab = NonNullable<TabsField['tabs']>[number];
12
13
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"themeConfigurationField.d.ts","sourceRoot":"","sources":["../../src/fields/themeConfigurationField.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAS,SAAS,EAAE,MAAM,SAAS,CAAA;AAO/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAG9C,UAAU,8BAA8B;IACtC,YAAY,EAAE,WAAW,EAAE,CAAA;IAC3B,YAAY,EAAE,MAAM,CAAA;IACpB,sBAAsB,EAAE,OAAO,CAAA;IAC/B,gBAAgB,EAAE,OAAO,CAAA;IACzB,oBAAoB,EAAE,OAAO,CAAA;IAC7B,sBAAsB,CAAC,EAAE,OAAO,CAAA;CACjC;AAQD,MAAM,MAAM,QAAQ,GAAG,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;AAE7D;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,8BAA8B,GAAG,QAAQ,CA6a/F"}
1
+ {"version":3,"file":"themeConfigurationField.d.ts","sourceRoot":"","sources":["../../src/fields/themeConfigurationField.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAS,SAAS,EAAE,MAAM,SAAS,CAAA;AAO/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAG9C,UAAU,8BAA8B;IACtC,YAAY,EAAE,WAAW,EAAE,CAAA;IAC3B,YAAY,EAAE,MAAM,CAAA;IACpB,sBAAsB,EAAE,OAAO,CAAA;IAC/B,gBAAgB,EAAE,OAAO,CAAA;IACzB,oBAAoB,EAAE,OAAO,CAAA;IAC7B,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B;AASD,MAAM,MAAM,QAAQ,GAAG,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;AAE7D;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,8BAA8B,GAAG,QAAQ,CA+a/F"}
@@ -4,7 +4,7 @@ import { darkModeField, lightModeField } from './colorModeFields.js';
4
4
  * Theme Configuration Field with Theme Selection as default value setter
5
5
  * Theme Selection populates lightMode/darkMode colors automatically
6
6
  */ export function createThemeConfigurationField(options) {
7
- const { themePresets, defaultTheme, includeColorModeToggle, includeCustomCSS, enableAdvancedFeatures = true } = options;
7
+ const { themePresets, defaultTheme, includeColorModeToggle, includeCustomCSS, enableAdvancedFeatures = true, useThemePreviewField = true } = options;
8
8
  const fields = [
9
9
  {
10
10
  name: 'theme',
@@ -30,7 +30,8 @@ import { darkModeField, lightModeField } from './colorModeFields.js';
30
30
  Field: '@kilivi/payloadcms-theme-management/fields/ThemePreviewField'
31
31
  },
32
32
  custom: {
33
- themePresets
33
+ themePresets,
34
+ useThemePreviewField
34
35
  }
35
36
  }
36
37
  }