@kilivi/payloadcms-theme-management 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +346 -845
- package/dist/components/AppearanceSessionControls.d.ts +15 -0
- package/dist/components/AppearanceSessionControls.d.ts.map +1 -0
- package/dist/components/AppearanceSessionControls.js +152 -0
- package/dist/components/AppearanceSessionControls.js.map +1 -0
- package/dist/components/ColorModeToggle.css +42 -0
- package/dist/components/ColorModeToggle.d.ts +40 -0
- package/dist/components/ColorModeToggle.d.ts.map +1 -0
- package/dist/components/ColorModeToggle.js +111 -0
- package/dist/components/ColorModeToggle.js.map +1 -0
- package/dist/components/ServerThemeInjector.d.ts +13 -1
- package/dist/components/ServerThemeInjector.d.ts.map +1 -1
- package/dist/components/ServerThemeInjector.js +65 -15
- package/dist/components/ServerThemeInjector.js.map +1 -1
- package/dist/components/ThemeLivePreviewSync.d.ts +4 -0
- package/dist/components/ThemeLivePreviewSync.d.ts.map +1 -1
- package/dist/components/ThemeLivePreviewSync.js +28 -4
- package/dist/components/ThemeLivePreviewSync.js.map +1 -1
- package/dist/components/ThemeSwitcher.d.ts +36 -0
- package/dist/components/ThemeSwitcher.d.ts.map +1 -0
- package/dist/components/ThemeSwitcher.js +89 -0
- package/dist/components/ThemeSwitcher.js.map +1 -0
- package/dist/components/typographyPreviewUtils.d.ts +5 -0
- package/dist/components/typographyPreviewUtils.d.ts.map +1 -1
- package/dist/components/typographyPreviewUtils.js +24 -11
- package/dist/components/typographyPreviewUtils.js.map +1 -1
- package/dist/constants/devicePreviews.d.ts +35 -0
- package/dist/constants/devicePreviews.d.ts.map +1 -0
- package/dist/constants/devicePreviews.js +43 -0
- package/dist/constants/devicePreviews.js.map +1 -0
- package/dist/constants/themeFonts.d.ts +94 -168
- package/dist/constants/themeFonts.d.ts.map +1 -1
- package/dist/constants/themeFonts.js +260 -140
- package/dist/constants/themeFonts.js.map +1 -1
- package/dist/endpoints/themeFonts.d.ts +5 -0
- package/dist/endpoints/themeFonts.d.ts.map +1 -0
- package/dist/endpoints/themeFonts.js +138 -0
- package/dist/endpoints/themeFonts.js.map +1 -0
- package/dist/extended-presets.d.ts +0 -4
- package/dist/extended-presets.d.ts.map +1 -1
- package/dist/extended-presets.js +1 -18
- package/dist/extended-presets.js.map +1 -1
- package/dist/extended-themes.d.ts.map +1 -1
- package/dist/extended-themes.js +428 -0
- package/dist/extended-themes.js.map +1 -1
- package/dist/fields/AccessibilityAuditField.d.ts +2 -0
- package/dist/fields/AccessibilityAuditField.d.ts.map +1 -0
- package/dist/fields/AccessibilityAuditField.js +303 -0
- package/dist/fields/AccessibilityAuditField.js.map +1 -0
- package/dist/fields/AppearancePreviewField.d.ts +2 -0
- package/dist/fields/AppearancePreviewField.d.ts.map +1 -0
- package/dist/fields/AppearancePreviewField.js +826 -0
- package/dist/fields/AppearancePreviewField.js.map +1 -0
- package/dist/fields/ColorPickerField.d.ts.map +1 -1
- package/dist/fields/ColorPickerField.js +89 -85
- package/dist/fields/ColorPickerField.js.map +1 -1
- package/dist/fields/FontSelectField.css +155 -0
- package/dist/fields/FontSelectField.d.ts +8 -0
- package/dist/fields/FontSelectField.d.ts.map +1 -1
- package/dist/fields/FontSelectField.js +223 -188
- package/dist/fields/FontSelectField.js.map +1 -1
- package/dist/fields/PaletteGeneratorField.d.ts +7 -0
- package/dist/fields/PaletteGeneratorField.d.ts.map +1 -0
- package/dist/fields/PaletteGeneratorField.js +327 -0
- package/dist/fields/PaletteGeneratorField.js.map +1 -0
- package/dist/fields/StylePresetField.d.ts +3 -0
- package/dist/fields/StylePresetField.d.ts.map +1 -0
- package/dist/fields/StylePresetField.js +463 -0
- package/dist/fields/StylePresetField.js.map +1 -0
- package/dist/fields/ThemeColorPickerField.css +115 -35
- package/dist/fields/ThemeColorPickerField.d.ts.map +1 -1
- package/dist/fields/ThemeColorPickerField.js +204 -70
- package/dist/fields/ThemeColorPickerField.js.map +1 -1
- package/dist/fields/ThemeExportField.d.ts +6 -0
- package/dist/fields/ThemeExportField.d.ts.map +1 -0
- package/dist/fields/ThemeExportField.js +202 -0
- package/dist/fields/ThemeExportField.js.map +1 -0
- package/dist/fields/ThemePresetImportField.d.ts.map +1 -1
- package/dist/fields/ThemePresetImportField.js +56 -25
- package/dist/fields/ThemePresetImportField.js.map +1 -1
- package/dist/fields/ThemePreviewField.css +444 -5
- package/dist/fields/ThemePreviewField.d.ts.map +1 -1
- package/dist/fields/ThemePreviewField.js +265 -170
- package/dist/fields/ThemePreviewField.js.map +1 -1
- package/dist/fields/ThemeTokenSelectField.d.ts.map +1 -1
- package/dist/fields/ThemeTokenSelectField.js +278 -80
- package/dist/fields/ThemeTokenSelectField.js.map +1 -1
- package/dist/fields/colorFieldHelpers.d.ts +90 -0
- package/dist/fields/colorFieldHelpers.d.ts.map +1 -0
- package/dist/fields/colorFieldHelpers.js +133 -0
- package/dist/fields/colorFieldHelpers.js.map +1 -0
- package/dist/fields/colorModeFields.d.ts +1 -1
- package/dist/fields/colorModeFields.d.ts.map +1 -1
- package/dist/fields/colorModeFields.js +49 -7
- package/dist/fields/colorModeFields.js.map +1 -1
- package/dist/fields/themeConfigurationField.d.ts +8 -1
- package/dist/fields/themeConfigurationField.d.ts.map +1 -1
- package/dist/fields/themeConfigurationField.js +1209 -228
- package/dist/fields/themeConfigurationField.js.map +1 -1
- package/dist/globals/ThemeSettings/FontPicker/FontPreview.d.ts.map +1 -1
- package/dist/globals/ThemeSettings/FontPicker/FontPreview.js +8 -4
- package/dist/globals/ThemeSettings/FontPicker/FontPreview.js.map +1 -1
- package/dist/globals/ThemeSettings/FontPicker/index.d.ts.map +1 -1
- package/dist/globals/ThemeSettings/FontPicker/index.js +81 -26
- package/dist/globals/ThemeSettings/FontPicker/index.js.map +1 -1
- package/dist/globals/ThemeSettings/FontPicker/styles.css +98 -41
- package/dist/globals/ThemeSettings/FontPicker/translations.d.ts +6 -0
- package/dist/globals/ThemeSettings/FontPicker/translations.d.ts.map +1 -1
- package/dist/globals/ThemeSettings/FontPicker/translations.js +14 -2
- package/dist/globals/ThemeSettings/FontPicker/translations.js.map +1 -1
- package/dist/globals/ThemeSettings/config.d.ts.map +1 -1
- package/dist/globals/ThemeSettings/config.js +76 -79
- package/dist/globals/ThemeSettings/config.js.map +1 -1
- package/dist/globals/ThemeSettings/fields/FontLoadingGuideField.d.ts.map +1 -1
- package/dist/globals/ThemeSettings/fields/FontLoadingGuideField.js +63 -62
- package/dist/globals/ThemeSettings/fields/FontLoadingGuideField.js.map +1 -1
- package/dist/globals/ThemeSettings/fields/TypographyInfoField.d.ts.map +1 -1
- package/dist/globals/ThemeSettings/fields/TypographyInfoField.js +22 -25
- package/dist/globals/ThemeSettings/fields/TypographyInfoField.js.map +1 -1
- package/dist/hooks/useAppearanceSession.d.ts +50 -0
- package/dist/hooks/useAppearanceSession.d.ts.map +1 -0
- package/dist/hooks/useAppearanceSession.js +91 -0
- package/dist/hooks/useAppearanceSession.js.map +1 -0
- package/dist/hooks/useNativeLivePreview.d.ts +15 -0
- package/dist/hooks/useNativeLivePreview.d.ts.map +1 -0
- package/dist/hooks/useNativeLivePreview.js +18 -0
- package/dist/hooks/useNativeLivePreview.js.map +1 -0
- package/dist/hooks/useThemeFonts.d.ts +10 -0
- package/dist/hooks/useThemeFonts.d.ts.map +1 -0
- package/dist/hooks/useThemeFonts.js +36 -0
- package/dist/hooks/useThemeFonts.js.map +1 -0
- package/dist/hooks/useThemeTranslations.d.ts +13 -0
- package/dist/hooks/useThemeTranslations.d.ts.map +1 -0
- package/dist/hooks/useThemeTranslations.js +22 -0
- package/dist/hooks/useThemeTranslations.js.map +1 -0
- package/dist/i18n.d.ts +53 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +53 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +13 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +59 -29
- package/dist/index.js.map +1 -1
- package/dist/next-fonts.d.ts +3 -0
- package/dist/next-fonts.d.ts.map +1 -0
- package/dist/next-fonts.js +360 -0
- package/dist/next-fonts.js.map +1 -0
- package/dist/payload-types.d.ts +34 -6
- package/dist/payload-types.d.ts.map +1 -1
- package/dist/payload-types.js.map +1 -1
- package/dist/presets.d.ts +14 -0
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js.map +1 -1
- package/dist/providers/Theme/index.d.ts.map +1 -1
- package/dist/providers/Theme/index.js +75 -11
- package/dist/providers/Theme/index.js.map +1 -1
- package/dist/providers/Theme/themeConfig.d.ts.map +1 -1
- package/dist/providers/Theme/themeConfig.js +104 -0
- package/dist/providers/Theme/themeConfig.js.map +1 -1
- package/dist/providers/Theme/types.d.ts +1 -1
- package/dist/providers/Theme/types.d.ts.map +1 -1
- package/dist/providers/Theme/types.js +10 -1
- package/dist/providers/Theme/types.js.map +1 -1
- package/dist/style-presets.d.ts +75 -0
- package/dist/style-presets.d.ts.map +1 -0
- package/dist/style-presets.js +738 -0
- package/dist/style-presets.js.map +1 -0
- package/dist/translations.d.ts +164 -1
- package/dist/translations.d.ts.map +1 -1
- package/dist/translations.js +320 -9
- package/dist/translations.js.map +1 -1
- package/dist/tweakcn-special-themes.d.ts.map +1 -1
- package/dist/tweakcn-special-themes.js +585 -9
- package/dist/tweakcn-special-themes.js.map +1 -1
- package/dist/types/css.d.js +3 -0
- package/dist/types/css.d.js.map +1 -0
- package/dist/types.d.ts +26 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utilities/getThemeSettings.d.ts.map +1 -1
- package/dist/utilities/getThemeSettings.js +2 -14
- package/dist/utilities/getThemeSettings.js.map +1 -1
- package/dist/utils/contrast.d.ts +63 -0
- package/dist/utils/contrast.d.ts.map +1 -0
- package/dist/utils/contrast.js +158 -0
- package/dist/utils/contrast.js.map +1 -0
- package/dist/utils/exportTokens.d.ts +30 -0
- package/dist/utils/exportTokens.d.ts.map +1 -0
- package/dist/utils/exportTokens.js +183 -0
- package/dist/utils/exportTokens.js.map +1 -0
- package/dist/utils/generatePalette.d.ts +46 -0
- package/dist/utils/generatePalette.d.ts.map +1 -0
- package/dist/utils/generatePalette.js +127 -0
- package/dist/utils/generatePalette.js.map +1 -0
- package/dist/utils/generateThemeCSS.d.ts.map +1 -1
- package/dist/utils/generateThemeCSS.js +2 -40
- package/dist/utils/generateThemeCSS.js.map +1 -1
- package/dist/utils/livePreviewThemeRuntime.d.ts +22 -3
- package/dist/utils/livePreviewThemeRuntime.d.ts.map +1 -1
- package/dist/utils/livePreviewThemeRuntime.js +48 -15
- package/dist/utils/livePreviewThemeRuntime.js.map +1 -1
- package/dist/utils/localizedText.d.ts +8 -0
- package/dist/utils/localizedText.d.ts.map +1 -0
- package/dist/utils/localizedText.js +21 -0
- package/dist/utils/localizedText.js.map +1 -0
- package/dist/utils/resolveThemeConfiguration.d.ts +60 -1
- package/dist/utils/resolveThemeConfiguration.d.ts.map +1 -1
- package/dist/utils/resolveThemeConfiguration.js +53 -13
- package/dist/utils/resolveThemeConfiguration.js.map +1 -1
- package/dist/utils/themeColors.d.ts +3 -0
- package/dist/utils/themeColors.d.ts.map +1 -1
- package/dist/utils/themeColors.js +30 -1
- package/dist/utils/themeColors.js.map +1 -1
- package/dist/utils/themeHtmlAttributes.d.ts +32 -12
- package/dist/utils/themeHtmlAttributes.d.ts.map +1 -1
- package/dist/utils/themeHtmlAttributes.js +38 -5
- package/dist/utils/themeHtmlAttributes.js.map +1 -1
- package/dist/utils/themeUtils.d.ts +3 -5
- package/dist/utils/themeUtils.d.ts.map +1 -1
- package/dist/utils/themeUtils.js +474 -6
- package/dist/utils/themeUtils.js.map +1 -1
- package/dist/utils/tweakcnConverter.d.ts +1 -3
- package/dist/utils/tweakcnConverter.d.ts.map +1 -1
- package/dist/utils/tweakcnConverter.js +1 -3
- package/dist/utils/tweakcnConverter.js.map +1 -1
- package/package.json +15 -5
- package/dist/components/ThemePreview.d.ts +0 -3
- package/dist/components/ThemePreview.d.ts.map +0 -1
- package/dist/components/ThemePreview.js +0 -321
- package/dist/components/ThemePreview.js.map +0 -1
- package/dist/plugin.d.ts +0 -2
- package/dist/plugin.d.ts.map +0 -1
- package/dist/plugin.js +0 -3
- package/dist/plugin.js.map +0 -1
|
@@ -1,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 {
|
|
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 {
|
|
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í
|
|
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í
|
|
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
|
-
|
|
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 (
|
|
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 (
|
|
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
|
-
|
|
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("
|
|
364
|
+
label && /*#__PURE__*/ _jsxs("div", {
|
|
287
365
|
className: "field-label",
|
|
288
|
-
|
|
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-
|
|
384
|
+
color: 'var(--theme-elevation-600)'
|
|
307
385
|
},
|
|
308
386
|
children: description
|
|
309
387
|
}),
|
|
310
|
-
/*#__PURE__*/
|
|
311
|
-
className: "token-grid",
|
|
388
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
312
389
|
style: {
|
|
313
|
-
display: '
|
|
314
|
-
|
|
315
|
-
gap: '
|
|
390
|
+
display: 'flex',
|
|
391
|
+
alignItems: 'center',
|
|
392
|
+
gap: '12px',
|
|
393
|
+
position: 'relative'
|
|
316
394
|
},
|
|
317
|
-
children:
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
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
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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__*/
|
|
336
|
-
|
|
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: '
|
|
339
|
-
|
|
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
|
|
342
|
-
backgroundColor:
|
|
343
|
-
|
|
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("
|
|
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
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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:
|
|
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
|
-
}
|
|
356
|
-
|
|
533
|
+
})
|
|
534
|
+
]
|
|
357
535
|
}),
|
|
358
|
-
/*#__PURE__*/
|
|
359
|
-
id: path,
|
|
360
|
-
value: selectedValue,
|
|
361
|
-
onChange: (event)=>handleSelect(event.target.value),
|
|
536
|
+
selectedLabel && /*#__PURE__*/ _jsxs("div", {
|
|
362
537
|
style: {
|
|
363
|
-
|
|
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:
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
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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"}
|