@forcecalendar/interface 1.0.27 → 1.0.28
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 +9 -0
- package/dist/force-calendar-interface.esm.js +102 -55
- package/dist/force-calendar-interface.esm.js.map +1 -1
- package/dist/force-calendar-interface.umd.js.map +1 -1
- package/package.json +3 -1
- package/src/components/EventForm.js +180 -176
- package/src/components/ForceCalendar.js +414 -392
- package/src/core/BaseComponent.js +146 -144
- package/src/core/EventBus.js +197 -197
- package/src/core/StateManager.js +405 -399
- package/src/index.js +3 -3
- package/src/renderers/BaseViewRenderer.js +195 -192
- package/src/renderers/DayViewRenderer.js +133 -118
- package/src/renderers/MonthViewRenderer.js +74 -72
- package/src/renderers/WeekViewRenderer.js +118 -96
- package/src/utils/DOMUtils.js +277 -277
- package/src/utils/DateUtils.js +164 -164
- package/src/utils/StyleUtils.js +286 -249
package/src/utils/StyleUtils.js
CHANGED
|
@@ -3,133 +3,133 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
export class StyleUtils {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Common CSS variables
|
|
36
|
-
*/
|
|
37
|
-
static cssVariables = {
|
|
38
|
-
// "Pro" Palette - Functional & Sharp
|
|
39
|
-
'--fc-primary-color': '#2563EB', // International Blue (Focus)
|
|
40
|
-
'--fc-primary-hover': '#1D4ED8',
|
|
41
|
-
'--fc-primary-light': '#EFF6FF',
|
|
42
|
-
|
|
43
|
-
// Neutral Scale (Slate/Gray for structure)
|
|
44
|
-
'--fc-text-color': '#111827', // Almost Black
|
|
45
|
-
'--fc-text-secondary': '#6B7280', // Cool Gray
|
|
46
|
-
'--fc-text-light': '#9CA3AF',
|
|
47
|
-
|
|
48
|
-
'--fc-border-color': '#E5E7EB', // Crisp Light Gray
|
|
49
|
-
'--fc-border-color-hover': '#D1D5DB',
|
|
50
|
-
|
|
51
|
-
'--fc-background': '#FFFFFF',
|
|
52
|
-
'--fc-background-alt': '#FAFAFA', // Very subtle off-white
|
|
53
|
-
'--fc-background-hover': '#F3F4F6',
|
|
54
|
-
'--fc-background-active': '#E5E7EB',
|
|
55
|
-
|
|
56
|
-
// Semantic Colors
|
|
57
|
-
'--fc-accent-color': '#F59E0B',
|
|
58
|
-
'--fc-danger-color': '#EF4444',
|
|
59
|
-
'--fc-success-color': '#10B981',
|
|
60
|
-
|
|
61
|
-
// Typography - optimized for UI density
|
|
62
|
-
'--fc-font-family': 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
63
|
-
'--fc-font-size-xs': '11px',
|
|
64
|
-
'--fc-font-size-sm': '12px',
|
|
65
|
-
'--fc-font-size-base': '13px', // Slightly smaller for density
|
|
66
|
-
'--fc-font-size-lg': '15px',
|
|
67
|
-
'--fc-font-size-xl': '18px',
|
|
68
|
-
'--fc-font-size-2xl': '24px',
|
|
69
|
-
'--fc-line-height': '1.4',
|
|
70
|
-
'--fc-font-weight-normal': '400',
|
|
71
|
-
'--fc-font-weight-medium': '500',
|
|
72
|
-
'--fc-font-weight-semibold': '600',
|
|
73
|
-
'--fc-font-weight-bold': '700',
|
|
74
|
-
|
|
75
|
-
// Spacing - Tighter
|
|
76
|
-
'--fc-spacing-xs': '2px',
|
|
77
|
-
'--fc-spacing-sm': '6px',
|
|
78
|
-
'--fc-spacing-md': '10px',
|
|
79
|
-
'--fc-spacing-lg': '14px',
|
|
80
|
-
'--fc-spacing-xl': '20px',
|
|
81
|
-
'--fc-spacing-2xl': '28px',
|
|
82
|
-
|
|
83
|
-
// Border
|
|
84
|
-
'--fc-border-width': '1px',
|
|
85
|
-
'--fc-border-radius-sm': '3px', // Micro rounding
|
|
86
|
-
'--fc-border-radius': '5px',
|
|
87
|
-
'--fc-border-radius-lg': '8px',
|
|
88
|
-
'--fc-border-radius-full': '9999px',
|
|
89
|
-
|
|
90
|
-
// Shadows - Minimal/Functional
|
|
91
|
-
'--fc-shadow-sm': '0 1px 1px rgba(0,0,0,0.05)',
|
|
92
|
-
'--fc-shadow': '0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06)',
|
|
93
|
-
'--fc-shadow-md': '0 4px 6px -1px rgba(0, 0, 0, 0.1)',
|
|
94
|
-
'--fc-shadow-lg': '0 10px 15px -3px rgba(0, 0, 0, 0.1)',
|
|
95
|
-
|
|
96
|
-
// Transitions - Snappy
|
|
97
|
-
'--fc-transition-fast': '100ms ease-out',
|
|
98
|
-
'--fc-transition': '150ms ease-out',
|
|
99
|
-
'--fc-transition-slow': '250ms ease-out',
|
|
100
|
-
|
|
101
|
-
// Z-index
|
|
102
|
-
'--fc-z-dropdown': '1000',
|
|
103
|
-
'--fc-z-modal': '2000',
|
|
104
|
-
'--fc-z-tooltip': '3000'
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Get CSS variable value
|
|
109
|
-
*/
|
|
110
|
-
static getCSSVariable(name, element = document.documentElement) {
|
|
111
|
-
return getComputedStyle(element).getPropertyValue(name).trim();
|
|
6
|
+
/**
|
|
7
|
+
* Default theme colors
|
|
8
|
+
*/
|
|
9
|
+
static colors = {
|
|
10
|
+
primary: '#3B82F6', // Modern Blue
|
|
11
|
+
secondary: '#64748B', // Slate
|
|
12
|
+
accent: '#F59E0B', // Amber
|
|
13
|
+
danger: '#EF4444', // Red
|
|
14
|
+
warning: '#F97316', // Orange
|
|
15
|
+
info: '#06B6D4', // Cyan
|
|
16
|
+
success: '#22C55E', // Green
|
|
17
|
+
light: '#F8FAFC',
|
|
18
|
+
dark: '#0F172A',
|
|
19
|
+
white: '#FFFFFF',
|
|
20
|
+
gray: {
|
|
21
|
+
50: '#F8FAFC',
|
|
22
|
+
100: '#F1F5F9',
|
|
23
|
+
200: '#E2E8F0',
|
|
24
|
+
300: '#CBD5E1',
|
|
25
|
+
400: '#94A3B8',
|
|
26
|
+
500: '#64748B',
|
|
27
|
+
600: '#475569',
|
|
28
|
+
700: '#334155',
|
|
29
|
+
800: '#1E293B',
|
|
30
|
+
900: '#0F172A'
|
|
112
31
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Common CSS variables
|
|
36
|
+
*/
|
|
37
|
+
static cssVariables = {
|
|
38
|
+
// "Pro" Palette - Functional & Sharp
|
|
39
|
+
'--fc-primary-color': '#2563EB', // International Blue (Focus)
|
|
40
|
+
'--fc-primary-hover': '#1D4ED8',
|
|
41
|
+
'--fc-primary-light': '#EFF6FF',
|
|
42
|
+
|
|
43
|
+
// Neutral Scale (Slate/Gray for structure)
|
|
44
|
+
'--fc-text-color': '#111827', // Almost Black
|
|
45
|
+
'--fc-text-secondary': '#6B7280', // Cool Gray
|
|
46
|
+
'--fc-text-light': '#9CA3AF',
|
|
47
|
+
|
|
48
|
+
'--fc-border-color': '#E5E7EB', // Crisp Light Gray
|
|
49
|
+
'--fc-border-color-hover': '#D1D5DB',
|
|
50
|
+
|
|
51
|
+
'--fc-background': '#FFFFFF',
|
|
52
|
+
'--fc-background-alt': '#FAFAFA', // Very subtle off-white
|
|
53
|
+
'--fc-background-hover': '#F3F4F6',
|
|
54
|
+
'--fc-background-active': '#E5E7EB',
|
|
55
|
+
|
|
56
|
+
// Semantic Colors
|
|
57
|
+
'--fc-accent-color': '#F59E0B',
|
|
58
|
+
'--fc-danger-color': '#EF4444',
|
|
59
|
+
'--fc-success-color': '#10B981',
|
|
60
|
+
|
|
61
|
+
// Typography - optimized for UI density
|
|
62
|
+
'--fc-font-family': 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
63
|
+
'--fc-font-size-xs': '11px',
|
|
64
|
+
'--fc-font-size-sm': '12px',
|
|
65
|
+
'--fc-font-size-base': '13px', // Slightly smaller for density
|
|
66
|
+
'--fc-font-size-lg': '15px',
|
|
67
|
+
'--fc-font-size-xl': '18px',
|
|
68
|
+
'--fc-font-size-2xl': '24px',
|
|
69
|
+
'--fc-line-height': '1.4',
|
|
70
|
+
'--fc-font-weight-normal': '400',
|
|
71
|
+
'--fc-font-weight-medium': '500',
|
|
72
|
+
'--fc-font-weight-semibold': '600',
|
|
73
|
+
'--fc-font-weight-bold': '700',
|
|
74
|
+
|
|
75
|
+
// Spacing - Tighter
|
|
76
|
+
'--fc-spacing-xs': '2px',
|
|
77
|
+
'--fc-spacing-sm': '6px',
|
|
78
|
+
'--fc-spacing-md': '10px',
|
|
79
|
+
'--fc-spacing-lg': '14px',
|
|
80
|
+
'--fc-spacing-xl': '20px',
|
|
81
|
+
'--fc-spacing-2xl': '28px',
|
|
82
|
+
|
|
83
|
+
// Border
|
|
84
|
+
'--fc-border-width': '1px',
|
|
85
|
+
'--fc-border-radius-sm': '3px', // Micro rounding
|
|
86
|
+
'--fc-border-radius': '5px',
|
|
87
|
+
'--fc-border-radius-lg': '8px',
|
|
88
|
+
'--fc-border-radius-full': '9999px',
|
|
89
|
+
|
|
90
|
+
// Shadows - Minimal/Functional
|
|
91
|
+
'--fc-shadow-sm': '0 1px 1px rgba(0,0,0,0.05)',
|
|
92
|
+
'--fc-shadow': '0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06)',
|
|
93
|
+
'--fc-shadow-md': '0 4px 6px -1px rgba(0, 0, 0, 0.1)',
|
|
94
|
+
'--fc-shadow-lg': '0 10px 15px -3px rgba(0, 0, 0, 0.1)',
|
|
95
|
+
|
|
96
|
+
// Transitions - Snappy
|
|
97
|
+
'--fc-transition-fast': '100ms ease-out',
|
|
98
|
+
'--fc-transition': '150ms ease-out',
|
|
99
|
+
'--fc-transition-slow': '250ms ease-out',
|
|
100
|
+
|
|
101
|
+
// Z-index
|
|
102
|
+
'--fc-z-dropdown': '1000',
|
|
103
|
+
'--fc-z-modal': '2000',
|
|
104
|
+
'--fc-z-tooltip': '3000'
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Get CSS variable value
|
|
109
|
+
*/
|
|
110
|
+
static getCSSVariable(name, element = document.documentElement) {
|
|
111
|
+
return getComputedStyle(element).getPropertyValue(name).trim();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Set CSS variables
|
|
116
|
+
*/
|
|
117
|
+
static setCSSVariables(variables, element = document.documentElement) {
|
|
118
|
+
Object.entries(variables).forEach(([key, value]) => {
|
|
119
|
+
element.style.setProperty(key, value);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Generate base styles
|
|
125
|
+
*/
|
|
126
|
+
static getBaseStyles() {
|
|
127
|
+
return `
|
|
128
128
|
:host {
|
|
129
129
|
/* Apply CSS variables */
|
|
130
130
|
${Object.entries(this.cssVariables)
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
.map(([key, value]) => `${key}: ${value};`)
|
|
132
|
+
.join('\n ')}
|
|
133
133
|
|
|
134
134
|
/* Base styles */
|
|
135
135
|
display: block;
|
|
@@ -178,13 +178,13 @@ export class StyleUtils {
|
|
|
178
178
|
outline-offset: 2px;
|
|
179
179
|
}
|
|
180
180
|
`;
|
|
181
|
-
|
|
181
|
+
}
|
|
182
182
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
183
|
+
/**
|
|
184
|
+
* Generate button styles
|
|
185
|
+
*/
|
|
186
|
+
static getButtonStyles() {
|
|
187
|
+
return `
|
|
188
188
|
.fc-btn {
|
|
189
189
|
display: inline-flex;
|
|
190
190
|
align-items: center;
|
|
@@ -270,108 +270,145 @@ export class StyleUtils {
|
|
|
270
270
|
border-radius: var(--fc-border-radius-full);
|
|
271
271
|
}
|
|
272
272
|
`;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Darken color by percentage
|
|
277
|
+
*/
|
|
278
|
+
static darken(color, percent) {
|
|
279
|
+
const num = parseInt(color.replace('#', ''), 16);
|
|
280
|
+
const amt = Math.round(2.55 * percent);
|
|
281
|
+
const R = (num >> 16) - amt;
|
|
282
|
+
const G = ((num >> 8) & 0x00ff) - amt;
|
|
283
|
+
const B = (num & 0x0000ff) - amt;
|
|
284
|
+
return (
|
|
285
|
+
'#' +
|
|
286
|
+
(
|
|
287
|
+
0x1000000 +
|
|
288
|
+
(R < 255 ? (R < 1 ? 0 : R) : 255) * 0x10000 +
|
|
289
|
+
(G < 255 ? (G < 1 ? 0 : G) : 255) * 0x100 +
|
|
290
|
+
(B < 255 ? (B < 1 ? 0 : B) : 255)
|
|
291
|
+
)
|
|
292
|
+
.toString(16)
|
|
293
|
+
.slice(1)
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Lighten color by percentage
|
|
299
|
+
*/
|
|
300
|
+
static lighten(color, percent) {
|
|
301
|
+
const num = parseInt(color.replace('#', ''), 16);
|
|
302
|
+
const amt = Math.round(2.55 * percent);
|
|
303
|
+
const R = (num >> 16) + amt;
|
|
304
|
+
const G = ((num >> 8) & 0x00ff) + amt;
|
|
305
|
+
const B = (num & 0x0000ff) + amt;
|
|
306
|
+
return (
|
|
307
|
+
'#' +
|
|
308
|
+
(
|
|
309
|
+
0x1000000 +
|
|
310
|
+
(R < 255 ? (R < 1 ? 0 : R) : 255) * 0x10000 +
|
|
311
|
+
(G < 255 ? (G < 1 ? 0 : G) : 255) * 0x100 +
|
|
312
|
+
(B < 255 ? (B < 1 ? 0 : B) : 255)
|
|
313
|
+
)
|
|
314
|
+
.toString(16)
|
|
315
|
+
.slice(1)
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Get contrast color (black or white) for background
|
|
321
|
+
*/
|
|
322
|
+
static getContrastColor(bgColor) {
|
|
323
|
+
const color = bgColor.replace('#', '');
|
|
324
|
+
const r = parseInt(color.substr(0, 2), 16);
|
|
325
|
+
const g = parseInt(color.substr(2, 2), 16);
|
|
326
|
+
const b = parseInt(color.substr(4, 2), 16);
|
|
327
|
+
const yiq = (r * 299 + g * 587 + b * 114) / 1000;
|
|
328
|
+
return yiq >= 128 ? '#000000' : '#FFFFFF';
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Sanitize color value to prevent CSS injection
|
|
333
|
+
* Returns the color if valid, or a fallback color if invalid
|
|
334
|
+
*/
|
|
335
|
+
static sanitizeColor(color, fallback = 'var(--fc-primary-color)') {
|
|
336
|
+
if (!color || typeof color !== 'string') {
|
|
337
|
+
return fallback;
|
|
273
338
|
}
|
|
274
339
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
const num = parseInt(color.replace('#', ''), 16);
|
|
280
|
-
const amt = Math.round(2.55 * percent);
|
|
281
|
-
const R = (num >> 16) - amt;
|
|
282
|
-
const G = (num >> 8 & 0x00FF) - amt;
|
|
283
|
-
const B = (num & 0x0000FF) - amt;
|
|
284
|
-
return '#' + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 +
|
|
285
|
-
(G < 255 ? G < 1 ? 0 : G : 255) * 0x100 +
|
|
286
|
-
(B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1);
|
|
340
|
+
// Trim and check for dangerous characters that could break out of CSS
|
|
341
|
+
const trimmed = color.trim();
|
|
342
|
+
if (/[;{}()<>\"\'\\]/.test(trimmed)) {
|
|
343
|
+
return fallback;
|
|
287
344
|
}
|
|
288
345
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
static lighten(color, percent) {
|
|
293
|
-
const num = parseInt(color.replace('#', ''), 16);
|
|
294
|
-
const amt = Math.round(2.55 * percent);
|
|
295
|
-
const R = (num >> 16) + amt;
|
|
296
|
-
const G = (num >> 8 & 0x00FF) + amt;
|
|
297
|
-
const B = (num & 0x0000FF) + amt;
|
|
298
|
-
return '#' + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 +
|
|
299
|
-
(G < 255 ? G < 1 ? 0 : G : 255) * 0x100 +
|
|
300
|
-
(B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1);
|
|
346
|
+
// Allow hex colors (#RGB, #RRGGBB, #RRGGBBAA)
|
|
347
|
+
if (/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/.test(trimmed)) {
|
|
348
|
+
return trimmed;
|
|
301
349
|
}
|
|
302
350
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
static getContrastColor(bgColor) {
|
|
307
|
-
const color = bgColor.replace('#', '');
|
|
308
|
-
const r = parseInt(color.substr(0, 2), 16);
|
|
309
|
-
const g = parseInt(color.substr(2, 2), 16);
|
|
310
|
-
const b = parseInt(color.substr(4, 2), 16);
|
|
311
|
-
const yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000;
|
|
312
|
-
return yiq >= 128 ? '#000000' : '#FFFFFF';
|
|
351
|
+
// Allow CSS variables
|
|
352
|
+
if (/^var\(--[a-zA-Z0-9-]+\)$/.test(trimmed)) {
|
|
353
|
+
return trimmed;
|
|
313
354
|
}
|
|
314
355
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
*/
|
|
319
|
-
static sanitizeColor(color, fallback = 'var(--fc-primary-color)') {
|
|
320
|
-
if (!color || typeof color !== 'string') {
|
|
321
|
-
return fallback;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// Trim and check for dangerous characters that could break out of CSS
|
|
325
|
-
const trimmed = color.trim();
|
|
326
|
-
if (/[;{}()<>\"\'\\]/.test(trimmed)) {
|
|
327
|
-
return fallback;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// Allow hex colors (#RGB, #RRGGBB, #RRGGBBAA)
|
|
331
|
-
if (/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/.test(trimmed)) {
|
|
332
|
-
return trimmed;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// Allow CSS variables
|
|
336
|
-
if (/^var\(--[a-zA-Z0-9-]+\)$/.test(trimmed)) {
|
|
337
|
-
return trimmed;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// Allow rgb/rgba with numbers only
|
|
341
|
-
if (/^rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(,\s*(0|1|0?\.\d+))?\s*\)$/.test(trimmed)) {
|
|
342
|
-
return trimmed;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// Allow safe CSS color keywords
|
|
346
|
-
const safeKeywords = [
|
|
347
|
-
'transparent', 'currentColor', 'inherit',
|
|
348
|
-
'black', 'white', 'red', 'green', 'blue', 'yellow', 'orange', 'purple',
|
|
349
|
-
'pink', 'brown', 'gray', 'grey', 'cyan', 'magenta', 'lime', 'navy',
|
|
350
|
-
'teal', 'aqua', 'maroon', 'olive', 'silver', 'fuchsia'
|
|
351
|
-
];
|
|
352
|
-
if (safeKeywords.includes(trimmed.toLowerCase())) {
|
|
353
|
-
return trimmed;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
return fallback;
|
|
356
|
+
// Allow rgb/rgba with numbers only
|
|
357
|
+
if (/^rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(,\s*(0|1|0?\.\d+))?\s*\)$/.test(trimmed)) {
|
|
358
|
+
return trimmed;
|
|
357
359
|
}
|
|
358
360
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
361
|
+
// Allow safe CSS color keywords
|
|
362
|
+
const safeKeywords = [
|
|
363
|
+
'transparent',
|
|
364
|
+
'currentColor',
|
|
365
|
+
'inherit',
|
|
366
|
+
'black',
|
|
367
|
+
'white',
|
|
368
|
+
'red',
|
|
369
|
+
'green',
|
|
370
|
+
'blue',
|
|
371
|
+
'yellow',
|
|
372
|
+
'orange',
|
|
373
|
+
'purple',
|
|
374
|
+
'pink',
|
|
375
|
+
'brown',
|
|
376
|
+
'gray',
|
|
377
|
+
'grey',
|
|
378
|
+
'cyan',
|
|
379
|
+
'magenta',
|
|
380
|
+
'lime',
|
|
381
|
+
'navy',
|
|
382
|
+
'teal',
|
|
383
|
+
'aqua',
|
|
384
|
+
'maroon',
|
|
385
|
+
'olive',
|
|
386
|
+
'silver',
|
|
387
|
+
'fuchsia'
|
|
388
|
+
];
|
|
389
|
+
if (safeKeywords.includes(trimmed.toLowerCase())) {
|
|
390
|
+
return trimmed;
|
|
368
391
|
}
|
|
369
392
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
393
|
+
return fallback;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Convert hex to rgba
|
|
398
|
+
*/
|
|
399
|
+
static hexToRgba(hex, alpha = 1) {
|
|
400
|
+
const color = hex.replace('#', '');
|
|
401
|
+
const r = parseInt(color.substr(0, 2), 16);
|
|
402
|
+
const g = parseInt(color.substr(2, 2), 16);
|
|
403
|
+
const b = parseInt(color.substr(4, 2), 16);
|
|
404
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Generate grid styles
|
|
409
|
+
*/
|
|
410
|
+
static getGridStyles() {
|
|
411
|
+
return `
|
|
375
412
|
.fc-grid {
|
|
376
413
|
display: grid;
|
|
377
414
|
gap: 1px;
|
|
@@ -403,34 +440,34 @@ export class StyleUtils {
|
|
|
403
440
|
letter-spacing: 0.5px;
|
|
404
441
|
}
|
|
405
442
|
`;
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Get responsive breakpoints
|
|
447
|
+
*/
|
|
448
|
+
static breakpoints = {
|
|
449
|
+
xs: '320px',
|
|
450
|
+
sm: '576px',
|
|
451
|
+
md: '768px',
|
|
452
|
+
lg: '992px',
|
|
453
|
+
xl: '1200px',
|
|
454
|
+
'2xl': '1400px'
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Generate media query
|
|
459
|
+
*/
|
|
460
|
+
static mediaQuery(breakpoint, styles) {
|
|
461
|
+
const size = this.breakpoints[breakpoint];
|
|
462
|
+
if (!size) return '';
|
|
463
|
+
return `@media (min-width: ${size}) { ${styles} }`;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Animation keyframes
|
|
468
|
+
*/
|
|
469
|
+
static getAnimations() {
|
|
470
|
+
return `
|
|
434
471
|
@keyframes fc-fade-in {
|
|
435
472
|
from { opacity: 0; }
|
|
436
473
|
to { opacity: 1; }
|
|
@@ -486,7 +523,7 @@ export class StyleUtils {
|
|
|
486
523
|
animation: fc-scale-in var(--fc-transition);
|
|
487
524
|
}
|
|
488
525
|
`;
|
|
489
|
-
|
|
526
|
+
}
|
|
490
527
|
}
|
|
491
528
|
|
|
492
|
-
export default StyleUtils;
|
|
529
|
+
export default StyleUtils;
|