feat: initial ACRIB WordPress deployment

- WordPress 6.9.4 (es_ES) with Kadence theme
- Homepage: Hero, La Asociación, Pilares, Beneficios, Eventos, Miembros, Hazte Miembro, Contacto
- Brand identity: #13294b navy, #a12932 burgundy, #c69c48 gold
- Fonts: Raleway (headings) + Source Sans 3 (body) + Lato (UI)
- Plugins: Kadence Blocks, Polylang, Contact Form 7
- Custom CSS with full brand styling and responsive layout
- HTTPS enforced via wp-config.php proxy detection
This commit is contained in:
Malin
2026-05-19 19:25:59 +02:00
commit f3ff7b7186
6119 changed files with 1984255 additions and 0 deletions

View File

@@ -0,0 +1,146 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import ResponsiveControl from '../common/responsive.js';
import Icons from '../common/icons.js';
import { ReactSortable } from "react-sortablejs";
import { __ } from '@wordpress/i18n';
const { ButtonGroup, Dashicon, Tooltip, Button } = wp.components;
const { Component, Fragment } = wp.element;
class AvailableComponent extends Component {
constructor() {
super( ...arguments );
this.linkRemovingItem = this.linkRemovingItem.bind( this );
this.onDragEnd = this.onDragEnd.bind( this );
this.onDragStart = this.onDragStart.bind( this );
this.onUpdate = this.onUpdate.bind( this );
this.onDragStop = this.onDragStop.bind( this );
this.focusPanel = this.focusPanel.bind( this );
let settings = {};
let defaultParams = {};
this.controlParams = this.props.control.params.input_attrs ? {
...defaultParams,
...this.props.control.params.input_attrs,
} : defaultParams;
if ( kadenceCustomizerControlsData.source && undefined !== this.props.customizer.control( kadenceCustomizerControlsData.source + '[' + this.controlParams.group + ']' ) ) {
settings = this.props.customizer.control( kadenceCustomizerControlsData.source + '[' + this.controlParams.group + ']' ).setting.get();
} else if ( undefined !== this.props.customizer.control( this.controlParams.group ) ) {
settings = this.props.customizer.control( this.controlParams.group ).setting.get();
}
this.choices = ( kadenceCustomizerControlsData && kadenceCustomizerControlsData.choices && kadenceCustomizerControlsData.choices[ this.controlParams.group ] ? kadenceCustomizerControlsData.choices[ this.controlParams.group ] : [] );
this.state = {
settings: settings,
};
this.linkRemovingItem();
}
onUpdate() {
if ( kadenceCustomizerControlsData.source && undefined !== this.props.customizer.control( kadenceCustomizerControlsData.source + '[' + this.controlParams.group + ']' ) ) {
const settings = this.props.customizer.control( kadenceCustomizerControlsData.source + '[' + this.controlParams.group + ']' ).setting.get();
this.setState( { settings: settings } );
} else if ( undefined !== this.props.customizer.control( this.controlParams.group ) ) {
const settings = this.props.customizer.control( this.controlParams.group ).setting.get();
this.setState( { settings: settings } );
}
}
onDragStart() {
var dropzones = document.querySelectorAll( '.kadence-builder-area' );
var i;
for (i = 0; i < dropzones.length; ++i) {
dropzones[i].classList.add( 'kadence-dragging-dropzones' );
}
}
onDragStop() {
var dropzones = document.querySelectorAll( '.kadence-builder-area' );
var i;
for (i = 0; i < dropzones.length; ++i) {
dropzones[i].classList.remove( 'kadence-dragging-dropzones' );
}
}
focusPanel( item ) {
if ( undefined !== this.props.customizer.section( this.choices[ item ].section ) ) {
this.props.customizer.section( this.choices[ item ].section ).focus();
}
}
onDragEnd( items ) {
if ( items.length != null && items.length === 0 ) {
this.onUpdate();
}
}
render() {
const renderItem = ( item, row ) => {
let available = true;
this.controlParams.zones.map( ( zone ) => {
Object.keys( this.state.settings[zone] ).map( ( area ) => {
if ( this.state.settings[zone][area].includes( item ) ) {
available = false;
}
} );
} );
let theitem = [ {
id: item,
} ];
return (
<Fragment>
{ available && row === 'available' && (
<ReactSortable animation={100} onStart={ () => this.onDragStart() } onEnd={ () => this.onDragStop() } group={ { name: this.controlParams.group, put: false } } className={ 'kadence-builder-item-start kadence-move-item' } list={ theitem } setList={ newState => this.onDragEnd( newState ) } >
<div className="kadence-builder-item" data-id={ item } data-section={ undefined !== this.choices[ item ] && undefined !== this.choices[ item ].section ? this.choices[ item ].section : '' } key={ item }>
<span
className="kadence-builder-item-icon kadence-move-icon"
>
{ Icons['drag'] }
</span>
{ ( undefined !== this.choices[ item ] && undefined !== this.choices[ item ].name ? this.choices[ item ].name : '' ) }
</div>
</ReactSortable>
) }
{ ! available && row === 'links' && (
<div className={ 'kadence-builder-item-start' }>
<Button className="kadence-builder-item" data-id={ item } onClick={ () => this.focusPanel( item ) } data-section={ undefined !== this.choices[ item ] && undefined !== this.choices[ item ].section ? this.choices[ item ].section : '' } key={ item }>
{ ( undefined !== this.choices[ item ] && undefined !== this.choices[ item ].name ? this.choices[ item ].name : '' ) }
<span
className="kadence-builder-item-icon"
>
<Dashicon icon="arrow-right-alt2"/>
</span>
</Button>
</div>
) }
</Fragment>
);
};
return (
<div className="kadence-control-field kadence-available-items">
{ Object.keys( this.choices ).map( ( item ) => {
return renderItem( item, 'links' );
} ) }
<div className="kadence-available-items-title">
<span className="customize-control-title">{ __( 'Available Items', 'kadence' ) }</span>
</div>
<div className="kadence-available-items-pool">
{ Object.keys( this.choices ).map( ( item ) => {
return renderItem( item, 'available' );
} ) }
</div>
{ this.props.control.renderNotice() }
</div>
);
}
linkRemovingItem() {
let self = this;
document.addEventListener( 'kadenceRemovedBuilderItem', function( e ) {
if ( e.detail === self.controlParams.group ) {
self.onUpdate();
}
} );
}
}
AvailableComponent.propTypes = {
control: PropTypes.object.isRequired,
customizer: PropTypes.object.isRequired
};
export default AvailableComponent;

View File

@@ -0,0 +1,11 @@
import { createRoot } from '@wordpress/element';
import AvailableComponent from './available-component.js';
export const AvailableControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <AvailableComponent control={ control } customizer={ wp.customize } /> );
// ReactDOM.render( <AvailableComponent control={ control } customizer={ wp.customize } />, control.container[0] );
}
} );

View File

@@ -0,0 +1,122 @@
/**
* External dependencies
*/
import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { Icon, check } from '@wordpress/icons';
/**
* Internal dependencies
*/
const {
Button,
Dropdown,
Tooltip,
} = wp.components;
function Option( {
className,
isSelected,
selectedIconProps,
tooltipText,
...additionalProps
} ) {
const optionButton = (
<Button
isPressed={ isSelected }
className={ classnames(
className,
'components-circular-option-picker__option'
) }
{ ...additionalProps }
/>
);
return (
<div className="components-circular-option-picker__option-wrapper">
{ tooltipText ? (
<Tooltip text={ tooltipText }>{ optionButton }</Tooltip>
) : (
optionButton
) }
{ isSelected && (
<Icon
icon={ check }
{ ...( selectedIconProps ? selectedIconProps : {} ) }
/>
) }
</div>
);
}
function DropdownLinkAction( {
buttonProps,
className,
dropdownProps,
linkText,
} ) {
return (
<Dropdown
className={ classnames(
'components-circular-option-picker__dropdown-link-action',
className
) }
renderToggle={ ( { isOpen, onToggle } ) => (
<Button
aria-expanded={ isOpen }
onClick={ onToggle }
isLink
{ ...buttonProps }
>
{ linkText }
</Button>
) }
{ ...dropdownProps }
/>
);
}
function ButtonAction( { className, children, ...additionalProps } ) {
return (
<Button
className={ classnames(
'components-circular-option-picker__clear',
className
) }
isSmall
isSecondary
{ ...additionalProps }
>
{ children }
</Button>
);
}
export default function CircularOptionPicker( {
actions,
className,
options,
children,
} ) {
return (
<div
className={ classnames(
'components-circular-option-picker',
className
) }
>
{ options }
{ children }
{ actions && (
<div className="components-circular-option-picker__custom-clear-wrapper">
{ actions }
</div>
) }
</div>
);
}
CircularOptionPicker.Option = Option;
CircularOptionPicker.ButtonAction = ButtonAction;
CircularOptionPicker.DropdownLinkAction = DropdownLinkAction;

View File

@@ -0,0 +1,229 @@
import { createRoot } from '@wordpress/element';
import BackgroundComponent from './background-component.js';
export const BackgroundControl = wp.customize.MediaControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <BackgroundComponent control={control} customizer={ wp.customize }/> );
},
initialize: function( id, options ) {
var control = this,
args = options || {};
args.params = args.params || {};
if ( ! args.params.type ) {
args.params.type = 'kadence-basic';
}
if ( ! args.params.content ) {
args.params.content = jQuery( '<li></li>' );
args.params.content.attr( 'id', 'customize-control-' + id.replace( /]/g, '' ).replace( /\[/g, '-' ) );
args.params.content.attr( 'class', 'customize-control customize-control-' + args.params.type );
}
control.propertyElements = [];
wp.customize.Control.prototype.initialize.call( control, id, args );
},
/**
* Add bidirectional data binding links between inputs and the setting(s).
*
* This is copied from wp.customize.Control.prototype.initialize(). It
* should be changed in Core to be applied once the control is embedded.
*
* @private
* @returns {null}
*/
_setUpSettingRootLinks: function() {
var control = this,
nodes = control.container.find( '[data-customize-setting-link]' );
nodes.each( function() {
var node = jQuery( this );
wp.customize( node.data( 'customizeSettingLink' ), function( setting ) {
var element = new wp.customize.Element( node );
control.elements.push( element );
element.sync( setting );
element.set( setting() );
} );
} );
},
/**
* Add bidirectional data binding links between inputs and the setting properties.
*
* @private
* @returns {null}
*/
_setUpSettingPropertyLinks: function() {
var control = this,
nodes;
if ( ! control.setting ) {
return;
}
nodes = control.container.find( '[data-customize-setting-property-link]' );
nodes.each( function() {
var node = jQuery( this ),
element,
propertyName = node.data( 'customizeSettingPropertyLink' );
element = new wp.customize.Element( node );
control.propertyElements.push( element );
element.set( control.setting()[ propertyName ] );
element.bind( function( newPropertyValue ) {
var newSetting = control.setting();
if ( newPropertyValue === newSetting[ propertyName ] ) {
return;
}
newSetting = _.clone( newSetting );
newSetting[ propertyName ] = newPropertyValue;
control.setting.set( newSetting );
} );
control.setting.bind( function( newValue ) {
if ( newValue[ propertyName ] !== element.get() ) {
element.set( newValue[ propertyName ] );
}
} );
} );
},
/**
* @inheritdoc
*/
ready: function() {
var control = this;
// Shortcut so that we don't have to use _.bind every time we add a callback.
_.bindAll( control, 'openFrame', 'select' );
// Bind events, with delegation to facilitate re-rendering.
control.container.on( 'click keydown', '.upload-button', function( e ) {
let event = new CustomEvent( 'kadenceOpenMediaModal', {
'detail': false,
} );
document.dispatchEvent( event );
control.openFrame( e );
} );
control._setUpSettingRootLinks();
control._setUpSettingPropertyLinks();
wp.customize.Control.prototype.ready.call( control );
control.setting.bind( control.renderContent() );
control.deferred.embedded.done( function() {
} );
},
/**
* Embed the control in the document.
*
* Override the embed() method to do nothing,
* so that the control isn't embedded on load,
* unless the containing section is already expanded.
*
* @returns {null}
*/
embed: function() {
var control = this,
sectionId = control.section();
if ( ! sectionId ) {
return;
}
wp.customize.section( sectionId, function( section ) {
if ( section.expanded() || wp.customize.settings.autofocus.control === control.id ) {
control.actuallyEmbed();
} else {
section.expanded.bind( function( expanded ) {
if ( expanded ) {
control.actuallyEmbed();
}
} );
}
} );
},
/**
* Deferred embedding of control when actually
*
* This function is called in Section.onChangeExpanded() so the control
* will only get embedded when the Section is first expanded.
*
* @returns {null}
*/
actuallyEmbed: function() {
var control = this;
if ( 'resolved' === control.deferred.embedded.state() ) {
return;
}
control.renderContent();
control.deferred.embedded.resolve(); // This triggers control.ready().
// Fire event after control is initialized.
control.container.trigger( 'init' );
},
/**
* This is not working with autofocus.
*
* @param {object} [args] Args.
* @returns {null}
*/
focus: function( args ) {
var control = this;
control.actuallyEmbed();
wp.customize.Control.prototype.focus.call( control, args );
},
/**
* Callback handler for when an attachment is selected in the media modal.
* Gets the selected image information, and sets it within the control.
*/
select: function() {
// Get the attachment from the modal frame.
var node,
attachment = this.frame.state().get( 'selection' ).first().toJSON(),
device = wp.customize.previewedDevice.get(),
settings = this.setting();
// This is a hack to make the popup background work, I don't like this and need to find a better solution.
if ( this.id && this.id === 'header_popup_background' ) {
if ( device === 'tablet' || device === 'mobile' ) {
if ( undefined !== settings['desktop'] && undefined !== settings['desktop'].type && settings['desktop'].type === 'image' ) {
if ( undefined !== settings[device] && undefined !== settings[device].type && settings[device].type === 'image' ) {
// Leave this alone
} else {
device = 'desktop';
}
}
}
}
if ( undefined === this.params.attachment ) {
this.params.attachment = {};
}
if ( undefined === this.params.input_attrs.attachments ) {
this.params.input_attrs.attachments = {};
}
this.params.input_attrs.attachments[ device ] = attachment;
if ( undefined === settings[ device ] ) {
settings[ device ] = {};
}
if ( undefined === settings[ device ].image ) {
settings[ device ].image = {};
}
settings[ device ].image.url = attachment.url;
// Set the Customizer setting; the callback takes care of rendering.
let event = new CustomEvent( 'kadenceOpenMediaModal', {
'detail': true,
} );
document.dispatchEvent( event );
this.setting.set( {
...this.setting.get(),
...settings,
flag: ! this.setting.get().flag
} );
},
} );

View File

@@ -0,0 +1,112 @@
/* jshint esversion: 6 */
const { Component, Fragment } = wp.element;
import { isString } from "lodash";
import KadenceColorPicker from "../../common/color-picker";
import SwatchesControl from "../../common/swatches";
import {
getGradientWithColorAtPositionChanged,
getGradientWithColorStopAdded,
} from "./utils";
class KadenceGradientColorPicker extends Component {
constructor() {
super(...arguments);
this.state = {
color: this.props.color ? this.props.color : "",
alreadyInsertedPoint: false,
};
}
render() {
const getColorValue = () => {
let color;
const paletteIndex = this.state.color?.match(/\d+$/)?.[0] - 1;
if (
undefined !== this.state.color &&
"" !== this.state.color &&
null !== this.state.color &&
isString(this.state.color) &&
this.state.color.includes("palette")
) {
color = this.props.activePalette[paletteIndex]?.color;
} else {
color = this.state.color;
}
return color;
};
return (
<div className="kadence-background-color-wrap">
<KadenceColorPicker
color={getColorValue()}
onChangeComplete={(color) => {
let rgb = {
type: "rgba",
value: "",
};
if (undefined !== color.rgb) {
this.setState({ color: color.rgb });
rgb.value = color.rgb;
} else {
this.setState({ color: color.hex });
rgb.type = "literal";
rgb.value = color.hex;
}
//console.log( rgb );
let newGradient;
if (this.state.alreadyInsertedPoint) {
newGradient = getGradientWithColorAtPositionChanged(
this.props.gradientAST,
this.props.insertPosition,
rgb
);
} else {
newGradient = getGradientWithColorStopAdded(
this.props.gradientAST,
this.props.insertPosition,
rgb
);
this.setState({ alreadyInsertedPoint: true });
}
this.props.onChange(newGradient);
}}
/>
<SwatchesControl
colors={this.props.activePalette}
isPalette={
undefined !== this.state.color &&
"" !== this.state.color &&
isString(this.state.color) &&
this.state.color.includes("palette")
? this.state.color
: ""
}
onClick={(color, palette) => {
this.setState({ color: palette });
let rgb = {
type: "literal",
value: "var(--global-" + palette + ")",
};
let newGradient;
if (this.state.alreadyInsertedPoint) {
newGradient = getGradientWithColorAtPositionChanged(
this.props.gradientAST,
this.props.insertPosition,
rgb
);
} else {
newGradient = getGradientWithColorStopAdded(
this.props.gradientAST,
this.props.insertPosition,
rgb
);
this.setState({ alreadyInsertedPoint: true });
}
this.props.onChange(newGradient);
}}
/>
</div>
);
}
}
export default KadenceGradientColorPicker;

View File

@@ -0,0 +1,20 @@
export const INSERT_POINT_WIDTH = 23;
export const GRADIENT_MARKERS_WIDTH = 18;
export const MINIMUM_DISTANCE_BETWEEN_INSERTER_AND_MARKER =
( INSERT_POINT_WIDTH + GRADIENT_MARKERS_WIDTH ) / 2;
export const MINIMUM_ABSOLUTE_LEFT_POSITION = 5;
export const MINIMUM_DISTANCE_BETWEEN_POINTS = 0;
export const MINIMUM_DISTANCE_BETWEEN_INSERTER_AND_POINT = 10;
export const KEYBOARD_CONTROL_POINT_VARIATION = MINIMUM_DISTANCE_BETWEEN_INSERTER_AND_POINT;
export const MINIMUM_SIGNIFICANT_MOVE = 5;
export const DEFAULT_GRADIENT =
'linear-gradient(135deg, rgba(6, 147, 227, 1) 0%, rgb(155, 81, 224) 100%)';
export const COLOR_POPOVER_PROPS = {
className: 'components-custom-gradient-picker__color-picker-popover kadence-popover-color',
position: 'top',
};
export const DEFAULT_LINEAR_GRADIENT_ANGLE = 180;
export const HORIZONTAL_GRADIENT_ORIENTATION = {
type: 'angular',
value: 90,
};

View File

@@ -0,0 +1,298 @@
/**
* External dependencies
*/
import classnames from 'classnames';
/**
* WordPress dependencies
*/
const {
useRef,
Component,
useEffect,
} = wp.element;
import { __, sprintf } from '@wordpress/i18n';
const {
useInstanceId,
} = wp.compose;
import KadenceGradientColorPicker from './edit-color-picker';
/**
* Internal dependencies
*/
const {
Button,
ColorPicker,
Dropdown,
VisuallyHidden,
KeyboardShortcuts,
} = wp.components;
import {
getGradientWithColorAtIndexChanged,
getGradientWithControlPointRemoved,
getGradientWithPositionAtIndexChanged,
getGradientWithPositionAtIndexDecreased,
getGradientWithPositionAtIndexIncreased,
getHorizontalRelativeGradientPosition,
isControlPointOverlapping,
} from './utils';
import {
COLOR_POPOVER_PROPS,
GRADIENT_MARKERS_WIDTH,
MINIMUM_SIGNIFICANT_MOVE,
} from './constants';
class ControlPointKeyboardMove extends Component {
constructor() {
super( ...arguments );
this.increase = this.increase.bind( this );
this.decrease = this.decrease.bind( this );
this.shortcuts = {
right: this.increase,
left: this.decrease,
};
}
increase( event ) {
// Stop propagation of the key press event to avoid focus moving
// to another editor area.
event.stopPropagation();
const { gradientIndex, onChange, gradientAST } = this.props;
onChange(
getGradientWithPositionAtIndexIncreased(
gradientAST,
gradientIndex
)
);
}
decrease( event ) {
// Stop propagation of the key press event to avoid focus moving
// to another editor area.
event.stopPropagation();
const { gradientIndex, onChange, gradientAST } = this.props;
onChange(
getGradientWithPositionAtIndexDecreased(
gradientAST,
gradientIndex
)
);
}
render() {
const { children } = this.props;
return (
<KeyboardShortcuts shortcuts={ this.shortcuts }>
{ children }
</KeyboardShortcuts>
);
}
}
function ControlPointButton( {
isOpen,
position,
color,
onChange,
gradientIndex,
gradientAST,
...additionalProps
} ) {
const instanceId = useInstanceId( ControlPointButton );
const descriptionId = `components-custom-gradient-picker__control-point-button-description-${ instanceId }`;
return (
<ControlPointKeyboardMove
onChange={ onChange }
gradientIndex={ gradientIndex }
gradientAST={ gradientAST }
>
<Button
aria-label={ sprintf(
// translators: %1$s: gradient position e.g: 70%, %2$s: gradient color code e.g: rgb(52,121,151).
__(
'Gradient control point at position %1$s with color code %2$s.'
),
position,
color
) }
aria-describedby={ descriptionId }
aria-haspopup="true"
aria-expanded={ isOpen }
className={ classnames(
'components-custom-gradient-picker__control-point-button',
{
'is-active': isOpen,
}
) }
style={ {
left: position,
} }
{ ...additionalProps }
/>
<VisuallyHidden id={ descriptionId }>
{ __(
'Use your left or right arrow keys or drag and drop with the mouse to change the gradient position. Press the button to change the color or remove the control point.'
) }
</VisuallyHidden>
</ControlPointKeyboardMove>
);
}
export default function ControlPoints( {
gradientPickerDomRef,
ignoreMarkerPosition,
markerPoints,
onChange,
gradientAST,
activePalette,
onStartControlPointChange,
onStopControlPointChange,
} ) {
const controlPointMoveState = useRef();
const onMouseMove = ( event ) => {
const relativePosition = getHorizontalRelativeGradientPosition(
event.clientX,
gradientPickerDomRef.current,
GRADIENT_MARKERS_WIDTH
);
const {
gradientAST: referenceGradientAST,
position,
significantMoveHappened,
} = controlPointMoveState.current;
if ( ! significantMoveHappened ) {
const initialPosition =
referenceGradientAST.colorStops[ position ].length.value;
if (
Math.abs( initialPosition - relativePosition ) >=
MINIMUM_SIGNIFICANT_MOVE
) {
controlPointMoveState.current.significantMoveHappened = true;
}
}
if (
! isControlPointOverlapping(
referenceGradientAST,
relativePosition,
position
)
) {
onChange(
getGradientWithPositionAtIndexChanged(
referenceGradientAST,
position,
relativePosition
)
);
}
};
const cleanEventListeners = () => {
if (
window &&
window.removeEventListener &&
controlPointMoveState.current &&
controlPointMoveState.current.listenersActivated
) {
window.removeEventListener( 'mousemove', onMouseMove );
window.removeEventListener( 'mouseup', cleanEventListeners );
onStopControlPointChange();
controlPointMoveState.current.listenersActivated = false;
}
};
useEffect( () => {
return () => {
cleanEventListeners();
};
}, [] );
return markerPoints.map(
( point, index ) =>
point &&
ignoreMarkerPosition !== point.positionValue && (
<Dropdown
key={ index }
onClose={ onStopControlPointChange }
renderToggle={ ( { isOpen, onToggle } ) => (
<ControlPointButton
key={ index }
onClick={ () => {
if (
controlPointMoveState.current &&
controlPointMoveState.current
.significantMoveHappened
) {
return;
}
if ( isOpen ) {
onStopControlPointChange();
} else {
onStartControlPointChange();
}
onToggle();
} }
onMouseDown={ () => {
if ( window && window.addEventListener ) {
controlPointMoveState.current = {
gradientAST,
position: index,
significantMoveHappened: false,
listenersActivated: true,
};
onStartControlPointChange();
window.addEventListener(
'mousemove',
onMouseMove
);
window.addEventListener(
'mouseup',
cleanEventListeners
);
}
} }
isOpen={ isOpen }
position={ point.position }
color={ point.color }
onChange={ onChange }
gradientAST={ gradientAST }
gradientIndex={ index }
/>
) }
renderContent={ ( { onClose } ) => (
<>
<KadenceGradientColorPicker
color={ point.color }
activePalette={ activePalette }
onChange={ ( value ) => {
onChange(
getGradientWithColorAtIndexChanged(
gradientAST,
index,
value
)
);
} }
/>
<Button
className="components-custom-gradient-picker__remove-control-point"
onClick={ () => {
onChange(
getGradientWithControlPointRemoved(
gradientAST,
index
)
);
onClose();
} }
isLink
>
{ __( 'Remove Control Point' ) }
</Button>
</>
) }
popoverProps={ COLOR_POPOVER_PROPS }
/>
)
);
}

View File

@@ -0,0 +1,260 @@
/**
* External dependencies
*/
import { some } from 'lodash';
import classnames from 'classnames';
/**
* WordPress dependencies
*/
const {
useRef,
useReducer,
useState
} = wp.element;
import { plusCircle } from '@wordpress/icons';
/**
* Internal dependencies
*/
import {
Button,
Dropdown,
ColorPicker,
} from '@wordpress/components';
import KadenceGradientColorPicker from './color-picker';
import ControlPoints from './control-points';
import {
INSERT_POINT_WIDTH,
COLOR_POPOVER_PROPS,
MINIMUM_DISTANCE_BETWEEN_INSERTER_AND_POINT,
} from './constants';
import { serializeGradient } from './serializer';
import {
getGradientWithColorAtPositionChanged,
getGradientWithColorStopAdded,
getHorizontalRelativeGradientPosition,
getMarkerPoints,
getGradientParsed,
getLinearGradientRepresentationOfARadial,
} from './utils';
function InsertPoint( {
onChange,
gradientAST,
onOpenInserter,
onCloseInserter,
insertPosition,
activePalette,
} ) {
const [ alreadyInsertedPoint, setAlreadyInsertedPoint ] = useState( false );
return (
<Dropdown
className="components-custom-gradient-picker__inserter"
onClose={ () => {
onCloseInserter();
} }
renderToggle={ ( { isOpen, onToggle } ) => (
<Button
aria-expanded={ isOpen }
onClick={ () => {
if ( isOpen ) {
onCloseInserter();
} else {
setAlreadyInsertedPoint( false );
onOpenInserter();
}
onToggle();
} }
className="components-custom-gradient-picker__insert-point"
icon={ plusCircle }
style={ {
left:
insertPosition !== null
? `${ insertPosition }%`
: undefined,
} }
/>
) }
renderContent={ () => (
<KadenceGradientColorPicker
color={''}
onChange={ ( value ) => onChange( value ) }
activePalette={ activePalette }
gradientAST={ gradientAST }
insertPosition={ insertPosition }
/>
) }
popoverProps={ COLOR_POPOVER_PROPS }
/>
);
}
function customGradientBarReducer( state, action ) {
switch ( action.type ) {
case 'MOVE_INSERTER':
if ( state.id === 'IDLE' || state.id === 'MOVING_INSERTER' ) {
return {
id: 'MOVING_INSERTER',
insertPosition: action.insertPosition,
};
}
break;
case 'STOP_INSERTER_MOVE':
if ( state.id === 'MOVING_INSERTER' ) {
return {
id: 'IDLE',
};
}
break;
case 'OPEN_INSERTER':
if ( state.id === 'MOVING_INSERTER' ) {
return {
id: 'INSERTING_CONTROL_POINT',
insertPosition: state.insertPosition,
};
}
break;
case 'CLOSE_INSERTER':
if ( state.id === 'INSERTING_CONTROL_POINT' ) {
return {
id: 'IDLE',
};
}
break;
case 'START_CONTROL_CHANGE':
if ( state.id === 'IDLE' ) {
return {
id: 'MOVING_CONTROL_POINT',
};
}
break;
case 'STOP_CONTROL_CHANGE':
if ( state.id === 'MOVING_CONTROL_POINT' ) {
return {
id: 'IDLE',
};
}
break;
}
return state;
}
const customGradientBarReducerInitialState = { id: 'IDLE' };
export default function CustomGradientBar( { value, onChange, activePalette } ) {
const { gradientAST, gradientValue, hasGradient } = getGradientParsed(
value
);
const onGradientStructureChange = ( newGradientStructure ) => {
onChange( serializeGradient( newGradientStructure ) );
};
const gradientPickerDomRef = useRef();
const markerPoints = getMarkerPoints( gradientAST );
const [ gradientBarState, gradientBarStateDispatch ] = useReducer(
customGradientBarReducer,
customGradientBarReducerInitialState
);
const onMouseEnterAndMove = ( event ) => {
const insertPosition = getHorizontalRelativeGradientPosition(
event.clientX,
gradientPickerDomRef.current,
INSERT_POINT_WIDTH
);
// If the insert point is close to an existing control point don't show it.
if (
some( markerPoints, ( { positionValue } ) => {
return (
Math.abs( insertPosition - positionValue ) <
MINIMUM_DISTANCE_BETWEEN_INSERTER_AND_POINT
);
} )
) {
if ( gradientBarState.id === 'MOVING_INSERTER' ) {
gradientBarStateDispatch( { type: 'STOP_INSERTER_MOVE' } );
}
return;
}
gradientBarStateDispatch( { type: 'MOVE_INSERTER', insertPosition } );
};
const onMouseLeave = () => {
gradientBarStateDispatch( { type: 'STOP_INSERTER_MOVE' } );
};
const isMovingInserter = gradientBarState.id === 'MOVING_INSERTER';
const isInsertingControlPoint =
gradientBarState.id === 'INSERTING_CONTROL_POINT';
return (
<div
ref={ gradientPickerDomRef }
className={ classnames(
'components-custom-gradient-picker__gradient-bar',
{ 'has-gradient': hasGradient }
) }
onMouseEnter={ onMouseEnterAndMove }
onMouseMove={ onMouseEnterAndMove }
// On radial gradients the bar should display a linear gradient.
// On radial gradients the bar represents a slice of the gradient from the center until the outside.
style={ {
background:
gradientAST.type === 'radial-gradient'
? getLinearGradientRepresentationOfARadial(
gradientAST
)
: gradientValue,
} }
onMouseLeave={ onMouseLeave }
>
<div className="components-custom-gradient-picker__markers-container">
{ ( isMovingInserter || isInsertingControlPoint ) && (
<InsertPoint
insertPosition={ gradientBarState.insertPosition }
onChange={ onGradientStructureChange }
gradientAST={ gradientAST }
onOpenInserter={ () => {
gradientBarStateDispatch( {
type: 'OPEN_INSERTER',
} );
} }
onCloseInserter={ () => {
gradientBarStateDispatch( {
type: 'CLOSE_INSERTER',
} );
} }
activePalette={ activePalette }
/>
) }
<ControlPoints
gradientPickerDomRef={ gradientPickerDomRef }
ignoreMarkerPosition={
isInsertingControlPoint
? gradientBarState.insertPosition
: undefined
}
markerPoints={ markerPoints }
onChange={ onGradientStructureChange }
gradientAST={ gradientAST }
onStartControlPointChange={ () => {
gradientBarStateDispatch( {
type: 'START_CONTROL_CHANGE',
} );
} }
onStopControlPointChange={ () => {
gradientBarStateDispatch( {
type: 'STOP_CONTROL_CHANGE',
} );
} }
activePalette={ activePalette }
/>
</div>
</div>
);
}

View File

@@ -0,0 +1,340 @@
// Copyright (c) 2014 Rafael Caricio. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
export default function CustomGradientParser( code ) {
var tokens = {
linearGradient: /^(\-(webkit|o|ms|moz)\-)?(linear\-gradient)/i,
repeatingLinearGradient: /^(\-(webkit|o|ms|moz)\-)?(repeating\-linear\-gradient)/i,
radialGradient: /^(\-(webkit|o|ms|moz)\-)?(radial\-gradient)/i,
repeatingRadialGradient: /^(\-(webkit|o|ms|moz)\-)?(repeating\-radial\-gradient)/i,
sideOrCorner: /^to (left (top|bottom)|right (top|bottom)|left|right|top|bottom)/i,
extentKeywords: /^(closest\-side|closest\-corner|farthest\-side|farthest\-corner|contain|cover)/,
positionKeywords: /^(left|center|right|top|bottom)/i,
pixelValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))px/,
percentageValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))\%/,
emValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))em/,
angleValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))deg/,
startCall: /^\(/,
endCall: /^\)/,
comma: /^,/,
hexColor: /^\#([0-9a-fA-F]+)/,
literalColor: /^([a-zA-Z]+)/,
varColor: /^var([0-9a-zA-Z\\)\\(-]+)/,
rgbColor: /^rgb/i,
rgbaColor: /^rgba/i,
number: /^(([0-9]*\.[0-9]+)|([0-9]+\.?))/
};
var input = code.toString();
function error(msg) {
var err = new Error(input + ': ' + msg);
err.source = input;
throw err;
}
function getAST() {
var ast = matchListDefinitions();
if (input.length > 0) {
error('Invalid input not EOF');
}
return ast;
}
function matchListDefinitions() {
return matchListing(matchDefinition);
}
function matchDefinition() {
return matchGradient(
'linear-gradient',
tokens.linearGradient,
matchLinearOrientation) ||
matchGradient(
'repeating-linear-gradient',
tokens.repeatingLinearGradient,
matchLinearOrientation) ||
matchGradient(
'radial-gradient',
tokens.radialGradient,
matchListRadialOrientations) ||
matchGradient(
'repeating-radial-gradient',
tokens.repeatingRadialGradient,
matchListRadialOrientations);
}
function matchGradient(gradientType, pattern, orientationMatcher) {
return matchCall(pattern, function(captures) {
var orientation = orientationMatcher();
if (orientation) {
if (!scan(tokens.comma)) {
error('Missing comma before color stops');
}
}
return {
type: gradientType,
orientation: orientation,
colorStops: matchListing(matchColorStop)
};
});
}
function matchCall(pattern, callback) {
var captures = scan(pattern);
if (captures) {
if (!scan(tokens.startCall)) {
error('Missing (');
}
var result = callback(captures);
if (!scan(tokens.endCall)) {
error('Missing )');
}
return result;
}
}
function matchLinearOrientation() {
return matchSideOrCorner() ||
matchAngle();
}
function matchSideOrCorner() {
return match('directional', tokens.sideOrCorner, 1);
}
function matchAngle() {
return match('angular', tokens.angleValue, 1);
}
function matchListRadialOrientations() {
var radialOrientations,
radialOrientation = matchRadialOrientation(),
lookaheadCache;
if (radialOrientation) {
radialOrientations = [];
radialOrientations.push(radialOrientation);
lookaheadCache = input;
if (scan(tokens.comma)) {
radialOrientation = matchRadialOrientation();
if (radialOrientation) {
radialOrientations.push(radialOrientation);
} else {
input = lookaheadCache;
}
}
}
return radialOrientations;
}
function matchRadialOrientation() {
var radialType = matchCircle() ||
matchEllipse();
if (radialType) {
radialType.at = matchAtPosition();
} else {
var extent = matchExtentKeyword();
if (extent) {
radialType = extent;
var positionAt = matchAtPosition();
if (positionAt) {
radialType.at = positionAt;
}
} else {
var defaultPosition = matchPositioning();
if (defaultPosition) {
radialType = {
type: 'default-radial',
at: defaultPosition
};
}
}
}
return radialType;
}
function matchCircle() {
var circle = match('shape', /^(circle)/i, 0);
if (circle) {
circle.style = matchLength() || matchExtentKeyword();
}
return circle;
}
function matchEllipse() {
var ellipse = match('shape', /^(ellipse)/i, 0);
if (ellipse) {
ellipse.style = matchDistance() || matchExtentKeyword();
}
return ellipse;
}
function matchExtentKeyword() {
return match('extent-keyword', tokens.extentKeywords, 1);
}
function matchAtPosition() {
if (match('position', /^at/, 0)) {
var positioning = matchPositioning();
if (!positioning) {
error('Missing positioning value');
}
return positioning;
}
}
function matchPositioning() {
var location = matchCoordinates();
if (location.x || location.y) {
return {
type: 'position',
value: location
};
}
}
function matchCoordinates() {
return {
x: matchDistance(),
y: matchDistance()
};
}
function matchListing(matcher) {
var captures = matcher(),
result = [];
if (captures) {
result.push(captures);
while (scan(tokens.comma)) {
captures = matcher();
if (captures) {
result.push(captures);
} else {
error('One extra comma');
}
}
}
return result;
}
function matchColorStop() {
var color = matchColor();
if (!color) {
error('Expected color definition');
}
color.length = matchDistance();
return color;
}
function matchColor() {
return matchHexColor() ||
matchVarColor() ||
matchRGBAColor() ||
matchRGBColor() ||
matchLiteralColor();
}
function matchLiteralColor() {
return match('literal', tokens.literalColor, 0);
}
function matchVarColor() {
return match('literal', tokens.varColor, 0);
}
function matchHexColor() {
return match('hex', tokens.hexColor, 1);
}
function matchRGBColor() {
return matchCall(tokens.rgbColor, function() {
return {
type: 'rgb',
value: matchListing(matchNumber)
};
});
}
function matchRGBAColor() {
return matchCall(tokens.rgbaColor, function() {
return {
type: 'rgba',
value: matchListing(matchNumber)
};
});
}
function matchNumber() {
return scan(tokens.number)[1];
}
function matchDistance() {
return match('%', tokens.percentageValue, 1) ||
matchPositionKeyword() ||
matchLength();
}
function matchPositionKeyword() {
return match('position-keyword', tokens.positionKeywords, 1);
}
function matchLength() {
return match('px', tokens.pixelValue, 1) ||
match('em', tokens.emValue, 1);
}
function match(type, pattern, captureIndex) {
var captures = scan(pattern);
if (captures) {
return {
type: type,
value: captures[captureIndex]
};
}
}
function scan(regexp) {
var captures,
blankCaptures;
blankCaptures = /^[\n\r\t\s]+/.exec(input);
if (blankCaptures) {
consume(blankCaptures[0].length);
}
captures = regexp.exec(input);
if (captures) {
consume(captures[0].length);
}
return captures;
}
function consume(size) {
input = input.substr(size);
}
return getAST();
}

View File

@@ -0,0 +1,79 @@
/* jshint esversion: 6 */
const { Component, Fragment } = wp.element;
import { isString } from "lodash";
import KadenceColorPicker from "../../common/color-picker";
import SwatchesControl from "../../common/swatches";
class KadenceGradientColorPicker extends Component {
constructor() {
super(...arguments);
this.state = {
color: this.props.color ? this.props.color : "",
};
}
render() {
const getColorValue = () => {
let color;
const paletteIndex = this.state.color?.match(/\d+$/)?.[0] - 1;
if (
undefined !== this.state.color &&
"" !== this.state.color &&
isString(this.state.color) &&
this.state.color.includes("palette") &&
this.props.activePalette &&
this.props.activePalette[paletteIndex]
) {
color = this.props.activePalette[paletteIndex]?.color;
} else {
color = this.state.color;
}
return color;
};
return (
<div className="kadence-background-color-wrap">
<KadenceColorPicker
color={getColorValue()}
onChangeComplete={(color) => {
let rgb = {
type: "rgba",
value: "",
};
if (undefined !== color.rgb) {
this.setState({ color: color.rgb });
rgb.value = color.rgb;
} else {
this.setState({ color: color.hex });
rgb.type = "literal";
rgb.value = color.hex;
}
this.props.onChange(rgb);
}}
/>
<SwatchesControl
colors={this.props.activePalette}
isPalette={
undefined !== this.state.color &&
"" !== this.state.color &&
isString(this.state.color) &&
this.state.color.includes("palette")
? this.state.color
: ""
}
onClick={(color, palette) => {
this.setState({
color: "var(--global-" + palette + ")",
});
let rgb = {
type: "literal",
value: "var(--global-" + palette + ")",
};
this.props.onChange(rgb);
}}
/>
</div>
);
}
}
export default KadenceGradientColorPicker;

View File

@@ -0,0 +1,72 @@
/**
* WordPress dependencies
*/
import { withInstanceId } from '@wordpress/compose';
import {
Circle,
LinearGradient,
Path,
RadialGradient,
Stop,
SVG,
} from '@wordpress/primitives';
/**
* Internal dependencies
*/
export const LinearGradientIcon = withInstanceId( ( { instanceId } ) => {
const linerGradientId = `linear-gradient-${ instanceId }`;
return (
<SVG
fill="none"
height="20"
viewBox="0 0 20 20"
width="20"
xmlns="http://www.w3.org/2000/svg"
>
<LinearGradient
id={ linerGradientId }
gradientUnits="userSpaceOnUse"
x1="10"
x2="10"
y1="1"
y2="19"
>
<Stop offset="0" stopColor="#000000" />
<Stop offset="1" stopColor="#ffffff" />
</LinearGradient>
<Path d="m1 1h18v18h-18z" fill={ `url(#${ linerGradientId })` } />
</SVG>
);
} );
export const RadialGradientIcon = withInstanceId( ( { instanceId } ) => {
const radialGradientId = `radial-gradient-${ instanceId }`;
return (
<SVG
fill="none"
height="20"
viewBox="0 0 20 20"
width="20"
xmlns="http://www.w3.org/2000/svg"
>
<RadialGradient
id={ radialGradientId }
cx="0"
cy="0"
gradientTransform="matrix(0 9 -9 0 10 10)"
gradientUnits="userSpaceOnUse"
r="1"
>
<Stop offset="0" stopColor="#000000" />
<Stop offset="1" stopColor="#ffffff" />
</RadialGradient>
<Circle
cx="10"
cy="10"
fill={ `url(#${ radialGradientId })` }
r="9"
/>
</SVG>
);
} );

View File

@@ -0,0 +1,123 @@
/**
* External dependencies
*/
import { get, omit } from 'lodash';
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import { LinearGradientIcon, RadialGradientIcon } from './icons';
import CustomGradientBar from './custom-gradient-bar';
import { getGradientParsed } from './utils';
import { serializeGradient } from './serializer';
import {
DEFAULT_LINEAR_GRADIENT_ANGLE,
HORIZONTAL_GRADIENT_ORIENTATION,
} from './constants';
const {
ToolbarGroup,
AnglePickerControl,
BaseControl,
} = wp.components;
const GradientAnglePicker = ( { gradientAST, hasGradient, onChange } ) => {
const angle = get(
gradientAST,
[ 'orientation', 'value' ],
DEFAULT_LINEAR_GRADIENT_ANGLE
);
const onAngleChange = ( newAngle ) => {
onChange(
serializeGradient( {
...gradientAST,
orientation: {
type: 'angular',
value: newAngle,
},
} )
);
};
return (
<AnglePickerControl
value={ hasGradient ? angle : '' }
onChange={ onAngleChange }
/>
);
};
const GradientTypePicker = ( { gradientAST, hasGradient, onChange } ) => {
const { type } = gradientAST;
const onSetLinearGradient = () => {
onChange(
serializeGradient( {
...gradientAST,
...( gradientAST.orientation
? {}
: { orientation: HORIZONTAL_GRADIENT_ORIENTATION } ),
type: 'linear-gradient',
} )
);
};
const onSetRadialGradient = () => {
onChange(
serializeGradient( {
...omit( gradientAST, [ 'orientation' ] ),
type: 'radial-gradient',
} )
);
};
return (
<BaseControl className="components-custom-gradient-picker__type-picker">
<BaseControl.VisualLabel>{ __( 'Type' ) }</BaseControl.VisualLabel>
<ToolbarGroup
className="components-custom-gradient-picker__toolbar"
controls={ [
{
icon: <LinearGradientIcon />,
title: __( 'Linear Gradient' ),
isActive: hasGradient && type === 'linear-gradient',
onClick: onSetLinearGradient,
},
{
icon: <RadialGradientIcon />,
title: __( 'Radial Gradient' ),
isActive: hasGradient && type === 'radial-gradient',
onClick: onSetRadialGradient,
},
] }
/>
</BaseControl>
);
};
export default function CustomGradientPicker( { value, onChange, activePalette } ) {
const { gradientAST, hasGradient } = getGradientParsed( value );
const { type } = gradientAST;
return (
<div className="components-custom-gradient-picker">
<CustomGradientBar value={ value } onChange={ onChange } activePalette={ activePalette } />
<div className="components-custom-gradient-picker__ui-line">
<GradientTypePicker
gradientAST={ gradientAST }
hasGradient={ hasGradient }
onChange={ onChange }
/>
{ type === 'linear-gradient' && (
<GradientAnglePicker
gradientAST={ gradientAST }
hasGradient={ hasGradient }
onChange={ onChange }
/>
) }
</div>
</div>
);
}

View File

@@ -0,0 +1,115 @@
/**
* External dependencies
*/
import { get, omit } from 'lodash';
/**
* WordPress dependencies
*/
import { PanelBody, RadioControl, RangeControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useState } from '@wordpress/element';
/**
* Internal dependencies
*/
import { colorsUtils } from '../mobile/color-settings/utils';
import { performLayoutAnimation } from '../mobile/layout-animation';
import { getGradientParsed } from './utils';
import { serializeGradient } from './serializer';
import {
DEFAULT_LINEAR_GRADIENT_ANGLE,
HORIZONTAL_GRADIENT_ORIENTATION,
} from './constants';
import styles from './style.scss';
function CustomGradientPicker( { currentValue, setColor, isGradientColor } ) {
const [ gradientOrientation, setGradientOrientation ] = useState(
HORIZONTAL_GRADIENT_ORIENTATION
);
const { getGradientType, gradients, gradientOptions } = colorsUtils;
const { gradientAST } = getGradientParsed( currentValue );
const gradientType = getGradientType( currentValue );
function isLinearGradient( type ) {
return type === gradients.linear;
}
function getGradientColor( type ) {
const orientation = get( gradientAST, [ 'orientation' ] );
if ( orientation ) {
setGradientOrientation( orientation );
}
return serializeGradient(
isLinearGradient( type )
? {
...gradientAST,
...( gradientAST.orientation
? {}
: {
orientation: gradientOrientation,
} ),
type,
}
: {
...omit( gradientAST, [ 'orientation' ] ),
type,
}
);
}
function onGradientTypeChange( type ) {
const gradientColor = getGradientColor( type );
performLayoutAnimation();
setColor( gradientColor );
}
function setGradientAngle( value ) {
const gradientColor = serializeGradient( {
...gradientAST,
orientation: {
type: 'angular',
value,
},
} );
if ( isGradientColor && gradientColor !== currentValue ) {
setColor( gradientColor );
}
}
function getGradientAngle() {
return get(
gradientAST,
[ 'orientation', 'value' ],
DEFAULT_LINEAR_GRADIENT_ANGLE
);
}
return (
<>
<PanelBody title={ __( 'Gradient Type' ) }>
<RadioControl
selected={ gradientType }
options={ gradientOptions }
onChange={ onGradientTypeChange }
/>
</PanelBody>
{ isLinearGradient( gradientType ) && (
<PanelBody style={ styles.angleControl }>
<RangeControl
label={ __( 'Angle' ) }
minimumValue={ 0 }
maximumValue={ 360 }
value={ getGradientAngle() }
onChange={ setGradientAngle }
/>
</PanelBody>
) }
</>
);
}
export default CustomGradientPicker;

View File

@@ -0,0 +1,53 @@
/**
* External dependencies
*/
import { compact, get } from 'lodash';
export function serializeGradientColor( { type, value } ) {
if ( type === 'literal' || type === 'hex' ) {
return value;
}
return `${ type }(${ value.join( ',' ) })`;
}
export function serializeGradientPosition( { type, value } ) {
return `${ value }${ type }`;
}
export function serializeGradientColorStop( { type, value, length } ) {
return `${ serializeGradientColor( {
type,
value,
} ) } ${ serializeGradientPosition( length ) }`;
}
export function serializeGradientOrientation( orientation ) {
if ( ! orientation || orientation.type !== 'angular' ) {
return;
}
return `${ orientation.value }deg`;
}
export function serializeGradient( { type, orientation, colorStops } ) {
const serializedOrientation = serializeGradientOrientation( orientation );
//console.log( colorStops );
const serializedColorStops = colorStops
.sort( ( colorStop1, colorStop2 ) => {
return (
get( colorStop1, [ 'length', 'value' ], 0 ) -
get( colorStop2, [ 'length', 'value' ], 0 )
);
} )
.map( serializeGradientColorStop );
// console.log(`${ type }(${ compact( [
// serializedOrientation,
// ...serializedColorStops,
// ] ).join( ',' ) })`);
return `${ type }(${ compact( [
serializedOrientation,
...serializedColorStops,
] ).join( ',' ) })`;
}

View File

@@ -0,0 +1,3 @@
.angleControl {
padding-top: (if(variable-exists(grid-unit-20), $grid-unit-20, 20px) / 2);
}

View File

@@ -0,0 +1,110 @@
@use 'sass:meta';
$components-custom-gradient-picker__padding: 3px; // 24px container, 18px handles inside, that leaves 6px padding, half of which is 3.
.components-custom-gradient-picker {
margin-top: (if(meta.variable-exists(grid-unit-10), $grid-unit-10, 10px));
}
.components-custom-gradient-picker__gradient-bar:not(.has-gradient) {
opacity: 0.4;
}
$button-size-small: 24px;
$white: #fff;
.components-custom-gradient-picker__gradient-bar {
width: 100%;
height: $button-size-small;
border-radius: $button-size-small;
margin-bottom: (if(meta.variable-exists(grid-unit-10), $grid-unit-10, 10px));
padding-left: $components-custom-gradient-picker__padding;
padding-right: $button-size-small - $components-custom-gradient-picker__padding;
.components-custom-gradient-picker__markers-container {
position: relative;
}
.components-custom-gradient-picker__insert-point {
border-radius: 50%;
background: $white;
padding: 2px;
min-width: $button-size-small;
width: $button-size-small;
height: $button-size-small;
position: relative;
svg {
height: 100%;
width: 100%;
}
}
.components-custom-gradient-picker__control-point-button {
border: 2px solid $white;
border-radius: 50%;
height: 18px;
padding: 0;
position: absolute;
width: 18px;
top: $components-custom-gradient-picker__padding;
&.is-active {
background: #fafafa;
color: #23282d;
border-color: #999;
box-shadow:
0 0 0 1px $white,
0 0 0 3px var(--wp-admin-theme-color);
}
}
}
.components-custom-gradient-picker__color-picker-popover .components-custom-gradient-picker__remove-control-point {
margin-left: auto;
margin-right: auto;
display: block;
margin-bottom: 8px;
}
.components-custom-gradient-picker__inserter {
width: 100%;
}
.components-custom-gradient-picker__liner-gradient-indicator {
display: inline-block;
flex: 0 auto;
width: 20px;
height: 20px;
}
.components-custom-gradient-picker__ui-line {
display: flex;
justify-content: space-between;
}
.components-custom-gradient-picker .components-custom-gradient-picker__ui-line {
.components-base-control.components-angle-picker,
.components-base-control.components-custom-gradient-picker__type-picker {
margin-bottom: 0;
}
}
.components-custom-gradient-picker .components-custom-gradient-picker__toolbar {
border: none;
// Work-around to target the inner button containers rendered by <ToolbarGroup />
> div + div {
margin-left: 1px;
}
button {
&.is-pressed {
$dark-gray-200: #999;
> svg {
background: $white;
border: 1px solid $dark-gray-200;
border-radius: 2px;
}
}
}
}

View File

@@ -0,0 +1,106 @@
/**
* External dependencies
*/
import classnames from 'classnames';
import { flatMap } from 'lodash';
/**
* WordPress dependencies
*/
import { useContext } from '@wordpress/element';
/**
* Internal dependencies
*/
import ToolbarButton from '../toolbar-button';
import ToolbarGroupCollapsed from './toolbar-group-collapsed';
import ToolbarContext from '../toolbar-context';
const ToolbarGroupContainer = ( { className, children, ...props } ) => (
<div className={ className } { ...props }>
{ children }
</div>
);
/**
* Renders a collapsible group of controls
*
* The `controls` prop accepts an array of sets. A set is an array of controls.
* Controls have the following shape:
*
* ```
* {
* icon: string,
* title: string,
* subscript: string,
* onClick: Function,
* isActive: boolean,
* isDisabled: boolean
* }
* ```
*
* For convenience it is also possible to pass only an array of controls. It is
* then assumed this is the only set.
*
* Either `controls` or `children` is required, otherwise this components
* renders nothing.
*
* @param {Object} props Component props.
* @param {Array} [props.controls] The controls to render in this toolbar.
* @param {WPElement} [props.children] Any other things to render inside the toolbar besides the controls.
* @param {string} [props.className] Class to set on the container div.
* @param {boolean} [props.isCollapsed] Turns ToolbarGroup into a dropdown menu.
* @param {string} [props.title] ARIA label for dropdown menu if is collapsed.
*/
function ToolbarGroup( {
controls = [],
children,
className,
isCollapsed,
title,
...props
} ) {
// It'll contain state if `ToolbarGroup` is being used within
// `<Toolbar accessibilityLabel="label" />`
const accessibleToolbarState = useContext( ToolbarContext );
if ( ( ! controls || ! controls.length ) && ! children ) {
return null;
}
const finalClassName = classnames(
// Unfortunately, there's legacy code referencing to `.components-toolbar`
// So we can't get rid of it
accessibleToolbarState
? 'components-toolbar-group'
: 'components-toolbar',
className
);
// Normalize controls to nested array of objects (sets of controls)
let controlSets = controls;
if ( ! Array.isArray( controlSets[ 0 ] ) ) {
controlSets = [ controlSets ];
}
return (
<ToolbarGroupContainer className={ finalClassName } { ...props }>
{ flatMap( controlSets, ( controlSet, indexOfSet ) =>
controlSet.map( ( control, indexOfControl ) => (
<ToolbarButton
key={ [ indexOfSet, indexOfControl ].join() }
containerClassName={
indexOfSet > 0 && indexOfControl === 0
? 'has-left-divider'
: null
}
{ ...control }
/>
) )
) }
{ children }
</ToolbarGroupContainer>
);
}
export default ToolbarGroup;

View File

@@ -0,0 +1,296 @@
/**
* External dependencies
*/
import { findIndex, map, some } from 'lodash';
import gradientParser from 'gradient-parser';
import CustomGradientParser from './custom-parser';
/**
* Internal dependencies
*/
import {
DEFAULT_GRADIENT,
INSERT_POINT_WIDTH,
MINIMUM_ABSOLUTE_LEFT_POSITION,
MINIMUM_DISTANCE_BETWEEN_POINTS,
KEYBOARD_CONTROL_POINT_VARIATION,
HORIZONTAL_GRADIENT_ORIENTATION,
} from './constants';
import {
serializeGradientColor,
serializeGradientPosition,
serializeGradient,
} from './serializer';
function tinyColorRgbToGradientColorStop( { type, value } ) {
//console.log( type );
//console.log( value );
if ( type === 'literal' ) {
return {
type: 'literal',
value: value,
};
} else if ( type === 'rgb' ) {
return {
type: 'rgb',
value: [ value.r, value.g, value.b ],
};
}
return {
type: 'rgba',
value: [ value.r, value.g, value.b, value.a ],
};
}
export function getGradientWithColorStopAdded(
gradientAST,
relativePosition,
rgbaColor
) {
const colorStop = tinyColorRgbToGradientColorStop( rgbaColor );
colorStop.length = {
type: '%',
value: relativePosition,
};
return {
...gradientAST,
colorStops: [ ...gradientAST.colorStops, colorStop ],
};
}
export function getGradientWithPositionAtIndexChanged(
gradientAST,
index,
relativePosition
) {
return {
...gradientAST,
colorStops: gradientAST.colorStops.map(
( colorStop, colorStopIndex ) => {
if ( colorStopIndex !== index ) {
return colorStop;
}
return {
...colorStop,
length: {
...colorStop.length,
value: relativePosition,
},
};
}
),
};
}
export function isControlPointOverlapping(
gradientAST,
position,
initialIndex
) {
const initialPosition = parseInt(
gradientAST.colorStops[ initialIndex ].length.value
);
const minPosition = Math.min( initialPosition, position );
const maxPosition = Math.max( initialPosition, position );
return some( gradientAST.colorStops, ( { length }, index ) => {
const itemPosition = parseInt( length.value );
return (
index !== initialIndex &&
( Math.abs( itemPosition - position ) <
MINIMUM_DISTANCE_BETWEEN_POINTS ||
( minPosition < itemPosition && itemPosition < maxPosition ) )
);
} );
}
function getGradientWithPositionAtIndexSummed(
gradientAST,
index,
valueToSum
) {
const currentPosition = gradientAST.colorStops[ index ].length.value;
const newPosition = Math.max(
0,
Math.min( 100, parseInt( currentPosition ) + valueToSum )
);
if ( isControlPointOverlapping( gradientAST, newPosition, index ) ) {
return gradientAST;
}
return getGradientWithPositionAtIndexChanged(
gradientAST,
index,
newPosition
);
}
export function getGradientWithPositionAtIndexIncreased( gradientAST, index ) {
return getGradientWithPositionAtIndexSummed(
gradientAST,
index,
KEYBOARD_CONTROL_POINT_VARIATION
);
}
export function getGradientWithPositionAtIndexDecreased( gradientAST, index ) {
return getGradientWithPositionAtIndexSummed(
gradientAST,
index,
-KEYBOARD_CONTROL_POINT_VARIATION
);
}
export function getGradientWithColorAtIndexChanged(
gradientAST,
index,
rgbaColor
) {
return {
...gradientAST,
colorStops: gradientAST.colorStops.map(
( colorStop, colorStopIndex ) => {
if ( colorStopIndex !== index ) {
return colorStop;
}
return {
...colorStop,
...tinyColorRgbToGradientColorStop( rgbaColor ),
};
}
),
};
}
export function getGradientWithColorAtPositionChanged(
gradientAST,
relativePositionValue,
rgbaColor
) {
const index = findIndex( gradientAST.colorStops, ( colorStop ) => {
return (
colorStop &&
colorStop.length &&
colorStop.length.type === '%' &&
colorStop.length.value === relativePositionValue.toString()
);
} );
return getGradientWithColorAtIndexChanged( gradientAST, index, rgbaColor );
}
export function getGradientWithControlPointRemoved( gradientAST, index ) {
return {
...gradientAST,
colorStops: gradientAST.colorStops.filter( ( elem, elemIndex ) => {
return elemIndex !== index;
} ),
};
}
export function getHorizontalRelativeGradientPosition(
mouseXCoordinate,
containerElement,
positionedElementWidth
) {
if ( ! containerElement ) {
return;
}
const { x, width } = containerElement.getBoundingClientRect();
const absolutePositionValue =
mouseXCoordinate -
x -
MINIMUM_ABSOLUTE_LEFT_POSITION -
positionedElementWidth / 2;
const availableWidth =
width - MINIMUM_ABSOLUTE_LEFT_POSITION - INSERT_POINT_WIDTH;
return Math.round(
Math.min(
Math.max( ( absolutePositionValue * 100 ) / availableWidth, 0 ),
100
)
);
}
/**
* Returns the marker points from a gradient AST.
*
* @param {Object} gradientAST An object representing the gradient AST.
*
* @return {Array.<{color: string, position: string, positionValue: number}>}
* An array of markerPoint objects.
* color: A string with the color code ready to be used in css style e.g: "rgba( 1, 2 , 3, 0.5)".
* position: A string with the position ready to be used in css style e.g: "70%".
* positionValue: A number with the relative position value e.g: 70.
*/
export function getMarkerPoints( gradientAST ) {
if ( ! gradientAST ) {
return [];
}
return map( gradientAST.colorStops, ( colorStop ) => {
if (
! colorStop ||
! colorStop.length ||
colorStop.length.type !== '%'
) {
return null;
}
return {
color: serializeGradientColor( colorStop ),
position: serializeGradientPosition( colorStop.length ),
positionValue: parseInt( colorStop.length.value ),
};
} );
}
export function getLinearGradientRepresentationOfARadial( gradientAST ) {
return serializeGradient( {
type: 'linear-gradient',
orientation: HORIZONTAL_GRADIENT_ORIENTATION,
colorStops: gradientAST.colorStops,
} );
}
const DIRECTIONAL_ORIENTATION_ANGLE_MAP = {
top: 0,
'top right': 45,
'right top': 45,
right: 90,
'right bottom': 135,
'bottom right': 135,
bottom: 180,
'bottom left': 225,
'left bottom': 225,
left: 270,
'top left': 315,
'left top': 315,
};
export function getGradientParsed( value ) {
let hasGradient = !! value;
// gradientAST will contain the gradient AST as parsed by gradient-parser npm module.
// More information of its structure available at https://www.npmjs.com/package/gradient-parser#ast.
let gradientAST;
let gradientValue;
try {
gradientAST = CustomGradientParser( value || DEFAULT_GRADIENT )[ 0 ];
gradientValue = value || DEFAULT_GRADIENT;
} catch ( error ) {
hasGradient = false;
gradientAST = CustomGradientParser( DEFAULT_GRADIENT )[ 0 ];
gradientValue = DEFAULT_GRADIENT;
}
if (
gradientAST.orientation &&
gradientAST.orientation.type === 'directional'
) {
gradientAST.orientation.type = 'angular';
gradientAST.orientation.value = DIRECTIONAL_ORIENTATION_ANGLE_MAP[
gradientAST.orientation.value
].toString();
}
return {
hasGradient,
gradientAST,
gradientValue,
};
}

View File

@@ -0,0 +1,83 @@
/**
* External dependencies
*/
import { map } from 'lodash';
/**
* WordPress dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
const {
useCallback,
useMemo
} = wp.element;
const {
BaseControl
} = wp.components;
/**
* Internal dependencies
*/
import CircularOptionPicker from './circular-option-picker.js';
import CustomGradientPicker from './custom-gradient-picker';
export default function KadenceGradientPicker( {
className,
gradients,
onChange,
value,
clearable = true,
disableCustomGradients = false,
activePalette,
} ) {
const clearGradient = useCallback( () => onChange( undefined ), [
onChange,
] );
const gradientOptions = useMemo( () => {
return map( gradients, ( { gradient, name } ) => (
<CircularOptionPicker.Option
key={ gradient }
value={ gradient }
isSelected={ value === gradient }
tooltipText={
name ||
// translators: %s: gradient code e.g: "linear-gradient(90deg, rgba(98,16,153,1) 0%, rgba(172,110,22,1) 100%);".
sprintf( __( 'Gradient code: %s' ), gradient )
}
style={ { color: 'rgba( 0,0,0,0 )', background: gradient } }
onClick={
value === gradient
? clearGradient
: () => onChange( gradient )
}
aria-label={
name
? // translators: %s: The name of the gradient e.g: "Angular red to blue".
sprintf( __( 'Gradient: %s' ), name )
: // translators: %s: gradient code e.g: "linear-gradient(90deg, rgba(98,16,153,1) 0%, rgba(172,110,22,1) 100%);".
sprintf( __( 'Gradient code: %s' ), gradient )
}
/>
) );
}, [ gradients, value, onChange, clearGradient ] );
return (
<CircularOptionPicker
className={ className }
options={ gradientOptions }
actions={
clearable && (
<CircularOptionPicker.ButtonAction
onClick={ clearGradient }
>
{ __( 'Clear' ) }
</CircularOptionPicker.ButtonAction>
)
}
>
{ ! disableCustomGradients && (
<CustomGradientPicker value={ value } onChange={ onChange } activePalette={ activePalette } />
) }
</CircularOptionPicker>
);
}

View File

@@ -0,0 +1,190 @@
/**
* A dynamic control.
*
* @class
* @augments wp.customize.Control
* @augments wp.customize.Class
*/
export const baseControl = wp.customize.KadenceControl = wp.customize.Control.extend( {
initialize: function( id, options ) {
var control = this,
args = options || {};
args.params = args.params || {};
if ( ! args.params.type ) {
args.params.type = 'kadence-basic';
}
if ( ! args.params.content ) {
args.params.content = jQuery( '<li></li>' );
args.params.content.attr( 'id', 'customize-control-' + id.replace( /]/g, '' ).replace( /\[/g, '-' ) );
args.params.content.attr( 'class', 'customize-control customize-control-' + args.params.type );
}
control.propertyElements = [];
wp.customize.Control.prototype.initialize.call( control, id, args );
},
/**
* Add bidirectional data binding links between inputs and the setting(s).
*
* This is copied from wp.customize.Control.prototype.initialize(). It
* should be changed in Core to be applied once the control is embedded.
*
* @private
* @returns {null}
*/
_setUpSettingRootLinks: function() {
var control = this,
nodes = control.container.find( '[data-customize-setting-link]' );
nodes.each( function() {
var node = jQuery( this );
wp.customize( node.data( 'customizeSettingLink' ), function( setting ) {
var element = new wp.customize.Element( node );
control.elements.push( element );
element.sync( setting );
element.set( setting() );
} );
} );
},
/**
* Add bidirectional data binding links between inputs and the setting properties.
*
* @private
* @returns {null}
*/
_setUpSettingPropertyLinks: function() {
var control = this,
nodes;
if ( ! control.setting ) {
return;
}
nodes = control.container.find( '[data-customize-setting-property-link]' );
nodes.each( function() {
var node = jQuery( this ),
element,
propertyName = node.data( 'customizeSettingPropertyLink' );
element = new wp.customize.Element( node );
control.propertyElements.push( element );
element.set( control.setting()[ propertyName ] );
element.bind( function( newPropertyValue ) {
var newSetting = control.setting();
if ( newPropertyValue === newSetting[ propertyName ] ) {
return;
}
newSetting = _.clone( newSetting );
newSetting[ propertyName ] = newPropertyValue;
control.setting.set( newSetting );
} );
control.setting.bind( function( newValue ) {
if ( newValue[ propertyName ] !== element.get() ) {
element.set( newValue[ propertyName ] );
}
} );
} );
},
/**
* @inheritdoc
*/
ready: function() {
var control = this;
control._setUpSettingRootLinks();
control._setUpSettingPropertyLinks();
wp.customize.Control.prototype.ready.call( control );
control.deferred.embedded.done( function() {
} );
},
/**
* Embed the control in the document.
*
* Override the embed() method to do nothing,
* so that the control isn't embedded on load,
* unless the containing section is already expanded.
*
* @returns {null}
*/
embed: function() {
var control = this,
sectionId = control.section();
if ( ! sectionId ) {
return;
}
wp.customize.section( sectionId, function( section ) {
if ( section.expanded() || wp.customize.settings.autofocus.control === control.id ) {
control.actuallyEmbed();
} else {
section.expanded.bind( function( expanded ) {
if ( expanded ) {
control.actuallyEmbed();
}
} );
}
} );
},
/**
* Deferred embedding of control when actually
*
* This function is called in Section.onChangeExpanded() so the control
* will only get embedded when the Section is first expanded.
*
* @returns {null}
*/
actuallyEmbed: function() {
var control = this;
if ( 'resolved' === control.deferred.embedded.state() ) {
return;
}
control.renderContent();
control.deferred.embedded.resolve(); // This triggers control.ready().
// Fire event after control is initialized.
control.container.trigger( 'init' );
},
/**
* Returns a WP-style warning notice React element if a notice string is
* provided via input_attrs.notice, otherwise returns null.
* Call this inside any child component's render() to get universal notice support.
*
* @returns {wp.element.Element|null}
*/
renderNotice: function() {
var control = this;
if ( ! control.params.input_attrs || ! control.params.input_attrs.notice ) {
return null;
}
return wp.element.createElement(
'div',
{ className: 'notice notice-warning kadence-control-notice' },
wp.element.createElement( 'p', { dangerouslySetInnerHTML: { __html: control.params.input_attrs.notice } } )
);
},
/**
* This is not working with autofocus.
*
* @param {object} [args] Args.
* @returns {null}
*/
focus: function( args ) {
var control = this;
control.actuallyEmbed();
wp.customize.Control.prototype.focus.call( control, args );
},
} );

View File

@@ -0,0 +1,553 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import ResponsiveControl from '../common/responsive.js';
import ColorControl from '../common/color.js';
import Icons from '../common/icons.js';
import { __ } from '@wordpress/i18n';
const { ButtonGroup, Dashicon, Toolbar, ToolbarGroup, Tooltip, Button } = wp.components;
/**
* WordPress dependencies
*/
import { createRef, Component, Fragment } from '@wordpress/element';
class BorderComponent extends Component {
constructor() {
super( ...arguments );
this.updateValues = this.updateValues.bind( this );
this.resetValues = this.resetValues.bind( this );
this.handleChangeComplete = this.handleChangeComplete.bind( this );
this.handleResponsiveChangeComplete = this.handleResponsiveChangeComplete.bind( this );
this.getUnitButtons = this.getUnitButtons.bind( this );
this.getResponsiveUnitButtons = this.getResponsiveUnitButtons.bind( this );
this.createLevelControlToolbar = this.createLevelControlToolbar.bind( this );
this.createResponsiveLevelControlToolbar = this.createResponsiveLevelControlToolbar.bind( this );
this.getStyleButtons = this.getStyleButtons.bind( this );
this.getResponsiveStyleButtons = this.getResponsiveStyleButtons.bind( this );
this.createStyleControlToolbar = this.createStyleControlToolbar.bind( this );
this.createResponsiveStyleControlToolbar = this.createResponsiveStyleControlToolbar.bind( this );
let value = this.props.control.setting.get();
let defaultParams = {
min: {
px: '0',
em: '0',
rem: '0',
},
max: {
px: '300',
em: '12',
rem: '12',
},
step: {
px: '1',
em: '0.01',
rem: '0.01',
},
units: ['px', 'em', 'rem'],
styles: ['none', 'solid', 'dashed', 'dotted', 'double'],
responsive:true,
color:true,
};
this.controlParams = this.props.control.params.input_attrs ? {
...defaultParams,
...this.props.control.params.input_attrs,
} : defaultParams;
let responsiveDefault = {
'desktop': {
'width': '',
'unit': 'px',
'style': 'none',
'color': ( this.controlParams.color ? '' : 'currentColor' ),
}
};
let noneResponsiveDefault = {
'width': '',
'unit': 'px',
'style': 'none',
'color': ( this.controlParams.color ? '' : 'currentColor' ),
};
let baseDefault;
if ( this.controlParams.responsive ) {
baseDefault = responsiveDefault;
} else {
baseDefault = noneResponsiveDefault;
}
this.defaultValue = this.props.control.params.default ? {
...baseDefault,
...this.props.control.params.default
} : baseDefault;
value = value ? {
...JSON.parse( JSON.stringify( this.defaultValue ) ),
...value
} : JSON.parse( JSON.stringify( this.defaultValue ) );
this.state = {
currentDevice: 'desktop',
value: value,
};
this.anchorNodeRef = createRef();
}
handleResponsiveChangeComplete( color, isPalette, device ) {
let value = this.state.value;
if ( undefined === value[ device ] ) {
value[ device ] = {
'width': '',
'unit': '',
'style': '',
'color': '',
}
}
if ( isPalette ) {
value[ device ].color = isPalette;
} else if ( undefined !== color.rgb && undefined !== color.rgb.a && 1 !== color.rgb.a ) {
value[ device ].color = 'rgba(' + color.rgb.r + ',' + color.rgb.g + ',' + color.rgb.b + ',' + color.rgb.a + ')';
} else {
value[ device ].color = color.hex;
}
this.updateValues( value );
}
handleChangeComplete( color, isPalette ) {
let value = this.state.value;
if ( isPalette ) {
value.color = isPalette;
} else if ( undefined !== color.rgb && undefined !== color.rgb.a && 1 !== color.rgb.a ) {
value.color = 'rgba(' + color.rgb.r + ',' + color.rgb.g + ',' + color.rgb.b + ',' + color.rgb.a + ')';
} else {
value.color = color.hex;
}
this.updateValues( value );
}
render() {
const data = this.props.control.params;
let currentUnit;
if ( this.controlParams.responsive ) {
if ( undefined === this.state.value[ this.state.currentDevice ] ) {
let largerDevice = ( this.state.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice].unit ) {
currentUnit = this.state.value[largerDevice].unit;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].unit ) {
currentUnit = this.state.value['desktop'].unit;
}
} else if ( undefined === this.state.value[ this.state.currentDevice ].unit ) {
let largerDevice = ( this.state.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice].unit ) {
currentUnit = this.state.value[largerDevice].unit;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].unit ) {
currentUnit = this.state.value['desktop'].unit;
}
} else if ( '' === this.state.value[ this.state.currentDevice ].unit ) {
let largerDevice = ( this.state.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice].unit ) {
currentUnit = this.state.value[largerDevice].unit;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].unit ) {
currentUnit = this.state.value['desktop'].unit;
}
} else if ( '' !== this.state.value[ this.state.currentDevice ].unit ) {
currentUnit = this.state.value[ this.state.currentDevice ].unit
}
} else {
currentUnit = ( undefined !== this.state.value.unit ? this.state.value.unit : 'px' );
}
let currentStyle;
if ( this.controlParams.responsive ) {
if ( undefined === this.state.value[ this.state.currentDevice ] ) {
let largerDevice = ( this.state.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice]?.style ) {
currentStyle = this.state.value[largerDevice].style;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].style ) {
currentStyle = this.state.value['desktop'].style;
}
} else if ( undefined === this.state.value[ this.state.currentDevice ]?.style ) {
let largerDevice = ( this.state.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice]?.style ) {
currentStyle = this.state.value[largerDevice].style;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].style ) {
currentStyle = this.state.value['desktop'].style;
}
} else if ( '' === this.state.value[ this.state.currentDevice ]?.style ) {
let largerDevice = ( this.state.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice]?.style ) {
currentStyle = this.state.value[largerDevice].style;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].style ) {
currentStyle = this.state.value['desktop'].style;
}
} else if ( '' !== this.state.value[ this.state.currentDevice ]?.style ) {
currentStyle = this.state.value[ this.state.currentDevice ].style
}
} else {
currentStyle = ( undefined !== this.state.value.style ? this.state.value.style : 'none' );
}
const onResponsiveInputChange = ( event ) => {
const newValue = Number( event.target.value );
let value = this.state.value;
if ( undefined === value[ this.state.currentDevice ] ) {
value[ this.state.currentDevice ] = {
'width': '',
'unit': '',
'style': '',
'color': '',
}
}
value[ this.state.currentDevice ].width = newValue;
this.updateValues( value );
}
const onInputChange = ( event ) => {
const newValue = ( '' !== event.target.value ? Number( event.target.value ) : '' );
let value = this.state.value;
value.width = newValue;
this.updateValues( value );
}
const responsiveControlLabel = (
<Fragment>
{ this.state.currentDevice !== 'desktop' && (
<Tooltip text={ __( 'Reset Device Values', 'kadence' ) }>
<Button
className="reset kadence-reset"
disabled={ ( undefined === this.state.value[this.state.currentDevice] ) }
onClick={ () => {
let value = this.state.value;
delete value[this.state.currentDevice];
this.updateValues( value );
} }
>
<Dashicon icon='image-rotate' />
</Button>
</Tooltip>
) }
{ this.state.currentDevice === 'desktop' && (
<Tooltip text={ __( 'Reset All Values', 'kadence' ) }>
<Button
className="reset kadence-reset"
onClick={ () => {
this.resetValues();
} }
>
<Dashicon icon='image-rotate' />
</Button>
</Tooltip>
) }
{ data.label &&
data.label
}
</Fragment>
);
const controlLabel = (
<Fragment>
<Tooltip text={ __( 'Reset Values', 'kadence' ) }>
<Button
className="reset kadence-reset"
disabled={ ( this.defaultValue === this.state.value ) }
onClick={ () => {
let value = this.state.value;
value = this.defaultValue
this.updateValues( value );
} }
>
<Dashicon icon='image-rotate' />
</Button>
</Tooltip>
{ data.label &&
data.label
}
</Fragment>
);
//console.log( this.state.colorPalette )
return (
<div ref={ this.anchorNodeRef } className="kadence-control-field kadence-border-control">
{ this.controlParams.responsive && (
<ResponsiveControl
onChange={ ( currentDevice) => this.setState( { currentDevice } ) }
controlLabel={ responsiveControlLabel }
>
{ 'none' !== currentStyle && (
<Fragment>
{ this.controlParams.color && (
<ColorControl
presetColors={ this.state.colorPalette }
color={ ( undefined !== this.state.value[ this.state.currentDevice ] && this.state.value[ this.state.currentDevice ].color ? this.state.value[ this.state.currentDevice ].color : '' ) }
usePalette={ true }
tooltip={ __( 'Border Color' ) }
onChangeComplete={ ( color, isPalette ) => this.handleResponsiveChangeComplete( color, isPalette, this.state.currentDevice ) }
customizer={ this.props.customizer }
controlRef={ this.anchorNodeRef }
/>
) }
<input
value={ ( undefined !== this.state.value[ this.state.currentDevice ] && undefined !== this.state.value[ this.state.currentDevice ]?.width ? this.state.value[ this.state.currentDevice ].width : '' ) }
onChange={ onResponsiveInputChange }
min={this.controlParams.min[currentUnit]}
max={this.controlParams.max[currentUnit]}
step={this.controlParams.step[currentUnit]}
type="number"
className="components-text-control__input"
/>
{ this.controlParams.units && (
<div className="kadence-units">
{ this.getResponsiveUnitButtons() }
</div>
) }
</Fragment>
) }
{ this.controlParams.styles && (
<div className="kadence-units kadence-style-options">
{ this.getResponsiveStyleButtons() }
</div>
) }
</ResponsiveControl>
) }
{ ! this.controlParams.responsive && (
<Fragment>
<div className="kadence-responsive-control-bar">
<span className="customize-control-title">{ controlLabel }</span>
</div>
<div className="kadence-responsive-controls-content">
{ 'none' !== currentStyle && (
<Fragment>
{ this.controlParams.color && (
<ColorControl
presetColors={ this.state.colorPalette }
color={ ( undefined !== this.state.value.color && this.state.value.color ? this.state.value.color : '' ) }
usePalette={ true }
tooltip={ __( 'Border Color' ) }
onChangeComplete={ ( color, isPalette ) => this.handleChangeComplete( color, isPalette ) }
customizer={ this.props.customizer }
controlRef={ this.anchorNodeRef }
/>
) }
<input
value={ ( undefined !== this.state.value && undefined !== this.state.value.width ? this.state.value.width : '' ) }
onChange={ onInputChange }
min={this.controlParams.min[currentUnit]}
max={this.controlParams.max[currentUnit]}
step={this.controlParams.step[currentUnit]}
type="number"
className="components-text-control__input"
/>
{ this.controlParams.units && (
<div className="kadence-units">
{ this.getUnitButtons() }
</div>
) }
</Fragment>
) }
{ this.controlParams.styles && (
<div className="kadence-units kadence-style-options">
{ this.getStyleButtons() }
</div>
) }
</div>
</Fragment>
) }
</div>
);
}
getResponsiveStyleButtons() {
let self = this;
const { styles } = this.controlParams;
let currentStyle;
if ( undefined === this.state.value[ this.state.currentDevice ] ) {
let largerDevice = ( this.state.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice]?.style ) {
currentStyle = this.state.value[largerDevice].style;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].style ) {
currentStyle = this.state.value['desktop'].style;
}
} else if ( undefined === this.state.value[ this.state.currentDevice ].style ) {
let largerDevice = ( this.state.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice]?.style ) {
currentStyle = this.state.value[largerDevice].style;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].style ) {
currentStyle = this.state.value['desktop'].style;
}
} else if ( '' === this.state.value[ this.state.currentDevice ].style ) {
let largerDevice = ( this.state.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice]?.style ) {
currentStyle = this.state.value[largerDevice].style;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].style ) {
currentStyle = this.state.value['desktop'].style;
}
} else if ( '' !== this.state.value[ this.state.currentDevice ].style ) {
currentStyle = this.state.value[ this.state.currentDevice ].style
}
if ( styles.length === 1 ) {
return ( <Button
className="is-active is-single"
isSmall
disabled
>{ Icons[ currentStyle ] }</Button> );
}
return <ToolbarGroup
isCollapsed={ true }
icon={ Icons[ currentStyle ] }
label={ __( 'Style', 'kadence' ) }
controls={ styles.map( ( style ) => this.createResponsiveStyleControlToolbar( style ) ) }
/>
}
createResponsiveStyleControlToolbar( style ) {
return [ {
icon: Icons[ style ],
isActive: ( undefined !== this.state.value[ this.state.currentDevice ] && undefined !== this.state.value[ this.state.currentDevice ].style && this.state.value[ this.state.currentDevice ].style === style ),
onClick: () => {
let value = this.state.value;
if ( undefined === value[ this.state.currentDevice ] ) {
value[ this.state.currentDevice ] = {
'width': '',
'unit': '',
'style': '',
'color': '',
}
}
value[ this.state.currentDevice ].style = style;
this.updateValues( value );
},
} ];
};
getStyleButtons() {
let self = this;
const { styles } = this.controlParams;
let currentStyle;
currentStyle = ( undefined !== this.state.value?.style ? this.state.value.style : 'none' );
if ( styles.length === 1 ) {
return ( <Button
className="is-active is-single"
isSmall
disabled
>{ Icons[ currentStyle ] }</Button> );
}
return <ToolbarGroup
isCollapsed={ true }
icon={ Icons[ currentStyle ] }
label={ __( 'Style', 'kadence' ) }
controls={ styles.map( ( style ) => this.createStyleControlToolbar( style ) ) }
/>
}
createStyleControlToolbar( style ) {
return [ {
icon: Icons[ style ],
isActive: ( undefined !== this.state.value && undefined !== this.state.value.style && this.state.value.style === style ),
onClick: () => {
let value = this.state.value;
value.style = style;
this.updateValues( value );
},
} ];
};
createResponsiveLevelControlToolbar( unit ) {
return [ {
icon: ( unit === '%' ? Icons.percent : Icons[ unit ] ),
isActive: ( undefined !== this.state.value[ this.state.currentDevice ] && undefined !== this.state.value[ this.state.currentDevice ].unit && this.state.value[ this.state.currentDevice ].unit === unit ),
onClick: () => {
let value = this.state.value;
if ( undefined === value[ this.state.currentDevice ] ) {
value[ this.state.currentDevice ] = {
'width': '',
'unit': '',
'style': '',
'color': '',
}
}
value[ this.state.currentDevice ].unit = unit;
this.updateValues( value );
},
} ];
};
getResponsiveUnitButtons() {
let self = this;
const { units } = this.controlParams;
let currentUnit;
if ( undefined === self.state.value[ self.state.currentDevice ] ) {
let largerDevice = ( self.state.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice].unit ) {
currentUnit = this.state.value[largerDevice].unit;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].unit ) {
currentUnit = this.state.value['desktop'].unit;
}
} else if ( undefined !== self.state.value[ self.state.currentDevice ].unit ) {
let largerDevice = ( self.state.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice].unit ) {
currentUnit = this.state.value[largerDevice].unit;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].unit ) {
currentUnit = this.state.value['desktop'].unit;
}
} else if ( '' === self.state.value[ self.state.currentDevice ].unit ) {
let largerDevice = ( self.state.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice].unit ) {
currentUnit = this.state.value[largerDevice].unit;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].unit ) {
currentUnit = this.state.value['desktop'].unit;
}
} else if ( '' !== self.state.value[ self.state.currentDevice ].unit ) {
currentUnit = self.state.value[ self.state.currentDevice ].unit
}
if ( units.length === 1 ) {
return ( <Button
className="is-active is-single"
isSmall
disabled
>{ ( '%' === currentUnit ? Icons.percent : Icons[ currentUnit ] ) }</Button> );
}
return <ToolbarGroup
isCollapsed={ true }
icon={ ( '%' === currentUnit ? Icons.percent : Icons[ currentUnit ] ) }
label={ __( 'Unit', 'kadence' ) }
controls={ units.map( ( unit ) => this.createResponsiveLevelControlToolbar( unit ) ) }
/>
}
createLevelControlToolbar( unit ) {
return [ {
icon: ( unit === '%' ? Icons.percent : Icons[ unit ] ),
isActive: ( undefined !== this.state.value && undefined !== this.state.value.unit && this.state.value.unit === unit ),
onClick: () => {
let value = this.state.value;
value.unit = unit;
this.updateValues( value );
},
} ];
};
getUnitButtons() {
let self = this;
const { units } = this.controlParams;
let currentUnit;
currentUnit = ( undefined !== this.state.value.unit ? this.state.value.unit : 'px' );
if ( units.length === 1 ) {
return ( <Button
className="is-active is-single"
isSmall
disabled
>{ ( '%' === currentUnit ? Icons.percent : Icons[ currentUnit ] ) }</Button> );
}
return <ToolbarGroup
isCollapsed={ true }
icon={ ( '%' === currentUnit ? Icons.percent : Icons[ currentUnit ] ) }
label={ __( 'Unit', 'kadence' ) }
controls={ units.map( ( unit ) => this.createLevelControlToolbar( unit ) ) }
/>
}
updateValues( value ) {
if ( value ) {
this.setState( { value: value } );
} else {
this.setState( { value: this.defaultValue } );
value = {};
}
if ( this.controlParams.responsive ) {
value.flag = !this.props.control.setting.get().flag;
}
this.props.control.setting.set( {
...{ flag: true },
...value,
} );
}
resetValues() {
this.setState( { value: this.defaultValue } );
this.props.control.setting.set( {} );
}
}
BorderComponent.propTypes = {
control: PropTypes.object.isRequired,
customizer: PropTypes.object.isRequired
};
export default BorderComponent;

View File

@@ -0,0 +1,14 @@
import { createRoot } from '@wordpress/element';
import BorderComponent from './border-component.js';
export const BorderControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <BorderComponent control={control} customizer={ wp.customize }/> );
// ReactDOM.render(
// <BorderComponent control={control} customizer={ wp.customize }/>,
// control.container[0]
// );
}
} );

View File

@@ -0,0 +1,522 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import ResponsiveControl from '../common/responsive.js';
import ColorControl from '../common/color.js';
import Icons from '../common/icons.js';
import { __ } from '@wordpress/i18n';
const { ButtonGroup, Dashicon, Toolbar, ToolbarGroup, Tooltip, Button } = wp.components;
/**
* WordPress dependencies
*/
import { createRef, Component, Fragment } from '@wordpress/element';
class SingleBorderComponent extends Component {
constructor() {
super( ...arguments );
this.updateValues = this.updateValues.bind( this );
this.resetValues = this.resetValues.bind( this );
this.handleChangeComplete = this.handleChangeComplete.bind( this );
this.handleResponsiveChangeComplete = this.handleResponsiveChangeComplete.bind( this );
this.getUnitButtons = this.getUnitButtons.bind( this );
this.getResponsiveUnitButtons = this.getResponsiveUnitButtons.bind( this );
this.createLevelControlToolbar = this.createLevelControlToolbar.bind( this );
this.createResponsiveLevelControlToolbar = this.createResponsiveLevelControlToolbar.bind( this );
this.getStyleButtons = this.getStyleButtons.bind( this );
this.getResponsiveStyleButtons = this.getResponsiveStyleButtons.bind( this );
this.createStyleControlToolbar = this.createStyleControlToolbar.bind( this );
this.createResponsiveStyleControlToolbar = this.createResponsiveStyleControlToolbar.bind( this );
let value = this.props.control.settings[this.props.item] ? this.props.control.settings[this.props.item].get() : [];
let defaultParams = {
min: {
px: '0',
em: '0',
rem: '0',
},
max: {
px: '300',
em: '12',
rem: '12',
},
step: {
px: '1',
em: '0.01',
rem: '0.01',
},
units: ['px', 'em', 'rem'],
styles: ['none', 'solid', 'dashed', 'dotted', 'double'],
responsive:true,
color:true,
};
this.controlParams = this.props.control.params.input_attrs ? {
...defaultParams,
...this.props.control.params.input_attrs,
} : defaultParams;
let responsiveDefault = {
'desktop': {
'width': '',
'unit': 'px',
'style': 'none',
'color': ( this.controlParams.color ? '' : 'currentColor' ),
}
};
let noneResponsiveDefault = {
'width': '',
'unit': 'px',
'style': 'none',
'color': ( this.controlParams.color ? '' : 'currentColor' ),
};
let baseDefault;
if ( this.controlParams.responsive ) {
baseDefault = responsiveDefault;
} else {
baseDefault = noneResponsiveDefault;
}
this.defaultValue = this.props.control.params.default ? {
...baseDefault,
...this.props.control.params.default
} : baseDefault;
value = value ? {
...JSON.parse( JSON.stringify( this.defaultValue ) ),
...value
} : JSON.parse( JSON.stringify( this.defaultValue ) );
this.state = {
currentDevice: 'desktop',
value: value,
};
this.anchorNodeRef = createRef();
}
handleResponsiveChangeComplete( color, isPalette, device ) {
let value = this.state.value;
if ( undefined === value[ device ] ) {
value[ device ] = {
'width': '',
'unit': '',
'style': '',
'color': '',
}
}
if ( isPalette ) {
value[ device ].color = isPalette;
} else if ( undefined !== color.rgb && undefined !== color.rgb.a && 1 !== color.rgb.a ) {
value[ device ].color = 'rgba(' + color.rgb.r + ',' + color.rgb.g + ',' + color.rgb.b + ',' + color.rgb.a + ')';
} else {
value[ device ].color = color.hex;
}
this.updateValues( value );
}
handleChangeComplete( color, isPalette ) {
let value = this.state.value;
if ( isPalette ) {
value.color = isPalette;
} else if ( undefined !== color.rgb && undefined !== color.rgb.a && 1 !== color.rgb.a ) {
value.color = 'rgba(' + color.rgb.r + ',' + color.rgb.g + ',' + color.rgb.b + ',' + color.rgb.a + ')';
} else {
value.color = color.hex;
}
this.updateValues( value );
}
render() {
const data = this.props.control.params;
let currentUnit;
if ( this.controlParams.responsive ) {
if ( undefined === this.state.value[ this.props.currentDevice ] ) {
let largerDevice = ( this.props.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice].unit ) {
currentUnit = this.state.value[largerDevice].unit;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].unit ) {
currentUnit = this.state.value['desktop'].unit;
}
} else if ( undefined === this.state.value[ this.props.currentDevice ].unit ) {
let largerDevice = ( this.props.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice].unit ) {
currentUnit = this.state.value[largerDevice].unit;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].unit ) {
currentUnit = this.state.value['desktop'].unit;
}
} else if ( '' === this.state.value[ this.props.currentDevice ].unit ) {
let largerDevice = ( this.props.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice].unit ) {
currentUnit = this.state.value[largerDevice].unit;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].unit ) {
currentUnit = this.state.value['desktop'].unit;
}
} else if ( '' !== this.state.value[ this.props.currentDevice ].unit ) {
currentUnit = this.state.value[ this.props.currentDevice ].unit
}
} else {
currentUnit = ( undefined !== this.state.value.unit ? this.state.value.unit : 'px' );
}
let currentStyle;
if ( this.controlParams.responsive ) {
if ( undefined === this.state.value[ this.props.currentDevice ] ) {
let largerDevice = ( this.props.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice].style ) {
currentStyle = this.state.value[largerDevice].style;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].style ) {
currentStyle = this.state.value['desktop'].style;
}
} else if ( undefined === this.state.value[ this.props.currentDevice ].style ) {
let largerDevice = ( this.props.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice].style ) {
currentStyle = this.state.value[largerDevice].style;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].style ) {
currentStyle = this.state.value['desktop'].style;
}
} else if ( '' === this.state.value[ this.props.currentDevice ].style ) {
let largerDevice = ( this.props.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice].style ) {
currentStyle = this.state.value[largerDevice].style;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].style ) {
currentStyle = this.state.value['desktop'].style;
}
} else if ( '' !== this.state.value[ this.props.currentDevice ].style ) {
currentStyle = this.state.value[ this.props.currentDevice ].style
}
} else {
currentStyle = ( undefined !== this.state.value.style ? this.state.value.style : 'none' );
}
const onResponsiveInputChange = ( event ) => {
const newValue = Number( event.target.value );
let value = this.state.value;
if ( undefined === value[ this.props.currentDevice ] ) {
value[ this.props.currentDevice ] = {
'width': '',
'unit': '',
'style': '',
'color': '',
}
}
value[ this.props.currentDevice ].width = newValue;
this.updateValues( value );
}
const onInputChange = ( event ) => {
const newValue = ( '' !== event.target.value ? Number( event.target.value ) : '' );
let value = this.state.value;
value.width = newValue;
this.updateValues( value );
}
let theIcon;
if ( 'border_top' === this.props.item ) {
theIcon = Icons.outlinetop;
} else if ( 'border_left' === this.props.item ) {
theIcon = Icons.outlineleft;
} else if ( 'border_right' === this.props.item ) {
theIcon = Icons.outlineright;
} else if ( 'border_bottom' === this.props.item ) {
theIcon = Icons.outlinebottom;
}
let isDisabled = true;
if ( this.controlParams.responsive ) {
if ( ( undefined !== this.state.value['tablet'] ) || ( undefined !== this.state.value['mobile'] ) ) {
isDisabled = false;
} else if ( ( 'none' !== this.state.value['desktop'].style ) || ( '' !== this.state.value['desktop'].color ) || ( '' !== this.state.value['desktop'].width ) || ( 'px' !== this.state.value['desktop'].unit ) ) {
isDisabled = false;
}
}
return (
<div ref={this.anchorNodeRef} className="kadence-responsive-controls-content kadence-border-single-item">
{ this.controlParams.responsive && (
<Fragment>
<Tooltip text={ __( 'Reset Values', 'kadence' ) }>
<Button
className="reset kadence-reset"
disabled={ isDisabled }
onClick={ () => {
this.resetValues();
} }
>
<Dashicon icon='image-rotate' />
</Button>
</Tooltip>
<span class="border-icon">{ theIcon }</span>
{ 'none' !== currentStyle && (
<Fragment>
{ this.controlParams.color && (
<ColorControl
presetColors={ this.state.colorPalette }
color={ ( undefined !== this.state.value[ this.props.currentDevice ] && this.state.value[ this.props.currentDevice ].color ? this.state.value[ this.props.currentDevice ].color : '' ) }
usePalette={ true }
tooltip={ __( 'Border Color' ) }
onChangeComplete={ ( color, isPalette ) => this.handleResponsiveChangeComplete( color, isPalette, this.props.currentDevice ) }
customizer={ this.props.customizer }
controlRef={ this.anchorNodeRef }
/>
) }
<input
value={ ( undefined !== this.state.value[ this.props.currentDevice ] && undefined !== this.state.value[ this.props.currentDevice ].width ? this.state.value[ this.props.currentDevice ].width : '' ) }
onChange={ onResponsiveInputChange }
min={this.controlParams.min[currentUnit]}
max={this.controlParams.max[currentUnit]}
step={this.controlParams.step[currentUnit]}
type="number"
className="components-text-control__input"
/>
{ this.controlParams.units && (
<div className="kadence-units">
{ this.getResponsiveUnitButtons() }
</div>
) }
</Fragment>
) }
{ this.controlParams.styles && (
<div className="kadence-units kadence-style-options">
{ this.getResponsiveStyleButtons() }
</div>
) }
</Fragment>
) }
{ ! this.controlParams.responsive && (
<Fragment>
{ 'none' !== currentStyle && (
<Fragment>
{ this.controlParams.color && (
<ColorControl
presetColors={ this.state.colorPalette }
color={ ( undefined !== this.state.value.color && this.state.value.color ? this.state.value.color : '' ) }
usePalette={ true }
tooltip={ __( 'Border Color' ) }
onChangeComplete={ ( color, isPalette ) => this.handleChangeComplete( color, isPalette ) }
customizer={ this.props.customizer }
controlRef={ this.anchorNodeRef }
/>
) }
<input
value={ ( undefined !== this.state.value && undefined !== this.state.value.width ? this.state.value.width : '' ) }
onChange={ onInputChange }
min={this.controlParams.min[currentUnit]}
max={this.controlParams.max[currentUnit]}
step={this.controlParams.step[currentUnit]}
type="number"
className="components-text-control__input"
/>
{ this.controlParams.units && (
<div className="kadence-units">
{ this.getUnitButtons() }
</div>
) }
</Fragment>
) }
{ this.controlParams.styles && (
<div className="kadence-units kadence-style-options">
{ this.getStyleButtons() }
</div>
) }
</Fragment>
) }
</div>
);
}
getResponsiveStyleButtons() {
let self = this;
const { styles } = this.controlParams;
let currentStyle;
if ( undefined === this.state.value[ this.props.currentDevice ] ) {
let largerDevice = ( this.props.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice].style ) {
currentStyle = this.state.value[largerDevice].style;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].style ) {
currentStyle = this.state.value['desktop'].style;
}
} else if ( undefined === this.state.value[ this.props.currentDevice ].style ) {
let largerDevice = ( this.props.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice].style ) {
currentStyle = this.state.value[largerDevice].style;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].style ) {
currentStyle = this.state.value['desktop'].style;
}
} else if ( '' === this.state.value[ this.props.currentDevice ].style ) {
let largerDevice = ( this.props.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice].style ) {
currentStyle = this.state.value[largerDevice].style;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].style ) {
currentStyle = this.state.value['desktop'].style;
}
} else if ( '' !== this.state.value[ this.props.currentDevice ].style ) {
currentStyle = this.state.value[ this.props.currentDevice ].style
}
if ( styles.length === 1 ) {
return ( <Button
className="is-active is-single"
isSmall
disabled
>{ Icons[ currentStyle ] }</Button> );
}
return <ToolbarGroup
isCollapsed={ true }
icon={ Icons[ currentStyle ] }
label={ __( 'Style', 'kadence' ) }
controls={ styles.map( ( style ) => this.createResponsiveStyleControlToolbar( style ) ) }
/>
}
createResponsiveStyleControlToolbar( style ) {
return [ {
icon: Icons[ style ],
isActive: ( undefined !== this.state.value[ this.props.currentDevice ] && undefined !== this.state.value[ this.props.currentDevice ].style && this.state.value[ this.props.currentDevice ].style === style ),
onClick: () => {
let value = this.state.value;
if ( undefined === value[ this.props.currentDevice ] ) {
value[ this.props.currentDevice ] = {
'width': '',
'unit': '',
'style': '',
'color': '',
}
}
value[ this.props.currentDevice ].style = style;
this.updateValues( value );
},
} ];
};
getStyleButtons() {
let self = this;
const { styles } = this.controlParams;
let currentStyle;
currentStyle = ( undefined !== this.state.value.style ? this.state.value.style : 'none' );
if ( styles.length === 1 ) {
return ( <Button
className="is-active is-single"
isSmall
disabled
>{ Icons[ currentStyle ] }</Button> );
}
return <ToolbarGroup
isCollapsed={ true }
icon={ Icons[ currentStyle ] }
label={ __( 'Style', 'kadence' ) }
controls={ styles.map( ( style ) => this.createStyleControlToolbar( style ) ) }
/>
}
createStyleControlToolbar( style ) {
return [ {
icon: Icons[ style ],
isActive: ( undefined !== this.state.value && undefined !== this.state.value.style && this.state.value.style === style ),
onClick: () => {
let value = this.state.value;
value.style = style;
this.updateValues( value );
},
} ];
};
createResponsiveLevelControlToolbar( unit ) {
return [ {
icon: ( unit === '%' ? Icons.percent : Icons[ unit ] ),
isActive: ( undefined !== this.state.value[ this.props.currentDevice ] && undefined !== this.state.value[ this.props.currentDevice ].unit && this.state.value[ this.props.currentDevice ].unit === unit ),
onClick: () => {
let value = this.state.value;
if ( undefined === value[ this.props.currentDevice ] ) {
value[ this.props.currentDevice ] = {
'width': '',
'unit': '',
'style': '',
'color': '',
}
}
value[ this.props.currentDevice ].unit = unit;
this.updateValues( value );
},
} ];
};
getResponsiveUnitButtons() {
let self = this;
const { units } = this.controlParams;
let currentUnit;
if ( undefined === self.state.value[ self.state.currentDevice ] ) {
let largerDevice = ( self.state.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice].unit ) {
currentUnit = this.state.value[largerDevice].unit;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].unit ) {
currentUnit = this.state.value['desktop'].unit;
}
} else if ( undefined !== self.state.value[ self.state.currentDevice ].unit ) {
let largerDevice = ( self.state.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice].unit ) {
currentUnit = this.state.value[largerDevice].unit;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].unit ) {
currentUnit = this.state.value['desktop'].unit;
}
} else if ( '' === self.state.value[ self.state.currentDevice ].unit ) {
let largerDevice = ( self.state.currentDevice === 'mobile' ? 'tablet' : 'desktop' );
if ( undefined !== this.state.value[largerDevice] && this.state.value[largerDevice].unit ) {
currentUnit = this.state.value[largerDevice].unit;
} else if ( 'tablet' === largerDevice && undefined !== this.state.value['desktop'] && this.state.value['desktop'].unit ) {
currentUnit = this.state.value['desktop'].unit;
}
} else if ( '' !== self.state.value[ self.state.currentDevice ].unit ) {
currentUnit = self.state.value[ self.state.currentDevice ].unit
}
if ( units.length === 1 ) {
return ( <Button
className="is-active is-single"
isSmall
disabled
>{ ( '%' === currentUnit ? Icons.percent : Icons[ currentUnit ] ) }</Button> );
}
return <ToolbarGroup
isCollapsed={ true }
icon={ ( '%' === currentUnit ? Icons.percent : Icons[ currentUnit ] ) }
label={ __( 'Unit', 'kadence' ) }
controls={ units.map( ( unit ) => this.createResponsiveLevelControlToolbar( unit ) ) }
/>
}
createLevelControlToolbar( unit ) {
return [ {
icon: ( unit === '%' ? Icons.percent : Icons[ unit ] ),
isActive: ( undefined !== this.state.value && undefined !== this.state.value.unit && this.state.value.unit === unit ),
onClick: () => {
let value = this.state.value;
value.unit = unit;
this.updateValues( value );
},
} ];
};
getUnitButtons() {
let self = this;
const { units } = this.controlParams;
let currentUnit;
currentUnit = ( undefined !== this.state.value.unit ? this.state.value.unit : 'px' );
if ( units.length === 1 ) {
return ( <Button
className="is-active is-single"
isSmall
disabled
>{ ( '%' === currentUnit ? Icons.percent : Icons[ currentUnit ] ) }</Button> );
}
return <ToolbarGroup
isCollapsed={ true }
icon={ ( '%' === currentUnit ? Icons.percent : Icons[ currentUnit ] ) }
label={ __( 'Unit', 'kadence' ) }
controls={ units.map( ( unit ) => this.createLevelControlToolbar( unit ) ) }
/>
}
resetValues() {
const value = JSON.parse( JSON.stringify( this.defaultValue ) );
this.setState( { value: value } );
if ( this.controlParams.responsive ) {
value.flag = !this.props.control.settings[this.props.item].get().flag;
}
this.props.control.settings[this.props.item].set( {
...value,
} );
}
updateValues( value ) {
this.setState( { value: value } );
if ( this.controlParams.responsive ) {
value.flag = !this.props.control.settings[this.props.item].get().flag;
}
this.props.control.settings[this.props.item].set( {
...this.props.control.settings[this.props.item].get(),
...value,
} );
}
}
SingleBorderComponent.propTypes = {
control: PropTypes.object.isRequired,
customizer: PropTypes.object.isRequired
};
export default SingleBorderComponent;

View File

@@ -0,0 +1,182 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import ResponsiveControl from '../common/responsive.js';
import Icons from '../common/icons.js';
import SingleBorderComponent from './border-component';
import { __ } from '@wordpress/i18n';
const { ButtonGroup, Dashicon, Toolbar, Tooltip, Button } = wp.components;
/**
* WordPress dependencies
*/
import { Component, Fragment } from '@wordpress/element';
class BordersComponent extends Component {
constructor() {
super( ...arguments );
//this.updateValues = this.updateValues.bind( this );
//this.resetValues = this.resetValues.bind( this );
let defaultParams = {
min: {
px: '0',
em: '0',
rem: '0',
},
max: {
px: '300',
em: '12',
rem: '12',
},
step: {
px: '1',
em: '0.01',
rem: '0.01',
},
units: ['px', 'em', 'rem'],
styles: ['none', 'solid', 'dashed', 'dotted', 'double'],
responsive:true,
color:true,
};
this.controlParams = this.props.control.params.input_attrs ? {
...defaultParams,
...this.props.control.params.input_attrs,
} : defaultParams;
let responsiveDefault = {
'desktop': {
'width': '',
'unit': 'px',
'style': 'none',
'color': ( this.controlParams.color ? '' : 'currentColor' ),
}
};
let noneResponsiveDefault = {
'width': '',
'unit': 'px',
'style': 'none',
'color': ( this.controlParams.color ? '' : 'currentColor' ),
};
let baseDefault;
if ( this.controlParams.responsive ) {
baseDefault = responsiveDefault;
} else {
baseDefault = noneResponsiveDefault;
}
this.defaultValue = this.props.control.params.default ? {
...baseDefault,
...this.props.control.params.default
} : baseDefault;
value = value ? {
...JSON.parse( JSON.stringify( this.defaultValue ) ),
...value
} : JSON.parse( JSON.stringify( this.defaultValue ) );
this.state = {
currentDevice: 'desktop',
value: value,
};
}
render() {
const data = this.props.control.params;
const responsiveControlLabel = (
<Fragment>
{/* <Tooltip text={ __( 'Reset Values', 'kadence' ) }>
<Button
className="reset kadence-reset"
disabled={ isDisabled }
onClick={ () => {
this.resetValues();
} }
>
<Dashicon icon='image-rotate' />
</Button>
</Tooltip> */}
{ data.label &&
data.label
}
</Fragment>
);
const controlLabel = (
<Fragment>
{/* <Tooltip text={ __( 'Reset Values', 'kadence' ) }>
<Button
className="reset kadence-reset"
disabled={ ( this.defaultValue === this.state.value ) }
onClick={ () => {
let value = this.state.value;
value = this.defaultValue
this.updateValues( value );
} }
>
<Dashicon icon='image-rotate' />
</Button>
</Tooltip> */}
{ data.label &&
data.label
}
</Fragment>
);
return (
<div className="kadence-control-field kadence-border-control">
{ this.controlParams.responsive && (
<ResponsiveControl
onChange={ ( currentDevice ) => this.setState( { currentDevice } ) }
controlLabel={ responsiveControlLabel }
>
{ Object.keys( this.props.control.params.settings ).map( ( item ) => {
return (
<SingleBorderComponent
currentDevice={ this.state.currentDevice }
item={ item }
name={ this.props.control.params.settings[item] }
customizer={ this.props.customizer }
control={ this.props.control }
/>
);
} ) }
</ResponsiveControl>
) }
{ ! this.controlParams.responsive && (
<Fragment>
<div className="kadence-responsive-control-bar">
<span className="customize-control-title">{ controlLabel }</span>
</div>
<div className="kadence-responsive-controls-content">
<SingleBorderComponent
currentDevice={ currentDevice }
item={ 'border_top' }
customizer={ this.props.customizer }
/>
</div>
</Fragment>
) }
{ this.props.control.renderNotice() }
</div>
);
}
// resetValues() {
// Object.keys( this.props.control.params.settings ).map( ( item ) => {
// this.props.control.settings[item].set( {
// responsiveDefault
// } );
// } );
// }
// updateValues( value ) {
// this.setState( { value: value } );
// if ( this.controlParams.responsive ) {
// value.flag = !this.props.control.setting.get().flag;
// }
// this.props.control.setting.set( {
// ...this.props.control.setting.get(),
// ...value,
// } );
// }
}
BordersComponent.propTypes = {
control: PropTypes.object.isRequired,
customizer: PropTypes.object.isRequired
};
export default BordersComponent;

View File

@@ -0,0 +1,14 @@
import { createRoot } from '@wordpress/element';
import BordersComponent from './borders-component.js';
export const BordersControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <BordersComponent control={control} customizer={ wp.customize }/> );
// ReactDOM.render(
// <BordersComponent control={control} customizer={ wp.customize }/>,
// control.container[0]
// );
}
} );

View File

@@ -0,0 +1,634 @@
/* jshint esversion: 6 */
import PropTypes from "prop-types";
import classnames from "classnames";
import ResponsiveControl from "../common/responsive.js";
import ColorControl from "../common/color.js";
import Icons from "../common/icons.js";
import { __ } from "@wordpress/i18n";
const { ButtonGroup, Dashicon, Toolbar, Tooltip, Button, ToggleControl } =
wp.components;
/**
* WordPress dependencies
*/
import { createRef, Component, Fragment } from "@wordpress/element";
class BoxshadowComponent extends Component {
constructor() {
super(...arguments);
this.updateValues = this.updateValues.bind(this);
this.handleChangeComplete = this.handleChangeComplete.bind(this);
this.handleResponsiveChangeComplete =
this.handleResponsiveChangeComplete.bind(this);
let value = this.props.control.setting.get();
let defaultParams = {
responsive: false,
};
this.controlParams = this.props.control.params.input_attrs
? {
...defaultParams,
...this.props.control.params.input_attrs,
}
: defaultParams;
let responsiveDefault = {
desktop: {
color: "rgba(0,0,0,0.05)",
hOffset: 0,
vOffset: 15,
blur: 15,
spread: -10,
inset: false,
disabled: false,
},
};
let noneResponsiveDefault = {
color: "rgba(0,0,0,0.05)",
hOffset: 0,
vOffset: 15,
blur: 15,
spread: -10,
inset: false,
disabled: false,
};
let baseDefault;
if (this.controlParams.responsive) {
baseDefault = responsiveDefault;
} else {
baseDefault = noneResponsiveDefault;
}
this.defaultValue = this.props.control.params.default
? {
...baseDefault,
...this.props.control.params.default,
}
: baseDefault;
value = value
? {
...JSON.parse(JSON.stringify(this.defaultValue)),
...value,
}
: JSON.parse(JSON.stringify(this.defaultValue));
this.state = {
currentDevice: "desktop",
value: value,
};
this.anchorNodeRef = createRef();
}
handleResponsiveChangeComplete(color, isPalette, device) {
let value = this.state.value;
if (undefined === value[device]) {
value[device] = {
color: "",
hOffset: "",
vOffset: "",
blur: "",
spread: "",
inset: "",
disabled: false,
};
}
if (isPalette) {
value[device].color = isPalette;
} else if (
undefined !== color.rgb &&
undefined !== color.rgb.a &&
1 !== color.rgb.a
) {
value[device].color =
"rgba(" +
color.rgb.r +
"," +
color.rgb.g +
"," +
color.rgb.b +
"," +
color.rgb.a +
")";
} else {
value[device].color = color.hex;
}
this.updateValues(value);
}
handleChangeComplete(color, isPalette) {
let value = this.state.value;
if (isPalette) {
value.color = isPalette;
} else if (
undefined !== color.rgb &&
undefined !== color.rgb.a &&
1 !== color.rgb.a
) {
value.color =
"rgba(" +
color.rgb.r +
"," +
color.rgb.g +
"," +
color.rgb.b +
"," +
color.rgb.a +
")";
} else {
value.color = color.hex;
}
this.updateValues(value);
}
render() {
const data = this.props.control.params;
const onResponsiveInputChange = (event, setting) => {
const newValue = Number(event.target.value);
let value = this.state.value;
if (undefined === value[this.state.currentDevice]) {
value[this.state.currentDevice] = {
color: "",
hOffset: "",
vOffset: "",
blur: "",
spread: "",
inset: "",
disabled: false,
};
}
value[this.state.currentDevice][setting] = newValue;
this.updateValues(value);
};
const onInputChange = (event, setting) => {
const newValue =
"" !== event.target.value ? Number(event.target.value) : "";
let value = this.state.value;
value[setting] = newValue;
this.updateValues(value);
};
const onInsetChange = (newValue) => {
let value = this.state.value;
value.inset = newValue;
this.updateValues(value);
};
const onDisableChange = (newValue) => {
let value = this.state.value;
value.disabled = newValue;
this.updateValues(value);
};
const responsiveControlLabel = (
<Fragment>
{this.state.currentDevice !== "desktop" && (
<Tooltip text={__("Reset Device Values", "kadence")}>
<Button
className="reset kadence-reset"
disabled={
undefined ===
this.state.value[this.state.currentDevice]
}
onClick={() => {
let value = this.state.value;
delete value[this.state.currentDevice];
this.updateValues(value);
}}
>
<Dashicon icon="image-rotate" />
</Button>
</Tooltip>
)}
{data.label && data.label}
</Fragment>
);
const controlLabel = (
<Fragment>
<Tooltip text={__("Reset Values", "kadence")}>
<Button
className="reset kadence-reset"
disabled={this.defaultValue === this.state.value}
onClick={() => {
let value = this.state.value;
value = this.defaultValue;
this.updateValues(value);
}}
>
<Dashicon icon="image-rotate" />
</Button>
</Tooltip>
{data.label && data.label}
</Fragment>
);
return (
<div
ref={this.anchorNodeRef}
className="kadence-control-field kadence-boxshadow-control kadence-border-control"
>
{this.controlParams.responsive && (
<ResponsiveControl
onChange={(currentDevice) =>
this.setState({ currentDevice })
}
controlLabel={responsiveControlLabel}
>
{!this.state.value.disabled && (
<>
<div className="kt-box-color-settings kt-box-shadow-subset">
<p className="kt-box-shadow-title">
{__("Color")}
</p>
<ColorControl
presetColors={this.state.colorPalette}
color={
undefined !==
this.state.value.color &&
this.state.value.color
? this.state.value.color
: ""
}
usePalette={true}
tooltip={__("Border Color")}
onChangeComplete={(color, isPalette) =>
this.handleChangeComplete(
color,
isPalette
)
}
customizer={this.props.customizer}
controlRef={this.anchorNodeRef}
/>
</div>
<div className="kt-box-x-settings kt-box-shadow-subset">
<p className="kt-box-shadow-title">
{__("X")}
</p>
<div className="components-base-control kt-boxshadow-number-input">
<div className="components-base-control__field">
<input
value={
undefined !==
this.state.value &&
undefined !==
this.state.value.hOffset
? this.state.value
.hOffset
: ""
}
onChange={(event) =>
onInputChange(
event,
"hOffset"
)
}
min={-200}
max={200}
step={1}
type="number"
className="components-text-control__input"
/>
</div>
</div>
</div>
<div className="kt-box-y-settings kt-box-shadow-subset">
<p className="kt-box-shadow-title">
{__("Y")}
</p>
<div className="components-base-control kt-boxshadow-number-input">
<div className="components-base-control__field">
<input
value={
undefined !==
this.state.value &&
undefined !==
this.state.value.vOffset
? this.state.value
.vOffset
: ""
}
onChange={(event) =>
onInputChange(
event,
"vOffset"
)
}
min={-200}
max={200}
step={1}
type="number"
className="components-text-control__input"
/>
</div>
</div>
</div>
<div className="kt-box-x-settings kt-box-shadow-subset">
<p className="kt-box-shadow-title">
{__("Blur")}
</p>
<div className="components-base-control kt-boxshadow-number-input">
<div className="components-base-control__field">
<input
value={
undefined !==
this.state.value &&
undefined !==
this.state.value.blur
? this.state.value.blur
: ""
}
onChange={(event) =>
onInputChange(event, "blur")
}
min={0}
max={200}
step={1}
type="number"
className="components-text-control__input"
/>
</div>
</div>
</div>
<div className="kt-box-y-settings kt-box-shadow-subset">
<p className="kt-box-shadow-title">
{__("Spread")}
</p>
<div className="components-base-control kt-boxshadow-number-input">
<div className="components-base-control__field">
<input
value={
undefined !==
this.state.value &&
undefined !==
this.state.value.spread
? this.state.value
.spread
: ""
}
onChange={(event) =>
onInputChange(
event,
"spread"
)
}
min={-200}
max={200}
step={1}
type="number"
className="components-text-control__input"
/>
</div>
</div>
</div>
<div className="kt-box-inset-settings">
<ToggleControl
label={__("Inset")}
checked={
undefined !== this.state.value &&
undefined !== this.state.value.inset
? this.state.value.inset
: false
}
onChange={(value) =>
this.props.onInsetChange(value)
}
/>
</div>
</>
)}
<div className="kt-box-disable-settings">
<ToggleControl
label={__("Disable")}
checked={
undefined !== this.state.value &&
undefined !== this.state.value.disabled
? this.state.value.disabled
: false
}
onChange={(value) =>
this.props.onDisableChange(value)
}
/>
</div>
</ResponsiveControl>
)}
{!this.controlParams.responsive && (
<Fragment>
<div className="kadence-responsive-control-bar">
<span className="customize-control-title">
{controlLabel}
</span>
</div>
{!this.state.value.disabled && (
<div className="kadence-responsive-controls-content">
<Fragment>
<div className="kt-box-color-settings kt-box-shadow-subset">
<p className="kt-box-shadow-title">
{__("Color")}
</p>
<ColorControl
presetColors={
this.state.colorPalette
}
color={
undefined !==
this.state.value.color &&
this.state.value.color
? this.state.value.color
: ""
}
usePalette={true}
tooltip={__("Border Color")}
onChangeComplete={(
color,
isPalette
) =>
this.handleChangeComplete(
color,
isPalette
)
}
customizer={this.props.customizer}
controlRef={this.anchorNodeRef}
/>
</div>
<div className="kt-box-x-settings kt-box-shadow-subset">
<p className="kt-box-shadow-title">
{__("X")}
</p>
<div className="components-base-control kt-boxshadow-number-input">
<div className="components-base-control__field">
<input
value={
undefined !==
this.state.value &&
undefined !==
this.state.value
.hOffset
? this.state.value
.hOffset
: ""
}
onChange={(event) =>
onInputChange(
event,
"hOffset"
)
}
min={-200}
max={200}
step={1}
type="number"
className="components-text-control__input"
/>
</div>
</div>
</div>
<div className="kt-box-y-settings kt-box-shadow-subset">
<p className="kt-box-shadow-title">
{__("Y")}
</p>
<div className="components-base-control kt-boxshadow-number-input">
<div className="components-base-control__field">
<input
value={
undefined !==
this.state.value &&
undefined !==
this.state.value
.vOffset
? this.state.value
.vOffset
: ""
}
onChange={(event) =>
onInputChange(
event,
"vOffset"
)
}
min={-200}
max={200}
step={1}
type="number"
className="components-text-control__input"
/>
</div>
</div>
</div>
<div className="kt-box-x-settings kt-box-shadow-subset">
<p className="kt-box-shadow-title">
{__("Blur")}
</p>
<div className="components-base-control kt-boxshadow-number-input">
<div className="components-base-control__field">
<input
value={
undefined !==
this.state.value &&
undefined !==
this.state.value
.blur
? this.state.value
.blur
: ""
}
onChange={(event) =>
onInputChange(
event,
"blur"
)
}
min={0}
max={200}
step={1}
type="number"
className="components-text-control__input"
/>
</div>
</div>
</div>
<div className="kt-box-y-settings kt-box-shadow-subset">
<p className="kt-box-shadow-title">
{__("Spread")}
</p>
<div className="components-base-control kt-boxshadow-number-input">
<div className="components-base-control__field">
<input
value={
undefined !==
this.state.value &&
undefined !==
this.state.value
.spread
? this.state.value
.spread
: ""
}
onChange={(event) =>
onInputChange(
event,
"spread"
)
}
min={-200}
max={200}
step={1}
type="number"
className="components-text-control__input"
/>
</div>
</div>
</div>
</Fragment>
</div>
)}
<div className="kadence-responsive-controls-content">
{!this.state.value.disabled && (
<div className="kt-box-inset-settings">
<ToggleControl
label={__("Inset")}
checked={
undefined !== this.state.value &&
undefined !==
this.state.value.inset &&
this.state.value.inset
? true
: false
}
onChange={(value) =>
onInsetChange(value)
}
/>
</div>
)}
<div className="kt-box-disable-settings">
<ToggleControl
label={__("Disable")}
checked={
undefined !== this.state.value &&
undefined !==
this.state.value.disabled &&
this.state.value.disabled
? true
: false
}
onChange={(value) => onDisableChange(value)}
/>
</div>
</div>
</Fragment>
)}
{ this.props.control.renderNotice() }
</div>
);
}
updateValues(value) {
this.setState({ value: value });
if (this.controlParams.responsive) {
value.flag = !this.props.control.setting.get().flag;
}
this.props.control.setting.set({
...this.props.control.setting.get(),
...value,
});
}
}
BoxshadowComponent.propTypes = {
control: PropTypes.object.isRequired,
customizer: PropTypes.object.isRequired,
};
export default BoxshadowComponent;

View File

@@ -0,0 +1,14 @@
import { createRoot } from '@wordpress/element';
import BoxShadowComponent from './boxshadow-component.js';
export const BoxShadowControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <BoxShadowComponent control={control} customizer={ wp.customize }/> );
// ReactDOM.render(
// <BoxShadowComponent control={control} customizer={ wp.customize }/>,
// control.container[0]
// );
}
} );

View File

@@ -0,0 +1,595 @@
@import "variables.scss";
.customize-control-kadence_builder_control {
border:0 !important;
}
// Areas
.kadence-builder-items {
padding: 10px 20px;
}
.kadence-builder-sortable-panel {
min-height: 44px;
display: flex;
flex: 1;
align-items: center;
}
.kadence-builder-item {
line-height: 32px;
display: inline-flex;
align-items: center;
justify-content: space-between;
height: auto;
min-width: 80px;
background: white;
position: relative;
border: 1px solid $color-gray-500;
white-space: nowrap;
position: relative;
cursor: grab;
margin: 0 4px;
padding: 0 12px;
border-radius: 3px;
> .kadence-builder-item-icon {
display: flex;
align-items: center;
justify-content: center;
right: 0;
cursor: pointer;
margin-right: -10px;
width: 28px;
height: 28px;
color:$color-gray-600;
background: transparent;
border: 0;
padding: 0;
margin-left: 8px;
}
}
.kadence-builder-item.sortable-ghost {
opacity: 0.4;
box-shadow: none;
opacity: 0.6;
font-size: 0;
border: 1px dashed #9c9c9c;
background: rgba(0, 0, 0, 0.015);
background: rgba(0, 124, 186, 0.25);
.kadence-builder-item-icon {
display: none;
}
}
.kadence-builder-item.sortable-drag {
box-shadow: 0 5px 20px -5px rgba(104, 104, 104, 0.4), inset 3px 0px 0px $color-primary;
z-index: 999999 !important;
.kadence-builder-item-icon:not(.kadence-move-icon) {
display: none;
}
}
.kadence-builder-item-start {
margin-bottom:10px;
min-height: 34px;
display: flex;
.kadence-builder-item {
flex:1; display:flex; width: 100%;
box-sizing: border-box;
&.sortable-drag {
width:auto;
}
}
}
#accordion-section-kadence_customizer_header_builder {
display: none !important;
}
#accordion-section-kadence_customizer_footer_builder {
display: none !important;
}
// Tabs
.kadence-build-tabs {
border-bottom:4px solid #ddd;
margin: 0;
padding-top: 9px;
padding-bottom: 0;
line-height: inherit;
display: flex;
padding: 0 12px;
}
.kadence-build-tabs .nav-tab {
font-size:14px;
line-height:20px;
display: flex;
align-items: center;
justify-content: center;
font-size: 11px;
font-weight: 600;
font-style: normal;
text-transform: uppercase;
height: 40px;
margin: 0;
margin-bottom: -4px;
padding: 0 18px;
cursor: pointer;
border: 0;
box-sizing: content-box;
border-bottom:4px solid #ddd;
border-radius: 0;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
.dashicons.dashicons-desktop {
font-size: 14px;
height: auto;
}
&:not(.nav-tab-active):hover {
background: #e5e5e5 !important;
color: #444 !important;
border-bottom-color: #f9f9f9;
}
&:hover {
box-shadow: none !important;
}
&:not(:first-child) {
margin-left: 8px;
}
}
.kadence-build-tabs .nav-tab.nav-tab-active {
border-bottom-color: #007cba;
background: #f9f9f9;
color:#000;
}
// Builder Container Area
#customize-theme-controls #sub-accordion-section-kadence_customizer_header_builder, #customize-theme-controls #sub-accordion-section-kadence_customizer_footer_builder {
position: fixed !important;
top: auto;
left: 300px;
right: 0;
min-height: 0;
background: #eee;
border-top: 1px solid $color-gray-500;
bottom: 0;
visibility: visible;
height: auto;
width: auto;
padding:0;
max-height: 60%;
overflow: auto;
transform: translateY(100%);
transition: transform 0.1s ease;
backface-visibility: hidden;
}
@media ( min-width: 1660px ) {
#customize-theme-controls #sub-accordion-section-kadence_customizer_header_builder, #customize-theme-controls #sub-accordion-section-kadence_customizer_footer_builder {
left: 18%;
}
}
@media ( max-width: 1659px ) {
.rtl {
#customize-theme-controls #sub-accordion-section-kadence_customizer_header_builder, #customize-theme-controls #sub-accordion-section-kadence_customizer_footer_builder {
right: 300px;
left:0;
}
}
}
#customize-theme-controls #sub-accordion-section-kadence_customizer_header_builder.kadence-builder-active, #customize-theme-controls #sub-accordion-section-kadence_customizer_footer_builder.kadence-footer-builder-active {
transform: translateY(0%);
visibility: visible;
overflow: visible;
}
#customize-theme-controls #sub-accordion-section-kadence_customizer_header_builder.kadence-builder-active.kadence-builder-hide, #customize-theme-controls #sub-accordion-section-kadence_customizer_footer_builder.kadence-footer-builder-active.kadence-builder-hide {
transform: translateY(100%) !important;
overflow: visible;
}
.kadence-builder-active > li.customize-section-description-container, .kadence-footer-builder-active > li.customize-section-description-container {
display: none !important;
}
.kadence-builder-areas .kadence-builder-group-horizontal {
display: flex;
margin-bottom: 15px;
border: 1px dashed $color-gray-500;
background:#f7f7f7;
.kadence-builder-area {
display: flex;
}
.kadence-builder-area-left, .kadence-builder-area-right {
flex: 1 1 0%;
}
.kadence-builder-area-right .kadence-builder-drop-right, .kadence-builder-drop-left_center {
justify-content:flex-end;
}
.kadence-builder-drop-left_center, .kadence-builder-drop-right_center {
width: 0px;
flex: 0;
overflow: hidden;
}
.kadence-builder-area-center {
min-width: 80px;
border-left: 1px dashed $color-gray-500;
border-right: 1px dashed $color-gray-500;
.kadence-builder-sortable-panel {
justify-content:center;
}
}
.kadence-builder-area-center.kadence-dragging-dropzones {
min-width: 120px;
}
}
.kadence-builder-areas.has-center-items {
.kadence-builder-drop-left_center, .kadence-builder-drop-right_center {
width: auto;
flex: 1;
overflow: auto;
}
.kadence-dragging-dropzones .kadence-builder-drop-left_center {
min-width: 100px;
border-left: 1px dashed $color-gray-500;
}
.kadence-dragging-dropzones .kadence-builder-drop-right_center {
min-width: 100px;
border-right: 1px dashed $color-gray-500;
}
.kadence-builder-area-center {
min-width: 120px;
border-left: 1px dashed $color-gray-500;
border-right: 1px dashed $color-gray-500;
}
}
.kadence-builder-areas .kadence-small-label {
display: none;
}
.kadence-builder-areas.popup-vertical-group {
width: 200px;
padding-right: 20px;
.kadence-builder-group {
height: 100%;
margin-bottom: 0;
}
}
.kadence-builder-areas.popup-vertical-group .kadence-builder-area {
flex: auto;
flex-direction: column;
.kadence-builder-sortable-panel {
min-height: 115px;
align-items: center;
flex-direction: column;
flex-wrap: wrap;
.kadence-builder-item {
width: 90%;
margin-top: 4px;
margin-bottom: 4px;
box-sizing: border-box;
}
}
}
.kadence-builder-item-start button.kadence-builder-item {
border:1px dashed #bbb;
background: #f2f2f2;
cursor: pointer;
box-shadow:none !important;
}
.kadence-builder-item-start button.kadence-builder-item:hover {
border:1px dashed #a2a2a2;
background: #f9f9f9 !important;
}
// Footer.
.kadence-footer-builder-is-active .in-sub-panel:not( .section-open ) ul#sub-accordion-section-kadence_customizer_footer_layout,
.kadence-builder-is-active .in-sub-panel:not( .section-open ) ul#sub-accordion-section-kadence_customizer_header_layout {
transform: none;
height: auto;
visibility: visible;
top: 75px;
}
.kadence-footer-builder-is-active .in-sub-panel:not( .section-open ) ul#sub-accordion-section-kadence_customizer_footer_layout .customize-section-description-container.section-meta,
.kadence-builder-is-active .in-sub-panel:not( .section-open ) ul#sub-accordion-section-kadence_customizer_header_layout .customize-section-description-container.section-meta {
display: none;
}
.kadence-footer-builder-is-active .in-sub-panel:not( .section-open ) #sub-accordion-section-kadence_customizer_footer_layout .customize-section-description-container,
.kadence-builder-is-active .in-sub-panel:not( .section-open ) ul#sub-accordion-section-kadence_customizer_header_layout .customize-section-description-container {
display: none;
}
.kadence-footer-builder-is-active .in-sub-panel:not( .section-open ) #sub-accordion-panel-kadence_customizer_footer .accordion-section.control-section,
.kadence-builder-is-active .in-sub-panel:not( .section-open ) #sub-accordion-panel-kadence_customizer_header .accordion-section.control-section {
display: none !important;
}
.kadence-footer-builder-is-active .preview-desktop #customize-preview, .kadence-footer-builder-is-active .preview-tablet #customize-preview, .kadence-builder-is-active .preview-desktop #customize-preview, .kadence-builder-is-active .preview-tablet #customize-preview {
height: auto;
}
#customize-control-header_mobile_items .kadence-builder-items {
display: flex;
}
#customize-control-header_mobile_items .kadence-builder-row-items {
flex: 1;
}
.customize-control-kadence_builder_control .kadence-builder-items.kadence-builder-items-with-popup {
display: flex;
.kadence-builder-row-items {
flex: 1;
}
}
.kadence-builder-areas button.components-button.kadence-row-actions {
background: $color-primary;
color: #c8dbe4;
text-transform: uppercase;
font-size: 10px;
height: auto;
line-height: 26px;
border-radius: 0;
position: absolute;
top: -26px;
border:0;
opacity: 0;
height: 26px;
padding-top: 0;
padding-bottom: 0;
z-index: 10;
}
.kadence-builder-areas:hover button.components-button.kadence-row-actions {
opacity: 1;
}
.kadence-builder-areas button.components-button.kadence-row-actions svg {
width: 10px;
margin-left: 8px;
}
.kadence-builder-areas button.components-button.kadence-row-actions .dashicons {
width: 10px;
font-size: 10px;
height: 10px;
margin-left: 8px;
}
.kadence-builder-areas button.components-button.kadence-row-actions:hover, .kadence-builder-areas button.components-button.kadence-row-actions:focus {
background: $color-primary !important;
color: white !important;
box-shadow: none !important;
}
.kadence-builder-areas {
position: relative;
}
.kadence-builder-areas:hover .kadence-builder-group-horizontal {
border: 1px solid $color-primary;
}
.kadence-builder-group.kadence-builder-group-horizontal[data-setting="bottom"] {
margin-bottom: 0;
}
.footer-column-row .kadence-builder-area {
flex: 1;
border-right: 1px dashed #A0AEC0;
.kadence-builder-sortable-panel {
justify-content: center;
}
&:first-child .kadence-builder-sortable-panel {
justify-content: flex-start;
}
&:last-child .kadence-builder-sortable-panel {
justify-content: flex-end;
}
}
.footer-column-row .kadence-builder-area:last-child {
border-right: 0;
}
#sub-accordion-section-kadence_customizer_footer_builder .customize-control-kadence_blank_control .kadence-builder-tab-toggle {
top: -4px;
}
#sub-accordion-section-kadence_customizer_footer_builder .customize-control-kadence_blank_control .kadence-builder-show-button.kadence-builder-tab-toggle {
top: auto;
}
.footer-row-columns-2 {
&.footer-row-layout-left-golden {
.kadence-builder-area-1 {
flex: 0 1 66.67%;
}
.kadence-builder-area-2 {
flex: 0 1 33.33%;
}
}
&.footer-row-layout-right-golden {
.kadence-builder-area-1 {
flex: 0 1 33.33%;
}
.kadence-builder-area-2 {
flex: 0 1 66.67%;
}
}
}
.footer-row-columns-3 {
&.footer-row-layout-left-half {
.kadence-builder-area {
flex: 0 1 25%;
}
.kadence-builder-area-1 {
flex: 0 1 50%;
}
}
&.footer-row-layout-right-half {
.kadence-builder-area {
flex: 0 1 25%;
}
.kadence-builder-area-3 {
flex: 0 1 50%;
}
}
&.footer-row-layout-center-half {
.kadence-builder-area {
flex: 0 1 25%;
}
.kadence-builder-area-2 {
flex: 0 1 50%;
}
}
&.footer-row-layout-center-wide {
.kadence-builder-area {
flex: 0 1 20%;
}
.kadence-builder-area-2 {
flex: 0 1 60%;
}
}
&.footer-row-layout-center-exwide {
.kadence-builder-area {
flex: 0 1 15%;
}
.kadence-builder-area-2 {
flex: 0 1 70%;
}
}
}
.footer-row-columns-4 {
&.footer-row-layout-left-forty {
.kadence-builder-area {
flex: 1;
}
.kadence-builder-area-1 {
flex: 2;
}
}
&.footer-row-layout-right-forty {
.kadence-builder-area {
flex: 1;
}
.kadence-builder-area-4 {
flex: 2;
}
}
}
.footer-column-row.footer-row-columns-1 .kadence-builder-area:last-child .kadence-builder-sortable-panel {
justify-content: center;
}
.kadence-builder-areas.footer-row-direction-column .kadence-builder-group-horizontal .kadence-builder-area .kadence-builder-drop {
flex-direction: column;
align-items: normal;
}
.kadence-builder-areas.footer-row-direction-column .kadence-builder-group-horizontal .kadence-builder-area .kadence-builder-drop .kadence-builder-item {
margin: 4px;
}
.kadence-builder-item-start .kadence-builder-item {
border-left:3px solid $color-primary;
}
.kadence-builder-item-start button.kadence-builder-item {
border: 1px solid #fff;
background: #fff;
}
.kadence-builder-item-start button.kadence-builder-item:hover {
border: 1px solid #fff;
background: #fff !important;
}
.kadence-builder-item-start .kadence-builder-item:hover>.kadence-builder-item-icon {
color: $color-primary;
}
.kadence-builder-item>.kadence-builder-item-icon.kadence-move-icon {
margin-left: -10px;
transform: rotate(90deg);
margin-right: 0;
cursor: grab;
width: 18px;
opacity: 0.7;
}
.kadence-builder-item-text {
flex-grow: 1;
}
.kadence-builder-item-start.kadence-move-item .kadence-builder-item {
justify-content:flex-start
}
.customize-control:not(.customize-control-kadence_blank_control) + .customize-control#customize-control-header_mobile_available_items {
padding-top: 0;
border-top: 0;
}
.kadence-available-items-pool {
min-width: 80px;
border: 1px dashed #A0AEC0;
padding: 20px 10px 10px;
}
.kadence-available-items-title {
padding: 10px 0;
}
.kadence-builder-item>.kadence-builder-item-icon.kadence-builder-item-focus-icon svg {width: 14px;}
.kadence-builder-item>.kadence-builder-item-icon.kadence-builder-item-focus-icon .dashicon {
font-size: 14px;
width: 14px;
height: 14px;
}
.kadence-builder-area .kadence-builder-add-item {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.kadence-builder-area {
position: relative;
.kadence-builder-item {
z-index: 10;
}
}
.kadence-builder-area .kadence-builder-item-add-icon {
display: block;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: transparent;
border: 0;
height: auto;
width: auto;
padding: 0;
min-width: 100%;
z-index: 1;
transition: all .2s ease-in-out;
color:transparent !important;
&:hover, &:focus {
color:#444 !important;
background: rgba(0, 124, 186, 0.05)!important;
box-shadow: none !important;
border:0 !important;
}
}
.components-popover.kadence-popover-add-builder.components-animate__appear {
left: 50% !important;
top: 0 !important;
position: absolute;
bottom: auto;
}
.components-popover__content .kadence-popover-builder-list .kadence-radio-container-control {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 10px;
width: 300px;
}
.kadence-popover-builder-list {
padding: 0 10px;
.kadence-radio-container-control button.components-button.is-tertiary {
font-size: 10px;
margin: 0;
}
}
.kadence-builder-area .kadence-builder-item-add-icon svg {
margin-top: 5px;
}
.kadence-builder-area-center .kadence-builder-drop-center .kadence-builder-item:first-child {
margin-left: 25px;
}
.kadence-builder-area-center .kadence-builder-drop-center .kadence-builder-item:last-child {
margin-right: 25px;
}
.kadence-builder-areas.has-center-items .kadence-builder-add-item.center-on-right {
right:50%;
}
.kadence-builder-areas.has-center-items .kadence-builder-add-item.center-on-right .kadence-builder-item-add-icon {
text-align:right;
padding-right:30px;
}
.kadence-builder-areas.has-center-items .kadence-builder-add-item.center-on-left {
left:50%;
}
.kadence-builder-areas.has-center-items .kadence-builder-add-item.center-on-left .kadence-builder-item-add-icon {
text-align:left;
padding-left:30px;
}
.kadence-builder-area .kadence-builder-add-item.left-center-on-left, .kadence-builder-area .kadence-builder-add-item.right-center-on-right {
display: none;
}
.kadence-builder-areas.has-center-items .kadence-builder-add-item.left-center-on-left {
display:block;
right: 50%;
}
.kadence-builder-areas.has-center-items .kadence-builder-add-item.right-center-on-right {
display:block;
left: 50%;
}

View File

@@ -0,0 +1,131 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import Icons from '../common/icons.js';
import { __ } from '@wordpress/i18n';
const { ButtonGroup, Dashicon, Tooltip, Button } = wp.components;
const { Component, Fragment } = wp.element;
class CheckIconComponent extends Component {
constructor() {
super( ...arguments );
this.updateValues = this.updateValues.bind( this );
let value = this.props.control.setting.get();
let defaultParams = {
options: {
desktop: {
name: __( 'Desktop', 'kadence' ),
icon: 'desktop',
},
tablet: {
name: __( 'Tablet', 'kadence' ),
icon: 'tablet',
},
mobile: {
name: __( 'Mobile', 'kadence' ),
icon: 'smartphone',
},
},
};
this.controlParams = this.props.control.params.input_attrs ? {
...defaultParams,
...this.props.control.params.input_attrs,
} : defaultParams;
let baseDefault = {
'mobile': true,
'tablet': true,
'desktop': true,
};
this.defaultValue = this.props.control.params.default ? this.props.control.params.default : baseDefault;
value = value ? {
...JSON.parse( JSON.stringify( this.defaultValue ) ),
...value
} : JSON.parse( JSON.stringify( this.defaultValue ) );
this.state = {
value: value,
};
}
render() {
const controlLabel = (
<Fragment>
<Tooltip text={ __( 'Reset Values', 'kadence' ) }>
<Button
className="reset kadence-reset"
disabled={ ( this.state.value == this.defaultValue ) }
onClick={ () => {
let value = this.defaultValue;
this.setState( { value: this.defaultValue } );
this.updateValues( value );
} }
>
<Dashicon icon='image-rotate' />
</Button>
</Tooltip>
{ this.props.control.params.label &&
this.props.control.params.label
}
</Fragment>
);
return (
<div className="kadence-control-field kadence-radio-icon-control">
<div className="kadence-responsive-control-bar">
<span className="customize-control-title">{ controlLabel }</span>
</div>
<ButtonGroup className="kadence-radio-container-control">
{ Object.keys( this.controlParams.options ).map( ( item ) => {
return (
<Fragment>
<Tooltip text={ this.controlParams.options[ item ].name }>
<Button
isTertiary
className={ ( true === this.state.value[ item ] ?
'active-radio ' :
'' ) + item }
onClick={ () => {
let value = this.state.value;
if( value[ item ] ) {
value[ item ] = false;
} else {
value[ item ] = true;
}
this.setState( { value: value });
this.updateValues( value );
} }
>
{ this.controlParams.options[ item ].icon && (
<span className="kadence-radio-icon">
{ <Dashicon icon={this.controlParams.options[ item ].icon}/> }
</span>
) }
{ ! this.controlParams.options[ item ].icon && (
<span className="kadence-radio-name">
{ this.controlParams.options[ item ].name }
</span>
) }
</Button>
</Tooltip>
</Fragment>
);
} )}
</ButtonGroup>
{ this.props.control.renderNotice() }
</div>
);
}
updateValues( value ) {
this.props.control.setting.set( {
...this.props.control.setting.get(),
...value,
flag: !this.props.control.setting.get().flag
} );
}
}
CheckIconComponent.propTypes = {
control: PropTypes.object.isRequired
};
export default CheckIconComponent;

View File

@@ -0,0 +1,14 @@
import { createRoot } from '@wordpress/element';
import CheckIconComponent from './check-icon-component.js';
export const CheckIconControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <CheckIconComponent control={control}/> );
// ReactDOM.render(
// <CheckIconComponent control={control}/>,
// control.container[0]
// );
}
} );

View File

@@ -0,0 +1,169 @@
import PropTypes from 'prop-types';
import { __ } from '@wordpress/i18n';
const { SelectControl } = wp.components;
import ColorControl from '../common/color.js';
/**
* WordPress dependencies
*/
import { createRef, Component, Fragment } from '@wordpress/element';
class ColorLinkComponent extends Component {
constructor(props) {
super( props );
this.handleChangeComplete = this.handleChangeComplete.bind( this );
this.updateValues = this.updateValues.bind( this );
let value = this.props.control.setting.get();
let baseDefault = {
'highlight': '',
'highlight-alt': '',
'highlight-alt2': '',
'style': 'standard',
};
this.defaultValue = this.props.control.params.default ? {
...baseDefault,
...this.props.control.params.default
} : baseDefault;
value = value ? {
...this.defaultValue,
...value
} : this.defaultValue;
let defaultParams = {
colors: {
'highlight': {
tooltip: __( 'Initial', 'kadence' ),
palette: true,
},
'highlight-alt': {
tooltip: __( 'Hover', 'kadence' ),
palette: true,
},
'highlight-alt2': {
tooltip: __( 'Text Alt', 'kadence' ),
palette: true,
},
},
styles: {
'standard': {
label: __( 'Standard (underline)', 'kadence' ),
},
'color-underline': {
label: __( 'Highlight Underline', 'kadence' ),
},
'no-underline': {
label: __( 'No Underline', 'kadence' ),
},
'hover-background': {
label: __( 'Background on Hover', 'kadence' ),
},
'offset-background': {
label: __( 'Offset Background', 'kadence' ),
},
},
};
this.controlParams = this.props.control.params.input_attrs ? {
...defaultParams,
...this.props.control.params.input_attrs,
} : defaultParams;
const palette = JSON.parse( this.props.customizer.control( 'kadence_color_palette' ).setting.get() );
this.state = {
value: value,
colorPalette: palette,
};
this.anchorNodeRef = createRef();
}
handleChangeComplete( color, isPalette, item ) {
let value = this.state.value;
if ( isPalette ) {
value[ item ] = isPalette;
} else if ( undefined !== color.rgb && undefined !== color.rgb.a && 1 !== color.rgb.a ) {
value[ item ] = 'rgba(' + color.rgb.r + ',' + color.rgb.g + ',' + color.rgb.b + ',' + color.rgb.a + ')';
} else {
value[ item ] = color.hex;
}
document.documentElement.style.setProperty('--global-palette-' + item, value[ item ] );
this.updateValues( value );
}
render() {
const styleOptions = Object.keys( this.controlParams.styles ).map( ( item ) => {
return ( { label: this.controlParams.styles[ item ].label, value: item } );
} );
const hoverBackgroundColors = {
'highlight': {
tooltip: __( 'Initial/Background', 'kadence' ),
palette: true,
},
'highlight-alt': {
tooltip: __( 'Unused', 'kadence' ),
palette: true,
},
'highlight-alt2': {
tooltip: __( 'Text Hover', 'kadence' ),
palette: true,
},
};
// Use special color labels for hover background;
const colorsToUse = this.state.value.style === 'hover-background' ? hoverBackgroundColors : this.controlParams.colors;
return (
<Fragment>
<div className="kadence-control-field kadence-color-control kadence-link-color-control">
<span className="customize-control-title">
{ __( 'Link Style', 'kadence' ) }
</span>
<SelectControl
value={ this.state.value.style }
options={ styleOptions }
onChange={ ( val ) => {
let value = this.state.value;
value.style = val;
this.updateValues( value );
} }
/>
</div>
<div ref={ this.anchorNodeRef } className="kadence-control-field kadence-color-control kadence-link-color-control">
{
this.props.control.params.label &&
<span className="customize-control-title">
{ this.props.control.params.label }
</span>
}
{ Object.keys( colorsToUse ).map( ( item ) => {
if ( ( this.state.value.style === 'standard' || this.state.value.style === 'color-underline' || this.state.value.style === 'no-underline' ) && item === 'highlight-alt2' ) {
return;
}
return (
<ColorControl
key={ item }
presetColors={ this.state.colorPalette }
color={ ( undefined !== this.state.value[ item ] && this.state.value[ item ] ? this.state.value[ item ] : '' ) }
usePalette={ ( undefined !== colorsToUse[ item ] && undefined !== colorsToUse[ item ].palette && '' !== colorsToUse[ item ].palette ? colorsToUse[ item ].palette : true ) }
tooltip={ ( undefined !== colorsToUse[ item ] && undefined !== colorsToUse[ item ].tooltip ? colorsToUse[ item ].tooltip : '' ) }
onChangeComplete={ ( color, isPalette ) => this.handleChangeComplete( color, isPalette, item ) }
customizer={ this.props.customizer }
controlRef={ this.anchorNodeRef }
/>
)
} ) }
</div>
{ this.props.control.renderNotice() }
</Fragment>
);
}
updateValues( value ) {
this.setState( { value: value } );
this.props.control.setting.set( {
...this.props.control.setting.get(),
...value,
} );
}
}
ColorLinkComponent.propTypes = {
control: PropTypes.object.isRequired,
customizer: PropTypes.object.isRequired
};
export default ColorLinkComponent;

View File

@@ -0,0 +1,14 @@
import { createRoot } from '@wordpress/element';
import ColorLinkComponent from './color-link-component.js';
export const ColorLinkControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <ColorLinkComponent control={control} customizer={ wp.customize }/> );
// ReactDOM.render(
// <ColorLinkComponent control={control} customizer={ wp.customize }/>,
// control.container[0]
// );
}
} );

View File

@@ -0,0 +1,176 @@
import PropTypes from "prop-types";
import { isEqual } from "lodash";
import { __ } from "@wordpress/i18n";
const { Tooltip, Button, Dashicon } = wp.components;
/**
* WordPress dependencies
*/
import { createRef, Component, Fragment } from "@wordpress/element";
import ColorControl from "../common/color.js";
class ColorComponent extends Component {
constructor(props) {
super(props);
this.handleChangeComplete = this.handleChangeComplete.bind(this);
this.updateValues = this.updateValues.bind(this);
let value = this.props.control.setting.get();
let baseDefault = {
color: "",
hover: "",
};
this.defaultValue = this.props.control.params.default
? {
...baseDefault,
...this.props.control.params.default,
}
: baseDefault;
value = value
? {
...JSON.parse(JSON.stringify(this.defaultValue)),
...value,
}
: JSON.parse(JSON.stringify(this.defaultValue));
let defaultParams = {
colors: {
color: {
tooltip: __("Color", "kadence"),
palette: true,
},
hover: {
tooltip: __("Hover Color", "kadence"),
palette: true,
},
},
allowGradient: false,
};
this.controlParams = this.props.control.params.input_attrs
? {
...defaultParams,
...this.props.control.params.input_attrs,
}
: defaultParams;
const palette = JSON.parse(
this.props.customizer.control("kadence_color_palette").setting.get()
);
//console.log( palette );
this.state = {
value: value,
colorPalette: palette,
};
this.anchorNodeRef = createRef();
}
handleChangeComplete(color, isPalette, item) {
let value = this.state.value;
if (isPalette) {
value[item] = isPalette;
} else if (typeof color === "string" || color instanceof String) {
value[item] = color;
} else if (
undefined !== color.rgb &&
undefined !== color.rgb.a &&
1 !== color.rgb.a
) {
value[item] =
"rgba(" +
color.rgb.r +
"," +
color.rgb.g +
"," +
color.rgb.b +
"," +
color.rgb.a +
")";
} else {
value[item] = color.hex;
}
this.updateValues(value);
}
render() {
return (
<div
ref={this.anchorNodeRef}
className="kadence-control-field kadence-color-control"
>
<span className="customize-control-title">
<Fragment>
<Tooltip text={__("Reset Values", "kadence")}>
<Button
className="reset kadence-reset"
disabled={
JSON.stringify(this.state.value) ===
JSON.stringify(this.defaultValue)
}
onClick={() => {
let value = JSON.parse(
JSON.stringify(this.defaultValue)
);
this.updateValues(value);
}}
>
<Dashicon icon="image-rotate" />
</Button>
</Tooltip>
{this.props.control.params.label &&
this.props.control.params.label}
</Fragment>
</span>
{Object.keys(this.controlParams.colors).map((item) => {
return (
<ColorControl
key={item}
presetColors={this.state.colorPalette}
color={
undefined !== this.state.value[item] &&
this.state.value[item]
? this.state.value[item]
: ""
}
usePalette={
undefined !== this.controlParams.colors[item] &&
undefined !==
this.controlParams.colors[item].palette &&
"" !== this.controlParams.colors[item].palette
? this.controlParams.colors[item].palette
: true
}
tooltip={
undefined !== this.controlParams.colors[item] &&
undefined !==
this.controlParams.colors[item].tooltip
? this.controlParams.colors[item].tooltip
: ""
}
onChangeComplete={(color, isPalette) =>
this.handleChangeComplete(
color,
isPalette,
item
)
}
customizer={this.props.customizer}
allowGradient={this.controlParams.allowGradient}
controlRef={this.anchorNodeRef}
/>
);
})}
{ this.props.control.renderNotice() }
</div>
);
}
updateValues(value) {
this.setState({ value: value });
this.props.control.setting.set({
...this.props.control.setting.get(),
...value,
});
}
}
ColorComponent.propTypes = {
control: PropTypes.object.isRequired,
customizer: PropTypes.object.isRequired,
};
export default ColorComponent;

View File

@@ -0,0 +1,14 @@
import { createRoot } from '@wordpress/element';
import ColorComponent from './color-component.js';
export const ColorControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <ColorComponent control={control} customizer={ wp.customize }/> );
// ReactDOM.render(
// <ColorComponent control={control} customizer={ wp.customize }/>,
// control.container[0]
// );
}
} );

View File

@@ -0,0 +1,8 @@
/**
* function to return string with capital letter.
* @param {string} string the word string.
* @returns {string} with capital letter.
*/
export default function capitalizeFirstLetter( string ) {
return string.charAt( 0 ).toUpperCase() + string.slice( 1 );
}

View File

@@ -0,0 +1,210 @@
import color from 'react-color/lib/helpers/color'
import { EditableInput } from 'react-color/lib/components/common'
const {
Component,
Fragment
} = wp.element;
const {
Dashicon,
} = wp.components;
class PickerFields extends Component {
constructor(props) {
super( props );
this.toggleViews = this.toggleViews.bind( this );
this.handleChange = this.handleChange.bind( this );
this.state = {
view: 'rgb',
};
}
toggleViews() {
if ( this.state.view === 'hsl' ) {
this.setState({ view: 'rgb' })
} else if (this.state.view === 'rgb') {
this.setState({ view: 'hsl' })
}
}
handleChange(data, e) {
if (data.hex) {
color.isValidHex(data.hex) && this.props.onChange({
hex: data.hex,
source: 'hex',
}, e)
} else if (data.r || data.g || data.b) {
this.props.onChange({
r: data.r || this.props.rgb.r,
g: data.g || this.props.rgb.g,
b: data.b || this.props.rgb.b,
a: this.props.rgb.a,
source: 'rgb',
}, e)
} else if (data.a) {
if (data.a < 0) {
data.a = 0
} else if (data.a > 1) {
data.a = 1
}
this.props.onChange({
h: this.props.hsl.h,
s: this.props.hsl.s,
l: this.props.hsl.l,
a: Math.round(data.a * 100) / 100,
source: 'rgb',
}, e)
} else if (data.h || data.s || data.l) {
// Remove any occurances of '%'.
if (typeof(data.s) === 'string') { data.s = data.s.replace('%', '') }
if (typeof(data.l) === 'string') { data.l = data.l.replace('%', '') }
this.props.onChange({
h: data.h || this.props.hsl.h || 0,
s: Number((data.s && data.s / 100) || this.props.hsl.s || 0.0 ),
l: Number((data.l && data.l / 100) || this.props.hsl.l || 0.0 ),
a: Math.round(data.a * 100) / 100 || this.props.rgb.a || 1,
source: 'hsl',
}, e)
}
}
render() {
const styles = {
fields: {
display: 'flex',
paddingTop: '4px',
},
single: {
flex: '1',
paddingLeft: '6px',
},
alpha: {
flex: '1',
paddingLeft: '6px',
},
double: {
flex: '2',
},
input: {
width: '100%',
padding: '4px 10% 3px',
border: 'none',
borderRadius: '2px',
boxShadow: 'rgb(218, 218, 218) 0px 0px 0px 1px inset',
fontSize: '11px',
},
label: {
display: 'block',
textAlign: 'center',
fontSize: '11px',
color: '#222',
paddingTop: '3px',
paddingBottom: '4px',
textTransform: 'capitalize',
},
toggle: {
width: '32px',
textAlign: 'right',
position: 'relative',
},
}
return (
<div style={ styles.fields } className="flexbox-fix">
<div style={ styles.double }>
<EditableInput
style={{ input: styles.input, label: styles.label }}
label="hex"
value={ this.props.hex.replace('#', '') }
onChange={ this.handleChange }
/>
</div>
{ this.state.view === 'rgb' && (
<Fragment>
<div style={ styles.single }>
<EditableInput
style={{ input: styles.input, label: styles.label }}
label="r"
value={ this.props.rgb.r }
onChange={ this.handleChange }
dragLabel="true"
dragMax="255"
/>
</div>
<div style={ styles.single }>
<EditableInput
style={{ input: styles.input, label: styles.label }}
label="g"
value={ this.props.rgb.g }
onChange={ this.handleChange }
dragLabel="true"
dragMax="255"
/>
</div>
<div style={ styles.single }>
<EditableInput
style={{ input: styles.input, label: styles.label }}
label="b"
value={ this.props.rgb.b }
onChange={ this.handleChange }
dragLabel="true"
dragMax="255"
/>
</div>
<div style={ styles.alpha }>
<EditableInput
style={{ input: styles.input, label: styles.label }}
label="a"
value={ this.props.rgb.a }
arrowOffset={ 0.01 }
onChange={ this.handleChange }
/>
</div>
</Fragment>
) }
{ this.state.view === 'hsl' && (
<Fragment>
<div style={ styles.single }>
<EditableInput
style={{ input: styles.input, label: styles.label }}
label="h"
value={ Math.round(this.props.hsl.h) }
onChange={ this.handleChange }
dragLabel="true"
dragMax="359"
/>
</div>
<div style={ styles.single }>
<EditableInput
style={{ input: styles.input, label: styles.label }}
label="s"
value={ `${ Math.round( this.props.hsl.s * 100 ) }` }
onChange={ this.handleChange }
/>
</div>
<div style={ styles.single }>
<EditableInput
style={{ input: styles.input, label: styles.label }}
label="l"
value={ `${ Math.round(this.props.hsl.l * 100) }` }
onChange={ this.handleChange }
/>
</div>
<div style={ styles.alpha }>
<EditableInput
style={{ input: styles.input, label: styles.label }}
label="a"
value={ this.props.hsl.a }
arrowOffset={ 0.01 }
onChange={ this.handleChange }
/>
</div>
</Fragment>
) }
<div style={ styles.toggle }>
<div className="toggle-icons" style={ styles.icon } onClick={ this.toggleViews } ref={ (icon) => this.icon = icon }>
<Dashicon icon="arrow-up-alt2" />
<Dashicon icon="arrow-down-alt2" />
</div>
</div>
</div>
);
}
}
export default PickerFields

View File

@@ -0,0 +1,128 @@
import { CustomPicker } from 'react-color'
import { EditableInput, Hue, Saturation, Alpha, Checkboard } from 'react-color/lib/components/common'
import { ChromePointerCircle } from 'react-color/lib/components/chrome/ChromePointerCircle'
import { ChromePointer } from 'react-color/lib/components/chrome/ChromePointer'
import PickerFields from './color-picker-fields'
export const KadenceColorPicker = ({ rgb, hex, hsv, hsl, onChange, renderers }) => {
const styles = {
picker: {
width: 300,
position: 'relative',
marginBottom: 10,
},
hue: {
height: 10,
position: 'relative',
marginBottom: '8px',
},
Hue: {
radius: '2px',
},
alpha: {
height: '10px',
position: 'relative',
},
Alpha: {
radius: '2px',
},
input: {
height: 34,
border: `1px solid ${ hex }`,
paddingLeft: 10,
},
body: {
padding: '10px 0',
},
controls: {
display: 'flex',
},
color: {
width: '30px',
height: '30px',
position: 'relative',
marginTop: '3px',
marginLeft: '10px',
borderRadius: '50%',
overflow: 'hidden',
},
activeColor: {
position: 'absolute',
left:0,
right:0,
top:0,
bottom:0,
borderRadius: '50%',
background: `rgba(${ rgb.r },${ rgb.g },${ rgb.b },${ rgb.a })`,
boxShadow: 'inset 0 0 0 1px rgba(0,0,0,.1)',
},
swatch: {
width: 54,
height: 38,
background: hex,
},
sliders: {
padding: '4px 0',
flex: '1',
},
saturation: {
width: '100%',
paddingBottom: '40%',
position: 'relative',
overflow: 'hidden',
},
Saturation: {
radius: '2px 2px 0 0',
shadow: 'inset 0 0 0 1px rgba(0,0,0,.15), inset 0 0 4px rgba(0,0,0,.25)',
},
}
return (
<div style={ styles.picker } className={ 'kadence-picker' }>
<div style={ styles.saturation }>
<Saturation
style={ styles.Saturation }
hsl={ hsl }
hsv={ hsv }
pointer={ ChromePointerCircle }
onChange={ onChange }
/>
</div>
<div style={ styles.body }>
<div style={ styles.controls } className="flexbox-fix">
<div style={ styles.sliders }>
<div style={ styles.hue }>
<Hue
style={ styles.Hue }
hsl={ hsl }
onChange={ onChange }
pointer={ ChromePointer }
/>
</div>
<div style={ styles.alpha }>
<Alpha
style={ styles.Alpha }
rgb={ rgb }
hsl={ hsl }
renderers={ renderers }
pointer={ ChromePointer }
onChange={ onChange }
/>
</div>
</div>
<div style={ styles.color }>
<Checkboard />
<div style={ styles.activeColor } />
</div>
</div>
</div>
<PickerFields
rgb={ rgb }
hsl={ hsl }
hex={ hex }
onChange={ onChange }
/>
</div>
)
}
export default CustomPicker(KadenceColorPicker)

View File

@@ -0,0 +1,752 @@
import PropTypes from "prop-types";
import SwatchesControl from "./swatches";
import KadenceColorPicker from "./color-picker";
import Icons from "./icons";
import { __ } from "@wordpress/i18n";
const { Component, Fragment } = wp.element;
const {
Button,
Popover,
Dashicon,
ColorIndicator,
Tooltip,
Icon,
TabPanel,
GradientPicker,
__experimentalGradientPicker,
} = wp.components;
import KadenceGradientPicker from "../gradient-control/index.js";
class ColorControl extends Component {
constructor(props) {
super(props);
this.onChangeState = this.onChangeState.bind(this);
this.onChangeComplete = this.onChangeComplete.bind(this);
this.onChangeGradientComplete =
this.onChangeGradientComplete.bind(this);
this.state = {
isVisible: false,
refresh: false,
stateColor: this.props.color,
color: this.props.color,
isPalette:
this.props.color &&
this.props.color.includes("palette") &&
!this.props.color.includes("gradient")
? true
: false,
palette:
this.props.presetColors && this.props.presetColors
? this.props.presetColors
: [],
activePalette:
this.props.presetColors && this.props.presetColors.active
? this.props.presetColors.active
: "palette",
supportGradient:
undefined === GradientPicker &&
undefined === __experimentalGradientPicker
? false
: true,
showSyncMessage: true,
};
}
render() {
// Helper function to check if we should show sync message
const shouldShowSyncMessage = () => {
return (
this.props.paletteName === "palette10" &&
this.props.color === "#FfFfFf" &&
this.state.showSyncMessage === true
);
};
const shouldShowResyncMessage = () => {
return (
this.props.paletteName === "palette10" &&
this.props.color !== "#FfFfFf" &&
this.state.showSyncMessage === false
);
};
const toggleVisible = () => {
if (this.props.usePalette) {
const updateColors = JSON.parse(
this.props.customizer
.control("kadence_color_palette")
.setting.get()
);
const active =
updateColors && updateColors.active
? updateColors.active
: "palette";
this.setState({ palette: updateColors, activePalette: active });
}
if (this.state.refresh === true) {
this.setState({ refresh: false });
} else {
this.setState({ refresh: true });
}
this.setState({ isVisible: true });
};
const toggleClose = () => {
if (this.state.isVisible === true) {
this.setState({ isVisible: false });
}
};
const position = this.props.position
? this.props.position
: "bottom right";
const showingGradient =
this.props.allowGradient && this.state.supportGradient
? true
: false;
const syncMessageContent = () => {
return (
<div
className="kadence-sync-message"
style={{ padding: "16px", textAlign: "center" }}
>
<p>
{__(
"This color is currently linked as the compliment to your accent color.",
"kadence"
)}
</p>
<Button
onClick={() =>
this.setState({ showSyncMessage: false })
}
variant="secondary"
isSmall
>
{__("Unlink Color", "kadence")}
</Button>
</div>
);
};
const resyncMessageContent = () => {
return (
<div
className="kadence-sync-message"
style={{ padding: "16px", textAlign: "center" }}
>
<Button
onClick={() => {
this.setState({ showSyncMessage: true });
this.onChangeState({ hex: "#FfFfFf" }, "");
this.props.onChangeComplete({ hex: "#FfFfFf" }, "");
}}
variant="secondary"
isSmall
>
{__("Link Color", "kadence")}
</Button>
</div>
);
};
const paletteIndexRegex = this.state.color?.match(/\d+$/)?.[0] - 1;
const paletteIndex = this.state.isPalette
? paletteIndexRegex
: undefined;
return (
<div
className={"kadence-color-picker-wrap " + this.props.className}
>
{this.props.colorDefault &&
this.props.color &&
this.props.color !== this.props.colorDefault && (
<Tooltip text={__("Clear")}>
<span className="tooltip-clear">
<Button
className="components-color-palette__clear"
type="button"
onClick={() => {
this.setState({
color: this.props.colorDefault,
isPalette: "",
});
this.props.onChangeComplete("", "");
}}
isSmall
>
<Dashicon icon="redo" />
</Button>
</span>
</Tooltip>
)}
{showingGradient && (
<Fragment>
{this.state.isVisible && (
<Popover
position={position}
inline={true}
anchor={
undefined !==
this.props?.controlRef?.current
? this.props.controlRef.current
: undefined
}
className="kadence-popover-color kadence-popover-color-gradient kadence-customizer-popover"
onClose={toggleClose}
>
{shouldShowSyncMessage() ? (
syncMessageContent()
) : (
<TabPanel
className="kadence-popover-tabs kadence-background-tabs"
activeClass="active-tab"
initialTabName={
this.state.color &&
this.state.color.includes(
"gradient"
)
? "gradient"
: "color"
}
tabs={[
{
name: "color",
title: __("Color", "kadence"),
className:
"kadence-color-background",
},
{
name: "gradient",
title: __(
"Gradient",
"kadence"
),
className:
"kadence-gradient-background",
},
]}
>
{(tab) => {
let tabout;
if (tab.name) {
if ("gradient" === tab.name) {
tabout = (
<Fragment>
<KadenceGradientPicker
value={
this.state
.color &&
this.state.color.includes(
"gradient"
)
? this
.state
.color
: ""
}
onChange={(
gradient
) =>
this.onChangeGradientComplete(
gradient
)
}
activePalette={
this.state
.palette &&
this.state
.palette[
this
.state
.activePalette
]
? this
.state
.palette[
this
.state
.activePalette
]
: []
}
/>
</Fragment>
);
} else {
tabout = (
<Fragment>
{this.state
.refresh && (
<Fragment>
<KadenceColorPicker
color={
this
.state
.isPalette &&
this
.state
.palette
.palette &&
this
.state
.palette
.palette[
paletteIndex
]
? this
.state
.palette
.palette[
paletteIndex
]
?.color
: this
.state
.color
}
onChange={(
color
) =>
this.onChangeState(
color,
""
)
}
onChangeComplete={(
color
) =>
this.onChangeComplete(
color,
""
)
}
/>
{this.props
.usePalette && (
<SwatchesControl
colors={
this
.state
.palette &&
this
.state
.palette[
this
.state
.activePalette
]
? this
.state
.palette[
this
.state
.activePalette
]
: []
}
isPalette={
this
.state
.isPalette
? this
.state
.color
: ""
}
onClick={(
color,
palette
) =>
this.onChangeComplete(
color,
palette
)
}
/>
)}
</Fragment>
)}
{!this.state
.refresh && (
<Fragment>
<KadenceColorPicker
//presetColors={ [] }
color={
this
.state
.isPalette &&
this
.state
.palette[
this
.state
.activePalette
] &&
this
.state
.palette[
this
.state
.activePalette
][
paletteIndex
]
? this
.state
.palette[
this
.state
.activePalette
][
paletteIndex
]
?.color
: this
.state
.color
}
onChange={(
color
) =>
this.onChangeState(
color,
""
)
}
onChangeComplete={(
color
) =>
this.onChangeComplete(
color,
""
)
}
//width={ 300 }
//styles={ styleing }
/>
{this.props
.usePalette && (
<SwatchesControl
colors={
this
.state
.palette &&
this
.state
.palette[
this
.state
.activePalette
]
? this
.state
.palette[
this
.state
.activePalette
]
: []
}
isPalette={
this
.state
.isPalette
? this
.state
.color
: ""
}
onClick={(
color,
palette
) =>
this.onChangeComplete(
color,
palette
)
}
/>
)}
</Fragment>
)}
</Fragment>
);
}
}
return (
<div>
{tabout}
{shouldShowResyncMessage()
? resyncMessageContent()
: ""}
</div>
);
}}
</TabPanel>
)}
</Popover>
)}
</Fragment>
)}
{!showingGradient && (
<Fragment>
{this.state.isVisible && this.state.refresh && (
<Popover
position="top right"
inline={true}
anchor={
undefined !==
this.props?.controlRef?.current
? this.props.controlRef.current
: undefined
}
className="kadence-popover-color kadence-customizer-popover"
onClose={toggleClose}
>
{shouldShowSyncMessage() ? (
syncMessageContent()
) : (
<Fragment>
<KadenceColorPicker
color={
this.state.isPalette &&
this.state.palette.palette &&
this.state.palette.palette[
paletteIndex
]
? this.state.palette
.palette[
paletteIndex
]?.color
: this.state.color
}
onChange={(color) =>
this.onChangeState(color, "")
}
onChangeComplete={(color) =>
this.onChangeComplete(color, "")
}
/>
{this.props.usePalette && (
<SwatchesControl
colors={
this.state.palette &&
this.state.palette[
this.state.activePalette
]
? this.state.palette[
this.state
.activePalette
]
: []
}
isPalette={
this.state.isPalette
? this.state.color
: ""
}
onClick={(color, palette) =>
this.onChangeComplete(
color,
palette
)
}
/>
)}
{shouldShowResyncMessage()
? resyncMessageContent()
: ""}
</Fragment>
)}
</Popover>
)}
{this.state.isVisible && !this.state.refresh && (
<Popover
position={position}
inline={true}
anchor={
undefined !==
this.props?.controlRef?.current
? this.props.controlRef.current
: undefined
}
className="kadence-popover-color kadence-customizer-popover"
onClose={toggleClose}
>
{shouldShowSyncMessage() ? (
syncMessageContent()
) : (
<Fragment>
<KadenceColorPicker
//presetColors={ [] }
color={
this.state.isPalette &&
this.state.palette[
this.state.activePalette
] &&
this.state.palette[
this.state.activePalette
][paletteIndex]
? this.state.palette[
this.state
.activePalette
][paletteIndex]?.color
: this.state.color
}
onChange={(color) =>
this.onChangeState(color, "")
}
onChangeComplete={(color) =>
this.onChangeComplete(color, "")
}
//width={ 300 }
//styles={ styleing }
/>
{this.props.usePalette && (
<SwatchesControl
colors={
this.state.palette &&
this.state.palette[
this.state.activePalette
]
? this.state.palette[
this.state
.activePalette
]
: []
}
isPalette={
this.state.isPalette
? this.state.color
: ""
}
onClick={(color, palette) =>
this.onChangeComplete(
color,
palette
)
}
/>
)}
{shouldShowResyncMessage()
? resyncMessageContent()
: ""}
</Fragment>
)}
</Popover>
)}
</Fragment>
)}
<Tooltip
text={
this.props.tooltip
? this.props.tooltip
: __("Select Color", "kadence")
}
>
<div className="color-button-wrap">
<Button
className={"kadence-color-icon-indicate"}
onClick={() => {
this.state.isVisible
? toggleClose()
: toggleVisible();
}}
disabled={this.props.disabled}
>
<ColorIndicator
className="kadence-advanced-color-indicate"
colorValue={
this.state.isPalette
? "var(--global-" +
this.props.color +
")"
: this.props.color
}
/>
{this.state.isPalette && (
<Icon className="dashicon" icon={Icons.globe} />
)}
</Button>
</div>
</Tooltip>
</div>
);
}
onChangeState(color, palette) {
let newColor;
if (palette) {
newColor = palette;
} else if (
undefined !== color.rgb &&
undefined !== color.rgb.a &&
1 !== color.rgb.a
) {
newColor =
"rgba(" +
color.rgb.r +
"," +
color.rgb.g +
"," +
color.rgb.b +
"," +
color.rgb.a +
")";
} else {
newColor = color.hex;
}
this.setState({ color: newColor, isPalette: palette ? true : false });
if (undefined !== this.props.onChange) {
this.props.onChange(color, palette);
}
}
onChangeGradientComplete(gradient) {
let newColor;
if (undefined === gradient) {
newColor = "";
} else {
newColor = gradient;
}
this.setState({ color: newColor, isPalette: false });
this.props.onChangeComplete(newColor, "");
}
onChangeComplete(color, palette) {
let newColor;
if (palette) {
newColor = palette;
} else if (
undefined !== color.rgb &&
undefined !== color.rgb.a &&
1 !== color.rgb.a
) {
newColor =
"rgba(" +
color.rgb.r +
"," +
color.rgb.g +
"," +
color.rgb.b +
"," +
color.rgb.a +
")";
} else {
newColor = color.hex;
}
this.setState({ color: newColor, isPalette: palette ? true : false });
this.props.onChangeComplete(color, palette);
}
}
ColorControl.propTypes = {
color: PropTypes.string,
usePalette: PropTypes.bool,
palette: PropTypes.string,
presetColors: PropTypes.array,
onChangeComplete: PropTypes.func,
onChange: PropTypes.func,
customizer: PropTypes.object,
};
export default ColorControl;

View File

@@ -0,0 +1,92 @@
if ( kadencegooglefonts === undefined ) {
var kadencegooglefonts = [];
}
const {
Component,
} = wp.element;
import PropTypes from "prop-types";
import WebFont from "webfontloader";
const statuses = {
inactive: 'inactive',
active: 'active',
loading: 'loading',
};
const noop = () => {};
class KadenceWebfontLoader extends Component {
constructor(props) {
super( props );
this.handleLoading = this.handleLoading.bind( this );
this.handleActive = this.handleActive.bind( this );
this.addFont = this.addFont.bind( this );
this.handleInactive = this.handleInactive.bind( this );
this.loadFonts = this.loadFonts.bind( this );
this.state = {
status: undefined,
};
}
addFont( font ) {
if ( ! kadencegooglefonts.includes( font ) ) {
kadencegooglefonts.push( font );
}
};
handleLoading() {
this.setState( { status: statuses.loading } );
};
handleActive() {
this.setState( { status: statuses.active } );
};
handleInactive() {
this.setState( { status: statuses.inactive } );
};
loadFonts() {
//if ( ! this.state.fonts.includes( this.props.config.google.families[ 0 ] ) ) {
if ( ! kadencegooglefonts.includes( this.props.config.google.families[ 0 ] ) ) {
WebFont.load( {
...this.props.config,
loading: this.handleLoading,
active: this.handleActive,
inactive: this.handleInactive,
} );
this.addFont( this.props.config.google.families[ 0 ] );
}
}
componentDidMount() {
this.loadFonts();
}
componentDidUpdate( prevProps, prevState ) {
const { onStatus, config } = this.props;
if ( prevState.status !== this.state.status ) {
onStatus( this.state.status );
}
if ( prevProps.config !== config ) {
this.loadFonts();
}
}
render() {
const { children } = this.props;
return children || null;
}
}
KadenceWebfontLoader.propTypes = {
config: PropTypes.object.isRequired,
children: PropTypes.element,
onStatus: PropTypes.func.isRequired,
};
KadenceWebfontLoader.defaultProps = {
onStatus: noop,
};
export default KadenceWebfontLoader;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,93 @@
const { RangeControl } = wp.components;
const { useInstanceId } = wp.compose;
/**
* Build the Measure controls
* @returns {object} Measure settings.
*/
export default function KadenceRange({
label,
onChange,
value = "",
className = "",
step = 1,
max = 100,
min = 0,
beforeIcon = "",
help = "",
}) {
const onChangInput = (event) => {
if (event.target.value === "") {
onChange(undefined);
return;
}
const newValue = Number(event.target.value);
if (newValue === "") {
onChange(undefined);
return;
}
if (min < -0.1) {
if (newValue > max) {
onChange(max);
} else if (newValue < min && newValue !== "-") {
onChange(min);
} else {
onChange(newValue);
}
} else {
if (newValue > max) {
onChange(max);
} else if (newValue < -0.1) {
onChange(min);
} else {
onChange(newValue);
}
}
};
const id = useInstanceId(KadenceRange, "inspector-kadence-range");
return [
onChange && (
<div
className={`components-base-control kadence-range-control${
className ? " " + className : ""
}`}
>
{label && (
<label
htmlFor={id}
className="components-base-control__label"
>
{label}
</label>
)}
<div className={"kadence-range-control-inner"}>
<RangeControl
className={"kadence-range-control-range"}
beforeIcon={beforeIcon}
value={value}
onChange={(newVal) => onChange(newVal)}
min={min}
max={max}
step={step}
help={help}
withInputField={false}
/>
<div className="components-base-control kt-range-number-input">
<div className="components-base-control__field">
<input
value={value}
onChange={onChangInput}
min={min}
max={max}
id={id}
step={step}
type="number"
className="components-text-control__input"
/>
</div>
</div>
</div>
</div>
),
];
}

View File

@@ -0,0 +1,162 @@
import PropTypes from "prop-types";
import Icons from "./icons";
import { __ } from "@wordpress/i18n";
const { Component, Fragment } = wp.element;
const { Button, Dashicon, Tooltip, ButtonGroup, Icon } = wp.components;
class ResponsiveControl extends Component {
constructor(props) {
super(props);
this.state = {
view:
undefined !== this.props.deviceSize
? this.props.deviceSize
: "desktop",
};
this.linkResponsiveButtons();
}
render() {
let { view } = this.state,
deviceMap = {
desktop: {
tooltip: __("Desktop", "kadence"),
icon: <Icon icon={Icons.desktop} />,
},
tablet: {
tooltip: __("Tablet", "kadence"),
icon: <Icon icon={Icons.tablet} />,
},
mobile: {
tooltip: __("Mobile", "kadence"),
icon: <Icon icon={Icons.smartphone} />,
},
};
return (
<Fragment>
<div className={"kadence-responsive-control-bar"}>
{this.props.controlLabel && (
<span className="customize-control-title">
{this.props.controlLabel}
</span>
)}
{this.props.advancedControls && (
<div className="advanced-controls">
<ButtonGroup>
<Tooltip
text={__("Clamp Font Size", "kadence")}
>
<Button
isTertiary
onClick={() => {
this.props.onAdvancedChange();
}}
isPressed={this.props.advanced}
>
<Dashicon icon="admin-settings" />
</Button>
</Tooltip>
</ButtonGroup>
</div>
)}
{!this.props.hideResponsive && (
<div className="floating-controls">
{this.props.tooltip && (
<ButtonGroup>
{Object.keys(deviceMap).map((device) => {
return (
<Tooltip
text={deviceMap[device].tooltip}
>
<Button
isTertiary
className={
(device === view
? "active-device "
: "") + device
}
onClick={() => {
let event =
new CustomEvent(
"kadenceChangedRepsonsivePreview",
{
detail: device,
}
);
document.dispatchEvent(
event
);
}}
>
{deviceMap[device].icon}
</Button>
</Tooltip>
);
})}
</ButtonGroup>
)}
{!this.props.tooltip && (
<ButtonGroup>
{Object.keys(deviceMap).map((device) => {
return (
<Button
isTertiary
className={
(device === view
? "active-device "
: "") + device
}
onClick={() => {
let event = new CustomEvent(
"kadenceChangedRepsonsivePreview",
{
detail: device,
}
);
document.dispatchEvent(
event
);
}}
>
{deviceMap[device].icon}
</Button>
);
})}
</ButtonGroup>
)}
</div>
)}
</div>
<div className="kadence-responsive-controls-content">
{this.props.children}
</div>
</Fragment>
);
}
changeViewType(device) {
this.setState({ view: device });
wp.customize.previewedDevice(device);
this.props.onChange(device);
}
linkResponsiveButtons() {
let self = this;
document.addEventListener(
"kadenceChangedRepsonsivePreview",
function (e) {
self.changeViewType(e.detail);
}
);
}
}
ResponsiveControl.propTypes = {
onChange: PropTypes.func,
controlLabel: PropTypes.string,
};
ResponsiveControl.defaultProps = {
tooltip: true,
};
export default ResponsiveControl;

View File

@@ -0,0 +1,104 @@
import PropTypes from "prop-types";
import Icons from "./icons";
import { __ } from "@wordpress/i18n";
const { Component, Fragment } = wp.element;
const { Button, Popover, Dashicon, ColorIndicator, Tooltip, Icon } =
wp.components;
// /**
// * WordPress dependencies
// */
// import { site, Icon } from '@wordpress/icons';
export const SwatchesControl = ({
colors,
isPalette,
onClick = () => {},
circleSize,
circleSpacing,
}) => {
const handleClick = (color, swatch) => {
onClick(
{
hex: color,
},
swatch
);
};
return (
<div
style={{
paddingBottom: "15px",
}}
className="kadence-swatches-wrap"
>
{colors.map((colorObjOrString) => {
const c =
typeof colorObjOrString === "string"
? { color: colorObjOrString }
: colorObjOrString;
const key = `${c.color}${c.slug || ""}`;
return (
<div
key={key}
style={{
width: circleSize,
height: circleSize,
marginBottom: 0,
transform: "scale(1)",
transition: "100ms transform ease",
}}
className="kadence-swatche-item-wrap"
>
<Button
className={`kadence-swatch-item ${
isPalette === c.slug
? "swatch-active"
: "swatch-inactive"
}`}
style={{
height: "100%",
width: "100%",
border: "1px solid rgb(218, 218, 218)",
borderRadius: "50%",
color:
c.slug === "palette10"
? "var(--global-palette10)"
: `${c.color}`,
boxShadow: `inset 0 0 0 ${circleSize / 2}px`,
transition: "100ms box-shadow ease",
}}
onClick={() => handleClick(c.color, c.slug)}
tabIndex={0}
>
{/* <Icon
className="dashicon"
icon={ site }
/> */}
<Icon className="dashicon" icon={Icons.globe} />
</Button>
</div>
);
})}
</div>
);
};
SwatchesControl.defaultProps = {
circleSize: 26,
circleSpacing: 15,
};
SwatchesControl.propTypes = {
colors: PropTypes.arrayOf(
PropTypes.oneOfType([
PropTypes.string,
PropTypes.shape({
color: PropTypes.string,
slug: PropTypes.string,
name: PropTypes.string,
}),
])
).isRequired,
isPalette: PropTypes.string,
};
export default SwatchesControl;

View File

@@ -0,0 +1,314 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import ResponsiveControl from '../common/responsive.js';
import Icons from '../common/icons.js';
import { ReactSortable } from "react-sortablejs";
import uniqueId from 'lodash/uniqueId';
import ItemComponent from './item-component';
import { __ } from '@wordpress/i18n';
const { ButtonGroup, Dashicon, Tooltip, Popover, Button, SelectControl } = wp.components;
const { Component, Fragment } = wp.element;
class ContactComponent extends Component {
constructor() {
super( ...arguments );
this.updateValues = this.updateValues.bind( this );
this.onDragEnd = this.onDragEnd.bind( this );
this.onDragStart = this.onDragStart.bind( this );
this.onDragStop = this.onDragStop.bind( this );
this.removeItem = this.removeItem.bind( this );
this.saveArrayUpdate = this.saveArrayUpdate.bind( this );
this.toggleEnableItem = this.toggleEnableItem.bind( this );
this.onChangeIcon = this.onChangeIcon.bind( this );
this.onChangeLabel = this.onChangeLabel.bind( this );
this.onChangeLink = this.onChangeLink.bind( this );
this.onChangeURL = this.onChangeURL.bind( this );
this.onChangeAttachment = this.onChangeAttachment.bind( this );
this.onChangeWidth = this.onChangeWidth.bind( this );
this.onChangeSource = this.onChangeSource.bind( this );
this.addItem = this.addItem.bind( this );
let value = this.props.control.setting.get();
let baseDefault = {
'items': [
{
'id': 'phone',
'enabled': true,
'source': 'icon',
'url': '',
'imageid': '',
'width': 24,
'link': '',
'icon': 'mobile',
'label': '444-546-8765',
},
{
'id': 'hours',
'enabled': true,
'source': 'icon',
'url': '',
'imageid': '',
'width': 24,
'link': '',
'icon': 'hours',
'label': 'Mon - Fri: 8AM - 5PM',
}
],
};
this.defaultValue = this.props.control.params.default ? {
...baseDefault,
...this.props.control.params.default
} : baseDefault;
value = value ? {
...this.defaultValue,
...value
} : this.defaultValue;
let defaultParams = {
'group' : 'contact_item_group',
'options': [
{ value: 'phone', label: __( 'Phone', 'kadence' ), content: __( '444-546-8765', 'kadence' ) },
{ value: 'hours', label: __( 'Hours', 'kadence' ), content: __( 'Mon - Fri: 8AM - 5PM', 'kadence' ) },
{ value: 'email', label: __( 'Email', 'kadence' ), content: __( 'example@example.com', 'kadence' ) },
{ value: 'location', label: __( 'Address', 'kadence' ), content: __( '4560 example street', 'kadence' ) },
],
};
this.controlParams = this.props.control.params.input_attrs ? {
...defaultParams,
...this.props.control.params.input_attrs,
} : defaultParams;
let availibleContactOptions = [];
this.controlParams.options.map( ( option ) => {
if ( ! value.items.some( obj => obj.id === option.value ) ) {
availibleContactOptions.push( option );
}
} );
this.state = {
value: value,
isVisible: false,
control: ( undefined !== availibleContactOptions[0] && undefined !== availibleContactOptions[0].value ? availibleContactOptions[0].value : '' ),
};
}
onDragStart() {
var dropzones = document.querySelectorAll( '.kadence-builder-area' );
var i;
for (i = 0; i < dropzones.length; ++i) {
dropzones[i].classList.add( 'kadence-dragging-dropzones' );
}
}
onDragStop() {
var dropzones = document.querySelectorAll( '.kadence-builder-area' );
var i;
for (i = 0; i < dropzones.length; ++i) {
dropzones[i].classList.remove( 'kadence-dragging-dropzones' );
}
}
saveArrayUpdate( value, index ) {
let updateState = this.state.value;
let items = updateState.items;
const newItems = items.map( ( item, thisIndex ) => {
if ( index === thisIndex ) {
item = { ...item, ...value };
}
return item;
} );
updateState.items = newItems;
this.setState( { value: updateState } );
this.updateValues( updateState );
}
toggleEnableItem( value, itemIndex ) {
this.saveArrayUpdate( { enabled: value }, itemIndex );
}
onChangeLabel( value, itemIndex ) {
this.saveArrayUpdate( { label: value }, itemIndex );
}
onChangeLink( value, itemIndex ) {
this.saveArrayUpdate( { link: value }, itemIndex );
}
onChangeIcon( value, itemIndex ) {
this.saveArrayUpdate( { icon: value }, itemIndex );
}
onChangeURL( value, itemIndex ) {
this.saveArrayUpdate( { url: value }, itemIndex );
}
onChangeAttachment( value, itemIndex ) {
this.saveArrayUpdate( { imageid: value }, itemIndex );
}
onChangeWidth( value, itemIndex ) {
this.saveArrayUpdate( { width: value }, itemIndex );
}
onChangeSource( value, itemIndex ) {
this.saveArrayUpdate( { source: value }, itemIndex );
}
removeItem( itemIndex ) {
let updateState = this.state.value;
let update = updateState.items;
let updateItems = [];
{ update.length > 0 && (
update.map( ( old, index ) => {
if ( itemIndex !== index ) {
updateItems.push( old );
}
} )
) };
updateState.items = updateItems;
this.setState( { value: updateState } );
this.updateValues( updateState );
}
addItem() {
const itemControl = this.state.control;
this.setState( { isVisible: false } );
if ( itemControl ) {
let updateState = this.state.value;
let update = updateState.items;
const itemLabel = this.controlParams.options.filter(function(o){return o.value === itemControl;} );
let newItem = {
'id': itemControl,
'enabled': true,
'source': 'icon',
'url': '',
'imageid': '',
'width': 24,
'link': '',
'icon': itemControl,
'label': itemLabel[0].content,
};
update.push( newItem );
updateState.items = update;
let availibleContactOptions = [];
this.controlParams.options.map( ( option ) => {
if ( ! update.some( obj => obj.id === option.value ) ) {
availibleContactOptions.push( option );
}
} );
this.setState( { control: ( undefined !== availibleContactOptions[0] && undefined !== availibleContactOptions[0].value ? availibleContactOptions[0].value : '' ) } );
this.setState( { value: updateState } );
this.updateValues( updateState );
}
}
onDragEnd( items ) {
let updateState = this.state.value;
let update = updateState.items;
let updateItems = [];
{ items.length > 0 && (
items.map( ( item ) => {
update.filter( obj => {
if ( obj.id === item.id ) {
updateItems.push( obj );
}
} )
} )
) };
if ( ! this.arraysEqual( update, updateItems ) ) {
update.items = updateItems;
updateState.items = updateItems;
this.setState( { value: updateState } );
this.updateValues( updateState );
}
}
arraysEqual( a, b ) {
if (a === b) return true;
if (a == null || b == null) return false;
if (a.length != b.length) return false;
for (var i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) return false;
}
return true;
}
render() {
const currentList = ( typeof this.state.value != "undefined" && this.state.value.items != null && this.state.value.items.length != null && this.state.value.items.length > 0 ? this.state.value.items : [] );
let theItems = [];
{ currentList.length > 0 && (
currentList.map( ( item ) => {
theItems.push(
{
id: item.id,
}
)
} )
) };
const availibleContactOptions = [];
this.controlParams.options.map( ( option ) => {
if ( ! theItems.some( obj => obj.id === option.value ) ) {
availibleContactOptions.push( option );
}
} )
const toggleClose = () => {
if ( this.state.isVisible === true ) {
this.setState( { isVisible: false } );
}
};
return (
<div className="kadence-control-field kadence-sorter-items">
<div className="kadence-sorter-row">
<ReactSortable animation={100} onStart={ () => this.onDragStop() } onEnd={ () => this.onDragStop() } group={ this.controlParams.group } className={ `kadence-sorter-drop kadence-sorter-sortable-panel kadence-sorter-drop-${ this.controlParams.group } kadence-sorter-drop-social_item_group` } handle={ '.kadence-sorter-item-panel-header' } list={ theItems } setList={ ( newState ) => this.onDragEnd( newState ) } >
{ currentList.length > 0 && (
currentList.map( ( item, index ) => {
return <ItemComponent removeItem={ ( remove ) => this.removeItem( remove ) } toggleEnabled={ ( enable, itemIndex ) => this.toggleEnableItem( enable, itemIndex ) } onChangeLabel={ ( label, itemIndex ) => this.onChangeLabel( label, itemIndex ) } onChangeLink={ ( link, itemIndex ) => this.onChangeLink( link, itemIndex ) } onChangeSource={ ( source, itemIndex ) => this.onChangeSource( source, itemIndex ) } onChangeWidth={ ( width, itemIndex ) => this.onChangeWidth( width, itemIndex ) } onChangeURL={ ( url, itemIndex ) => this.onChangeURL( url, itemIndex ) } onChangeAttachment={ ( imageid, itemIndex ) => this.onChangeAttachment( imageid, itemIndex ) } onChangeIcon={ ( icon, itemIndex ) => this.onChangeIcon( icon, itemIndex ) } key={ item.id } index={ index } item={ item } controlParams={ this.controlParams } />;
} )
) }
</ReactSortable>
</div>
{ undefined !== availibleContactOptions[0] && undefined !== availibleContactOptions[0].value && (
<div className="kadence-contact-add-area kadence-social-add-area">
{ this.state.isVisible && (
<Popover position="top right" className="kadence-popover-color kadence-popover-contact kadence-customizer-popover" onClose={ toggleClose }>
<div className="kadence-popover-contact-list kadence-popover-social-list">
<ButtonGroup className="kadence-radio-container-control">
{ availibleContactOptions.map( ( item, index ) => {
return (
<Fragment>
<Button
isTertiary
className={ 'contact-radio-btn' }
onClick={ () => {
this.setState( { control: availibleContactOptions[index].value } );
this.state.control = availibleContactOptions[index].value;
this.addItem();
} }
>
{ availibleContactOptions[index].label && (
availibleContactOptions[index].label
) }
</Button>
</Fragment>
);
} ) }
</ButtonGroup>
</div>
</Popover>
) }
<Button
className="kadence-sorter-add-item"
isPrimary
onClick={ () => {
this.setState( { isVisible: true } );
} }
>
{ __( 'Add Contact', 'kadence' ) }
<Dashicon icon="plus"/>
</Button>
</div>
) }
{ this.props.control.renderNotice() }
</div>
);
}
updateValues( value ) {
this.props.control.setting.set( {
...this.props.control.setting.get(),
...value,
flag: !this.props.control.setting.get().flag
} );
}
}
ContactComponent.propTypes = {
control: PropTypes.object.isRequired,
};
export default ContactComponent;

View File

@@ -0,0 +1,11 @@
import { createRoot } from '@wordpress/element';
import ContactComponent from './contact-component.js';
export const ContactControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <ContactComponent control={ control } /> );
// ReactDOM.render( <ContactComponent control={ control } />, control.container[0] );
}
} );

View File

@@ -0,0 +1,99 @@
const ContactIcons = {
email: <svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 16 16"
>
<path d="M15 2H1c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h14c.55 0 1-.45 1-1V3c0-.55-.45-1-1-1zM5.831 9.773l-3 2.182a.559.559 0 01-.785-.124.563.563 0 01.124-.786l3-2.182a.563.563 0 01.662.91zm8.124 2.058a.563.563 0 01-.785.124l-3-2.182a.563.563 0 01.662-.91l3 2.182a.563.563 0 01.124.786zm-.124-6.876l-5.5 4a.562.562 0 01-.662 0l-5.5-4a.563.563 0 01.662-.91L8 7.804l5.169-3.759a.563.563 0 01.662.91z"></path>
</svg>,
emailAlt: <svg
xmlns="http://www.w3.org/2000/svg"
width="28"
height="28"
viewBox="0 0 28 28"
>
<path d="M28 11.094V23.5c0 1.375-1.125 2.5-2.5 2.5h-23A2.507 2.507 0 010 23.5V11.094c.469.516 1 .969 1.578 1.359 2.594 1.766 5.219 3.531 7.766 5.391 1.313.969 2.938 2.156 4.641 2.156h.031c1.703 0 3.328-1.188 4.641-2.156 2.547-1.844 5.172-3.625 7.781-5.391a9.278 9.278 0 001.563-1.359zM28 6.5c0 1.75-1.297 3.328-2.672 4.281-2.438 1.687-4.891 3.375-7.313 5.078-1.016.703-2.734 2.141-4 2.141h-.031c-1.266 0-2.984-1.437-4-2.141-2.422-1.703-4.875-3.391-7.297-5.078-1.109-.75-2.688-2.516-2.688-3.938 0-1.531.828-2.844 2.5-2.844h23c1.359 0 2.5 1.125 2.5 2.5z"></path>
</svg>,
emailAlt2: <svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
>
<path d="M3 7.921l8.427 5.899c.34.235.795.246 1.147 0L21 7.921V18c0 .272-.11.521-.295.705S20.272 19 20 19H4c-.272 0-.521-.11-.705-.295S3 18.272 3 18zM1 5.983V18c0 .828.34 1.579.88 2.12S3.172 21 4 21h16c.828 0 1.579-.34 2.12-.88S23 18.828 23 18V6.012v-.03a2.995 2.995 0 00-.88-2.102A2.998 2.998 0 0020 3H4c-.828 0-1.579.34-2.12.88A2.995 2.995 0 001 5.983zm19.894-.429L12 11.779 3.106 5.554a.999.999 0 01.188-.259A.994.994 0 014 5h16a1.016 1.016 0 01.893.554z"></path>
</svg>,
phone:<svg
xmlns="http://www.w3.org/2000/svg"
width="12"
height="28"
viewBox="0 0 12 28"
>
<path d="M7.25 22c0-.688-.562-1.25-1.25-1.25s-1.25.562-1.25 1.25.562 1.25 1.25 1.25 1.25-.562 1.25-1.25zm3.25-2.5v-11c0-.266-.234-.5-.5-.5H2c-.266 0-.5.234-.5.5v11c0 .266.234.5.5.5h8c.266 0 .5-.234.5-.5zm-3-13.25A.246.246 0 007.25 6h-2.5c-.141 0-.25.109-.25.25s.109.25.25.25h2.5c.141 0 .25-.109.25-.25zM12 6v16c0 1.094-.906 2-2 2H2c-1.094 0-2-.906-2-2V6c0-1.094.906-2 2-2h8c1.094 0 2 .906 2 2z"></path>
</svg>,
phoneAlt:<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
>
<path d="M7 1a2.997 2.997 0 00-3 3v16a2.997 2.997 0 003 3h10a2.997 2.997 0 003-3V4a2.997 2.997 0 00-3-3zm0 2h10c.276 0 .525.111.707.293S18 3.724 18 4v16c0 .276-.111.525-.293.707S17.276 21 17 21H7c-.276 0-.525-.111-.707-.293S6 20.276 6 20V4c0-.276.111-.525.293-.707S6.724 3 7 3zm5 16a1 1 0 100-2 1 1 0 000 2z"></path>
</svg>,
phoneAlt2: <svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="28"
viewBox="0 0 24 28"
>
<path d="M20 18.641c0-.078 0-.172-.031-.25-.094-.281-2.375-1.437-2.812-1.687-.297-.172-.656-.516-1.016-.516-.688 0-1.703 2.047-2.312 2.047-.313 0-.703-.281-.984-.438-2.063-1.156-3.484-2.578-4.641-4.641-.156-.281-.438-.672-.438-.984 0-.609 2.047-1.625 2.047-2.312 0-.359-.344-.719-.516-1.016-.25-.438-1.406-2.719-1.687-2.812-.078-.031-.172-.031-.25-.031-.406 0-1.203.187-1.578.344-1.031.469-1.781 2.438-1.781 3.516 0 1.047.422 2 .781 2.969 1.25 3.422 4.969 7.141 8.391 8.391.969.359 1.922.781 2.969.781 1.078 0 3.047-.75 3.516-1.781.156-.375.344-1.172.344-1.578zM24 6.5v15c0 2.484-2.016 4.5-4.5 4.5h-15A4.502 4.502 0 010 21.5v-15C0 4.016 2.016 2 4.5 2h15C21.984 2 24 4.016 24 6.5z"></path>
</svg>,
hours: <svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="28"
viewBox="0 0 24 28"
>
<path d="M14 8.5v7c0 .281-.219.5-.5.5h-5a.494.494 0 01-.5-.5v-1c0-.281.219-.5.5-.5H12V8.5c0-.281.219-.5.5-.5h1c.281 0 .5.219.5.5zm6.5 5.5c0-4.688-3.813-8.5-8.5-8.5S3.5 9.313 3.5 14s3.813 8.5 8.5 8.5 8.5-3.813 8.5-8.5zm3.5 0c0 6.625-5.375 12-12 12S0 20.625 0 14 5.375 2 12 2s12 5.375 12 12z"></path>
</svg>,
hoursAlt: <svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
>
<path d="M23 12c0-3.037-1.232-5.789-3.222-7.778S15.037 1 12 1 6.211 2.232 4.222 4.222 1 8.963 1 12s1.232 5.789 3.222 7.778S8.963 23 12 23s5.789-1.232 7.778-3.222S23 15.037 23 12zm-2 0c0 2.486-1.006 4.734-2.636 6.364S14.486 21 12 21s-4.734-1.006-6.364-2.636S3 14.486 3 12s1.006-4.734 2.636-6.364S9.514 3 12 3s4.734 1.006 6.364 2.636S21 9.514 21 12zM11 6v6a1 1 0 00.553.894l4 2a1 1 0 00.895-1.789L13 11.382V6a1 1 0 00-2 0z"></path>
</svg>,
hoursAlt2: <svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 16 16"
>
<path d="M8 0a8 8 0 100 16A8 8 0 008 0zm2.293 11.707L7 8.414V4h2v3.586l2.707 2.707-1.414 1.414z"></path>
</svg>,
location: <svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="28"
viewBox="0 0 16 28"
>
<path d="M12 10c0-2.203-1.797-4-4-4s-4 1.797-4 4 1.797 4 4 4 4-1.797 4-4zm4 0c0 .953-.109 1.937-.516 2.797L9.796 24.891C9.468 25.579 8.749 26 7.999 26s-1.469-.422-1.781-1.109L.515 12.797C.109 11.938-.001 10.953-.001 10c0-4.422 3.578-8 8-8s8 3.578 8 8z"></path>
</svg>,
locationAlt: <svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
>
<path d="M22 10c0-2.761-1.12-5.263-2.929-7.071S14.761 0 12 0 6.737 1.12 4.929 2.929 2 7.239 2 10c0 .569.053 1.128.15 1.676.274 1.548.899 3.004 1.682 4.32 2.732 4.591 7.613 7.836 7.613 7.836.331.217.765.229 1.109 0 0 0 4.882-3.245 7.613-7.836.783-1.316 1.408-2.772 1.682-4.32A9.506 9.506 0 0022 10zm-2 0c0 .444-.041.887-.119 1.328-.221 1.25-.737 2.478-1.432 3.646-1.912 3.214-5.036 5.747-6.369 6.74-1.398-.916-4.588-3.477-6.53-6.74-.695-1.168-1.211-2.396-1.432-3.646A7.713 7.713 0 014 10c0-2.209.894-4.208 2.343-5.657S9.791 2 12 2s4.208.894 5.657 2.343S20 7.791 20 10zm-4 0c0-1.104-.449-2.106-1.172-2.828a3.994 3.994 0 00-5.656 0 3.994 3.994 0 000 5.656 3.994 3.994 0 005.656 0A3.994 3.994 0 0016 10zm-2 0c0 .553-.223 1.051-.586 1.414S12.553 12 12 12s-1.051-.223-1.414-.586S10 10.553 10 10s.223-1.051.586-1.414S11.447 8 12 8s1.051.223 1.414.586S14 9.447 14 10z"></path>
</svg>,
locationAlt2: <svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 16 16"
>
<path d="M8 0a5 5 0 00-5 5c0 5 5 9 5 9s5-4 5-9a5 5 0 00-5-5zm0 8a3 3 0 110-6 3 3 0 010 6zm4.285 2.9a16.57 16.57 0 01-.682.988l.108.052c.76.38 1.101.806 1.101 1.059s-.34.679-1.101 1.059c-.957.479-2.31.753-3.712.753s-2.754-.275-3.712-.753c-.76-.38-1.101-.806-1.101-1.059s.34-.679 1.101-1.059l.108-.052c-.231-.31-.461-.64-.682-.988-1.061.541-1.715 1.282-1.715 2.1 0 1.657 2.686 3 6 3s6-1.343 6-3c0-.817-.654-1.558-1.715-2.1z"></path>
</svg>,
};
export default ContactIcons;

View File

@@ -0,0 +1,203 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import ContactIcons from './icons.js';
import FontIconPicker from '@fonticonpicker/react-fonticonpicker';
import { __ } from '@wordpress/i18n';
const { MediaUpload } = wp.blockEditor;
const { ButtonGroup, Dashicon, Tooltip, TextControl, Button, TabPanel, RangeControl, Placeholder } = wp.components;
const { Component, Fragment } = wp.element;
class ItemComponent extends Component {
constructor() {
super( ...arguments );
this.state = {
open: false,
};
}
render() {
return (
<div className="kadence-sorter-item" data-id={ this.props.item.id } key={ this.props.item.id }>
<div className="kadence-sorter-item-panel-header">
<Tooltip text={ __( 'Toggle Item Visibility', 'kadence' ) }>
<Button
className={ `kadence-sorter-visiblity ${ ( this.props.item.enabled ? 'item-is-visible' : 'item-is-hidden' ) }`}
onClick={ () => {
this.props.toggleEnabled( ( this.props.item.enabled ? false : true ), this.props.index );
} }
>
{ ContactIcons[this.props.item.id] }
</Button>
</Tooltip>
<span className="kadence-sorter-title">
{ ( undefined !== this.props.item.label && '' !== this.props.item.label ? this.props.item.label : __( 'Contact Item', 'kadence' ) ) }
</span>
<Tooltip text={ __( 'Expand Item Controls', 'kadence' ) }>
<Button
className="kadence-sorter-item-expand"
onClick={ () => {
this.setState( { open: ( this.state.open ? false : true ) } )
} }
>
<Dashicon icon={ ( this.state.open ? 'arrow-up-alt2' : 'arrow-down-alt2' ) }/>
</Button>
</Tooltip>
</div>
{ this.state.open && (
<div className="kadence-sorter-item-panel-content">
<TabPanel className="sortable-style-tabs kadence-contact-type"
activeClass="active-tab"
initialTabName={ ( undefined !== this.props.item.source ? this.props.item.source : 'icon' ) }
onSelect={ ( value ) => this.props.onChangeSource( value, this.props.index ) }
tabs={ [
{
name: 'icon',
title: __( 'Icon', 'kadence' ),
},
{
name: 'image',
title: __( 'Image', 'kadence' ),
},
] }>
{
( tab ) => {
let tabout;
if ( tab.name ) {
if ( 'image' === tab.name ) {
tabout = (
<Fragment>
{ ! this.props.item.url && (
<div className="attachment-media-view">
<MediaUpload
onSelect={ ( imageData ) => {
this.props.onChangeURL( imageData.url, this.props.index );
this.props.onChangeAttachment( imageData.id, this.props.index );
} }
allowedTypes={ ['image'] }
render={ ( { open } ) => (
<Button className="button-add-media" isSecondary onClick={ open }>
{ __( 'Add Image', 'kadence' )}
</Button>
) }
/>
</div>
) }
{ this.props.item.url && (
<div className="contact-custom-image">
<div className="kadence-Contact-image">
<img className="kadence-Contact-image-preview" src={ this.props.item.url } />
</div>
<Button
className='remove-image'
isDestructive
onClick={ () => {
this.props.onChangeURL( '', this.props.index );
this.props.onChangeAttachment( '', this.props.index );
} }
>
{ __( 'Remove Image', 'kadence' ) }
<Dashicon icon='no'/>
</Button>
</div>
) }
<RangeControl
label={ __( 'Max Width (px)', 'kadence' ) }
value={ ( undefined !== this.props.item.width ? this.props.item.width : 24 ) }
onChange={ ( value ) => {
this.props.onChangeWidth( value, this.props.index );
} }
step={ 1 }
min={ 2 }
max={ 100 }
/>
</Fragment>
);
} else {
tabout = (
<Fragment>
<ButtonGroup className="kadence-radio-container-control">
<Button
isTertiary
className={ ( this.props.item.id === ( undefined !== this.props.item.icon ? this.props.item.icon : this.props.item.id ) ?
'active-radio ' :
'' ) + 'svg-icon-' + this.props.item.id }
onClick={ () => {
this.props.onChangeIcon( this.props.item.id, this.props.index );
} }
>
<span className="kadence-radio-icon">
{ ContactIcons[this.props.item.id] }
</span>
</Button>
{ ContactIcons[ this.props.item.id + 'Alt' ] && (
<Button
isTertiary
className={ ( this.props.item.id + 'Alt' === ( undefined !== this.props.item.icon ? this.props.item.icon : this.props.item.id ) ?
'active-radio ' :
'' ) + 'svg-icon-' + this.props.item.id + 'Alt' }
onClick={ () => {
this.props.onChangeIcon( this.props.item.id + 'Alt', this.props.index );
} }
>
<span className="kadence-radio-icon">
{ ContactIcons[ this.props.item.id + 'Alt' ] }
</span>
</Button>
) }
{ ContactIcons[ this.props.item.id + 'Alt2' ] && (
<Button
isTertiary
className={ ( this.props.item.id + 'Alt2' === ( undefined !== this.props.item.icon ? this.props.item.icon : this.props.item.id ) ?
'active-radio ' :
'' ) + 'svg-icon-' + this.props.item.id + 'Alt2' }
onClick={ () => {
this.props.onChangeIcon( this.props.item.id + 'Alt2', this.props.index );
} }
>
<span className="kadence-radio-icon">
{ ContactIcons[ this.props.item.id + 'Alt2' ] }
</span>
</Button>
)}
</ButtonGroup>
</Fragment>
);
}
}
return <div>{ tabout }</div>;
}
}
</TabPanel>
<TextControl
label={ __( 'Item Label', 'kadence' ) }
value={ this.props.item.label ? this.props.item.label : '' }
onChange={ ( value ) => {
this.props.onChangeLabel( value, this.props.index );
} }
/>
<TextControl
label={ __( 'Item Link', 'kadence' ) }
value={ this.props.item.link ? this.props.item.link : '' }
onChange={ ( value ) => {
this.props.onChangeLink( value, this.props.index );
} }
/>
<Button
className="kadence-sorter-item-remove"
isDestructive
onClick={ () => {
this.props.removeItem( this.props.index );
} }
>
{ __( 'Remove Item', 'kadence' ) }
<Dashicon icon="no-alt"/>
</Button>
</div>
) }
</div>
);
}
}
export default ItemComponent;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,433 @@
( function( $, api ) {
var $window = $( window ),
$document = $( document ),
$body = $( 'body' );
/**
* API on ready event handlers
*
* All handlers need to be inside the 'ready' state.
*/
wp.customize.bind( 'ready', function() {
$( 'input[name=kadence-flush-local-fonts-button]' ).on( 'click', function( e ) {
var data = {
wp_customize: 'on',
action: 'kadence_flush_fonts_folder',
nonce: kadenceCustomizerControlsData.flushFonts
};
$( 'input[name=kadence-flush-local-fonts-button]' ).attr('disabled', 'disabled');
$.post( ajaxurl, data, function ( response ) {
if ( response && response.success ) {
$( 'input[name=kadence-flush-local-fonts-button]' ).val( 'Successfully Flushed' );
} else {
$( 'input[name=kadence-flush-local-fonts-button]' ).val( 'Failed, Reload Page and Try Again' );
}
});
});
wp.customize.state.create( 'kadenceTab' );
wp.customize.state( 'kadenceTab' ).set( 'general' );
wp.customize.sectionConstructor['kadence_section_pro'] = wp.customize.Section.extend( {
// No events for this type of section.
attachEvents: () => {},
// Always make the section active.
isContextuallyActive: () => {
return true;
}
} );
// Set handler when custom responsive toggle is clicked.
$( '#customize-theme-controls' ).on( 'click', '.kadence-build-tabs-button:not(.kadence-nav-tabs-button)', function( e ) {
e.preventDefault();
wp.customize.previewedDevice.set( $( this ).attr( 'data-device' ) );
});
// Set handler when custom responsive toggle is clicked.
$( '#customize-theme-controls' ).on( 'click', '.kadence-compontent-tabs-button:not(.kadence-nav-tabs-button)', function( e ) {
e.preventDefault();
wp.customize.state( 'kadenceTab' ).set( $( this ).attr( 'data-tab' ) );
});
var setCustomTabElementsDisplay = function() {
var tabState = wp.customize.state( 'kadenceTab' ).get(),
$tabs = $( '.kadence-compontent-tabs-button:not(.kadence-nav-tabs-button)' );
$tabs.removeClass( 'nav-tab-active' ).filter( '.kadence-' + tabState + '-tab' ).addClass( 'nav-tab-active' );
}
// Refresh all responsive elements when previewedDevice is changed.
wp.customize.state( 'kadenceTab' ).bind( setCustomTabElementsDisplay );
$( '#customize-theme-controls' ).on( 'click', 'customize-section-back', function( e ) {
wp.customize.state( 'kadenceTab' ).set( 'general' );
});
if ( kadenceCustomizerControlsData && kadenceCustomizerControlsData.contexts ) {
/**
* Active callback script (JS version)
* ref: https://make.xwp.co/2016/07/24/dependently-contextual-customizer-controls/
*/
_.each( kadenceCustomizerControlsData.contexts, function( rules, key ) {
var getSetting = function( settingName ) {
// Get the dependent setting.
switch ( settingName ) {
case '__device':
return wp.customize.previewedDevice;
break;
case '__current_tab':
return wp.customize.state( 'kadenceTab' );
break;
default:
// Check if we have an extra source in the mix
if ( kadenceCustomizerControlsData.source ) {
// Check if this setting might be powered by the extra source.
if ( wp.customize( kadenceCustomizerControlsData.source + '[' + settingName + ']' ) ) {
return wp.customize( kadenceCustomizerControlsData.source + '[' + settingName + ']' );
} else {
return wp.customize( settingName );
}
}
return wp.customize( settingName );
break;
}
}
var initContext = function( element ) {
// Main function returning the conditional value
var isDisplayed = function() {
var displayed = false,
relation = rules['relation'];
// Fallback invalid relation type to "AND".
// Assign default displayed to true for "AND" relation type.
if ( 'OR' !== relation ) {
relation = 'AND';
displayed = true;
}
// Each rule iteration
_.each( rules, function( rule, i ) {
// Skip "relation" property.
if ( 'relation' == i ) return;
// If in "AND" relation and "displayed" already flagged as false, skip the rest rules.
if ( 'AND' == relation && false == displayed ) return;
// Skip if no setting propery found.
if ( undefined === rule['setting'] ) return;
var result = false,
setting = getSetting( rule['setting'] );
// Only process the rule if dependent setting is found.
// Otherwise leave the result to "false".
if ( undefined !== setting ) {
var operator = rule['operator'],
comparedValue = rule['value'],
currentValue = setting.get();
if ( undefined == operator || '=' == operator ) {
operator = '==';
}
if ( 'sub_object_contains' === operator ) {
if ( undefined !== currentValue[ rule['sub_key'] ] ) {
currentValue = currentValue[ rule['sub_key'] ];
}
}
if ( 'sub_object_does_not_contain' === operator ) {
if ( undefined !== currentValue[ rule['sub_key'] ] ) {
currentValue = currentValue[ rule['sub_key'] ];
}
}
switch ( operator ) {
case '>':
result = currentValue > comparedValue;
break;
case '<':
result = currentValue < comparedValue;
break;
case '>=':
result = currentValue >= comparedValue;
break;
case '<=':
result = currentValue <= comparedValue;
break;
case 'in':
result = 0 <= comparedValue.indexOf( currentValue );
break;
case 'not_in':
result = 0 > comparedValue.indexOf( currentValue );
break;
case 'contain':
//result = ( currentValue.includes( comparedValue ) );
result = 0 <= currentValue.indexOf( comparedValue );
break;
case 'not_contain':
result = 0 > currentValue.indexOf( comparedValue );
break;
case 'in':
result = 0 <= comparedValue.indexOf( currentValue );
break;
case 'array_includes':
result = currentValue.includes( comparedValue );
break;
case 'sub_object_does_not_contain':
if ( rule['responsive'] ) {
result = true;
{ Object.keys( { 'desktop':'', 'tablet':'', 'mobile':'' } ).map( ( device ) => {
if ( currentValue[ device ].includes( comparedValue ) ) {
result = false;
}
} ) }
} else {
result = ! currentValue.includes( comparedValue );
}
break;
case 'sub_object_contains':
if ( rule['responsive'] ) {
{ Object.keys( { 'desktop':'', 'tablet':'', 'mobile':'' } ).map( ( device ) => {
if ( currentValue[ device ].includes( comparedValue ) ) {
result = true;
}
} ) }
} else {
result = currentValue.includes( comparedValue );
}
break;
case 'empty':
result = (currentValue === undefined || currentValue == null || currentValue.length <= 0);
//result = 0 == currentValue.length;
break;
case '!empty':
result = typeof currentValue !== 'undefined' && undefined !== currentValue && null !== currentValue && '' !== currentValue;
//result = 0 < currentValue.length;
break;
case '!=':
result = comparedValue !== currentValue;
//result = 0 < currentValue.length;
break;
case 'load_italic':
result = false;
if ( currentValue['family'] && currentValue['google'] && currentValue['variant'] ) {
if ( 0 > currentValue['variant'].indexOf( 'italic' ) ) {
if ( kadenceCustomizerControlsData.gfontvars && kadenceCustomizerControlsData.gfontvars[ currentValue['family'] ] && kadenceCustomizerControlsData.gfontvars[ currentValue['family'] ].v && kadenceCustomizerControlsData.gfontvars[ currentValue['family'] ].v.includes( 'italic' ) ) {
result = true;
}
}
}
break;
default:
result = comparedValue == currentValue;
break;
}
}
// Combine to the final result.
switch ( relation ) {
case 'OR':
displayed = displayed || result;
break;
default:
displayed = displayed && result;
break;
}
});
return displayed;
};
// Wrapper function for binding purpose
var setActiveState = function() {
element.active.set( isDisplayed() );
};
// Setting changes bind
_.each( rules, function( rule, i ) {
// Skip "relation" property.
if ( 'relation' == i ) return;
var setting = getSetting( rule['setting'] );
if ( undefined !== setting ) {
// Bind the setting for future use.
setting.bind( setActiveState );
}
});
// Initial run
element.active.validate = isDisplayed;
setActiveState();
};
if ( 0 == key.indexOf( 'kadence_customizer' ) ) {
wp.customize.section( key, initContext );
} else {
wp.customize.control( key, initContext );
}
});
}
// Set all custom responsive toggles and fieldsets.
var setCustomResponsiveElementsDisplay = function() {
var device = wp.customize.previewedDevice.get(),
$tabs = $( '.kadence-build-tabs-button.nav-tab' );
$tabs.removeClass( 'nav-tab-active' ).filter( '.preview-' + device ).addClass( 'nav-tab-active' );
}
// Refresh all responsive elements when previewedDevice is changed.
wp.customize.previewedDevice.bind( setCustomResponsiveElementsDisplay );
// Refresh all responsive elements when any section is expanded.
// This is required to set responsive elements on newly added controls inside the section.
wp.customize.section.each(function ( section ) {
section.expanded.bind( setCustomResponsiveElementsDisplay );
});
/**
* Resize Preview Frame when show / hide Builder.
*/
var resizePreviewer = function() {
var $section = $( '.control-section.kadence-builder-active' );
var $footer = $( '.control-section.kadence-footer-builder-active' );
if ( $body.hasClass( 'kadence-builder-is-active' ) || $body.hasClass( 'kadence-footer-builder-is-active' ) ) {
if ( $body.hasClass( 'kadence-footer-builder-is-active' ) && 0 < $footer.length && ! $footer.hasClass( 'kadence-builder-hide' ) ) {
setTimeout(function() {
wp.customize.previewer.container.css( 'bottom', $footer.outerHeight() + 'px' );
}, 250);
} else if ( $body.hasClass( 'kadence-builder-is-active' ) && 0 < $section.length && ! $section.hasClass( 'kadence-builder-hide' ) ) {
setTimeout(function() {
wp.customize.previewer.container.css({ "bottom" : $section.outerHeight() + 'px' });
}, 250);
} else {
wp.customize.previewer.container.css( 'bottom', '');
}
} else {
wp.customize.previewer.container.css( 'bottom', '');
}
}
$window.on( 'resize', resizePreviewer );
wp.customize.previewedDevice.bind(function( device ) {
setTimeout(function() {
resizePreviewer();
}, 250 );
});
var reloadPreviewer = function() {
$( wp.customize.previewer.container ).find( 'iframe' ).css( 'position', 'static' );
$( wp.customize.previewer.container ).find( 'iframe' ).css( 'position', 'absolute' );
}
wp.customize.previewer.bind( 'ready', reloadPreviewer );
/**
* Init Header & Footer Builder
*/
var initHeaderBuilderPanel = function( panel ) {
var section = wp.customize.section( 'kadence_customizer_header_builder' );
if ( section ) {
var $section = section.contentContainer,
section_layout = wp.customize.section( 'kadence_customizer_header_layout' );
// If Header panel is expanded, add class to the body tag (for CSS styling).
panel.expanded.bind(function( isExpanded ) {
_.each(section.controls(), function( control ) {
if ( 'resolved' === control.deferred.embedded.state() ) {
return;
}
control.renderContent();
control.deferred.embedded.resolve(); // This triggers control.ready().
// Fire event after control is initialized.
control.container.trigger( 'init' );
});
if ( isExpanded ) {
$body.addClass( 'kadence-builder-is-active' );
$section.addClass( 'kadence-builder-active' );
$section.css('display', 'none').height();
$section.css('display', 'block');
} else {
$body.removeClass( 'kadence-builder-is-active' );
$section.removeClass( 'kadence-builder-active' );
}
_.each(section_layout.controls(), function( control ) {
if ( 'resolved' === control.deferred.embedded.state() ) {
return;
}
control.renderContent();
control.deferred.embedded.resolve(); // This triggers control.ready().
// Fire event after control is initialized.
control.container.trigger( 'init' );
});
resizePreviewer();
});
// Attach callback to builder toggle.
$section.on( 'click', '.kadence-builder-tab-toggle', function( e ) {
e.preventDefault();
$section.toggleClass( 'kadence-builder-hide' );
resizePreviewer();
});
}
};
wp.customize.panel( 'kadence_customizer_header', initHeaderBuilderPanel );
/**
* Init Header & Footer Builder
*/
var initFooterBuilderPanel = function( panel ) {
var section = wp.customize.section( 'kadence_customizer_footer_builder' );
if ( section ) {
var $section = section.contentContainer,
section_layout = wp.customize.section( 'kadence_customizer_footer_layout' );
// If Header panel is expanded, add class to the body tag (for CSS styling).
panel.expanded.bind(function( isExpanded ) {
_.each(section.controls(), function( control ) {
if ( 'resolved' === control.deferred.embedded.state() ) {
return;
}
control.renderContent();
control.deferred.embedded.resolve(); // This triggers control.ready().
// Fire event after control is initialized.
control.container.trigger( 'init' );
});
if ( isExpanded ) {
$body.addClass( 'kadence-footer-builder-is-active' );
$section.addClass( 'kadence-footer-builder-active' );
$section.css('display', 'none').height();
$section.css('display', 'block');
} else {
$body.removeClass( 'kadence-footer-builder-is-active' );
$section.removeClass( 'kadence-footer-builder-active' );
}
_.each(section_layout.controls(), function( control ) {
if ( 'resolved' === control.deferred.embedded.state() ) {
return;
}
control.renderContent();
control.deferred.embedded.resolve(); // This triggers control.ready().
// Fire event after control is initialized.
control.container.trigger( 'init' );
});
resizePreviewer();
});
// Attach callback to builder toggle.
$section.on( 'click', '.kadence-builder-tab-toggle', function( e ) {
e.preventDefault();
$section.toggleClass( 'kadence-builder-hide' );
resizePreviewer();
} );
}
};
wp.customize.panel( 'kadence_customizer_footer', initFooterBuilderPanel );
});
} )( jQuery, wp );

View File

@@ -0,0 +1,14 @@
import { createRoot } from '@wordpress/element';
import EditorComponent from './editor-component.js';
export const EditorControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <EditorComponent control={control} customizer={ wp.customize } /> );
// ReactDOM.render(
// <EditorComponent control={control} customizer={ wp.customize } />,
// control.container[0]
// );
}
} );

View File

@@ -0,0 +1,95 @@
import PropTypes from 'prop-types';
import debounce from 'lodash/debounce';
import { __ } from '@wordpress/i18n';
const { Component } = wp.element;
class EditorComponent extends Component {
constructor(props) {
super( props );
this.updateValues = this.updateValues.bind( this );
this.triggerChangeIfDirty = this.triggerChangeIfDirty.bind( this );
this.onInit = this.onInit.bind( this );
let value = props.control.setting.get();
this.state = {
value,
editor:{},
restoreTextMode: false,
};
let defaultParams = {
id: 'header_html',
toolbar1: 'bold,italic,bullist,numlist,link',
toolbar2: '',
};
this.controlParams = this.props.control.params.input_attrs ? {
...defaultParams,
...this.props.control.params.input_attrs,
} : defaultParams;
this.defaultValue = props.control.params.default || '';
}
componentDidMount() {
if ( window.tinymce.get( this.controlParams.id ) ) {
this.setState( { restoreTextMode: window.tinymce.get( this.controlParams.id ).isHidden() } );
window.wp.oldEditor.remove( this.controlParams.id );
}
window.wp.oldEditor.initialize( this.controlParams.id, {
tinymce: {
wpautop: true,
toolbar1: this.controlParams.toolbar1,
toolbar2: this.controlParams.toolbar2,
},
quicktags: true,
mediaButtons: true,
} );
const editor = window.tinymce.get( this.controlParams.id );
if ( editor.initialized ) {
this.onInit();
} else {
editor.on( 'init', this.onInit );
}
}
onInit() {
const editor = window.tinymce.get( this.controlParams.id );
if ( this.state.restoreTextMode ) {
window.switchEditors.go( this.controlParams.id, 'html' );
}
editor.on( 'NodeChange', debounce( this.triggerChangeIfDirty, 250 ) );
this.setState( { editor: editor } );
}
triggerChangeIfDirty() {
this.updateValues( window.wp.oldEditor.getContent( this.controlParams.id ) );
}
render() {
return (
<div className="kadence-control-field kadence-editor-control">
{ this.props.control.params.label && (
<span className="customize-control-title">{ this.props.control.params.label }</span>
) }
<textarea
className="kadence-control-tinymce-editor wp-editor-area"
id={ this.controlParams.id }
value={ this.state.value }
onChange={ ( { target: { value } } ) => {
this.updateValues(value);
} }
/>
{ this.props.control.params.description && (
<span className="customize-control-description">{ this.props.control.params.description }</span>
) }
{ this.props.control.renderNotice() }
</div>
);
}
updateValues(value) {
this.setState( { value: value } );
this.props.control.setting.set( value );
}
}
EditorComponent.propTypes = {
control: PropTypes.object.isRequired,
customizer: PropTypes.object.isRequired,
};
export default EditorComponent;

View File

@@ -0,0 +1,11 @@
import { createRoot } from '@wordpress/element';
import FocusButtonComponent from './focus-button-component';
export const FocusButtonControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <FocusButtonComponent control={ control } customizer={ wp.customize } /> );
// ReactDOM.render( <FocusButtonComponent control={ control } customizer={ wp.customize } />, control.container[0] );
}
} );

View File

@@ -0,0 +1,54 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import ResponsiveControl from '../common/responsive.js';
import Icons from '../common/icons.js';
import { ReactSortable } from "react-sortablejs";
import { __ } from '@wordpress/i18n';
const { ButtonGroup, Dashicon, Tooltip, Button } = wp.components;
const { Component, Fragment } = wp.element;
class FocusButtonComponent extends Component {
constructor() {
super( ...arguments );
this.focusPanel = this.focusPanel.bind( this );
let defaultParams = {
'section': '',
};
this.controlParams = this.props.control.params.input_attrs ? {
...defaultParams,
...this.props.control.params.input_attrs,
} : defaultParams;
}
focusPanel( section ) {
if ( undefined !== this.props.customizer.section( section ) ) {
this.props.customizer.section( section ).focus();
}
}
render() {
return (
<div className="kadence-control-field kadence-available-items">
<div className={ 'kadence-builder-item-start' }>
<Button className="kadence-builder-item" onClick={ () => this.focusPanel( this.controlParams.section ) } data-section={ this.controlParams.section }>
{ ( this.props.control.params.label ? this.props.control.params.label : '' ) }
<span
className="kadence-builder-item-icon"
>
<Dashicon icon="arrow-right-alt2"/>
</span>
</Button>
</div>
{ this.props.control.renderNotice() }
</div>
);
}
}
FocusButtonComponent.propTypes = {
control: PropTypes.object.isRequired,
customizer: PropTypes.object.isRequired
};
export default FocusButtonComponent;

View File

@@ -0,0 +1,66 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
export const DEFAULT_GRADIENT =
'linear-gradient(135deg, rgb(6, 147, 227) 0%, rgb(20, 39, 109) 100%)';
export const DEFAULT_LINEAR_GRADIENT_ANGLE = 180;
export const HORIZONTAL_GRADIENT_ORIENTATION = {
type: 'angular',
value: 90,
};
export const DEFAULT_RADIAL_GRADIENT_POSITION = 'center center';
export const RADIAL_GRADIENT_ORIENTATION = [ {
type: 'shape',
value: 'ellipse',
at: {
type: 'position',
value: {
x: {
type: 'position-keyword',
value: 'center'
},
y: {
type: 'position-keyword',
value: 'center'
}
}
}
} ];
export const DEFAULT_RADIAL_GRADIENT_SHAPE = 'ellipse';
export const GRADIENT_OPTIONS = [
{ value: 'linear-gradient', label: __( 'Linear', 'kadence-blocks' ) },
{ value: 'radial-gradient', label: __( 'Radial', 'kadence-blocks' ) },
];
export const GRADIENT_POSITION_OPTIONS = [
{ value: 'center top', label: __( 'Center Top', 'kadence-blocks' ) },
{ value: 'center center', label: __( 'Center Center', 'kadence-blocks' ) },
{ value: 'center bottom', label: __( 'Center Bottom', 'kadence-blocks' ) },
{ value: 'left top', label: __( 'Left Top', 'kadence-blocks' ) },
{ value: 'left center', label: __( 'Left Center', 'kadence-blocks' ) },
{ value: 'left bottom', label: __( 'Left Bottom', 'kadence-blocks' ) },
{ value: 'right top', label: __( 'Right Top', 'kadence-blocks' ) },
{ value: 'right center', label: __( 'Right Center', 'kadence-blocks' ) },
{ value: 'right bottom', label: __( 'Right Bottom', 'kadence-blocks' ) },
];
export const DIRECTIONAL_ORIENTATION_ANGLE_MAP = {
top: 0,
'top right': 45,
'right top': 45,
right: 90,
'right bottom': 135,
'bottom right': 135,
bottom: 180,
'bottom left': 225,
'left bottom': 225,
left: 270,
'top left': 315,
'left top': 315,
};

View File

@@ -0,0 +1,216 @@
.components-custom-gradient-picker__item {
display: block;
flex:5 1 0%;
max-height: 100%;
max-width: 100%;
min-height: 0px;
min-width: 0px;
.kadence-controls-content {
gap: 12px;
}
.kadence-controls-content .components-base-control {
margin-bottom: 0;
flex: 10 0 0;
}
.kadence-control-toggle-advanced.only-icon {
flex: 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 10px;
font-weight: 600;
font-style: normal;
text-transform: uppercase;
height: 30px;
line-height: 1.2;
border: 1px solid #CBD5E0;
border-radius: 2px;
background: transparent;
color: #4A5568;
padding: 4px;
box-shadow: none;
white-space: normal;
svg {
width: 20px;
}
&.is-primary {
border-color: var(--wp-admin-theme-color, #00669b);
background: var(--wp-admin-theme-color, #00669b);
color: #fff;
box-shadow: none;
}
}
}
.block-editor-block-inspector .components-custom-gradient-picker__item .kadence-select-large .components-select-control__input {
height: 40px;
min-height: 40px;
}
.kadence-gradient-position-control .kadence-gradient-position_header .kadence-gradient-position__label {
margin: 0px 0px 8px;
display:block;
}
.kadence-gradient-position-control .components-unit-control-wrapper {
flex-grow: 1;
}
// .kadence-gradient-control .components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__control-point-button {
// border-radius: 50%;
// width: 30px;
// height: 30px;
// bottom: 100%;
// top: auto;
// margin-left: -15px;
// }
.kadence-gradient-control .components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__control-point-dropdown {
position: absolute;
height: 16px;
width: 16px;
top: 16px;
display: flex;
}
.kadence-gradient-control .components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__control-point-button {
height: inherit;
width: inherit;
border-radius: 50%;
padding: 0;
box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) #fff,0 0 2px 0 rgba(0, 0, 0, 0.25);
outline: 2px solid transparent;
position: static;
top: auto;
}
// $grid-unit-20: 20px;
// $grid-unit-60: 40px;
// $radius-block-ui: 4px;
// $grid-unit-15: 15px;
// $grid-unit-30: 30px;
// $grid-unit-10: 10px;
// $border-width-tab: 1px;
// $components-custom-gradient-picker__padding: $grid-unit-20; // 48px container, 16px handles inside, that leaves 32px padding, half of which is 1å6.
// .components-custom-gradient-picker {
// &:not(.is-next-has-no-margin) {
// margin-top: $grid-unit-15;
// margin-bottom: $grid-unit-30;
// }
// }
// .components-custom-gradient-picker__gradient-bar:not(.has-gradient) {
// opacity: 0.4;
// }
.kadence-gradient-control .components-custom-gradient-picker__gradient-bar:not(.has-gradient) {
opacity: 0.4;
}
.kadence-select-no-margin-after {
}
.kadence-gradient-control {
.components-custom-gradient-picker__ui-line .components-base-control {
margin-bottom: 0;
}
.components-custom-gradient-picker__ui-line .components-base-control .components-base-control__field {
margin-bottom: 0;
}
}
.kadence-gradient-control .components-custom-gradient-picker__gradient-bar {
border-radius: 2px;
width: 100%;
height: 48px;
margin-bottom: 16px;
padding-right: 0;
.components-custom-gradient-picker__markers-container {
position: relative;
width: calc(100% - 48px);
margin-left: auto;
margin-right: auto;
}
.components-custom-gradient-picker__control-point-dropdown {
position: absolute;
height: 16px;
width: 16px;
top: 16px;
display: flex;
}
.components-custom-gradient-picker__insert-point-dropdown {
position: relative;
// Same size as the .components-custom-gradient-picker__control-point-dropdown parent
height: inherit;
width: inherit;
min-width: 16px;
border-radius: 50%;
background: #fff;
padding: 2px;
color: #111;
svg {
height: 100%;
width: 100%;
}
}
}
.kadence-gradient-control .components-angle-picker-control .components-input-control__container .components-input-control__input {
height: 32px;
padding-left: 8px;
padding-right: 8px;
}
// .components-custom-gradient-picker__control-point-button {
// // Same size as the .components-custom-gradient-picker__control-point-dropdown parent
// height: inherit;
// width: inherit;
// border-radius: 50%;
// padding: 0;
// // Shadow and stroke.
// box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) #fff, 0 0 4px 0 rgba(#000, 0.25);
// // Windows High Contrast mode will show this outline, but not the box-shadow.
// outline: 2px solid transparent;
// &:focus,
// &.is-active {
// box-shadow: inset 0 0 0 calc(var(--wp-admin-border-width-focus) * 2) #fff, 0 0 4px 0 rgba(#000, 0.25);
// // Windows High Contrast mode will show this outline, but not the box-shadow.
// outline: $border-width-tab solid transparent;
// }
// }
// }
// .components-custom-gradient-picker__remove-control-point-wrapper {
// padding-bottom: $grid-unit-10;
// }
// .components-custom-gradient-picker__inserter {
// /*rtl:ignore*/
// direction: ltr;
// }
// .components-custom-gradient-picker__liner-gradient-indicator {
// display: inline-block;
// flex: 0 auto;
// width: 20px;
// height: 20px;
// }
// .components-custom-gradient-picker .components-custom-gradient-picker__toolbar {
// border: none;
// // Work-around to target the inner button containers rendered by <ToolbarGroup />
// > div + div {
// margin-left: 1px;
// }
// button {
// &.is-pressed {
// > svg {
// background: #fff;
// border: 1px solid #565656;
// border-radius: 2px;
// }
// }
// }
// }

View File

@@ -0,0 +1,10 @@
export const GRADIENT_MARKERS_WIDTH = 16;
export const INSERT_POINT_WIDTH = 16;
export const MINIMUM_DISTANCE_BETWEEN_INSERTER_AND_POINT = 10;
export const MINIMUM_DISTANCE_BETWEEN_POINTS = 0;
export const MINIMUM_SIGNIFICANT_MOVE = 5;
export const KEYBOARD_CONTROL_POINT_VARIATION =
MINIMUM_DISTANCE_BETWEEN_INSERTER_AND_POINT;
export const MINIMUM_DISTANCE_BETWEEN_INSERTER_AND_MARKER =
( INSERT_POINT_WIDTH + GRADIENT_MARKERS_WIDTH ) / 2;

View File

@@ -0,0 +1,864 @@
/**
* External dependencies
*/
import classnames from "classnames";
import { colord } from "colord";
import { map } from "lodash";
/**
* WordPress dependencies
*/
import { useSetting } from "@wordpress/block-editor";
import { useInstanceId, useMergeRefs } from "@wordpress/compose";
import { useEffect, useRef, useState, useMemo } from "@wordpress/element";
import { __, sprintf } from "@wordpress/i18n";
import { plus } from "@wordpress/icons";
const globeIcon = (
<svg
xmlns="http://www.w3.org/2000/svg"
fillRule="evenodd"
strokeLinejoin="round"
strokeMiterlimit="2"
clipRule="evenodd"
viewBox="0 0 20 20"
>
<path fill="none" d="M0 0H20V20H0z"></path>
<path
fillRule="nonzero"
d="M10 1a9 9 0 10.001 18.001A9 9 0 0010 1zm3.46 11.95c0 1.47-.8 3.3-4.06 4.7.3-4.17-2.52-3.69-3.2-5A3.25 3.25 0 018 10.1c-1.552-.266-3-.96-4.18-2 .05.47.28.904.64 1.21a4.18 4.18 0 01-1.94-1.5 7.94 7.94 0 017.25-5.63c-.84 1.38-1.5 4.13 0 5.57C8.23 8 7.26 6 6.41 6.79c-1.13 1.06.33 2.51 3.42 3.08 3.29.59 3.66 1.58 3.63 3.08zm1.34-4c-.32-1.11.62-2.23 1.69-3.14a7.27 7.27 0 01.84 6.68c-.77-1.89-2.17-2.32-2.53-3.57v.03z"
></path>
</svg>
);
/**
* Internal dependencies
*/
// import { HStack } from '../../h-stack';
// import { ColorPicker } from '../../color-picker';
// import { VisuallyHidden } from '../../visually-hidden';
import ColorPicker from "../../common/color-picker";
import {
__experimentalHStack as HStack,
Button,
VisuallyHidden,
Popover,
Dashicon,
Tooltip,
Icon,
} from "@wordpress/components";
import {
addControlPoint,
clampPercent,
removeControlPoint,
updateControlPointColor,
updateControlPointColorByPosition,
updateControlPointPosition,
getHorizontalRelativeGradientPosition,
} from "./utils";
import {
MINIMUM_SIGNIFICANT_MOVE,
KEYBOARD_CONTROL_POINT_VARIATION,
} from "./constants";
function useObservableState(initialState, onStateChange) {
const [state, setState] = useState(initialState);
return [
state,
(value) => {
setState(value);
if (onStateChange) {
onStateChange(value);
}
},
];
}
function CustomDropdown(props) {
const {
renderContent,
renderToggle,
className,
contentClassName,
expandOnMobile,
headerTitle,
focusOnMount,
position,
popoverProps,
onClose,
onToggle,
style,
popoverRef,
} = props;
// Use internal state instead of a ref to make sure that the component
// re-renders when the popover's anchor updates.
const [fallbackPopoverAnchor, setFallbackPopoverAnchor] = useState(null);
const containerRef = useRef();
const [isOpen, setIsOpen] = useObservableState(false, onToggle);
useEffect(
() => () => {
if (onToggle && isOpen) {
onToggle(false);
}
},
[onToggle, isOpen]
);
function toggle() {
setIsOpen(!isOpen);
}
/**
* Closes the popover when focus leaves it unless the toggle was pressed or
* focus has moved to a separate dialog. The former is to let the toggle
* handle closing the popover and the latter is to preserve presence in
* case a dialog has opened, allowing focus to return when it's dismissed.
*/
function closeIfFocusOutside() {
const { ownerDocument } = containerRef.current;
const dialog = ownerDocument.activeElement.closest('[role="dialog"]');
if (
!containerRef.current.contains(ownerDocument.activeElement) &&
(!dialog || dialog.contains(containerRef.current))
) {
close();
}
}
function close() {
if (onClose) {
onClose();
}
setIsOpen(false);
}
const args = { isOpen, onToggle: toggle, onClose: close };
const popoverPropsHaveAnchor =
!!popoverProps?.anchor ||
// Note: `anchorRef`, `getAnchorRect` and `anchorRect` are deprecated and
// be removed from `Popover` from WordPress 6.3
!!popoverProps?.anchorRef ||
!!popoverProps?.getAnchorRect ||
!!popoverProps?.anchorRect;
return (
<div
className={classnames("components-dropdown", className)}
ref={useMergeRefs([setFallbackPopoverAnchor, containerRef])}
// Some UAs focus the closest focusable parent when the toggle is
// clicked. Making this div focusable ensures such UAs will focus
// it and `closeIfFocusOutside` can tell if the toggle was clicked.
tabIndex="-1"
style={style}
>
{renderToggle(args)}
{isOpen && (
<Popover
position={position}
onClose={close}
onFocusOutside={closeIfFocusOutside}
expandOnMobile={expandOnMobile}
headerTitle={headerTitle}
focusOnMount={focusOnMount}
// This value is used to ensure that the dropdowns
// align with the editor header by default.
offset={13}
anchorRef={
!popoverPropsHaveAnchor ? popoverRef.current : undefined
}
anchor={
!popoverPropsHaveAnchor
? fallbackPopoverAnchor
: undefined
}
{...popoverProps}
className={classnames(
"components-dropdown__content",
popoverProps ? popoverProps.className : undefined,
contentClassName
)}
>
{renderContent(args)}
</Popover>
)}
</div>
);
}
function CustomColorPickerDropdown({
isRenderedInSidebar,
popoverProps: receivedPopoverProps,
...props
}) {
const popoverProps = useMemo(
() => ({
shift: true,
...(isRenderedInSidebar
? {
// When in the sidebar: open to the left (stacking),
// leaving the same gap as the parent popover.
placement: "left-start",
offset: 34,
}
: {
// Default behavior: open below the anchor
placement: "bottom",
offset: 8,
}),
...receivedPopoverProps,
}),
[isRenderedInSidebar, receivedPopoverProps]
);
return (
<CustomDropdown
contentClassName="components-color-palette__custom-color-dropdown-content kadence-pop-color-popover"
popoverProps={popoverProps}
{...props}
/>
);
}
function ControlPointButton({ isOpen, position, color, ...additionalProps }) {
const instanceId = useInstanceId(ControlPointButton);
const descriptionId = `components-custom-gradient-picker__control-point-button-description-${instanceId}`;
return (
<>
<Button
aria-label={sprintf(
// translators: %1$s: gradient position e.g: 70, %2$s: gradient color code e.g: rgb(52,121,151).
__(
"Gradient control point at position %1$s%% with color code %2$s."
),
position,
color
)}
aria-describedby={descriptionId}
aria-haspopup="true"
aria-expanded={isOpen}
className={classnames(
"components-custom-gradient-picker__control-point-button",
{
"is-active": isOpen,
}
)}
{...additionalProps}
/>
<VisuallyHidden id={descriptionId}>
{__(
"Use your left or right arrow keys or drag and drop with the mouse to change the gradient position. Press the button to change the color or remove the control point."
)}
</VisuallyHidden>
</>
);
}
function GradientColorPickerDropdown({
popoverRef,
isRenderedInSidebar,
className,
...props
}) {
// Open the popover below the gradient control/insertion point
const popoverProps = useMemo(
() => ({
placement: "bottom",
offset: 8,
flip: false,
}),
[]
);
const mergedClassName = classnames(
"components-custom-gradient-picker__control-point-dropdown",
className
);
return (
<CustomColorPickerDropdown
isRenderedInSidebar={isRenderedInSidebar}
popoverRef={popoverRef}
popoverProps={popoverProps}
className={mergedClassName}
{...props}
/>
);
}
function getReadableColor(value, colors) {
if (!value) {
return "";
}
if (!colors) {
return value;
}
if (value.startsWith("var(--global-")) {
let slug = value.replace("var(--global-", "");
slug = slug.substring(0, 9);
slug = slug.replace(",", "");
const found = colors.find((option) => option.slug === slug);
if (found) {
return found.color;
}
}
return value;
}
function ControlPoints({
disableRemove,
gradientPickerDomRef,
ignoreMarkerPosition,
value: controlPoints,
onChange,
onStartControlPointChange,
onStopControlPointChange,
isRenderedInSidebar,
popoverRef,
activePalette,
}) {
const controlPointMoveState = useRef();
const onMouseMove = (event) => {
const relativePosition = getHorizontalRelativeGradientPosition(
event.clientX,
gradientPickerDomRef.current
);
const { initialPosition, index, significantMoveHappened } =
controlPointMoveState.current;
if (
!significantMoveHappened &&
Math.abs(initialPosition - relativePosition) >=
MINIMUM_SIGNIFICANT_MOVE
) {
controlPointMoveState.current.significantMoveHappened = true;
}
onChange(
updateControlPointPosition(controlPoints, index, relativePosition)
);
};
const cleanEventListeners = () => {
if (
window &&
window.removeEventListener &&
controlPointMoveState.current &&
controlPointMoveState.current.listenersActivated
) {
window.removeEventListener("mousemove", onMouseMove);
window.removeEventListener("mouseup", cleanEventListeners);
onStopControlPointChange();
controlPointMoveState.current.listenersActivated = false;
}
};
// Adding `cleanEventListeners` to the dependency array below requires the function itself to be wrapped in a `useCallback`
// This memoization would prevent the event listeners from being properly cleaned.
// Instead, we'll pass a ref to the function in our `useEffect` so `cleanEventListeners` itself is no longer a dependency.
const cleanEventListenersRef = useRef();
cleanEventListenersRef.current = cleanEventListeners;
useEffect(() => {
return () => {
cleanEventListenersRef.current();
};
}, []);
const disableCustomColors = false;
const colors = activePalette ? activePalette : useSetting("color.palette");
return controlPoints.map((point, index) => {
const initialPosition = point?.position;
const pointColor = getReadableColor(point.color, colors);
return (
ignoreMarkerPosition !== initialPosition && (
<GradientColorPickerDropdown
isRenderedInSidebar={isRenderedInSidebar}
key={index}
popoverRef={popoverRef}
onClose={onStopControlPointChange}
renderToggle={({ isOpen, onToggle }) => (
<ControlPointButton
key={index}
onClick={() => {
if (
controlPointMoveState.current &&
controlPointMoveState.current
.significantMoveHappened
) {
return;
}
if (isOpen) {
onStopControlPointChange();
} else {
onStartControlPointChange();
}
onToggle();
}}
onMouseDown={() => {
if (window && window.addEventListener) {
controlPointMoveState.current = {
initialPosition,
index,
significantMoveHappened: false,
listenersActivated: true,
};
onStartControlPointChange();
window.addEventListener(
"mousemove",
onMouseMove
);
window.addEventListener(
"mouseup",
cleanEventListeners
);
}
}}
onKeyDown={(event) => {
if (event.code === "ArrowLeft") {
// Stop propagation of the key press event to avoid focus moving
// to another editor area.
event.stopPropagation();
onChange(
updateControlPointPosition(
controlPoints,
index,
clampPercent(
point.position -
KEYBOARD_CONTROL_POINT_VARIATION
)
)
);
} else if (event.code === "ArrowRight") {
// Stop propagation of the key press event to avoid focus moving
// to another editor area.
event.stopPropagation();
onChange(
updateControlPointPosition(
controlPoints,
index,
clampPercent(
point.position +
KEYBOARD_CONTROL_POINT_VARIATION
)
)
);
}
}}
isOpen={isOpen}
position={point.position}
color={point.color}
/>
)}
renderContent={({ onClose }) => (
<div className="kadence-pop-gradient-color-picker">
<HStack
className="components-custom-gradient-picker__remove-control-point-wrapper"
alignment="center"
>
<Button
onClick={() => {
onClose();
}}
variant="link"
>
{__("Close Color Picker", "kadence")}
</Button>
</HStack>
{!disableCustomColors && (
<ColorPicker
color={pointColor}
onChange={(color) => {
onChange(
updateControlPointColor(
controlPoints,
index,
colord(color.rgb).toRgbString()
)
);
}}
onChangeComplete={(color) => {
onChange(
updateControlPointColor(
controlPoints,
index,
colord(color.rgb).toRgbString()
)
);
}}
/>
)}
{colors && (
<>
<div
style={{
paddingTop: "15px",
paddingBottom: "15px",
}}
className="kadence-swatches-wrap"
>
{map(
colors,
({ color, slug, name }) => {
const key = `${color}${
slug || ""
}`;
const palette = slug.replace(
"theme-",
""
);
const isActive =
slug.startsWith(
"palette"
) && pointColor === color;
return (
<div
key={key}
style={{
width: 26,
height: 26,
marginBottom: 0,
transform:
"scale(1)",
transition:
"100ms transform ease",
}}
className="kadence-swatche-item-wrap"
>
<Button
className={`kadence-swatch-item ${
isActive
? "swatch-active"
: "swatch-inactive"
}`}
style={{
height: "100%",
width: "100%",
border: "1px solid rgb(218, 218, 218)",
borderRadius:
"50%",
color:
slug ===
"palette10"
? "var(--global-palette10)"
: `${color}`,
boxShadow: `inset 0 0 0 ${
26 / 2
}px`,
transition:
"100ms box-shadow ease",
}}
onClick={() => {
if (
slug.startsWith(
"palette"
)
) {
onChange(
updateControlPointColor(
controlPoints,
index,
"var(--global-" +
palette +
"," +
color +
")"
)
);
} else {
onChange(
updateControlPointColor(
controlPoints,
index,
colord(
color
).toRgbString()
)
);
}
}}
tabIndex={0}
>
<Icon
className="dashicon"
icon={globeIcon}
/>
</Button>
</div>
);
}
)}
</div>
</>
)}
{!disableRemove && controlPoints.length > 2 && (
<HStack
className="components-custom-gradient-picker__remove-control-point-wrapper"
alignment="center"
>
<Button
onClick={() => {
onChange(
removeControlPoint(
controlPoints,
index
)
);
onClose();
}}
variant="link"
>
{__("Remove Control Point", "kadence")}
</Button>
</HStack>
)}
</div>
)}
style={{
left: `${point.position}%`,
transform: "translateX( -50% )",
}}
/>
)
);
});
}
function InsertPoint({
value: controlPoints,
onChange,
onOpenInserter,
onCloseInserter,
insertPosition,
isRenderedInSidebar,
activePalette,
popoverRef,
}) {
const [alreadyInsertedPoint, setAlreadyInsertedPoint] = useState(false);
const disableCustomColors = false;
const colors = activePalette ? activePalette : useSetting("color.palette");
const [tempColor, setTempColor] = useState("");
const pointColor = getReadableColor(tempColor, colors);
return (
<GradientColorPickerDropdown
isRenderedInSidebar={isRenderedInSidebar}
popoverRef={popoverRef}
className="components-custom-gradient-picker__inserter"
onClose={() => {
onCloseInserter();
}}
renderToggle={({ isOpen, onToggle }) => (
<Button
aria-expanded={isOpen}
aria-haspopup="true"
onClick={() => {
if (isOpen) {
onCloseInserter();
} else {
setAlreadyInsertedPoint(false);
onOpenInserter();
}
onToggle();
}}
className="components-custom-gradient-picker__insert-point-dropdown"
icon={plus}
/>
)}
renderContent={() => (
<div className="kadence-pop-gradient-color-picker">
<HStack
className="components-custom-gradient-picker__remove-control-point-wrapper"
alignment="center"
>
<Button
onClick={() => {
onCloseInserter();
}}
variant="link"
>
{__("Close Color Picker", "kadence")}
</Button>
</HStack>
{!disableCustomColors && (
<ColorPicker
color={pointColor}
onChange={(color) => {
setTempColor(colord(color.rgb).toRgbString());
if (!alreadyInsertedPoint) {
onChange(
addControlPoint(
controlPoints,
insertPosition,
colord(color.rgb).toRgbString()
)
);
setAlreadyInsertedPoint(true);
} else {
onChange(
updateControlPointColorByPosition(
controlPoints,
insertPosition,
colord(color.rgb).toRgbString()
)
);
}
}}
onChangeComplete={(color) => {
setTempColor(colord(color.rgb).toRgbString());
if (!alreadyInsertedPoint) {
onChange(
addControlPoint(
controlPoints,
insertPosition,
colord(color.rgb).toRgbString()
)
);
setAlreadyInsertedPoint(true);
} else {
onChange(
updateControlPointColorByPosition(
controlPoints,
insertPosition,
colord(color.rgb).toRgbString()
)
);
}
}}
/>
)}
{colors && (
<div
style={{
paddingTop: "15px",
paddingBottom: "15px",
}}
className="kadence-swatches-wrap"
>
{map(colors, ({ color, slug, name }) => {
const key = `${color}${slug || ""}`;
const palette = slug.replace("theme-", "");
const isActive =
slug.startsWith("palette") &&
pointColor === color;
return (
<div
key={key}
style={{
width: 26,
height: 26,
marginBottom: 0,
transform: "scale(1)",
transition: "100ms transform ease",
}}
className="kadence-swatche-item-wrap"
>
<Button
className={`kadence-swatch-item ${
isActive
? "swatch-active"
: "swatch-inactive"
}`}
style={{
height: "100%",
width: "100%",
border: "1px solid rgb(218, 218, 218)",
borderRadius: "50%",
color:
slug === "palette10"
? "var(--global-palette10)"
: `${color}`,
boxShadow: `inset 0 0 0 ${
26 / 2
}px`,
transition:
"100ms box-shadow ease",
}}
onClick={() => {
setTempColor(
colord(color).toRgbString()
);
if (!alreadyInsertedPoint) {
if (
slug.startsWith(
"palette"
)
) {
onChange(
addControlPoint(
controlPoints,
insertPosition,
"var(--global-" +
palette +
"," +
color +
")"
)
);
} else {
onChange(
addControlPoint(
controlPoints,
insertPosition,
colord(
color
).toRgbString()
)
);
}
setAlreadyInsertedPoint(
true
);
} else {
if (
slug.startsWith(
"palette"
)
) {
onChange(
updateControlPointColorByPosition(
controlPoints,
insertPosition,
"var(--global-" +
palette +
"," +
color +
")"
)
);
} else {
onChange(
updateControlPointColorByPosition(
controlPoints,
insertPosition,
colord(
color
).toRgbString()
)
);
}
}
}}
tabIndex={0}
>
<Icon
className="dashicon"
icon={globeIcon}
/>
</Button>
</div>
);
})}
</div>
)}
</div>
)}
style={
insertPosition !== null
? {
left: `${insertPosition}%`,
transform: "translateX( -50% )",
}
: undefined
}
/>
);
}
ControlPoints.InsertPoint = InsertPoint;
export default ControlPoints;

View File

@@ -0,0 +1,183 @@
/**
* External dependencies
*/
import { some } from 'lodash';
import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { useRef, useReducer } from '@wordpress/element';
/**
* Internal dependencies
*/
import ControlPoints from './control-points';
import { getHorizontalRelativeGradientPosition } from './utils';
import { MINIMUM_DISTANCE_BETWEEN_INSERTER_AND_POINT } from './constants';
function customGradientBarReducer( state, action ) {
switch ( action.type ) {
case 'MOVE_INSERTER':
if ( state.id === 'IDLE' || state.id === 'MOVING_INSERTER' ) {
return {
id: 'MOVING_INSERTER',
insertPosition: action.insertPosition,
};
}
break;
case 'STOP_INSERTER_MOVE':
if ( state.id === 'MOVING_INSERTER' ) {
return {
id: 'IDLE',
};
}
break;
case 'OPEN_INSERTER':
if ( state.id === 'MOVING_INSERTER' ) {
return {
id: 'INSERTING_CONTROL_POINT',
insertPosition: state.insertPosition,
};
}
break;
case 'CLOSE_INSERTER':
if ( state.id === 'INSERTING_CONTROL_POINT' ) {
return {
id: 'IDLE',
};
}
break;
case 'START_CONTROL_CHANGE':
if ( state.id === 'IDLE' ) {
return {
id: 'MOVING_CONTROL_POINT',
};
}
break;
case 'STOP_CONTROL_CHANGE':
if ( state.id === 'MOVING_CONTROL_POINT' ) {
return {
id: 'IDLE',
};
}
break;
}
return state;
}
const customGradientBarReducerInitialState = { id: 'IDLE' };
export default function CustomGradientBar( {
background,
hasGradient,
value: controlPoints,
onChange,
disableInserter = false,
isRenderedInSidebar,
activePalette,
} ) {
const gradientMarkersContainerDomRef = useRef();
const [ gradientBarState, gradientBarStateDispatch ] = useReducer(
customGradientBarReducer,
customGradientBarReducerInitialState
);
const popoverRef = useRef();
const onMouseEnterAndMove = ( event ) => {
const insertPosition = getHorizontalRelativeGradientPosition(
event.clientX,
gradientMarkersContainerDomRef.current
);
// If the insert point is close to an existing control point don't show it.
if (
some( controlPoints, ( { position } ) => {
return (
Math.abs( insertPosition - position ) <
MINIMUM_DISTANCE_BETWEEN_INSERTER_AND_POINT
);
} )
) {
if ( gradientBarState.id === 'MOVING_INSERTER' ) {
gradientBarStateDispatch( { type: 'STOP_INSERTER_MOVE' } );
}
return;
}
gradientBarStateDispatch( { type: 'MOVE_INSERTER', insertPosition } );
};
const onMouseLeave = () => {
gradientBarStateDispatch( { type: 'STOP_INSERTER_MOVE' } );
};
const isMovingInserter = gradientBarState.id === 'MOVING_INSERTER';
const isInsertingControlPoint =
gradientBarState.id === 'INSERTING_CONTROL_POINT';
return (
<div
ref={ popoverRef }
className={ classnames(
'components-custom-gradient-picker__gradient-bar',
{ 'has-gradient': hasGradient }
) }
onMouseEnter={ onMouseEnterAndMove }
onMouseMove={ onMouseEnterAndMove }
style={ { background } }
onMouseLeave={ onMouseLeave }
>
<div
ref={ gradientMarkersContainerDomRef }
className="components-custom-gradient-picker__markers-container"
>
{ ! disableInserter &&
( isMovingInserter || isInsertingControlPoint ) && (
<ControlPoints.InsertPoint
isRenderedInSidebar={ isRenderedInSidebar }
insertPosition={ gradientBarState.insertPosition }
value={ controlPoints }
onChange={ onChange }
activePalette={ activePalette }
popoverRef={ popoverRef }
onOpenInserter={ () => {
gradientBarStateDispatch( {
type: 'OPEN_INSERTER',
} );
} }
onCloseInserter={ () => {
gradientBarStateDispatch( {
type: 'CLOSE_INSERTER',
} );
} }
/>
) }
<ControlPoints
isRenderedInSidebar={ isRenderedInSidebar }
activePalette={ activePalette }
disableRemove={ disableInserter }
gradientPickerDomRef={ gradientMarkersContainerDomRef }
ignoreMarkerPosition={
isInsertingControlPoint
? gradientBarState.insertPosition
: undefined
}
value={ controlPoints }
onChange={ onChange }
popoverRef={ popoverRef }
onStartControlPointChange={ () => {
gradientBarStateDispatch( {
type: 'START_CONTROL_CHANGE',
} );
} }
onStopControlPointChange={ () => {
gradientBarStateDispatch( {
type: 'STOP_CONTROL_CHANGE',
} );
} }
/>
</div>
</div>
);
}

View File

@@ -0,0 +1,187 @@
/**
* Internal dependencies
*/
import { MINIMUM_DISTANCE_BETWEEN_POINTS } from './constants';
/**
* Control point for the gradient bar.
*
* @typedef {Object} ControlPoint
* @property {string} color Color of the control point.
* @property {number} position Integer position of the control point as a percentage.
*/
/**
* Color as parsed from the gradient by gradient-parser.
*
* @typedef {Object} Color
* @property {string} r Red component.
* @property {string} g Green component.
* @property {string} b Green component.
* @property {string} [a] Optional alpha component.
*/
/**
* Clamps a number between 0 and 100.
*
* @param {number} value Value to clamp.
*
* @return {number} Value clamped between 0 and 100.
*/
export function clampPercent( value ) {
return Math.max( 0, Math.min( 100, value ) );
}
/**
* Check if a control point is overlapping with another.
*
* @param {ControlPoint[]} value Array of control points.
* @param {number} initialIndex Index of the position to test.
* @param {number} newPosition New position of the control point.
* @param {number} minDistance Distance considered to be overlapping.
*
* @return {boolean} True if the point is overlapping.
*/
export function isOverlapping(
value,
initialIndex,
newPosition,
minDistance = MINIMUM_DISTANCE_BETWEEN_POINTS
) {
const initialPosition = value[ initialIndex ].position;
const minPosition = Math.min( initialPosition, newPosition );
const maxPosition = Math.max( initialPosition, newPosition );
return value.some( ( { position }, index ) => {
return (
index !== initialIndex &&
( Math.abs( position - newPosition ) < minDistance ||
( minPosition < position && position < maxPosition ) )
);
} );
}
/**
* Adds a control point from an array and returns the new array.
*
* @param {ControlPoint[]} points Array of control points.
* @param {number} position Position to insert the new point.
* @param {Color} color Color to update the control point at index.
*
* @return {ControlPoint[]} New array of control points.
*/
export function addControlPoint( points, position, color ) {
const nextIndex = points.findIndex(
( point ) => point.position > position
);
const newPoint = { color, position };
const newPoints = points.slice();
newPoints.splice( nextIndex - 1, 0, newPoint );
return newPoints;
}
/**
* Removes a control point from an array and returns the new array.
*
* @param {ControlPoint[]} points Array of control points.
* @param {number} index Index to remove.
*
* @return {ControlPoint[]} New array of control points.
*/
export function removeControlPoint( points, index ) {
return points.filter( ( point, pointIndex ) => {
return pointIndex !== index;
} );
}
/**
* Updates a control point from an array and returns the new array.
*
* @param {ControlPoint[]} points Array of control points.
* @param {number} index Index to update.
* @param {ControlPoint[]} newPoint New control point to replace the index.
*
* @return {ControlPoint[]} New array of control points.
*/
export function updateControlPoint( points, index, newPoint ) {
const newValue = points.slice();
newValue[ index ] = newPoint;
return newValue;
}
/**
* Updates the position of a control point from an array and returns the new array.
*
* @param {ControlPoint[]} points Array of control points.
* @param {number} index Index to update.
* @param {number} newPosition Position to move the control point at index.
*
* @return {ControlPoint[]} New array of control points.
*/
export function updateControlPointPosition( points, index, newPosition ) {
if ( isOverlapping( points, index, newPosition ) ) {
return points;
}
const newPoint = {
...points[ index ],
position: newPosition,
};
return updateControlPoint( points, index, newPoint );
}
/**
* Updates the position of a control point from an array and returns the new array.
*
* @param {ControlPoint[]} points Array of control points.
* @param {number} index Index to update.
* @param {Color} newColor Color to update the control point at index.
*
* @return {ControlPoint[]} New array of control points.
*/
export function updateControlPointColor( points, index, newColor ) {
const newPoint = {
...points[ index ],
color: newColor,
};
return updateControlPoint( points, index, newPoint );
}
/**
* Updates the position of a control point from an array and returns the new array.
*
* @param {ControlPoint[]} points Array of control points.
* @param {number} position Position of the color stop.
* @param {string} newColor Color to update the control point at index.
*
* @return {ControlPoint[]} New array of control points.
*/
export function updateControlPointColorByPosition(
points,
position,
newColor
) {
const index = points.findIndex( ( point ) => point.position === position );
return updateControlPointColor( points, index, newColor );
}
/**
* Gets the horizontal coordinate when dragging a control point with the mouse.
*
* @param {number} mouseXCoordinate Horizontal coordinate of the mouse position.
* @param {Element} containerElement Container for the gradient picker.
*
* @return {number} Whole number percentage from the left.
*/
export function getHorizontalRelativeGradientPosition(
mouseXCoordinate,
containerElement
) {
if ( ! containerElement ) {
return;
}
const { x, width } = containerElement.getBoundingClientRect();
const absolutePositionValue = mouseXCoordinate - x;
return Math.round(
clampPercent( ( absolutePositionValue * 100 ) / width )
);
}

View File

@@ -0,0 +1,443 @@
/**
* External dependencies
*/
import classnames from 'classnames';
//import './editor.scss';
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { AnglePickerControl, Flex, FlexItem,__experimentalUnitControl as UnitControl, SelectControl, Button } from '@wordpress/components';
/**
* Internal dependencies
*/
import { settings } from '@wordpress/icons';
import CustomGradientBar from './gradient-bar';
import {
getGradientAstWithDefault,
getLinearGradientRepresentation,
getGradientAstWithControlPoints,
getStopCssColor,
} from './utils';
import { serializeGradient } from './serializer';
import {
DEFAULT_LINEAR_GRADIENT_ANGLE,
HORIZONTAL_GRADIENT_ORIENTATION,
GRADIENT_OPTIONS,
RADIAL_GRADIENT_ORIENTATION,
DEFAULT_GRADIENT,
DEFAULT_RADIAL_GRADIENT_POSITION,
GRADIENT_POSITION_OPTIONS,
DEFAULT_RADIAL_GRADIENT_SHAPE,
} from './constants';
// import {
// AccessoryWrapper,
// SelectWrapper,
// } from './styles/custom-gradient-picker-styles';
const GradientAnglePicker = ( { gradientAST, hasGradient, onChange } ) => {
const angle =
gradientAST?.orientation?.value ?? DEFAULT_LINEAR_GRADIENT_ANGLE;
const onAngleChange = ( newAngle ) => {
onChange(
serializeGradient( {
...gradientAST,
orientation: {
type: 'angular',
value: newAngle,
},
} )
);
};
return (
<AnglePickerControl
__nextHasNoMarginBottom
onChange={ onAngleChange }
labelPosition="top"
value={ hasGradient ? angle : '' }
/>
);
};
const GradientTypePicker = ( { gradientAST, hasGradient, onChange } ) => {
const { type } = gradientAST;
const onSetLinearGradient = () => {
onChange(
serializeGradient( {
...gradientAST,
...( { orientation: HORIZONTAL_GRADIENT_ORIENTATION } ),
type: 'linear-gradient',
} )
);
};
const onSetRadialGradient = () => {
onChange(
serializeGradient( {
...gradientAST,
...( { orientation: RADIAL_GRADIENT_ORIENTATION, }),
type: 'radial-gradient',
} )
);
};
const handleOnChange = ( next ) => {
if ( next === 'linear-gradient' ) {
onSetLinearGradient();
}
if ( next === 'radial-gradient' ) {
onSetRadialGradient();
}
};
return (
<SelectControl
className="components-custom-gradient-picker__type-picker kadence-select-large"
label={ __( 'Type' ) }
labelPosition="top"
onChange={ handleOnChange }
options={ GRADIENT_OPTIONS }
//size="__unstable-large"
value={ hasGradient && type }
/>
);
};
const GradientPositionPicker = ( { gradientAST, hasGradient, onChange } ) => {
let position = DEFAULT_RADIAL_GRADIENT_POSITION;
let positionLeft = '50%';
let positionTop = '50%';
let positionType = 'position-keyword';
if ( gradientAST?.orientation && gradientAST?.orientation[0]?.at?.value?.x?.value ) {
positionType = gradientAST.orientation[0].at.value.x.type;
if ( positionType !== 'position-keyword' ) {
position = gradientAST.orientation[0].at.value.x.value + '% ' + gradientAST.orientation[0].at.value.y.value + '%';
positionLeft = gradientAST.orientation[0].at.value.x.value + '%';
positionTop = gradientAST.orientation[0].at.value.y.value + '%';
} else {
position = gradientAST.orientation[0].at.value.x.value + ' ' + gradientAST.orientation[0].at.value.y.value;
}
}
const onPositionChange = ( newPosition ) => {
const positionArray = newPosition.split( ' ' );
onChange(
serializeGradient( {
...gradientAST,
orientation: [ {
type: 'shape',
value: gradientAST.orientation[0].value,
at: {
type: 'position',
value: {
x: {
type: 'position-keyword',
value: ( undefined !== positionArray[0] && positionArray[0] ? positionArray[0] : 'center' )
},
y: {
type: 'position-keyword',
value: ( undefined !== positionArray[1] && positionArray[1] ? positionArray[1] : 'center' )
}
}
}
} ],
} )
);
};
const onLeftPositionChange = ( left ) => {
onChange(
serializeGradient( {
...gradientAST,
orientation: [ {
type: 'shape',
value: gradientAST.orientation[0].value,
at: {
type: 'position',
value: {
x: {
type: '%',
value: parseInt( left, 10 ),
},
y: gradientAST.orientation[0].at.value.y,
}
}
} ],
} )
);
};
const onTopPositionChange = ( top ) => {
onChange(
serializeGradient( {
...gradientAST,
orientation: [ {
type: 'shape',
value: gradientAST.orientation[0].value,
at: {
type: 'position',
value: {
x: gradientAST.orientation[0].at.value.x,
y: {
type: '%',
value: parseInt( top, 10 ),
}
}
}
} ],
} )
);
};
const onPositionTypeChange = ( type ) => {
const positionArray = position.split( ' ' );
let positionX = '%' === type ? 50 : 'center';
let positionY = '%' === type ? 50 : 'center';
if ( positionArray[0] ) {
switch ( positionArray[ 0 ] ) {
case 'left':
positionX = 0;
break;
case 'right':
positionX = '100';
break;
case 'center':
positionX = 50;
break;
case 0:
positionY = 'left';
break;
case 100:
positionY = 'right';
break;
case 50:
positionY = 'center';
break;
}
}
if ( positionArray[1] ) {
switch ( positionArray[ 1 ] ) {
case 'top':
positionY = 0;
break;
case 'bottom':
positionY = 100;
break;
case 'center':
positionY = 50;
break;
case 0:
positionY = 'top';
break;
case 100:
positionY = 'bottom';
break;
case 50:
positionY = 'center';
break;
}
}
onChange(
serializeGradient( {
...gradientAST,
orientation: [ {
type: 'shape',
value: gradientAST.orientation[0].value,
at: {
type: 'position',
value: {
x: {
type: type,
value: positionX
},
y: {
type: type,
value: positionY
}
}
}
} ],
} )
);
};
if ( ! hasGradient ) {
return;
}
return (
<div className={ `components-base-control kadence-gradient-position-control` }>
<Flex
justify="space-between"
className={ 'kadence-gradient-position_header' }
>
<FlexItem>
<label className="kadence-gradient-position__label">{ __( 'Position', 'kadence-blocks' ) }</label>
</FlexItem>
</Flex>
{ positionType === 'position-keyword' && (
<div className={ 'kadence-controls-content' }>
<SelectControl
className="components-custom-gradient-picker__position-picker"
// label={ __( 'Position', 'kadence-blocks' ) }
// labelPosition="top"
onChange={ onPositionChange }
options={ GRADIENT_POSITION_OPTIONS }
value={ position }
/>
<Button
className={'kadence-control-toggle-advanced only-icon'}
label={ __( 'Set custom position', 'kadence-blocks' ) }
icon={ settings }
onClick={ () => onPositionTypeChange( '%' ) }
isPressed={ false }
isTertiary={ true }
/>
</div>
) }
{ positionType !== 'position-keyword' && (
<div className={ 'kadence-controls-content' }>
<UnitControl
labelPosition="left"
label={ __( 'Left', 'kadence-blocks' ) }
max={ 100 }
min={ 0 }
units={ [ { value: '%', label: '%' } ] }
value={ positionLeft }
onChange={ onLeftPositionChange }
/>
<UnitControl
labelPosition="left"
label={ __( 'Top', 'kadence-blocks' ) }
max={ 100 }
min={ 0 }
value={ positionTop }
units={ [ { value: '%', label: '%' } ] }
onChange={ onTopPositionChange }
/>
<Button
className={'kadence-control-toggle-advanced only-icon'}
label={ __( 'Set standard position', 'kadence-blocks' ) }
icon={ settings }
onClick={ () => onPositionTypeChange( 'position-keyword' ) }
isPrimary={true}
isPressed={ true }
/>
</div>
) }
</div>
);
};
const GradientShapePicker = ( { gradientAST, hasGradient, onChange } ) => {
let shape = DEFAULT_RADIAL_GRADIENT_SHAPE;
if ( gradientAST?.orientation && gradientAST?.orientation[0]?.type === 'shape' && gradientAST?.orientation[0]?.value ) {
shape = gradientAST.orientation[0].value;
}
const onShapeChange = ( newShape ) => {
onChange(
serializeGradient( {
...gradientAST,
orientation: [ {
type: 'shape',
value: newShape,
at: gradientAST.orientation[0].at,
} ],
} )
);
};
return (
<SelectControl
className="components-custom-gradient-picker__shape-picker kadence-select-large"
label={ __( 'Shape', 'kadence-blocks' ) }
labelPosition="top"
onChange={ onShapeChange }
options={ [
{ value: 'ellipse', label: __( 'Ellipse', 'kadence-blocks' ) },
{ value: 'circle', label: __( 'Circle', 'kadence-blocks' ) },
] }
value={ hasGradient && shape }
/>
);
};
export default function CustomGradientPicker( {
value,
onChange,
isRenderedInSidebar = false,
activePalette = [],
} ) {
const gradientAST = getGradientAstWithDefault( value );
// On radial gradients the bar should display a linear gradient.
// On radial gradients the bar represents a slice of the gradient from the center until the outside.
// On liner gradients the bar represents the color stops from left to right independently of the angle.
const background = getLinearGradientRepresentation( gradientAST );
const hasGradient = gradientAST.value !== DEFAULT_GRADIENT;
// Control points color option may be hex from presets, custom colors will be rgb.
// The position should always be a percentage.
const controlPoints = gradientAST.colorStops.map( ( colorStop ) => ( {
color: getStopCssColor( colorStop ),
position: parseInt( colorStop.length.value ),
} ) );
return (
<div className={ 'components-base-control components-custom-gradient-picker kadence-gradient-control' }>
<div className='wrap-components-custom-gradient-picker'>
<CustomGradientBar
isRenderedInSidebar={isRenderedInSidebar}
background={ background }
hasGradient={ hasGradient }
value={ controlPoints }
activePalette={ activePalette }
onChange={ ( newControlPoints ) => {
onChange(
serializeGradient(
getGradientAstWithControlPoints(
gradientAST,
newControlPoints
)
)
);
} }
/>
</div>
<Flex
gap={ 3 }
className="components-custom-gradient-picker__ui-line"
>
<div className='components-custom-gradient-picker__item components-custom-gradient-picker-type'>
<GradientTypePicker
gradientAST={ gradientAST }
hasGradient={ hasGradient }
onChange={ onChange }
/>
</div>
{ gradientAST.type === 'linear-gradient' && (
<div className='components-custom-gradient-picker__item components-custom-gradient-picker-angle'>
<GradientAnglePicker
gradientAST={ gradientAST }
hasGradient={ hasGradient }
onChange={ onChange }
/>
</div>
) }
{ gradientAST.type === 'radial-gradient' && (
<div className='components-custom-gradient-picker__item components-custom-gradient-picker-shape'>
<GradientShapePicker
gradientAST={ gradientAST }
hasGradient={ hasGradient }
onChange={ onChange }
/>
</div>
) }
</Flex>
{ gradientAST.type === 'radial-gradient' && (
<Flex
gap={ 3 }
className="components-custom-gradient-picker__ui-line"
>
<div className='components-custom-gradient-picker__item components-custom-gradient-picker-position'>
<GradientPositionPicker
gradientAST={ gradientAST }
hasGradient={ hasGradient }
onChange={ onChange }
/>
</div>
</Flex>
) }
</div>
);
}

View File

@@ -0,0 +1,517 @@
// Copyright (c) 2014 Rafael Caricio. All rights reserved.
// Use of this source code is governed by (The MIT License).
var GradientParser = (GradientParser || {});
GradientParser.stringify = (function() {
var visitor = {
'visit_linear-gradient': function(node) {
return visitor.visit_gradient(node);
},
'visit_repeating-linear-gradient': function(node) {
return visitor.visit_gradient(node);
},
'visit_radial-gradient': function(node) {
return visitor.visit_gradient(node);
},
'visit_repeating-radial-gradient': function(node) {
return visitor.visit_gradient(node);
},
'visit_gradient': function(node) {
var orientation = visitor.visit(node.orientation);
if (orientation) {
orientation += ', ';
}
return node.type + '(' + orientation + visitor.visit(node.colorStops) + ')';
},
'visit_shape': function(node) {
var result = node.value,
at = visitor.visit(node.at),
style = visitor.visit(node.style);
if (style) {
result += ' ' + style;
}
if (at) {
result += ' at ' + at;
}
return result;
},
'visit_default-radial': function(node) {
var result = '',
at = visitor.visit(node.at);
if (at) {
result += at;
}
return result;
},
'visit_extent-keyword': function(node) {
var result = node.value,
at = visitor.visit(node.at);
if (at) {
result += ' at ' + at;
}
return result;
},
'visit_position-keyword': function(node) {
return node.value;
},
'visit_position': function(node) {
return visitor.visit(node.value.x) + ' ' + visitor.visit(node.value.y);
},
'visit_%': function(node) {
return node.value + '%';
},
'visit_em': function(node) {
return node.value + 'em';
},
'visit_px': function(node) {
return node.value + 'px';
},
'visit_literal': function(node) {
return visitor.visit_color(node.value, node);
},
'visit_hex': function(node) {
return visitor.visit_color('#' + node.value, node);
},
'visit_rgb': function(node) {
return visitor.visit_color('rgb(' + node.value.join(', ') + ')', node);
},
'visit_rgba': function(node) {
return visitor.visit_color('rgba(' + node.value.join(', ') + ')', node);
},
'visit_color': function(resultColor, node) {
var result = resultColor,
length = visitor.visit(node.length);
if (length) {
result += ' ' + length;
}
return result;
},
'visit_angular': function(node) {
return node.value + 'deg';
},
'visit_directional': function(node) {
return 'to ' + node.value;
},
'visit_array': function(elements) {
var result = '',
size = elements.length;
elements.forEach(function(element, i) {
result += visitor.visit(element);
if (i < size - 1) {
result += ', ';
}
});
return result;
},
'visit': function(element) {
if (!element) {
return '';
}
var result = '';
if (element instanceof Array) {
return visitor.visit_array(element, result);
} else if (element.type) {
var nodeVisitor = visitor['visit_' + element.type];
if (nodeVisitor) {
return nodeVisitor(element);
} else {
throw Error('Missing visitor visit_' + element.type);
}
} else {
throw Error('Invalid node.');
}
}
};
return function(root) {
return visitor.visit(root);
};
})();
// Copyright (c) 2014 Rafael Caricio. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var GradientParser = (GradientParser || {});
GradientParser.parse = (function() {
var tokens = {
linearGradient: /^(\-(webkit|o|ms|moz)\-)?(linear\-gradient)/i,
repeatingLinearGradient: /^(\-(webkit|o|ms|moz)\-)?(repeating\-linear\-gradient)/i,
radialGradient: /^(\-(webkit|o|ms|moz)\-)?(radial\-gradient)/i,
repeatingRadialGradient: /^(\-(webkit|o|ms|moz)\-)?(repeating\-radial\-gradient)/i,
sideOrCorner: /^to (left (top|bottom)|right (top|bottom)|left|right|top|bottom)/i,
extentKeywords: /^(closest\-side|closest\-corner|farthest\-side|farthest\-corner|contain|cover)/,
positionKeywords: /^(left|center|right|top|bottom)/i,
pixelValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))px/,
percentageValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))\%/,
emValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))em/,
angleValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))deg/,
startCall: /^\(/,
endCall: /^\)/,
comma: /^,/,
hexColor: /^\#([0-9a-fA-F]+)/,
literalColor: /^([a-zA-Z]+)/,
rgbColor: /^rgb/i,
rgbaColor: /^rgba/i,
varColor: /^var/i,
number: /^(([0-9]*\.[0-9]+)|([0-9]+\.?))/,
variable: /var\(([a-zA-Z-0-9_#,\s]+)\)/
};
var input = '';
function error(msg) {
var err = new Error(input + ': ' + msg);
err.source = input;
throw err;
}
function getAST() {
var ast = matchListDefinitions();
if (input.length > 0) {
error('Invalid input not EOF');
}
return ast;
}
function matchListDefinitions() {
return matchListing(matchDefinition);
}
function matchDefinition() {
return matchGradient(
'linear-gradient',
tokens.linearGradient,
matchLinearOrientation) ||
matchGradient(
'repeating-linear-gradient',
tokens.repeatingLinearGradient,
matchLinearOrientation) ||
matchGradient(
'radial-gradient',
tokens.radialGradient,
matchListRadialOrientations) ||
matchGradient(
'repeating-radial-gradient',
tokens.repeatingRadialGradient,
matchListRadialOrientations);
}
function matchGradient(gradientType, pattern, orientationMatcher) {
return matchCall(pattern, function(captures) {
var orientation = orientationMatcher();
if (orientation) {
if (!scan(tokens.comma)) {
error('Missing comma before color stops');
}
}
return {
type: gradientType,
orientation: orientation,
colorStops: matchListing(matchColorStop)
};
});
}
function matchCall(pattern, callback) {
var captures = scan(pattern);
if (captures) {
if (!scan(tokens.startCall)) {
error('Missing (');
}
var result = callback(captures);
if (!scan(tokens.endCall)) {
error('Missing )');
}
return result;
}
}
function matchLinearOrientation() {
return matchSideOrCorner() ||
matchAngle();
}
function matchSideOrCorner() {
return match('directional', tokens.sideOrCorner, 1);
}
function matchAngle() {
return match('angular', tokens.angleValue, 1);
}
function matchListRadialOrientations() {
var radialOrientations,
radialOrientation = matchRadialOrientation(),
lookaheadCache;
if (radialOrientation) {
radialOrientations = [];
radialOrientations.push(radialOrientation);
lookaheadCache = input;
if (scan(tokens.comma)) {
radialOrientation = matchRadialOrientation();
if (radialOrientation) {
radialOrientations.push(radialOrientation);
} else {
input = lookaheadCache;
}
}
}
return radialOrientations;
}
function matchRadialOrientation() {
var radialType = matchCircle() ||
matchEllipse();
if (radialType) {
radialType.at = matchAtPosition();
} else {
var extent = matchExtentKeyword();
if (extent) {
radialType = extent;
var positionAt = matchAtPosition();
if (positionAt) {
radialType.at = positionAt;
}
} else {
var defaultPosition = matchPositioning();
if (defaultPosition) {
radialType = {
type: 'default-radial',
at: defaultPosition
};
}
}
}
return radialType;
}
function matchCircle() {
var circle = match('shape', /^(circle)/i, 0);
if (circle) {
circle.style = matchLength() || matchExtentKeyword();
}
return circle;
}
function matchEllipse() {
var ellipse = match('shape', /^(ellipse)/i, 0);
if (ellipse) {
ellipse.style = matchDistance() || matchExtentKeyword();
}
return ellipse;
}
function matchExtentKeyword() {
return match('extent-keyword', tokens.extentKeywords, 1);
}
function matchAtPosition() {
if (match('position', /^at/, 0)) {
var positioning = matchPositioning();
if (!positioning) {
error('Missing positioning value');
}
return positioning;
}
}
function matchPositioning() {
var location = matchCoordinates();
if (location.x || location.y) {
return {
type: 'position',
value: location
};
}
}
function matchCoordinates() {
return {
x: matchDistance(),
y: matchDistance()
};
}
function matchListing(matcher) {
var captures = matcher(),
result = [];
if (captures) {
result.push(captures);
while (scan(tokens.comma)) {
captures = matcher();
if (captures) {
result.push(captures);
} else {
error('One extra comma');
}
}
}
return result;
}
function matchColorStop() {
var color = matchColor();
if (!color) {
error('Expected color definition');
}
color.length = matchDistance();
return color;
}
function matchColor() {
return matchHexColor() ||
matchRGBAColor() ||
matchRGBColor() ||
matchVARColor() ||
matchLiteralColor();
}
function matchLiteralColor() {
return match('literal', tokens.literalColor, 0);
}
function matchVARColor() {
return match('literal', tokens.variable, 0);
}
function matchHexColor() {
return match('hex', tokens.hexColor, 1);
}
function matchRGBColor() {
return matchCall(tokens.rgbColor, function() {
return {
type: 'rgb',
value: matchListing(matchNumber)
};
});
}
function matchRGBAColor() {
return matchCall(tokens.rgbaColor, function() {
return {
type: 'rgba',
value: matchListing(matchNumber)
};
});
}
function matchNumber() {
return scan(tokens.number)[1];
}
function matchDistance() {
return match('%', tokens.percentageValue, 1) ||
matchPositionKeyword() ||
matchLength();
}
function matchPositionKeyword() {
return match('position-keyword', tokens.positionKeywords, 1);
}
function matchLength() {
return match('px', tokens.pixelValue, 1) ||
match('em', tokens.emValue, 1);
}
function match(type, pattern, captureIndex) {
var captures = scan(pattern);
if (captures) {
return {
type: type,
value: captures[captureIndex]
};
}
}
function scan(regexp) {
var captures,
blankCaptures;
blankCaptures = /^[\n\r\t\s]+/.exec(input);
if (blankCaptures) {
consume(blankCaptures[0].length);
}
captures = regexp.exec(input);
if (captures) {
consume(captures[0].length);
}
return captures;
}
function consume(size) {
input = input.substr(size);
}
return function(code) {
input = code.toString();
return getAST();
};
})();
exports.parse = GradientParser.parse;
exports.stringify = GradientParser.stringify;

View File

@@ -0,0 +1,55 @@
export function serializeGradientColor( { type, value } ) {
if ( type === 'literal' ) {
return value;
}
if ( type === 'hex' ) {
return `#${ value }`;
}
return `${ type }(${ value.join( ',' ) })`;
}
export function serializeGradientPosition( position ) {
if ( ! position ) {
return '';
}
const { value, type } = position;
return `${ value }${ type }`;
}
export function serializeGradientColorStop( { type, value, length } ) {
return `${ serializeGradientColor( {
type,
value,
} ) } ${ serializeGradientPosition( length ) }`;
}
export function serializeGradientOrientation( type, orientation ) {
if ( 'radial-gradient' === type ) {
if ( ! orientation || ! orientation[0] || orientation[0].type !== 'shape' ) {
return;
}
if ( '%' === orientation[0].at.value.x.type ) {
return `${ orientation[0].value } at ${ orientation[0].at.value.x.value }% ${ orientation[0].at.value.y.value }%`;
}
return `${ orientation[0].value } at ${ orientation[0].at.value.x.value } ${ orientation[0].at.value.y.value }`;
}
if ( ! orientation || orientation.type !== 'angular' ) {
return;
}
return `${ orientation.value }deg`;
}
export function serializeGradient( { type, orientation, colorStops } ) {
const serializedOrientation = serializeGradientOrientation( type, orientation );
const serializedColorStops = colorStops
.sort( ( colorStop1, colorStop2 ) => {
return (
( colorStop1?.length?.value ?? 0 ) -
( colorStop2?.length?.value ?? 0 )
);
} )
.map( serializeGradientColorStop );
return `${ type }(${ [ serializedOrientation, ...serializedColorStops ]
.filter( Boolean )
.join( ',' ) })`;
}

View File

@@ -0,0 +1,109 @@
/**
* External dependencies
*/
import gradientParser from './parser';
import { colord, extend } from 'colord';
/**
* Internal dependencies
*/
import {
DEFAULT_GRADIENT,
HORIZONTAL_GRADIENT_ORIENTATION,
DIRECTIONAL_ORIENTATION_ANGLE_MAP,
} from './constants';
import { serializeGradient } from './serializer';
export function getLinearGradientRepresentation( gradientAST ) {
return serializeGradient( {
type: 'linear-gradient',
orientation: HORIZONTAL_GRADIENT_ORIENTATION,
colorStops: gradientAST.colorStops,
} );
}
function hasUnsupportedLength( item ) {
return item.length === undefined || item.length.type !== '%';
}
export function getGradientAstWithDefault( value ) {
// gradientAST will contain the gradient AST as parsed by gradient-parser npm module.
// More information of its structure available at https://www.npmjs.com/package/gradient-parser#ast.
let gradientAST;
try {
gradientAST = gradientParser.parse( value )[ 0 ];
gradientAST.value = value;
} catch ( error ) {
gradientAST = gradientParser.parse( DEFAULT_GRADIENT )[ 0 ];
gradientAST.value = DEFAULT_GRADIENT;
}
if ( gradientAST.orientation?.type === 'directional' ) {
gradientAST.orientation.type = 'angular';
gradientAST.orientation.value =
DIRECTIONAL_ORIENTATION_ANGLE_MAP[
gradientAST.orientation.value
].toString();
}
if ( gradientAST.colorStops.some( hasUnsupportedLength ) ) {
const { colorStops } = gradientAST;
const step = 100 / ( colorStops.length - 1 );
colorStops.forEach( ( stop, index ) => {
stop.length = {
value: step * index,
type: '%',
};
} );
gradientAST.value = serializeGradient( gradientAST );
}
return gradientAST;
}
export function getGradientAstWithControlPoints(
gradientAST,
newControlPoints
) {
return {
...gradientAST,
colorStops: newControlPoints.map( ( { position, color } ) => {
if ( color.startsWith( 'var(' ) ) {
return {
length: {
type: '%',
value: position?.toString(),
},
type: 'literal',
value: color,
};
}
const { r, g, b, a } = colord( color ).toRgb();
return {
length: {
type: '%',
value: position?.toString(),
},
type: a < 1 ? 'rgba' : 'rgb',
value: a < 1 ? [ r, g, b, a ] : [ r, g, b ],
};
} ),
};
}
export function getStopCssColor( colorStop ) {
switch ( colorStop.type ) {
case 'hex':
return `#${ colorStop.value }`;
case 'literal':
return colorStop.value;
case 'rgb':
case 'rgba':
return `${ colorStop.type }(${ colorStop.value.join( ',' ) })`;
default:
// Should be unreachable if passing an AST from gradient-parser.
// See https://github.com/rafaelcaricio/gradient-parser#ast.
return 'transparent';
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,68 @@
/* global wp */
import { Base } from './customizer.js';
import { BaseControl } from './base/control.js';
import { ColorControl } from './color/control.js';
import { PaletteControl } from './palette/control.js';
import { RangeControl } from './range/control.js';
import { SwitchControl } from './switch/control.js';
import { RadioIconControl } from './radio-icon/control.js';
import { MultiRadioIconControl } from './multi-radio-icon/control.js';
import { BuilderControl } from './layout-builder/control.js';
import { AvailableControl } from './available/control.js';
import { BackgroundControl } from './background/control.js';
import { BorderControl } from './border/control.js';
import { BordersControl } from './borders/control.js';
import { TypographyControl } from './typography/control.js';
import { TitleControl } from './title/control.js';
import { FocusButtonControl } from './focus-button/control.js';
import { ColorLinkControl } from './color-link/control.js';
import { TextControl } from './text/control.js';
import { TextareaControl } from './textarea/control.js';
import { MeasureControl } from './measure/control.js';
import { EditorControl } from './editor/control.js';
import { SocialControl } from './social/control.js';
import { ContactControl } from './contact/control.js';
import { CheckIconControl } from './check-icon/control.js';
import { SelectControl } from './select/control.js';
import { SorterControl } from './sorter/control.js';
import { RowControl } from './row-layout/control.js';
import { TabsControl } from './tabs/control.js';
import { BoxShadowControl } from './boxshadow/control.js';
wp.customize.controlConstructor.kadence_shadow_control = BoxShadowControl;
wp.customize.controlConstructor.kadence_tab_control = TabsControl;
wp.customize.controlConstructor.kadence_borders_control = BordersControl;
wp.customize.controlConstructor.kadence_row_control = RowControl;
wp.customize.controlConstructor.kadence_sorter_control = SorterControl;
wp.customize.controlConstructor.kadence_select_control = SelectControl;
wp.customize.controlConstructor.kadence_check_icon_control = CheckIconControl;
wp.customize.controlConstructor.kadence_contact_control = ContactControl;
wp.customize.controlConstructor.kadence_social_control = SocialControl;
wp.customize.controlConstructor.kadence_editor_control = EditorControl;
wp.customize.controlConstructor.kadence_measure_control = MeasureControl;
wp.customize.controlConstructor.kadence_text_control = TextControl;
wp.customize.controlConstructor.kadence_textarea_control = TextareaControl;
wp.customize.controlConstructor.kadence_color_link_control = ColorLinkControl;
wp.customize.controlConstructor.kadence_focus_button_control = FocusButtonControl;
wp.customize.controlConstructor.kadence_title_control = TitleControl;
wp.customize.controlConstructor.kadence_typography_control = TypographyControl;
wp.customize.controlConstructor.kadence_border_control = BorderControl;
wp.customize.controlConstructor.kadence_background_control = BackgroundControl;
wp.customize.controlConstructor.kadence_color_palette_control = PaletteControl;
wp.customize.controlConstructor.kadence_available_control = AvailableControl;
wp.customize.controlConstructor.kadence_builder_control = BuilderControl;
wp.customize.controlConstructor.kadence_color_control = ColorControl;
wp.customize.controlConstructor.kadence_range_control = RangeControl;
wp.customize.controlConstructor.kadence_switch_control = SwitchControl;
wp.customize.controlConstructor.kadence_radio_icon_control = RadioIconControl;
wp.customize.controlConstructor.kadence_multi_radio_icon_control = MultiRadioIconControl;
window.addEventListener( 'load', () => {
let deviceButtons = document.querySelector('#customize-footer-actions .devices' );
deviceButtons.addEventListener( 'click', function(e) {
let event = new CustomEvent( 'kadenceChangedRepsonsivePreview', {
'detail': e.target.dataset.device
} );
document.dispatchEvent( event );
} );
} );

View File

@@ -0,0 +1,101 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import ResponsiveControl from '../common/responsive.js';
import Icons from '../common/icons.js';
import { __ } from '@wordpress/i18n';
const { ButtonGroup, Dashicon, Popover, Tooltip, Button } = wp.components;
const { Component, Fragment } = wp.element;
class AddComponent extends Component {
constructor() {
super( ...arguments );
this.addItem = this.addItem.bind( this );
this.state = {
isVisible: false,
}
}
addItem( item, row, column ) {
this.setState( { isVisible: false } );
let updateItems = this.props.list;
let theitem = [ {
id: item,
} ];
updateItems.push( {
id: item,
});
this.props.setList( updateItems );
}
render() {
const renderItems = ( item, row, column ) => {
let available = true;
this.props.controlParams.rows.map( ( zone ) => {
Object.keys( this.props.settings[zone] ).map( ( area ) => {
if ( this.props.settings[zone][area].includes( item ) ) {
available = false;
}
} );
} );
return (
<Fragment>
{ available && (
<Button
isTertiary
className={ 'builder-add-btn' }
onClick={ () => {
this.addItem( item, row, column );
} }
>
{ ( undefined !== this.props.choices[ item ] && undefined !== this.props.choices[ item ].name ? this.props.choices[ item ].name : '' ) }
</Button>
) }
</Fragment>
);
};
const toggleClose = () => {
if ( this.state.isVisible === true ) {
this.setState( { isVisible: false } );
}
};
let classForAdd = 'kadence-builder-add-item';
if ( 'header_desktop_items' === this.props.controlParams.group && 'right' === this.props.location ) {
classForAdd = classForAdd + ' center-on-left';
}
if ( 'header_desktop_items' === this.props.controlParams.group && 'left' === this.props.location ) {
classForAdd = classForAdd + ' center-on-right';
}
if ( 'header_desktop_items' === this.props.controlParams.group && 'left_center' === this.props.location ) {
classForAdd = classForAdd + ' right-center-on-right';
}
if ( 'header_desktop_items' === this.props.controlParams.group && 'right_center' === this.props.location ) {
classForAdd = classForAdd + ' left-center-on-left';
}
return (
<div className={ classForAdd } key={ this.props.id }>
{ this.state.isVisible && (
<Popover position="top" inline={true} className="kadence-popover-add-builder" onClose={ toggleClose }>
<div className="kadence-popover-builder-list">
<ButtonGroup className="kadence-radio-container-control">
{ Object.keys( this.props.choices ).map( ( item ) => {
return renderItems( item, this.props.row, this.props.column );
} ) }
</ButtonGroup>
</div>
</Popover>
) }
<Button
className="kadence-builder-item-add-icon"
onClick={ () => {
this.setState( { isVisible: true } );
} }
>
<Dashicon icon="plus"/>
</Button>
</div>
);
}
}
export default AddComponent;

View File

@@ -0,0 +1,239 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import ResponsiveControl from '../common/responsive.js';
import Icons from '../common/icons.js';
import RowComponent from './row-component';
import { __ } from '@wordpress/i18n';
const { ButtonGroup, Dashicon, Tooltip, Button } = wp.components;
const { Component, Fragment } = wp.element;
class BuilderComponent extends Component {
constructor() {
super( ...arguments );
this.updateValues = this.updateValues.bind( this );
this.onDragEnd = this.onDragEnd.bind( this );
this.onAddItem = this.onAddItem.bind( this );
this.onDragStart = this.onDragStart.bind( this );
this.onDragStop = this.onDragStop.bind( this );
this.removeItem = this.removeItem.bind( this );
this.focusPanel = this.focusPanel.bind( this );
this.focusItem = this.focusItem.bind( this );
this.onFooterUpdate = this.onFooterUpdate.bind( this );
this.linkColumns();
let value = this.props.control.setting.get();
let baseDefault = {};
this.defaultValue = this.props.control.params.default ? {
...baseDefault,
...this.props.control.params.default
} : baseDefault;
value = value ? {
...this.defaultValue,
...value
} : this.defaultValue;
let defaultParams = {};
this.controlParams = this.props.control.params.input_attrs ? {
...defaultParams,
...this.props.control.params.input_attrs,
} : defaultParams;
this.choices = ( kadenceCustomizerControlsData && kadenceCustomizerControlsData.choices && kadenceCustomizerControlsData.choices[ this.controlParams.group ] ? kadenceCustomizerControlsData.choices[ this.controlParams.group ] : [] );
this.state = {
value: value,
};
}
onDragStart() {
var dropzones = document.querySelectorAll( '.kadence-builder-area' );
var i;
for (i = 0; i < dropzones.length; ++i) {
dropzones[i].classList.add( 'kadence-dragging-dropzones' );
}
}
onDragStop() {
var dropzones = document.querySelectorAll( '.kadence-builder-area' );
var i;
for (i = 0; i < dropzones.length; ++i) {
dropzones[i].classList.remove( 'kadence-dragging-dropzones' );
}
}
removeItem( item, row, zone ) {
let updateState = this.state.value;
let update = updateState[ row ];
let updateItems = [];
{ update[ zone ].length > 0 && (
update[ zone ].map( ( old ) => {
if ( item !== old ) {
updateItems.push( old );
}
} )
) };
if ( 'header_desktop_items' === this.controlParams.group && row + '_center' === zone && updateItems.length === 0 ) {
if ( update[ row + '_left_center' ].length > 0 ) {
update[ row + '_left_center' ].map( ( move ) => {
updateState[ row ][ row + '_left' ].push( move );
} )
updateState[ row ][ row + '_left_center' ] = [];
}
if ( update[ row + '_right_center' ].length > 0 ) {
update[ row + '_right_center' ].map( ( move ) => {
updateState[ row ][ row + '_right' ].push( move );
} )
updateState[ row ][ row + '_right_center' ] = [];
}
}
update[ zone ] = updateItems;
updateState[ row ][ zone ] = updateItems;
this.setState( { value: updateState } );
this.updateValues( updateState );
let event = new CustomEvent(
'kadenceRemovedBuilderItem', {
'detail': this.controlParams.group
} );
document.dispatchEvent( event );
}
onDragEnd( row, zone, items ) {
let updateState = this.state.value;
let update = updateState[ row ];
let updateItems = [];
{ items.length > 0 && (
items.map( ( item ) => {
updateItems.push( item.id );
} )
) };
if ( ! this.arraysEqual( update[ zone ], updateItems ) ) {
if ( 'header_desktop_items' === this.controlParams.group && row + '_center' === zone && updateItems.length === 0 ) {
if ( undefined !== update[ row + '_left_center' ] && update[ row + '_left_center' ].length > 0 ) {
update[ row + '_left_center' ].map( ( move ) => {
updateState[ row ][ row + '_left' ].push( move );
} )
updateState[ row ][ row + '_left_center' ] = [];
}
if ( undefined !== update[ row + '_right_center' ] && update[ row + '_right_center' ].length > 0 ) {
update[ row + '_right_center' ].map( ( move ) => {
updateState[ row ][ row + '_right' ].push( move );
} )
updateState[ row ][ row + '_right_center' ] = [];
}
}
update[ zone ] = updateItems;
updateState[ row ][ zone ] = updateItems;
this.setState( { value: updateState } );
this.updateValues( updateState );
}
}
onAddItem( row, zone, items ) {
this.onDragEnd( row, zone, items );
let event = new CustomEvent(
'kadenceRemovedBuilderItem', {
'detail': this.controlParams.group
} );
document.dispatchEvent( event );
}
onFooterUpdate( row ) {
let updateState = this.state.value;
let update = updateState[ row ];
let removeEvent = false;
const columns = parseInt( this.props.customizer.control( 'footer_' + row + '_columns' ).setting.get(), 10 );
if ( columns < 5 ) {
if ( undefined !== update[ row + '_5' ] && update[ row + '_5' ].length > 0 ) {
updateState[ row ][ row + '_5' ] = [];
removeEvent = true;
}
}
if ( columns < 4 ) {
if ( undefined !== update[ row + '_4' ] && update[ row + '_4' ].length > 0 ) {
updateState[ row ][ row + '_4' ] = [];
removeEvent = true;
}
}
if ( columns < 3 ) {
if ( undefined !== update[ row + '_3' ] && update[ row + '_3' ].length > 0 ) {
updateState[ row ][ row + '_3' ] = [];
removeEvent = true;
}
}
if ( columns < 2 ) {
if ( undefined !== update[ row + '_2' ] && update[ row + '_2' ].length > 0 ) {
updateState[ row ][ row + '_2' ] = [];
removeEvent = true;
}
}
this.setState( { value: updateState } );
this.updateValues( updateState );
if ( removeEvent ) {
let event = new CustomEvent(
'kadenceRemovedBuilderItem', {
'detail': this.controlParams.group
} );
document.dispatchEvent( event );
}
}
arraysEqual( a, b ) {
if (a === b) return true;
if (a == null || b == null) return false;
if (a.length != b.length) return false;
for (var i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) return false;
}
return true;
}
focusPanel( item ) {
if ( undefined !== this.props.customizer.section( 'kadence_customizer_' + item ) ) {
this.props.customizer.section( 'kadence_customizer_' + item ).focus();
}
}
focusItem( item ) {
if ( undefined !== this.props.customizer.section( item ) ) {
this.props.customizer.section( item ).focus();
}
}
render() {
return (
<div className={ `kadence-control-field kadence-builder-items${ ( this.controlParams.rows.includes( 'popup' ) ? ' kadence-builder-items-with-popup' : '' ) }` }>
{ this.controlParams.rows.includes( 'popup' ) && (
<RowComponent showDrop={ () => this.onDragStart() } focusPanel={ ( item ) => this.focusPanel( item ) } focusItem={ ( item ) => this.focusItem( item ) } removeItem={ ( remove, row, zone ) => this.removeItem( remove, row, zone ) } onAddItem={ ( updateRow, updateZone, updateItems ) => this.onAddItem( updateRow, updateZone, updateItems ) } hideDrop={ () => this.onDragStop() } onUpdate={ ( updateRow, updateZone, updateItems ) => this.onDragEnd( updateRow, updateZone, updateItems ) } key={ 'popup' } row={ 'popup' } controlParams={ this.controlParams } choices={ this.choices } items={ this.state.value[ 'popup' ] } settings={ this.state.value } />
) }
<div className="kadence-builder-row-items">
{ this.controlParams.rows.map( ( row ) => {
if ( 'popup' === row ) {
return;
}
return <RowComponent showDrop={ () => this.onDragStart() } focusPanel={ ( item ) => this.focusPanel( item ) } focusItem={ ( item ) => this.focusItem( item ) } removeItem={ ( remove, row, zone ) => this.removeItem( remove, row, zone ) } hideDrop={ () => this.onDragStop() } onUpdate={ ( updateRow, updateZone, updateItems ) => this.onDragEnd( updateRow, updateZone, updateItems ) } onAddItem={ ( updateRow, updateZone, updateItems ) => this.onAddItem( updateRow, updateZone, updateItems ) } key={ row } row={ row } controlParams={ this.controlParams } choices={ this.choices } customizer={ this.props.customizer } items={ this.state.value[ row ] } settings={ this.state.value } />;
} ) }
</div>
</div>
);
}
// linkFocusButtons() {
// this.props.control.container.on( 'click', '.kadence-builder-areas .kadence-builder-item', function( e ) {
// e.preventDefault();
// var targetKey = e.target.getAttribute( 'data-section' );
// var targetControl = wp.customize.section( targetKey );
// if ( targetControl ) targetControl.focus();
// } );
// }
updateValues( value ) {
this.props.control.setting.set( {
...this.props.control.setting.get(),
...value,
flag: !this.props.control.setting.get().flag
} );
}
linkColumns() {
let self = this;
document.addEventListener( 'kadenceUpdateFooterColumns', function( e ) {
if ( 'footer_items' === self.controlParams.group ) {
self.onFooterUpdate( e.detail );
}
} );
}
}
BuilderComponent.propTypes = {
control: PropTypes.object.isRequired,
customizer: PropTypes.object.isRequired
};
export default BuilderComponent;

View File

@@ -0,0 +1,11 @@
import { createRoot } from '@wordpress/element';
import BuilderComponent from './builder-component.js';
export const BuilderControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <BuilderComponent control={ control } customizer={ wp.customize } /> );
// ReactDOM.render( <BuilderComponent control={ control } customizer={ wp.customize } />, control.container[0] );
}
} );

View File

@@ -0,0 +1,79 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import ResponsiveControl from '../common/responsive.js';
import { ReactSortable } from "react-sortablejs";
import Icons from '../common/icons.js';
import ItemComponent from './item-component';
import AddComponent from './add-component';
import { __ } from '@wordpress/i18n';
const { ButtonGroup, Dashicon, Tooltip, Button } = wp.components;
const { Component, Fragment } = wp.element;
class DropComponent extends Component {
render() {
const location = this.props.zone.replace( this.props.row + '_', '');
const currentList = ( typeof this.props.items != "undefined" && this.props.items != null && this.props.items.length != null && this.props.items.length > 0 ? this.props.items : [] );
let theItems = [];
{ currentList.length > 0 && (
currentList.map( ( item ) => {
theItems.push(
{
id: item,
}
)
} )
) };
const currentCenterList = ( typeof this.props.centerItems != "undefined" && this.props.centerItems != null && this.props.centerItems.length != null && this.props.centerItems.length > 0 ? this.props.centerItems : [] );
let theCenterItems = [];
{ currentCenterList.length > 0 && (
currentCenterList.map( ( item ) => {
theCenterItems.push(
{
id: item,
}
)
} )
) };
return (
<div className={ `kadence-builder-area kadence-builder-area-${ location }` } data-location={ this.props.zone }>
<p className="kadence-small-label">{ this.props.controlParams.zones[this.props.row][this.props.zone] }</p>
{ 'header_desktop_items' === this.props.controlParams.group && 'right' === location && (
<Fragment>
<ReactSortable animation={100} onStart={ () => this.props.showDrop() } onEnd={ () => this.props.hideDrop() } group={ this.props.controlParams.group } className={ `kadence-builder-drop kadence-builder-sortable-panel kadence-builder-drop-${ location }_center` } list={ theCenterItems } setList={ newState => this.props.onUpdate( this.props.row, this.props.zone + '_center', newState ) } >
{ currentCenterList.length > 0 && (
currentCenterList.map( ( item, index ) => {
return <ItemComponent removeItem={ ( remove ) => this.props.removeItem( remove, this.props.row, this.props.zone + '_center' ) } focusItem={ ( focus ) => this.props.focusItem( focus ) } key={ item } index={ index } item={ item } controlParams={ this.props.controlParams } />;
} )
) }
</ReactSortable>
<AddComponent row={ this.props.row } list={ theCenterItems } settings={ this.props.settings } column={ this.props.zone + '_center' } setList={ newState => this.props.onAddItem( this.props.row, this.props.zone + '_center', newState ) } key={ location } location={ location + '_center' } id={ 'add-center-' + location } controlParams={ this.props.controlParams } choices={ this.props.choices } />
</Fragment>
) }
<ReactSortable animation={100} onStart={ () => this.props.showDrop() } onEnd={ () => this.props.hideDrop() } group={ this.props.controlParams.group } className={ `kadence-builder-drop kadence-builder-sortable-panel kadence-builder-drop-${ location }` } list={ theItems } setList={ newState => this.props.onUpdate( this.props.row, this.props.zone, newState ) } >
{ currentList.length > 0 && (
currentList.map( ( item, index ) => {
return <ItemComponent removeItem={ ( remove ) => this.props.removeItem( remove, this.props.row, this.props.zone ) } focusItem={ ( focus ) => this.props.focusItem( focus ) } key={ item } index={ index } item={ item } controlParams={ this.props.controlParams } />;
} )
) }
</ReactSortable>
<AddComponent row={ this.props.row } list={ theItems } settings={ this.props.settings } column={ this.props.zone } setList={ newState => this.props.onAddItem( this.props.row, this.props.zone, newState ) } key={ location } location={ location } id={ 'add-' + location } controlParams={ this.props.controlParams } choices={ this.props.choices } />
{ 'header_desktop_items' === this.props.controlParams.group && 'left' === location && (
<Fragment>
<ReactSortable animation={100} onStart={ () => this.props.showDrop() } onEnd={ () => this.props.hideDrop() } group={ this.props.controlParams.group } className={ `kadence-builder-drop kadence-builder-sortable-panel kadence-builder-drop-${ location }_center` } list={ theCenterItems } setList={ newState => this.props.onUpdate( this.props.row, this.props.zone + '_center', newState ) } >
{ currentCenterList.length > 0 && (
currentCenterList.map( ( item, index ) => {
return <ItemComponent removeItem={ ( remove ) => this.props.removeItem( remove, this.props.row, this.props.zone + '_center' ) } focusItem={ ( focus ) => this.props.focusItem( focus ) } key={ item } index={ index } item={ item } controlParams={ this.props.controlParams } />;
} )
) }
</ReactSortable>
<AddComponent row={ this.props.row } list={ theCenterItems } settings={ this.props.settings } column={ this.props.zone + '_center' } setList={ newState => this.props.onAddItem( this.props.row, this.props.zone + '_center', newState ) } key={ location } location={ location + '_center' } id={ 'add-center-' + location } controlParams={ this.props.controlParams } choices={ this.props.choices } />
</Fragment>
) }
</div>
);
}
}
export default DropComponent;

View File

@@ -0,0 +1,74 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import ResponsiveControl from '../common/responsive.js';
import Icons from '../common/icons.js';
import { __ } from '@wordpress/i18n';
const { ButtonGroup, Dashicon, Tooltip, Button } = wp.components;
const { Component, Fragment } = wp.element;
class ItemComponent extends Component {
constructor() {
super( ...arguments );
this.choices = ( kadenceCustomizerControlsData && kadenceCustomizerControlsData.choices && kadenceCustomizerControlsData.choices[ this.props.controlParams.group ] ? kadenceCustomizerControlsData.choices[ this.props.controlParams.group ] : [] );
}
render() {
return (
<div className="kadence-builder-item" data-id={ this.props.item } data-section={ undefined !== this.choices[ this.props.item ] && undefined !== this.choices[ this.props.item ].section ? this.choices[ this.props.item ].section : '' } key={ this.props.item }>
<span
className="kadence-builder-item-icon kadence-move-icon"
>
{ Icons['drag'] }
</span>
<span
className="kadence-builder-item-text"
>
{ ( undefined !== this.choices[ this.props.item ] && undefined !== this.choices[ this.props.item ].name ? this.choices[ this.props.item ].name : '' ) }
</span>
<Button
className="kadence-builder-item-focus-icon kadence-builder-item-icon"
aria-label={ __( 'Setting settings for', 'kadence' ) + ' ' + ( undefined !== this.choices[ this.props.item ] && undefined !== this.choices[ this.props.item ].name ? this.choices[ this.props.item ].name : '' ) }
onClick={ () => {
this.props.focusItem( undefined !== this.choices[ this.props.item ] && undefined !== this.choices[ this.props.item ].section ? this.choices[ this.props.item ].section : '' );
} }
>
<Dashicon icon="admin-generic"/>
</Button>
{ kadenceCustomizerControlsData.blockWidgets && this.props.item.includes('widget') && 'toggle-widget' !== this.props.item && (
<Button
className="kadence-builder-item-focus-icon kadence-builder-item-icon"
aria-label={ __( 'Setting settings for', 'kadence' ) + ' ' + ( undefined !== this.choices[ this.props.item ] && undefined !== this.choices[ this.props.item ].name ? this.choices[ this.props.item ].name : '' ) }
onClick={ () => {
this.props.focusItem( undefined !== this.choices[ this.props.item ] && undefined !== this.choices[ this.props.item ].section ? 'kadence_customizer_' + this.choices[ this.props.item ].section : '' );
} }
>
<Dashicon icon="admin-settings"/>
</Button>
) }
{ kadenceCustomizerControlsData.blockWidgets && 'toggle-widget' === this.props.item && (
<Button
className="kadence-builder-item-focus-icon kadence-builder-item-icon"
aria-label={ __( 'Setting settings for', 'kadence' ) + ' ' + ( undefined !== this.choices[ this.props.item ] && undefined !== this.choices[ this.props.item ].name ? this.choices[ this.props.item ].name : '' ) }
onClick={ () => {
this.props.focusItem( 'kadence_customizer_sidebar-widgets-header2' );
} }
>
<Dashicon icon="admin-settings"/>
</Button>
) }
<Button
className="kadence-builder-item-icon"
aria-label={ __( 'Remove', 'kadence' ) + ' ' + ( undefined !== this.choices[ this.props.item ] && undefined !== this.choices[ this.props.item ].name ? this.choices[ this.props.item ].name : '' ) }
onClick={ () => {
this.props.removeItem( this.props.item );
} }
>
<Dashicon icon="no-alt"/>
</Button>
</div>
);
}
}
export default ItemComponent;

View File

@@ -0,0 +1,70 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import ResponsiveControl from '../common/responsive.js';
import Icons from '../common/icons.js';
import DropComponent from './drop-component';
import { __ } from '@wordpress/i18n';
const { ButtonGroup, Dashicon, Tooltip, Button } = wp.components;
const { Component, Fragment } = wp.element;
class RowComponent extends Component {
render() {
let centerClass = 'no-center-items';
if ( 'header_desktop_items' === this.props.controlParams.group && typeof this.props.items[this.props.row + '_center'] != "undefined" && this.props.items[this.props.row + '_center'] != null && this.props.items[this.props.row + '_center'].length != null && this.props.items[this.props.row + '_center'].length > 0 ){
centerClass = 'has-center-items';
}
if ( 'popup' === this.props.row ) {
centerClass = 'popup-vertical-group';
}
if ( 'footer_items' === this.props.controlParams.group ) {
var columns = this.props.customizer.control( 'footer_' + this.props.row + '_columns' ).setting.get();
var layout = this.props.customizer.control( 'footer_' + this.props.row + '_layout' ).setting.get();
var direction = this.props.customizer.control( 'footer_' + this.props.row + '_direction' ).setting.get();
centerClass = 'footer-column-row footer-row-columns-' + columns + ' footer-row-layout-' + layout.desktop + ' footer-row-direction-' + direction.desktop;
}
const mode = ( this.props.controlParams.group.indexOf( 'header' ) !== -1 ? 'header' : 'footer' );
let besideItems = [];
return (
<div className={ `kadence-builder-areas ${ centerClass }` }>
<Button
className="kadence-row-left-actions"
aria-label={ __( 'Edit Settings for', 'kadence' ) + ' ' + ( this.props.row === 'popup' ? __( 'Off Canvas', 'kadence' ) : this.props.row + ' ' + __( 'Row', 'kadence' ) ) }
onClick={ () => this.props.focusPanel( mode + '_' + this.props.row ) }
icon="admin-generic"
>
</Button>
<Button
className="kadence-row-actions"
aria-label={ __( 'Edit Settings for', 'kadence' ) + ' ' + ( this.props.row === 'popup' ? __( 'Off Canvas', 'kadence' ) : this.props.row + ' ' + __( 'Row', 'kadence' ) ) }
onClick={ () => this.props.focusPanel( mode + '_' + this.props.row ) }
>
{ ( this.props.row === 'popup' ? __( 'Off Canvas', 'kadence' ) : this.props.row + ' ' + __( 'Row', 'kadence' ) ) }
<Dashicon icon="admin-generic" />
</Button>
<div className="kadence-builder-group kadence-builder-group-horizontal" data-setting={ this.props.row }>
{ Object.keys( this.props.controlParams.zones[ this.props.row ] ).map( ( zone, index ) => {
if ( this.props.row + '_left_center' === zone || this.props.row + '_right_center' === zone ) {
return;
}
if ( 'footer_items' === this.props.controlParams.group ) {
if ( columns < ( index + 1 ) ) {
return;
}
}
if ( 'header_desktop_items' === this.props.controlParams.group && this.props.row + '_left' === zone ) {
besideItems = this.props.items[ this.props.row + '_left_center' ];
}
if ( 'header_desktop_items' === this.props.controlParams.group && this.props.row + '_right' === zone ) {
besideItems = this.props.items[ this.props.row + '_right_center' ];
}
return <DropComponent removeItem={ ( remove, removeRow, removeZone ) => this.props.removeItem( remove, removeRow, removeZone ) } focusItem={ ( focus ) => this.props.focusItem( focus ) } hideDrop={ () => this.props.hideDrop() } showDrop={ () => this.props.showDrop() } onUpdate={ ( updateRow, updateZone, updateItems ) => this.props.onUpdate( updateRow, updateZone, updateItems ) } zone={ zone } row={ this.props.row } choices={ this.props.choices } key={ zone } items={ this.props.items[zone] } centerItems={ besideItems } controlParams={ this.props.controlParams } onAddItem={ ( updateRow, updateZone, updateItems ) => this.props.onAddItem( updateRow, updateZone, updateItems ) } settings={ this.props.settings } />;
} ) }
</div>
</div>
);
}
}
export default RowComponent;

View File

@@ -0,0 +1,14 @@
import { createRoot } from '@wordpress/element';
import MeasureComponent from './measure-component';
export const MeasureControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <MeasureComponent control={control}/> );
// ReactDOM.render(
// <MeasureComponent control={control}/>,
// control.container[0]
// );
}
} );

View File

@@ -0,0 +1,516 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import ResponsiveControl from '../common/responsive.js';
import Icons from '../common/icons.js';
import { __ } from '@wordpress/i18n';
const { RangeControl, Dashicon, Tooltip, Button, Toolbar, TextControl, ToolbarGroup } = wp.components;
const { Component, Fragment } = wp.element;
class MeasureComponent extends Component {
constructor() {
super( ...arguments );
this.updateValues = this.updateValues.bind( this );
this.getUnitButtons = this.getUnitButtons.bind( this );
this.createLevelControlToolbar = this.createLevelControlToolbar.bind( this );
this.createResponsiveLevelControlToolbar = this.createResponsiveLevelControlToolbar.bind( this );
this.getResponsiveUnitButtons = this.getResponsiveUnitButtons.bind( this );
let value = this.props.control.setting.get();
let baseDefault = {
'unit': {
'desktop': 'px'
},
'size': {
'desktop': [ 0, 0, 0, 0 ]
},
'locked': {
'desktop': true
}
};
this.defaultValue = this.props.control.params.default ? {
...baseDefault,
...this.props.control.params.default
} : baseDefault;
value = value ? {
...this.defaultValue,
...value
} : this.defaultValue;
let defaultParams = {
min: {
px: '0',
em: '0',
rem: '0',
},
max: {
px: '120',
em: '12',
rem: '12',
},
step: {
px: '1',
em: '0.01',
rem: '0.01',
},
units: ['px', 'em', 'rem' ],
responsive: true,
};
this.controlParams = this.props.control.params.input_attrs ? {
...defaultParams,
...this.props.control.params.input_attrs,
} : defaultParams;
this.state = {
currentDevice: 'desktop',
size: value.size,
unit: value.unit,
locked: value.locked
};
}
render() {
const responsiveControlLabel = (
<Fragment>
{ this.controlParams.responsive && (
<Fragment>
<Tooltip text={ __( 'Reset Device Values', 'kadence' ) }>
<Button
className="reset kadence-reset"
disabled={ ( this.state.size[this.state.currentDevice] === this.defaultValue.size[this.state.currentDevice] ) && ( this.state.unit[this.state.currentDevice] === this.defaultValue.unit[this.state.currentDevice] ) }
onClick={ () => {
let value = this.state.size;
value[this.state.currentDevice] = this.defaultValue.size[this.state.currentDevice];
let svalue = this.state.unit;
svalue[this.state.currentDevice] = this.defaultValue.unit[this.state.currentDevice];
let lvalue = this.state.unit;
lvalue[this.state.currentDevice] = this.defaultValue.locked[this.state.currentDevice];
this.setState( { size: value, unit: svalue, locked: lvalue } );
this.updateValues( { size: value, unit: svalue, locked: lvalue } );
} }
>
<Dashicon icon='image-rotate' />
</Button>
</Tooltip>
{ this.props.control.params.label &&
this.props.control.params.label
}
</Fragment>
) }
</Fragment>
);
const controlLabel = (
<Fragment>
<Tooltip text={ __( 'Reset Values', 'kadence' ) }>
<Button
className="reset kadence-reset"
disabled={ ( this.state.size === this.defaultValue.size ) && ( this.state.unit === this.defaultValue.unit ) }
onClick={ () => {
let value = this.state.size;
value = this.defaultValue.size;
let svalue = this.state.unit;
svalue = this.defaultValue.unit;
let lvalue = this.state.locked;
lvalue = this.defaultValue.locked;
this.setState( { size: value, unit: svalue, locked: lvalue } );
this.updateValues( { size: value, unit: svalue, locked: lvalue } );
} }
>
<Dashicon icon='image-rotate' />
</Button>
</Tooltip>
{ this.props.control.params.label &&
this.props.control.params.label
}
</Fragment>
);
return (
<div className="kadence-control-field kadence-range-control">
{ this.controlParams.responsive && (
<ResponsiveControl
onChange={ ( currentDevice) => this.setState( { currentDevice } ) }
controlLabel={ responsiveControlLabel }
>
{ this.state.locked[this.state.currentDevice] && (
<RangeControl
initialPosition={ ( this.state.size[this.state.currentDevice] && this.state.size[this.state.currentDevice][0] ? this.state.size[this.state.currentDevice][0] : '' ) }
value={ ( this.state.size[this.state.currentDevice] && this.state.size[this.state.currentDevice][0] ? this.state.size[this.state.currentDevice][0] : '' ) }
onChange={ (val) => {
let value = this.state.size;
value[ this.state.currentDevice ] = [ val, val, val, val ];
this.setState( { size: value } );
this.updateValues( { size: value } );
} }
min={this.controlParams.min[this.state.unit[this.state.currentDevice]]}
max={this.controlParams.max[this.state.unit[this.state.currentDevice]]}
step={this.controlParams.step[this.state.unit[this.state.currentDevice]]}
/>
) }
{ ! this.state.locked[this.state.currentDevice] && (
<Fragment>
<TextControl
label={ __( 'Top', 'kadence' ) }
hideLabelFromVision={ true }
type="number"
className="measure-inputs"
value={( this.state.size[this.state.currentDevice] && this.state.size[this.state.currentDevice][0] ? this.state.size[this.state.currentDevice][0] : '' )}
onChange={ (val) => {
let value = this.state.size;
if ( undefined === value[ this.state.currentDevice ] ) {
value[ this.state.currentDevice ] = [ 0, 0, 0, 0 ];
}
value[ this.state.currentDevice ][0] = val;
this.setState( { size: value } );
this.updateValues( { size: value } );
} }
min={this.controlParams.min[this.state.unit[this.state.currentDevice]]}
max={this.controlParams.max[this.state.unit[this.state.currentDevice]]}
step={this.controlParams.step[this.state.unit[this.state.currentDevice]]}
/>
<TextControl
label={ __( 'Right', 'kadence' ) }
hideLabelFromVision={ true }
type="number"
className="measure-inputs"
value={( this.state.size[this.state.currentDevice] && this.state.size[this.state.currentDevice][1] ? this.state.size[this.state.currentDevice][1] : '' )}
onChange={ (val) => {
let value = this.state.size;
if ( undefined === value[ this.state.currentDevice ] ) {
value[ this.state.currentDevice ] = [ 0, 0, 0, 0 ];
}
value[ this.state.currentDevice ][1] = val;
this.setState( { size: value } );
this.updateValues( { size: value } );
} }
min={this.controlParams.min[this.state.unit[this.state.currentDevice]]}
max={this.controlParams.max[this.state.unit[this.state.currentDevice]]}
step={this.controlParams.step[this.state.unit[this.state.currentDevice]]}
/>
<TextControl
label={ __( 'Bottom', 'kadence' ) }
hideLabelFromVision={ true }
type="number"
className="measure-inputs"
value={( this.state.size[this.state.currentDevice] && this.state.size[this.state.currentDevice][2] ? this.state.size[this.state.currentDevice][2] : '' )}
onChange={ (val) => {
let value = this.state.size;
if ( undefined === value[ this.state.currentDevice ] ) {
value[ this.state.currentDevice ] = [ 0, 0, 0, 0 ];
}
value[ this.state.currentDevice ][2] = val;
this.setState( { size: value } );
this.updateValues( { size: value } );
} }
min={this.controlParams.min[this.state.unit[this.state.currentDevice]]}
max={this.controlParams.max[this.state.unit[this.state.currentDevice]]}
step={this.controlParams.step[this.state.unit[this.state.currentDevice]]}
/>
<TextControl
label={ __( 'Left', 'kadence' ) }
hideLabelFromVision={ true }
type="number"
className="measure-inputs"
value={( this.state.size[this.state.currentDevice] && this.state.size[this.state.currentDevice][3] ? this.state.size[this.state.currentDevice][3] : '' )}
onChange={ (val) => {
let value = this.state.size;
if ( undefined === value[ this.state.currentDevice ] ) {
value[ this.state.currentDevice ] = [ 0, 0, 0, 0 ];
}
value[ this.state.currentDevice ][3] = val;
this.setState( { size: value } );
this.updateValues( { size: value } );
} }
min={this.controlParams.min[this.state.unit[this.state.currentDevice]]}
max={this.controlParams.max[this.state.unit[this.state.currentDevice]]}
step={this.controlParams.step[this.state.unit[this.state.currentDevice]]}
/>
</Fragment>
) }
<div className="kadence-units kadence-locked">
{ this.getResponsiveLockedButtons() }
</div>
{ this.controlParams.units && (
<div className="kadence-units">
{ this.getResponsiveUnitButtons() }
</div>
) }
</ResponsiveControl>
) }
{ ! this.controlParams.responsive && (
<Fragment>
<div className="kadence-responsive-control-bar">
<span className="customize-control-title">{ controlLabel }</span>
</div>
<div className="kadence-responsive-controls-content">
{ this.state.locked && (
<RangeControl
initialPosition={ this.state.size[0] }
value={this.state.size[0]}
onChange={ (val) => {
let value = this.state.size;
value = [ val, val, val, val ];
this.setState( { size: value } );
this.updateValues( { size: value } );
} }
min={this.controlParams.min[this.state.unit]}
max={this.controlParams.max[this.state.unit]}
step={this.controlParams.step[this.state.unit]}
/>
) }
{ ! this.state.locked && (
<Fragment>
<div className="measure-input-wrap">
<input
value={this.state.size[0]}
onChange={ ( event ) => {
const val = ( '' !== event.target.value ? Number( event.target.value ) : '' );
let value = this.state.size;
value[0] = val;
if ( val !== '' ) {
if ( '' === value[1] ) {
value[1] = 0;
}
if ( '' === value[2] ) {
value[2] = 0;
}
if ( '' === value[3] ) {
value[3] = 0;
}
}
this.setState( { size: value } );
this.updateValues( { size: value } );
} }
min={this.controlParams.min[this.state.unit]}
max={this.controlParams.max[this.state.unit]}
step={this.controlParams.step[this.state.unit]}
type="number"
className="measure-inputs"
/>
<small>{ __( 'Top', 'kadence' ) }</small>
</div>
<div className="measure-input-wrap">
<input
value={this.state.size[1]}
onChange={ ( event ) => {
const val = ( '' !== event.target.value ? Number( event.target.value ) : '' );
let value = this.state.size;
value[1] = val;
if ( val !== '' ) {
if ( '' === value[0] ) {
value[0] = 0;
}
if ( '' === value[2] ) {
value[2] = 0;
}
if ( '' === value[3] ) {
value[3] = 0;
}
}
this.setState( { size: value } );
this.updateValues( { size: value } );
} }
min={this.controlParams.min[this.state.unit]}
max={this.controlParams.max[this.state.unit]}
step={this.controlParams.step[this.state.unit]}
type="number"
className="measure-inputs"
/>
<small>{ __( 'Right', 'kadence' ) }</small>
</div>
<div className="measure-input-wrap">
<input
value={this.state.size[2]}
onChange={ ( event ) => {
const val = ( '' !== event.target.value ? Number( event.target.value ) : '' );
let value = this.state.size;
value[2] = val;
if ( val !== '' ) {
if ( '' === value[0] ) {
value[0] = 0;
}
if ( '' === value[1] ) {
value[1] = 0;
}
if ( '' === value[3] ) {
value[3] = 0;
}
}
this.setState( { size: value } );
this.updateValues( { size: value } );
} }
min={this.controlParams.min[this.state.unit]}
max={this.controlParams.max[this.state.unit]}
step={this.controlParams.step[this.state.unit]}
type="number"
className="measure-inputs"
/>
<small>{ __( 'Bottom', 'kadence' ) }</small>
</div>
<div className="measure-input-wrap">
<input
value={this.state.size[3]}
onChange={ ( event ) => {
const val = ( '' !== event.target.value ? Number( event.target.value ) : '' );
let value = this.state.size;
value[3] = val;
if ( val !== '' ) {
if ( '' === value[0] ) {
value[0] = 0;
}
if ( '' === value[1] ) {
value[1] = 0;
}
if ( '' === value[2] ) {
value[2] = 0;
}
}
this.setState( { size: value } );
this.updateValues( { size: value } );
} }
min={this.controlParams.min[this.state.unit]}
max={this.controlParams.max[this.state.unit]}
step={this.controlParams.step[this.state.unit]}
type="number"
className="measure-inputs"
/>
<small>{ __( 'Left', 'kadence' ) }</small>
</div>
</Fragment>
) }
<div className="kadence-units kadence-locked">
{ this.getLockedButtons() }
</div>
{ this.controlParams.units && (
<div className="kadence-units">
{ this.getUnitButtons() }
</div>
) }
</div>
</Fragment>
) }
{ this.props.control.renderNotice() }
</div>
);
}
getLockedButtons() {
const { locked } = this.state;
if ( locked ) {
return ( <Button
className="is-single"
onClick={ () => {
let value = this.state.locked;
value = false;
this.setState( { locked: value } );
this.updateValues( { locked: value } );
} }
isSmall
>{ Icons['locked'] }</Button> );
}
return ( <Button
className="is-single"
isSmall
onClick={ () => {
let value = this.state.locked;
value = true;
this.setState( { locked: value } );
this.updateValues( { locked: value } );
} }
>{ Icons['unlocked'] }</Button> );
}
getUnitButtons() {
let self = this;
const { units } = this.controlParams;
if ( units.length === 1 ) {
return ( <Button
className="is-active is-single"
isSmall
disabled
>{ ( '%' === self.state.unit ? Icons.percent : Icons[ self.state.unit ] ) }</Button> );
}
return <ToolbarGroup
isCollapsed={ true }
icon={ ( '%' === self.state.unit ? Icons.percent : Icons[ self.state.unit ] ) }
label={ __( 'Unit', 'kadence' ) }
controls={ units.map( (unit) => this.createLevelControlToolbar( unit ) ) }
/>
}
createLevelControlToolbar( unit ) {
return [ {
icon: ( unit === '%' ? Icons.percent : Icons[ unit ] ),
isActive: this.state.unit === unit,
onClick: () => {
let value = this.state.unit;
value = unit;
this.setState( { unit: value } );
this.updateValues( { unit: value } );
},
} ];
};
createResponsiveLevelControlToolbar( unit ) {
return [ {
icon: ( unit === '%' ? Icons.percent : Icons[ unit ] ),
isActive: this.state.unit[this.state.currentDevice] === unit,
onClick: () => {
let value = this.state.unit;
value[ this.state.currentDevice ] = unit;
this.setState( { unit: value } );
this.updateValues( { unit: value } );
},
} ];
};
getResponsiveLockedButtons() {
let self = this;
const { locked } = this.state;
if ( locked[ self.state.currentDevice ] ) {
return ( <Button
className="is-single"
isSmall
onClick={ () => {
let value = this.state.locked;
value[ this.state.currentDevice ] = false;
this.setState( { locked: value } );
this.updateValues( { locked: value } );
} }
>{ Icons['locked'] }</Button> );
}
return ( <Button
className="is-single"
isSmall
onClick={ () => {
let value = this.state.locked;
value[ this.state.currentDevice ] = true;
this.setState( { locked: value } );
this.updateValues( { locked: value } );
} }
>{ Icons['unlocked'] }</Button> );
}
getResponsiveUnitButtons() {
let self = this;
const { units } = this.controlParams;
if ( units.length === 1 ) {
return ( <Button
className="is-active is-single"
isSmall
disabled
>{ ( '%' === self.state.unit[ self.state.currentDevice ] ? Icons.percent : Icons[ self.state.unit[ self.state.currentDevice ] ] ) }</Button> );
}
return <ToolbarGroup
isCollapsed={ true }
icon={ ( '%' === self.state.unit[ self.state.currentDevice ] ? Icons.percent : Icons[ self.state.unit[ self.state.currentDevice ] ] ) }
label={ __( 'Unit', 'kadence' ) }
controls={ units.map( (unit) => this.createResponsiveLevelControlToolbar( unit ) ) }
/>
}
updateValues( value ) {
this.props.control.setting.set( {
...this.props.control.setting.get(),
...value,
flag: !this.props.control.setting.get().flag
} );
}
}
MeasureComponent.propTypes = {
control: PropTypes.object.isRequired
};
export default MeasureComponent;

View File

@@ -0,0 +1,15 @@
import { createRoot } from '@wordpress/element';
import MultiRadioIconComponent from './multi-radio-icon-component.js';
export const MultiRadioIconControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <MultiRadioIconComponent control={control}/> );
// ReactDOM.render(
// <MultiRadioIconComponent control={control}/>,
// control.container[0]
// );
}
} );

View File

@@ -0,0 +1,211 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import ResponsiveControl from '../common/responsive.js';
import Icons from '../common/icons.js';
import { __ } from '@wordpress/i18n';
const { ButtonGroup, Dashicon, Tooltip, Button } = wp.components;
const { Component, Fragment } = wp.element;
class RadioIconComponent extends Component {
constructor() {
super( ...arguments );
this.updateValues = this.updateValues.bind( this );
let value = this.props.control.setting.get();
let baseDefault = {
'include': {
'mobile': '',
'tablet': '',
'desktop': 'logo_title_tagline'
},
'layout': {
'mobile': '',
'tablet': '',
'desktop': 'standard'
}
};
this.defaultValue = this.props.control.params.default ? {
...baseDefault,
...this.props.control.params.default
} : baseDefault;
value = value ? {
...this.defaultValue,
...value
} : this.defaultValue;
let defaultParams = {
include: {
logo_only: {
tooltip: __( 'Logo Only', 'kadence' ),
name: __( 'Logo', 'kadence' ),
},
logo_title: {
tooltip: __( 'Logo & Title', 'kadence' ),
name: __( 'Logo & Title', 'kadence' ),
},
logo_title_tagline: {
tooltip: __( 'Logo, Title & Tagline', 'kadence' ),
name: __( 'Logo, Title & Tagline', 'kadence' ),
},
},
layout: {
logo_only: {
standard: {
tooltip: __( 'Logo Only', 'kadence' ),
icon: Icons.logo
},
},
logo_title: {
standard: {
tooltip: __( 'Logo - Title', 'kadence' ),
icon: Icons.logoTitle
},
title_logo: {
tooltip: __( 'Title - Logo', 'kadence' ),
icon: Icons.titleLogo
},
top_logo_title: {
tooltip: __( 'Top Logo - Title', 'kadence' ),
icon: Icons.topLogoTitle
},
top_title_logo: {
tooltip: __( 'Top Title - Logo', 'kadence' ),
icon: Icons.topTitleLogo
},
},
logo_title_tagline: {
standard: {
tooltip: __( 'Logo - Title - Tagline', 'kadence' ),
icon: Icons.logoTitleTag
},
title_tag_logo: {
tooltip: __( 'Title - Tagline - Logo', 'kadence' ),
icon: Icons.titleTagLogo
},
top_logo_title_tag: {
tooltip: __( 'Top Logo - Title - Tagline', 'kadence' ),
icon: Icons.topLogoTitleTag
},
top_title_tag_logo: {
tooltip: __( 'Top Title - Tagline - Logo', 'kadence' ),
icon: Icons.topTitleTagLogo
},
top_title_logo_tag: {
tooltip: __( 'Top Title - Logo - Tagline', 'kadence' ),
icon: Icons.topTitleLogoTag
}
},
}
};
this.controlParams = this.props.control.params.input_attrs ? {
...defaultParams,
...this.props.control.params.input_attrs,
} : defaultParams;
this.state = {
currentDevice: 'desktop',
include: value.include,
layout: value.layout,
};
}
render() {
const controlLabel = (
<Fragment>
{ this.state.currentDevice !== 'desktop' && (
<Tooltip text={ __( 'Reset Device Values', 'kadence' ) }>
<Button
className="reset kadence-reset"
disabled={ ( this.state.include[this.state.currentDevice] === this.defaultValue.include[this.state.currentDevice] ) && ( this.state.layout[this.state.currentDevice] === this.defaultValue.layout[this.state.currentDevice] ) }
onClick={ () => {
let value = this.state.include;
value[this.state.currentDevice] = this.defaultValue.include[this.state.currentDevice];
let svalue = this.state.layout;
svalue[this.state.currentDevice] = this.defaultValue.layout[this.state.currentDevice];
this.setState( { include: value, layout: svalue } );
this.updateValues( { include: value, layout: svalue } );
} }
>
<Dashicon icon='image-rotate' />
</Button>
</Tooltip>
) }
{ this.props.control.params.label &&
this.props.control.params.label
}
</Fragment>
);
return (
<div className="kadence-control-field kadence-radio-icon-control">
<ResponsiveControl
onChange={ ( currentDevice) => this.setState( { currentDevice } ) }
controlLabel={ controlLabel }
>
<ButtonGroup className="kadence-radio-container-control">
{ Object.keys( this.controlParams.include ).map( ( item ) => {
return (
<Tooltip text={ this.controlParams.include[ item ].tooltip }>
<Button
isTertiary
className={ ( item === this.state.include[this.state.currentDevice] ?
'active-radio ' :
'' ) + item }
onClick={ () => {
let value = this.state.include;
value[ this.state.currentDevice ] = item;
let svalue = this.state.layout;
svalue[ this.state.currentDevice ] = 'standard';
this.setState( { include: value, layout: svalue } );
this.updateValues( { include: value, layout: svalue } );
} }
>
{ this.controlParams.include[ item ].name }
</Button>
</Tooltip>
);
} )}
</ButtonGroup>
{ undefined !== this.state.include[this.state.currentDevice] && '' !== this.state.include[this.state.currentDevice] && 'logo_only' !== this.state.include[this.state.currentDevice] && (
<ButtonGroup className="kadence-radio-container-control kadence-radio-icon-container-control">
{ Object.keys( this.controlParams.layout[this.state.include[this.state.currentDevice] ] ).map( ( item ) => {
return (
<Tooltip text={ this.controlParams.layout[this.state.include[this.state.currentDevice] ][ item ].tooltip }>
<Button
isTertiary
className={ ( item === this.state.layout[this.state.currentDevice] ?
'active-radio ' :
'' ) + item }
onClick={ () => {
let value = this.state.layout;
value[ this.state.currentDevice ] = item;
this.setState( { layout: value } );
this.updateValues( { layout: value } );
} }
>
{ this.controlParams.layout[this.state.include[this.state.currentDevice] ][ item ].icon }
</Button>
</Tooltip>
);
} )}
</ButtonGroup>
) }
</ResponsiveControl>
{ this.props.control.renderNotice() }
</div>
);
}
updateValues( value ) {
this.props.control.setting.set( {
...this.props.control.setting.get(),
...value,
flag: !this.props.control.setting.get().flag
} );
}
}
RadioIconComponent.propTypes = {
control: PropTypes.object.isRequired
};
export default RadioIconComponent;

View File

@@ -0,0 +1,14 @@
import { createRoot } from '@wordpress/element';
import PaletteComponent from './palette-component.js';
export const PaletteControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <PaletteComponent control={control}/> );
// ReactDOM.render(
// <PaletteComponent control={control}/>,
// control.container[0]
// );
}
} );

View File

@@ -0,0 +1,748 @@
import PropTypes from "prop-types";
import { __ } from "@wordpress/i18n";
/**
* WordPress dependencies
*/
import { createRef, Component, Fragment } from "@wordpress/element";
import map from "lodash/map";
import ColorControl from "../common/color.js";
const {
ButtonGroup,
Dashicon,
Tooltip,
Button,
Popover,
TabPanel,
TextareaControl,
} = wp.components;
class ColorComponent extends Component {
constructor(props) {
super(props);
this.handleChangeComplete = this.handleChangeComplete.bind(this);
this.handleChangePalette = this.handleChangePalette.bind(this);
this.handleTextImport = this.handleTextImport.bind(this);
this.handlePresetImport = this.handlePresetImport.bind(this);
this.updateValues = this.updateValues.bind(this);
let value = JSON.parse(this.props.control.setting.get());
let baseDefault = kadenceCustomizerControlsData.palette
? JSON.parse(kadenceCustomizerControlsData.palette)
: { palette: [] };
this.defaultValue = this.props.control.params.default
? {
...baseDefault,
...this.props.control.params.default,
}
: baseDefault;
value = value
? {
...this.defaultValue,
...value,
}
: this.defaultValue;
let defaultParams = {
reset: '{"palette":[{"color":"#3182CE","slug":"palette1","name":"Palette Color 1"},{"color":"#2B6CB0","slug":"palette2","name":"Palette Color 2"},{"color":"#1A202C","slug":"palette3","name":"Palette Color 3"},{"color":"#2D3748","slug":"palette4","name":"Palette Color 4"},{"color":"#4A5568","slug":"palette5","name":"Palette Color 5"},{"color":"#718096","slug":"palette6","name":"Palette Color 6"},{"color":"#EDF2F7","slug":"palette7","name":"Palette Color 7"},{"color":"#F7FAFC","slug":"palette8","name":"Palette Color 8"},{"color":"#FFFFFF","slug":"palette9","name":"Palette Color 9"},{"color":"#FfFfFf","slug":"palette10","name":"Palette Color Complement"},{"color":"#13612e","slug":"palette11","name":"Palette Color Success"},{"color":"#1159af","slug":"palette12","name":"Palette Color Info"},{"color":"#b82105","slug":"palette13","name":"Palette Color Alert"},{"color":"#f7630c","slug":"palette14","name":"Palette Color Warning"},{"color":"#f5a524","slug":"palette15","name":"Palette Color Rating"}],"second-palette":[{"color":"#3182CE","slug":"palette1","name":"Palette Color 1"},{"color":"#2B6CB0","slug":"palette2","name":"Palette Color 2"},{"color":"#1A202C","slug":"palette3","name":"Palette Color 3"},{"color":"#2D3748","slug":"palette4","name":"Palette Color 4"},{"color":"#4A5568","slug":"palette5","name":"Palette Color 5"},{"color":"#718096","slug":"palette6","name":"Palette Color 6"},{"color":"#EDF2F7","slug":"palette7","name":"Palette Color 7"},{"color":"#F7FAFC","slug":"palette8","name":"Palette Color 8"},{"color":"#FFFFFF","slug":"palette9","name":"Palette Color 9"},{"color":"#FfFfFf","slug":"palette10","name":"Palette Color Complement"},{"color":"#13612e","slug":"palette11","name":"Palette Color Success"},{"color":"#1159af","slug":"palette12","name":"Palette Color Info"},{"color":"#b82105","slug":"palette13","name":"Palette Color Alert"},{"color":"#f7630c","slug":"palette14","name":"Palette Color Warning"},{"color":"#f5a524","slug":"palette15","name":"Palette Color Rating"}],"third-palette":[{"color":"#3182CE","slug":"palette1","name":"Palette Color 1"},{"color":"#2B6CB0","slug":"palette2","name":"Palette Color 2"},{"color":"#1A202C","slug":"palette3","name":"Palette Color 3"},{"color":"#2D3748","slug":"palette4","name":"Palette Color 4"},{"color":"#4A5568","slug":"palette5","name":"Palette Color 5"},{"color":"#718096","slug":"palette6","name":"Palette Color 6"},{"color":"#EDF2F7","slug":"palette7","name":"Palette Color 7"},{"color":"#F7FAFC","slug":"palette8","name":"Palette Color 8"},{"color":"#FFFFFF","slug":"palette9","name":"Palette Color 9"},{"color":"#FfFfFf","slug":"palette10","name":"Palette Color Complement"},{"color":"#13612e","slug":"palette11","name":"Palette Color Success"},{"color":"#1159af","slug":"palette12","name":"Palette Color Info"},{"color":"#b82105","slug":"palette13","name":"Palette Color Alert"},{"color":"#f7630c","slug":"palette14","name":"Palette Color Warning"},{"color":"#f5a524","slug":"palette15","name":"Palette Color Rating"}],"active":"palette"}',
palettes: kadenceCustomizerControlsData.palettePresets
? kadenceCustomizerControlsData.palettePresets
: [],
colors: {
palette1: {
tooltip: __("1 - Accent", "kadence"),
palette: false,
},
palette2: {
tooltip: __("2 - Accent - alt", "kadence"),
palette: false,
},
palette3: {
tooltip: __("3 - Strongest text", "kadence"),
palette: false,
},
palette4: {
tooltip: __("4 - Strong Text", "kadence"),
palette: false,
},
palette5: {
tooltip: __("5 - Medium text", "kadence"),
palette: false,
},
palette6: {
tooltip: __("6 - Subtle Text", "kadence"),
palette: false,
},
palette7: {
tooltip: __("7 - Subtle Background", "kadence"),
palette: false,
},
palette8: {
tooltip: __("8 - Lighter Background", "kadence"),
palette: false,
},
palette9: {
tooltip: __("9 - White or offwhite", "kadence"),
palette: false,
},
palette10: {
tooltip: __("10 - Accent - Complement", "kadence"),
palette: false,
},
palette11: {
tooltip: __("11 - Notices - Success", "kadence"),
palette: false,
},
palette12: {
tooltip: __("12 - Notices - Info", "kadence"),
palette: false,
},
palette13: {
tooltip: __("13 - Notices - Alert", "kadence"),
palette: false,
},
palette14: {
tooltip: __("14 - Notices - Warning", "kadence"),
palette: false,
},
palette15: {
tooltip: __("15 - Notices - Rating", "kadence"),
palette: false,
},
},
paletteMap: {
palette: {
tooltip: __("Palette 1", "kadence"),
},
"second-palette": {
tooltip: __("Palette 2", "kadence"),
},
"third-palette": {
tooltip: __("Palette 3", "kadence"),
},
},
};
this.controlParams = this.props.control.params.input_attrs
? {
...defaultParams,
...this.props.control.params.input_attrs,
}
: defaultParams;
this.state = {
value: value,
colorPalette: [],
fresh: "start",
isVisible: false,
textImport: "",
importError: false,
};
this.anchorNodeRef = createRef();
}
handleChangePalette(active) {
let value = this.state.value;
const newItems = this.state.value[active].map((item, index) => {
const colorToUse =
item.slug === "palette10" && item.color === "#FfFfFf"
? "oklch(from var(--global-palette1) calc(l + 0.10 * (1 - l)) calc(c * 1.00) calc(h + 180) / 100%)"
: item.color;
document.documentElement.style.setProperty(
"--global-" + item.slug,
colorToUse
);
return item;
});
value.active = active;
value[active] = newItems;
this.setState({
fresh: this.state.fresh !== "start" ? "start" : "second",
});
this.updateValues(value);
}
handlePresetImport(preset) {
const presetPalettes = JSON.parse(this.controlParams.palettes);
// Verify data.
if (
presetPalettes &&
presetPalettes[preset] &&
9 === presetPalettes[preset].length
) {
const newItems = presetPalettes[preset].map((item, index) => {
if (item.color) {
this.handleChangeComplete(
{ hex: item.color },
false,
"",
index
);
}
});
this.setState({
fresh: this.state.fresh !== "start" ? "start" : "second",
importError: false,
});
} else {
this.setState({ importPresetError: true });
}
}
handleTextImport() {
const importText = this.state.textImport;
if (!importText) {
this.setState({ importError: true });
return;
}
const textImportData = JSON.parse(importText);
// Get current palette
const currentPalette = this.state.value[this.state.value.active];
// Get imported palette
let sanitizedPalette = null;
// Check if imported palette is in named format (object with palette1, palette2, etc.)
if (
textImportData &&
!Array.isArray(textImportData) &&
typeof textImportData === "object"
) {
// Named format - loop through the palette colors
sanitizedPalette = [];
currentPalette.forEach((paletteItem) => {
const paletteKey = paletteItem.slug;
// Find the corresponding named color in the import
if (
textImportData[paletteKey] &&
textImportData[paletteKey].color
) {
// Start with a copy of current paletteItem, then merge in changes
sanitizedPalette.push({
...paletteItem,
...textImportData[paletteKey],
});
} else {
// Use current palette values for any that are missing
sanitizedPalette.push(paletteItem);
}
});
} else if (textImportData instanceof Array) {
// Array format - continue with existing logic
sanitizedPalette = textImportData;
}
// Use the sanitized palette in the usual loop to complete the import
// Verify data.
if (
sanitizedPalette &&
sanitizedPalette instanceof Array &&
sanitizedPalette[0] &&
sanitizedPalette[0].color
) {
const newItems = sanitizedPalette.map((item, index) => {
if (item.color) {
this.handleChangeComplete(
{ hex: item.color },
false,
"",
index
);
}
});
this.setState({
fresh: this.state.fresh !== "start" ? "start" : "second",
textImport: "",
isVisible: false,
importError: false,
});
} else {
this.setState({ importError: true });
}
}
convertPaletteToNamedFormat(paletteArray) {
const namedFormat = {};
paletteArray.forEach((paletteItem) => {
namedFormat[paletteItem.slug] = { color: paletteItem.color };
});
return namedFormat;
}
handleChangeComplete(color, isPalette, item, index) {
let newColor = {};
if (
undefined !== color.rgb &&
undefined !== color.rgb.a &&
1 !== color.rgb.a
) {
newColor.color =
"rgba(" +
color.rgb.r +
"," +
color.rgb.g +
"," +
color.rgb.b +
"," +
color.rgb.a +
")";
} else {
newColor.color = color.hex;
}
let value = this.state.value;
const newItems = this.state.value[this.state.value.active].map(
(item, thisIndex) => {
if (parseInt(index) === parseInt(thisIndex)) {
item = { ...item, ...newColor };
const colorToSet =
this.state.value[this.state.value.active][index]
.slug === "palette10" &&
newColor.color === "#FfFfFf"
? "oklch(from var(--global-palette1) calc(l + 0.10 * (1 - l)) calc(c * 1.00) calc(h + 180) / 100%)"
: newColor.color;
document.documentElement.style.setProperty(
"--global-" +
this.state.value[this.state.value.active][index]
.slug,
colorToSet
);
}
return item;
}
);
value[this.state.value.active] = newItems;
this.updateValues(value);
}
render() {
const toggleVisible = () => {
this.setState({ isVisible: true });
};
const toggleClose = () => {
if (this.state.isVisible === true) {
this.setState({ isVisible: false });
}
};
const presetPalettes = JSON.parse(this.controlParams.palettes);
const currentPaletteData = this.convertPaletteToNamedFormat(
this.state.value[this.state.value.active]
);
const currentPaletteJson = JSON.stringify(currentPaletteData);
const paletteGroupData = {
accent: {
name: __("Accents", "kadence"),
colors: ["palette1", "palette2", "palette10"],
},
contrast: {
name: __("Contrast", "kadence"),
colors: ["palette3", "palette4", "palette5", "palette6"],
},
base: {
name: __("Base", "kadence"),
colors: ["palette7", "palette8", "palette9"],
},
notice: {
name: __("Notices", "kadence"),
colors: [
"palette11",
"palette12",
"palette13",
"palette14",
"palette15",
],
},
};
return (
<div className="kadence-control-field kadence-palette-control kadence-color-control">
<div className="kadence-palette-header">
<Tooltip text={__("Reset Values", "kadence")}>
<Button
className="reset kadence-reset"
onClick={() => {
let value = this.state.value;
const reset = JSON.parse(
this.controlParams.reset
);
const newItems = this.state.value[
this.state.value.active
].map((item, thisIndex) => {
item = {
...item,
...reset[this.state.value.active][
thisIndex
],
};
document.documentElement.style.setProperty(
"--global-" +
reset[this.state.value.active][
thisIndex
].slug,
item.slug === "palette10" &&
item.color === "#FfFfFf"
? "oklch(from var(--global-palette1) calc(l + 0.10 * (1 - l)) calc(c * 1.00) calc(h + 180) / 100%)"
: reset[this.state.value.active][
thisIndex
].color
);
return item;
});
value[this.state.value.active] = newItems;
this.updateValues(value);
}}
>
<Dashicon icon="image-rotate" />
</Button>
</Tooltip>
{this.props.control.params.label && (
<span className="customize-control-title">
{this.props.control.params.label}
</span>
)}
{!this.props.hideResponsive && (
<div className="floating-controls">
<ButtonGroup>
{Object.keys(this.controlParams.paletteMap).map(
(palette) => {
return (
<Tooltip
text={
this.controlParams
.paletteMap[palette]
.tooltip
}
>
<Button
isTertiary
className={
(palette ===
this.state.value.active
? "active-palette "
: "") + palette
}
onClick={() => {
this.handleChangePalette(
palette
);
}}
>
{
this.controlParams
.paletteMap[palette]
.tooltip
}
</Button>
</Tooltip>
);
}
)}
</ButtonGroup>
</div>
)}
</div>
<div
ref={this.anchorNodeRef}
className="kadence-palette-colors"
>
{Object.keys(paletteGroupData).map((group, index) => {
return (
<div className="kadence-palette-group">
<div className="kadence-palette-group-name">
{paletteGroupData[group].name}
</div>
<div className="kadence-palette-group-colors">
{paletteGroupData[group].colors.map(
(item, colorIndex) => {
const paletteIndex =
item.match(/\d+$/)?.[0] - 1;
return (
<ColorControl
key={
item +
this.state.value
.active +
this.state.fresh
}
presetColors={
this.state.colorPalette
}
color={
undefined !==
this.state.value[
this.state.value
.active
][paletteIndex] &&
this.state.value[
this.state.value
.active
][paletteIndex].color
? this.state.value[
this.state
.value
.active
][paletteIndex]
.color
: ""
}
isPalette={""}
usePalette={false}
paletteName={item}
className={"kt-" + item}
tooltip={
undefined !==
this.controlParams
.colors[item]
.tooltip
? this.controlParams
.colors[
item
].tooltip
: ""
}
onChangeComplete={(
color,
isPalette
) =>
this.handleChangeComplete(
color,
isPalette,
item,
paletteIndex
)
}
controlRef={
this.anchorNodeRef
}
/>
);
}
)}
</div>
</div>
);
})}
</div>
<div className={"kadence-palette-import-wrap"}>
<Button
className={"kadence-palette-import"}
onClick={() => {
this.state.isVisible
? toggleClose()
: toggleVisible();
}}
>
<Dashicon icon="portfolio" />
</Button>
{this.state.isVisible && (
<Popover
position="bottom right"
inline={true}
className="kadence-palette-popover-copy-paste kadence-customizer-popover"
onClose={toggleClose}
>
<TabPanel
className="kadence-palette-popover-tabs"
activeClass="active-tab"
initialTabName={"import"}
tabs={[
{
name: "import",
title: __("Select Palette", "kadence"),
className: "kadence-color-presets",
},
{
name: "custom",
title: __("Export/Import", "kadence"),
className: "kadence-export-import",
},
]}
>
{(tab) => {
let tabout;
if (tab.name) {
if ("import" === tab.name) {
tabout = (
<Fragment>
{Object.keys(
presetPalettes
).map((item, index) => {
return (
<Button
className={
"kadence-palette-item"
}
style={{
height: "100%",
width: "100%",
}}
onClick={() =>
this.handlePresetImport(
item
)
}
tabIndex={0}
>
{Object.keys(
presetPalettes[
item
]
).map(
(
color,
subIndex
) => {
return (
<div
key={
subIndex
}
style={{
width: 26,
height: 26,
marginBottom: 0,
transform:
"scale(1)",
transition:
"100ms transform ease",
}}
className="kadence-swatche-item-wrap"
>
<span
className={
"kadence-swatch-item"
}
style={{
height: "100%",
display:
"block",
width: "100%",
border: "1px solid rgb(218, 218, 218)",
borderRadius:
"50%",
color: `${presetPalettes[item][color].color}`,
boxShadow: `inset 0 0 0 ${
30 /
2
}px`,
transition:
"100ms box-shadow ease",
}}
></span>
</div>
);
}
)}
</Button>
);
})}
</Fragment>
);
} else {
tabout = (
<Fragment>
<h2>
{__(
"Export",
"kadence"
)}
</h2>
<TextareaControl
label=""
help={__(
"Copy export data to use in another site.",
"kadence"
)}
value={
currentPaletteJson
}
onChange={false}
/>
<h2>
{__(
"Import",
"kadence"
)}
</h2>
<TextareaControl
label={__(
"Import color set from text data.",
"kadence"
)}
help={__(
"Follow format from export above.",
"kadence"
)}
value={
this.state
.textImport
}
onChange={(text) =>
this.setState({
textImport:
text,
})
}
/>
{this.state.importError && (
<p
style={{
color: "red",
}}
>
{__(
"Error with Import data",
"kadence"
)}
</p>
)}
<Button
className={
"kadence-import-button"
}
isPrimary
disabled={
this.state
.textImport
? false
: true
}
onClick={() =>
this.handleTextImport()
}
>
{__(
"Import",
"kadence"
)}
</Button>
</Fragment>
);
}
}
return <div>{tabout}</div>;
}}
</TabPanel>
</Popover>
)}
</div>
{this.props.control.params.description && (
<span className="customize-control-description">
<a
href="https://kadence-theme.com/docs/how-to-use-the-kadence-color-palette/"
target="_blank"
>
{this.props.control.params.description}
</a>
</span>
)}
{ this.props.control.renderNotice() }
</div>
);
}
updateValues(value) {
this.setState({ value: value });
this.props.control.setting.set(JSON.stringify(value));
kadenceCustomizerControlsData.palette = JSON.stringify(value);
}
}
ColorComponent.propTypes = {
control: PropTypes.object.isRequired,
};
export default ColorComponent;

View File

@@ -0,0 +1,14 @@
import { createRoot } from '@wordpress/element';
import RadioIconComponent from './radio-icon-component.js';
export const RadioIconControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <RadioIconComponent control={control}/> );
// ReactDOM.render(
// <RadioIconComponent control={control}/>,
// control.container[0]
// );
}
} );

View File

@@ -0,0 +1,293 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import ResponsiveControl from '../common/responsive.js';
import Icons from '../common/icons.js';
import { __ } from '@wordpress/i18n';
const { ButtonGroup, Dashicon, Tooltip, Button } = wp.components;
const { Component, Fragment } = wp.element;
class RadioIconComponent extends Component {
constructor() {
super( ...arguments );
this.updateValues = this.updateValues.bind( this );
let value = this.props.control.setting.get();
let defaultParams = {
layout: {
standard: {
tooltip: __( 'Background Fullwidth, Content Contained', 'kadence' ),
name: __( 'Standard', 'kadence' ),
icon: '',
},
fullwidth: {
tooltip: __( 'Background & Content Fullwidth', 'kadence' ),
name: __( 'Fullwidth', 'kadence' ),
icon: '',
},
contained: {
tooltip: __( 'Background & Content Contained', 'kadence' ),
name: __( 'Contained', 'kadence' ),
icon: '',
},
},
responsive: true,
};
this.controlParams = this.props.control.params.input_attrs ? {
...defaultParams,
...this.props.control.params.input_attrs,
} : defaultParams;
let responsiveDefault = {
'mobile': '',
'tablet': '',
'desktop': 'standard'
};
let nonResponsiveDefault = 'standard';
let baseDefault;
if ( this.controlParams.responsive ) {
baseDefault = responsiveDefault;
this.defaultValue = this.props.control.params.default ? {
...baseDefault,
...this.props.control.params.default
} : baseDefault;
} else {
baseDefault = nonResponsiveDefault;
this.defaultValue = this.props.control.params.default ? this.props.control.params.default : baseDefault;
}
if ( this.controlParams.responsive ) {
value = value ? {
...JSON.parse( JSON.stringify( this.defaultValue ) ),
...value
} : JSON.parse( JSON.stringify( this.defaultValue ) );
} else {
value = value ? value : this.defaultValue;
}
this.state = {
currentDevice: 'desktop',
value: value,
};
}
render() {
const responsiveControlLabel = (
<Fragment>
{ this.state.currentDevice !== 'desktop' && (
<Tooltip text={ __( 'Reset Device Values', 'kadence' ) }>
<Button
className="reset kadence-reset"
disabled={ ( this.state.value[this.state.currentDevice] === this.defaultValue[this.state.currentDevice] ) }
onClick={ () => {
let value = this.state.value;
value[this.state.currentDevice] = this.defaultValue[this.state.currentDevice];
this.setState( value );
this.updateValues( value );
} }
>
<Dashicon icon='image-rotate' />
</Button>
</Tooltip>
) }
{ this.props.control.params.label &&
this.props.control.params.label
}
</Fragment>
);
const controlLabel = (
<Fragment>
<Tooltip text={ __( 'Reset Values', 'kadence' ) }>
<Button
className="reset kadence-reset"
disabled={ ( this.state.value === this.defaultValue ) }
onClick={ () => {
let value = this.defaultValue;
this.setState( { value: this.defaultValue } );
this.updateValues( value );
} }
>
<Dashicon icon='image-rotate' />
</Button>
</Tooltip>
{ this.props.control.params.label &&
this.props.control.params.label
}
</Fragment>
);
return (
<div className={ `kadence-control-field kadence-radio-icon-control${ this.controlParams.class ? ' ' + this.controlParams.class : '' }` }>
{ this.controlParams.responsive && (
<ResponsiveControl
onChange={ ( currentDevice) => this.setState( { currentDevice } ) }
controlLabel={ responsiveControlLabel }
>
<ButtonGroup className="kadence-radio-container-control">
{ Object.keys( this.controlParams.layout ).map( ( item ) => {
return (
<Fragment>
{ this.controlParams.layout[ item ].tooltip && (
<Tooltip text={ this.controlParams.layout[ item ].tooltip }>
<Button
isTertiary
className={ ( item === this.state.value[this.state.currentDevice] ?
'active-radio ' :
'' ) + 'kt-ratio-' + item + ( this.controlParams.layout[ item ].icon && this.controlParams.layout[ item ].name ? ' btn-flex-col' : '' ) }
onClick={ () => {
let value = this.state.value;
value[ this.state.currentDevice ] = item;
this.setState( value );
this.updateValues( value );
} }
>
{ this.controlParams.layout[ item ].icon && (
<span className="kadence-radio-icon">
{ Icons[ this.controlParams.layout[ item ].icon ] }
</span>
) }
{ this.controlParams.layout[ item ].dashicon && (
<span className="kadence-radio-icon kadence-radio-dashicon">
<Dashicon icon={ this.controlParams.layout[ item ].dashicon } />
</span>
) }
{ this.controlParams.layout[ item ].name && (
this.controlParams.layout[ item ].name
) }
</Button>
</Tooltip>
) }
{ ! this.controlParams.layout[ item ].tooltip && (
<Button
isTertiary
className={ ( item === this.state.value[this.state.currentDevice] ?
'active-radio ' :
'' ) + 'kt-radio-' + item + ( this.controlParams.layout[ item ].icon && this.controlParams.layout[ item ].name ? ' btn-flex-col' : '' ) }
onClick={ () => {
let value = this.state.value;
value[ this.state.currentDevice ] = item;
this.setState( value );
this.updateValues( value );
} }
>
{ this.controlParams.layout[ item ].icon && (
<span className="kadence-radio-icon">
{ Icons[ this.controlParams.layout[ item ].icon ] }
</span>
) }
{ this.controlParams.layout[ item ].dashicon && (
<span className="kadence-radio-icon kadence-radio-dashicon">
<Dashicon icon={ this.controlParams.layout[ item ].dashicon } />
</span>
) }
{ this.controlParams.layout[ item ].name && (
this.controlParams.layout[ item ].name
) }
</Button>
) }
</Fragment>
);
} )}
</ButtonGroup>
</ResponsiveControl>
) }
{ ! this.controlParams.responsive && (
<Fragment>
<div className="kadence-responsive-control-bar">
<span className="customize-control-title">{ controlLabel }</span>
</div>
<ButtonGroup className="kadence-radio-container-control">
{ Object.keys( this.controlParams.layout ).map( ( item ) => {
return (
<Fragment>
{ this.controlParams.layout[ item ].tooltip && (
<Tooltip text={ this.controlParams.layout[ item ].tooltip }>
<Button
isTertiary
className={ ( item === this.state.value ?
'active-radio ' :
'' ) + 'kt-radio-' + item + ( this.controlParams.layout[ item ].icon && this.controlParams.layout[ item ].name ? ' btn-flex-col' : '' ) }
onClick={ () => {
let value = this.state.value;
value = item;
this.setState( { value: item });
this.updateValues( value );
} }
>
{ this.controlParams.layout[ item ].icon && (
<span className="kadence-radio-icon">
{ Icons[ this.controlParams.layout[ item ].icon ] }
</span>
) }
{ this.controlParams.layout[ item ].dashicon && (
<span className="kadence-radio-icon kadence-radio-dashicon">
<Dashicon icon={ this.controlParams.layout[ item ].dashicon } />
</span>
) }
{ this.controlParams.layout[ item ].name && (
this.controlParams.layout[ item ].name
) }
</Button>
</Tooltip>
) }
{ ! this.controlParams.layout[ item ].tooltip && (
<Button
isTertiary
className={ ( item === this.state.value ?
'active-radio ' :
'' ) + 'kt-radio-' + item + ( this.controlParams.layout[ item ].icon && this.controlParams.layout[ item ].name ? ' btn-flex-col' : '' ) }
onClick={ () => {
let value = this.state.value;
value = item;
this.setState( { value: item });
this.updateValues( value );
} }
>
{ this.controlParams.layout[ item ].icon && (
<span className="kadence-radio-icon">
{ Icons[ this.controlParams.layout[ item ].icon ] }
</span>
) }
{ this.controlParams.layout[ item ].dashicon && (
<span className="kadence-radio-icon kadence-radio-dashicon">
<Dashicon icon={ this.controlParams.layout[ item ].dashicon } />
</span>
) }
{ this.controlParams.layout[ item ].name && (
this.controlParams.layout[ item ].name
) }
</Button>
) }
</Fragment>
);
} )}
</ButtonGroup>
</Fragment>
) }
{ this.props.control.renderNotice() }
</div>
);
}
updateValues( value ) {
if ( this.controlParams.footer ) {
let event = new CustomEvent(
'kadenceUpdateFooterColumns', {
'detail': this.controlParams.footer,
} );
document.dispatchEvent( event );
}
if ( this.controlParams.responsive ) {
this.props.control.setting.set( {
...this.props.control.setting.get(),
...value,
flag: !this.props.control.setting.get().flag
} );
} else {
this.props.control.setting.set( value );
}
}
}
RadioIconComponent.propTypes = {
control: PropTypes.object.isRequired
};
export default RadioIconComponent;

View File

@@ -0,0 +1,14 @@
import { createRoot } from '@wordpress/element';
import RangeComponent from './range-component.js';
export const RangeControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <RangeComponent control={control}/> );
// ReactDOM.render(
// <RangeComponent control={control}/>,
// control.container[0]
// );
}
} );

View File

@@ -0,0 +1,307 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import ResponsiveControl from '../common/responsive.js';
import KadenceRange from '../common/range.js';
import Icons from '../common/icons.js';
import { __ } from '@wordpress/i18n';
const { RangeControl, Dashicon, Tooltip, Button, ToolbarGroup } = wp.components;
const { Component, Fragment } = wp.element;
class RangeComponent extends Component {
constructor() {
super( ...arguments );
this.updateValues = this.updateValues.bind( this );
this.getUnitButtons = this.getUnitButtons.bind( this );
this.createLevelControlToolbar = this.createLevelControlToolbar.bind( this );
this.createResponsiveLevelControlToolbar = this.createResponsiveLevelControlToolbar.bind( this );
this.getResponsiveUnitButtons = this.getResponsiveUnitButtons.bind( this );
let value = this.props.control.setting.get();
let baseDefault = {
'unit': {
'mobile': 'px',
'tablet': 'px',
'desktop': 'px'
},
'size': {
'mobile': 70,
'tablet': 70,
'desktop': 140
}
};
this.defaultValue = this.props.control.params.default ? {
...baseDefault,
...this.props.control.params.default
} : baseDefault;
value = value ? {
...this.defaultValue,
...value
} : this.defaultValue;
let defaultParams = {
min: {
px: '0',
em: '0',
rem: '0',
vh: '0'
},
max: {
px: '300',
em: '12',
rem: '12',
vh: '40'
},
step: {
px: '1',
em: '0.01',
rem: '0.01',
vh: '1'
},
units: ['px', 'em', 'rem', 'vh'],
responsive: true,
};
this.controlParams = this.props.control.params.input_attrs ? {
...defaultParams,
...this.props.control.params.input_attrs,
} : defaultParams;
this.state = {
currentDevice: 'desktop',
size: value.size,
unit: value.unit,
};
}
render() {
const responsiveControlLabel = (
<Fragment>
{ this.controlParams.responsive && (
<Fragment>
<Tooltip text={ __( 'Reset Device Values', 'kadence' ) }>
<Button
className="reset kadence-reset"
disabled={ ( this.state.size[this.state.currentDevice] === this.defaultValue.size[this.state.currentDevice] ) && ( this.state.unit[this.state.currentDevice] === this.defaultValue.unit[this.state.currentDevice] ) }
onClick={ () => {
let value = this.state.size;
let unit = this.state.unit;
if ( typeof value !== 'object' ) {
value = {
'mobile': '',
'tablet': '',
'desktop': '',
};
this.setState( { size: value } );
if ( typeof unit !== 'object' ) {
unit = {
'mobile': '',
'tablet': '',
'desktop': '',
};
this.setState( { unit: unit } );
}
}
value[this.state.currentDevice] = this.defaultValue.size[this.state.currentDevice];
unit[this.state.currentDevice] = this.defaultValue.unit[this.state.currentDevice];
this.setState( { size: value, unit: unit } );
this.updateValues( { size: value, unit: unit } );
} }
>
<Dashicon icon='image-rotate' />
</Button>
</Tooltip>
{ this.props.control.params.label &&
this.props.control.params.label
}
</Fragment>
) }
</Fragment>
);
const controlLabel = (
<Fragment>
<Tooltip text={ __( 'Reset Values', 'kadence' ) }>
<Button
className="reset kadence-reset"
disabled={ ( this.state.size === this.defaultValue.size ) && ( this.state.unit === this.defaultValue.unit ) }
onClick={ () => {
let value = this.state.size;
value = this.defaultValue.size;
let svalue = this.state.unit;
svalue = this.defaultValue.unit;
this.setState( { size: value, unit: svalue } );
this.updateValues( { size: value, unit: svalue } );
} }
>
<Dashicon icon='image-rotate' />
</Button>
</Tooltip>
{ this.props.control.params.label &&
this.props.control.params.label
}
</Fragment>
);
return (
<div className="kadence-control-field kadence-range-control">
{ this.controlParams.responsive && (
<ResponsiveControl
onChange={ ( currentDevice) => this.setState( { currentDevice } ) }
controlLabel={ responsiveControlLabel }
>
<KadenceRange
initialPosition={ ( ! this.state.size[this.state.currentDevice] ? this.defaultValue.size[this.state.currentDevice] : undefined ) }
value={ ( undefined !== this.state.size[this.state.currentDevice] ? this.state.size[this.state.currentDevice] : undefined ) }
onChange={ (val) => {
let value = this.state.size;
if ( typeof value !== 'object' ) {
value = {
'mobile': '',
'tablet': '',
'desktop': '',
};
this.setState( { size: value } );
let unit = this.state.unit;
if ( typeof unit !== 'object' ) {
unit = {
'mobile': '',
'tablet': '',
'desktop': '',
};
this.setState( { unit: unit } );
}
}
value[ this.state.currentDevice ] = val;
this.setState( { size: value } );
this.updateValues( { size: value } );
} }
min={this.controlParams.min[this.state.unit[this.state.currentDevice]]}
max={this.controlParams.max[this.state.unit[this.state.currentDevice]]}
step={this.controlParams.step[this.state.unit[this.state.currentDevice]]}
/>
{ this.controlParams.units && (
<div className="kadence-units">
{ this.getResponsiveUnitButtons() }
</div>
) }
</ResponsiveControl>
) }
{ ! this.controlParams.responsive && (
<Fragment>
<div className="kadence-responsive-control-bar">
<span className="customize-control-title">{ controlLabel }</span>
</div>
<div className="kadence-responsive-controls-content">
<KadenceRange
initialPosition={ ( ! this.state.size ? this.defaultValue.size : undefined ) }
value={this.state.size}
onChange={ (val) => {
let value = this.state.size;
value = val;
this.setState( { size: value } );
this.updateValues( { size: value } );
} }
min={this.controlParams.min[this.state.unit]}
max={this.controlParams.max[this.state.unit]}
step={this.controlParams.step[this.state.unit]}
/>
{ this.controlParams.units && (
<div className="kadence-units">
{ this.getUnitButtons() }
</div>
) }
</div>
</Fragment>
) }
{ this.props.control.renderNotice() }
</div>
);
}
getUnitButtons() {
let self = this;
const { units } = this.controlParams;
if ( units.length === 1 ) {
return ( <Button
className="is-active is-single"
isSmall
disabled
>{ ( '%' === self.state.unit ? Icons.percent : Icons[ self.state.unit ] ) }</Button> );
}
return <ToolbarGroup
isCollapsed={ true }
icon={ ( '%' === self.state.unit ? Icons.percent : Icons[ self.state.unit ] ) }
label={ __( 'Unit', 'kadence' ) }
controls={ units.map( (unit) => this.createLevelControlToolbar( unit ) ) }
/>
}
createLevelControlToolbar( unit ) {
return [ {
icon: ( unit === '%' ? Icons.percent : Icons[ unit ] ),
isActive: this.state.unit === unit,
onClick: () => {
let value = this.state.unit;
value = unit;
this.setState( { unit: value } );
this.updateValues( { unit: value } );
},
} ];
};
createResponsiveLevelControlToolbar( unit ) {
return [ {
icon: ( unit === '%' ? Icons.percent : Icons[ unit ] ),
isActive: this.state.unit[this.state.currentDevice] === unit,
onClick: () => {
let value = this.state.unit;
if ( typeof value !== 'object' ) {
value = {
'mobile': '',
'tablet': '',
'desktop': '',
};
this.setState( { unit: value } );
let size = this.state.size;
if ( typeof size !== 'object' ) {
size = {
'mobile': '',
'tablet': '',
'desktop': '',
};
this.setState( { size: size } );
}
}
value[ this.state.currentDevice ] = unit;
this.setState( { unit: value } );
this.updateValues( { unit: value } );
},
} ];
};
getResponsiveUnitButtons() {
let self = this;
const { units } = this.controlParams;
if ( units.length === 1 ) {
return ( <Button
className="is-active is-single"
isSmall
disabled
>{ ( '%' === self.state.unit[ self.state.currentDevice ] ? Icons.percent : Icons[ self.state.unit[ self.state.currentDevice ] ] ) }</Button> );
}
return <ToolbarGroup
isCollapsed={ true }
icon={ ( '%' === self.state.unit[ self.state.currentDevice ] ? Icons.percent : Icons[ self.state.unit[ self.state.currentDevice ] ] ) }
label={ __( 'Unit', 'kadence' ) }
controls={ units.map( (unit) => this.createResponsiveLevelControlToolbar( unit ) ) }
/>
}
updateValues( value ) {
if ( this.controlParams.responsive ) {
value.flag = !this.props.control.setting.get().flag;
}
this.props.control.setting.set( {
...this.props.control.setting.get(),
...value,
} );
}
}
RangeComponent.propTypes = {
control: PropTypes.object.isRequired
};
export default RangeComponent;

View File

@@ -0,0 +1,14 @@
import { createRoot } from '@wordpress/element';
import RowLayoutComponent from './row-layout-component';
export const RowControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <RowLayoutComponent control={control} customizer={ wp.customize }/> );
// ReactDOM.render(
// <RowLayoutComponent control={control} customizer={ wp.customize }/>,
// control.container[0]
// );
}
} );

View File

@@ -0,0 +1,450 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import ResponsiveControl from '../common/responsive.js';
import Icons from '../common/icons.js';
import { __ } from '@wordpress/i18n';
const { ButtonGroup, Dashicon, Tooltip, Button } = wp.components;
const { Component, Fragment } = wp.element;
class RowLayoutComponent extends Component {
constructor() {
super( ...arguments );
this.updateValues = this.updateValues.bind( this );
this.onFooterUpdate = this.onFooterUpdate.bind( this );
this.linkColumns();
let value = this.props.control.setting.get();
let defaultParams = {
desktop: {
'column5': {
'equal': {
tooltip: __( 'Equal Width Columns', 'kadence' ),
icon: 'fivecol',
},
},
'column4': {
'equal': {
tooltip: __( 'Equal Width Columns', 'kadence' ),
icon: 'fourcol',
},
'left-forty': {
tooltip: __( 'Left Heavy 40/20/20/20', 'kadence' ),
icon: 'lfourforty',
},
'right-forty': {
tooltip: __( 'Right Heavy 20/20/20/40', 'kadence' ),
icon: 'rfourforty',
},
},
'column3': {
'equal': {
tooltip: __( 'Equal Width Columns', 'kadence' ),
icon: 'threecol',
},
'left-half': {
tooltip: __( 'Left Heavy 50/25/25', 'kadence' ),
icon: 'lefthalf',
},
'right-half': {
tooltip: __( 'Right Heavy 25/25/50', 'kadence' ),
icon: 'righthalf',
},
'center-half': {
tooltip: __( 'Center Heavy 25/50/25', 'kadence' ),
icon: 'centerhalf',
},
'center-wide': {
tooltip: __( 'Wide Center 20/60/20', 'kadence' ),
icon: 'widecenter',
},
},
'column2': {
'equal': {
tooltip: __( 'Equal Width Columns', 'kadence' ),
icon: 'twocol',
},
'left-golden': {
tooltip: __( 'Left Heavy 66/33', 'kadence' ),
icon: 'twoleftgolden',
},
'right-golden': {
tooltip: __( 'Right Heavy 33/66', 'kadence' ),
icon: 'tworightgolden',
},
},
'column1': {
'row': {
tooltip: __( 'Equal Width Columns', 'kadence' ),
icon: 'row',
},
}
},
mobile: {
'column5': {
'equal': {
tooltip: __( 'Equal Width Columns', 'kadence' ),
icon: 'fivecol',
},
'row': {
tooltip: __( 'Collapse to Rows', 'kadence' ),
icon: 'collapserowfive',
},
},
'column4': {
'equal': {
tooltip: __( 'Equal Width Columns', 'kadence' ),
icon: 'fourcol',
},
'two-grid': {
tooltip: __( 'Two Column Grid', 'kadence' ),
icon: 'grid',
},
'row': {
tooltip: __( 'Collapse to Rows', 'kadence' ),
icon: 'collapserowfour',
},
},
'column3': {
'equal': {
tooltip: __( 'Equal Width Columns', 'kadence' ),
icon: 'threecol',
},
'left-half': {
tooltip: __( 'Left Heavy 50/25/25', 'kadence' ),
icon: 'lefthalf',
},
'right-half': {
tooltip: __( 'Right Heavy 25/25/50', 'kadence' ),
icon: 'righthalf',
},
'center-half': {
tooltip: __( 'Center Heavy 25/50/25', 'kadence' ),
icon: 'centerhalf',
},
'center-wide': {
tooltip: __( 'Wide Center 20/60/20', 'kadence' ),
icon: 'widecenter',
},
'first-row': {
tooltip: __( 'First Row, Next Columns 100 - 50/50', 'kadence' ),
icon: 'firstrow',
},
'last-row': {
tooltip: __( 'Last Row, Previous Columns 50/50 - 100', 'kadence' ),
icon: 'lastrow',
},
'row': {
tooltip: __( 'Collapse to Rows', 'kadence' ),
icon: 'collapserowthree',
},
},
'column2': {
'equal': {
tooltip: __( 'Equal Width Columns', 'kadence' ),
icon: 'twocol',
},
'left-golden': {
tooltip: __( 'Left Heavy 66/33', 'kadence' ),
icon: 'twoleftgolden',
},
'right-golden': {
tooltip: __( 'Right Heavy 33/66', 'kadence' ),
icon: 'tworightgolden',
},
'row': {
tooltip: __( 'Collapse to Rows', 'kadence' ),
icon: 'collapserow',
},
},
'column1': {
'row': {
tooltip: __( 'Single Row', 'kadence' ),
icon: 'row',
},
}
},
responsive: true,
};
this.controlParams = this.props.control.params.input_attrs ? {
...defaultParams,
...this.props.control.params.input_attrs,
} : defaultParams;
let responsiveDefault = {
'mobile': 'row',
'tablet': '',
'desktop': 'equal'
};
let nonResponsiveDefault = 'equal';
let baseDefault;
if ( this.controlParams.responsive ) {
baseDefault = responsiveDefault;
this.defaultValue = this.props.control.params.default ? {
...baseDefault,
...this.props.control.params.default
} : baseDefault;
} else {
baseDefault = nonResponsiveDefault;
this.defaultValue = this.props.control.params.default ? this.props.control.params.default : baseDefault;
}
if ( this.controlParams.responsive ) {
value = value ? {
...JSON.parse( JSON.stringify( this.defaultValue ) ),
...value
} : JSON.parse( JSON.stringify( this.defaultValue ) );
} else {
value = value ? value : this.defaultValue;
}
let columns = 0;
if ( this.controlParams.footer ) {
columns = parseInt( this.props.customizer.control( 'footer_' + this.controlParams.footer + '_columns' ).setting.get(), 10 );
}
this.state = {
currentDevice: 'desktop',
columns: columns,
value: value,
};
}
render() {
const responsiveControlLabel = (
<Fragment>
{ this.state.currentDevice !== 'desktop' && (
<Tooltip text={ __( 'Reset Device Values', 'kadence' ) }>
<Button
className="reset kadence-reset"
disabled={ ( this.state.value[this.state.currentDevice] === this.defaultValue[this.state.currentDevice] ) }
onClick={ () => {
let value = this.state.value;
value[this.state.currentDevice] = this.defaultValue[this.state.currentDevice];
this.setState( value );
this.updateValues( value );
} }
>
<Dashicon icon='image-rotate' />
</Button>
</Tooltip>
) }
{ this.props.control.params.label &&
this.props.control.params.label
}
</Fragment>
);
const controlLabel = (
<Fragment>
<Tooltip text={ __( 'Reset Values', 'kadence' ) }>
<Button
className="reset kadence-reset"
disabled={ ( this.state.value === this.defaultValue ) }
onClick={ () => {
let value = this.defaultValue;
this.setState( { value: this.defaultValue } );
this.updateValues( value );
} }
>
<Dashicon icon='image-rotate' />
</Button>
</Tooltip>
{ this.props.control.params.label &&
this.props.control.params.label
}
</Fragment>
);
let controlMap = {}
if ( this.state.currentDevice !== 'desktop' ) {
controlMap = this.controlParams.mobile['column' + this.state.columns ];
} else {
controlMap = this.controlParams.desktop['column' + this.state.columns ];
}
return (
<div className="kadence-control-field kadence-radio-icon-control kadence-row-layout-control">
{ this.controlParams.responsive && (
<ResponsiveControl
onChange={ ( currentDevice) => this.setState( { currentDevice } ) }
controlLabel={ responsiveControlLabel }
>
<ButtonGroup className="kadence-radio-container-control">
{ Object.keys( controlMap ).map( ( item ) => {
return (
<Fragment>
{ controlMap[ item ].tooltip && (
<Tooltip text={ controlMap[ item ].tooltip }>
<Button
isTertiary
className={ ( item === this.state.value[this.state.currentDevice] ?
'active-radio ' :
'' ) + 'kadence-btn-item-' + item }
onClick={ () => {
let value = this.state.value;
value[ this.state.currentDevice ] = item;
this.setState( value );
this.updateValues( value );
} }
>
{ controlMap[ item ].icon && (
<span className="kadence-radio-icon">
{ Icons[ controlMap[ item ].icon ] }
</span>
) }
{ controlMap[ item ].dashicon && (
<span className="kadence-radio-icon kadence-radio-dashicon">
<Dashicon icon={ controlMap[ item ].dashicon } />
</span>
) }
{ controlMap[ item ].name && (
controlMap[ item ].name
) }
</Button>
</Tooltip>
) }
{ ! controlMap[ item ].tooltip && (
<Button
isTertiary
className={ ( item === this.state.value[this.state.currentDevice] ?
'active-radio ' :
'' ) + 'kadence-btn-item-' + item }
onClick={ () => {
let value = this.state.value;
value[ this.state.currentDevice ] = item;
this.setState( value );
this.updateValues( value );
} }
>
{ controlMap[ item ].icon && (
<span className="kadence-radio-icon">
{ Icons[ controlMap[ item ].icon ] }
</span>
) }
{ controlMap[ item ].dashicon && (
<span className="kadence-radio-icon kadence-radio-dashicon">
<Dashicon icon={ controlMap[ item ].dashicon } />
</span>
) }
{ controlMap[ item ].name && (
controlMap[ item ].name
) }
</Button>
) }
</Fragment>
);
} )}
</ButtonGroup>
</ResponsiveControl>
) }
{ ! this.controlParams.responsive && (
<Fragment>
<div className="kadence-responsive-control-bar">
<span className="customize-control-title">{ controlLabel }</span>
</div>
<ButtonGroup className="kadence-radio-container-control">
{ Object.keys( controlMap ).map( ( item ) => {
return (
<Fragment>
{ controlMap[ item ].tooltip && (
<Tooltip text={ controlMap[ item ].tooltip }>
<Button
isTertiary
className={ ( item === this.state.value ?
'active-radio ' :
'' ) + 'kadence-btn-item-' + item }
onClick={ () => {
let value = this.state.value;
value = item;
this.setState( { value: item });
this.updateValues( value );
} }
>
{ controlMap[ item ].icon && (
<span className="kadence-radio-icon">
{ Icons[ controlMap[ item ].icon ] }
</span>
) }
{ controlMap[ item ].name && (
controlMap[ item ].name
) }
</Button>
</Tooltip>
) }
{ ! controlMap[ item ].tooltip && (
<Button
isTertiary
className={ ( item === this.state.value ?
'active-radio ' :
'' ) + 'kadence-btn-item-' + item }
onClick={ () => {
let value = this.state.value;
value = item;
this.setState( { value: item });
this.updateValues( value );
} }
>
{ controlMap[ item ].icon && (
<span className="kadence-radio-icon">
{ Icons[ controlMap[ item ].icon ] }
</span>
) }
{ controlMap[ item ].name && (
controlMap[ item ].name
) }
</Button>
) }
</Fragment>
);
} )}
</ButtonGroup>
</Fragment>
) }
{ this.props.control.renderNotice() }
</div>
);
}
onFooterUpdate() {
const columns = parseInt( this.props.customizer.control( 'footer_' + this.controlParams.footer + '_columns' ).setting.get(), 10 );
if ( this.state.columns !== columns ) {
this.setState( { columns: columns } );
let value = this.state.value;
if ( columns === 1 ) {
value.desktop = 'row';
} else {
value.desktop = 'equal';
}
value.tablet = '';
value.mobile = 'row';
this.setState( value );
this.updateValues( value );
}
}
linkColumns() {
let self = this;
document.addEventListener( 'kadenceUpdateFooterColumns', function( e ) {
if ( e.detail === self.controlParams.footer ) {
setTimeout(function(){ self.onFooterUpdate(); }, 200);
}
} );
}
updateValues( value ) {
if ( undefined !== this.controlParams.footer && this.controlParams.footer ) {
let event = new CustomEvent(
'kadenceUpdateFooterColumns', {
'detail': this.controlParams.footer,
} );
document.dispatchEvent( event );
}
if ( this.controlParams.responsive ) {
this.props.control.setting.set( {
...this.props.control.setting.get(),
...value,
flag: !this.props.control.setting.get().flag
} );
} else {
this.props.control.setting.set( value );
}
}
}
RowLayoutComponent.propTypes = {
control: PropTypes.object.isRequired
};
export default RowLayoutComponent;

View File

@@ -0,0 +1,14 @@
import { createRoot } from '@wordpress/element';
import SelectComponent from './select-component.js';
export const SelectControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <SelectComponent control={control}/> );
// ReactDOM.render(
// <SelectComponent control={control}/>,
// control.container[0]
// );
}
} );

View File

@@ -0,0 +1,89 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { __ } from '@wordpress/i18n';
const { SelectControl, Dashicon, Tooltip, Button } = wp.components;
const { Component, Fragment } = wp.element;
class SelectComponent extends Component {
constructor() {
super( ...arguments );
this.updateValues = this.updateValues.bind( this );
let value = this.props.control.setting.get();
let defaultParams = {
options: {
standard: {
name: __( 'Standard', 'kadence' ),
},
fullwidth: {
name: __( 'Fullwidth', 'kadence' ),
},
contained: {
name: __( 'Contained', 'kadence' ),
},
},
};
this.controlParams = this.props.control.params.input_attrs ? {
...defaultParams,
...this.props.control.params.input_attrs,
} : defaultParams;
let baseDefault = 'standard';
this.defaultValue = this.props.control.params.default ? this.props.control.params.default : baseDefault;
value = value ? value : this.defaultValue;
this.state = {
value: value,
};
}
render() {
const controlLabel = (
<Fragment>
<Tooltip text={ __( 'Reset Value', 'kadence' ) }>
<Button
className="reset kadence-reset"
disabled={ ( this.state.value === this.defaultValue ) }
onClick={ () => {
let value = this.defaultValue;
this.updateValues( value );
} }
>
<Dashicon icon='image-rotate' />
</Button>
</Tooltip>
{ this.props.control.params.label &&
this.props.control.params.label
}
</Fragment>
);
const selectOptions = Object.keys( this.controlParams.options ).map( ( item ) => {
return ( { label: this.controlParams.options[ item ].name, value: item } );
} );
return (
<div className="kadence-control-field kadence-select-control">
<div className="kadence-responsive-control-bar">
<span className="customize-control-title">{ controlLabel }</span>
</div>
<SelectControl
value={ this.state.value }
options={ selectOptions }
onChange={ ( val ) => {
this.updateValues( val );
} }
/>
{ this.props.control.renderNotice() }
</div>
);
}
updateValues( value ) {
this.setState( { value: value } );
this.props.control.setting.set( value );
}
}
SelectComponent.propTypes = {
control: PropTypes.object.isRequired
};
export default SelectComponent;

View File

@@ -0,0 +1,11 @@
import { createRoot } from '@wordpress/element';
import SocialComponent from './social-component.js';
export const SocialControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <SocialComponent control={ control } /> );
// ReactDOM.render( <SocialComponent control={ control } />, control.container[0] );
}
} );

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,234 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import SocialIcons from './icons.js';
import DOMPurify from 'dompurify';
import { __ } from '@wordpress/i18n';
const { MediaUpload } = wp.blockEditor;
const { ButtonGroup, Dashicon, Tooltip, TextControl, Button, TabPanel, RangeControl, Placeholder } = wp.components;
const { Component, Fragment } = wp.element;
class ItemComponent extends Component {
constructor() {
super( ...arguments );
this.state = {
open: false,
};
}
render() {
const tabOptions = ( ( 'custom1' === this.props.item.id || 'custom2' === this.props.item.id || 'custom3' === this.props.item.id ) ? [
{
name: 'svg',
title: __( 'SVG', 'kadence' ),
},
{
name: 'image',
title: __( 'Image', 'kadence' ),
},
] : [
{
name: 'icon',
title: __( 'Icon', 'kadence' ),
},
{
name: 'svg',
title: __( 'SVG', 'kadence' ),
},
{
name: 'image',
title: __( 'Image', 'kadence' ),
},
] );
const defaultTab = ( ( 'custom1' === this.props.item.id || 'custom2' === this.props.item.id || 'custom3' === this.props.item.id ) ? 'svg' : 'icon' );
return (
<div className="kadence-sorter-item" data-id={ this.props.item.id } key={ this.props.item.id }>
<div className="kadence-sorter-item-panel-header">
<Tooltip text={ __( 'Toggle Item Visibility', 'kadence' ) }>
<Button
className={ `kadence-sorter-visiblity ${ ( this.props.item.enabled ? 'item-is-visible' : 'item-is-hidden' ) }`}
onClick={ () => {
this.props.toggleEnabled( ( this.props.item.enabled ? false : true ), this.props.index );
} }
>
{ SocialIcons[this.props.item.id] }
</Button>
</Tooltip>
<span className="kadence-sorter-title">
{ ( undefined !== this.props.item.label && '' !== this.props.item.label ? this.props.item.label : __( 'Social Item', 'kadence' ) ) }
</span>
<Tooltip text={ __( 'Expand Item Controls', 'kadence' ) }>
<Button
className="kadence-sorter-item-expand"
onClick={ () => {
this.setState( { open: ( this.state.open ? false : true ) } )
} }
>
<Dashicon icon={ ( this.state.open ? 'arrow-up-alt2' : 'arrow-down-alt2' ) }/>
</Button>
</Tooltip>
</div>
{ this.state.open && (
<div className="kadence-sorter-item-panel-content">
<TabPanel className="sortable-style-tabs kadence-social-type"
activeClass="active-tab"
initialTabName={ ( undefined !== this.props.item.source && '' !== this.props.item.source ? this.props.item.source : defaultTab ) }
onSelect={ ( value ) => this.props.onChangeSource( value, this.props.index ) }
tabs={ tabOptions }>
{
( tab ) => {
let tabout;
if ( tab.name ) {
if ( 'image' === tab.name ) {
tabout = (
<Fragment>
{ ! this.props.item.url && (
<div className="attachment-media-view">
<MediaUpload
onSelect={ ( imageData ) => {
this.props.onChangeURL( imageData.url, this.props.index );
this.props.onChangeAttachment( imageData.id, this.props.index );
} }
allowedTypes={ ['image'] }
render={ ( { open } ) => (
<Button className="button-add-media" isSecondary onClick={ open }>
{ __( 'Add Image', 'kadence' )}
</Button>
) }
/>
</div>
) }
{ this.props.item.url && (
<div className="social-custom-image">
<div className="kadence-social-image">
<img className="kadence-social-image-preview" src={ this.props.item.url } />
</div>
<Button
className='remove-image'
isDestructive
onClick={ () => {
this.props.onChangeURL( '', this.props.index );
this.props.onChangeAttachment( '', this.props.index );
} }
>
{ __( 'Remove Image', 'kadence' ) }
<Dashicon icon='no'/>
</Button>
</div>
) }
<RangeControl
label={ __( 'Max Width (px)', 'kadence' ) }
value={ ( undefined !== this.props.item.width ? this.props.item.width : 24 ) }
onChange={ ( value ) => {
this.props.onChangeWidth( value, this.props.index );
} }
step={ 1 }
min={ 2 }
max={ 100 }
/>
</Fragment>
);
} else if ( 'svg' === tab.name ) {
tabout = (
<Fragment>
<TextControl
label={ __( 'SVG HTML', 'kadence' ) }
value={ this.props.item.svg ? this.props.item.svg : '' }
onChange={ ( value ) => {
const newvalue = DOMPurify.sanitize( value, { USE_PROFILES: { svg: true, svgFilters: true } } );
this.props.onChangeSVG( newvalue, this.props.index );
} }
/>
<RangeControl
label={ __( 'Max Width (px)', 'kadence' ) }
value={ ( undefined !== this.props.item.width ? this.props.item.width : 24 ) }
onChange={ ( value ) => {
this.props.onChangeWidth( value, this.props.index );
} }
step={ 1 }
min={ 2 }
max={ 100 }
/>
</Fragment>
);
} else {
tabout = (
<Fragment>
<ButtonGroup className="kadence-radio-container-control">
<Button
isTertiary
className={ ( this.props.item.id === ( undefined !== this.props.item.icon ? this.props.item.icon : this.props.item.id ) ?
'active-radio ' :
'' ) + 'svg-icon-' + this.props.item.id }
onClick={ () => {
this.props.onChangeIcon( this.props.item.id, this.props.index );
} }
>
<span className="kadence-radio-icon">
{ SocialIcons[this.props.item.id] }
</span>
</Button>
{ SocialIcons[ this.props.item.id + 'Alt' ] && (
<Button
isTertiary
className={ ( this.props.item.id + 'Alt' === ( undefined !== this.props.item.icon ? this.props.item.icon : this.props.item.id ) ?
'active-radio ' :
'' ) + 'svg-icon-' + this.props.item.id + 'Alt' }
onClick={ () => {
this.props.onChangeIcon( this.props.item.id + 'Alt', this.props.index );
} }
>
<span className="kadence-radio-icon">
{ SocialIcons[ this.props.item.id + 'Alt' ] }
</span>
</Button>
) }
{ SocialIcons[ this.props.item.id + 'Alt2' ] && (
<Button
isTertiary
className={ ( this.props.item.id + 'Alt2' === ( undefined !== this.props.item.icon ? this.props.item.icon : this.props.item.id ) ?
'active-radio ' :
'' ) + 'svg-icon-' + this.props.item.id + 'Alt2' }
onClick={ () => {
this.props.onChangeIcon( this.props.item.id + 'Alt2', this.props.index );
} }
>
<span className="kadence-radio-icon">
{ SocialIcons[ this.props.item.id + 'Alt2' ] }
</span>
</Button>
)}
</ButtonGroup>
</Fragment>
);
}
}
return <div>{ tabout }</div>;
}
}
</TabPanel>
<TextControl
label={ __( 'Item Label', 'kadence' ) }
value={ this.props.item.label ? this.props.item.label : '' }
onChange={ ( value ) => {
this.props.onChangeLabel( value, this.props.index );
} }
/>
<Button
className="kadence-sorter-item-remove"
isDestructive
onClick={ () => {
this.props.removeItem( this.props.index );
} }
>
{ __( 'Remove Item', 'kadence' ) }
<Dashicon icon="no-alt"/>
</Button>
</div>
) }
</div>
);
}
}
export default ItemComponent;

View File

@@ -0,0 +1,386 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import ResponsiveControl from '../common/responsive.js';
import Icons from '../common/icons.js';
import { ReactSortable } from "react-sortablejs";
import uniqueId from 'lodash/uniqueId';
import ItemComponent from './item-component';
import { __ } from '@wordpress/i18n';
const { ButtonGroup, Dashicon, Tooltip, Popover, Button, SelectControl } = wp.components;
const { Component, Fragment } = wp.element;
class SocialComponent extends Component {
constructor() {
super( ...arguments );
this.updateValues = this.updateValues.bind( this );
this.onDragEnd = this.onDragEnd.bind( this );
this.onDragStart = this.onDragStart.bind( this );
this.onDragStop = this.onDragStop.bind( this );
this.removeItem = this.removeItem.bind( this );
this.saveArrayUpdate = this.saveArrayUpdate.bind( this );
this.toggleEnableItem = this.toggleEnableItem.bind( this );
this.onChangeIcon = this.onChangeIcon.bind( this );
this.onChangeLabel = this.onChangeLabel.bind( this );
this.onChangeURL = this.onChangeURL.bind( this );
this.onChangeAttachment = this.onChangeAttachment.bind( this );
this.onChangeWidth = this.onChangeWidth.bind( this );
this.onChangeSVG = this.onChangeSVG.bind( this );
this.onChangeSource = this.onChangeSource.bind( this );
this.addItem = this.addItem.bind( this );
let value = this.props.control.setting.get();
let baseDefault = {
'items': [
{
'id': 'facebook',
'enabled': true,
'source': 'icon',
'url': '',
'imageid': '',
'width': 24,
'icon': 'facebook',
'label': 'Facebook',
'svg': '',
},
{
'id': 'twitter',
'enabled': true,
'source': 'icon',
'url': '',
'imageid': '',
'width': 24,
'icon': 'twitterAlt2',
'label': 'X',
'svg': '',
}
],
};
this.defaultValue = this.props.control.params.default ? {
...baseDefault,
...this.props.control.params.default
} : baseDefault;
value = value ? {
...this.defaultValue,
...value
} : this.defaultValue;
let defaultParams = {
'group' : 'social_item_group',
'options': [
{ value: '500px', label: __( '500PX', 'kadence' ) },
{ value: 'amazon', label: __( 'Amazon', 'kadence' ) },
{ value: 'anchor', label: __( 'Anchor', 'kadence' ) },
{ value: 'apple_podcasts', label: __( 'Apple Podcast', 'kadence' ) },
{ value: 'bandcamp', label: __( 'Bandcamp', 'kadence' ) },
{ value: 'behance', label: __( 'Behance', 'kadence' ) },
{ value: 'bluesky', label: __( 'Bluesky', 'kadence' ) },
{ value: 'bookbub', label: __( 'Bookbub', 'kadence' ) },
{ value: 'discord', label: __( 'Discord', 'kadence' ) },
{ value: 'dribbble', label: __( 'Dribbble', 'kadence' ) },
{ value: 'email', label: __( 'Email', 'kadence' ) },
{ value: 'facebook', label: __( 'Facebook', 'kadence' ) },
{ value: 'facebook_group', label: __( 'Facebook Group', 'kadence' ) },
{ value: 'flickr', label: __( 'Flickr', 'kadence' ) },
{ value: 'flipboard', label: __( 'Flipboard', 'kadence' ) },
{ value: 'fstoppers', label: __( 'Fstoppers', 'kadence' ) },
{ value: 'github', label: __( 'GitHub', 'kadence' ) },
{ value: 'goodreads', label: __( 'Goodreads', 'kadence' ) },
{ value: 'google_reviews', label: __( 'Google Reviews', 'kadence' ) },
{ value: 'imgur', label: __( 'Imgur', 'kadence' ) },
{ value: 'imdb', label: __( 'IMDB', 'kadence' ) },
{ value: 'instagram', label: __( 'Instagram', 'kadence' ) },
{ value: 'line', label: __( 'Line', 'kadence' ) },
{ value: 'linkedin', label: __( 'Linkedin', 'kadence' ) },
{ value: 'mastodon', label: __( 'Mastodon', 'kadence' ) },
{ value: 'medium', label: __( 'Medium', 'kadence' ) },
{ value: 'mewe', label: __( 'MeWe', 'kadence' ) },
{ value: 'parler', label: __( 'Parler', 'kadence' ) },
{ value: 'patreon', label: __( 'Patreon', 'kadence' ) },
{ value: 'phone', label: __( 'Phone', 'kadence' ) },
{ value: 'pinterest', label: __( 'Pinterest', 'kadence' ) },
{ value: 'quora', label: __( 'Quora', 'kadence' ) },
{ value: 'ravelry', label: __( 'Ravelry', 'kadence' ) },
{ value: 'reddit', label: __( 'Reddit', 'kadence' ) },
{ value: 'rumble', label: __( 'Rumble', 'kadence' ) },
{ value: 'rss', label: __( 'RSS', 'kadence' ) },
{ value: 'snapchat', label: __( 'Snapchat', 'kadence' ) },
{ value: 'soundcloud', label: __( 'SoundCloud', 'kadence' ) },
{ value: 'spotify', label: __( 'Spotify', 'kadence' ) },
{ value: 'steam', label: __( 'Steam', 'kadence' ) },
{ value: 'strava', label: __( 'Strava', 'kadence' ) },
{ value: 'telegram', label: __( 'Telegram', 'kadence' ) },
{ value: 'threads', label: __( 'Threads', 'kadence' ) },
{ value: 'tiktok', label: __( 'TikTok', 'kadence' ) },
{ value: 'trip_advisor', label: __( 'Trip Advisor', 'kadence' ) },
{ value: 'tumblr', label: __( 'Tumblr', 'kadence' ) },
{ value: 'twitch', label: __( 'Twitch', 'kadence' ) },
{ value: 'twitter', label: __( 'X formerly Twitter', 'kadence' ) },
{ value: 'vero', label: __( 'Vero', 'kadence' ) },
{ value: 'vimeo', label: __( 'Vimeo', 'kadence' ) },
{ value: 'vk', label: __( 'VK', 'kadence' ) },
{ value: 'whatsapp', label: __( 'WhatsApp', 'kadence' ) },
{ value: 'wordpress', label: __( 'WordPress', 'kadence' ) },
{ value: 'xing', label: __( 'Xing', 'kadence' ) },
{ value: 'yelp', label: __( 'Yelp', 'kadence' ) },
{ value: 'youtube', label: __( 'YouTube', 'kadence' ) },
{ value: 'custom1', label: __( 'Custom 1', 'kadence' ) },
{ value: 'custom2', label: __( 'Custom 2', 'kadence' ) },
{ value: 'custom3', label: __( 'Custom 3', 'kadence' ) },
],
};
this.controlParams = this.props.control.params.input_attrs ? {
...defaultParams,
...this.props.control.params.input_attrs,
} : defaultParams;
let availableSocialOptions = [];
this.controlParams.options.map( ( option ) => {
if ( ! value.items.some( obj => obj.id === option.value ) ) {
availableSocialOptions.push( option );
}
} );
this.state = {
value: value,
isVisible: false,
control: ( undefined !== availableSocialOptions[0] && undefined !== availableSocialOptions[0].value ? availableSocialOptions[0].value : '' ),
};
}
onDragStart() {
var dropzones = document.querySelectorAll( '.kadence-builder-area' );
var i;
for (i = 0; i < dropzones.length; ++i) {
dropzones[i].classList.add( 'kadence-dragging-dropzones' );
}
}
onDragStop() {
var dropzones = document.querySelectorAll( '.kadence-builder-area' );
var i;
for (i = 0; i < dropzones.length; ++i) {
dropzones[i].classList.remove( 'kadence-dragging-dropzones' );
}
}
saveArrayUpdate( value, index ) {
let updateState = this.state.value;
let items = updateState.items;
const newItems = items.map( ( item, thisIndex ) => {
if ( index === thisIndex ) {
item = { ...item, ...value };
}
return item;
} );
updateState.items = newItems;
this.setState( { value: updateState } );
this.updateValues( updateState );
}
toggleEnableItem( value, itemIndex ) {
this.saveArrayUpdate( { enabled: value }, itemIndex );
}
onChangeLabel( value, itemIndex ) {
this.saveArrayUpdate( { label: value }, itemIndex );
}
onChangeIcon( value, itemIndex ) {
this.saveArrayUpdate( { icon: value }, itemIndex );
}
onChangeURL( value, itemIndex ) {
this.saveArrayUpdate( { url: value }, itemIndex );
}
onChangeAttachment( value, itemIndex ) {
this.saveArrayUpdate( { imageid: value }, itemIndex );
}
onChangeWidth( value, itemIndex ) {
this.saveArrayUpdate( { width: value }, itemIndex );
}
onChangeSVG( value, itemIndex ) {
this.saveArrayUpdate( { svg: value }, itemIndex );
}
onChangeSource( value, itemIndex ) {
this.saveArrayUpdate( { source: value }, itemIndex );
}
removeItem( itemIndex ) {
let updateState = this.state.value;
let update = updateState.items;
let updateItems = [];
{ update.length > 0 && (
update.map( ( old, index ) => {
if ( itemIndex !== index ) {
updateItems.push( old );
}
} )
) };
updateState.items = updateItems;
this.setState( { value: updateState } );
this.updateValues( updateState );
}
addItem() {
const itemControl = this.state.control;
this.setState( { isVisible: false } );
if ( itemControl ) {
let updateState = this.state.value;
let update = updateState.items;
const itemLabel = this.controlParams.options.filter(function(o){return o.value === itemControl;} );
let newItem = {
'id': itemControl,
'enabled': true,
'source': 'icon',
'url': '',
'imageid': '',
'width': 24,
'icon': itemControl,
'label': itemLabel[0].label,
'svg': '',
};
update.push( newItem );
updateState.items = update;
let availableSocialOptions = [];
this.controlParams.options.map( ( option ) => {
if ( ! update.some( obj => obj.id === option.value ) ) {
availableSocialOptions.push( option );
}
} );
this.setState( { control: ( undefined !== availableSocialOptions[0] && undefined !== availableSocialOptions[0].value ? availableSocialOptions[0].value : '' ) } );
this.setState( { value: updateState } );
this.updateValues( updateState );
}
}
onDragEnd( items ) {
let updateState = this.state.value;
let update = updateState.items;
let updateItems = [];
{ items.length > 0 && (
items.map( ( item ) => {
update.filter( obj => {
if ( obj.id === item.id ) {
updateItems.push( obj );
}
} )
} )
) };
if ( ! this.arraysEqual( update, updateItems ) ) {
update.items = updateItems;
updateState.items = updateItems;
this.setState( { value: updateState } );
this.updateValues( updateState );
}
}
arraysEqual( a, b ) {
if (a === b) return true;
if (a == null || b == null) return false;
if (a.length != b.length) return false;
for (var i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) return false;
}
return true;
}
render() {
const currentList = ( typeof this.state.value != "undefined" && this.state.value.items != null && this.state.value.items.length != null && this.state.value.items.length > 0 ? this.state.value.items : [] );
let theItems = [];
{ currentList.length > 0 && (
currentList.map( ( item ) => {
theItems.push(
{
id: item.id,
}
)
} )
) };
const availableSocialOptions = [];
this.controlParams.options.map( ( option ) => {
if ( ! theItems.some( obj => obj.id === option.value ) ) {
availableSocialOptions.push( option );
}
} );
const toggleClose = () => {
if ( this.state.isVisible === true ) {
this.setState( { isVisible: false } );
}
};
return (
<div className="kadence-control-field kadence-sorter-items">
<div className="kadence-sorter-row">
<ReactSortable animation={100} onStart={ () => this.onDragStop() } onEnd={ () => this.onDragStop() } group={ this.controlParams.group } className={ `kadence-sorter-drop kadence-sorter-sortable-panel kadence-sorter-drop-${ this.controlParams.group }` } handle={ '.kadence-sorter-item-panel-header' } list={ theItems } setList={ ( newState ) => this.onDragEnd( newState ) } >
{ currentList.length > 0 && (
currentList.map( ( item, index ) => {
return <ItemComponent removeItem={ ( remove ) => this.removeItem( remove ) } toggleEnabled={ ( enable, itemIndex ) => this.toggleEnableItem( enable, itemIndex ) } onChangeLabel={ ( label, itemIndex ) => this.onChangeLabel( label, itemIndex ) } onChangeSource={ ( source, itemIndex ) => this.onChangeSource( source, itemIndex ) } onChangeWidth={ ( width, itemIndex ) => this.onChangeWidth( width, itemIndex ) } onChangeSVG={ ( svg, itemIndex ) => this.onChangeSVG( svg, itemIndex ) } onChangeURL={ ( url, itemIndex ) => this.onChangeURL( url, itemIndex ) } onChangeAttachment={ ( imageid, itemIndex ) => this.onChangeAttachment( imageid, itemIndex ) } onChangeIcon={ ( icon, itemIndex ) => this.onChangeIcon( icon, itemIndex ) } key={ item.id } index={ index } item={ item } controlParams={ this.controlParams } />;
} )
) }
</ReactSortable>
</div>
{ undefined !== availableSocialOptions[0] && undefined !== availableSocialOptions[0].value && (
<div className="kadence-social-add-area">
{/* <SelectControl
value={ this.state.control }
options={ availableSocialOptions }
onChange={ value => {
this.setState( { control: value } );
} }
/> */}
{ this.state.isVisible && (
<Popover position="top right" inline={true} className="kadence-popover-color kadence-popover-social kadence-customizer-popover" onClose={ toggleClose }>
<div className="kadence-popover-social-list">
<ButtonGroup className="kadence-radio-container-control">
{ availableSocialOptions.map( ( item, index ) => {
return (
<Fragment>
<Button
isTertiary
className={ 'social-radio-btn' }
onClick={ () => {
this.setState( { control: availableSocialOptions[index].value } );
this.state.control = availableSocialOptions[index].value;
this.addItem();
} }
>
{ availableSocialOptions[index].label && (
availableSocialOptions[index].label
) }
</Button>
</Fragment>
);
} ) }
</ButtonGroup>
</div>
</Popover>
) }
<Button
className="kadence-sorter-add-item"
isPrimary
onClick={ () => {
this.setState( { isVisible: true } );
} }
>
{ __( 'Add Social', 'kadence' ) }
<Dashicon icon="plus"/>
</Button>
{/* <Button
className="kadence-sorter-add-item"
isPrimary
onClick={ () => {
this.addItem();
} }
>
{ __( 'Add Item', 'kadence' ) }
<Dashicon icon="plus"/>
</Button> */}
</div>
) }
{ this.props.control.renderNotice() }
</div>
);
}
updateValues( value ) {
this.props.control.setting.set( {
...this.props.control.setting.get(),
...value,
flag: !this.props.control.setting.get().flag
} );
}
}
SocialComponent.propTypes = {
control: PropTypes.object.isRequired,
};
export default SocialComponent;

View File

@@ -0,0 +1,11 @@
import { createRoot } from '@wordpress/element';
import SorterComponent from './setting-sorter-component.js';
export const SorterControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <SorterComponent control={ control } customizer={ wp.customize } /> );
// ReactDOM.render( <SorterComponent control={ control } customizer={ wp.customize } />, control.container[0] );
}
} );

View File

@@ -0,0 +1,264 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import capitalizeFirstLetter from '../common/capitalize-first.js';
import { __ } from '@wordpress/i18n';
import Icons from '../common/icons.js';
const { MediaUpload } = wp.blockEditor;
const { ButtonGroup, Dashicon, Tooltip, TextControl, Button, TabPanel, ToggleControl, RangeControl, Placeholder } = wp.components;
const { Component, Fragment } = wp.element;
class ItemComponent extends Component {
constructor() {
super( ...arguments );
this.state = {
open: false,
};
}
render() {
return (
<div className="kadence-sorter-item" data-id={ this.props.item.id } key={ this.props.item.id }>
<div className={ `kadence-sorter-item-panel-header ${ ( this.props.item.enabled ? 'panel-item-is-visible' : 'panel-item-is-hidden' ) }` }>
<Tooltip text={ __( 'Toggle Item Visibility', 'kadence' ) }>
<Button
className={ `kadence-sorter-visiblity ${ ( this.props.item.enabled ? 'item-is-visible' : 'item-is-hidden' ) }`}
onClick={ () => {
this.props.onItemChange( { enabled: ( this.props.item.enabled ? false : true ) }, this.props.index );
} }
>
<Dashicon icon={ ( this.props.item.enabled ? 'visibility' : 'hidden' ) } />
</Button>
</Tooltip>
<span className="kadence-sorter-title">
{ capitalizeFirstLetter( this.props.item.id ) }
</span>
{ 'title' !== this.props.item.id && (
<Tooltip text={ __( 'Expand Item Controls', 'kadence' ) }>
<Button
className="kadence-sorter-item-expand"
onClick={ () => {
this.setState( { open: ( this.state.open ? false : true ) } )
} }
>
<Dashicon icon={ ( this.state.open ? 'arrow-up-alt2' : 'arrow-down-alt2' ) }/>
</Button>
</Tooltip>
) }
</div>
{ this.state.open && (
<div className="kadence-sorter-item-panel-content">
{ undefined !== this.props.item.divider && (
<div class="components-base-control">
<span className="sorter-control-title">{ __( 'Choose a Divider', 'kadence' ) }</span>
<ButtonGroup className="kadence-radio-container-control">
{ Object.keys( this.props.controlParams.dividers ).map( ( item ) => {
return (
<Fragment>
<Button
isTertiary
className={ ( item === this.props.item.divider ?
'active-radio ' :
'' ) + 'radio-btn-' + item }
onClick={ () => {
this.props.onItemChange( { divider: item }, this.props.index );
} }
>
{ this.props.controlParams.dividers[ item ].icon && (
<span className="kadence-radio-icon">
{ Icons[ this.props.controlParams.dividers[ item ].icon ] }
</span>
) }
{ this.props.controlParams.dividers[ item ].name && (
this.props.controlParams.dividers[ item ].name
) }
</Button>
</Fragment>
);
} ) }
</ButtonGroup>
</div>
) }
{ undefined !== this.props.item.author && (
<div className="sorter-sub-option">
<ToggleControl
label={ __( 'Show Author?', 'kadence' ) }
checked={ this.props.item.author ? this.props.item.author : this.props.item.author }
onChange={ ( value ) => {
this.props.onItemChange( { author: value }, this.props.index );
} }
/>
{ this.props.item.author && (
<Fragment>
{ undefined !== this.props.item.authorImage && (
<ToggleControl
label={ __( 'Show Author Image?', 'kadence' ) }
checked={ this.props.item.authorImage ? this.props.item.authorImage : this.props.item.authorImage }
onChange={ ( value ) => {
this.props.onItemChange( { authorImage: value }, this.props.index );
} }
/>
) }
{ undefined !== this.props.item.authorLabel && (
<div className="meta-label-control">
<span className="sorter-control-title">{ __( 'Author Label', 'kadence' ) }</span>
<div className={ `meta-label-input-control ${ ( this.props.item.authorEnableLabel ? 'label-is-visible' : 'label-is-hidden' ) }` }>
<Tooltip text={ __( 'Toggle Label Visibility', 'kadence' ) }>
<Button
className={ `kadence-label-visiblity ${ ( this.props.item.authorEnableLabel ? 'item-is-visible' : 'item-is-hidden' ) }`}
onClick={ () => {
this.props.onItemChange( { authorEnableLabel: ( this.props.item.authorEnableLabel ? false : true ) }, this.props.index );
} }
>
<Dashicon icon={ ( this.props.item.authorEnableLabel ? 'visibility' : 'hidden' ) } />
</Button>
</Tooltip>
<TextControl
label=""
placeholder={ __( 'By', 'kadence' ) }
value={ this.props.item.authorLabel ? this.props.item.authorLabel : this.props.item.authorLabel }
onChange={ ( value ) => {
this.props.onItemChange( { authorLabel: value }, this.props.index );
} }
/>
</div>
</div>
) }
</Fragment>
) }
</div>
) }
{ undefined !== this.props.item.date && (
<div className="sorter-sub-option">
<ToggleControl
label={ __( 'Show Date?', 'kadence' ) }
checked={ this.props.item.date ? this.props.item.date : this.props.item.date }
onChange={ ( value ) => {
this.props.onItemChange( { date: value }, this.props.index );
} }
/>
{ this.props.item.date && (
<ToggleControl
label={ __( 'Show Time?', 'kadence' ) }
checked={ this.props.item.dateTime ? this.props.item.dateTime : false }
onChange={ ( value ) => {
this.props.onItemChange( { dateTime: value }, this.props.index );
} }
/>
) }
{ undefined !== this.props.item.dateLabel && this.props.item.date && (
<div className="meta-label-control">
<span className="sorter-control-title">{ __( 'Date Label', 'kadence' ) }</span>
<div className={ `meta-label-input-control ${ ( this.props.item.dateEnableLabel ? 'label-is-visible' : 'label-is-hidden' ) }` }>
<Tooltip text={ __( 'Toggle Label Visibility', 'kadence' ) }>
<Button
className={ `kadence-label-visiblity ${ ( this.props.item.dateEnableLabel ? 'item-is-visible' : 'item-is-hidden' ) }`}
onClick={ () => {
this.props.onItemChange( { dateEnableLabel: ( this.props.item.dateEnableLabel ? false : true ) }, this.props.index );
} }
>
<Dashicon icon={ ( this.props.item.dateEnableLabel ? 'visibility' : 'hidden' ) } />
</Button>
</Tooltip>
<TextControl
label=""
placeholder={ __( 'Posted on', 'kadence' ) }
value={ this.props.item.dateLabel ? this.props.item.dateLabel : this.props.item.dateLabel }
onChange={ ( value ) => {
this.props.onItemChange( { dateLabel: value }, this.props.index );
} }
/>
</div>
</div>
) }
</div>
) }
{ undefined !== this.props.item.dateUpdated && (
<div className="sorter-sub-option">
<ToggleControl
label={ __( 'Show Last Updated Date?', 'kadence' ) }
checked={ this.props.item.dateUpdated ? this.props.item.dateUpdated : this.props.item.dateUpdated }
onChange={ ( value ) => {
this.props.onItemChange( { dateUpdated: value }, this.props.index );
} }
/>
{ undefined !== this.props.item.dateUpdatedLabel && this.props.item.dateUpdated && (
<div className="meta-label-control">
<span className="sorter-control-title">{ __( 'Updated Date Label', 'kadence' ) }</span>
<div className={ `meta-label-input-control ${ ( this.props.item.dateUpdatedEnableLabel ? 'label-is-visible' : 'label-is-hidden' ) }` }>
<Tooltip text={ __( 'Toggle Label Visibility', 'kadence' ) }>
<Button
className={ `kadence-label-visiblity ${ ( this.props.item.dateUpdatedEnableLabel ? 'item-is-visible' : 'item-is-hidden' ) }`}
onClick={ () => {
this.props.onItemChange( { dateUpdatedEnableLabel: ( this.props.item.dateUpdatedEnableLabel ? false : true ) }, this.props.index );
} }
>
<Dashicon icon={ ( this.props.item.dateUpdatedEnableLabel ? 'visibility' : 'hidden' ) } />
</Button>
</Tooltip>
<TextControl
label=""
placeholder={ __( 'Updated on', 'kadence' ) }
value={ this.props.item.dateUpdatedLabel ? this.props.item.dateUpdatedLabel : this.props.item.dateUpdatedLabel }
onChange={ ( value ) => {
this.props.onItemChange( { dateUpdatedLabel: value }, this.props.index );
} }
/>
</div>
</div>
) }
</div>
) }
{ undefined !== this.props.item.categories && (
<div className="sorter-sub-option">
<ToggleControl
label={ __( 'Show Categories?', 'kadence' ) }
checked={ this.props.item.categories ? this.props.item.categories : this.props.item.categories }
onChange={ ( value ) => {
this.props.onItemChange( { categories: value }, this.props.index );
} }
/>
{ undefined !== this.props.item.categoriesLabel && this.props.item.categories && this.props.item.metaLabel && (
<div className="meta-label-control">
<span className="sorter-control-title">{ __( 'Categories Label', 'kadence' ) }</span>
<div className={ `meta-label-input-control ${ ( this.props.item.categoriesEnableLabel ? 'label-is-visible' : 'label-is-hidden' ) }` }>
<Tooltip text={ __( 'Toggle Label Visibility', 'kadence' ) }>
<Button
className={ `kadence-label-visiblity ${ ( this.props.item.categoriesEnableLabel ? 'item-is-visible' : 'item-is-hidden' ) }`}
onClick={ () => {
this.props.onItemChange( { categoriesEnableLabel: ( this.props.item.categoriesEnableLabel ? false : true ) }, this.props.index );
} }
>
<Dashicon icon={ ( this.props.item.categoriesEnableLabel ? 'visibility' : 'hidden' ) } />
</Button>
</Tooltip>
<TextControl
label=""
placeholder={ __( 'Posted in', 'kadence' ) }
value={ this.props.item.categoriesLabel ? this.props.item.categoriesLabel : this.props.item.categoriesLabel }
onChange={ ( value ) => {
this.props.onItemChange( { categoriesLabel: value }, this.props.index );
} }
/>
</div>
</div>
) }
</div>
) }
{ undefined !== this.props.item.comments && (
<div className="sorter-sub-option">
<ToggleControl
label={ __( 'Show Comments?', 'kadence' ) }
checked={ this.props.item.comments ? this.props.item.comments : this.props.item.comments }
onChange={ ( value ) => {
this.props.onItemChange( { comments: value }, this.props.index );
} }
/>
</div>
) }
</div>
) }
</div>
);
}
}
export default ItemComponent;

View File

@@ -0,0 +1,224 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import ResponsiveControl from '../common/responsive.js';
import Icons from '../common/icons.js';
import { ReactSortable } from "react-sortablejs";
import isEqual from 'lodash/isEqual';
import union from 'lodash/union';
import ItemComponent from './setting-item-component';
import { __ } from '@wordpress/i18n';
const { ButtonGroup, Dashicon, Tooltip, Button } = wp.components;
const { Component, Fragment } = wp.element;
class SorterComponent extends Component {
constructor() {
super( ...arguments );
this.updateValues = this.updateValues.bind( this );
this.onDragEnd = this.onDragEnd.bind( this );
this.onDragStart = this.onDragStart.bind( this );
this.onDragStop = this.onDragStop.bind( this );
let value = this.props.control.settings['elements'].get();
let baseDefault = [ 'title', 'breadcrumb', 'meta' ];
this.defaultValue = this.props.control.params.default ? this.props.control.params.default : baseDefault;
value = value ? union(
value,
this.defaultValue
) : this.defaultValue;
let defaultParams = {
'group': 'title_item_group',
'sortable': true,
dividers: {
dot: {
icon: 'dot',
},
slash: {
icon: 'slash',
},
dash: {
icon: 'dash',
},
vline: {
icon: 'vline',
},
},
imageSizes: {
thumbnail: {
name: __( 'Thumbnail', 'kadence' ),
},
medium: {
name: __( 'Medium', 'kadence' ),
},
medium_large: {
name: __( 'Medium Large', 'kadence' ),
},
large: {
name: __( 'Large', 'kadence' ),
},
full: {
name: __( 'Full', 'kadence' ),
},
},
ratios: {
'inherit': {
'name': __( 'Inherit', 'kadence' ),
},
'1-1': {
'name': '1:1',
},
'3-4': {
'name': '4:3',
},
'2-3': {
'name': '3:2',
},
'9-16': {
'name': '16:9',
},
'1-2': {
'name': '2:1',
},
'5-4': {
'name': '4:5',
},
'4-3': {
'name': '3:4',
},
'3-2': {
'name': '2:3',
},
}
};
this.controlParams = this.props.control.params.input_attrs ? {
...defaultParams,
...this.props.control.params.input_attrs,
} : defaultParams;
this.state = {
value: value,
};
}
onDragStart() {
var dropzones = document.querySelectorAll( '.kadence-builder-area' );
var i;
for (i = 0; i < dropzones.length; ++i) {
dropzones[i].classList.add( 'kadence-dragging-dropzones' );
}
}
onDragStop() {
var dropzones = document.querySelectorAll( '.kadence-builder-area' );
var i;
for (i = 0; i < dropzones.length; ++i) {
dropzones[i].classList.remove( 'kadence-dragging-dropzones' );
}
}
onDragEnd( items ) {
let updateState = this.state.value;
let update = updateState;
let updateItems = [];
{ items.length > 0 && (
items.map( ( item ) => {
updateItems.push( item.id );
} )
) };
if ( JSON.stringify( update ) !== JSON.stringify( updateItems ) ) {
update = updateItems;
updateState = updateItems;
this.setState( { value: updateState } );
this.updateValues( updateState );
}
}
arraysEqual( a, b ) {
if (a === b) return true;
if (a == null || b == null) return false;
if (a.length != b.length) return false;
for (var i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) return false;
}
return true;
}
render() {
const controlLabel = (
<Fragment>
{/* <Tooltip text={ __( 'Reset Value', 'kadence' ) }>
<Button
className="reset kadence-reset"
disabled={ ( this.state.value === this.defaultValue ) }
onClick={ () => {
let value = this.defaultValue;
this.setState( { value: value } );
this.updateValues( value );
} }
>
<Dashicon icon='image-rotate' />
</Button>
</Tooltip> */}
{ this.props.control.params.label &&
this.props.control.params.label
}
</Fragment>
);
const currentList = ( typeof this.state.value != "undefined" && undefined !== this.state.value ? this.state.value : [] );
let theItems = [];
{ currentList.map( ( item ) => {
theItems.push(
{
id: item,
}
)
} ) }
return (
<div className="kadence-control-field kadence-sorter-items kadence-post-title-sorter">
<div className="kadence-responsive-control-bar">
<span className="customize-control-title">{ controlLabel }</span>
</div>
<div className="kadence-sorter-row">
{ this.controlParams.sortable && (
<ReactSortable animation={100} onStart={ () => this.onDragStop() } onEnd={ () => this.onDragStop() } group={ this.controlParams.group } className={ `kadence-sorter-drop kadence-sorter-sortable-panel kadence-meta-sorter kadence-sorter-drop-${ this.controlParams.group }` } handle={ '.kadence-sorter-item-panel-header' } list={ theItems } setList={ ( newState ) => this.onDragEnd( newState ) } >
{ currentList.map( ( item, index ) => {
return <ItemComponent
key={ item }
item={ item }
setting={ this.controlParams.group }
index={ index }
control={ this.props.control }
moveable={ true }
controlParams={ this.controlParams }
customizer={ this.props.customizer }
/>;
} ) }
</ReactSortable>
) }
{ ! this.controlParams.sortable && (
<div className={ `kadence-sorter-drop kadence-sorter-sortable-panel kadence-sorter-no-sorting kadence-sorter-drop-${ this.controlParams.group }` } >
{ currentList.map( ( item, index ) => {
return <ItemComponent
key={ item }
item={ item }
setting={ this.controlParams.group }
index={ index }
moveable={ false }
control={ this.props.control }
controlParams={ this.controlParams }
customizer={ this.props.customizer }
/>;
} ) }
</div>
) }
</div>
</div>
);
}
updateValues( value ) {
this.props.control.settings['elements'].set( value );
}
}
SorterComponent.propTypes = {
control: PropTypes.object.isRequired,
customizer: PropTypes.object.isRequired
};
export default SorterComponent;

View File

@@ -0,0 +1,228 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import ResponsiveControl from '../common/responsive.js';
import Icons from '../common/icons.js';
import { ReactSortable } from "react-sortablejs";
import isEqual from 'lodash/isEqual';
import ItemComponent from './item-component';
import { __ } from '@wordpress/i18n';
const { ButtonGroup, Dashicon, Tooltip, Button } = wp.components;
const { Component, Fragment } = wp.element;
class SorterComponent extends Component {
constructor() {
super( ...arguments );
this.updateValues = this.updateValues.bind( this );
this.onDragEnd = this.onDragEnd.bind( this );
this.onDragStart = this.onDragStart.bind( this );
this.onDragStop = this.onDragStop.bind( this );
this.saveObjectUpdate = this.saveObjectUpdate.bind( this );
this.onItemChange = this.onItemChange.bind( this );;
let value = this.props.control.setting.get();
let baseDefault = {
'items': {
'title': {
'id': 'title',
'enabled': true,
},
'breadcrumb': {
'id': 'breadcrumb',
'enabled': true,
'divider': 'dot',
},
'meta': {
'id': 'meta',
'enabled': true,
'metaLabel': true,
'divider': 'dot',
'author': true,
'authorImage': true,
'authorLabel': '',
'date': true,
'dateTime': false,
'dateLabel': '',
'dateUpdated': true,
'dateUpdatedTime': false,
'dateUpdatedDifferent': false,
'dateUpdatedLabel': '',
'categories': true,
'categoriesLabel': '',
'comments': false,
'commentsLabel': '',
'commentsCondition': false,
},
'categories': {
'id': 'categories',
'enabled': true,
'divider': 'dot',
}
}
};
this.defaultValue = this.props.control.params.default ? {
...baseDefault,
...this.props.control.params.default
} : baseDefault;
value = value ? {
...JSON.parse( JSON.stringify( this.defaultValue ) ),
...value
} : JSON.parse( JSON.stringify( this.defaultValue ) );
let defaultParams = {
'group': 'title_item_group',
dividers: {
dot: {
icon: 'dot',
},
slash: {
name: '/',
icon: '',
},
dash: {
name: '-',
icon: '',
},
arrow: {
name: '>',
icon: '',
},
doubleArrow: {
name: '>>',
icon: '',
},
},
};
this.controlParams = this.props.control.params.input_attrs ? {
...defaultParams,
...this.props.control.params.input_attrs,
} : defaultParams;
this.state = {
value: value,
};
}
onDragStart() {
var dropzones = document.querySelectorAll( '.kadence-builder-area' );
var i;
for (i = 0; i < dropzones.length; ++i) {
dropzones[i].classList.add( 'kadence-dragging-dropzones' );
}
}
onDragStop() {
var dropzones = document.querySelectorAll( '.kadence-builder-area' );
var i;
for (i = 0; i < dropzones.length; ++i) {
dropzones[i].classList.remove( 'kadence-dragging-dropzones' );
}
}
saveObjectUpdate( value, index ) {
let updateState = this.state.value;
let items = updateState.items;
let newItems = updateState.items;
Object.keys( items ).map( ( item, thisIndex ) => {
if ( index === thisIndex ) {
newItems[item] = { ...items[item], ...value };
}
} );
updateState.items = newItems;
this.setState( { value: updateState } );
this.updateValues( updateState );
}
onItemChange( value, itemIndex ) {
this.saveObjectUpdate( value, itemIndex );
}
onDragEnd( items ) {
let updateState = this.state.value;
let update = updateState.items;
let updateItems = {};
{ items.length > 0 && (
items.map( ( item ) => {
if ( update[item.id].id === item.id ) {
updateItems[item.id] = update[item.id];
}
} )
) };
if ( JSON.stringify( update ) !== JSON.stringify( updateItems ) ) {
update.items = updateItems;
updateState.items = updateItems;
this.setState( { value: updateState } );
this.updateValues( updateState );
}
}
arraysEqual( a, b ) {
if (a === b) return true;
if (a == null || b == null) return false;
if (a.length != b.length) return false;
for (var i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) return false;
}
return true;
}
render() {
const controlLabel = (
<Fragment>
<Tooltip text={ __( 'Reset Value', 'kadence' ) }>
<Button
className="reset kadence-reset"
disabled={ ( this.state.value === this.defaultValue ) }
onClick={ () => {
let value = this.defaultValue;
this.setState( { value: value } );
this.updateValues( value );
} }
>
<Dashicon icon='image-rotate' />
</Button>
</Tooltip>
{ this.props.control.params.label &&
this.props.control.params.label
}
</Fragment>
);
const currentList = ( typeof this.state.value != "undefined" && undefined !== this.state.value.items ? this.state.value.items : {} );
let theItems = [];
{ Object.keys( currentList ).map( ( item ) => {
theItems.push(
{
id: item,
}
)
} ) }
return (
<div className="kadence-control-field kadence-sorter-items kadence-post-title-sorter">
<div className="kadence-responsive-control-bar">
<span className="customize-control-title">{ controlLabel }</span>
</div>
<div className="kadence-sorter-row">
<ReactSortable animation={100} onStart={ () => this.onDragStop() } onEnd={ () => this.onDragStop() } group={ this.controlParams.group } className={ `kadence-sorter-drop kadence-sorter-sortable-panel kadence-meta-sorter kadence-sorter-drop-${ this.controlParams.group }` } handle={ '.kadence-sorter-item-panel-header' } list={ theItems } setList={ ( newState ) => this.onDragEnd( newState ) } >
{ Object.keys( currentList ).map( ( item, index ) => {
return <ItemComponent
onItemChange={ ( value, itemIndex ) => this.onItemChange( value, itemIndex ) }
key={ item }
index={ index }
item={ currentList[item] }
controlParams={ this.controlParams }
/>;
} ) }
</ReactSortable>
</div>
{ this.props.control.renderNotice() }
</div>
);
}
updateValues( value ) {
this.props.control.setting.set( {
...this.props.control.setting.get(),
...value,
flag: !this.props.control.setting.get().flag
} );
}
}
SorterComponent.propTypes = {
control: PropTypes.object.isRequired,
customizer: PropTypes.object.isRequired
};
export default SorterComponent;

View File

@@ -0,0 +1,14 @@
import { createRoot } from '@wordpress/element';
import SwitchComponent from './switch-component.js';
export const SwitchControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <SwitchComponent control={control}/> );
// ReactDOM.render(
// <SwitchComponent control={control}/>,
// control.container[0]
// );
}
} );

View File

@@ -0,0 +1,45 @@
import PropTypes from 'prop-types';
import { __ } from '@wordpress/i18n';
const { Component } = wp.element;
const { ToggleControl } = wp.components;
class SwitchComponent extends Component {
constructor(props) {
super( props );
let value = props.control.setting.get();
this.state = {
value
};
this.defaultValue = props.control.params.default || '';
this.updateValues = this.updateValues.bind( this );
}
render() {
//console.log( this.props.control.params );
return (
<div className="kadence-control-field kadence-switch-control">
<ToggleControl
label={ this.props.control.params.label ? this.props.control.params.label : undefined }
checked={ this.state.value }
help={ this.props.control.params.input_attrs && this.props.control.params.input_attrs.help ? this.props.control.params.input_attrs.help : undefined }
onChange={ (value) => {
this.updateValues( value );
} }
/>
{ this.props.control.renderNotice() }
</div>
);
}
updateValues(value) {
this.setState( { value: value } );
this.props.control.setting.set( value );
}
}
SwitchComponent.propTypes = {
control: PropTypes.object.isRequired
};
export default SwitchComponent;

View File

@@ -0,0 +1,11 @@
import { createRoot } from '@wordpress/element';
import TabsComponent from './tabs-component';
export const TabsControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <TabsComponent control={ control } customizer={ wp.customize } /> );
// ReactDOM.render( <TabsComponent control={ control } customizer={ wp.customize } />, control.container[0] );
}
} );

View File

@@ -0,0 +1,78 @@
/* jshint esversion: 6 */
import PropTypes from 'prop-types';
import { __ } from '@wordpress/i18n';
const { ButtonGroup, Dashicon, Tooltip, Button } = wp.components;
const { Component, Fragment } = wp.element;
class TabsComponent extends Component {
constructor() {
super( ...arguments );
this.focusPanel = this.focusPanel.bind( this );
let defaultParams = {
'general': {
'label': 'General',
'target' : '',
},
'design': {
'label': 'Design',
'target' : 'design',
},
'active': 'general',
};
this.controlParams = this.props.control.params.input_attrs ? {
...defaultParams,
...this.props.control.params.input_attrs,
} : defaultParams;
}
focusPanel( section ) {
let self = this;
let otherSection;
let secton_id = ( 'woocommerce_product_catalog_design' === section || 'woocommerce_product_catalog' === section || 'woocommerce_store_notice' === section || 'woocommerce_store_notice_design' === section ? section : 'kadence_customizer_' + section )
if ( section === self.controlParams.design.target ) {
otherSection = ( 'woocommerce_product_catalog_design' === section || 'woocommerce_product_catalog' === section || 'woocommerce_store_notice' === section || 'woocommerce_store_notice_design' === section ? self.controlParams.general.target : 'kadence_customizer_' + self.controlParams.general.target );
} else {
otherSection = ( 'woocommerce_product_catalog_design' === section || 'woocommerce_product_catalog' === section || 'woocommerce_store_notice' === section || 'woocommerce_store_notice_design' === section ? self.controlParams.design.target : 'kadence_customizer_' + self.controlParams.design.target );
}
if ( undefined !== self.props.customizer.section( secton_id ) ) {
const container = self.props.customizer.section( secton_id ).contentContainer[0];
const otherContainer = self.props.customizer.section( otherSection ).contentContainer[0];
container.classList.add( 'kadence-prevent-transition' );
otherContainer.classList.add( 'kadence-prevent-transition' );
setTimeout( function(){
self.props.customizer.section( secton_id ).focus();
}, 10);
setTimeout( function(){
container.classList.remove( 'kadence-prevent-transition' );
container.classList.remove( 'busy' );
container.style.top = null;
otherContainer.classList.remove( 'kadence-prevent-transition' );
otherContainer.classList.remove( 'busy' );
}, 300);
}
}
render() {
return (
<div className="customize-control-kadence_blank_control">
<div className="customize-control-description">
<div class="kadence-nav-tabs kadence-compontent-tabs nav-tab-wrapper wp-clearfix">
<Button className={ `nav-tab kadence-general-tab kadence-compontent-tabs-button kadence-nav-tabs-button${ 'general' === this.controlParams.active ? ' nav-tab-active' : '' }` } onClick={ () => this.focusPanel( this.controlParams.general.target ) }>
<span>{ this.controlParams.general.label }</span>
</Button>
<Button className={ `nav-tab kadence-design-tab kadence-compontent-tabs-button kadence-nav-tabs-button${ 'design' === this.controlParams.active ? ' nav-tab-active' : '' }` } onClick={ () => this.focusPanel( this.controlParams.design.target ) }>
<span>{ this.controlParams.design.label }</span>
</Button>
</div>
</div>
{ this.props.control.renderNotice() }
</div>
);
}
}
TabsComponent.propTypes = {
control: PropTypes.object.isRequired,
customizer: PropTypes.object.isRequired
};
export default TabsComponent;

View File

@@ -0,0 +1,11 @@
import { createRoot } from '@wordpress/element';
import TextComponent from './text-component.js';
export const TextControl = wp.customize.KadenceControl.extend( {
renderContent: function renderContent() {
let control = this;
let root = createRoot( control.container[0] );
root.render( <TextComponent control={ control } /> );
// ReactDOM.render( <TextComponent control={ control } />, control.container[0] );
}
} );

Some files were not shown because too many files have changed in this diff Show More