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:
5425
wp-content/themes/kadence/inc/customizer/react/build/controls.css
Normal file
5425
wp-content/themes/kadence/inc/customizer/react/build/controls.css
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/**
|
||||
* The blank customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Available
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Available extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_available_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Refresh the parameters passed to the JavaScript via JSON.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Available' );
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/**
|
||||
* The Background customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Background
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Background extends WP_Customize_Media_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_background_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array(
|
||||
'attachments' => array(
|
||||
'desktop' => array(),
|
||||
'tablet' => array(),
|
||||
'mobile' => array(),
|
||||
),
|
||||
);
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $mime_type = 'image';
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$value = $this->value();
|
||||
if ( $value && is_array( $value ) ) {
|
||||
foreach ( array( 'desktop', 'tablet', 'mobile' ) as $device ) {
|
||||
if ( isset( $value[ $device ] ) && isset( $value[ $device ]['image'] ) && isset( $value[ $device ]['image']['url'] ) && ! empty( $value[ $device ]['image']['url'] ) ) {
|
||||
$attachment_id = attachment_url_to_postid( $value[ $device ]['image']['url'] );
|
||||
$this->input_attrs['attachments'][ $device ] = wp_prepare_attachment_for_js( $attachment_id );
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
$this->json['default'] = $this->default;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Background' );
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* The Border customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Border
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Border extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_border_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
$this->json['default'] = $this->default;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Border' );
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* The Borders customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Borders
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Borders extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_borders_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
$this->json['default'] = $this->default;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Borders' );
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* The blank customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Blank
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Builder extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_builder_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Refresh the parameters passed to the JavaScript via JSON.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['default'] = $this->default;
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Builder' );
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* The CheckBox Icon customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Check_Icon
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Check_Icon extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_check_icon_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['default'] = $this->default;
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Check_Icon' );
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* The Color customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Color_Link
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Color_Link extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_color_link_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['default'] = $this->default;
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Color_Link' );
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* The blank customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Blank
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Color_Palette extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_color_palette_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['default'] = $this->default;
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Color_Palette' );
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* The Color customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Color
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Color extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_color_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['default'] = $this->default;
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Color' );
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* The Social customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Contact
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Contact extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_contact_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
$this->json['default'] = $this->default;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Contact' );
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* The Editor customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Blank
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Editor extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_editor_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Refresh the parameters passed to the JavaScript via JSON.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['default'] = $this->default;
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Editor' );
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/**
|
||||
* The Focus Button customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Focus_Button
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Focus_Button extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_focus_button_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Focus_Button' );
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* The Measure customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Measure
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Measure extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_measure_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
$this->json['default'] = $this->default;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Measure' );
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* The Radio Icon customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Multi_Radio_Icon
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Multi_Radio_Icon extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_multi_radio_icon_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['default'] = $this->default;
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Multi_Radio_Icon' );
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* The Radio Icon customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Radio_Icon
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Radio_Icon extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_radio_icon_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['default'] = $this->default;
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Radio_Icon' );
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* The blank customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Blank
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Range extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_range_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
$this->json['default'] = $this->default;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Range' );
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* The Row customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Row
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Row extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_row_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
$this->json['default'] = $this->default;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Row' );
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* The Select customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Select
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Select extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_select_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
$this->json['default'] = $this->default;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Select' );
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* The Shadow customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Shadow
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Shadow extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_shadow_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
$this->json['default'] = $this->default;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Shadow' );
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* The Social customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Social
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Social extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_social_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
$this->json['default'] = $this->default;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Social' );
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* The Sorter customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Sorter
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Sorter extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_sorter_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
$this->json['default'] = $this->default;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Sorter' );
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* The Switch customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Switch
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Switch extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_switch_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['default'] = $this->default;
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Switch' );
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/**
|
||||
* The Tab customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Tab
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Tab extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_tab_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Tab' );
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/**
|
||||
* The Text customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Text
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Text extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_text_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['default'] = $this->default;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Text' );
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/**
|
||||
* The Text customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Text
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Textarea extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_textarea_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['default'] = $this->default;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Textarea' );
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/**
|
||||
* The Switch customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Switch
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Title extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_title_control';
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Title' );
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* The Typography customize control extends the WP_Customize_Control class.
|
||||
*
|
||||
* @package customizer-controls
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'WP_Customize_Control' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Kadence_Control_Typography
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
class Kadence_Control_Typography extends WP_Customize_Control {
|
||||
/**
|
||||
* Control type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'kadence_typography_control';
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $default = array();
|
||||
|
||||
/**
|
||||
* Additional arguments passed to JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $input_attrs = array();
|
||||
|
||||
/**
|
||||
* Send to JS.
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
$this->json['input_attrs'] = $this->input_attrs;
|
||||
$this->json['default'] = $this->default;
|
||||
}
|
||||
/**
|
||||
* Empty Render Function to prevent errors.
|
||||
*/
|
||||
public function render_content() {
|
||||
}
|
||||
}
|
||||
$wp_customize->register_control_type( 'Kadence_Control_Typography' );
|
||||
@@ -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;
|
||||
@@ -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] );
|
||||
}
|
||||
} );
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
@@ -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
|
||||
} );
|
||||
},
|
||||
} );
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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 }
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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>
|
||||
);
|
||||
} );
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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( ',' ) })`;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
.angleControl {
|
||||
padding-top: (if(variable-exists(grid-unit-20), $grid-unit-20, 20px) / 2);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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 );
|
||||
},
|
||||
|
||||
} );
|
||||
@@ -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;
|
||||
@@ -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]
|
||||
// );
|
||||
}
|
||||
} );
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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]
|
||||
// );
|
||||
}
|
||||
} );
|
||||
@@ -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;
|
||||
@@ -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]
|
||||
// );
|
||||
}
|
||||
} );
|
||||
@@ -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%;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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]
|
||||
// );
|
||||
}
|
||||
} );
|
||||
@@ -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;
|
||||
@@ -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]
|
||||
// );
|
||||
}
|
||||
} );
|
||||
@@ -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;
|
||||
@@ -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]
|
||||
// );
|
||||
}
|
||||
} );
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
1360
wp-content/themes/kadence/inc/customizer/react/src/common/icons.js
Normal file
1360
wp-content/themes/kadence/inc/customizer/react/src/common/icons.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||
),
|
||||
];
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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] );
|
||||
}
|
||||
} );
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
2196
wp-content/themes/kadence/inc/customizer/react/src/controls.scss
Normal file
2196
wp-content/themes/kadence/inc/customizer/react/src/controls.scss
Normal file
File diff suppressed because it is too large
Load Diff
433
wp-content/themes/kadence/inc/customizer/react/src/customizer.js
Normal file
433
wp-content/themes/kadence/inc/customizer/react/src/customizer.js
Normal 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 );
|
||||
@@ -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]
|
||||
// );
|
||||
}
|
||||
} );
|
||||
@@ -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;
|
||||
@@ -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] );
|
||||
}
|
||||
} );
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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 )
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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( ',' ) })`;
|
||||
}
|
||||
@@ -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
68
wp-content/themes/kadence/inc/customizer/react/src/index.js
Normal file
68
wp-content/themes/kadence/inc/customizer/react/src/index.js
Normal 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 );
|
||||
} );
|
||||
} );
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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] );
|
||||
}
|
||||
} );
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user