@elementor/editor-controls 4.0.0-650 → 4.0.0-660
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/package.json +15 -15
- package/src/controls/size-control/hooks/use-size-unit-keyboard.tsx +55 -0
- package/src/controls/size-control/hooks/use-size-value.ts +75 -0
- package/src/controls/size-control/size-component.tsx +73 -0
- package/src/controls/size-control/size-field.tsx +89 -0
- package/src/controls/size-control/sync/get-units.ts +3 -0
- package/src/controls/size-control/types.ts +9 -0
- package/src/controls/size-control/utils/is-extended-unit.ts +8 -0
- package/src/controls/size-control/utils/is-numeric-value.ts +11 -0
- package/src/controls/size-control/utils/resolve-size-value.ts +84 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-controls",
|
|
3
3
|
"description": "This package contains the controls model and utils for the Elementor editor",
|
|
4
|
-
"version": "4.0.0-
|
|
4
|
+
"version": "4.0.0-660",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Elementor Team",
|
|
7
7
|
"homepage": "https://elementor.com/",
|
|
@@ -40,22 +40,22 @@
|
|
|
40
40
|
"dev": "tsup --config=../../tsup.dev.ts"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@elementor/editor-current-user": "4.0.0-
|
|
44
|
-
"@elementor/editor-elements": "4.0.0-
|
|
45
|
-
"@elementor/editor-props": "4.0.0-
|
|
46
|
-
"@elementor/editor-responsive": "4.0.0-
|
|
47
|
-
"@elementor/editor-ui": "4.0.0-
|
|
48
|
-
"@elementor/editor-v1-adapters": "4.0.0-
|
|
49
|
-
"@elementor/env": "4.0.0-
|
|
50
|
-
"@elementor/http-client": "4.0.0-
|
|
43
|
+
"@elementor/editor-current-user": "4.0.0-660",
|
|
44
|
+
"@elementor/editor-elements": "4.0.0-660",
|
|
45
|
+
"@elementor/editor-props": "4.0.0-660",
|
|
46
|
+
"@elementor/editor-responsive": "4.0.0-660",
|
|
47
|
+
"@elementor/editor-ui": "4.0.0-660",
|
|
48
|
+
"@elementor/editor-v1-adapters": "4.0.0-660",
|
|
49
|
+
"@elementor/env": "4.0.0-660",
|
|
50
|
+
"@elementor/http-client": "4.0.0-660",
|
|
51
51
|
"@elementor/icons": "^1.68.0",
|
|
52
|
-
"@elementor/locations": "4.0.0-
|
|
53
|
-
"@elementor/events": "4.0.0-
|
|
54
|
-
"@elementor/query": "4.0.0-
|
|
55
|
-
"@elementor/session": "4.0.0-
|
|
52
|
+
"@elementor/locations": "4.0.0-660",
|
|
53
|
+
"@elementor/events": "4.0.0-660",
|
|
54
|
+
"@elementor/query": "4.0.0-660",
|
|
55
|
+
"@elementor/session": "4.0.0-660",
|
|
56
56
|
"@elementor/ui": "1.36.17",
|
|
57
|
-
"@elementor/utils": "4.0.0-
|
|
58
|
-
"@elementor/wp-media": "4.0.0-
|
|
57
|
+
"@elementor/utils": "4.0.0-660",
|
|
58
|
+
"@elementor/wp-media": "4.0.0-660",
|
|
59
59
|
"@wordpress/i18n": "^5.13.0",
|
|
60
60
|
"@monaco-editor/react": "^4.7.0",
|
|
61
61
|
"dayjs": "^1.11.18",
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import { useTypingBuffer } from '../../../hooks/use-typing-buffer';
|
|
4
|
+
import { type SizeUnit } from '../types';
|
|
5
|
+
import { isExtendedUnit } from '../utils/is-extended-unit';
|
|
6
|
+
import { isNumericValue } from '../utils/is-numeric-value';
|
|
7
|
+
|
|
8
|
+
const UNIT_KEY_PATTERN = /^[a-zA-Z%]$/;
|
|
9
|
+
|
|
10
|
+
type Props = {
|
|
11
|
+
unit: SizeUnit;
|
|
12
|
+
units: SizeUnit[];
|
|
13
|
+
onUnitChange: ( unit: SizeUnit ) => void;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const useSizeUnitKeyboard = ( { unit, units, onUnitChange }: Props ) => {
|
|
17
|
+
const { appendKey, startsWith } = useTypingBuffer();
|
|
18
|
+
|
|
19
|
+
const onUnitKeyDown = ( event: React.KeyboardEvent< HTMLInputElement > ) => {
|
|
20
|
+
if ( units.length === 0 ) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const { key, altKey, ctrlKey, metaKey } = event;
|
|
25
|
+
|
|
26
|
+
if ( altKey || ctrlKey || metaKey ) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if ( isExtendedUnit( unit ) && isNumericValue( key ) ) {
|
|
31
|
+
const [ defaultUnit ] = units;
|
|
32
|
+
|
|
33
|
+
if ( defaultUnit ) {
|
|
34
|
+
onUnitChange( defaultUnit );
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if ( ! UNIT_KEY_PATTERN.test( key ) ) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
event.preventDefault();
|
|
45
|
+
|
|
46
|
+
const updatedBuffer = appendKey( key.toLowerCase() );
|
|
47
|
+
const matchedUnit = units.find( ( u ) => startsWith( u, updatedBuffer ) );
|
|
48
|
+
|
|
49
|
+
if ( matchedUnit ) {
|
|
50
|
+
onUnitChange( matchedUnit );
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return { onUnitKeyDown };
|
|
55
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { type SizePropValue } from '@elementor/editor-props';
|
|
3
|
+
|
|
4
|
+
import { useSyncExternalState } from '../../../hooks/use-sync-external-state';
|
|
5
|
+
import { type SizeUnit } from '../types';
|
|
6
|
+
import { isExtendedUnit } from '../utils/is-extended-unit';
|
|
7
|
+
import { createDefaultSizeValue, resolveSizeOnUnitChange, resolveSizeValue } from '../utils/resolve-size-value';
|
|
8
|
+
|
|
9
|
+
type SizeValue = SizePropValue[ 'value' ];
|
|
10
|
+
|
|
11
|
+
type UseSizeValueProps< T, U > = {
|
|
12
|
+
value: T | null;
|
|
13
|
+
onChange: ( value: T ) => void;
|
|
14
|
+
units: U[];
|
|
15
|
+
defaultUnit?: U;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const useSizeValue = < T extends SizeValue, U extends SizeUnit >( {
|
|
19
|
+
value,
|
|
20
|
+
onChange,
|
|
21
|
+
units,
|
|
22
|
+
defaultUnit,
|
|
23
|
+
}: UseSizeValueProps< T, U > ) => {
|
|
24
|
+
const resolvedValue = useMemo(
|
|
25
|
+
() => resolveSizeValue( value, { units, defaultUnit } ),
|
|
26
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
27
|
+
[ value?.size, value?.unit, defaultUnit ]
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const [ sizeValue, setSizeValue ] = useSyncExternalState< T >( {
|
|
31
|
+
external: resolvedValue as T,
|
|
32
|
+
setExternal: ( newState ) => {
|
|
33
|
+
// TODO we need to check behaviour that low level doesn't set to null only the high level components size component
|
|
34
|
+
// This will fix the issue of if size is empty string '' it gets sends to the model
|
|
35
|
+
// but on blur the size component set to null.
|
|
36
|
+
// But we need to test this behaviour
|
|
37
|
+
if ( newState !== null ) {
|
|
38
|
+
onChange( newState );
|
|
39
|
+
}
|
|
40
|
+
}, // TODO we will need to handle options, meta if context need them
|
|
41
|
+
persistWhen: ( next ) => hasChanged( next, resolvedValue as T ),
|
|
42
|
+
fallback: () => createDefaultSizeValue< T >( units, defaultUnit ),
|
|
43
|
+
} );
|
|
44
|
+
|
|
45
|
+
const setSize = ( newSize: string ) => {
|
|
46
|
+
if ( isExtendedUnit( sizeValue.unit ) ) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const trimmed = newSize.trim();
|
|
51
|
+
const parsed = Number( trimmed );
|
|
52
|
+
|
|
53
|
+
const newState = {
|
|
54
|
+
...sizeValue,
|
|
55
|
+
size: trimmed && ! isNaN( parsed ) ? parsed : '',
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
setSizeValue( newState );
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const setUnit = ( unit: SizeValue[ 'unit' ] ) => {
|
|
62
|
+
setSizeValue( { unit, size: resolveSizeOnUnitChange( sizeValue.size, unit ) } as T );
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
size: sizeValue.size,
|
|
67
|
+
unit: sizeValue.unit,
|
|
68
|
+
setSize,
|
|
69
|
+
setUnit,
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const hasChanged = ( next?: SizeValue | null, current?: SizeValue | null ): boolean => {
|
|
74
|
+
return next?.size !== current?.size || next?.unit !== current?.unit;
|
|
75
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type RefObject, useEffect } from 'react';
|
|
3
|
+
import type { SizePropValue } from '@elementor/editor-props';
|
|
4
|
+
import { usePopupState } from '@elementor/ui';
|
|
5
|
+
|
|
6
|
+
import { SizeField, type SizeFieldProps } from './size-field';
|
|
7
|
+
import { TextFieldPopover } from './ui/text-field-popover';
|
|
8
|
+
import { EXTENDED_UNITS } from './utils/resolve-size-value';
|
|
9
|
+
|
|
10
|
+
type SizeValue = SizePropValue[ 'value' ];
|
|
11
|
+
|
|
12
|
+
type SizeUnit = SizePropValue[ 'value' ][ 'unit' ];
|
|
13
|
+
|
|
14
|
+
type Props = SizeFieldProps< SizeValue, SizeUnit > & {
|
|
15
|
+
anchorRef?: RefObject< HTMLDivElement | null >;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const SizeComponent = ( { anchorRef, ...sizeFieldProps }: Props ) => {
|
|
19
|
+
const popupState = usePopupState( { variant: 'popover' } );
|
|
20
|
+
|
|
21
|
+
const isCustomUnit = sizeFieldProps?.value?.unit === EXTENDED_UNITS.custom;
|
|
22
|
+
const hasCustomUnitOption = sizeFieldProps.units.includes( EXTENDED_UNITS.custom );
|
|
23
|
+
|
|
24
|
+
useEffect( () => {
|
|
25
|
+
if ( isCustomUnit && anchorRef?.current && ! popupState.isOpen ) {
|
|
26
|
+
popupState.open( anchorRef?.current );
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
30
|
+
}, [ anchorRef, isCustomUnit ] );
|
|
31
|
+
|
|
32
|
+
const handleCustomSizeChange = ( event: React.ChangeEvent< HTMLInputElement > ) => {
|
|
33
|
+
sizeFieldProps.onChange( {
|
|
34
|
+
size: event.target.value,
|
|
35
|
+
unit: EXTENDED_UNITS.custom,
|
|
36
|
+
} );
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const handleSizeFieldClick = ( event: React.MouseEvent ) => {
|
|
40
|
+
if ( ( event.target as HTMLElement ).closest( 'input' ) && isCustomUnit ) {
|
|
41
|
+
popupState.open( anchorRef?.current );
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const popupAttributes = {
|
|
46
|
+
'aria-controls': popupState.isOpen ? popupState.popupId : undefined,
|
|
47
|
+
'aria-haspopup': true,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<>
|
|
52
|
+
<SizeField
|
|
53
|
+
{ ...sizeFieldProps }
|
|
54
|
+
InputProps={ {
|
|
55
|
+
...popupAttributes,
|
|
56
|
+
onClick: handleSizeFieldClick,
|
|
57
|
+
} }
|
|
58
|
+
unitSelectorProps={ {
|
|
59
|
+
menuItemsAttributes: hasCustomUnitOption ? { custom: popupAttributes } : undefined,
|
|
60
|
+
} }
|
|
61
|
+
/>
|
|
62
|
+
{ popupState.isOpen && anchorRef?.current && (
|
|
63
|
+
<TextFieldPopover
|
|
64
|
+
popupState={ popupState }
|
|
65
|
+
anchorRef={ anchorRef as RefObject< HTMLDivElement > }
|
|
66
|
+
value={ String( sizeFieldProps?.value?.size ?? '' ) }
|
|
67
|
+
onChange={ handleCustomSizeChange }
|
|
68
|
+
onClose={ () => {} }
|
|
69
|
+
/>
|
|
70
|
+
) }
|
|
71
|
+
</>
|
|
72
|
+
);
|
|
73
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { PropValue, SizePropValue } from '@elementor/editor-props';
|
|
3
|
+
import { MathFunctionIcon } from '@elementor/icons';
|
|
4
|
+
import { InputAdornment, type TextFieldProps } from '@elementor/ui';
|
|
5
|
+
|
|
6
|
+
import { useSizeUnitKeyboard } from './hooks/use-size-unit-keyboard';
|
|
7
|
+
import { useSizeValue } from './hooks/use-size-value';
|
|
8
|
+
import { type SizeUnit } from './types';
|
|
9
|
+
import { SizeInput } from './ui/size-input';
|
|
10
|
+
import { UnitSelector, type UnitSelectorProps } from './ui/unit-selector';
|
|
11
|
+
import { isExtendedUnit } from './utils/is-extended-unit';
|
|
12
|
+
|
|
13
|
+
export type SizeFieldProps< TValue extends SizePropValue[ 'value' ], TUnit extends SizeUnit > = {
|
|
14
|
+
units: TUnit[];
|
|
15
|
+
value: TValue | null;
|
|
16
|
+
placeholder?: string;
|
|
17
|
+
defaultUnit?: SizeUnit;
|
|
18
|
+
startIcon?: React.ReactNode;
|
|
19
|
+
onChange: ( value: TValue ) => void;
|
|
20
|
+
onBlur?: ( event: React.FocusEvent< HTMLInputElement > ) => void;
|
|
21
|
+
onKeyDown?: ( event: React.KeyboardEvent< HTMLInputElement > ) => void;
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
InputProps?: TextFieldProps[ 'InputProps' ];
|
|
24
|
+
unitSelectorProps?: Partial< UnitSelectorProps< TUnit > >;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const UNIT_DISPLAY_LABELS_OVERRIDES: Partial< Record< SizeUnit, React.ReactNode > > = {
|
|
28
|
+
custom: <MathFunctionIcon fontSize="tiny" />,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const SizeField = < T extends SizePropValue[ 'value' ], U extends SizeUnit >( {
|
|
32
|
+
value,
|
|
33
|
+
disabled,
|
|
34
|
+
InputProps,
|
|
35
|
+
defaultUnit,
|
|
36
|
+
startIcon,
|
|
37
|
+
onKeyDown,
|
|
38
|
+
onChange,
|
|
39
|
+
onBlur,
|
|
40
|
+
units,
|
|
41
|
+
unitSelectorProps,
|
|
42
|
+
}: SizeFieldProps< T, U > ) => {
|
|
43
|
+
const { size, unit, setSize, setUnit } = useSizeValue( { value, onChange, units, defaultUnit } );
|
|
44
|
+
const { onUnitKeyDown } = useSizeUnitKeyboard( { unit, onUnitChange: setUnit, units } );
|
|
45
|
+
|
|
46
|
+
const handleKeyDown = ( event: React.KeyboardEvent< HTMLInputElement > ) => {
|
|
47
|
+
onUnitKeyDown( event );
|
|
48
|
+
|
|
49
|
+
onKeyDown?.( event );
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const inputType = isExtendedUnit( unit ) ? 'text' : 'number';
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<SizeInput
|
|
56
|
+
type={ inputType }
|
|
57
|
+
value={ size }
|
|
58
|
+
onBlur={ onBlur }
|
|
59
|
+
onKeyDown={ handleKeyDown }
|
|
60
|
+
onChange={ ( event ) => setSize( event.target.value ) }
|
|
61
|
+
InputProps={ {
|
|
62
|
+
...InputProps,
|
|
63
|
+
autoComplete: 'off',
|
|
64
|
+
readOnly: isExtendedUnit( unit ),
|
|
65
|
+
startAdornment: startIcon && (
|
|
66
|
+
<InputAdornment position="start" disabled={ disabled }>
|
|
67
|
+
{ startIcon }
|
|
68
|
+
</InputAdornment>
|
|
69
|
+
),
|
|
70
|
+
endAdornment: (
|
|
71
|
+
<InputAdornment position="end">
|
|
72
|
+
<UnitSelector< U >
|
|
73
|
+
options={ units }
|
|
74
|
+
value={ unit as U }
|
|
75
|
+
onSelect={ ( newUnit ) => setUnit( newUnit ) }
|
|
76
|
+
isActive={ hasValue( size ) }
|
|
77
|
+
{ ...unitSelectorProps }
|
|
78
|
+
optionLabelOverrides={ UNIT_DISPLAY_LABELS_OVERRIDES }
|
|
79
|
+
/>
|
|
80
|
+
</InputAdornment>
|
|
81
|
+
),
|
|
82
|
+
} }
|
|
83
|
+
/>
|
|
84
|
+
);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const hasValue = ( value: PropValue ): boolean => {
|
|
88
|
+
return Boolean( value ) || value === 0;
|
|
89
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type LengthUnit = 'px' | '%' | 'em' | 'rem' | 'vw' | 'vh' | 'ch';
|
|
2
|
+
type AngleUnit = 'deg' | 'rad' | 'grad' | 'turn';
|
|
3
|
+
type TimeUnit = 's' | 'ms';
|
|
4
|
+
|
|
5
|
+
type ExtendedSizeOption = 'auto' | 'custom';
|
|
6
|
+
|
|
7
|
+
type Unit = LengthUnit | AngleUnit | TimeUnit;
|
|
8
|
+
|
|
9
|
+
export type SizeUnit = Unit | ExtendedSizeOption;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { type SizePropValue } from '@elementor/editor-props';
|
|
2
|
+
|
|
3
|
+
import { type SizeUnit } from '../types';
|
|
4
|
+
import { isExtendedUnit } from './is-extended-unit';
|
|
5
|
+
|
|
6
|
+
type SizeValue = SizePropValue[ 'value' ];
|
|
7
|
+
|
|
8
|
+
type ResolverContext< U > = {
|
|
9
|
+
units: U[];
|
|
10
|
+
defaultUnit?: U;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const DEFAULT_SIZE = '';
|
|
14
|
+
|
|
15
|
+
export const EXTENDED_UNITS = {
|
|
16
|
+
auto: 'auto',
|
|
17
|
+
custom: 'custom',
|
|
18
|
+
} as const;
|
|
19
|
+
|
|
20
|
+
export const resolveSizeValue = < TValue extends SizeValue | null, TUnit extends SizeValue[ 'unit' ] >(
|
|
21
|
+
value: TValue,
|
|
22
|
+
context: ResolverContext< TUnit >
|
|
23
|
+
) => {
|
|
24
|
+
if ( ! value ) {
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const { units, defaultUnit } = context;
|
|
29
|
+
|
|
30
|
+
const unit = resolveFallbackUnit( value.unit as TUnit, units, defaultUnit );
|
|
31
|
+
|
|
32
|
+
if ( unit === EXTENDED_UNITS.auto ) {
|
|
33
|
+
return { size: DEFAULT_SIZE, unit };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if ( unit === EXTENDED_UNITS.custom ) {
|
|
37
|
+
return { size: String( value.size ?? DEFAULT_SIZE ), unit };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
size: sanitizeSize( value.size ) ?? DEFAULT_SIZE,
|
|
42
|
+
unit,
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const resolveSizeOnUnitChange = (
|
|
47
|
+
size: SizeValue[ 'size' ],
|
|
48
|
+
unit: SizeValue[ 'unit' ]
|
|
49
|
+
): SizeValue[ 'size' ] => {
|
|
50
|
+
return isExtendedUnit( unit ) ? DEFAULT_SIZE : size;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const createDefaultSizeValue = < T extends SizeValue >( units: SizeUnit[], defaultUnit?: SizeUnit ): T => {
|
|
54
|
+
let unit = units[ 0 ];
|
|
55
|
+
|
|
56
|
+
if ( defaultUnit !== undefined ) {
|
|
57
|
+
unit = resolveFallbackUnit( defaultUnit, units ) as SizeUnit;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return { size: DEFAULT_SIZE, unit } as T;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const resolveFallbackUnit = < TUnit extends SizeUnit >(
|
|
64
|
+
unit: TUnit,
|
|
65
|
+
units: readonly TUnit[],
|
|
66
|
+
defaultUnit?: TUnit
|
|
67
|
+
): TUnit | string => {
|
|
68
|
+
if ( units.includes( unit ) ) {
|
|
69
|
+
return unit;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if ( defaultUnit && units.includes( defaultUnit ) ) {
|
|
73
|
+
return defaultUnit;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return units[ 0 ] ?? '';
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const sanitizeSize = ( size: SizeValue[ 'size' ] ): SizeValue[ 'size' ] => {
|
|
80
|
+
if ( typeof size === 'number' && isNaN( size ) ) {
|
|
81
|
+
return DEFAULT_SIZE;
|
|
82
|
+
}
|
|
83
|
+
return size;
|
|
84
|
+
};
|