@elementor/editor-controls 0.4.0 → 0.5.0

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.
@@ -1,53 +1,38 @@
1
1
  import * as React from 'react';
2
- import { imagePropTypeUtil, type ImageSrcPropValue, type PropValue, type SizePropValue } from '@elementor/editor-props';
2
+ import { imagePropTypeUtil } from '@elementor/editor-props';
3
3
  import { Grid, Stack } from '@elementor/ui';
4
4
  import { __ } from '@wordpress/i18n';
5
5
 
6
- import { BoundPropProvider, useBoundProp } from '../bound-prop-context';
6
+ import { PropKeyProvider, PropProvider, useBoundProp } from '../bound-prop-context';
7
7
  import { ControlLabel } from '../components/control-label';
8
8
  import { createControl } from '../create-control';
9
9
  import { ImageMediaControl } from './image-media-control';
10
10
  import { SelectControl } from './select-control';
11
11
 
12
- type SetContextValue = ( v: PropValue ) => void;
13
-
14
12
  export type ImageControlProps = {
15
13
  sizes: { label: string; value: string }[];
16
14
  };
17
15
 
18
16
  export const ImageControl = createControl( ( props: ImageControlProps ) => {
19
- const { value, setValue } = useBoundProp( imagePropTypeUtil );
20
- const { src, size } = value || {};
21
-
22
- const setImageSrc = ( newValue: ImageSrcPropValue ) => {
23
- setValue( {
24
- src: newValue,
25
- size: size as SizePropValue,
26
- } );
27
- };
28
-
29
- const setImageSize = ( newValue: SizePropValue ) => {
30
- setValue( {
31
- src: src as ImageSrcPropValue,
32
- size: newValue,
33
- } );
34
- };
17
+ const propContext = useBoundProp( imagePropTypeUtil );
35
18
 
36
19
  return (
37
- <Stack gap={ 1.5 }>
38
- <BoundPropProvider value={ src } setValue={ setImageSrc as SetContextValue } bind={ 'src' }>
39
- <ImageMediaControl />
40
- </BoundPropProvider>
41
- <BoundPropProvider value={ size } setValue={ setImageSize as SetContextValue } bind={ 'size' }>
42
- <Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
43
- <Grid item xs={ 6 }>
44
- <ControlLabel> { __( 'Image Resolution', 'elementor' ) }</ControlLabel>
45
- </Grid>
46
- <Grid item xs={ 6 }>
47
- <SelectControl options={ props.sizes } />
20
+ <PropProvider { ...propContext }>
21
+ <Stack gap={ 1.5 }>
22
+ <PropKeyProvider bind={ 'src' }>
23
+ <ImageMediaControl />
24
+ </PropKeyProvider>
25
+ <PropKeyProvider bind={ 'size' }>
26
+ <Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
27
+ <Grid item xs={ 6 }>
28
+ <ControlLabel> { __( 'Image Resolution', 'elementor' ) }</ControlLabel>
29
+ </Grid>
30
+ <Grid item xs={ 6 }>
31
+ <SelectControl options={ props.sizes } />
32
+ </Grid>
48
33
  </Grid>
49
- </Grid>
50
- </BoundPropProvider>
51
- </Stack>
34
+ </PropKeyProvider>
35
+ </Stack>
36
+ </PropProvider>
52
37
  );
53
38
  } );
