@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.
- package/CHANGELOG.md +20 -0
- package/dist/index.d.mts +35 -18
- package/dist/index.d.ts +35 -18
- package/dist/index.js +363 -575
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +347 -565
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
- package/src/bound-prop-context/errors.ts +16 -0
- package/src/bound-prop-context/index.ts +3 -0
- package/src/bound-prop-context/prop-context.tsx +48 -0
- package/src/bound-prop-context/prop-key-context.tsx +103 -0
- package/src/bound-prop-context/use-bound-prop.ts +69 -0
- package/src/components/repeater.tsx +3 -13
- package/src/controls/background-control/background-control.tsx +19 -42
- package/src/controls/background-control/background-overlay/background-overlay-repeater-control.tsx +32 -48
- package/src/controls/box-shadow-repeater-control.tsx +75 -139
- package/src/controls/color-control.tsx +16 -20
- package/src/controls/equal-unequal-sizes-control.tsx +65 -139
- package/src/controls/gap-control.tsx +20 -25
- package/src/controls/image-control.tsx +19 -34
- package/src/controls/image-media-control.tsx +1 -1
- package/src/controls/link-control.tsx +57 -58
- package/src/controls/linked-dimensions-control.tsx +25 -54
- package/src/controls/number-control.tsx +1 -1
- package/src/controls/stroke-control.tsx +18 -48
- package/src/controls/url-control.tsx +4 -14
- package/src/index.ts +3 -2
- package/src/bound-prop-context.tsx +0 -67
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { createContext, useContext } from 'react';
|
|
3
|
+
import { type CreateOptions, type PropKey, type PropType, type PropValue } from '@elementor/editor-props';
|
|
4
|
+
|
|
5
|
+
import { HookOutsideProviderError } from './errors';
|
|
6
|
+
|
|
7
|
+
type SetValueMeta = {
|
|
8
|
+
bind?: PropKey;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type SetValue< T > = ( value: T, options?: CreateOptions, meta?: SetValueMeta ) => void;
|
|
12
|
+
|
|
13
|
+
type PropContext< T extends PropValue, P extends PropType > = {
|
|
14
|
+
setValue: SetValue< T >;
|
|
15
|
+
value: T | null;
|
|
16
|
+
propType: P;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const PropContext = createContext< PropContext< PropValue, PropType > | null >( null );
|
|
20
|
+
|
|
21
|
+
export type PropProviderProps< T extends PropValue, P extends PropType > = React.PropsWithChildren<
|
|
22
|
+
PropContext< T, P >
|
|
23
|
+
>;
|
|
24
|
+
|
|
25
|
+
export const PropProvider = < T extends PropValue, P extends PropType >( {
|
|
26
|
+
children,
|
|
27
|
+
value,
|
|
28
|
+
setValue,
|
|
29
|
+
propType,
|
|
30
|
+
}: PropProviderProps< T, P > ) => {
|
|
31
|
+
// @ts-expect-error - figure out how to fix this
|
|
32
|
+
return <PropContext.Provider value={ { value, setValue, propType } }>{ children }</PropContext.Provider>;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const usePropContext = < T extends PropValue, P extends PropType >() => {
|
|
36
|
+
const context = useContext( PropContext ) as PropContext< T, P > | null;
|
|
37
|
+
|
|
38
|
+
if ( ! context ) {
|
|
39
|
+
throw new HookOutsideProviderError( {
|
|
40
|
+
context: {
|
|
41
|
+
hook: 'usePropContext',
|
|
42
|
+
provider: 'PropProvider',
|
|
43
|
+
},
|
|
44
|
+
} );
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return context;
|
|
48
|
+
};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { createContext, useContext } from 'react';
|
|
3
|
+
import {
|
|
4
|
+
type ArrayPropType,
|
|
5
|
+
type ArrayPropValue,
|
|
6
|
+
type CreateOptions,
|
|
7
|
+
type ObjectPropType,
|
|
8
|
+
type ObjectPropValue,
|
|
9
|
+
type PropKey,
|
|
10
|
+
type PropType,
|
|
11
|
+
type PropValue,
|
|
12
|
+
} from '@elementor/editor-props';
|
|
13
|
+
|
|
14
|
+
import { HookOutsideProviderError, MissingPropTypeError, UnsupportedParentError } from './errors';
|
|
15
|
+
import { type SetValue, usePropContext } from './prop-context';
|
|
16
|
+
|
|
17
|
+
export type PropKeyContextValue< T, P > = {
|
|
18
|
+
bind: PropKey;
|
|
19
|
+
setValue: SetValue< T >;
|
|
20
|
+
value: T;
|
|
21
|
+
propType: P;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const PropKeyContext = createContext< PropKeyContextValue< PropValue, PropType > | null >( null );
|
|
25
|
+
|
|
26
|
+
type PropKeyProviderProps = React.PropsWithChildren< {
|
|
27
|
+
bind: PropKey;
|
|
28
|
+
} >;
|
|
29
|
+
|
|
30
|
+
export const PropKeyProvider = ( { children, bind }: PropKeyProviderProps ) => {
|
|
31
|
+
const { propType } = usePropContext();
|
|
32
|
+
|
|
33
|
+
if ( ! propType ) {
|
|
34
|
+
throw new MissingPropTypeError( { context: { bind } } );
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if ( propType.kind === 'array' ) {
|
|
38
|
+
return <ArrayPropKeyProvider bind={ bind }>{ children }</ArrayPropKeyProvider>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if ( propType.kind === 'object' ) {
|
|
42
|
+
return <ObjectPropKeyProvider bind={ bind }>{ children }</ObjectPropKeyProvider>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
throw new UnsupportedParentError( { context: { propType } } );
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const ObjectPropKeyProvider = ( { children, bind }: PropKeyProviderProps ) => {
|
|
49
|
+
const context = usePropContext< ObjectPropValue[ 'value' ], ObjectPropType >();
|
|
50
|
+
|
|
51
|
+
const setValue: SetValue< PropValue > = ( value, options, meta ) => {
|
|
52
|
+
const newValue = {
|
|
53
|
+
...context.value,
|
|
54
|
+
[ bind ]: value,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
return context?.setValue( newValue, options, { ...meta, bind } );
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const value = context.value?.[ bind ];
|
|
61
|
+
|
|
62
|
+
const propType = context.propType.shape[ bind ];
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<PropKeyContext.Provider value={ { ...context, value, setValue, bind, propType } }>
|
|
66
|
+
{ children }
|
|
67
|
+
</PropKeyContext.Provider>
|
|
68
|
+
);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const ArrayPropKeyProvider = ( { children, bind }: PropKeyProviderProps ) => {
|
|
72
|
+
const context = usePropContext< ArrayPropValue[ 'value' ], ArrayPropType >();
|
|
73
|
+
|
|
74
|
+
const setValue = ( value: PropValue, options?: CreateOptions ) => {
|
|
75
|
+
const newValue = [ ...( context.value ?? [] ) ];
|
|
76
|
+
|
|
77
|
+
newValue[ Number( bind ) ] = value;
|
|
78
|
+
|
|
79
|
+
return context?.setValue( newValue, options, { bind } );
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const value = context.value?.[ Number( bind ) ];
|
|
83
|
+
|
|
84
|
+
const propType = context.propType.item_prop_type;
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<PropKeyContext.Provider value={ { ...context, value, setValue, bind, propType } }>
|
|
88
|
+
{ children }
|
|
89
|
+
</PropKeyContext.Provider>
|
|
90
|
+
);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const usePropKeyContext = () => {
|
|
94
|
+
const context = useContext( PropKeyContext );
|
|
95
|
+
|
|
96
|
+
if ( ! context ) {
|
|
97
|
+
throw new HookOutsideProviderError( {
|
|
98
|
+
context: { hook: 'usePropKeyContext', provider: 'PropKeyProvider' },
|
|
99
|
+
} );
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return context;
|
|
103
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type CreateOptions,
|
|
3
|
+
type PropKey,
|
|
4
|
+
type PropType,
|
|
5
|
+
type PropTypeUtil,
|
|
6
|
+
type PropValue,
|
|
7
|
+
} from '@elementor/editor-props';
|
|
8
|
+
|
|
9
|
+
import { MissingPropTypeError } from './errors';
|
|
10
|
+
import { type SetValue } from './prop-context';
|
|
11
|
+
import { type PropKeyContextValue, usePropKeyContext } from './prop-key-context';
|
|
12
|
+
|
|
13
|
+
type UseBoundProp< TValue extends PropValue > = {
|
|
14
|
+
bind: PropKey;
|
|
15
|
+
setValue: SetValue< TValue | null >;
|
|
16
|
+
value: TValue;
|
|
17
|
+
propType: PropType;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export function useBoundProp< T extends PropValue = PropValue >(): PropKeyContextValue< T, PropType >;
|
|
21
|
+
|
|
22
|
+
export function useBoundProp< TKey extends string, TValue extends PropValue >(
|
|
23
|
+
propTypeUtil: PropTypeUtil< TKey, TValue >
|
|
24
|
+
): UseBoundProp< TValue >;
|
|
25
|
+
|
|
26
|
+
export function useBoundProp< TKey extends string, TValue extends PropValue >(
|
|
27
|
+
propTypeUtil?: PropTypeUtil< TKey, TValue >
|
|
28
|
+
) {
|
|
29
|
+
const propKeyContext = usePropKeyContext();
|
|
30
|
+
|
|
31
|
+
// allow using the hook without a propTypeUtil, with no modifications or validations.
|
|
32
|
+
if ( ! propTypeUtil ) {
|
|
33
|
+
return propKeyContext;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function setValue( value: TValue | null, options: CreateOptions, meta: { bind?: PropKey } ) {
|
|
37
|
+
if ( value === null ) {
|
|
38
|
+
return propKeyContext?.setValue( null, options, meta );
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return propKeyContext?.setValue( propTypeUtil?.create( value, options ), {}, meta );
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const propType = resolveUnionPropType( propKeyContext.propType, propTypeUtil.key );
|
|
45
|
+
|
|
46
|
+
const value = propTypeUtil.extract( propKeyContext.value ?? propType.default ?? null );
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
...propKeyContext,
|
|
50
|
+
setValue,
|
|
51
|
+
value,
|
|
52
|
+
propType,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// utils
|
|
57
|
+
const resolveUnionPropType = ( propType: PropType, key: string ): PropType => {
|
|
58
|
+
let resolvedPropType = propType;
|
|
59
|
+
|
|
60
|
+
if ( propType.kind === 'union' ) {
|
|
61
|
+
resolvedPropType = propType.prop_types[ key ];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if ( ! resolvedPropType ) {
|
|
65
|
+
throw new MissingPropTypeError( { context: { key } } );
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return resolvedPropType;
|
|
69
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { useId, useRef, useState } from 'react';
|
|
3
|
+
import { type PropKey } from '@elementor/editor-props';
|
|
3
4
|
import { CopyIcon, EyeIcon, EyeOffIcon, PlusIcon, XIcon } from '@elementor/icons';
|
|
4
5
|
import {
|
|
5
6
|
bindPopover,
|
|
@@ -32,9 +33,8 @@ export type RepeaterProps< T > = {
|
|
|
32
33
|
Label: React.ComponentType< { value: T } >;
|
|
33
34
|
Icon: React.ComponentType< { value: T } >;
|
|
34
35
|
Content: React.ComponentType< {
|
|
35
|
-
value: T;
|
|
36
|
-
setValue: ( newValue: T ) => void;
|
|
37
36
|
anchorEl: AnchorEl;
|
|
37
|
+
bind: PropKey;
|
|
38
38
|
} >;
|
|
39
39
|
};
|
|
40
40
|
};
|
|
@@ -99,17 +99,7 @@ export const Repeater = < T, >( {
|
|
|
99
99
|
duplicateItem={ () => duplicateRepeaterItem( index ) }
|
|
100
100
|
toggleDisableItem={ () => toggleDisableRepeaterItem( index ) }
|
|
101
101
|
>
|
|
102
|
-
{ ( props ) => (
|
|
103
|
-
<itemSettings.Content
|
|
104
|
-
{ ...props }
|
|
105
|
-
value={ value }
|
|
106
|
-
setValue={ ( newValue ) =>
|
|
107
|
-
setRepeaterValues(
|
|
108
|
-
repeaterValues.map( ( item, i ) => ( i === index ? newValue : item ) )
|
|
109
|
-
)
|
|
110
|
-
}
|
|
111
|
-
/>
|
|
112
|
-
) }
|
|
102
|
+
{ ( props ) => <itemSettings.Content { ...props } bind={ String( index ) } /> }
|
|
113
103
|
</RepeaterItem>
|
|
114
104
|
) ) }
|
|
115
105
|
</Stack>
|
|
@@ -1,57 +1,34 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
type BackgroundColorOverlayPropValue,
|
|
4
|
-
backgroundPropTypeUtil,
|
|
5
|
-
type ColorPropValue,
|
|
6
|
-
type PropValue,
|
|
7
|
-
} from '@elementor/editor-props';
|
|
2
|
+
import { backgroundPropTypeUtil } from '@elementor/editor-props';
|
|
8
3
|
import { Grid, Stack } from '@elementor/ui';
|
|
9
4
|
import { __ } from '@wordpress/i18n';
|
|
10
5
|
|
|
11
|
-
import {
|
|
6
|
+
import { PropKeyProvider, PropProvider, useBoundProp } from '../../bound-prop-context';
|
|
12
7
|
import { ControlLabel } from '../../components/control-label';
|
|
13
8
|
import { createControl } from '../../create-control';
|
|
14
9
|
import { ColorControl } from '../color-control';
|
|
15
10
|
import { BackgroundOverlayRepeaterControl } from './background-overlay/background-overlay-repeater-control';
|
|
16
11
|
|
|
17
|
-
type SetContextValue = ( v: PropValue ) => void;
|
|
18
|
-
|
|
19
12
|
export const BackgroundControl = createControl( () => {
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
const setColor = ( newValue: ColorPropValue ) => {
|
|
23
|
-
setValue( {
|
|
24
|
-
...value,
|
|
25
|
-
color: newValue,
|
|
26
|
-
} );
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const setBackgroundColorOverlay = ( newValue: BackgroundColorOverlayPropValue ) => {
|
|
30
|
-
setValue( {
|
|
31
|
-
...value,
|
|
32
|
-
'background-overlay': newValue,
|
|
33
|
-
} );
|
|
34
|
-
};
|
|
13
|
+
const propContext = useBoundProp( backgroundPropTypeUtil );
|
|
35
14
|
|
|
36
15
|
return (
|
|
37
|
-
<
|
|
38
|
-
<
|
|
39
|
-
bind="background-overlay"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
<Grid item xs={ 6 }>
|
|
51
|
-
<ColorControl />
|
|
16
|
+
<PropProvider { ...propContext }>
|
|
17
|
+
<Stack gap={ 1.5 }>
|
|
18
|
+
<PropKeyProvider bind="background-overlay">
|
|
19
|
+
<BackgroundOverlayRepeaterControl />
|
|
20
|
+
</PropKeyProvider>
|
|
21
|
+
<PropKeyProvider bind="color">
|
|
22
|
+
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
23
|
+
<Grid item xs={ 6 }>
|
|
24
|
+
<ControlLabel>{ __( 'Color', 'elementor' ) }</ControlLabel>
|
|
25
|
+
</Grid>
|
|
26
|
+
<Grid item xs={ 6 }>
|
|
27
|
+
<ColorControl />
|
|
28
|
+
</Grid>
|
|
52
29
|
</Grid>
|
|
53
|
-
</
|
|
54
|
-
</
|
|
55
|
-
</
|
|
30
|
+
</PropKeyProvider>
|
|
31
|
+
</Stack>
|
|
32
|
+
</PropProvider>
|
|
56
33
|
);
|
|
57
34
|
} );
|
package/src/controls/background-control/background-overlay/background-overlay-repeater-control.tsx
CHANGED
|
@@ -1,46 +1,41 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
backgroundColorOverlayPropTypeUtil,
|
|
4
4
|
type BackgroundOverlayItemPropValue,
|
|
5
5
|
backgroundOverlayPropTypeUtil,
|
|
6
|
-
type
|
|
7
|
-
type PropValue,
|
|
6
|
+
type PropKey,
|
|
8
7
|
} from '@elementor/editor-props';
|
|
9
8
|
import { Grid, Stack, UnstableColorIndicator } from '@elementor/ui';
|
|
10
9
|
import { __ } from '@wordpress/i18n';
|
|
11
10
|
|
|
12
|
-
import {
|
|
11
|
+
import { PropKeyProvider, PropProvider, useBoundProp } from '../../../bound-prop-context';
|
|
13
12
|
import { ControlLabel } from '../../../components/control-label';
|
|
14
13
|
import { Repeater } from '../../../components/repeater';
|
|
15
14
|
import { createControl } from '../../../create-control';
|
|
16
15
|
import { ColorControl } from '../../color-control';
|
|
17
16
|
|
|
18
|
-
type SetContextValue = ( v: PropValue ) => void;
|
|
19
|
-
|
|
20
17
|
const initialBackgroundOverlay: BackgroundOverlayItemPropValue = {
|
|
21
18
|
$$type: 'background-color-overlay',
|
|
22
19
|
value: 'rgba(0, 0, 0, 0.2)',
|
|
23
20
|
};
|
|
24
21
|
|
|
25
22
|
export const BackgroundOverlayRepeaterControl = createControl( () => {
|
|
26
|
-
const { value: overlayValues, setValue } = useBoundProp( backgroundOverlayPropTypeUtil );
|
|
27
|
-
|
|
28
|
-
const setColorOverlay = ( newValue: BackgroundOverlayPropValue[ 'value' ] ) => {
|
|
29
|
-
setValue( newValue );
|
|
30
|
-
};
|
|
23
|
+
const { propType, value: overlayValues, setValue } = useBoundProp( backgroundOverlayPropTypeUtil );
|
|
31
24
|
|
|
32
25
|
return (
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
26
|
+
<PropProvider propType={ propType } value={ overlayValues } setValue={ setValue }>
|
|
27
|
+
<Repeater
|
|
28
|
+
values={ overlayValues ?? [] }
|
|
29
|
+
setValues={ setValue }
|
|
30
|
+
label={ __( 'Overlay', 'elementor' ) }
|
|
31
|
+
itemSettings={ {
|
|
32
|
+
Icon: ItemIcon,
|
|
33
|
+
Label: ItemLabel,
|
|
34
|
+
Content: ItemContent,
|
|
35
|
+
initialValues: initialBackgroundOverlay,
|
|
36
|
+
} }
|
|
37
|
+
/>
|
|
38
|
+
</PropProvider>
|
|
44
39
|
);
|
|
45
40
|
} );
|
|
46
41
|
|
|
@@ -48,36 +43,25 @@ const ItemIcon = ( { value }: { value: BackgroundOverlayItemPropValue } ) => (
|
|
|
48
43
|
<UnstableColorIndicator size="inherit" component="span" value={ value.value } />
|
|
49
44
|
);
|
|
50
45
|
|
|
51
|
-
const ItemContent = ( {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
const setBackgroundColorOverlay = ( newValue: BackgroundColorOverlayPropValue ) => {
|
|
59
|
-
setValue( {
|
|
60
|
-
$$type: 'background-color-overlay',
|
|
61
|
-
value: newValue.value,
|
|
62
|
-
} );
|
|
63
|
-
};
|
|
46
|
+
const ItemContent = ( { bind }: { bind: PropKey } ) => {
|
|
47
|
+
return (
|
|
48
|
+
<PropKeyProvider bind={ bind }>
|
|
49
|
+
<Content />
|
|
50
|
+
</PropKeyProvider>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
64
53
|
|
|
54
|
+
const Content = () => {
|
|
65
55
|
return (
|
|
66
56
|
<Stack gap={ 1.5 }>
|
|
67
|
-
<
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
<Grid item xs={ 12 }>
|
|
74
|
-
<ControlLabel>{ __( 'Color', 'elementor' ) }</ControlLabel>
|
|
75
|
-
</Grid>
|
|
76
|
-
<Grid item xs={ 12 }>
|
|
77
|
-
<ColorControl />
|
|
78
|
-
</Grid>
|
|
57
|
+
<Grid container spacing={ 1 } alignItems="center">
|
|
58
|
+
<Grid item xs={ 12 }>
|
|
59
|
+
<ControlLabel>{ __( 'Color', 'elementor' ) }</ControlLabel>
|
|
60
|
+
</Grid>
|
|
61
|
+
<Grid item xs={ 12 }>
|
|
62
|
+
<ColorControl propTypeUtil={ backgroundColorOverlayPropTypeUtil } />
|
|
79
63
|
</Grid>
|
|
80
|
-
</
|
|
64
|
+
</Grid>
|
|
81
65
|
</Stack>
|
|
82
66
|
);
|
|
83
67
|
};
|