@kilivi/payloadcms-theme-management 2.0.0 → 2.1.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 (214) hide show
  1. package/README.md +318 -847
  2. package/dist/components/AppearanceSessionControls.d.ts +15 -0
  3. package/dist/components/AppearanceSessionControls.d.ts.map +1 -0
  4. package/dist/components/AppearanceSessionControls.js +152 -0
  5. package/dist/components/AppearanceSessionControls.js.map +1 -0
  6. package/dist/components/ColorModeToggle.css +42 -0
  7. package/dist/components/ColorModeToggle.d.ts +40 -0
  8. package/dist/components/ColorModeToggle.d.ts.map +1 -0
  9. package/dist/components/ColorModeToggle.js +111 -0
  10. package/dist/components/ColorModeToggle.js.map +1 -0
  11. package/dist/components/ServerThemeInjector.d.ts.map +1 -1
  12. package/dist/components/ServerThemeInjector.js +41 -14
  13. package/dist/components/ServerThemeInjector.js.map +1 -1
  14. package/dist/components/ThemeLivePreviewSync.d.ts +1 -0
  15. package/dist/components/ThemeLivePreviewSync.d.ts.map +1 -1
  16. package/dist/components/ThemeLivePreviewSync.js +1 -1
  17. package/dist/components/ThemeLivePreviewSync.js.map +1 -1
  18. package/dist/components/ThemeSwitcher.d.ts +36 -0
  19. package/dist/components/ThemeSwitcher.d.ts.map +1 -0
  20. package/dist/components/ThemeSwitcher.js +89 -0
  21. package/dist/components/ThemeSwitcher.js.map +1 -0
  22. package/dist/components/typographyPreviewUtils.d.ts.map +1 -1
  23. package/dist/components/typographyPreviewUtils.js +8 -1
  24. package/dist/components/typographyPreviewUtils.js.map +1 -1
  25. package/dist/constants/devicePreviews.d.ts +35 -0
  26. package/dist/constants/devicePreviews.d.ts.map +1 -0
  27. package/dist/constants/devicePreviews.js +43 -0
  28. package/dist/constants/devicePreviews.js.map +1 -0
  29. package/dist/constants/themeFonts.js +9 -9
  30. package/dist/constants/themeFonts.js.map +1 -1
  31. package/dist/extended-presets.d.ts +0 -4
  32. package/dist/extended-presets.d.ts.map +1 -1
  33. package/dist/extended-presets.js +1 -18
  34. package/dist/extended-presets.js.map +1 -1
  35. package/dist/extended-themes.d.ts.map +1 -1
  36. package/dist/extended-themes.js +428 -0
  37. package/dist/extended-themes.js.map +1 -1
  38. package/dist/fields/AccessibilityAuditField.d.ts +2 -0
  39. package/dist/fields/AccessibilityAuditField.d.ts.map +1 -0
  40. package/dist/fields/AccessibilityAuditField.js +303 -0
  41. package/dist/fields/AccessibilityAuditField.js.map +1 -0
  42. package/dist/fields/AppearancePreviewField.d.ts +2 -0
  43. package/dist/fields/AppearancePreviewField.d.ts.map +1 -0
  44. package/dist/fields/AppearancePreviewField.js +763 -0
  45. package/dist/fields/AppearancePreviewField.js.map +1 -0
  46. package/dist/fields/ColorPickerField.d.ts.map +1 -1
  47. package/dist/fields/ColorPickerField.js +89 -85
  48. package/dist/fields/ColorPickerField.js.map +1 -1
  49. package/dist/fields/FontSelectField.d.ts +6 -0
  50. package/dist/fields/FontSelectField.d.ts.map +1 -1
  51. package/dist/fields/FontSelectField.js +195 -122
  52. package/dist/fields/FontSelectField.js.map +1 -1
  53. package/dist/fields/PaletteGeneratorField.d.ts +7 -0
  54. package/dist/fields/PaletteGeneratorField.d.ts.map +1 -0
  55. package/dist/fields/PaletteGeneratorField.js +327 -0
  56. package/dist/fields/PaletteGeneratorField.js.map +1 -0
  57. package/dist/fields/StylePresetField.d.ts +3 -0
  58. package/dist/fields/StylePresetField.d.ts.map +1 -0
  59. package/dist/fields/StylePresetField.js +462 -0
  60. package/dist/fields/StylePresetField.js.map +1 -0
  61. package/dist/fields/ThemeColorPickerField.css +115 -35
  62. package/dist/fields/ThemeColorPickerField.d.ts.map +1 -1
  63. package/dist/fields/ThemeColorPickerField.js +204 -70
  64. package/dist/fields/ThemeColorPickerField.js.map +1 -1
  65. package/dist/fields/ThemeExportField.d.ts +6 -0
  66. package/dist/fields/ThemeExportField.d.ts.map +1 -0
  67. package/dist/fields/ThemeExportField.js +202 -0
  68. package/dist/fields/ThemeExportField.js.map +1 -0
  69. package/dist/fields/ThemePresetImportField.d.ts.map +1 -1
  70. package/dist/fields/ThemePresetImportField.js +56 -25
  71. package/dist/fields/ThemePresetImportField.js.map +1 -1
  72. package/dist/fields/ThemePreviewField.css +382 -5
  73. package/dist/fields/ThemePreviewField.d.ts.map +1 -1
  74. package/dist/fields/ThemePreviewField.js +268 -170
  75. package/dist/fields/ThemePreviewField.js.map +1 -1
  76. package/dist/fields/ThemeTokenSelectField.d.ts.map +1 -1
  77. package/dist/fields/ThemeTokenSelectField.js +278 -80
  78. package/dist/fields/ThemeTokenSelectField.js.map +1 -1
  79. package/dist/fields/colorFieldHelpers.d.ts +90 -0
  80. package/dist/fields/colorFieldHelpers.d.ts.map +1 -0
  81. package/dist/fields/colorFieldHelpers.js +133 -0
  82. package/dist/fields/colorFieldHelpers.js.map +1 -0
  83. package/dist/fields/colorModeFields.d.ts +1 -1
  84. package/dist/fields/colorModeFields.d.ts.map +1 -1
  85. package/dist/fields/colorModeFields.js +49 -7
  86. package/dist/fields/colorModeFields.js.map +1 -1
  87. package/dist/fields/themeConfigurationField.d.ts +8 -1
  88. package/dist/fields/themeConfigurationField.d.ts.map +1 -1
  89. package/dist/fields/themeConfigurationField.js +961 -29
  90. package/dist/fields/themeConfigurationField.js.map +1 -1
  91. package/dist/globals/ThemeSettings/FontPicker/FontPreview.d.ts.map +1 -1
  92. package/dist/globals/ThemeSettings/FontPicker/FontPreview.js +8 -4
  93. package/dist/globals/ThemeSettings/FontPicker/FontPreview.js.map +1 -1
  94. package/dist/globals/ThemeSettings/FontPicker/index.d.ts.map +1 -1
  95. package/dist/globals/ThemeSettings/FontPicker/index.js +81 -26
  96. package/dist/globals/ThemeSettings/FontPicker/index.js.map +1 -1
  97. package/dist/globals/ThemeSettings/FontPicker/styles.css +98 -41
  98. package/dist/globals/ThemeSettings/FontPicker/translations.d.ts +6 -0
  99. package/dist/globals/ThemeSettings/FontPicker/translations.d.ts.map +1 -1
  100. package/dist/globals/ThemeSettings/FontPicker/translations.js +14 -2
  101. package/dist/globals/ThemeSettings/FontPicker/translations.js.map +1 -1
  102. package/dist/globals/ThemeSettings/config.d.ts.map +1 -1
  103. package/dist/globals/ThemeSettings/config.js +76 -79
  104. package/dist/globals/ThemeSettings/config.js.map +1 -1
  105. package/dist/globals/ThemeSettings/fields/FontLoadingGuideField.d.ts.map +1 -1
  106. package/dist/globals/ThemeSettings/fields/FontLoadingGuideField.js +63 -62
  107. package/dist/globals/ThemeSettings/fields/FontLoadingGuideField.js.map +1 -1
  108. package/dist/globals/ThemeSettings/fields/TypographyInfoField.d.ts.map +1 -1
  109. package/dist/globals/ThemeSettings/fields/TypographyInfoField.js +22 -25
  110. package/dist/globals/ThemeSettings/fields/TypographyInfoField.js.map +1 -1
  111. package/dist/hooks/useAppearanceSession.d.ts +50 -0
  112. package/dist/hooks/useAppearanceSession.d.ts.map +1 -0
  113. package/dist/hooks/useAppearanceSession.js +91 -0
  114. package/dist/hooks/useAppearanceSession.js.map +1 -0
  115. package/dist/hooks/useThemeTranslations.d.ts +13 -0
  116. package/dist/hooks/useThemeTranslations.d.ts.map +1 -0
  117. package/dist/hooks/useThemeTranslations.js +22 -0
  118. package/dist/hooks/useThemeTranslations.js.map +1 -0
  119. package/dist/i18n.d.ts +53 -0
  120. package/dist/i18n.d.ts.map +1 -0
  121. package/dist/i18n.js +53 -0
  122. package/dist/i18n.js.map +1 -0
  123. package/dist/index.d.ts +10 -4
  124. package/dist/index.d.ts.map +1 -1
  125. package/dist/index.js +50 -29
  126. package/dist/index.js.map +1 -1
  127. package/dist/payload-types.d.ts +24 -0
  128. package/dist/payload-types.d.ts.map +1 -1
  129. package/dist/payload-types.js.map +1 -1
  130. package/dist/presets.d.ts +8 -0
  131. package/dist/presets.d.ts.map +1 -1
  132. package/dist/presets.js.map +1 -1
  133. package/dist/providers/Theme/index.d.ts.map +1 -1
  134. package/dist/providers/Theme/index.js +75 -11
  135. package/dist/providers/Theme/index.js.map +1 -1
  136. package/dist/providers/Theme/themeConfig.d.ts.map +1 -1
  137. package/dist/providers/Theme/themeConfig.js +104 -0
  138. package/dist/providers/Theme/themeConfig.js.map +1 -1
  139. package/dist/providers/Theme/types.d.ts +1 -1
  140. package/dist/providers/Theme/types.d.ts.map +1 -1
  141. package/dist/providers/Theme/types.js +10 -1
  142. package/dist/providers/Theme/types.js.map +1 -1
  143. package/dist/style-presets.d.ts +66 -0
  144. package/dist/style-presets.d.ts.map +1 -0
  145. package/dist/style-presets.js +556 -0
  146. package/dist/style-presets.js.map +1 -0
  147. package/dist/translations.d.ts +159 -1
  148. package/dist/translations.d.ts.map +1 -1
  149. package/dist/translations.js +310 -9
  150. package/dist/translations.js.map +1 -1
  151. package/dist/tweakcn-special-themes.d.ts.map +1 -1
  152. package/dist/tweakcn-special-themes.js +585 -9
  153. package/dist/tweakcn-special-themes.js.map +1 -1
  154. package/dist/types/css.d.js +3 -0
  155. package/dist/types/css.d.js.map +1 -0
  156. package/dist/types.d.ts +26 -0
  157. package/dist/types.d.ts.map +1 -1
  158. package/dist/types.js +1 -1
  159. package/dist/types.js.map +1 -1
  160. package/dist/utilities/getThemeSettings.d.ts.map +1 -1
  161. package/dist/utilities/getThemeSettings.js +2 -14
  162. package/dist/utilities/getThemeSettings.js.map +1 -1
  163. package/dist/utils/contrast.d.ts +63 -0
  164. package/dist/utils/contrast.d.ts.map +1 -0
  165. package/dist/utils/contrast.js +158 -0
  166. package/dist/utils/contrast.js.map +1 -0
  167. package/dist/utils/exportTokens.d.ts +30 -0
  168. package/dist/utils/exportTokens.d.ts.map +1 -0
  169. package/dist/utils/exportTokens.js +183 -0
  170. package/dist/utils/exportTokens.js.map +1 -0
  171. package/dist/utils/generatePalette.d.ts +46 -0
  172. package/dist/utils/generatePalette.d.ts.map +1 -0
  173. package/dist/utils/generatePalette.js +127 -0
  174. package/dist/utils/generatePalette.js.map +1 -0
  175. package/dist/utils/generateThemeCSS.d.ts.map +1 -1
  176. package/dist/utils/generateThemeCSS.js +2 -40
  177. package/dist/utils/generateThemeCSS.js.map +1 -1
  178. package/dist/utils/livePreviewThemeRuntime.d.ts +16 -2
  179. package/dist/utils/livePreviewThemeRuntime.d.ts.map +1 -1
  180. package/dist/utils/livePreviewThemeRuntime.js +37 -14
  181. package/dist/utils/livePreviewThemeRuntime.js.map +1 -1
  182. package/dist/utils/localizedText.d.ts +8 -0
  183. package/dist/utils/localizedText.d.ts.map +1 -0
  184. package/dist/utils/localizedText.js +21 -0
  185. package/dist/utils/localizedText.js.map +1 -0
  186. package/dist/utils/resolveThemeConfiguration.d.ts +45 -1
  187. package/dist/utils/resolveThemeConfiguration.d.ts.map +1 -1
  188. package/dist/utils/resolveThemeConfiguration.js +12 -5
  189. package/dist/utils/resolveThemeConfiguration.js.map +1 -1
  190. package/dist/utils/themeColors.d.ts +3 -0
  191. package/dist/utils/themeColors.d.ts.map +1 -1
  192. package/dist/utils/themeColors.js +30 -1
  193. package/dist/utils/themeColors.js.map +1 -1
  194. package/dist/utils/themeHtmlAttributes.d.ts +32 -12
  195. package/dist/utils/themeHtmlAttributes.d.ts.map +1 -1
  196. package/dist/utils/themeHtmlAttributes.js +38 -5
  197. package/dist/utils/themeHtmlAttributes.js.map +1 -1
  198. package/dist/utils/themeUtils.d.ts +3 -5
  199. package/dist/utils/themeUtils.d.ts.map +1 -1
  200. package/dist/utils/themeUtils.js +416 -6
  201. package/dist/utils/themeUtils.js.map +1 -1
  202. package/dist/utils/tweakcnConverter.d.ts +1 -3
  203. package/dist/utils/tweakcnConverter.d.ts.map +1 -1
  204. package/dist/utils/tweakcnConverter.js +1 -3
  205. package/dist/utils/tweakcnConverter.js.map +1 -1
  206. package/package.json +11 -5
  207. package/dist/components/ThemePreview.d.ts +0 -3
  208. package/dist/components/ThemePreview.d.ts.map +0 -1
  209. package/dist/components/ThemePreview.js +0 -321
  210. package/dist/components/ThemePreview.js.map +0 -1
  211. package/dist/plugin.d.ts +0 -2
  212. package/dist/plugin.d.ts.map +0 -1
  213. package/dist/plugin.js +0 -3
  214. package/dist/plugin.js.map +0 -1
