first
This commit is contained in:
@ -0,0 +1,886 @@
|
||||
import './style.scss';
|
||||
|
||||
import classnames from 'classnames/dedupe';
|
||||
|
||||
import {
|
||||
__experimentalUnitControl,
|
||||
BaseControl,
|
||||
Button,
|
||||
ButtonGroup,
|
||||
CheckboxControl,
|
||||
Notice,
|
||||
PanelBody,
|
||||
RadioControl,
|
||||
RangeControl,
|
||||
TextareaControl,
|
||||
TextControl,
|
||||
ToggleControl,
|
||||
Tooltip,
|
||||
UnitControl as __stableUnitControl,
|
||||
} from '@wordpress/components';
|
||||
import {
|
||||
Component,
|
||||
RawHTML,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from '@wordpress/element';
|
||||
import { applyFilters } from '@wordpress/hooks';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
import controlConditionCheck from '../../utils/control-condition-check';
|
||||
import controlGetValue from '../../utils/control-get-value';
|
||||
import { maybeDecode, maybeEncode } from '../../utils/encode-decode';
|
||||
import AlignControl from '../align-control';
|
||||
import AspectRatio from '../aspect-ratio';
|
||||
import ClassesTree from '../classes-tree';
|
||||
import CodeEditor from '../code-editor';
|
||||
import CollapseControl from '../collapse-control';
|
||||
import ColorPicker from '../color-picker';
|
||||
import DatePicker from '../date-picker';
|
||||
import ElementsSelector from '../elements-selector';
|
||||
import GalleryControl from '../gallery-control';
|
||||
import IconsSelector from '../icons-selector';
|
||||
import NavigatorControl from '../navigator-control';
|
||||
import ProNote from '../pro-note';
|
||||
import SelectControl from '../select-control';
|
||||
import SortableControl from '../sortable-control';
|
||||
import TabsControl from '../tabs-control';
|
||||
import TilesSelector from '../tiles-selector';
|
||||
import ToggleGroupControl from '../toggle-group-control';
|
||||
import ToggleModal from '../toggle-modal';
|
||||
|
||||
const UnitControl = __stableUnitControl || __experimentalUnitControl;
|
||||
|
||||
const {
|
||||
controls: registeredControls,
|
||||
controls_categories: registeredControlsCategories,
|
||||
plugin_version: pluginVersion,
|
||||
} = window.VPGutenbergVariables;
|
||||
|
||||
const openedCategoriesCache = {};
|
||||
|
||||
/**
|
||||
* Component Class
|
||||
*/
|
||||
class ControlsRender extends Component {
|
||||
render() {
|
||||
const {
|
||||
category,
|
||||
categoryToggle = true,
|
||||
attributes,
|
||||
setAttributes,
|
||||
controls,
|
||||
clientId,
|
||||
isSetupWizard,
|
||||
showPanel = true,
|
||||
} = this.props;
|
||||
|
||||
if (!attributes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// content source conditions.
|
||||
if (
|
||||
/^content-source-/g.test(category) &&
|
||||
category !== 'content-source-general' &&
|
||||
`content-source-${attributes.content_source}` !== category
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const usedControls = controls || registeredControls;
|
||||
const result = [];
|
||||
|
||||
Object.keys(usedControls).forEach((name) => {
|
||||
const control = usedControls[name];
|
||||
|
||||
if (
|
||||
category &&
|
||||
(!control.category || category !== control.category)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const controlData = applyFilters(
|
||||
'vpf.editor.controls-render-data',
|
||||
{
|
||||
attributes,
|
||||
setAttributes,
|
||||
onChange: (val) => {
|
||||
const newAttrs = applyFilters(
|
||||
'vpf.editor.controls-on-change',
|
||||
{ [control.name]: val },
|
||||
control,
|
||||
val,
|
||||
attributes
|
||||
);
|
||||
setAttributes(newAttrs);
|
||||
},
|
||||
...control,
|
||||
}
|
||||
);
|
||||
|
||||
// Conditions check.
|
||||
if (!ControlsRender.AllowRender(controlData, isSetupWizard)) {
|
||||
return;
|
||||
}
|
||||
|
||||
result.push(
|
||||
applyFilters(
|
||||
'vpf.editor.controls-render',
|
||||
<ControlsRender.Control
|
||||
key={`control-${control.name}-${control.label}`}
|
||||
{...controlData}
|
||||
clientId={clientId}
|
||||
isSetupWizard={isSetupWizard}
|
||||
renderProps={this.props}
|
||||
/>,
|
||||
controlData,
|
||||
this.props
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
let categoryTitle = categoryToggle ? category : false;
|
||||
let categoryIcon = false;
|
||||
let categoryPro = false;
|
||||
let categoryOpened = !categoryToggle;
|
||||
|
||||
if (
|
||||
categoryToggle &&
|
||||
typeof registeredControlsCategories[category] !== 'undefined'
|
||||
) {
|
||||
categoryTitle = registeredControlsCategories[category].title;
|
||||
categoryIcon = registeredControlsCategories[category].icon || false;
|
||||
categoryPro = !!registeredControlsCategories[category].is_pro;
|
||||
|
||||
if (typeof openedCategoriesCache[category] === 'undefined') {
|
||||
openedCategoriesCache[category] =
|
||||
registeredControlsCategories[category].is_opened || false;
|
||||
}
|
||||
categoryOpened = openedCategoriesCache[category];
|
||||
}
|
||||
|
||||
if (isSetupWizard) {
|
||||
return result.length ? (
|
||||
<div className="vpf-setup-wizard-panel">{result}</div>
|
||||
) : (
|
||||
''
|
||||
);
|
||||
}
|
||||
|
||||
if (!showPanel) {
|
||||
return result.length ? result : '';
|
||||
}
|
||||
|
||||
return result.length ? (
|
||||
<PanelBody
|
||||
title={
|
||||
categoryTitle ? (
|
||||
<>
|
||||
{categoryIcon ? (
|
||||
<span className="vpf-control-category-title-icon">
|
||||
<RawHTML>{categoryIcon}</RawHTML>
|
||||
</span>
|
||||
) : null}
|
||||
<span>{categoryTitle}</span>
|
||||
{categoryPro ? (
|
||||
<span className="vpf-control-category-title-pro">
|
||||
{__('PRO', 'visual-portfolio')}
|
||||
</span>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
false
|
||||
)
|
||||
}
|
||||
onToggle={() => {
|
||||
openedCategoriesCache[category] = !categoryOpened;
|
||||
}}
|
||||
initialOpen={categoryOpened}
|
||||
scrollAfterOpen
|
||||
>
|
||||
{result}
|
||||
</PanelBody>
|
||||
) : (
|
||||
''
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render Single Control.
|
||||
*
|
||||
* @param {Object} props - control props.
|
||||
*
|
||||
* @return {JSX} control.
|
||||
*/
|
||||
ControlsRender.Control = function (props) {
|
||||
const { attributes, onChange, isSetupWizard } = props;
|
||||
const $ref = useRef();
|
||||
const [positionInGroup, setPositionInGroup] = useState('');
|
||||
|
||||
const controlVal = controlGetValue(props.name, attributes);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.group && $ref.current) {
|
||||
const $element = $ref.current.parentElement.parentElement;
|
||||
let $prevSibling = $element.previousElementSibling;
|
||||
let $nextSibling = $element.nextElementSibling;
|
||||
|
||||
// Skip separator.
|
||||
while (
|
||||
$prevSibling &&
|
||||
$prevSibling.classList.contains('vpf-control-group-separator')
|
||||
) {
|
||||
$prevSibling = $prevSibling.previousElementSibling;
|
||||
}
|
||||
while (
|
||||
$nextSibling &&
|
||||
$nextSibling.classList.contains('vpf-control-group-separator')
|
||||
) {
|
||||
$nextSibling = $nextSibling.nextElementSibling;
|
||||
}
|
||||
|
||||
const isGroupEnabled =
|
||||
($prevSibling &&
|
||||
$prevSibling.classList.contains(
|
||||
`vpf-control-group-${props.group}`
|
||||
)) ||
|
||||
($nextSibling &&
|
||||
$nextSibling.classList.contains(
|
||||
`vpf-control-group-${props.group}`
|
||||
));
|
||||
const isStart =
|
||||
$prevSibling &&
|
||||
!$prevSibling.classList.contains(
|
||||
`vpf-control-group-${props.group}`
|
||||
) &&
|
||||
$prevSibling.classList.contains(`vpf-control-wrap`);
|
||||
const isEnd =
|
||||
$nextSibling &&
|
||||
!$nextSibling.classList.contains(
|
||||
`vpf-control-group-${props.group}`
|
||||
) &&
|
||||
$nextSibling.classList.contains(`vpf-control-wrap`);
|
||||
|
||||
let newPosition = '';
|
||||
|
||||
if (!isGroupEnabled) {
|
||||
// skip
|
||||
} else if (isStart) {
|
||||
newPosition = 'start';
|
||||
} else if (isEnd) {
|
||||
newPosition = 'end';
|
||||
}
|
||||
|
||||
if (positionInGroup !== newPosition) {
|
||||
setPositionInGroup(newPosition);
|
||||
}
|
||||
}
|
||||
}, [$ref, props.group, controlVal, positionInGroup]);
|
||||
|
||||
// Conditions check.
|
||||
if (!ControlsRender.AllowRender(props, isSetupWizard)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let renderControl = '';
|
||||
let renderControlLabel = props.label;
|
||||
let renderControlAfter = '';
|
||||
let renderControlHelp = props.description ? (
|
||||
<RawHTML className="components-base-control__help">
|
||||
{props.description}
|
||||
</RawHTML>
|
||||
) : null;
|
||||
let renderControlClassName = classnames(
|
||||
'vpf-control-wrap',
|
||||
`vpf-control-wrap-${props.type}`
|
||||
);
|
||||
|
||||
if (props.group) {
|
||||
renderControlClassName = classnames(
|
||||
renderControlClassName,
|
||||
'vpf-control-with-group',
|
||||
`vpf-control-group-${props.group}`,
|
||||
positionInGroup
|
||||
? `vpf-control-group-position-${positionInGroup}`
|
||||
: false
|
||||
);
|
||||
}
|
||||
|
||||
const categoryControlOptions = [];
|
||||
|
||||
// Check if category is empty.
|
||||
if (
|
||||
(props.type === 'category_tabs' ||
|
||||
props.type === 'category_toggle_group' ||
|
||||
props.type === 'category_collapse' ||
|
||||
props.type === 'category_navigator') &&
|
||||
props.options &&
|
||||
props.options.length
|
||||
) {
|
||||
props.options.forEach((opt) => {
|
||||
const isEmpty = ControlsRender.isCategoryEmpty({
|
||||
...props.renderProps,
|
||||
category: opt.category,
|
||||
categoryToggle: false,
|
||||
});
|
||||
|
||||
if (!isEmpty) {
|
||||
categoryControlOptions.push(opt);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Specific controls.
|
||||
switch (props.type) {
|
||||
case 'category_tabs':
|
||||
if (categoryControlOptions.length) {
|
||||
renderControl = (
|
||||
<TabsControl
|
||||
controlName={props.name}
|
||||
options={categoryControlOptions}
|
||||
key={categoryControlOptions}
|
||||
>
|
||||
{(tab) => {
|
||||
return (
|
||||
<ControlsRender
|
||||
{...props.renderProps}
|
||||
category={tab.name}
|
||||
categoryToggle={false}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</TabsControl>
|
||||
);
|
||||
} else {
|
||||
renderControl = null;
|
||||
}
|
||||
|
||||
break;
|
||||
case 'category_toggle_group':
|
||||
if (categoryControlOptions.length) {
|
||||
renderControl = (
|
||||
<ToggleGroupControl
|
||||
controlName={props.name}
|
||||
options={categoryControlOptions}
|
||||
key={categoryControlOptions}
|
||||
>
|
||||
{(group) => {
|
||||
return (
|
||||
<ControlsRender
|
||||
{...props.renderProps}
|
||||
category={group.category}
|
||||
categoryToggle={false}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</ToggleGroupControl>
|
||||
);
|
||||
} else {
|
||||
renderControl = null;
|
||||
}
|
||||
|
||||
break;
|
||||
case 'category_collapse':
|
||||
if (categoryControlOptions.length) {
|
||||
renderControl = (
|
||||
<CollapseControl
|
||||
controlName={props.name}
|
||||
initialOpen={props.initialOpen}
|
||||
options={categoryControlOptions}
|
||||
key={categoryControlOptions}
|
||||
>
|
||||
{(tab) => {
|
||||
return (
|
||||
<ControlsRender
|
||||
{...props.renderProps}
|
||||
category={tab.category}
|
||||
categoryToggle={false}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</CollapseControl>
|
||||
);
|
||||
} else {
|
||||
renderControl = null;
|
||||
}
|
||||
|
||||
break;
|
||||
case 'category_navigator':
|
||||
if (categoryControlOptions.length) {
|
||||
renderControl = (
|
||||
<NavigatorControl
|
||||
controlName={props.name}
|
||||
options={categoryControlOptions}
|
||||
key={categoryControlOptions}
|
||||
>
|
||||
{(tab) => {
|
||||
return (
|
||||
<ControlsRender
|
||||
{...props.renderProps}
|
||||
category={tab.category}
|
||||
categoryToggle={false}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</NavigatorControl>
|
||||
);
|
||||
} else {
|
||||
renderControl = null;
|
||||
}
|
||||
|
||||
break;
|
||||
case 'html':
|
||||
renderControl = <RawHTML>{props.default}</RawHTML>;
|
||||
break;
|
||||
case 'select':
|
||||
case 'select2':
|
||||
renderControl = (
|
||||
<SelectControl
|
||||
controlName={props.name}
|
||||
callback={props.value_callback}
|
||||
attributes={attributes}
|
||||
value={controlVal}
|
||||
options={props.options || {}}
|
||||
onChange={(val) => onChange(val)}
|
||||
isSearchable={props.searchable}
|
||||
isMultiple={props.multiple}
|
||||
isCreatable={props.creatable || props.tags}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'buttons':
|
||||
renderControl = (
|
||||
<ButtonGroup>
|
||||
{Object.keys(props.options || {}).map((val) => (
|
||||
<Button
|
||||
isSmall
|
||||
isPrimary={controlVal === val}
|
||||
isPressed={controlVal === val}
|
||||
key={val}
|
||||
onClick={() => onChange(val)}
|
||||
>
|
||||
{props.options[val]}
|
||||
</Button>
|
||||
))}
|
||||
</ButtonGroup>
|
||||
);
|
||||
break;
|
||||
case 'icons_selector':
|
||||
renderControl = (
|
||||
<IconsSelector
|
||||
controlName={props.name}
|
||||
callback={props.value_callback}
|
||||
attributes={attributes}
|
||||
value={controlVal}
|
||||
options={props.options}
|
||||
onChange={(val) => onChange(val)}
|
||||
collapseRows={props.collapse_rows || false}
|
||||
isSetupWizard={isSetupWizard}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'tiles_selector':
|
||||
renderControl = (
|
||||
<TilesSelector
|
||||
value={controlVal}
|
||||
options={props.options}
|
||||
onChange={(val) => onChange(val)}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'elements_selector':
|
||||
renderControl = (
|
||||
<ElementsSelector
|
||||
value={controlVal}
|
||||
locations={props.locations}
|
||||
options={props.options}
|
||||
onChange={(val) => onChange(val)}
|
||||
props={props}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'align': {
|
||||
renderControl = (
|
||||
<AlignControl
|
||||
value={controlVal}
|
||||
options={props.options || 'horizontal'}
|
||||
onChange={(val) => onChange(val)}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'aspect_ratio': {
|
||||
renderControl = (
|
||||
<AspectRatio
|
||||
value={controlVal}
|
||||
onChange={(val) => onChange(val)}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'gallery':
|
||||
renderControl = (
|
||||
<GalleryControl
|
||||
imageControls={props.image_controls}
|
||||
focalPoint={props.focal_point}
|
||||
attributes={attributes}
|
||||
name={props.name}
|
||||
value={controlVal}
|
||||
onChange={(val) => onChange(val)}
|
||||
isSetupWizard={isSetupWizard}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'code_editor':
|
||||
renderControl = (
|
||||
<CodeEditor
|
||||
value={props.encode ? maybeDecode(controlVal) : controlVal}
|
||||
mode={props.mode}
|
||||
maxLines={props.max_lines}
|
||||
minLines={props.min_lines}
|
||||
codePlaceholder={props.code_placeholder}
|
||||
onChange={(val) =>
|
||||
onChange(props.encode ? maybeEncode(val) : val)
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
if (props.allow_modal) {
|
||||
renderControlAfter = (
|
||||
<ToggleModal
|
||||
modalTitle={__('Custom CSS', 'visual-portfolio')}
|
||||
buttonLabel={__('Open in Modal', 'visual-portfolio')}
|
||||
size="md"
|
||||
>
|
||||
<BaseControl
|
||||
id={`vpf-custom-css-${props.label || props.name}`}
|
||||
label={props.label}
|
||||
help={
|
||||
props.description ? (
|
||||
<RawHTML>{props.description}</RawHTML>
|
||||
) : (
|
||||
false
|
||||
)
|
||||
}
|
||||
className={classnames(
|
||||
'vpf-control-wrap',
|
||||
`vpf-control-wrap-${props.type}`
|
||||
)}
|
||||
>
|
||||
<div>{renderControl}</div>
|
||||
</BaseControl>
|
||||
{props.classes_tree ? (
|
||||
<>
|
||||
<p>{__('Classes Tree:', 'visual-portfolio')}</p>
|
||||
<ClassesTree {...props} />
|
||||
</>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</ToggleModal>
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'range':
|
||||
renderControl = (
|
||||
<RangeControl
|
||||
min={props.min}
|
||||
max={props.max}
|
||||
step={props.step}
|
||||
value={parseFloat(controlVal)}
|
||||
onChange={(val) => onChange(parseFloat(val))}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'toggle':
|
||||
renderControl = (
|
||||
<ToggleControl
|
||||
checked={controlVal}
|
||||
label={props.alongside}
|
||||
onChange={(val) => onChange(val)}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'checkbox':
|
||||
renderControl = (
|
||||
<CheckboxControl
|
||||
checked={controlVal}
|
||||
label={props.alongside}
|
||||
onChange={(val) => onChange(val)}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'radio':
|
||||
renderControl = (
|
||||
<RadioControl
|
||||
label={renderControlLabel}
|
||||
selected={controlVal}
|
||||
options={Object.keys(props.options || {}).map((val) => ({
|
||||
label: props.options[val],
|
||||
value: val,
|
||||
}))}
|
||||
onChange={(option) => onChange(option)}
|
||||
/>
|
||||
);
|
||||
renderControlLabel = false;
|
||||
break;
|
||||
case 'color':
|
||||
renderControl = (
|
||||
<ColorPicker
|
||||
label={renderControlLabel}
|
||||
value={controlVal}
|
||||
alpha={props.alpha}
|
||||
gradient={props.gradient}
|
||||
onChange={(val) => onChange(val)}
|
||||
/>
|
||||
);
|
||||
renderControlLabel = false;
|
||||
break;
|
||||
case 'date':
|
||||
renderControl = (
|
||||
<DatePicker
|
||||
value={controlVal}
|
||||
onChange={(val) => onChange(val)}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'textarea':
|
||||
renderControl = (
|
||||
<TextareaControl
|
||||
label={renderControlLabel}
|
||||
value={controlVal}
|
||||
onChange={(val) => onChange(val)}
|
||||
/>
|
||||
);
|
||||
renderControlLabel = false;
|
||||
break;
|
||||
case 'url':
|
||||
renderControl = (
|
||||
<TextControl
|
||||
label={renderControlLabel}
|
||||
type="url"
|
||||
value={controlVal}
|
||||
onChange={(val) => onChange(val)}
|
||||
/>
|
||||
);
|
||||
renderControlLabel = false;
|
||||
break;
|
||||
case 'number':
|
||||
renderControl = (
|
||||
<TextControl
|
||||
label={renderControlLabel}
|
||||
type="number"
|
||||
min={props.min}
|
||||
max={props.max}
|
||||
step={props.step}
|
||||
value={parseFloat(controlVal)}
|
||||
onChange={(val) => onChange(parseFloat(val))}
|
||||
/>
|
||||
);
|
||||
renderControlLabel = false;
|
||||
break;
|
||||
case 'unit':
|
||||
renderControl = (
|
||||
<UnitControl
|
||||
label={renderControlLabel}
|
||||
value={controlVal}
|
||||
onChange={(val) => onChange(val)}
|
||||
labelPosition="edge"
|
||||
__unstableInputWidth="70px"
|
||||
/>
|
||||
);
|
||||
renderControlLabel = false;
|
||||
break;
|
||||
case 'hidden':
|
||||
renderControl = (
|
||||
<TextControl
|
||||
type="hidden"
|
||||
value={controlVal}
|
||||
onChange={(val) => onChange(val)}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case 'notice':
|
||||
renderControl = renderControlHelp ? (
|
||||
<Notice status={props.status} isDismissible={false}>
|
||||
{renderControlHelp}
|
||||
</Notice>
|
||||
) : (
|
||||
''
|
||||
);
|
||||
renderControlHelp = false;
|
||||
break;
|
||||
case 'pro_note':
|
||||
renderControl = (
|
||||
<ProNote title={renderControlLabel}>
|
||||
{renderControlHelp || ''}
|
||||
<ProNote.Button
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href={`https://visualportfolio.co/pricing/?utm_source=plugin&utm_medium=block_settings&utm_campaign=${props.name}&utm_content=${pluginVersion}`}
|
||||
>
|
||||
{__('Go Pro', 'visual-portfolio')}
|
||||
</ProNote.Button>
|
||||
</ProNote>
|
||||
);
|
||||
renderControlLabel = false;
|
||||
renderControlHelp = false;
|
||||
break;
|
||||
case 'sortable':
|
||||
renderControl = (
|
||||
<SortableControl
|
||||
label={renderControlLabel}
|
||||
controlName={props.name}
|
||||
attributes={attributes}
|
||||
value={controlVal}
|
||||
options={props.options || {}}
|
||||
defaultVal={props.default || {}}
|
||||
allowDisablingOptions={
|
||||
props.allow_disabling_options || false
|
||||
}
|
||||
onChange={(val) => onChange(val)}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
default:
|
||||
renderControl = (
|
||||
<TextControl
|
||||
label={renderControlLabel}
|
||||
value={controlVal}
|
||||
onChange={(val) => onChange(val)}
|
||||
/>
|
||||
);
|
||||
renderControlLabel = false;
|
||||
}
|
||||
|
||||
// Hint.
|
||||
if (props.hint) {
|
||||
renderControl = (
|
||||
<Tooltip text={props.hint} position={props.hint_place}>
|
||||
<div>{renderControl}</div>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: use this filter for custom controls.
|
||||
const data = applyFilters(
|
||||
'vpf.editor.controls-render-inner-data',
|
||||
{
|
||||
renderControl,
|
||||
renderControlLabel,
|
||||
renderControlHelp,
|
||||
renderControlAfter,
|
||||
renderControlClassName,
|
||||
},
|
||||
{ props, controlVal }
|
||||
);
|
||||
|
||||
// Prevent rendering.
|
||||
if (data.renderControl === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{positionInGroup === 'start' ? (
|
||||
<div className="vpf-control-group-separator" />
|
||||
) : null}
|
||||
<BaseControl
|
||||
id={`vpf-control-group-${props.name}`}
|
||||
label={data.renderControlLabel}
|
||||
className={data.renderControlClassName}
|
||||
>
|
||||
<div ref={$ref}>{data.renderControl}</div>
|
||||
{data.renderControlHelp}
|
||||
</BaseControl>
|
||||
{data.renderControlAfter}
|
||||
{positionInGroup === 'end' ? (
|
||||
<div className="vpf-control-group-separator" />
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if control is allowed to rendering.
|
||||
*
|
||||
* @param props
|
||||
* @param isSetupWizard
|
||||
*/
|
||||
ControlsRender.AllowRender = function (props, isSetupWizard = false) {
|
||||
if (props.skip) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
props.condition &&
|
||||
props.condition.length &&
|
||||
!controlConditionCheck(props.condition, props.attributes)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isSetupWizard && !props.setup_wizard) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if category does not contains controls.
|
||||
*
|
||||
* @param props
|
||||
*/
|
||||
ControlsRender.isCategoryEmpty = function (props) {
|
||||
const { category, attributes, setAttributes, controls, isSetupWizard } =
|
||||
props;
|
||||
|
||||
const usedControls = controls || registeredControls;
|
||||
let isEmpty = true;
|
||||
|
||||
Object.keys(usedControls).forEach((name) => {
|
||||
if (!isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
const control = usedControls[name];
|
||||
|
||||
if (category && (!control.category || category !== control.category)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const controlData = applyFilters('vpf.editor.controls-render-data', {
|
||||
attributes,
|
||||
setAttributes,
|
||||
onChange: (val) => {
|
||||
const newAttrs = applyFilters(
|
||||
'vpf.editor.controls-on-change',
|
||||
{ [control.name]: val },
|
||||
control,
|
||||
val,
|
||||
attributes
|
||||
);
|
||||
setAttributes(newAttrs);
|
||||
},
|
||||
...control,
|
||||
});
|
||||
|
||||
// Conditions check.
|
||||
if (!ControlsRender.AllowRender(controlData, isSetupWizard)) {
|
||||
return;
|
||||
}
|
||||
|
||||
isEmpty = false;
|
||||
});
|
||||
|
||||
return isEmpty;
|
||||
};
|
||||
|
||||
export default ControlsRender;
|
@ -0,0 +1,78 @@
|
||||
.vpf-control-wrap {
|
||||
> .components-base-control__help,
|
||||
> .components-base-control__field > .components-base-control__help {
|
||||
margin-bottom: 1em;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
color: rgb(117, 117, 117);
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.components-base-control__label {
|
||||
display: inline-block;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.components-modal__content & {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
// Text control.
|
||||
.vpf-control-wrap-text input[disabled] {
|
||||
color: rgba(44, 51, 56, 50%);
|
||||
border-color: rgba(220, 220, 222, 75%);
|
||||
box-shadow: inset 0 1px 2px rgb(0 0 0 / 4%);
|
||||
}
|
||||
|
||||
// Notice control.
|
||||
.vpf-control-wrap-notice .components-notice {
|
||||
margin: 0;
|
||||
|
||||
&.is-info {
|
||||
background-color: #e6f7ff;
|
||||
}
|
||||
}
|
||||
|
||||
.vpf-control-category-title-pro {
|
||||
padding: 0.2em 0.8em;
|
||||
margin-right: 30px;
|
||||
margin-left: auto;
|
||||
font-size: 0.8em;
|
||||
color: #fff;
|
||||
background-color: #2540cc;
|
||||
border-radius: 1em;
|
||||
}
|
||||
|
||||
.components-panel__body-toggle > .vpf-control-category-title-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
display: block;
|
||||
transform: translateY(-50%);
|
||||
|
||||
+ span {
|
||||
margin-left: 28px;
|
||||
}
|
||||
|
||||
svg {
|
||||
display: block;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
// Group controls.
|
||||
.vpf-control-group-separator {
|
||||
margin-bottom: 18px;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
|
||||
+ .vpf-control-group-separator {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.vpf-component-modal &,
|
||||
.vpf-component-elements-selector-modal & {
|
||||
margin-right: -32px;
|
||||
margin-left: -32px;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user