@elementor/editor-controls 4.1.0-821 → 4.1.0-823

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 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-821",
4
+ "version": "4.1.0-823",
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-821",
44
- "@elementor/editor-elements": "4.1.0-821",
45
- "@elementor/editor-props": "4.1.0-821",
46
- "@elementor/editor-responsive": "4.1.0-821",
47
- "@elementor/editor-ui": "4.1.0-821",
48
- "@elementor/editor-v1-adapters": "4.1.0-821",
49
- "@elementor/env": "4.1.0-821",
50
- "@elementor/events": "4.1.0-821",
51
- "@elementor/http-client": "4.1.0-821",
43
+ "@elementor/editor-current-user": "4.1.0-823",
44
+ "@elementor/editor-elements": "4.1.0-823",
45
+ "@elementor/editor-props": "4.1.0-823",
46
+ "@elementor/editor-responsive": "4.1.0-823",
47
+ "@elementor/editor-ui": "4.1.0-823",
48
+ "@elementor/editor-v1-adapters": "4.1.0-823",
49
+ "@elementor/env": "4.1.0-823",
50
+ "@elementor/events": "4.1.0-823",
51
+ "@elementor/http-client": "4.1.0-823",
52
52
  "@elementor/icons": "^1.68.0",
53
- "@elementor/locations": "4.1.0-821",
54
- "@elementor/query": "4.1.0-821",
55
- "@elementor/session": "4.1.0-821",
53
+ "@elementor/locations": "4.1.0-823",
54
+ "@elementor/query": "4.1.0-823",
55
+ "@elementor/session": "4.1.0-823",
56
56
  "@elementor/ui": "1.37.5",
57
- "@elementor/utils": "4.1.0-821",
58
- "@elementor/wp-media": "4.1.0-821",
57
+ "@elementor/utils": "4.1.0-823",
58
+ "@elementor/wp-media": "4.1.0-823",
59
59
  "@monaco-editor/react": "^4.7.0",
60
60
  "@tiptap/extension-bold": "^3.11.1",
61
61
  "@tiptap/extension-document": "^3.11.1",
@@ -0,0 +1,83 @@
1
+ import * as React from 'react';
2
+ import { dateRangePropTypeUtil, dateStringPropTypeUtil, type PropKey } from '@elementor/editor-props';
3
+ import { FormHelperText, 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 { DateStringControl } from './date-string-control';
10
+
11
+ const RANGE_LABELS = {
12
+ min: __( 'Min date', 'elementor' ),
13
+ max: __( 'Max date', 'elementor' ),
14
+ };
15
+
16
+ const isMaxBeforeMin = ( minIso?: string | null, maxIso?: string | null ): boolean => {
17
+ if ( ! minIso || ! maxIso || [ minIso, maxIso ].some( ( v ) => v === 'Invalid Date' ) ) {
18
+ return false;
19
+ }
20
+
21
+ return maxIso < minIso;
22
+ };
23
+
24
+ const RANGE_ERROR_MESSAGE = __( 'Max date must be on or after Min date', 'elementor' );
25
+
26
+ export const DateRangeControl = createControl( () => {
27
+ const { value, setValue, ...propContext } = useBoundProp( dateRangePropTypeUtil );
28
+
29
+ const minString = dateStringPropTypeUtil.extract( value?.min );
30
+ const maxString = dateStringPropTypeUtil.extract( value?.max );
31
+
32
+ const hasInvalidRange = isMaxBeforeMin( minString, maxString );
33
+
34
+ return (
35
+ <PropProvider { ...propContext } value={ value } setValue={ setValue }>
36
+ <Stack gap={ 0.75 }>
37
+ <Stack direction="row" gap={ 2 } flexWrap="nowrap">
38
+ <Grid container gap={ 0.75 } alignItems="center">
39
+ <Grid item xs={ 12 }>
40
+ <ControlFormLabel>{ RANGE_LABELS.min }</ControlFormLabel>
41
+ </Grid>
42
+ <Grid item xs={ 12 }>
43
+ <BoundDateStringControl
44
+ bind={ 'min' }
45
+ ariaLabel={ RANGE_LABELS.min }
46
+ error={ hasInvalidRange }
47
+ />
48
+ </Grid>
49
+ </Grid>
50
+ <Grid container gap={ 0.75 } alignItems="center">
51
+ <Grid item xs={ 12 }>
52
+ <ControlFormLabel>{ RANGE_LABELS.max }</ControlFormLabel>
53
+ </Grid>
54
+ <Grid item xs={ 12 }>
55
+ <BoundDateStringControl
56
+ bind={ 'max' }
57
+ ariaLabel={ RANGE_LABELS.max }
58
+ error={ hasInvalidRange }
59
+ />
60
+ </Grid>
61
+ </Grid>
62
+ </Stack>
63
+ { hasInvalidRange && <FormHelperText error>{ RANGE_ERROR_MESSAGE }</FormHelperText> }
64
+ </Stack>
65
+ </PropProvider>
66
+ );
67
+ } );
68
+
69
+ const BoundDateStringControl = ( {
70
+ bind,
71
+ ariaLabel,
72
+ error,
73
+ }: {
74
+ bind: PropKey;
75
+ ariaLabel?: string;
76
+ error?: boolean;
77
+ } ) => {
78
+ return (
79
+ <PropKeyProvider bind={ bind }>
80
+ <DateStringControl ariaLabel={ ariaLabel } error={ error } />
81
+ </PropKeyProvider>
82
+ );
83
+ };
@@ -0,0 +1,70 @@
1
+ import * as React from 'react';
2
+ import type { Dayjs } from 'dayjs';
3
+ import * as dayjs from 'dayjs';
4
+ import { dateStringPropTypeUtil } from '@elementor/editor-props';
5
+ import { DatePicker, LocalizationProvider } from '@elementor/ui';
6
+
7
+ import { useBoundProp } from '../bound-prop-context';
8
+ import ControlActions from '../control-actions/control-actions';
9
+ import { createControl } from '../create-control';
10
+
11
+ type DateStringControlProps = {
12
+ inputDisabled?: boolean;
13
+ ariaLabel?: string;
14
+ error?: boolean;
15
+ };
16
+
17
+ const DATE_FORMAT = 'YYYY-MM-DD';
18
+
19
+ export const DateStringControl = createControl( ( { inputDisabled, ariaLabel, error }: 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
+ setValue( newValue.format( format ) );
42
+ };
43
+
44
+ return (
45
+ <LocalizationProvider>
46
+ <ControlActions>
47
+ <DatePicker
48
+ value={ parseDateString( value ?? '' ) }
49
+ onChange={ ( newValue: Dayjs | null ) => handleChange( newValue, DATE_FORMAT ) }
50
+ disabled={ isDisabled }
51
+ slotProps={ slotProps }
52
+ />
53
+ </ControlActions>
54
+ </LocalizationProvider>
55
+ );
56
+ } );
57
+
58
+ function parseDateString( raw: string ): Dayjs | null {
59
+ if ( ! raw ) {
60
+ return null;
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
+ }
package/src/index.ts CHANGED
@@ -37,6 +37,7 @@ export { PopoverContent } from './components/popover-content';
37
37
  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
+ export { DateRangeControl } from './controls/date-range-control';
40
41
  export { InlineEditingControl } from './controls/inline-editing-control';
41
42
  export { EmailFormActionControl } from './controls/email-form-action-control';
42
43
  export { UnstableSizeControl } from './controls/size-control/unstable-size-control';