-
Notifications
You must be signed in to change notification settings - Fork 139
Expand file tree
/
Copy pathstyle.ts
More file actions
155 lines (134 loc) · 5.74 KB
/
style.ts
File metadata and controls
155 lines (134 loc) · 5.74 KB
1
2
3
4
5
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import React from 'react';
import { isDefined } from "@/utils/nullables";
import { executeScriptSync } from '@/providers/form/utils';
import { IPropertySetting } from '..';
export interface DimensionValue {
value: number;
unit: 'px' | '%' | 'vw' | 'vh' | 'em' | 'rem' | 'auto' | 'none';
}
/**
* Type guard to check if a value is a valid dimension input type
* @param value - The value to check
* @returns true if the value is string, number, null, or undefined
*/
const isValidDimensionResult = (value: unknown): value is string | number | null | undefined => {
const valueType = typeof value;
return valueType === 'string' || valueType === 'number' || value === null || value === undefined;
};
/**
* Parse a dimension value into its numeric value and unit
* @param value - The dimension value to parse (e.g., "50vw", "100%", 300, "auto", or JS code object)
* @param context - Optional context object containing available constants (from useAvailableConstantsData)
* @returns Parsed dimension object with value and unit, or null if invalid
*/
export const parseDimension = (value: string | number | null | undefined | IPropertySetting, context?: object): DimensionValue | null => {
if (!isDefined(value)) return null;
if (typeof value === 'number') {
return { value, unit: 'px' };
}
// Handle JavaScript code execution for dynamic values
if (typeof value === 'object' && value._mode === 'code' && value._code) {
try {
const executedValue = executeScriptSync(value._code, context ?? {});
// Validate that the executed result is a valid dimension type
if (!isValidDimensionResult(executedValue)) {
console.error(
`Invalid dimension value returned from script execution. Expected string, number, null, or undefined but got ${typeof executedValue}:`,
executedValue,
);
return null;
}
// Recursively parse the validated result
return parseDimension(executedValue, context);
} catch (error) {
console.error('Error executing dimension code:', error);
return null;
}
}
// Handle IPropertySetting with _mode === 'value' - extract the underlying value
if (typeof value === 'object' && value._mode === 'value' && isDefined(value._value)) {
// Validate that _value is a valid dimension type before recursing
if (!isValidDimensionResult(value._value)) {
console.error(
`Invalid dimension value in IPropertySetting._value. Expected string, number, null, or undefined but got ${typeof value._value}:`,
value._value,
);
return null;
}
return parseDimension(value._value, context);
}
if (typeof value !== 'string') return null;
if (value === 'auto' || value === 'none') {
return { value: 0, unit: value };
}
// Match number with optional unit
const match = /^(-?\d+(?:\.\d+)?)(px|%|vw|vh|em|rem)?$/.exec(value.trim());
if (match && match[1] !== undefined) {
const unit = match[2] || 'px';
// Type guard: validate unit is one of the allowed values
if (unit === 'px' || unit === '%' || unit === 'vw' || unit === 'vh' || unit === 'em' || unit === 'rem') {
return {
value: parseFloat(match[1]),
unit,
};
}
}
return null;
};
/**
* Add 'px' unit to bare numbers, preserve existing units
* @param value - The value to add units to
* @param context - Optional context object containing available constants (from useAvailableConstantsData)
* @returns String with appropriate units, or undefined
*/
export const addPx = (value: number | string | null | undefined, context?: object): string | undefined => {
const parsed = parseDimension(value, context);
if (!parsed) return undefined;
if (parsed.unit === 'auto' || parsed.unit === 'none') {
return parsed.unit;
}
return `${parsed.value}${parsed.unit}`;
};
/**
* Returns style overrides for ghost buttons.
* Ghost buttons display only foreground color (text/icon) with no background, border, or shadow.
* These overrides ensure ghost buttons maintain their transparent appearance.
*
* @returns Style object with transparent background, no border, and no shadow
* @example
* const ghostStyles = getGhostStyleOverrides();
* // Returns: { background: 'transparent', backgroundColor: 'transparent', border: 'none', boxShadow: 'none' }
*/
export const getGhostStyleOverrides = (fontStyles?: React.CSSProperties): React.CSSProperties => {
return {
...fontStyles,
background: 'transparent',
backgroundColor: 'transparent',
border: 'none',
boxShadow: 'none',
color: fontStyles?.color ?? '#000',
};
};
export const hasNumber = (str: string | number): boolean => typeof str === 'number' ? true : /\d/.test(str);
export const getTagStyle = (style: React.CSSProperties = {}, hasColor: boolean = false): React.CSSProperties => {
const { backgroundColor, backgroundImage, borderColor, borderTopColor,
borderLeftColor, borderRightColor, borderBottomColor, color, ...rest } = style;
return hasColor ? { ...rest, margin: 0 } : style;
};
/**
* Caps percentage width values at a maximum percentage to prevent layout issues.
* @param value - The width value to cap (can be a number, string, null, or undefined)
* @param maxPercentage - The maximum percentage value (default: 98)
* @returns The capped value or the original value if not a percentage string
*/
export const capPercentageWidth = (value: number | string | null | undefined, maxPercentage: number = 98): number | string | null | undefined => {
if (!value) return value;
// Check if it's a percentage string (e.g., "99%", "100%")
if (typeof value === 'string' && value.endsWith('%')) {
const numericValue = parseFloat(value);
if (!isNaN(numericValue) && numericValue > maxPercentage) {
return `${maxPercentage}%`;
}
}
return value;
};