@@ -1,9 +1,10 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useField } from '@payloadcms/ui';
4
- import { useCallback, useEffect, useMemo, useState } from 'react';
4
+ import { Check, ChevronDown } from 'lucide-react';
5
+ import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';
5
6
  import { allThemePresets, fetchThemeConfiguration } from '../index.js';
6
- import { getAdminLanguage } from '../utils/getAdminLanguage.js';
7
+ import { useThemeLanguage, useThemeTranslations } from '../hooks/useThemeTranslations.js';
7
8
  import { inferTenant } from '../utils/inferTenant.js';
8
9
  import { resolveThemeConfiguration } from '../utils/resolveThemeConfiguration.js';
9
10
  const FALLBACK_TOKENS = [
@@ -11,7 +12,7 @@ const FALLBACK_TOKENS = [
11
12
  value: 'background',
12
13
  label: {
13
14
  en: 'Theme background',
14
- cs: 'Pozadí tématu'
15
+ cs: 'Pozadí motivu'
15
16
  },
16
17
  color: 'var(--background)'
17
18
  },
@@ -83,7 +84,7 @@ function buildOptionsFromConfiguration(configuration, themePresets) {
83
84
  const labelMap = {
84
85
  background: {
85
86
  en: 'Theme background',
86
- cs: 'Pozadí tématu'
87
+ cs: 'Pozadí motivu'
87
88
  },
88
89
  card: {
89
90
  en: 'Card background',
@@ -137,6 +138,9 @@ export default function ThemeTokenSelectField(props) {
137
138
  });
138
139
  const [options, setOptions] = useState(FALLBACK_TOKENS);
139
140
  const selectedValue = value || 'background';
141
+ // Active Payload admin language (reactive via Payload's i18n context).
142
+ const adminLang = useThemeLanguage();
143
+ const t = useThemeTranslations();
140
144
  // Get themePresets from admin.custom or use defaults
141
145
  const themePresets = useMemo(()=>{
142
146
  const customPresets = field.admin?.custom?.themePresets;
@@ -150,7 +154,7 @@ export default function ThemeTokenSelectField(props) {
150
154
  setOptions(buildOptionsFromConfiguration(formThemeConfiguration, themePresets));
151
155
  return;
152
156
  }
153
- let isMounted = true;
157
+ const controller = new AbortController();
154
158
  const custom = field.admin?.custom;
155
159
  // Prefer tenant ID from the current form (`formTenant`) first since editor fills the relation id.
156
160
  // If the relation is an object, prefer `id` over `slug` to avoid passing a human-readable slug when an id is available.
@@ -164,8 +168,6 @@ export default function ThemeTokenSelectField(props) {
164
168
  return undefined;
165
169
  })();
166
170
  const inferredTenant = tenantFromForm ?? custom?.tenantSlug ?? inferTenant();
167
- // Determine admin language to pass as `locale` to fetch, if not provided
168
- const adminLang = getAdminLanguage();
169
171
  // Normalize fetch options so that even when callers provide an empty object ("{}"),
170
172
  // we still ensure `tenantSlug` and `locale` are set to sensible defaults (inferred/form/adminLang).
171
173
  const rawFetchOpts = custom?.fetchThemeConfigurationOptions ?? custom?.fetchOptions ?? (custom?.collectionSlug || typeof custom?.useGlobal !== 'undefined' ? {
@@ -181,10 +183,11 @@ export default function ThemeTokenSelectField(props) {
181
183
  const fetchOpts = {
182
184
  ...rawFetchOpts ?? {},
183
185
  tenantSlug: rawFetchOpts?.tenantSlug ?? inferredTenant,
184
- locale: rawFetchOpts?.locale ?? adminLang
186
+ locale: rawFetchOpts?.locale ?? adminLang,
187
+ signal: controller.signal
185
188
  };
186
189
  fetchThemeConfiguration(fetchOpts).then(async (configuration)=>{
187
- if (!isMounted) return;
190
+ if (controller.signal.aborted) return;
188
191
  if (configuration) {
189
192
  setOptions(buildOptionsFromConfiguration(configuration, themePresets));
190
193
  return;
@@ -200,10 +203,11 @@ export default function ThemeTokenSelectField(props) {
200
203
  useGlobal: true,
201
204
  collectionSlug: fallbackCollection,
202
205
  tenantSlug: inferredTenant,
203
- locale: custom?.locale ?? adminLang
206
+ locale: custom?.locale ?? adminLang,
207
+ signal: controller.signal
204
208
  };
205
209
  const fallbackConfig = await fetchThemeConfiguration(fallbackOpts);
206
- if (!isMounted) return;
210
+ if (controller.signal.aborted) return;
207
211
  if (fallbackConfig) {
208
212
  // Found theme config in global, use it
209
213
  setOptions(buildOptionsFromConfiguration(fallbackConfig, themePresets));
@@ -217,39 +221,20 @@ export default function ThemeTokenSelectField(props) {
217
221
  setOptions(buildOptionsFromConfiguration(configuration, themePresets));
218
222
  });
219
223
  return ()=>{
220
- isMounted = false;
224
+ controller.abort();
221
225
  };
222
226
  }, [
223
227
  themePresets,
224
228
  field.admin?.custom,
225
229
  formThemeConfiguration,
226
- formTenant
230
+ formTenant,
231
+ adminLang
227
232
  ]);
228
233
  const handleSelect = useCallback((nextValue)=>{
229
234
  setValue(nextValue);
230
235
  }, [
231
236
  setValue
232
237
  ]);
233
- // Make admin language reactive so switching admin UI language updates labels
234
- const initialAdminLang = getAdminLanguage();
235
- const [adminLang, setAdminLang] = useState(initialAdminLang);
236
- useEffect(()=>{
237
- if (typeof document === 'undefined' || !('MutationObserver' in window)) return;
238
- const el = document.documentElement;
239
- const obs = new MutationObserver(()=>{
240
- const next = getAdminLanguage();
241
- if (next !== adminLang) setAdminLang(next);
242
- });
243
- obs.observe(el, {
244
- attributes: true,
245
- attributeFilter: [
246
- 'lang'
247
- ]
248
- });
249
- return ()=>obs.disconnect();
250
- }, [
251
- adminLang
252
- ]);
253
238
  const label = typeof field.label === 'string' ? field.label : field.label && field.label[adminLang] || field.label?.en || field.label?.cs || '';
254
239
  let description = '';
255
240
  if (typeof field.admin?.description === 'string') {
@@ -280,12 +265,105 @@ export default function ThemeTokenSelectField(props) {
280
265
  return color;
281
266
  }
282
267
  };
268
+ const selectedIndex = options.findIndex((opt)=>opt.value === selectedValue);
269
+ const selectedOption = selectedIndex >= 0 ? options[selectedIndex] : undefined;
270
+ const selectedColor = selectedOption ? resolveCssColor(selectedOption.color) : '';
271
+ const selectedLabel = selectedOption ? getOptionLabel(selectedOption) : '';
272
+ const [isOpen, setIsOpen] = useState(false);
273
+ const [activeIndex, setActiveIndex] = useState(-1);
274
+ const baseId = useId();
275
+ const labelId = `${baseId}-label`;
276
+ const listboxId = `${baseId}-listbox`;
277
+ const optionId = (index)=>`${baseId}-option-${index}`;
278
+ const containerRef = useRef(null);
279
+ const triggerRef = useRef(null);
280
+ const listboxRef = useRef(null);
281
+ const openList = (index = selectedIndex >= 0 ? selectedIndex : 0)=>{
282
+ setActiveIndex(index);
283
+ setIsOpen(true);
284
+ };
285
+ const closeList = useCallback((restoreFocus)=>{
286
+ setIsOpen(false);
287
+ if (restoreFocus) triggerRef.current?.focus();
288
+ }, []);
289
+ const chooseOption = (index)=>{
290
+ const option = options[index];
291
+ if (!option) return;
292
+ handleSelect(option.value);
293
+ closeList(true);
294
+ };
295
+ useEffect(()=>{
296
+ if (!isOpen) return;
297
+ listboxRef.current?.focus();
298
+ const handlePointerOutside = (event)=>{
299
+ if (!containerRef.current?.contains(event.target)) closeList(false);
300
+ };
301
+ document.addEventListener('pointerdown', handlePointerOutside);
302
+ return ()=>document.removeEventListener('pointerdown', handlePointerOutside);
303
+ }, [
304
+ isOpen,
305
+ closeList
306
+ ]);
307
+ useEffect(()=>{
308
+ if (!isOpen || activeIndex < 0) return;
309
+ listboxRef.current?.querySelector(`#${CSS.escape(optionId(activeIndex))}`)?.scrollIntoView({
310
+ block: 'nearest'
311
+ });
312
+ }, [
313
+ isOpen,
314
+ activeIndex
315
+ ]);
316
+ const handleTriggerKeyDown = (event)=>{
317
+ if ([
318
+ 'ArrowDown',
319
+ 'ArrowUp',
320
+ 'Enter',
321
+ ' '
322
+ ].includes(event.key)) {
323
+ event.preventDefault();
324
+ openList();
325
+ }
326
+ };
327
+ const handleListboxKeyDown = (event)=>{
328
+ const last = options.length - 1;
329
+ switch(event.key){
330
+ case 'ArrowDown':
331
+ event.preventDefault();
332
+ setActiveIndex((i)=>Math.min(last, i + 1));
333
+ break;
334
+ case 'ArrowUp':
335
+ event.preventDefault();
336
+ setActiveIndex((i)=>Math.max(0, i - 1));
337
+ break;
338
+ case 'Home':
339
+ event.preventDefault();
340
+ setActiveIndex(0);
341
+ break;
342
+ case 'End':
343
+ event.preventDefault();
344
+ setActiveIndex(last);
345
+ break;
346
+ case 'Enter':
347
+ case ' ':
348
+ event.preventDefault();
349
+ chooseOption(activeIndex);
350
+ break;
351
+ case 'Escape':
352
+ event.preventDefault();
353
+ event.stopPropagation();
354
+ closeList(true);
355
+ break;
356
+ case 'Tab':
357
+ closeList(false);
358
+ break;
359
+ }
360
+ };
283
361
  return /*#__PURE__*/ _jsxs("div", {
284
362
  className: "field-type theme-token-select",
285
363
  children: [
286
- label && /*#__PURE__*/ _jsxs("label", {
364
+ label && /*#__PURE__*/ _jsxs("div", {
287
365
  className: "field-label",
288
- htmlFor: path,
366
+ id: labelId,
289
367
  style: {
290
368
  display: 'block',
291
369
  marginBottom: '8px'
@@ -303,69 +381,189 @@ export default function ThemeTokenSelectField(props) {
303
381
  style: {
304
382
  marginBottom: '12px',
305
383
  fontSize: '13px',
306
- color: 'var(--theme-elevation-500)'
384
+ color: 'var(--theme-elevation-600)'
307
385
  },
308
386
  children: description
309
387
  }),
310
- /*#__PURE__*/ _jsx("div", {
311
- className: "token-grid",
388
+ /*#__PURE__*/ _jsxs("div", {
312
389
  style: {
313
- display: 'grid',
314
- gridTemplateColumns: 'repeat(auto-fill, minmax(140px, 1fr))',
315
- gap: '10px'
390
+ display: 'flex',
391
+ alignItems: 'center',
392
+ gap: '12px',
393
+ position: 'relative'
316
394
  },
317
- children: options.map((option)=>{
318
- const isActive = option.value === selectedValue;
319
- return /*#__PURE__*/ _jsxs("button", {
320
- type: "button",
321
- onClick: ()=>handleSelect(option.value),
395
+ children: [
396
+ /*#__PURE__*/ _jsx("div", {
397
+ "aria-hidden": true,
398
+ style: {
399
+ width: '40px',
400
+ height: '40px',
401
+ borderRadius: '8px',
402
+ border: '2px solid var(--theme-elevation-200)',
403
+ backgroundColor: selectedColor,
404
+ flexShrink: 0,
405
+ boxShadow: selectedColor ? '0 2px 8px rgba(0, 0, 0, 0.1)' : 'inset 0 1px 2px rgba(0, 0, 0, 0.05)'
406
+ }
407
+ }),
408
+ /*#__PURE__*/ _jsxs("div", {
409
+ ref: containerRef,
322
410
  style: {
323
- display: 'flex',
324
- alignItems: 'center',
325
- gap: '10px',
326
- padding: '10px 12px',
327
- borderRadius: '10px',
328
- border: isActive ? '2px solid var(--theme-success-500)' : '1px solid var(--theme-elevation-150)',
329
- backgroundColor: 'var(--theme-elevation-0)',
330
- boxShadow: isActive ? '0 10px 20px -10px rgba(59, 130, 246, 0.4)' : '0 1px 2px rgba(15, 23, 42, 0.08)',
331
- cursor: 'pointer',
332
- transition: 'border-color 0.2s ease, box-shadow 0.2s ease'
411
+ flex: 1,
412
+ minWidth: 0,
413
+ position: 'relative'
333
414
  },
334
415
  children: [
335
- /*#__PURE__*/ _jsx("span", {
336
- "aria-hidden": true,
416
+ /*#__PURE__*/ _jsxs("button", {
417
+ ref: triggerRef,
418
+ id: path,
419
+ type: "button",
420
+ role: "combobox",
421
+ "aria-haspopup": "listbox",
422
+ "aria-expanded": isOpen,
423
+ "aria-controls": isOpen ? listboxId : undefined,
424
+ "aria-labelledby": label ? `${labelId} ${baseId}-value` : undefined,
425
+ onClick: ()=>isOpen ? closeList(false) : openList(),
426
+ onKeyDown: handleTriggerKeyDown,
337
427
  style: {
338
- width: '32px',
339
- height: '32px',
428
+ width: '100%',
429
+ display: 'flex',
430
+ alignItems: 'center',
431
+ justifyContent: 'space-between',
432
+ gap: '8px',
433
+ padding: '10px 12px',
340
434
  borderRadius: '8px',
341
- border: '1px solid rgba(15, 23, 42, 0.08)',
342
- backgroundColor: resolveCssColor(option.color),
343
- flexShrink: 0
344
- }
435
+ border: '1px solid var(--theme-elevation-200)',
436
+ backgroundColor: 'var(--theme-input-bg, var(--theme-elevation-0))',
437
+ color: 'var(--theme-elevation-900)',
438
+ fontSize: '14px',
439
+ fontWeight: 500,
440
+ cursor: 'pointer',
441
+ textAlign: 'left'
442
+ },
443
+ children: [
444
+ /*#__PURE__*/ _jsx("span", {
445
+ id: `${baseId}-value`,
446
+ style: {
447
+ minWidth: 0
448
+ },
449
+ children: selectedLabel
450
+ }),
451
+ /*#__PURE__*/ _jsx(ChevronDown, {
452
+ size: 14,
453
+ "aria-hidden": true,
454
+ style: {
455
+ flexShrink: 0,
456
+ transform: isOpen ? 'rotate(180deg)' : undefined
457
+ }
458
+ })
459
+ ]
345
460
  }),
346
- /*#__PURE__*/ _jsx("span", {
461
+ isOpen && /*#__PURE__*/ _jsx("div", {
462
+ ref: listboxRef,
463
+ id: listboxId,
464
+ role: "listbox",
465
+ tabIndex: -1,
466
+ "aria-labelledby": label ? labelId : undefined,
467
+ "aria-activedescendant": activeIndex >= 0 ? optionId(activeIndex) : undefined,
468
+ onKeyDown: handleListboxKeyDown,
347
469
  style: {
348
- fontSize: '13px',
349
- fontWeight: 600,
350
- color: 'var(--theme-elevation-800)'
470
+ position: 'absolute',
471
+ top: '100%',
472
+ left: 0,
473
+ right: 0,
474
+ marginTop: '4px',
475
+ backgroundColor: 'var(--theme-elevation-0)',
476
+ border: '1px solid var(--theme-elevation-200)',
477
+ borderRadius: '8px',
478
+ boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',
479
+ zIndex: 1000,
480
+ maxHeight: '300px',
481
+ overflowY: 'auto'
351
482
  },
352
- children: getOptionLabel(option)
483
+ children: options.map((option, index)=>{
484
+ const isSelected = option.value === selectedValue;
485
+ const isActive = index === activeIndex;
486
+ const optionColor = resolveCssColor(option.color);
487
+ return /*#__PURE__*/ _jsxs("div", {
488
+ id: optionId(index),
489
+ role: "option",
490
+ "aria-selected": isSelected,
491
+ onClick: ()=>chooseOption(index),
492
+ onPointerMove: ()=>setActiveIndex(index),
493
+ style: {
494
+ display: 'flex',
495
+ alignItems: 'center',
496
+ gap: '10px',
497
+ padding: '10px 12px',
498
+ backgroundColor: isActive ? 'var(--theme-elevation-100)' : isSelected ? 'var(--theme-elevation-50)' : 'transparent',
499
+ outline: isActive ? '2px solid var(--theme-elevation-800)' : undefined,
500
+ outlineOffset: '-2px',
501
+ color: 'var(--theme-elevation-900)',
502
+ fontSize: '14px',
503
+ fontWeight: isSelected ? 600 : 500,
504
+ cursor: 'pointer'
505
+ },
506
+ children: [
507
+ /*#__PURE__*/ _jsx("span", {
508
+ "aria-hidden": true,
509
+ style: {
510
+ width: '24px',
511
+ height: '24px',
512
+ borderRadius: '6px',
513
+ border: '1px solid var(--theme-elevation-150)',
514
+ backgroundColor: optionColor,
515
+ flexShrink: 0
516
+ }
517
+ }),
518
+ /*#__PURE__*/ _jsx("span", {
519
+ style: {
520
+ flex: 1
521
+ },
522
+ children: getOptionLabel(option)
523
+ }),
524
+ isSelected && /*#__PURE__*/ _jsx(Check, {
525
+ size: 14,
526
+ "aria-hidden": true
527
+ })
528
+ ]
529
+ }, option.value);
530
+ })
353
531
  })
354
532
  ]
355
- }, option.value);
356
- })
533
+ })
534
+ ]
357
535
  }),
358
- /*#__PURE__*/ _jsx("select", {
359
- id: path,
360
- value: selectedValue,
361
- onChange: (event)=>handleSelect(event.target.value),
536
+ selectedLabel && /*#__PURE__*/ _jsxs("div", {
362
537
  style: {
363
- display: 'none'
538
+ marginTop: '10px',
539
+ padding: '8px 12px',
540
+ borderRadius: '6px',
541
+ backgroundColor: 'var(--theme-elevation-50)',
542
+ fontSize: '12px',
543
+ color: 'var(--theme-elevation-700)'
364
544
  },
365
- children: options.map((option)=>/*#__PURE__*/ _jsx("option", {
366
- value: option.value,
367
- children: getOptionLabel(option)
368
- }, option.value))
545
+ children: [
546
+ /*#__PURE__*/ _jsx("span", {
547
+ style: {
548
+ fontWeight: 600
549
+ },
550
+ children: t.ui.selectedColor
551
+ }),
552
+ " ",
553
+ selectedLabel,
554
+ selectedColor && selectedColor !== '' && /*#__PURE__*/ _jsxs("span", {
555
+ style: {
556
+ marginLeft: '8px',
557
+ fontFamily: 'monospace',
558
+ color: 'var(--theme-elevation-600)'
559
+ },
560
+ children: [
561
+ "(",
562
+ selectedColor,
563
+ ")"
564
+ ]
565
+ })
566
+ ]
369
567
  })
370
568
  ]
371
569
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/fields/ThemeTokenSelectField.tsx"],"sourcesContent":["'use client'\n\nimport { useField } from '@payloadcms/ui'\nimport type { SelectFieldClientProps } from 'payload'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport { allThemePresets, fetchThemeConfiguration } from '../index.js'\nimport type { SiteThemeConfiguration } from '../payload-types.js'\nimport type { ThemePreset } from '../presets.js'\nimport type { FetchThemeConfigurationOptions } from '../types.js'\nimport { getAdminLanguage } from '../utils/getAdminLanguage.js'\nimport { inferTenant } from '../utils/inferTenant.js'\nimport { resolveThemeConfiguration } from '../utils/resolveThemeConfiguration.js'\n\ninterface ThemeColorOption {\n value: string\n label: string | { [key: string]: string | undefined }\n color: string\n description?: string\n}\n\nconst FALLBACK_TOKENS: ThemeColorOption[] = [\n {\n value: 'background',\n label: { en: 'Theme background', cs: 'Pozadí tématu' },\n color: 'var(--background)',\n },\n { value: 'card', label: { en: 'Card background', cs: 'Pozadí karty' }, color: 'var(--card)' },\n { value: 'muted', label: { en: 'Muted surface', cs: 'Tlumený povrch' }, color: 'var(--muted)' },\n {\n value: 'accent',\n label: { en: 'Accent surface', cs: 'Akcentní povrch' },\n color: 'var(--accent)',\n },\n {\n value: 'secondary',\n label: { en: 'Secondary surface', cs: 'Sekundární povrch' },\n color: 'var(--secondary)',\n },\n {\n value: 'primary',\n label: { en: 'Primary surface', cs: 'Primární povrch' },\n color: 'var(--primary)',\n },\n]\n\n// Use plugin-provided fetch helper which supports collection/global and options\n// This will use `collectionSlug`, `useGlobal`, tenant, locale, depth, draft, etc.\n// Accept fetch options from field.admin.custom to allow overrides in different setups.\n\nfunction buildOptionsFromConfiguration(\n configuration: SiteThemeConfiguration | Record<string, unknown> | null,\n themePresets: ThemePreset[],\n): ThemeColorOption[] {\n if (!configuration) {\n return FALLBACK_TOKENS\n }\n\n const resolved = resolveThemeConfiguration(configuration)\n const lightMode = resolved.lightMode ?? themePresets[0]?.lightMode ?? {}\n const orderedKeys: string[] = [\n 'background',\n 'card',\n 'muted',\n 'accent',\n 'secondary',\n 'primary',\n 'popover',\n ]\n\n const typedLightMode = lightMode as Record<string, string | null | undefined>\n\n const tokens = orderedKeys\n .map((key) => {\n const value = typedLightMode?.[key]\n if (typeof value !== 'string' || value.trim().length === 0) {\n return null\n }\n\n const labelMap: Record<string, { en: string; cs: string }> = {\n background: { en: 'Theme background', cs: 'Pozadí tématu' },\n card: { en: 'Card background', cs: 'Pozadí karty' },\n muted: { en: 'Muted surface', cs: 'Tlumený povrch' },\n accent: { en: 'Accent surface', cs: 'Akcentní povrch' },\n secondary: { en: 'Secondary surface', cs: 'Sekundární povrch' },\n primary: { en: 'Primary surface', cs: 'Primární povrch' },\n popover: { en: 'Popover surface', cs: 'Popover povrch' },\n }\n\n return {\n value: key,\n label: labelMap[key] ?? { en: key, cs: key },\n color: value,\n }\n })\n .filter((token): token is NonNullable<typeof token> => token !== null)\n\n return tokens.length > 0 ? tokens : FALLBACK_TOKENS\n}\n\nexport default function ThemeTokenSelectField(props: SelectFieldClientProps) {\n const { path, field } = props\n const { value, setValue } = useField<string>({ path })\n // Try to read themeConfiguration from the active form (Site Settings) first\n const { value: formThemeConfiguration } = useField<SiteThemeConfiguration | null>({\n path: 'themeConfiguration',\n })\n\n // Read tenant from the current form (sibling data) where present.\n // Prefer `tenant` field as it is populated correctly in most setups.\n const { value: formTenant } = useField<any>({ path: 'tenant' })\n\n const [options, setOptions] = useState<ThemeColorOption[]>(FALLBACK_TOKENS)\n const selectedValue = value || 'background'\n\n // Get themePresets from admin.custom or use defaults\n const themePresets = useMemo(() => {\n const customPresets = (field.admin?.custom as { themePresets?: ThemePreset[] })?.themePresets\n return customPresets && customPresets.length > 0 ? customPresets : allThemePresets\n }, [field.admin?.custom])\n\n useEffect(() => {\n // If the active form contains themeConfiguration (e.g., editing Site Settings), prefer it\n if (formThemeConfiguration) {\n setOptions(buildOptionsFromConfiguration(formThemeConfiguration, themePresets))\n return\n }\n\n let isMounted = true\n\n // Allow fields to override fetch options via admin.custom\n type CustomAdmin = {\n fetchThemeConfigurationOptions?: FetchThemeConfigurationOptions\n fetchOptions?: FetchThemeConfigurationOptions\n collectionSlug?: string\n useGlobal?: boolean\n tenantSlug?: string\n depth?: number\n locale?: string\n draft?: boolean\n queryParams?: Record<string, unknown>\n }\n\n const custom = field.admin?.custom as unknown as CustomAdmin\n\n // Prefer tenant ID from the current form (`formTenant`) first since editor fills the relation id.\n // If the relation is an object, prefer `id` over `slug` to avoid passing a human-readable slug when an id is available.\n // Then respect an explicit `admin.custom.tenantSlug` override, otherwise fall back to other heuristics.\n const tenantFromForm = (() => {\n if (typeof formTenant === 'string' && formTenant.trim()) return formTenant\n if (formTenant && typeof formTenant === 'object') {\n // Prefer id first\n return (formTenant.id ?? formTenant.slug ?? formTenant.value) as string | undefined\n }\n return undefined\n })()\n\n const inferredTenant = tenantFromForm ?? custom?.tenantSlug ?? inferTenant()\n\n // Determine admin language to pass as `locale` to fetch, if not provided\n const adminLang = getAdminLanguage()\n\n // Normalize fetch options so that even when callers provide an empty object (\"{}\"),\n // we still ensure `tenantSlug` and `locale` are set to sensible defaults (inferred/form/adminLang).\n const rawFetchOpts =\n custom?.fetchThemeConfigurationOptions ??\n custom?.fetchOptions ??\n (custom?.collectionSlug || typeof custom?.useGlobal !== 'undefined'\n ? ({\n collectionSlug: custom.collectionSlug,\n useGlobal: custom.useGlobal,\n depth: custom.depth,\n locale: custom.locale,\n draft: custom.draft,\n queryParams: custom.queryParams,\n } as unknown as FetchThemeConfigurationOptions)\n : undefined)\n\n // Always build a fetch options object so we can inject sensible defaults (tenantSlug, locale)\n // even when callers passed an empty object or no options at all.\n const fetchOpts: FetchThemeConfigurationOptions = {\n ...(rawFetchOpts ?? {}),\n tenantSlug: rawFetchOpts?.tenantSlug ?? inferredTenant,\n locale: rawFetchOpts?.locale ?? adminLang,\n }\n\n fetchThemeConfiguration(fetchOpts).then(async (configuration) => {\n if (!isMounted) return\n if (configuration) {\n setOptions(buildOptionsFromConfiguration(configuration, themePresets))\n return\n }\n\n // If nothing found and fetchOpts didn't explicitly request global, try fallback to global\n // This helps in setups where plugin created a standalone global (default slug 'appearance-settings')\n const explicitlyRequestedGlobal = !!(\n (fetchOpts as FetchThemeConfigurationOptions | undefined)?.useGlobal === true ||\n (fetchOpts as FetchThemeConfigurationOptions | undefined)?.collectionSlug ===\n 'appearance-settings'\n )\n\n if (!explicitlyRequestedGlobal) {\n try {\n // Prefer custom.collectionSlug if provided, otherwise try the default standalone slug\n const fallbackCollection = custom?.collectionSlug || 'appearance-settings'\n const fallbackOpts: FetchThemeConfigurationOptions = {\n useGlobal: true,\n collectionSlug: fallbackCollection,\n tenantSlug: inferredTenant,\n locale: custom?.locale ?? adminLang,\n }\n const fallbackConfig = await fetchThemeConfiguration(fallbackOpts)\n if (!isMounted) return\n if (fallbackConfig) {\n // Found theme config in global, use it\n setOptions(buildOptionsFromConfiguration(fallbackConfig, themePresets))\n return\n }\n } catch (e) {\n console.warn('[ThemeTokenSelectField] Fallback global fetch failed:', e)\n }\n }\n\n // final fallback: use empty tokens\n setOptions(buildOptionsFromConfiguration(configuration, themePresets))\n })\n\n return () => {\n isMounted = false\n }\n }, [themePresets, field.admin?.custom, formThemeConfiguration, formTenant])\n\n const handleSelect = useCallback(\n (nextValue: string) => {\n setValue(nextValue)\n },\n [setValue],\n )\n\n // Make admin language reactive so switching admin UI language updates labels\n const initialAdminLang = getAdminLanguage()\n const [adminLang, setAdminLang] = useState<string>(initialAdminLang)\n\n useEffect(() => {\n if (typeof document === 'undefined' || !('MutationObserver' in window)) return\n const el = document.documentElement\n const obs = new MutationObserver(() => {\n const next = getAdminLanguage()\n if (next !== adminLang) setAdminLang(next)\n })\n obs.observe(el, { attributes: true, attributeFilter: ['lang'] })\n return () => obs.disconnect()\n }, [adminLang])\n\n const label =\n typeof field.label === 'string'\n ? field.label\n : (field.label && (field.label as Record<string, string>)[adminLang]) ||\n field.label?.en ||\n field.label?.cs ||\n ''\n\n let description = ''\n if (typeof field.admin?.description === 'string') {\n description = field.admin.description\n } else if (field.admin?.description && typeof field.admin.description === 'object') {\n description =\n (field.admin.description as Record<string, string>)[adminLang] ||\n (field.admin.description as Record<string, string>).en ||\n (field.admin.description as Record<string, string>).cs ||\n ''\n }\n\n // Helper function to get label text from localized or string label\n const getOptionLabel = (option: ThemeColorOption): string => {\n if (typeof option.label === 'string') {\n return option.label\n }\n // Prefer current admin language, fallback to English/Czech, then any available language\n return (\n (option.label as Record<string, string>)[adminLang] ||\n option.label.en ||\n option.label.cs ||\n Object.values(option.label)[0] ||\n option.value\n )\n }\n\n // Resolve CSS variable colors (e.g., 'var(--primary)') to their computed values when possible\n const resolveCssColor = (color: string): string => {\n if (typeof window === 'undefined' || !color || !color.trim().startsWith('var(')) {\n return color\n }\n\n try {\n const match = color.trim().match(/var\\((--[^)]+)\\)/)\n if (!match) return color\n const varName = match[1]\n const computed = getComputedStyle(document.documentElement).getPropertyValue(varName).trim()\n return computed || color\n } catch (e) {\n return color\n }\n }\n\n return (\n <div className=\"field-type theme-token-select\">\n {label && (\n <label\n className=\"field-label\"\n htmlFor={path}\n style={{ display: 'block', marginBottom: '8px' }}\n >\n {label}\n {field.required && <span className=\"required\">*</span>}\n </label>\n )}\n\n {description && (\n <div\n className=\"field-description\"\n style={{ marginBottom: '12px', fontSize: '13px', color: 'var(--theme-elevation-500)' }}\n >\n {description}\n </div>\n )}\n\n <div\n className=\"token-grid\"\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(auto-fill, minmax(140px, 1fr))',\n gap: '10px',\n }}\n >\n {options.map((option) => {\n const isActive = option.value === selectedValue\n return (\n <button\n type=\"button\"\n key={option.value}\n onClick={() => handleSelect(option.value)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n padding: '10px 12px',\n borderRadius: '10px',\n border: isActive\n ? '2px solid var(--theme-success-500)'\n : '1px solid var(--theme-elevation-150)',\n backgroundColor: 'var(--theme-elevation-0)',\n boxShadow: isActive\n ? '0 10px 20px -10px rgba(59, 130, 246, 0.4)'\n : '0 1px 2px rgba(15, 23, 42, 0.08)',\n cursor: 'pointer',\n transition: 'border-color 0.2s ease, box-shadow 0.2s ease',\n }}\n >\n <span\n aria-hidden\n style={{\n width: '32px',\n height: '32px',\n borderRadius: '8px',\n border: '1px solid rgba(15, 23, 42, 0.08)',\n backgroundColor: resolveCssColor(option.color),\n flexShrink: 0,\n }}\n />\n <span\n style={{ fontSize: '13px', fontWeight: 600, color: 'var(--theme-elevation-800)' }}\n >\n {getOptionLabel(option)}\n </span>\n </button>\n )\n })}\n </div>\n\n <select\n id={path}\n value={selectedValue}\n onChange={(event) => handleSelect(event.target.value)}\n style={{ display: 'none' }}\n >\n {options.map((option) => (\n <option key={option.value} value={option.value}>\n {getOptionLabel(option)}\n </option>\n ))}\n </select>\n </div>\n )\n}\n"],"names":["useField","useCallback","useEffect","useMemo","useState","allThemePresets","fetchThemeConfiguration","getAdminLanguage","inferTenant","resolveThemeConfiguration","FALLBACK_TOKENS","value","label","en","cs","color","buildOptionsFromConfiguration","configuration","themePresets","resolved","lightMode","orderedKeys","typedLightMode","tokens","map","key","trim","length","labelMap","background","card","muted","accent","secondary","primary","popover","filter","token","ThemeTokenSelectField","props","path","field","setValue","formThemeConfiguration","formTenant","options","setOptions","selectedValue","customPresets","admin","custom","isMounted","tenantFromForm","id","slug","undefined","inferredTenant","tenantSlug","adminLang","rawFetchOpts","fetchThemeConfigurationOptions","fetchOptions","collectionSlug","useGlobal","depth","locale","draft","queryParams","fetchOpts","then","explicitlyRequestedGlobal","fallbackCollection","fallbackOpts","fallbackConfig","e","console","warn","handleSelect","nextValue","initialAdminLang","setAdminLang","document","window","el","documentElement","obs","MutationObserver","next","observe","attributes","attributeFilter","disconnect","description","getOptionLabel","option","Object","values","resolveCssColor","startsWith","match","varName","computed","getComputedStyle","getPropertyValue","div","className","htmlFor","style","display","marginBottom","required","span","fontSize","gridTemplateColumns","gap","isActive","button","type","onClick","alignItems","padding","borderRadius","border","backgroundColor","boxShadow","cursor","transition","aria-hidden","width","height","flexShrink","fontWeight","select","onChange","event","target"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/fields/ThemeTokenSelectField.tsx"],"sourcesContent":["'use client'\n\nimport { useField } from '@payloadcms/ui'\nimport type { SelectFieldClientProps } from 'payload'\nimport { Check, ChevronDown } from 'lucide-react'\nimport { useCallback, useEffect, useId, useMemo, useRef, useState, type KeyboardEvent } from 'react'\nimport { allThemePresets, fetchThemeConfiguration } from '../index.js'\nimport type { SiteThemeConfiguration } from '../payload-types.js'\nimport type { ThemePreset } from '../presets.js'\nimport type { FetchThemeConfigurationOptions } from '../types.js'\nimport { useThemeLanguage, useThemeTranslations } from '../hooks/useThemeTranslations.js'\nimport { inferTenant } from '../utils/inferTenant.js'\nimport { resolveThemeConfiguration } from '../utils/resolveThemeConfiguration.js'\n\ninterface ThemeColorOption {\n value: string\n label: string | { [key: string]: string | undefined }\n color: string\n description?: string\n}\n\nconst FALLBACK_TOKENS: ThemeColorOption[] = [\n {\n value: 'background',\n label: { en: 'Theme background', cs: 'Pozadí motivu' },\n color: 'var(--background)',\n },\n { value: 'card', label: { en: 'Card background', cs: 'Pozadí karty' }, color: 'var(--card)' },\n { value: 'muted', label: { en: 'Muted surface', cs: 'Tlumený povrch' }, color: 'var(--muted)' },\n {\n value: 'accent',\n label: { en: 'Accent surface', cs: 'Akcentní povrch' },\n color: 'var(--accent)',\n },\n {\n value: 'secondary',\n label: { en: 'Secondary surface', cs: 'Sekundární povrch' },\n color: 'var(--secondary)',\n },\n {\n value: 'primary',\n label: { en: 'Primary surface', cs: 'Primární povrch' },\n color: 'var(--primary)',\n },\n]\n\n// Use plugin-provided fetch helper which supports collection/global and options\n// This will use `collectionSlug`, `useGlobal`, tenant, locale, depth, draft, etc.\n// Accept fetch options from field.admin.custom to allow overrides in different setups.\n\nfunction buildOptionsFromConfiguration(\n configuration: SiteThemeConfiguration | Record<string, unknown> | null,\n themePresets: ThemePreset[],\n): ThemeColorOption[] {\n if (!configuration) {\n return FALLBACK_TOKENS\n }\n\n const resolved = resolveThemeConfiguration(configuration)\n const lightMode = resolved.lightMode ?? themePresets[0]?.lightMode ?? {}\n const orderedKeys: string[] = [\n 'background',\n 'card',\n 'muted',\n 'accent',\n 'secondary',\n 'primary',\n 'popover',\n ]\n\n const typedLightMode = lightMode as Record<string, string | null | undefined>\n\n const tokens = orderedKeys\n .map((key) => {\n const value = typedLightMode?.[key]\n if (typeof value !== 'string' || value.trim().length === 0) {\n return null\n }\n\n const labelMap: Record<string, { en: string; cs: string }> = {\n background: { en: 'Theme background', cs: 'Pozadí motivu' },\n card: { en: 'Card background', cs: 'Pozadí karty' },\n muted: { en: 'Muted surface', cs: 'Tlumený povrch' },\n accent: { en: 'Accent surface', cs: 'Akcentní povrch' },\n secondary: { en: 'Secondary surface', cs: 'Sekundární povrch' },\n primary: { en: 'Primary surface', cs: 'Primární povrch' },\n popover: { en: 'Popover surface', cs: 'Popover povrch' },\n }\n\n return {\n value: key,\n label: labelMap[key] ?? { en: key, cs: key },\n color: value,\n }\n })\n .filter((token): token is NonNullable<typeof token> => token !== null)\n\n return tokens.length > 0 ? tokens : FALLBACK_TOKENS\n}\n\nexport default function ThemeTokenSelectField(props: SelectFieldClientProps) {\n const { path, field } = props\n const { value, setValue } = useField<string>({ path })\n // Try to read themeConfiguration from the active form (Site Settings) first\n const { value: formThemeConfiguration } = useField<SiteThemeConfiguration | null>({\n path: 'themeConfiguration',\n })\n\n // Read tenant from the current form (sibling data) where present.\n // Prefer `tenant` field as it is populated correctly in most setups.\n const { value: formTenant } = useField<any>({ path: 'tenant' })\n\n const [options, setOptions] = useState<ThemeColorOption[]>(FALLBACK_TOKENS)\n const selectedValue = value || 'background'\n // Active Payload admin language (reactive via Payload's i18n context).\n const adminLang = useThemeLanguage()\n const t = useThemeTranslations()\n\n // Get themePresets from admin.custom or use defaults\n const themePresets = useMemo(() => {\n const customPresets = (field.admin?.custom as { themePresets?: ThemePreset[] })?.themePresets\n return customPresets && customPresets.length > 0 ? customPresets : allThemePresets\n }, [field.admin?.custom])\n\n useEffect(() => {\n // If the active form contains themeConfiguration (e.g., editing Site Settings), prefer it\n if (formThemeConfiguration) {\n setOptions(buildOptionsFromConfiguration(formThemeConfiguration, themePresets))\n return\n }\n\n const controller = new AbortController()\n\n // Allow fields to override fetch options via admin.custom\n type CustomAdmin = {\n fetchThemeConfigurationOptions?: FetchThemeConfigurationOptions\n fetchOptions?: FetchThemeConfigurationOptions\n collectionSlug?: string\n useGlobal?: boolean\n tenantSlug?: string\n depth?: number\n locale?: string\n draft?: boolean\n queryParams?: Record<string, string | number | boolean>\n }\n\n const custom = field.admin?.custom as unknown as CustomAdmin\n\n // Prefer tenant ID from the current form (`formTenant`) first since editor fills the relation id.\n // If the relation is an object, prefer `id` over `slug` to avoid passing a human-readable slug when an id is available.\n // Then respect an explicit `admin.custom.tenantSlug` override, otherwise fall back to other heuristics.\n const tenantFromForm = (() => {\n if (typeof formTenant === 'string' && formTenant.trim()) return formTenant\n if (formTenant && typeof formTenant === 'object') {\n // Prefer id first\n return (formTenant.id ?? formTenant.slug ?? formTenant.value) as string | undefined\n }\n return undefined\n })()\n\n const inferredTenant = tenantFromForm ?? custom?.tenantSlug ?? inferTenant()\n\n // Normalize fetch options so that even when callers provide an empty object (\"{}\"),\n // we still ensure `tenantSlug` and `locale` are set to sensible defaults (inferred/form/adminLang).\n const rawFetchOpts =\n custom?.fetchThemeConfigurationOptions ??\n custom?.fetchOptions ??\n (custom?.collectionSlug || typeof custom?.useGlobal !== 'undefined'\n ? ({\n collectionSlug: custom.collectionSlug,\n useGlobal: custom.useGlobal,\n depth: custom.depth,\n locale: custom.locale,\n draft: custom.draft,\n queryParams: custom.queryParams,\n } as unknown as FetchThemeConfigurationOptions)\n : undefined)\n\n // Always build a fetch options object so we can inject sensible defaults (tenantSlug, locale)\n // even when callers passed an empty object or no options at all.\n const fetchOpts: FetchThemeConfigurationOptions = {\n ...(rawFetchOpts ?? {}),\n tenantSlug: rawFetchOpts?.tenantSlug ?? inferredTenant,\n locale: rawFetchOpts?.locale ?? adminLang,\n signal: controller.signal,\n }\n\n fetchThemeConfiguration(fetchOpts).then(async (configuration) => {\n if (controller.signal.aborted) return\n if (configuration) {\n setOptions(buildOptionsFromConfiguration(configuration, themePresets))\n return\n }\n\n // If nothing found and fetchOpts didn't explicitly request global, try fallback to global\n // This helps in setups where plugin created a standalone global (default slug 'appearance-settings')\n const explicitlyRequestedGlobal = !!(\n (fetchOpts as FetchThemeConfigurationOptions | undefined)?.useGlobal === true ||\n (fetchOpts as FetchThemeConfigurationOptions | undefined)?.collectionSlug ===\n 'appearance-settings'\n )\n\n if (!explicitlyRequestedGlobal) {\n try {\n // Prefer custom.collectionSlug if provided, otherwise try the default standalone slug\n const fallbackCollection = custom?.collectionSlug || 'appearance-settings'\n const fallbackOpts: FetchThemeConfigurationOptions = {\n useGlobal: true,\n collectionSlug: fallbackCollection,\n tenantSlug: inferredTenant,\n locale: custom?.locale ?? adminLang,\n signal: controller.signal,\n }\n const fallbackConfig = await fetchThemeConfiguration(fallbackOpts)\n if (controller.signal.aborted) return\n if (fallbackConfig) {\n // Found theme config in global, use it\n setOptions(buildOptionsFromConfiguration(fallbackConfig, themePresets))\n return\n }\n } catch (e) {\n console.warn('[ThemeTokenSelectField] Fallback global fetch failed:', e)\n }\n }\n\n // final fallback: use empty tokens\n setOptions(buildOptionsFromConfiguration(configuration, themePresets))\n })\n\n return () => {\n controller.abort()\n }\n }, [themePresets, field.admin?.custom, formThemeConfiguration, formTenant, adminLang])\n\n const handleSelect = useCallback(\n (nextValue: string) => {\n setValue(nextValue)\n },\n [setValue],\n )\n\n const label =\n typeof field.label === 'string'\n ? field.label\n : (field.label && (field.label as Record<string, string>)[adminLang]) ||\n field.label?.en ||\n field.label?.cs ||\n ''\n\n let description = ''\n if (typeof field.admin?.description === 'string') {\n description = field.admin.description\n } else if (field.admin?.description && typeof field.admin.description === 'object') {\n description =\n (field.admin.description as Record<string, string>)[adminLang] ||\n (field.admin.description as Record<string, string>).en ||\n (field.admin.description as Record<string, string>).cs ||\n ''\n }\n\n // Helper function to get label text from localized or string label\n const getOptionLabel = (option: ThemeColorOption): string => {\n if (typeof option.label === 'string') {\n return option.label\n }\n // Prefer current admin language, fallback to English/Czech, then any available language\n return (\n (option.label as Record<string, string>)[adminLang] ||\n option.label.en ||\n option.label.cs ||\n Object.values(option.label)[0] ||\n option.value\n )\n }\n\n // Resolve CSS variable colors (e.g., 'var(--primary)') to their computed values when possible\n const resolveCssColor = (color: string): string => {\n if (typeof window === 'undefined' || !color || !color.trim().startsWith('var(')) {\n return color\n }\n\n try {\n const match = color.trim().match(/var\\((--[^)]+)\\)/)\n if (!match) return color\n const varName = match[1]\n const computed = getComputedStyle(document.documentElement).getPropertyValue(varName).trim()\n return computed || color\n } catch (e) {\n return color\n }\n }\n\n const selectedIndex = options.findIndex((opt) => opt.value === selectedValue)\n const selectedOption = selectedIndex >= 0 ? options[selectedIndex] : undefined\n const selectedColor = selectedOption ? resolveCssColor(selectedOption.color) : ''\n const selectedLabel = selectedOption ? getOptionLabel(selectedOption) : ''\n const [isOpen, setIsOpen] = useState(false)\n const [activeIndex, setActiveIndex] = useState(-1)\n const baseId = useId()\n const labelId = `${baseId}-label`\n const listboxId = `${baseId}-listbox`\n const optionId = (index: number) => `${baseId}-option-${index}`\n const containerRef = useRef<HTMLDivElement>(null)\n const triggerRef = useRef<HTMLButtonElement>(null)\n const listboxRef = useRef<HTMLDivElement>(null)\n\n const openList = (index = selectedIndex >= 0 ? selectedIndex : 0) => {\n setActiveIndex(index)\n setIsOpen(true)\n }\n\n const closeList = useCallback((restoreFocus: boolean) => {\n setIsOpen(false)\n if (restoreFocus) triggerRef.current?.focus()\n }, [])\n\n const chooseOption = (index: number) => {\n const option = options[index]\n if (!option) return\n handleSelect(option.value)\n closeList(true)\n }\n\n useEffect(() => {\n if (!isOpen) return\n listboxRef.current?.focus()\n const handlePointerOutside = (event: PointerEvent) => {\n if (!containerRef.current?.contains(event.target as Node)) closeList(false)\n }\n document.addEventListener('pointerdown', handlePointerOutside)\n return () => document.removeEventListener('pointerdown', handlePointerOutside)\n }, [isOpen, closeList])\n\n useEffect(() => {\n if (!isOpen || activeIndex < 0) return\n listboxRef.current\n ?.querySelector<HTMLElement>(`#${CSS.escape(optionId(activeIndex))}`)\n ?.scrollIntoView({ block: 'nearest' })\n }, [isOpen, activeIndex])\n\n const handleTriggerKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n if (['ArrowDown', 'ArrowUp', 'Enter', ' '].includes(event.key)) {\n event.preventDefault()\n openList()\n }\n }\n\n const handleListboxKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const last = options.length - 1\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault()\n setActiveIndex((i) => Math.min(last, i + 1))\n break\n case 'ArrowUp':\n event.preventDefault()\n setActiveIndex((i) => Math.max(0, i - 1))\n break\n case 'Home':\n event.preventDefault()\n setActiveIndex(0)\n break\n case 'End':\n event.preventDefault()\n setActiveIndex(last)\n break\n case 'Enter':\n case ' ':\n event.preventDefault()\n chooseOption(activeIndex)\n break\n case 'Escape':\n event.preventDefault()\n event.stopPropagation()\n closeList(true)\n break\n case 'Tab':\n closeList(false)\n break\n }\n }\n\n return (\n <div className=\"field-type theme-token-select\">\n {label && (\n <div className=\"field-label\" id={labelId} style={{ display: 'block', marginBottom: '8px' }}>\n {label}\n {field.required && <span className=\"required\">*</span>}\n </div>\n )}\n\n {description && (\n <div\n className=\"field-description\"\n style={{ marginBottom: '12px', fontSize: '13px', color: 'var(--theme-elevation-600)' }}\n >\n {description}\n </div>\n )}\n\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '12px',\n position: 'relative',\n }}\n >\n {/* Color preview swatch */}\n <div\n aria-hidden\n style={{\n width: '40px',\n height: '40px',\n borderRadius: '8px',\n border: '2px solid var(--theme-elevation-200)',\n backgroundColor: selectedColor,\n flexShrink: 0,\n boxShadow: selectedColor\n ? '0 2px 8px rgba(0, 0, 0, 0.1)'\n : 'inset 0 1px 2px rgba(0, 0, 0, 0.05)',\n }}\n />\n\n {/* Select-only combobox (WAI-ARIA): button trigger + keyboard listbox */}\n <div ref={containerRef} style={{ flex: 1, minWidth: 0, position: 'relative' }}>\n <button\n ref={triggerRef}\n id={path}\n type=\"button\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-expanded={isOpen}\n aria-controls={isOpen ? listboxId : undefined}\n aria-labelledby={label ? `${labelId} ${baseId}-value` : undefined}\n onClick={() => (isOpen ? closeList(false) : openList())}\n onKeyDown={handleTriggerKeyDown}\n style={{\n width: '100%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: '8px',\n padding: '10px 12px',\n borderRadius: '8px',\n border: '1px solid var(--theme-elevation-200)',\n backgroundColor: 'var(--theme-input-bg, var(--theme-elevation-0))',\n color: 'var(--theme-elevation-900)',\n fontSize: '14px',\n fontWeight: 500,\n cursor: 'pointer',\n textAlign: 'left',\n }}\n >\n <span id={`${baseId}-value`} style={{ minWidth: 0 }}>\n {selectedLabel}\n </span>\n <ChevronDown\n size={14}\n aria-hidden\n style={{ flexShrink: 0, transform: isOpen ? 'rotate(180deg)' : undefined }}\n />\n </button>\n\n {isOpen && (\n <div\n ref={listboxRef}\n id={listboxId}\n role=\"listbox\"\n tabIndex={-1}\n aria-labelledby={label ? labelId : undefined}\n aria-activedescendant={activeIndex >= 0 ? optionId(activeIndex) : undefined}\n onKeyDown={handleListboxKeyDown}\n style={{\n position: 'absolute',\n top: '100%',\n left: 0,\n right: 0,\n marginTop: '4px',\n backgroundColor: 'var(--theme-elevation-0)',\n border: '1px solid var(--theme-elevation-200)',\n borderRadius: '8px',\n boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',\n zIndex: 1000,\n maxHeight: '300px',\n overflowY: 'auto',\n }}\n >\n {options.map((option, index) => {\n const isSelected = option.value === selectedValue\n const isActive = index === activeIndex\n const optionColor = resolveCssColor(option.color)\n return (\n <div\n key={option.value}\n id={optionId(index)}\n role=\"option\"\n aria-selected={isSelected}\n onClick={() => chooseOption(index)}\n onPointerMove={() => setActiveIndex(index)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n padding: '10px 12px',\n backgroundColor: isActive\n ? 'var(--theme-elevation-100)'\n : isSelected\n ? 'var(--theme-elevation-50)'\n : 'transparent',\n outline: isActive ? '2px solid var(--theme-elevation-800)' : undefined,\n outlineOffset: '-2px',\n color: 'var(--theme-elevation-900)',\n fontSize: '14px',\n fontWeight: isSelected ? 600 : 500,\n cursor: 'pointer',\n }}\n >\n <span\n aria-hidden\n style={{\n width: '24px',\n height: '24px',\n borderRadius: '6px',\n border: '1px solid var(--theme-elevation-150)',\n backgroundColor: optionColor,\n flexShrink: 0,\n }}\n />\n <span style={{ flex: 1 }}>{getOptionLabel(option)}</span>\n {isSelected && <Check size={14} aria-hidden />}\n </div>\n )\n })}\n </div>\n )}\n </div>\n </div>\n\n {selectedLabel && (\n <div\n style={{\n marginTop: '10px',\n padding: '8px 12px',\n borderRadius: '6px',\n backgroundColor: 'var(--theme-elevation-50)',\n fontSize: '12px',\n color: 'var(--theme-elevation-700)',\n }}\n >\n <span style={{ fontWeight: 600 }}>{t.ui.selectedColor}</span> {selectedLabel}\n {selectedColor && selectedColor !== '' && (\n <span style={{ marginLeft: '8px', fontFamily: 'monospace', color: 'var(--theme-elevation-600)' }}>\n ({selectedColor})\n </span>\n )}\n </div>\n )}\n </div>\n )\n}\n\n"],"names":["useField","Check","ChevronDown","useCallback","useEffect","useId","useMemo","useRef","useState","allThemePresets","fetchThemeConfiguration","useThemeLanguage","useThemeTranslations","inferTenant","resolveThemeConfiguration","FALLBACK_TOKENS","value","label","en","cs","color","buildOptionsFromConfiguration","configuration","themePresets","resolved","lightMode","orderedKeys","typedLightMode","tokens","map","key","trim","length","labelMap","background","card","muted","accent","secondary","primary","popover","filter","token","ThemeTokenSelectField","props","path","field","setValue","formThemeConfiguration","formTenant","options","setOptions","selectedValue","adminLang","t","customPresets","admin","custom","controller","AbortController","tenantFromForm","id","slug","undefined","inferredTenant","tenantSlug","rawFetchOpts","fetchThemeConfigurationOptions","fetchOptions","collectionSlug","useGlobal","depth","locale","draft","queryParams","fetchOpts","signal","then","aborted","explicitlyRequestedGlobal","fallbackCollection","fallbackOpts","fallbackConfig","e","console","warn","abort","handleSelect","nextValue","description","getOptionLabel","option","Object","values","resolveCssColor","window","startsWith","match","varName","computed","getComputedStyle","document","documentElement","getPropertyValue","selectedIndex","findIndex","opt","selectedOption","selectedColor","selectedLabel","isOpen","setIsOpen","activeIndex","setActiveIndex","baseId","labelId","listboxId","optionId","index","containerRef","triggerRef","listboxRef","openList","closeList","restoreFocus","current","focus","chooseOption","handlePointerOutside","event","contains","target","addEventListener","removeEventListener","querySelector","CSS","escape","scrollIntoView","block","handleTriggerKeyDown","includes","preventDefault","handleListboxKeyDown","last","i","Math","min","max","stopPropagation","div","className","style","display","marginBottom","required","span","fontSize","alignItems","gap","position","aria-hidden","width","height","borderRadius","border","backgroundColor","flexShrink","boxShadow","ref","flex","minWidth","button","type","role","aria-haspopup","aria-expanded","aria-controls","aria-labelledby","onClick","onKeyDown","justifyContent","padding","fontWeight","cursor","textAlign","size","transform","tabIndex","aria-activedescendant","top","left","right","marginTop","zIndex","maxHeight","overflowY","isSelected","isActive","optionColor","aria-selected","onPointerMove","outline","outlineOffset","ui","marginLeft","fontFamily"],"mappings":"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"}