@kilivi/payloadcms-theme-management 1.1.2 → 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.
- package/README.md +318 -847
- 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.map +1 -1
- package/dist/components/ServerThemeInjector.js +41 -14
- package/dist/components/ServerThemeInjector.js.map +1 -1
- package/dist/components/ThemeLivePreviewSync.d.ts +1 -0
- package/dist/components/ThemeLivePreviewSync.d.ts.map +1 -1
- package/dist/components/ThemeLivePreviewSync.js +1 -1
- 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.map +1 -1
- package/dist/components/typographyPreviewUtils.js +8 -1
- 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.js +9 -9
- package/dist/constants/themeFonts.js.map +1 -1
- 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 +763 -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.d.ts +6 -0
- package/dist/fields/FontSelectField.d.ts.map +1 -1
- package/dist/fields/FontSelectField.js +195 -122
- 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 +462 -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 +382 -5
- package/dist/fields/ThemePreviewField.d.ts.map +1 -1
- package/dist/fields/ThemePreviewField.js +268 -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 +961 -29
- 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/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 +10 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +130 -32
- package/dist/index.js.map +1 -1
- package/dist/payload-types.d.ts +24 -0
- package/dist/payload-types.d.ts.map +1 -1
- package/dist/payload-types.js.map +1 -1
- package/dist/presets.d.ts +8 -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 +66 -0
- package/dist/style-presets.d.ts.map +1 -0
- package/dist/style-presets.js +556 -0
- package/dist/style-presets.js.map +1 -0
- package/dist/translations.d.ts +159 -1
- package/dist/translations.d.ts.map +1 -1
- package/dist/translations.js +310 -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 +30 -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 +16 -2
- package/dist/utils/livePreviewThemeRuntime.d.ts.map +1 -1
- package/dist/utils/livePreviewThemeRuntime.js +37 -14
- 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 +45 -1
- package/dist/utils/resolveThemeConfiguration.d.ts.map +1 -1
- package/dist/utils/resolveThemeConfiguration.js +12 -5
- 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 +416 -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 +11 -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,74 +1,172 @@
|
|
|
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 {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
4
|
+
import { Check, ChevronDown } from 'lucide-react';
|
|
5
|
+
import { useCallback, useEffect, useId, useRef, useState } from 'react';
|
|
6
|
+
import { useThemeLanguage, useThemeTranslations } from '../hooks/useThemeTranslations.js';
|
|
7
|
+
import { resolveLocalizedText } from '../utils/localizedText.js';
|
|
8
|
+
const NON_GOOGLE_VALUES = [
|
|
9
|
+
'preset',
|
|
10
|
+
'custom',
|
|
11
|
+
'system-ui'
|
|
12
|
+
];
|
|
13
|
+
function previewFamily(option) {
|
|
14
|
+
if (option.fontFamily) return option.fontFamily;
|
|
15
|
+
if (option.category === 'sans-serif') return 'system-ui, sans-serif';
|
|
16
|
+
if (option.category === 'serif') return 'Georgia, serif';
|
|
17
|
+
if (option.category === 'monospace') return 'monospace';
|
|
18
|
+
return 'inherit';
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Font select with live font previews. Implements the WAI-ARIA "select-only
|
|
22
|
+
* combobox" pattern: a button trigger plus a listbox navigated with the arrow
|
|
23
|
+
* keys, Home/End, Enter/Space and Escape. Preview fonts load for whichever option
|
|
24
|
+
* is active, so keyboard users get the same previews as mouse users.
|
|
25
|
+
*/ const FontSelectField = ({ field, path })=>{
|
|
8
26
|
const { value, setValue } = useField({
|
|
9
27
|
path
|
|
10
28
|
});
|
|
11
29
|
const [isOpen, setIsOpen] = useState(false);
|
|
30
|
+
const [activeIndex, setActiveIndex] = useState(-1);
|
|
31
|
+
const lang = useThemeLanguage();
|
|
32
|
+
const t = useThemeTranslations();
|
|
33
|
+
const baseId = useId();
|
|
34
|
+
const labelId = `${baseId}-label`;
|
|
35
|
+
const listboxId = `${baseId}-listbox`;
|
|
36
|
+
const containerRef = useRef(null);
|
|
37
|
+
const triggerRef = useRef(null);
|
|
38
|
+
const listboxRef = useRef(null);
|
|
39
|
+
const loadedFonts = useRef(new Set());
|
|
12
40
|
const options = field.options || [];
|
|
13
|
-
const
|
|
14
|
-
const [
|
|
15
|
-
const getOptionLabel = (opt)=>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
'preset',
|
|
23
|
-
'custom',
|
|
24
|
-
'system-ui'
|
|
25
|
-
].includes(fontValue)) return;
|
|
26
|
-
// Avoid duplicate loads
|
|
27
|
-
if (loadedFonts.has(fontValue)) return;
|
|
28
|
-
if (typeof document === 'undefined') return;
|
|
41
|
+
const selectedIndex = options.findIndex((opt)=>opt.value === value);
|
|
42
|
+
const selectedOption = selectedIndex >= 0 ? options[selectedIndex] : undefined;
|
|
43
|
+
const getOptionLabel = (opt)=>resolveLocalizedText(opt.label, lang, 'Font');
|
|
44
|
+
const label = resolveLocalizedText(field.label, lang, 'Font');
|
|
45
|
+
const optionId = (index)=>`${baseId}-option-${index}`;
|
|
46
|
+
const ensureFontLoaded = useCallback((fontValue)=>{
|
|
47
|
+
if (!fontValue || NON_GOOGLE_VALUES.includes(fontValue)) return;
|
|
48
|
+
if (loadedFonts.current.has(fontValue) || typeof document === 'undefined') return;
|
|
49
|
+
loadedFonts.current.add(fontValue);
|
|
29
50
|
const linkId = `font-${fontValue.replace(/\s+/g, '-')}`;
|
|
30
|
-
if (document.getElementById(linkId))
|
|
31
|
-
setLoadedFonts((prev)=>new Set(prev).add(fontValue));
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
const weights = '400;700' // reasonable default weights
|
|
35
|
-
;
|
|
36
|
-
const fontUrl = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(fontValue)}:wght@${weights}&display=swap`;
|
|
51
|
+
if (document.getElementById(linkId)) return;
|
|
37
52
|
const link = document.createElement('link');
|
|
38
53
|
link.id = linkId;
|
|
39
54
|
link.rel = 'stylesheet';
|
|
40
|
-
link.href =
|
|
41
|
-
link.onload = ()=>setLoadedFonts((prev)=>new Set(prev).add(fontValue));
|
|
55
|
+
link.href = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(fontValue)}:wght@400;700&display=swap`;
|
|
42
56
|
document.head.appendChild(link);
|
|
43
|
-
};
|
|
44
|
-
const
|
|
45
|
-
|
|
57
|
+
}, []);
|
|
58
|
+
const open = useCallback((index = selectedIndex >= 0 ? selectedIndex : 0)=>{
|
|
59
|
+
setActiveIndex(index);
|
|
60
|
+
setIsOpen(true);
|
|
61
|
+
}, [
|
|
62
|
+
selectedIndex
|
|
63
|
+
]);
|
|
64
|
+
const close = useCallback((restoreFocus)=>{
|
|
46
65
|
setIsOpen(false);
|
|
66
|
+
if (restoreFocus) triggerRef.current?.focus();
|
|
67
|
+
}, []);
|
|
68
|
+
const handleSelect = (index)=>{
|
|
69
|
+
const option = options[index];
|
|
70
|
+
if (!option) return;
|
|
71
|
+
setValue(option.value);
|
|
72
|
+
close(true);
|
|
47
73
|
};
|
|
74
|
+
// Load the preview font for the active option and keep it scrolled into view.
|
|
48
75
|
useEffect(()=>{
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
76
|
+
if (!isOpen || activeIndex < 0) return;
|
|
77
|
+
ensureFontLoaded(options[activeIndex]?.value);
|
|
78
|
+
listboxRef.current?.querySelector(`#${CSS.escape(optionId(activeIndex))}`)?.scrollIntoView({
|
|
79
|
+
block: 'nearest'
|
|
80
|
+
});
|
|
81
|
+
}, [
|
|
82
|
+
isOpen,
|
|
83
|
+
activeIndex
|
|
84
|
+
]);
|
|
85
|
+
// Focus the listbox when it opens so keyboard navigation works immediately.
|
|
86
|
+
useEffect(()=>{
|
|
87
|
+
if (isOpen) listboxRef.current?.focus();
|
|
59
88
|
}, [
|
|
60
89
|
isOpen
|
|
61
90
|
]);
|
|
62
|
-
|
|
63
|
-
|
|
91
|
+
useEffect(()=>{
|
|
92
|
+
if (!isOpen) return;
|
|
93
|
+
const handlePointerOutside = (e)=>{
|
|
94
|
+
if (!containerRef.current?.contains(e.target)) close(false);
|
|
95
|
+
};
|
|
96
|
+
document.addEventListener('pointerdown', handlePointerOutside);
|
|
97
|
+
return ()=>document.removeEventListener('pointerdown', handlePointerOutside);
|
|
98
|
+
}, [
|
|
99
|
+
isOpen,
|
|
100
|
+
close
|
|
101
|
+
]);
|
|
102
|
+
const handleTriggerKeyDown = (event)=>{
|
|
103
|
+
if ([
|
|
104
|
+
'ArrowDown',
|
|
105
|
+
'ArrowUp',
|
|
106
|
+
'Enter',
|
|
107
|
+
' '
|
|
108
|
+
].includes(event.key)) {
|
|
109
|
+
event.preventDefault();
|
|
110
|
+
open(event.key === 'ArrowUp' && selectedIndex < 0 ? options.length - 1 : undefined);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const handleListboxKeyDown = (event)=>{
|
|
114
|
+
const last = options.length - 1;
|
|
115
|
+
switch(event.key){
|
|
116
|
+
case 'ArrowDown':
|
|
117
|
+
event.preventDefault();
|
|
118
|
+
setActiveIndex((i)=>Math.min(last, i + 1));
|
|
119
|
+
break;
|
|
120
|
+
case 'ArrowUp':
|
|
121
|
+
event.preventDefault();
|
|
122
|
+
setActiveIndex((i)=>Math.max(0, i - 1));
|
|
123
|
+
break;
|
|
124
|
+
case 'Home':
|
|
125
|
+
event.preventDefault();
|
|
126
|
+
setActiveIndex(0);
|
|
127
|
+
break;
|
|
128
|
+
case 'End':
|
|
129
|
+
event.preventDefault();
|
|
130
|
+
setActiveIndex(last);
|
|
131
|
+
break;
|
|
132
|
+
case 'Enter':
|
|
133
|
+
case ' ':
|
|
134
|
+
event.preventDefault();
|
|
135
|
+
handleSelect(activeIndex);
|
|
136
|
+
break;
|
|
137
|
+
case 'Escape':
|
|
138
|
+
event.preventDefault();
|
|
139
|
+
event.stopPropagation();
|
|
140
|
+
close(true);
|
|
141
|
+
break;
|
|
142
|
+
case 'Tab':
|
|
143
|
+
close(false);
|
|
144
|
+
break;
|
|
145
|
+
default:
|
|
146
|
+
// Type-ahead: jump to the first option starting with the typed letter.
|
|
147
|
+
if (event.key.length === 1 && /\S/.test(event.key)) {
|
|
148
|
+
const letter = event.key.toLowerCase();
|
|
149
|
+
const start = activeIndex + 1;
|
|
150
|
+
const ordered = [
|
|
151
|
+
...options.slice(start),
|
|
152
|
+
...options.slice(0, start)
|
|
153
|
+
];
|
|
154
|
+
const match = ordered.find((opt)=>getOptionLabel(opt).toLowerCase().startsWith(letter));
|
|
155
|
+
if (match) setActiveIndex(options.indexOf(match));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
};
|
|
64
159
|
return /*#__PURE__*/ _jsxs("div", {
|
|
160
|
+
ref: containerRef,
|
|
65
161
|
className: "font-select-container",
|
|
66
162
|
style: {
|
|
67
163
|
position: 'relative',
|
|
68
|
-
marginBottom: '12px'
|
|
164
|
+
marginBottom: '12px',
|
|
165
|
+
maxWidth: '360px'
|
|
69
166
|
},
|
|
70
167
|
children: [
|
|
71
|
-
/*#__PURE__*/ _jsx("
|
|
168
|
+
/*#__PURE__*/ _jsx("div", {
|
|
169
|
+
id: labelId,
|
|
72
170
|
style: {
|
|
73
171
|
display: 'block',
|
|
74
172
|
marginBottom: '6px',
|
|
@@ -79,10 +177,18 @@ const FontSelectField = ({ field, path })=>{
|
|
|
79
177
|
children: label
|
|
80
178
|
}),
|
|
81
179
|
/*#__PURE__*/ _jsxs("button", {
|
|
180
|
+
ref: triggerRef,
|
|
82
181
|
type: "button",
|
|
83
|
-
|
|
182
|
+
className: "font-select-trigger",
|
|
183
|
+
role: "combobox",
|
|
184
|
+
"aria-haspopup": "listbox",
|
|
185
|
+
"aria-expanded": isOpen,
|
|
186
|
+
"aria-controls": isOpen ? listboxId : undefined,
|
|
187
|
+
"aria-labelledby": `${labelId} ${baseId}-value`,
|
|
188
|
+
onClick: ()=>isOpen ? close(false) : open(),
|
|
189
|
+
onKeyDown: handleTriggerKeyDown,
|
|
84
190
|
style: {
|
|
85
|
-
width: '
|
|
191
|
+
width: '100%',
|
|
86
192
|
padding: '10px 14px',
|
|
87
193
|
borderRadius: '6px',
|
|
88
194
|
border: '1px solid var(--theme-elevation-200)',
|
|
@@ -93,44 +199,38 @@ const FontSelectField = ({ field, path })=>{
|
|
|
93
199
|
display: 'flex',
|
|
94
200
|
justifyContent: 'space-between',
|
|
95
201
|
alignItems: 'center',
|
|
202
|
+
gap: '8px',
|
|
96
203
|
fontSize: '14px',
|
|
97
|
-
fontFamily: selectedOption?.fontFamily || 'inherit'
|
|
98
|
-
transition: 'border-color 0.2s ease'
|
|
99
|
-
},
|
|
100
|
-
onMouseEnter: (e)=>{
|
|
101
|
-
e.currentTarget.style.borderColor = 'var(--theme-elevation-400)';
|
|
102
|
-
},
|
|
103
|
-
onMouseLeave: (e)=>{
|
|
104
|
-
e.currentTarget.style.borderColor = 'var(--theme-elevation-200)';
|
|
204
|
+
fontFamily: selectedOption?.fontFamily || 'inherit'
|
|
105
205
|
},
|
|
106
206
|
children: [
|
|
107
207
|
/*#__PURE__*/ _jsx("span", {
|
|
208
|
+
id: `${baseId}-value`,
|
|
108
209
|
style: {
|
|
109
|
-
flex: 1
|
|
210
|
+
flex: 1,
|
|
211
|
+
minWidth: 0
|
|
110
212
|
},
|
|
111
213
|
children: selectedOption ? getOptionLabel(selectedOption) : t.ui.selectFontPlaceholder
|
|
112
214
|
}),
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
height: "12",
|
|
117
|
-
viewBox: "0 0 12 12",
|
|
118
|
-
fill: "none",
|
|
215
|
+
/*#__PURE__*/ _jsx(ChevronDown, {
|
|
216
|
+
size: 14,
|
|
217
|
+
"aria-hidden": true,
|
|
119
218
|
style: {
|
|
120
|
-
|
|
121
|
-
transform: isOpen ? 'rotate(180deg)' :
|
|
122
|
-
}
|
|
123
|
-
children: /*#__PURE__*/ _jsx("path", {
|
|
124
|
-
d: "M3 4.5L6 7.5L9 4.5",
|
|
125
|
-
stroke: "currentColor",
|
|
126
|
-
strokeWidth: "1.5",
|
|
127
|
-
strokeLinecap: "round",
|
|
128
|
-
strokeLinejoin: "round"
|
|
129
|
-
})
|
|
219
|
+
flexShrink: 0,
|
|
220
|
+
transform: isOpen ? 'rotate(180deg)' : undefined
|
|
221
|
+
}
|
|
130
222
|
})
|
|
131
223
|
]
|
|
132
224
|
}),
|
|
133
225
|
isOpen && /*#__PURE__*/ _jsx("div", {
|
|
226
|
+
ref: listboxRef,
|
|
227
|
+
id: listboxId,
|
|
228
|
+
role: "listbox",
|
|
229
|
+
tabIndex: -1,
|
|
230
|
+
"aria-labelledby": labelId,
|
|
231
|
+
"aria-activedescendant": activeIndex >= 0 ? optionId(activeIndex) : undefined,
|
|
232
|
+
onKeyDown: handleListboxKeyDown,
|
|
233
|
+
className: "font-select-listbox",
|
|
134
234
|
style: {
|
|
135
235
|
position: 'absolute',
|
|
136
236
|
top: '100%',
|
|
@@ -145,47 +245,31 @@ const FontSelectField = ({ field, path })=>{
|
|
|
145
245
|
boxShadow: '0 8px 24px rgba(15, 23, 42, 0.15)',
|
|
146
246
|
zIndex: 1000
|
|
147
247
|
},
|
|
148
|
-
children: options.map((option)=>{
|
|
248
|
+
children: options.map((option, index)=>{
|
|
149
249
|
const isSelected = option.value === value;
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
return /*#__PURE__*/ _jsxs("button", {
|
|
158
|
-
type: "button",
|
|
159
|
-
onClick: ()=>handleSelect(option.value),
|
|
250
|
+
const isActive = index === activeIndex;
|
|
251
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
252
|
+
id: optionId(index),
|
|
253
|
+
role: "option",
|
|
254
|
+
"aria-selected": isSelected,
|
|
255
|
+
onClick: ()=>handleSelect(index),
|
|
256
|
+
onPointerMove: ()=>setActiveIndex(index),
|
|
160
257
|
style: {
|
|
161
|
-
width: '250px',
|
|
162
258
|
padding: '12px 14px',
|
|
163
|
-
|
|
164
|
-
|
|
259
|
+
backgroundColor: isActive ? 'var(--theme-elevation-100)' : isSelected ? 'var(--theme-elevation-50)' : 'transparent',
|
|
260
|
+
// The active option gets an outline so keyboard focus never relies on a subtle fill alone.
|
|
261
|
+
outline: isActive ? '2px solid var(--theme-elevation-800)' : undefined,
|
|
262
|
+
outlineOffset: '-2px',
|
|
165
263
|
color: 'var(--theme-elevation-800)',
|
|
166
|
-
textAlign: 'left',
|
|
167
264
|
cursor: 'pointer',
|
|
168
265
|
fontSize: '14px',
|
|
169
|
-
fontFamily,
|
|
266
|
+
fontFamily: previewFamily(option),
|
|
170
267
|
display: 'flex',
|
|
171
268
|
flexDirection: 'column',
|
|
172
|
-
gap: '4px'
|
|
173
|
-
transition: 'background-color 0.15s ease'
|
|
174
|
-
},
|
|
175
|
-
onMouseEnter: (e)=>{
|
|
176
|
-
if (!isSelected) {
|
|
177
|
-
e.currentTarget.style.backgroundColor = 'var(--theme-elevation-50)';
|
|
178
|
-
}
|
|
179
|
-
// Lazy-load a preview font when hovering
|
|
180
|
-
ensureFontLoaded(option.value);
|
|
181
|
-
},
|
|
182
|
-
onMouseLeave: (e)=>{
|
|
183
|
-
if (!isSelected) {
|
|
184
|
-
e.currentTarget.style.backgroundColor = 'transparent';
|
|
185
|
-
}
|
|
269
|
+
gap: '4px'
|
|
186
270
|
},
|
|
187
271
|
children: [
|
|
188
|
-
/*#__PURE__*/ _jsxs("
|
|
272
|
+
/*#__PURE__*/ _jsxs("span", {
|
|
189
273
|
style: {
|
|
190
274
|
fontWeight: isSelected ? 600 : 500,
|
|
191
275
|
display: 'flex',
|
|
@@ -193,34 +277,23 @@ const FontSelectField = ({ field, path })=>{
|
|
|
193
277
|
gap: '8px'
|
|
194
278
|
},
|
|
195
279
|
children: [
|
|
196
|
-
isSelected && /*#__PURE__*/ _jsx(
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
fill: "none",
|
|
201
|
-
children: /*#__PURE__*/ _jsx("path", {
|
|
202
|
-
d: "M11.6667 3.5L5.25 9.91667L2.33334 7",
|
|
203
|
-
stroke: "var(--theme-elevation-500)",
|
|
204
|
-
strokeWidth: "2",
|
|
205
|
-
strokeLinecap: "round",
|
|
206
|
-
strokeLinejoin: "round"
|
|
207
|
-
})
|
|
280
|
+
isSelected && /*#__PURE__*/ _jsx(Check, {
|
|
281
|
+
size: 14,
|
|
282
|
+
color: "var(--theme-elevation-600)",
|
|
283
|
+
"aria-hidden": true
|
|
208
284
|
}),
|
|
209
285
|
getOptionLabel(option)
|
|
210
286
|
]
|
|
211
287
|
}),
|
|
212
|
-
/*#__PURE__*/ _jsx("
|
|
288
|
+
/*#__PURE__*/ _jsx("span", {
|
|
289
|
+
"aria-hidden": true,
|
|
213
290
|
style: {
|
|
214
291
|
fontSize: '16px',
|
|
215
292
|
color: 'var(--theme-elevation-600)',
|
|
216
293
|
fontStyle: option.value === 'preset' || option.value === 'custom' ? 'italic' : 'normal',
|
|
217
294
|
fontFamily: option.fontFamily || undefined
|
|
218
295
|
},
|
|
219
|
-
children:
|
|
220
|
-
if (option.value === 'preset') return t.ui.usePreset;
|
|
221
|
-
if (option.value === 'custom') return t.ui.specifyCustom;
|
|
222
|
-
return t.ui.sampleSentence;
|
|
223
|
-
})()
|
|
296
|
+
children: option.value === 'preset' ? t.ui.usePreset : option.value === 'custom' ? t.ui.specifyCustom : t.ui.sampleSentence
|
|
224
297
|
})
|
|
225
298
|
]
|
|
226
299
|
}, option.value);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/fields/FontSelectField.tsx"],"sourcesContent":["'use client'\n\nimport { useField } from '@payloadcms/ui'\nimport type { SelectFieldClientComponent } from 'payload'\nimport { useEffect, useState } from 'react'\nimport { getTranslations } from '../translations.js'\nimport { getAdminLanguage } from '../utils/getAdminLanguage.js'\n\ntype LocalizedLabel = Record<string, string>\n\ninterface FontOption {\n label: string | LocalizedLabel\n value: string\n fontFamily?: string\n category?: 'sans-serif' | 'serif' | 'monospace' | 'display'\n}\n\nconst FontSelectField: SelectFieldClientComponent = ({ field, path }) => {\n const { value, setValue } = useField<string>({ path })\n const [isOpen, setIsOpen] = useState(false)\n\n const options = (field.options as FontOption[]) || []\n const selectedOption = options.find((opt) => opt.value === value)\n const [loadedFonts, setLoadedFonts] = useState<Set<string>>(new Set())\n\n const getOptionLabel = (opt: FontOption) => {\n if (typeof opt.label === 'string') return opt.label\n const lang = getAdminLanguage()\n return opt.label[lang] || opt.label.en || opt.label.cs || 'Font'\n }\n\n const ensureFontLoaded = (fontValue: string | undefined) => {\n if (!fontValue || ['preset', 'custom', 'system-ui'].includes(fontValue)) return\n // Avoid duplicate loads\n if (loadedFonts.has(fontValue)) return\n\n if (typeof document === 'undefined') return\n\n const linkId = `font-${fontValue.replace(/\\s+/g, '-')}`\n if (document.getElementById(linkId)) {\n setLoadedFonts((prev) => new Set(prev).add(fontValue))\n return\n }\n\n const weights = '400;700' // reasonable default weights\n const fontUrl = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(\n fontValue,\n )}:wght@${weights}&display=swap`\n const link = document.createElement('link')\n link.id = linkId\n link.rel = 'stylesheet'\n link.href = fontUrl\n link.onload = () => setLoadedFonts((prev) => new Set(prev).add(fontValue))\n document.head.appendChild(link)\n }\n\n const handleSelect = (optionValue: string) => {\n setValue(optionValue)\n setIsOpen(false)\n }\n\n useEffect(() => {\n const handleClickOutside = (e: MouseEvent) => {\n const target = e.target as HTMLElement\n if (!target.closest('.font-select-container')) {\n setIsOpen(false)\n }\n }\n\n if (isOpen) {\n document.addEventListener('mousedown', handleClickOutside)\n return () => document.removeEventListener('mousedown', handleClickOutside)\n }\n }, [isOpen])\n\n const t = getTranslations(getAdminLanguage())\n const label =\n typeof field.label === 'string'\n ? field.label\n : typeof field.label === 'object'\n ? field.label?.en || field.label?.cs\n : field.label || 'Font'\n\n return (\n <div className=\"font-select-container\" style={{ position: 'relative', marginBottom: '12px' }}>\n <label\n style={{\n display: 'block',\n marginBottom: '6px',\n fontSize: '13px',\n fontWeight: 600,\n color: 'var(--theme-elevation-800)',\n }}\n >\n {label}\n </label>\n\n <button\n type=\"button\"\n onClick={() => setIsOpen(!isOpen)}\n style={{\n width: '300px',\n padding: '10px 14px',\n borderRadius: '6px',\n border: '1px solid var(--theme-elevation-200)',\n backgroundColor: 'var(--theme-input-bg)',\n color: 'var(--theme-elevation-800)',\n textAlign: 'left',\n cursor: 'pointer',\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n fontSize: '14px',\n fontFamily: selectedOption?.fontFamily || 'inherit',\n transition: 'border-color 0.2s ease',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.borderColor = 'var(--theme-elevation-400)'\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.borderColor = 'var(--theme-elevation-200)'\n }}\n >\n <span style={{ flex: 1 }}>\n {selectedOption ? getOptionLabel(selectedOption) : t.ui.selectFontPlaceholder}\n </span>{' '}\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n style={{\n transition: 'transform 0.2s ease',\n transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)',\n }}\n >\n <path\n d=\"M3 4.5L6 7.5L9 4.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n\n {isOpen && (\n <div\n style={{\n position: 'absolute',\n top: '100%',\n left: 0,\n right: 0,\n marginTop: '4px',\n maxHeight: '280px',\n overflowY: 'auto',\n backgroundColor: 'var(--theme-elevation-0)',\n border: '1px solid var(--theme-elevation-200)',\n borderRadius: '8px',\n boxShadow: '0 8px 24px rgba(15, 23, 42, 0.15)',\n zIndex: 1000,\n }}\n >\n {options.map((option) => {\n const isSelected = option.value === value\n\n let fontFamily = option.fontFamily\n if (!fontFamily) {\n if (option.category === 'sans-serif') fontFamily = 'system-ui, sans-serif'\n else if (option.category === 'serif') fontFamily = 'Georgia, serif'\n else if (option.category === 'monospace') fontFamily = 'monospace'\n else fontFamily = 'inherit'\n }\n\n return (\n <button\n key={option.value}\n type=\"button\"\n onClick={() => handleSelect(option.value)}\n style={{\n width: '250px',\n padding: '12px 14px',\n border: 'none',\n backgroundColor: isSelected ? 'var(--theme-elevation-100)' : 'transparent',\n color: 'var(--theme-elevation-800)',\n textAlign: 'left',\n cursor: 'pointer',\n fontSize: '14px',\n fontFamily,\n display: 'flex',\n flexDirection: 'column',\n gap: '4px',\n transition: 'background-color 0.15s ease',\n }}\n onMouseEnter={(e) => {\n if (!isSelected) {\n e.currentTarget.style.backgroundColor = 'var(--theme-elevation-50)'\n }\n // Lazy-load a preview font when hovering\n ensureFontLoaded(option.value)\n }}\n onMouseLeave={(e) => {\n if (!isSelected) {\n e.currentTarget.style.backgroundColor = 'transparent'\n }\n }}\n >\n <div\n style={{\n fontWeight: isSelected ? 600 : 500,\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n }}\n >\n {isSelected && (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\">\n <path\n d=\"M11.6667 3.5L5.25 9.91667L2.33334 7\"\n stroke=\"var(--theme-elevation-500)\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n )}\n {getOptionLabel(option)}\n </div>\n <div\n style={{\n fontSize: '16px',\n color: 'var(--theme-elevation-600)',\n fontStyle:\n option.value === 'preset' || option.value === 'custom' ? 'italic' : 'normal',\n fontFamily: option.fontFamily || undefined,\n }}\n >\n {(() => {\n if (option.value === 'preset') return t.ui.usePreset\n if (option.value === 'custom') return t.ui.specifyCustom\n return t.ui.sampleSentence\n })()}\n </div>\n </button>\n )\n })}\n </div>\n )}\n </div>\n )\n}\n\nexport default FontSelectField\n"],"names":["useField","useEffect","useState","getTranslations","getAdminLanguage","FontSelectField","field","path","value","setValue","isOpen","setIsOpen","options","selectedOption","find","opt","loadedFonts","setLoadedFonts","Set","getOptionLabel","label","lang","en","cs","ensureFontLoaded","fontValue","includes","has","document","linkId","replace","getElementById","prev","add","weights","fontUrl","encodeURIComponent","link","createElement","id","rel","href","onload","head","appendChild","handleSelect","optionValue","handleClickOutside","e","target","closest","addEventListener","removeEventListener","t","div","className","style","position","marginBottom","display","fontSize","fontWeight","color","button","type","onClick","width","padding","borderRadius","border","backgroundColor","textAlign","cursor","justifyContent","alignItems","fontFamily","transition","onMouseEnter","currentTarget","borderColor","onMouseLeave","span","flex","ui","selectFontPlaceholder","svg","height","viewBox","fill","transform","d","stroke","strokeWidth","strokeLinecap","strokeLinejoin","top","left","right","marginTop","maxHeight","overflowY","boxShadow","zIndex","map","option","isSelected","category","flexDirection","gap","fontStyle","undefined","usePreset","specifyCustom","sampleSentence"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/fields/FontSelectField.tsx"],"sourcesContent":["'use client'\n\nimport { useField } from '@payloadcms/ui'\nimport { Check, ChevronDown } from 'lucide-react'\nimport type { SelectFieldClientComponent } from 'payload'\nimport { useCallback, useEffect, useId, useRef, useState, type KeyboardEvent } from 'react'\nimport { useThemeLanguage, useThemeTranslations } from '../hooks/useThemeTranslations.js'\nimport { resolveLocalizedText } from '../utils/localizedText.js'\n\ntype LocalizedLabel = Record<string, string>\n\ninterface FontOption {\n label: string | LocalizedLabel\n value: string\n fontFamily?: string\n category?: 'sans-serif' | 'serif' | 'monospace' | 'display'\n}\n\nconst NON_GOOGLE_VALUES = ['preset', 'custom', 'system-ui']\n\nfunction previewFamily(option: FontOption): string {\n if (option.fontFamily) return option.fontFamily\n if (option.category === 'sans-serif') return 'system-ui, sans-serif'\n if (option.category === 'serif') return 'Georgia, serif'\n if (option.category === 'monospace') return 'monospace'\n return 'inherit'\n}\n\n/**\n * Font select with live font previews. Implements the WAI-ARIA \"select-only\n * combobox\" pattern: a button trigger plus a listbox navigated with the arrow\n * keys, Home/End, Enter/Space and Escape. Preview fonts load for whichever option\n * is active, so keyboard users get the same previews as mouse users.\n */\nconst FontSelectField: SelectFieldClientComponent = ({ field, path }) => {\n const { value, setValue } = useField<string>({ path })\n const [isOpen, setIsOpen] = useState(false)\n const [activeIndex, setActiveIndex] = useState(-1)\n const lang = useThemeLanguage()\n const t = useThemeTranslations()\n const baseId = useId()\n const labelId = `${baseId}-label`\n const listboxId = `${baseId}-listbox`\n const containerRef = useRef<HTMLDivElement>(null)\n const triggerRef = useRef<HTMLButtonElement>(null)\n const listboxRef = useRef<HTMLDivElement>(null)\n const loadedFonts = useRef<Set<string>>(new Set())\n\n const options = (field.options as FontOption[]) || []\n const selectedIndex = options.findIndex((opt) => opt.value === value)\n const selectedOption = selectedIndex >= 0 ? options[selectedIndex] : undefined\n\n const getOptionLabel = (opt: FontOption) => resolveLocalizedText(opt.label, lang, 'Font')\n const label = resolveLocalizedText(field.label, lang, 'Font')\n const optionId = (index: number) => `${baseId}-option-${index}`\n\n const ensureFontLoaded = useCallback((fontValue: string | undefined) => {\n if (!fontValue || NON_GOOGLE_VALUES.includes(fontValue)) return\n if (loadedFonts.current.has(fontValue) || typeof document === 'undefined') return\n loadedFonts.current.add(fontValue)\n\n const linkId = `font-${fontValue.replace(/\\s+/g, '-')}`\n if (document.getElementById(linkId)) return\n\n const link = document.createElement('link')\n link.id = linkId\n link.rel = 'stylesheet'\n link.href = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(fontValue)}:wght@400;700&display=swap`\n document.head.appendChild(link)\n }, [])\n\n const open = useCallback(\n (index = selectedIndex >= 0 ? selectedIndex : 0) => {\n setActiveIndex(index)\n setIsOpen(true)\n },\n [selectedIndex],\n )\n\n const close = useCallback((restoreFocus: boolean) => {\n setIsOpen(false)\n if (restoreFocus) triggerRef.current?.focus()\n }, [])\n\n const handleSelect = (index: number) => {\n const option = options[index]\n if (!option) return\n setValue(option.value)\n close(true)\n }\n\n // Load the preview font for the active option and keep it scrolled into view.\n useEffect(() => {\n if (!isOpen || activeIndex < 0) return\n ensureFontLoaded(options[activeIndex]?.value)\n listboxRef.current\n ?.querySelector<HTMLElement>(`#${CSS.escape(optionId(activeIndex))}`)\n ?.scrollIntoView({ block: 'nearest' })\n }, [isOpen, activeIndex])\n\n // Focus the listbox when it opens so keyboard navigation works immediately.\n useEffect(() => {\n if (isOpen) listboxRef.current?.focus()\n }, [isOpen])\n\n useEffect(() => {\n if (!isOpen) return\n const handlePointerOutside = (e: PointerEvent) => {\n if (!containerRef.current?.contains(e.target as Node)) close(false)\n }\n document.addEventListener('pointerdown', handlePointerOutside)\n return () => document.removeEventListener('pointerdown', handlePointerOutside)\n }, [isOpen, close])\n\n const handleTriggerKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n if (['ArrowDown', 'ArrowUp', 'Enter', ' '].includes(event.key)) {\n event.preventDefault()\n open(event.key === 'ArrowUp' && selectedIndex < 0 ? options.length - 1 : undefined)\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 handleSelect(activeIndex)\n break\n case 'Escape':\n event.preventDefault()\n event.stopPropagation()\n close(true)\n break\n case 'Tab':\n close(false)\n break\n default:\n // Type-ahead: jump to the first option starting with the typed letter.\n if (event.key.length === 1 && /\\S/.test(event.key)) {\n const letter = event.key.toLowerCase()\n const start = activeIndex + 1\n const ordered = [...options.slice(start), ...options.slice(0, start)]\n const match = ordered.find((opt) => getOptionLabel(opt).toLowerCase().startsWith(letter))\n if (match) setActiveIndex(options.indexOf(match))\n }\n }\n }\n\n return (\n <div\n ref={containerRef}\n className=\"font-select-container\"\n style={{ position: 'relative', marginBottom: '12px', maxWidth: '360px' }}\n >\n <div\n id={labelId}\n style={{\n display: 'block',\n marginBottom: '6px',\n fontSize: '13px',\n fontWeight: 600,\n color: 'var(--theme-elevation-800)',\n }}\n >\n {label}\n </div>\n\n <button\n ref={triggerRef}\n type=\"button\"\n className=\"font-select-trigger\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-expanded={isOpen}\n aria-controls={isOpen ? listboxId : undefined}\n aria-labelledby={`${labelId} ${baseId}-value`}\n onClick={() => (isOpen ? close(false) : open())}\n onKeyDown={handleTriggerKeyDown}\n style={{\n width: '100%',\n padding: '10px 14px',\n borderRadius: '6px',\n border: '1px solid var(--theme-elevation-200)',\n backgroundColor: 'var(--theme-input-bg)',\n color: 'var(--theme-elevation-800)',\n textAlign: 'left',\n cursor: 'pointer',\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n gap: '8px',\n fontSize: '14px',\n fontFamily: selectedOption?.fontFamily || 'inherit',\n }}\n >\n <span id={`${baseId}-value`} style={{ flex: 1, minWidth: 0 }}>\n {selectedOption ? getOptionLabel(selectedOption) : t.ui.selectFontPlaceholder}\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={labelId}\n aria-activedescendant={activeIndex >= 0 ? optionId(activeIndex) : undefined}\n onKeyDown={handleListboxKeyDown}\n className=\"font-select-listbox\"\n style={{\n position: 'absolute',\n top: '100%',\n left: 0,\n right: 0,\n marginTop: '4px',\n maxHeight: '280px',\n overflowY: 'auto',\n backgroundColor: 'var(--theme-elevation-0)',\n border: '1px solid var(--theme-elevation-200)',\n borderRadius: '8px',\n boxShadow: '0 8px 24px rgba(15, 23, 42, 0.15)',\n zIndex: 1000,\n }}\n >\n {options.map((option, index) => {\n const isSelected = option.value === value\n const isActive = index === activeIndex\n\n return (\n <div\n key={option.value}\n id={optionId(index)}\n role=\"option\"\n aria-selected={isSelected}\n onClick={() => handleSelect(index)}\n onPointerMove={() => setActiveIndex(index)}\n style={{\n padding: '12px 14px',\n backgroundColor: isActive\n ? 'var(--theme-elevation-100)'\n : isSelected\n ? 'var(--theme-elevation-50)'\n : 'transparent',\n // The active option gets an outline so keyboard focus never relies on a subtle fill alone.\n outline: isActive ? '2px solid var(--theme-elevation-800)' : undefined,\n outlineOffset: '-2px',\n color: 'var(--theme-elevation-800)',\n cursor: 'pointer',\n fontSize: '14px',\n fontFamily: previewFamily(option),\n display: 'flex',\n flexDirection: 'column',\n gap: '4px',\n }}\n >\n <span\n style={{\n fontWeight: isSelected ? 600 : 500,\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n }}\n >\n {isSelected && <Check size={14} color=\"var(--theme-elevation-600)\" aria-hidden />}\n {getOptionLabel(option)}\n </span>\n <span\n aria-hidden\n style={{\n fontSize: '16px',\n color: 'var(--theme-elevation-600)',\n fontStyle:\n option.value === 'preset' || option.value === 'custom' ? 'italic' : 'normal',\n fontFamily: option.fontFamily || undefined,\n }}\n >\n {option.value === 'preset'\n ? t.ui.usePreset\n : option.value === 'custom'\n ? t.ui.specifyCustom\n : t.ui.sampleSentence}\n </span>\n </div>\n )\n })}\n </div>\n )}\n </div>\n )\n}\n\nexport default FontSelectField\n"],"names":["useField","Check","ChevronDown","useCallback","useEffect","useId","useRef","useState","useThemeLanguage","useThemeTranslations","resolveLocalizedText","NON_GOOGLE_VALUES","previewFamily","option","fontFamily","category","FontSelectField","field","path","value","setValue","isOpen","setIsOpen","activeIndex","setActiveIndex","lang","t","baseId","labelId","listboxId","containerRef","triggerRef","listboxRef","loadedFonts","Set","options","selectedIndex","findIndex","opt","selectedOption","undefined","getOptionLabel","label","optionId","index","ensureFontLoaded","fontValue","includes","current","has","document","add","linkId","replace","getElementById","link","createElement","id","rel","href","encodeURIComponent","head","appendChild","open","close","restoreFocus","focus","handleSelect","querySelector","CSS","escape","scrollIntoView","block","handlePointerOutside","e","contains","target","addEventListener","removeEventListener","handleTriggerKeyDown","event","key","preventDefault","length","handleListboxKeyDown","last","i","Math","min","max","stopPropagation","test","letter","toLowerCase","start","ordered","slice","match","find","startsWith","indexOf","div","ref","className","style","position","marginBottom","maxWidth","display","fontSize","fontWeight","color","button","type","role","aria-haspopup","aria-expanded","aria-controls","aria-labelledby","onClick","onKeyDown","width","padding","borderRadius","border","backgroundColor","textAlign","cursor","justifyContent","alignItems","gap","span","flex","minWidth","ui","selectFontPlaceholder","size","aria-hidden","flexShrink","transform","tabIndex","aria-activedescendant","top","left","right","marginTop","maxHeight","overflowY","boxShadow","zIndex","map","isSelected","isActive","aria-selected","onPointerMove","outline","outlineOffset","flexDirection","fontStyle","usePreset","specifyCustom","sampleSentence"],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin tool that generates a full light + dark palette from a single brand
|
|
3
|
+
* colour (or a colour extracted from an uploaded logo/image) and writes it
|
|
4
|
+
* straight into the colour-mode fields.
|
|
5
|
+
*/
|
|
6
|
+
export default function PaletteGeneratorField(): import("react").JSX.Element;
|
|
7
|
+
//# sourceMappingURL=PaletteGeneratorField.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PaletteGeneratorField.d.ts","sourceRoot":"","sources":["../../src/fields/PaletteGeneratorField.tsx"],"names":[],"mappings":"AAkBA;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,qBAAqB,gCA2P5C"}
|