@@ -14,7 +14,7 @@ export const ImageMediaControl = createControl( () => {
14
14
  const { id, url } = value ?? {};
15
15
 
16
16
  const { data: attachment, isFetching } = useWpMediaAttachment( id?.value || null );
17
- const src = attachment?.url ?? url;
17
+ const src = attachment?.url ?? url?.value ?? null;
18
18
 
19
19
  const { open } = useWpMediaFrame( {
20
20
  types: [ 'image' ],
@@ -1,89 +1,88 @@
1
1
  import * as React from 'react';
2
- import { type LinkPropValue, type UrlPropValue } from '@elementor/editor-props';
2
+ import { linkPropTypeUtil, type LinkPropValue } from '@elementor/editor-props';
3
3
  import { MinusIcon, PlusIcon } from '@elementor/icons';
4
4
  import { Collapse, Divider, Grid, IconButton, Stack, Switch } from '@elementor/ui';
5
5
  import { __ } from '@wordpress/i18n';
6
6
 
7
- import { BoundPropProvider, useBoundProp } from '../bound-prop-context';
7
+ import { PropKeyProvider, PropProvider, useBoundProp } from '../bound-prop-context';
8
8
  import { ControlLabel } from '../components/control-label';
9
9
  import { createControl } from '../create-control';
10
10
  import { UrlControl } from './url-control';
11
11
 
12
12
  const SIZE = 'tiny';
13
13
 
14
- const DEFAULT_LINK_CONTROL_VALUE: LinkPropValue = {
15
- $$type: 'link',
16
- value: {
17
- enabled: false,
18
- href: {
19
- $$type: 'url',
20
- value: '',
21
- },
22
- isTargetBlank: false,
14
+ const DEFAULT_LINK_CONTROL_VALUE: LinkPropValue[ 'value' ] = {
15
+ enabled: false,
16
+ href: {
17
+ $$type: 'url',
18
+ value: '',
23
19
  },
20
+ isTargetBlank: false,
24
21
  };
25
22
 
26
23
  export const LinkControl = createControl( () => {
27
- const { value = DEFAULT_LINK_CONTROL_VALUE, setValue } = useBoundProp< LinkPropValue >();
28
- const { enabled, href, isTargetBlank } = value?.value || {};
29
-
30
- const handleOnChange = < T extends keyof LinkPropValue[ 'value' ] >(
31
- key: T,
32
- newValue: LinkPropValue[ 'value' ][ T ]
33
- ) => {
34
- setValue( {
35
- $$type: 'link',
36
- value: {
37
- ...( value?.value ?? DEFAULT_LINK_CONTROL_VALUE.value ),
38
- [ key ]: newValue,
39
- },
40
- } );
41
- };
24
+ const { value = DEFAULT_LINK_CONTROL_VALUE, ...propContext } = useBoundProp( linkPropTypeUtil );
42
25
 
43
26
  return (
44
- <Stack gap={ 1.5 }>
45
- <Divider />
46
- <Stack
47
- direction="row"
48
- sx={ {
49
- justifyContent: 'space-between',
50
- alignItems: 'center',
51
- } }
52
- >
53
- <ControlLabel>{ __( 'Link', 'elementor' ) }</ControlLabel>
54
- <IconButton size={ SIZE } onClick={ () => handleOnChange( 'enabled', ! enabled ) }>
55
- { enabled ? <MinusIcon fontSize={ SIZE } /> : <PlusIcon fontSize={ SIZE } /> }
56
- </IconButton>
57
- </Stack>
58
- <Collapse in={ enabled } timeout="auto" unmountOnExit>
59
- <Stack gap={ 1.5 }>
60
- <BoundPropProvider
61
- value={ href }
62
- setValue={ ( newHref ) => handleOnChange( 'href', newHref as UrlPropValue ) }
63
- bind={ 'href' }
64
- >
65
- <UrlControl placeholder={ __( 'Paste URL or type', 'elementor' ) } />
66
- </BoundPropProvider>
67
-
68
- <SwitchControl
69
- value={ isTargetBlank }
70
- onSwitch={ () => handleOnChange( 'isTargetBlank', ! isTargetBlank ) }
71
- />
27
+ <PropProvider { ...propContext } value={ value }>
28
+ <Stack gap={ 1.5 }>
29
+ <Divider />
30
+ <Stack
31
+ direction="row"
32
+ sx={ {
33
+ justifyContent: 'space-between',
34
+ alignItems: 'center',
35
+ } }
36
+ >
37
+ <ControlLabel>{ __( 'Link', 'elementor' ) }</ControlLabel>
38
+ <PropKeyProvider bind={ 'enabled' }>
39
+ <ToggleIconControl />
40
+ </PropKeyProvider>
72
41
  </Stack>
73
- </Collapse>
74
- </Stack>
42
+ <Collapse in={ value?.enabled } timeout="auto" unmountOnExit>
43
+ <Stack gap={ 1.5 }>
44
+ <PropKeyProvider bind={ 'href' }>
45
+ <UrlControl placeholder={ __( 'Paste URL or type', 'elementor' ) } />
46
+ </PropKeyProvider>
47
+
48
+ <PropKeyProvider bind={ 'isTargetBlank' }>
49
+ <SwitchControl />
50
+ </PropKeyProvider>
51
+ </Stack>
52
+ </Collapse>
53
+ </Stack>
54
+ </PropProvider>
75
55
  );
76
56
  } );
77
57
 
58
+ // @TODO Should be refactored in EDS-1086
59
+ const ToggleIconControl = () => {
60
+ const { value = false, setValue } = useBoundProp();
61
+
62
+ const handleOnChange = () => setValue( ! value );
63
+
64
+ return (
65
+ <IconButton size={ SIZE } onClick={ handleOnChange }>
66
+ { value ? <MinusIcon fontSize={ SIZE } /> : <PlusIcon fontSize={ SIZE } /> }
67
+ </IconButton>
68
+ );
69
+ };
70
+
78
71
  // @TODO Should be refactored in ED-16323
79
- const SwitchControl = ( { value, onSwitch }: { value: boolean; onSwitch: () => void } ) => {
72
+ const SwitchControl = () => {
73
+ const { value = false, setValue } = useBoundProp();
74
+
75
+ const onChange = () => {
76
+ setValue( ! value );
77
+ };
78
+
80
79
  return (
81
80
  <Grid container alignItems="center" flexWrap="nowrap" justifyContent="space-between">
82
81
  <Grid item>
83
82
  <ControlLabel>{ __( 'Open in new tab', 'elementor' ) }</ControlLabel>
84
83
  </Grid>
85
84
  <Grid item>
86
- <Switch checked={ value } onChange={ onSwitch } />
85
+ <Switch checked={ value } onChange={ onChange } />
87
86
  </Grid>
88
87
  </Grid>
89
88
  );
@@ -1,31 +1,32 @@
1
1
  import * as React from 'react';
2
- import { linkedDimensionsPropTypeUtil, type PropValue } from '@elementor/editor-props';
2
+ import { linkedDimensionsPropTypeUtil, type LinkedDimensionsPropValue, type PropKey } from '@elementor/editor-props';
3
3
  import { DetachIcon, LinkIcon, SideBottomIcon, SideLeftIcon, SideRightIcon, SideTopIcon } from '@elementor/icons';
4
4
  import { Grid, Stack, ToggleButton } from '@elementor/ui';
5
5
  import { __ } from '@wordpress/i18n';
6
6
 
7
- import { BoundPropProvider, useBoundProp } from '../bound-prop-context';
7
+ import { PropKeyProvider, PropProvider, type SetValue, useBoundProp } from '../bound-prop-context';
8
8
  import { ControlLabel } from '../components/control-label';
9
9
  import { createControl } from '../create-control';
10
10
  import { SizeControl } from './size-control';
11
11
 
12
- export type Position = 'top' | 'right' | 'bottom' | 'left';
13
-
14
12
  export const LinkedDimensionsControl = createControl( ( { label }: { label: string } ) => {
15
- const { value, setValue } = useBoundProp( linkedDimensionsPropTypeUtil );
13
+ const { value, setValue, propType } = useBoundProp( linkedDimensionsPropTypeUtil );
16
14
  const { top, right, bottom, left, isLinked = true } = value || {};
17
15
 
18
- const setLinkedValue = ( position: Position, newValue: PropValue ) => {
19
- const updatedValue = {
20
- isLinked,
21
- top: isLinked ? newValue : top,
22
- right: isLinked ? newValue : right,
23
- bottom: isLinked ? newValue : bottom,
24
- left: isLinked ? newValue : left,
25
- [ position ]: newValue,
26
- };
16
+ const setLinkedValue: SetValue< LinkedDimensionsPropValue[ 'value' ] > = ( newValue, _, meta ) => {
17
+ if ( ! isLinked ) {
18
+ return setValue( newValue );
19
+ }
27
20
 
28
- setValue( updatedValue );
21
+ const newDimension = newValue[ meta?.bind as keyof LinkedDimensionsPropValue[ 'value' ] ];
22
+
23
+ setValue( {
24
+ isLinked,
25
+ top: newDimension,
26
+ right: newDimension,
27
+ bottom: newDimension,
28
+ left: newDimension,
29
+ } );
29
30
  };
30
31
 
31
32
  const toggleLinked = () => {
@@ -43,7 +44,7 @@ export const LinkedDimensionsControl = createControl( ( { label }: { label: stri
43
44
  const LinkedIcon = isLinked ? LinkIcon : DetachIcon;
44
45
 
45
46
  return (
46
- <>
47
+ <PropProvider propType={ propType } value={ value } setValue={ setLinkedValue }>
47
48
  <Stack direction="row" gap={ 2 } flexWrap="nowrap">
48
49
  <ControlLabel>{ label }</ControlLabel>
49
50
  <ToggleButton
@@ -63,12 +64,7 @@ export const LinkedDimensionsControl = createControl( ( { label }: { label: stri
63
64
  <ControlLabel>{ __( 'Top', 'elementor' ) }</ControlLabel>
64
65
  </Grid>
65
66
  <Grid item xs={ 12 }>
66
- <Control
67
- bind={ 'top' }
68
- value={ top }
69
- setValue={ setLinkedValue }
70
- startIcon={ <SideTopIcon fontSize={ 'tiny' } /> }
71
- />
67
+ <Control bind={ 'top' } startIcon={ <SideTopIcon fontSize={ 'tiny' } /> } />
72
68
  </Grid>
73
69
  </Grid>
74
70
  <Grid container gap={ 1 } alignItems="center">
@@ -76,12 +72,7 @@ export const LinkedDimensionsControl = createControl( ( { label }: { label: stri
76
72
  <ControlLabel>{ __( 'Right', 'elementor' ) }</ControlLabel>
77
73
  </Grid>
78
74
  <Grid item xs={ 12 }>
79
- <Control
80
- bind={ 'right' }
81
- value={ right }
82
- setValue={ setLinkedValue }
83
- startIcon={ <SideRightIcon fontSize={ 'tiny' } /> }
84
- />
75
+ <Control bind={ 'right' } startIcon={ <SideRightIcon fontSize={ 'tiny' } /> } />
85
76
  </Grid>
86
77
  </Grid>
87
78
  </Stack>
@@ -91,12 +82,7 @@ export const LinkedDimensionsControl = createControl( ( { label }: { label: stri
91
82
  <ControlLabel>{ __( 'Bottom', 'elementor' ) }</ControlLabel>
92
83
  </Grid>
93
84
  <Grid item xs={ 12 }>
94
- <Control
95
- bind={ 'bottom' }
96
- value={ bottom }
97
- setValue={ setLinkedValue }
98
- startIcon={ <SideBottomIcon fontSize={ 'tiny' } /> }
99
- />
85
+ <Control bind={ 'bottom' } startIcon={ <SideBottomIcon fontSize={ 'tiny' } /> } />
100
86
  </Grid>
101
87
  </Grid>
102
88
  <Grid container gap={ 1 } alignItems="center">
@@ -104,31 +90,16 @@ export const LinkedDimensionsControl = createControl( ( { label }: { label: stri
104
90
  <ControlLabel>{ __( 'Left', 'elementor' ) }</ControlLabel>
105
91
  </Grid>
106
92
  <Grid item xs={ 12 }>
107
- <Control
108
- bind={ 'left' }
109
- value={ left }
110
- setValue={ setLinkedValue }
111
- startIcon={ <SideLeftIcon fontSize={ 'tiny' } /> }
112
- />
93
+ <Control bind={ 'left' } startIcon={ <SideLeftIcon fontSize={ 'tiny' } /> } />
113
94
  </Grid>
114
95
  </Grid>
115
96
  </Stack>
116
- </>
97
+ </PropProvider>
117
98
  );
118
99
  } );
119
100
 
120
- const Control = ( {
121
- bind,
122
- startIcon,
123
- value,
124
- setValue,
125
- }: {
126
- bind: Position;
127
- value: PropValue;
128
- startIcon: React.ReactNode;
129
- setValue: ( bind: Position, newValue: PropValue ) => void;
130
- } ) => (
131
- <BoundPropProvider setValue={ ( newValue ) => setValue( bind, newValue ) } value={ value } bind={ bind }>
101
+ const Control = ( { bind, startIcon }: { bind: PropKey; startIcon: React.ReactNode } ) => (
102
+ <PropKeyProvider bind={ bind }>
132
103
  <SizeControl startIcon={ startIcon } />
133
- </BoundPropProvider>
104
+ </PropKeyProvider>
134
105
  );
@@ -6,7 +6,7 @@ import { useBoundProp } from '../bound-prop-context';
6
6
  import ControlActions from '../control-actions/control-actions';
7
7
  import { createControl } from '../create-control';
8
8
 
9
- const isEmptyOrNaN = ( value?: string | number ) =>
9
+ const isEmptyOrNaN = ( value?: string | number | null ) =>
10
10
  value === null || value === undefined || value === '' || Number.isNaN( Number( value ) );
11
11
 
12
12
  export const NumberControl = createControl(
@@ -1,71 +1,41 @@
1
1
  import * as React from 'react';
2
- import { type ColorPropValue, type PropValue, type SizePropValue, strokePropTypeUtil } from '@elementor/editor-props';
2
+ import { strokePropTypeUtil } from '@elementor/editor-props';
3
3
  import { Grid, Stack } from '@elementor/ui';
4
4
  import { __ } from '@wordpress/i18n';
5
5
 
6
- import { BoundPropProvider, useBoundProp } from '../bound-prop-context';
6
+ import { PropKeyProvider, PropProvider, useBoundProp } from '../bound-prop-context';
7
7
  import { ControlLabel } from '../components/control-label';
8
8
  import { createControl } from '../create-control';
9
9
  import { ColorControl } from './color-control';
10
10
  import { SizeControl, type Unit } from './size-control';
11
11
 
12
- type SetContextValue = ( v: PropValue ) => void;
13
-
14
- export type StrokeProps< T > = {
12
+ export type StrokeProps = {
15
13
  bind: string;
16
- value: T;
17
- setValue: ( v: T ) => void;
18
14
  label: string;
19
15
  children: React.ReactNode;
20
16
  };
17
+
21
18
  const units: Unit[] = [ 'px', 'em', 'rem' ];
22
19
 
23
20
  export const StrokeControl = createControl( () => {
24
- const { value, setValue } = useBoundProp( strokePropTypeUtil );
25
-
26
- const setStrokeWidth = ( newValue: SizePropValue ) => {
27
- const updatedValue = {
28
- ...value,
29
- width: newValue,
30
- };
31
-
32
- setValue( updatedValue );
33
- };
34
-
35
- const setStrokeColor = ( newValue: ColorPropValue ) => {
36
- const updatedValue = {
37
- ...value,
38
- color: newValue,
39
- };
40
-
41
- setValue( updatedValue );
42
- };
21
+ const propContext = useBoundProp( strokePropTypeUtil );
43
22
 
44
23
  return (
45
- <Stack gap={ 1.5 }>
46
- <Control
47
- bind="width"
48
- label={ __( 'Stroke Width', 'elementor' ) }
49
- value={ value?.width }
50
- setValue={ setStrokeWidth }
51
- >
52
- <SizeControl units={ units } />
53
- </Control>
54
-
55
- <Control
56
- bind="color"
57
- label={ __( 'Stroke Color', 'elementor' ) }
58
- value={ value?.color }
59
- setValue={ setStrokeColor }
60
- >
61
- <ColorControl />
62
- </Control>
63
- </Stack>
24
+ <PropProvider { ...propContext }>
25
+ <Stack gap={ 1.5 }>
26
+ <Control bind="width" label={ __( 'Stroke Width', 'elementor' ) }>
27
+ <SizeControl units={ units } />
28
+ </Control>
29
+ <Control bind="color" label={ __( 'Stroke Color', 'elementor' ) }>
30
+ <ColorControl />
31
+ </Control>
32
+ </Stack>
33
+ </PropProvider>
64
34
  );
65
35
  } );
66
36
 
67
- const Control = < T extends PropValue >( { bind, value, setValue, label, children }: StrokeProps< T > ) => (
68
- <BoundPropProvider bind={ bind } value={ value } setValue={ setValue as SetContextValue }>
37
+ const Control = ( { bind, label, children }: StrokeProps ) => (
38
+ <PropKeyProvider bind={ bind }>
69
39
  <Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
70
40
  <Grid item xs={ 6 }>
71
41
  <ControlLabel>{ label }</ControlLabel>
@@ -74,5 +44,5 @@ const Control = < T extends PropValue >( { bind, value, setValue, label, childre
74
44
  { children }
75
45
  </Grid>
76
46
  </Grid>
77
- </BoundPropProvider>
47
+ </PropKeyProvider>
78
48
  );
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { type UrlPropValue } from '@elementor/editor-props';
2
+ import { urlPropTypeUtil } from '@elementor/editor-props';
3
3
  import { TextField } from '@elementor/ui';
4
4
 
5
5
  import { useBoundProp } from '../bound-prop-context';
@@ -7,23 +7,13 @@ import ControlActions from '../control-actions/control-actions';
7
7
  import { createControl } from '../create-control';
8
8
 
9
9
  export const UrlControl = createControl( ( { placeholder }: { placeholder?: string } ) => {
10
- const { value, setValue } = useBoundProp< UrlPropValue >();
10
+ const { value, setValue } = useBoundProp( urlPropTypeUtil );
11
11
 
12
- const handleChange = ( event: React.ChangeEvent< HTMLInputElement > ) =>
13
- setValue( {
14
- $$type: 'url',
15
- value: event.target.value,
16
- } );
12
+ const handleChange = ( event: React.ChangeEvent< HTMLInputElement > ) => setValue( event.target.value );
17
13
 
18
14
  return (
19
15
  <ControlActions>
20
- <TextField
21
- size="tiny"
22
- fullWidth
23
- value={ value?.value }
24
- onChange={ handleChange }
25
- placeholder={ placeholder }
26
- />
16
+ <TextField size="tiny" fullWidth value={ value } onChange={ handleChange } placeholder={ placeholder } />
27
17
  </ControlActions>
28
18
  );
29
19
  } );
package/src/index.ts CHANGED
@@ -26,12 +26,13 @@ export type { ControlComponent } from './create-control';
26
26
  export type { ToggleButtonGroupItem } from './components/control-toggle-button-group';
27
27
  export type { EqualUnequalItems } from './controls/equal-unequal-sizes-control';
28
28
  export type { ControlActionsItems } from './control-actions/control-actions-context';
29
- export type { BoundPropProviderProps } from './bound-prop-context';
29
+ export type { PropProviderProps } from './bound-prop-context';
30
+ export type { SetValue } from './bound-prop-context/prop-context';
30
31
 
31
32
  // providers
32
33
  export { createControlReplacement, ControlReplacementProvider } from './create-control-replacement';
33
- export { useBoundProp, BoundPropProvider } from './bound-prop-context';
34
34
  export { ControlActionsProvider, useControlActions } from './control-actions/control-actions-context';
35
+ export { useBoundProp, PropProvider, PropKeyProvider } from './bound-prop-context';
35
36
 
36
37
  // hooks
37
38
  export { useSyncExternalState } from './hooks/use-sync-external-state';
@@ -1,67 +0,0 @@
1
- import * as React from 'react';
2
- import { createContext, useContext } from 'react';
3
- import { type CreateOptions, type PropKey, type PropTypeUtil, type PropValue } from '@elementor/editor-props';
4
-
5
- // Context
6
- export type BoundPropContext< T extends PropValue > = {
7
- bind: PropKey;
8
- setValue: ( value: T | null ) => void;
9
- value: T;
10
- };
11
-
12
- const BoundPropContext = createContext< BoundPropContext< PropValue > | null >( null );
13
-
14
- // Provider
15
- export type BoundPropProviderProps< T extends PropValue > = BoundPropContext< T > & {
16
- children: React.ReactNode;
17
- setValue: ( value: T | null ) => void;
18
- };
19
-
20
- export const BoundPropProvider = ( { children, value, setValue, bind }: BoundPropProviderProps< PropValue > ) => {
21
- return <BoundPropContext.Provider value={ { value, setValue, bind } }>{ children }</BoundPropContext.Provider>;
22
- };
23
-
24
- // Hook
25
- type SetValue< T > = ( value: T | null, options?: CreateOptions ) => void;
26
-
27
- type UseBoundProp< TValue > = {
28
- bind: PropKey;
29
- setValue: SetValue< TValue >;
30
- value: TValue;
31
- };
32
-
33
- export function useBoundProp< TValue extends PropValue >(): BoundPropContext< TValue >;
34
-
35
- export function useBoundProp< TKey extends string, TValue extends PropValue >(
36
- propTypeUtil: PropTypeUtil< TKey, TValue >
37
- ): UseBoundProp< TValue >;
38
-
39
- export function useBoundProp< TKey extends string, TValue extends PropValue >(
40
- propTypeUtil?: PropTypeUtil< TKey, TValue >
41
- ) {
42
- const boundPropContext = useContext< BoundPropContext< TValue > >( BoundPropContext as never );
43
-
44
- if ( ! boundPropContext ) {
45
- throw new Error( 'useBoundProp must be used within a BoundPropProvider' );
46
- }
47
-
48
- if ( ! propTypeUtil ) {
49
- return boundPropContext;
50
- }
51
-
52
- function setValue( value: TValue | null, options?: CreateOptions ) {
53
- if ( value === null ) {
54
- return boundPropContext.setValue( null );
55
- }
56
-
57
- return boundPropContext.setValue( propTypeUtil?.create( value, options ) as TValue );
58
- }
59
-
60
- const value = propTypeUtil.extract( boundPropContext.value );
61
-
62
- return {
63
- ...boundPropContext,
64
- setValue,
65
- value,
66
- };
67
- }