@elementor/editor-controls 4.1.0-832 → 4.1.0-833
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/dist/index.d.mts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +287 -198
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +246 -159
- package/dist/index.mjs.map +1 -1
- package/package.json +15 -15
- package/src/controls/date-range-control.tsx +2 -2
- package/src/controls/date-string-control.tsx +46 -54
- package/src/controls/time-range-control.tsx +49 -0
- package/src/controls/time-string-control.tsx +62 -0
- package/src/hooks/use-form-field-suggestions.ts +2 -0
- package/src/index.ts +2 -0
- package/src/utils/date-time.ts +41 -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.1.0-
|
|
4
|
+
"version": "4.1.0-833",
|
|
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.1.0-
|
|
44
|
-
"@elementor/editor-elements": "4.1.0-
|
|
45
|
-
"@elementor/editor-props": "4.1.0-
|
|
46
|
-
"@elementor/editor-responsive": "4.1.0-
|
|
47
|
-
"@elementor/editor-ui": "4.1.0-
|
|
48
|
-
"@elementor/editor-v1-adapters": "4.1.0-
|
|
49
|
-
"@elementor/env": "4.1.0-
|
|
50
|
-
"@elementor/events": "4.1.0-
|
|
51
|
-
"@elementor/http-client": "4.1.0-
|
|
43
|
+
"@elementor/editor-current-user": "4.1.0-833",
|
|
44
|
+
"@elementor/editor-elements": "4.1.0-833",
|
|
45
|
+
"@elementor/editor-props": "4.1.0-833",
|
|
46
|
+
"@elementor/editor-responsive": "4.1.0-833",
|
|
47
|
+
"@elementor/editor-ui": "4.1.0-833",
|
|
48
|
+
"@elementor/editor-v1-adapters": "4.1.0-833",
|
|
49
|
+
"@elementor/env": "4.1.0-833",
|
|
50
|
+
"@elementor/events": "4.1.0-833",
|
|
51
|
+
"@elementor/http-client": "4.1.0-833",
|
|
52
52
|
"@elementor/icons": "^1.68.0",
|
|
53
|
-
"@elementor/locations": "4.1.0-
|
|
54
|
-
"@elementor/query": "4.1.0-
|
|
55
|
-
"@elementor/session": "4.1.0-
|
|
53
|
+
"@elementor/locations": "4.1.0-833",
|
|
54
|
+
"@elementor/query": "4.1.0-833",
|
|
55
|
+
"@elementor/session": "4.1.0-833",
|
|
56
56
|
"@elementor/ui": "1.37.5",
|
|
57
|
-
"@elementor/utils": "4.1.0-
|
|
58
|
-
"@elementor/wp-media": "4.1.0-
|
|
57
|
+
"@elementor/utils": "4.1.0-833",
|
|
58
|
+
"@elementor/wp-media": "4.1.0-833",
|
|
59
59
|
"@monaco-editor/react": "^4.7.0",
|
|
60
60
|
"@tiptap/extension-bold": "^3.11.1",
|
|
61
61
|
"@tiptap/extension-document": "^3.11.1",
|
|
@@ -14,7 +14,7 @@ const RANGE_LABELS = {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
const isMaxBeforeMin = ( minIso?: string | null, maxIso?: string | null ): boolean => {
|
|
17
|
-
if ( ! minIso || ! maxIso
|
|
17
|
+
if ( ! minIso || ! maxIso ) {
|
|
18
18
|
return false;
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -77,7 +77,7 @@ const BoundDateStringControl = ( {
|
|
|
77
77
|
} ) => {
|
|
78
78
|
return (
|
|
79
79
|
<PropKeyProvider bind={ bind }>
|
|
80
|
-
<DateStringControl ariaLabel={ ariaLabel } error={ error } />
|
|
80
|
+
<DateStringControl ariaLabel={ ariaLabel } error={ error } coerceInvalidToNull />
|
|
81
81
|
</PropKeyProvider>
|
|
82
82
|
);
|
|
83
83
|
};
|
|
@@ -1,70 +1,62 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { Dayjs } from 'dayjs';
|
|
3
|
-
import * as dayjs from 'dayjs';
|
|
4
3
|
import { dateStringPropTypeUtil } from '@elementor/editor-props';
|
|
5
4
|
import { DatePicker, LocalizationProvider } from '@elementor/ui';
|
|
6
5
|
|
|
7
6
|
import { useBoundProp } from '../bound-prop-context';
|
|
8
7
|
import ControlActions from '../control-actions/control-actions';
|
|
9
8
|
import { createControl } from '../create-control';
|
|
9
|
+
import { DATE_FORMAT, isValidDayjs, parseDateString } from '../utils/date-time';
|
|
10
10
|
|
|
11
11
|
type DateStringControlProps = {
|
|
12
12
|
inputDisabled?: boolean;
|
|
13
13
|
ariaLabel?: string;
|
|
14
14
|
error?: boolean;
|
|
15
|
+
coerceInvalidToNull?: boolean;
|
|
15
16
|
};
|
|
16
17
|
|
|
17
|
-
const
|
|
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
|
-
return null;
|
|
18
|
+
export const DateStringControl = createControl(
|
|
19
|
+
( { inputDisabled, ariaLabel, error, coerceInvalidToNull = false }: DateStringControlProps ) => {
|
|
20
|
+
const { value, setValue, disabled } = useBoundProp( dateStringPropTypeUtil );
|
|
21
|
+
|
|
22
|
+
const isDisabled = inputDisabled ?? disabled;
|
|
23
|
+
|
|
24
|
+
const slotProps = {
|
|
25
|
+
textField: {
|
|
26
|
+
size: 'tiny' as const,
|
|
27
|
+
fullWidth: true,
|
|
28
|
+
error,
|
|
29
|
+
inputProps: ariaLabel ? { 'aria-label': ariaLabel } : undefined,
|
|
30
|
+
},
|
|
31
|
+
openPickerButton: { size: 'tiny' as const },
|
|
32
|
+
openPickerIcon: { fontSize: 'tiny' as const },
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const handleChange = ( newValue: Dayjs | null, format: string ) => {
|
|
36
|
+
if ( ! newValue ) {
|
|
37
|
+
setValue( null );
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if ( coerceInvalidToNull && ! isValidDayjs( newValue ) ) {
|
|
42
|
+
setValue( null );
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
setValue( newValue.format( format ) );
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<LocalizationProvider>
|
|
51
|
+
<ControlActions>
|
|
52
|
+
<DatePicker
|
|
53
|
+
value={ parseDateString( value ?? '' ) }
|
|
54
|
+
onChange={ ( newValue: Dayjs | null ) => handleChange( newValue, DATE_FORMAT ) }
|
|
55
|
+
disabled={ isDisabled }
|
|
56
|
+
slotProps={ slotProps }
|
|
57
|
+
/>
|
|
58
|
+
</ControlActions>
|
|
59
|
+
</LocalizationProvider>
|
|
60
|
+
);
|
|
61
61
|
}
|
|
62
|
-
|
|
63
|
-
const parsed = ( dayjs as unknown as { default: ( s?: string | number | Date ) => Dayjs } ).default( raw );
|
|
64
|
-
|
|
65
|
-
return isValidDayjs( parsed ) ? parsed : null;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function isValidDayjs( value: Dayjs | null ): value is Dayjs {
|
|
69
|
-
return !! value && typeof value.isValid === 'function' && value.isValid();
|
|
70
|
-
}
|
|
62
|
+
);
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type PropKey, timeRangePropTypeUtil } from '@elementor/editor-props';
|
|
3
|
+
import { Grid, Stack } from '@elementor/ui';
|
|
4
|
+
import { __ } from '@wordpress/i18n';
|
|
5
|
+
|
|
6
|
+
import { PropKeyProvider, PropProvider, useBoundProp } from '../bound-prop-context';
|
|
7
|
+
import { ControlFormLabel } from '../components/control-form-label';
|
|
8
|
+
import { createControl } from '../create-control';
|
|
9
|
+
import { TimeStringControl } from './time-string-control';
|
|
10
|
+
|
|
11
|
+
const RANGE_LABELS = {
|
|
12
|
+
min: __( 'Start time', 'elementor' ),
|
|
13
|
+
max: __( 'End time', 'elementor' ),
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const TimeRangeControl = createControl( () => {
|
|
17
|
+
const { value, setValue, ...propContext } = useBoundProp( timeRangePropTypeUtil );
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<PropProvider { ...propContext } value={ value } setValue={ setValue }>
|
|
21
|
+
<Stack direction="row" gap={ 2 } flexWrap="nowrap">
|
|
22
|
+
<Grid container gap={ 0.75 } alignItems="center">
|
|
23
|
+
<Grid item xs={ 12 }>
|
|
24
|
+
<ControlFormLabel>{ RANGE_LABELS.min }</ControlFormLabel>
|
|
25
|
+
</Grid>
|
|
26
|
+
<Grid item xs={ 12 }>
|
|
27
|
+
<BoundTimeStringControl bind={ 'min' } ariaLabel={ RANGE_LABELS.min } />
|
|
28
|
+
</Grid>
|
|
29
|
+
</Grid>
|
|
30
|
+
<Grid container gap={ 0.75 } alignItems="center">
|
|
31
|
+
<Grid item xs={ 12 }>
|
|
32
|
+
<ControlFormLabel>{ RANGE_LABELS.max }</ControlFormLabel>
|
|
33
|
+
</Grid>
|
|
34
|
+
<Grid item xs={ 12 }>
|
|
35
|
+
<BoundTimeStringControl bind={ 'max' } ariaLabel={ RANGE_LABELS.max } />
|
|
36
|
+
</Grid>
|
|
37
|
+
</Grid>
|
|
38
|
+
</Stack>
|
|
39
|
+
</PropProvider>
|
|
40
|
+
);
|
|
41
|
+
} );
|
|
42
|
+
|
|
43
|
+
const BoundTimeStringControl = ( { bind, ariaLabel }: { bind: PropKey; ariaLabel?: string } ) => {
|
|
44
|
+
return (
|
|
45
|
+
<PropKeyProvider bind={ bind }>
|
|
46
|
+
<TimeStringControl ariaLabel={ ariaLabel } coerceInvalidToNull />
|
|
47
|
+
</PropKeyProvider>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { Dayjs } from 'dayjs';
|
|
3
|
+
import { timeStringPropTypeUtil } from '@elementor/editor-props';
|
|
4
|
+
import { LocalizationProvider, TimePicker } from '@elementor/ui';
|
|
5
|
+
|
|
6
|
+
import { useBoundProp } from '../bound-prop-context';
|
|
7
|
+
import ControlActions from '../control-actions/control-actions';
|
|
8
|
+
import { createControl } from '../create-control';
|
|
9
|
+
import { isValidDayjs, parseTimeString, TIME_FORMAT } from '../utils/date-time';
|
|
10
|
+
|
|
11
|
+
type TimeStringControlProps = {
|
|
12
|
+
inputDisabled?: boolean;
|
|
13
|
+
ariaLabel?: string;
|
|
14
|
+
error?: boolean;
|
|
15
|
+
coerceInvalidToNull?: boolean;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const TimeStringControl = createControl(
|
|
19
|
+
( { inputDisabled, ariaLabel, error, coerceInvalidToNull = false }: TimeStringControlProps ) => {
|
|
20
|
+
const { value, setValue, disabled } = useBoundProp( timeStringPropTypeUtil );
|
|
21
|
+
|
|
22
|
+
const isDisabled = inputDisabled ?? disabled;
|
|
23
|
+
|
|
24
|
+
const slotProps = {
|
|
25
|
+
textField: {
|
|
26
|
+
size: 'tiny' as const,
|
|
27
|
+
fullWidth: true,
|
|
28
|
+
error,
|
|
29
|
+
inputProps: ariaLabel ? { 'aria-label': ariaLabel } : undefined,
|
|
30
|
+
},
|
|
31
|
+
openPickerButton: { size: 'tiny' as const },
|
|
32
|
+
openPickerIcon: { fontSize: 'tiny' as const },
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const handleChange = ( newValue: Dayjs | null, format: string ) => {
|
|
36
|
+
if ( ! newValue ) {
|
|
37
|
+
setValue( null );
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if ( coerceInvalidToNull && ! isValidDayjs( newValue ) ) {
|
|
42
|
+
setValue( null );
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
setValue( newValue.format( format ) );
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<LocalizationProvider>
|
|
51
|
+
<ControlActions>
|
|
52
|
+
<TimePicker
|
|
53
|
+
value={ parseTimeString( value ?? '' ) }
|
|
54
|
+
onChange={ ( newValue: Dayjs | null ) => handleChange( newValue, TIME_FORMAT ) }
|
|
55
|
+
disabled={ isDisabled }
|
|
56
|
+
slotProps={ slotProps }
|
|
57
|
+
/>
|
|
58
|
+
</ControlActions>
|
|
59
|
+
</LocalizationProvider>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
);
|
package/src/index.ts
CHANGED
|
@@ -38,6 +38,8 @@ export { enqueueFont } from './controls/font-family-control/enqueue-font';
|
|
|
38
38
|
export { transitionProperties, transitionsItemsList } from './controls/transition-control/data';
|
|
39
39
|
export { DateTimeControl } from './controls/date-time-control';
|
|
40
40
|
export { DateRangeControl } from './controls/date-range-control';
|
|
41
|
+
export { TimeStringControl } from './controls/time-string-control';
|
|
42
|
+
export { TimeRangeControl } from './controls/time-range-control';
|
|
41
43
|
export { InlineEditingControl } from './controls/inline-editing-control';
|
|
42
44
|
export { EmailFormActionControl } from './controls/email-form-action-control';
|
|
43
45
|
export { AttachmentTypeControl } from './controls/attachment-type-control';
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Dayjs } from 'dayjs';
|
|
2
|
+
import * as dayjs from 'dayjs';
|
|
3
|
+
|
|
4
|
+
export const DATE_FORMAT = 'YYYY-MM-DD';
|
|
5
|
+
export const TIME_FORMAT = 'HH:mm';
|
|
6
|
+
|
|
7
|
+
export function isValidDayjs( value: Dayjs | null ): value is Dayjs {
|
|
8
|
+
return !! value && typeof value.isValid === 'function' && value.isValid();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function parseDateString( raw: string ): Dayjs | null {
|
|
12
|
+
if ( ! raw ) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const parsed = ( dayjs as unknown as { default: ( s?: string | number | Date ) => Dayjs } ).default( raw );
|
|
17
|
+
|
|
18
|
+
return isValidDayjs( parsed ) ? parsed : null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function parseTimeString( raw: string ): Dayjs | null {
|
|
22
|
+
if ( ! raw ) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const [ hours, minutes, seconds ] = raw.split( ':' );
|
|
27
|
+
const h = Number.parseInt( hours ?? '', 10 );
|
|
28
|
+
const m = Number.parseInt( minutes ?? '', 10 );
|
|
29
|
+
const s = Number.parseInt( seconds ?? '0', 10 );
|
|
30
|
+
|
|
31
|
+
if ( Number.isNaN( h ) || Number.isNaN( m ) ) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const base = ( dayjs as unknown as { default: () => Dayjs } ).default();
|
|
36
|
+
return base
|
|
37
|
+
.hour( h )
|
|
38
|
+
.minute( m )
|
|
39
|
+
.second( Number.isNaN( s ) ? 0 : s )
|
|
40
|
+
.millisecond( 0 );
|
|
41
|
+
}
|