@elementor/editor-editing-panel 1.48.0 → 1.50.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 +48 -0
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +56 -31
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +71 -45
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -11
- package/src/components/css-classes/css-class-item.tsx +3 -2
- package/src/components/css-classes/css-class-menu.tsx +2 -2
- package/src/components/css-classes/css-class-selector.tsx +10 -2
- package/src/components/popover-body.tsx +12 -0
- package/src/components/style-sections/effects-section/effects-section.tsx +6 -1
- package/src/components/style-sections/layout-section/flex-order-field.tsx +6 -1
- package/src/dynamics/components/dynamic-selection-control.tsx +22 -14
- package/src/dynamics/components/dynamic-selection.tsx +32 -36
- package/src/index.ts +1 -1
- package/src/reset-style-props.tsx +1 -1
- package/src/styles-inheritance/components/styles-inheritance-infotip.tsx +1 -1
- package/src/utils/get-styles-provider-color.ts +8 -0
- package/src/components/popover-scrollable-content.tsx +0 -12
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-editing-panel",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.50.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "Elementor Team",
|
|
6
6
|
"homepage": "https://elementor.com/",
|
|
@@ -39,17 +39,17 @@
|
|
|
39
39
|
"dev": "tsup --config=../../tsup.dev.ts"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@elementor/editor": "0.21.
|
|
43
|
-
"@elementor/editor-canvas": "0.
|
|
44
|
-
"@elementor/editor-controls": "1.
|
|
45
|
-
"@elementor/editor-documents": "0.13.
|
|
46
|
-
"@elementor/editor-elements": "0.9.
|
|
47
|
-
"@elementor/editor-panels": "0.17.
|
|
48
|
-
"@elementor/editor-props": "0.
|
|
42
|
+
"@elementor/editor": "0.21.1",
|
|
43
|
+
"@elementor/editor-canvas": "0.28.0",
|
|
44
|
+
"@elementor/editor-controls": "1.5.0",
|
|
45
|
+
"@elementor/editor-documents": "0.13.10",
|
|
46
|
+
"@elementor/editor-elements": "0.9.2",
|
|
47
|
+
"@elementor/editor-panels": "0.17.1",
|
|
48
|
+
"@elementor/editor-props": "0.18.0",
|
|
49
49
|
"@elementor/editor-responsive": "0.13.6",
|
|
50
|
-
"@elementor/editor-styles": "0.6.
|
|
51
|
-
"@elementor/editor-styles-repository": "0.10.
|
|
52
|
-
"@elementor/editor-ui": "0.14.
|
|
50
|
+
"@elementor/editor-styles": "0.6.14",
|
|
51
|
+
"@elementor/editor-styles-repository": "0.10.7",
|
|
52
|
+
"@elementor/editor-ui": "0.14.2",
|
|
53
53
|
"@elementor/editor-v1-adapters": "0.12.1",
|
|
54
54
|
"@elementor/icons": "1.46.0",
|
|
55
55
|
"@elementor/locations": "0.8.0",
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
type ChipOwnProps,
|
|
11
11
|
Stack,
|
|
12
12
|
type Theme,
|
|
13
|
+
ThemeProvider,
|
|
13
14
|
Typography,
|
|
14
15
|
UnstableChipGroup,
|
|
15
16
|
usePopupState,
|
|
@@ -69,7 +70,7 @@ export function CssClassItem( props: CssClassItemProps ) {
|
|
|
69
70
|
const isShowingState = isActive && meta.state;
|
|
70
71
|
|
|
71
72
|
return (
|
|
72
|
-
|
|
73
|
+
<ThemeProvider palette="default">
|
|
73
74
|
<UnstableChipGroup
|
|
74
75
|
ref={ setChipRef }
|
|
75
76
|
{ ...chipGroupProps }
|
|
@@ -144,7 +145,7 @@ export function CssClassItem( props: CssClassItemProps ) {
|
|
|
144
145
|
<CssClassProvider { ...classProps } handleRename={ openEditMode }>
|
|
145
146
|
<CssClassMenu popupState={ popupState } anchorEl={ chipRef } fixed={ fixed } />
|
|
146
147
|
</CssClassProvider>
|
|
147
|
-
|
|
148
|
+
</ThemeProvider>
|
|
148
149
|
);
|
|
149
150
|
}
|
|
150
151
|
|
|
@@ -7,7 +7,7 @@ import { __ } from '@wordpress/i18n';
|
|
|
7
7
|
|
|
8
8
|
import { useStyle } from '../../contexts/style-context';
|
|
9
9
|
import { type StyleDefinitionStateWithNormal } from '../../styles-inheritance/types';
|
|
10
|
-
import {
|
|
10
|
+
import { getTempStylesProviderThemeColor } from '../../utils/get-styles-provider-color';
|
|
11
11
|
import { StyleIndicator } from '../style-indicator';
|
|
12
12
|
import { useCssClass } from './css-class-context';
|
|
13
13
|
import { useUnapplyClass } from './use-apply-and-unapply-class';
|
|
@@ -161,7 +161,7 @@ function StateMenuItem( { state, closeMenu, ...props }: StateMenuItemProps ) {
|
|
|
161
161
|
{ isStyled && (
|
|
162
162
|
<StyleIndicator
|
|
163
163
|
aria-label={ __( 'Has style', 'elementor' ) }
|
|
164
|
-
getColor={
|
|
164
|
+
getColor={ getTempStylesProviderThemeColor( provider ?? '' ) }
|
|
165
165
|
/>
|
|
166
166
|
) }
|
|
167
167
|
{ state ?? 'normal' }
|
|
@@ -53,7 +53,7 @@ const EMPTY_OPTION = {
|
|
|
53
53
|
label: __( 'local', 'elementor' ),
|
|
54
54
|
value: null,
|
|
55
55
|
fixed: true,
|
|
56
|
-
color: 'accent',
|
|
56
|
+
color: getTempStylesProviderColorName( 'accent' ),
|
|
57
57
|
icon: <MapPinIcon />,
|
|
58
58
|
provider: null,
|
|
59
59
|
} satisfies StyleDefOption;
|
|
@@ -221,7 +221,7 @@ function useOptions() {
|
|
|
221
221
|
label: styleDef.label,
|
|
222
222
|
value: styleDef.id,
|
|
223
223
|
fixed: isElements,
|
|
224
|
-
color: getStylesProviderColorName( provider.getKey() ),
|
|
224
|
+
color: getTempStylesProviderColorName( getStylesProviderColorName( provider.getKey() ) ),
|
|
225
225
|
icon: isElements ? <MapPinIcon /> : null,
|
|
226
226
|
provider: provider.getKey(),
|
|
227
227
|
};
|
|
@@ -229,6 +229,14 @@ function useOptions() {
|
|
|
229
229
|
} );
|
|
230
230
|
}
|
|
231
231
|
|
|
232
|
+
function getTempStylesProviderColorName( color: ChipOwnProps[ 'color' ] ): ChipOwnProps[ 'color' ] {
|
|
233
|
+
if ( color === 'accent' ) {
|
|
234
|
+
return 'primary';
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return color;
|
|
238
|
+
}
|
|
239
|
+
|
|
232
240
|
function useCreateAction() {
|
|
233
241
|
const [ provider, createAction ] = useCreateAndApplyClass();
|
|
234
242
|
if ( ! provider || ! createAction ) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { PopoverBody as BasePopoverBody } from '@elementor/editor-ui';
|
|
3
|
+
|
|
4
|
+
import { useSectionWidth } from '../contexts/section-context';
|
|
5
|
+
|
|
6
|
+
type Props = React.ComponentProps< typeof BasePopoverBody >;
|
|
7
|
+
|
|
8
|
+
export const PopoverBody = ( props: Props ) => {
|
|
9
|
+
const sectionWidth = useSectionWidth();
|
|
10
|
+
|
|
11
|
+
return <BasePopoverBody { ...props } width={ sectionWidth } />;
|
|
12
|
+
};
|
|
@@ -10,8 +10,9 @@ import { SectionContent } from '../../section-content';
|
|
|
10
10
|
import { OpacityControlField } from '../layout-section/opacity-control-field';
|
|
11
11
|
|
|
12
12
|
const BOX_SHADOW_LABEL = __( 'Box shadow', 'elementor' );
|
|
13
|
-
const FILTER_LABEL = __( '
|
|
13
|
+
const FILTER_LABEL = __( 'Filters', 'elementor' );
|
|
14
14
|
const TRANSFORM_LABEL = __( 'Transform', 'elementor' );
|
|
15
|
+
const BACKDROP_FILTER_LABEL = __( 'Backdrop filters', 'elementor' );
|
|
15
16
|
|
|
16
17
|
export const EffectsSection = () => {
|
|
17
18
|
const isVersion331Active = isExperimentActive( EXPERIMENTAL_FEATURES.V_3_31 );
|
|
@@ -37,6 +38,10 @@ export const EffectsSection = () => {
|
|
|
37
38
|
<StylesField bind="filter" propDisplayName={ FILTER_LABEL }>
|
|
38
39
|
<FilterRepeaterControl />
|
|
39
40
|
</StylesField>
|
|
41
|
+
<PanelDivider />
|
|
42
|
+
<StylesField bind="backdrop-filter" propDisplayName={ BACKDROP_FILTER_LABEL }>
|
|
43
|
+
<FilterRepeaterControl filterPropName="backdrop-filter" />
|
|
44
|
+
</StylesField>
|
|
40
45
|
</>
|
|
41
46
|
) }
|
|
42
47
|
</SectionContent>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { useState } from 'react';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
3
|
import { ControlToggleButtonGroup, NumberControl, type ToggleButtonGroupItem } from '@elementor/editor-controls';
|
|
4
4
|
import { type NumberPropValue } from '@elementor/editor-props';
|
|
5
5
|
import { ArrowDownSmallIcon, ArrowUpSmallIcon, PencilIcon } from '@elementor/icons';
|
|
@@ -60,6 +60,11 @@ export const FlexOrderField = () => {
|
|
|
60
60
|
|
|
61
61
|
const [ groupControlValue, setGroupControlValue ] = useState( getGroupControlValue( order?.value || null ) );
|
|
62
62
|
|
|
63
|
+
useEffect( () => {
|
|
64
|
+
const newGroupControlValue = getGroupControlValue( order?.value || null );
|
|
65
|
+
setGroupControlValue( newGroupControlValue );
|
|
66
|
+
}, [ order?.value ] );
|
|
67
|
+
|
|
63
68
|
const handleToggleButtonChange = ( group: GroupControlItemOption | null ) => {
|
|
64
69
|
setGroupControlValue( group );
|
|
65
70
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { ControlFormLabel, useBoundProp } from '@elementor/editor-controls';
|
|
3
3
|
import type { Control, ControlsSection } from '@elementor/editor-elements';
|
|
4
|
-
import { PopoverHeader
|
|
4
|
+
import { PopoverHeader } from '@elementor/editor-ui';
|
|
5
5
|
import { DatabaseIcon, SettingsIcon, XIcon } from '@elementor/icons';
|
|
6
6
|
import {
|
|
7
7
|
bindPopover,
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
} from '@elementor/ui';
|
|
22
22
|
import { __ } from '@wordpress/i18n';
|
|
23
23
|
|
|
24
|
+
import { PopoverBody } from '../../components/popover-body';
|
|
24
25
|
import { Control as BaseControl } from '../../controls-registry/control';
|
|
25
26
|
import { type ControlType, getControl } from '../../controls-registry/controls-registry';
|
|
26
27
|
import { usePersistDynamicValue } from '../../hooks/use-persist-dynamic-value';
|
|
@@ -82,9 +83,9 @@ export const DynamicSelectionControl = () => {
|
|
|
82
83
|
} }
|
|
83
84
|
{ ...bindPopover( selectionPopoverState ) }
|
|
84
85
|
>
|
|
85
|
-
<
|
|
86
|
+
<PopoverBody>
|
|
86
87
|
<DynamicSelection close={ selectionPopoverState.close } />
|
|
87
|
-
</
|
|
88
|
+
</PopoverBody>
|
|
88
89
|
</Popover>
|
|
89
90
|
</Box>
|
|
90
91
|
);
|
|
@@ -107,18 +108,21 @@ export const DynamicSettingsPopover = ( { dynamicTag }: { dynamicTag: DynamicTag
|
|
|
107
108
|
<Popover
|
|
108
109
|
disablePortal
|
|
109
110
|
disableScrollLock
|
|
110
|
-
anchorOrigin={ { vertical: 'bottom', horizontal: '
|
|
111
|
+
anchorOrigin={ { vertical: 'bottom', horizontal: 'right' } }
|
|
112
|
+
transformOrigin={ { vertical: 'top', horizontal: 'right' } }
|
|
111
113
|
PaperProps={ {
|
|
112
|
-
sx: { my:
|
|
114
|
+
sx: { my: 1 },
|
|
113
115
|
} }
|
|
114
116
|
{ ...bindPopover( popupState ) }
|
|
115
117
|
>
|
|
116
|
-
<
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
118
|
+
<PopoverBody>
|
|
119
|
+
<PopoverHeader
|
|
120
|
+
title={ dynamicTag.label }
|
|
121
|
+
onClose={ popupState.close }
|
|
122
|
+
icon={ <DatabaseIcon fontSize={ SIZE } /> }
|
|
123
|
+
/>
|
|
124
|
+
<DynamicSettings controls={ dynamicTag.atomic_controls } />
|
|
125
|
+
</PopoverBody>
|
|
122
126
|
</Popover>
|
|
123
127
|
</>
|
|
124
128
|
);
|
|
@@ -134,7 +138,7 @@ const DynamicSettings = ( { controls }: { controls: DynamicTag[ 'atomic_controls
|
|
|
134
138
|
}
|
|
135
139
|
|
|
136
140
|
return (
|
|
137
|
-
|
|
141
|
+
<>
|
|
138
142
|
<Tabs size="small" variant="fullWidth" { ...getTabsProps() }>
|
|
139
143
|
{ tabs.map( ( { value }, index ) => (
|
|
140
144
|
<Tab key={ index } label={ value.label } sx={ { px: 1, py: 0.5 } } { ...getTabProps( index ) } />
|
|
@@ -144,7 +148,11 @@ const DynamicSettings = ( { controls }: { controls: DynamicTag[ 'atomic_controls
|
|
|
144
148
|
|
|
145
149
|
{ tabs.map( ( { value }, index ) => {
|
|
146
150
|
return (
|
|
147
|
-
<TabPanel
|
|
151
|
+
<TabPanel
|
|
152
|
+
key={ index }
|
|
153
|
+
sx={ { flexGrow: 1, py: 0, overflowY: 'auto' } }
|
|
154
|
+
{ ...getTabPanelProps( index ) }
|
|
155
|
+
>
|
|
148
156
|
<Stack p={ 2 } gap={ 2 }>
|
|
149
157
|
{ value.items.map( ( item ) => {
|
|
150
158
|
if ( item.type === 'control' ) {
|
|
@@ -156,7 +164,7 @@ const DynamicSettings = ( { controls }: { controls: DynamicTag[ 'atomic_controls
|
|
|
156
164
|
</TabPanel>
|
|
157
165
|
);
|
|
158
166
|
} ) }
|
|
159
|
-
|
|
167
|
+
</>
|
|
160
168
|
);
|
|
161
169
|
};
|
|
162
170
|
|
|
@@ -3,10 +3,10 @@ import * as React from 'react';
|
|
|
3
3
|
import { useBoundProp } from '@elementor/editor-controls';
|
|
4
4
|
import { PopoverHeader, PopoverMenuList, PopoverSearch } from '@elementor/editor-ui';
|
|
5
5
|
import { DatabaseIcon } from '@elementor/icons';
|
|
6
|
-
import {
|
|
6
|
+
import { Divider, Link, Stack, Typography, useTheme } from '@elementor/ui';
|
|
7
7
|
import { __ } from '@wordpress/i18n';
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import { PopoverBody } from '../../components/popover-body';
|
|
10
10
|
import { usePersistDynamicValue } from '../../hooks/use-persist-dynamic-value';
|
|
11
11
|
import { usePropDynamicTags } from '../hooks/use-prop-dynamic-tags';
|
|
12
12
|
import { getAtomicDynamicTags } from '../sync/get-atomic-dynamic-tags';
|
|
@@ -76,43 +76,39 @@ export const DynamicSelection = ( { close: closePopover }: DynamicSelectionProps
|
|
|
76
76
|
] );
|
|
77
77
|
|
|
78
78
|
return (
|
|
79
|
-
|
|
79
|
+
<PopoverBody>
|
|
80
80
|
<PopoverHeader
|
|
81
81
|
title={ __( 'Dynamic tags', 'elementor' ) }
|
|
82
82
|
onClose={ closePopover }
|
|
83
83
|
icon={ <DatabaseIcon fontSize={ SIZE } /> }
|
|
84
84
|
/>
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
<
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
</Fragment>
|
|
113
|
-
) }
|
|
114
|
-
</Stack>
|
|
115
|
-
</>
|
|
85
|
+
{ hasNoDynamicTags ? (
|
|
86
|
+
<NoDynamicTags />
|
|
87
|
+
) : (
|
|
88
|
+
<Fragment>
|
|
89
|
+
<PopoverSearch
|
|
90
|
+
value={ searchValue }
|
|
91
|
+
onSearch={ handleSearch }
|
|
92
|
+
placeholder={ __( 'Search dynamic tags…', 'elementor' ) }
|
|
93
|
+
/>
|
|
94
|
+
|
|
95
|
+
<Divider />
|
|
96
|
+
|
|
97
|
+
<PopoverMenuList
|
|
98
|
+
items={ virtualizedItems }
|
|
99
|
+
onSelect={ handleSetDynamicTag }
|
|
100
|
+
onClose={ closePopover }
|
|
101
|
+
selectedValue={ dynamicValue?.name }
|
|
102
|
+
itemStyle={ ( item ) =>
|
|
103
|
+
item.type === 'item' ? { paddingInlineStart: theme.spacing( 3.5 ) } : {}
|
|
104
|
+
}
|
|
105
|
+
noResultsComponent={
|
|
106
|
+
<NoResults searchValue={ searchValue } onClear={ () => setSearchValue( '' ) } />
|
|
107
|
+
}
|
|
108
|
+
/>
|
|
109
|
+
</Fragment>
|
|
110
|
+
) }
|
|
111
|
+
</PopoverBody>
|
|
116
112
|
);
|
|
117
113
|
};
|
|
118
114
|
|
|
@@ -142,7 +138,7 @@ const NoResults = ( { searchValue, onClear }: NoResultsProps ) => (
|
|
|
142
138
|
);
|
|
143
139
|
|
|
144
140
|
const NoDynamicTags = () => (
|
|
145
|
-
|
|
141
|
+
<>
|
|
146
142
|
<Divider />
|
|
147
143
|
<Stack
|
|
148
144
|
gap={ 1 }
|
|
@@ -161,7 +157,7 @@ const NoDynamicTags = () => (
|
|
|
161
157
|
{ __( "You'll need Elementor Pro to use this feature.", 'elementor' ) }
|
|
162
158
|
</Typography>
|
|
163
159
|
</Stack>
|
|
164
|
-
|
|
160
|
+
</>
|
|
165
161
|
);
|
|
166
162
|
|
|
167
163
|
const useFilteredOptions = ( searchValue: string ): OptionEntry[] => {
|
package/src/index.ts
CHANGED
|
@@ -9,7 +9,7 @@ export { usePanelActions, usePanelStatus } from './panel';
|
|
|
9
9
|
export { type ValidationResult, type ValidationEvent } from './components/creatable-autocomplete';
|
|
10
10
|
export { controlActionsMenu } from './controls-actions';
|
|
11
11
|
export { useFontFamilies } from './components/style-sections/typography-section/hooks/use-font-families';
|
|
12
|
-
export {
|
|
12
|
+
export { PopoverBody } from './components/popover-body';
|
|
13
13
|
export { useSectionWidth } from './contexts/section-context';
|
|
14
14
|
|
|
15
15
|
export { init } from './init';
|
|
@@ -15,7 +15,7 @@ export function initResetStyleProps() {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
// Temporary fix for the issue with ControlToggleButtonGroup.
|
|
18
|
-
const EXCLUDED_BINDS = [ '
|
|
18
|
+
const EXCLUDED_BINDS = [ 'flex-grow', 'flex-shrink', 'flex-basis' ];
|
|
19
19
|
|
|
20
20
|
export function useResetStyleValueProps() {
|
|
21
21
|
const isStyle = useIsStyle();
|
|
@@ -41,7 +41,7 @@ export const StylesInheritanceInfotip = ( { inheritanceChain, propType, path, la
|
|
|
41
41
|
|
|
42
42
|
const key = path.join( '.' );
|
|
43
43
|
|
|
44
|
-
const sectionWidth = useSectionWidth()
|
|
44
|
+
const sectionWidth = useSectionWidth();
|
|
45
45
|
|
|
46
46
|
const resolve = useMemo< PropsResolver >( () => {
|
|
47
47
|
return createPropsResolver( {
|
|
@@ -26,3 +26,11 @@ export const getStylesProviderThemeColor = ( provider: string ): ( ( theme: Them
|
|
|
26
26
|
|
|
27
27
|
return getStyleProviderColors( provider ).getThemeColor;
|
|
28
28
|
};
|
|
29
|
+
|
|
30
|
+
export function getTempStylesProviderThemeColor( provider: string ): ( ( theme: Theme ) => string ) | null {
|
|
31
|
+
if ( isElementsStylesProvider( provider ) ) {
|
|
32
|
+
return ( theme: Theme ) => theme.palette.primary.main;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return getStylesProviderThemeColor( provider );
|
|
36
|
+
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { PopoverScrollableContent as BasePopoverScrollableContent } from '@elementor/editor-ui';
|
|
3
|
-
|
|
4
|
-
import { useSectionWidth } from '../contexts/section-context';
|
|
5
|
-
|
|
6
|
-
type Props = React.ComponentProps< typeof BasePopoverScrollableContent >;
|
|
7
|
-
|
|
8
|
-
export const PopoverScrollableContent = ( props: Props ) => {
|
|
9
|
-
const sectionWidth = useSectionWidth();
|
|
10
|
-
|
|
11
|
-
return <BasePopoverScrollableContent { ...props } width={ sectionWidth } />;
|
|
12
|
-
};
|