corvée(dépendances) ajoute Carbon Fields
This commit is contained in:
parent
135cc65eed
commit
62368587e5
459 changed files with 72750 additions and 26 deletions
315
web/vendor/htmlburger/carbon-fields/packages/blocks/components/block-edit/index.js
vendored
Normal file
315
web/vendor/htmlburger/carbon-fields/packages/blocks/components/block-edit/index.js
vendored
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import cx from 'classnames';
|
||||
import { Component, Fragment } from '@wordpress/element';
|
||||
import { ToolbarGroup, PanelBody } from '@wordpress/components';
|
||||
import {
|
||||
InnerBlocks,
|
||||
BlockControls,
|
||||
InspectorControls
|
||||
} from '@wordpress/editor';
|
||||
import { withSelect } from '@wordpress/data';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import {
|
||||
get,
|
||||
map,
|
||||
find
|
||||
} from 'lodash';
|
||||
|
||||
/**
|
||||
* Carbon Fields dependencies.
|
||||
*/
|
||||
import { getFieldType } from '@carbon-fields/core';
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
import Field from '../field';
|
||||
import ServerSideRender from '../server-side-render';
|
||||
|
||||
class BlockEdit extends Component {
|
||||
/**
|
||||
* Local state.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
state = {
|
||||
mode: this.props.container.settings.mode,
|
||||
currentTab: this.props.supportsTabs
|
||||
? Object.keys( this.props.container.settings.tabs )[ 0 ]
|
||||
: null
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the change of the field's value.
|
||||
*
|
||||
* @param {string} fieldId
|
||||
* @param {mixed} value
|
||||
* @return {void}
|
||||
*/
|
||||
handleFieldChange = ( fieldId, value ) => {
|
||||
const { attributes, setAttributes } = this.props;
|
||||
|
||||
const fieldName = fieldId.replace( /^.+__(.+)?$/, '$1' );
|
||||
|
||||
setAttributes( {
|
||||
data: {
|
||||
...attributes.data,
|
||||
[ fieldName ]: value
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles changing of the mode.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
handleModeChange = () => {
|
||||
this.setState( {
|
||||
mode: this.isInEditMode ? 'preview' : 'edit'
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles changing on the tabs.
|
||||
*
|
||||
* @param {string} tab
|
||||
* @return {void}
|
||||
*/
|
||||
handleTabChange = ( tab ) => {
|
||||
this.setState( {
|
||||
currentTab: tab
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the block is in edit mode.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
get isInEditMode() {
|
||||
return this.state.mode === 'edit';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the block is in edit mode.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
get isInPreviewMode() {
|
||||
return this.state.mode === 'preview';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a field.
|
||||
*
|
||||
* @param {Object} field
|
||||
* @param {number} index
|
||||
* @return {Object}
|
||||
*/
|
||||
renderField = ( field, index ) => {
|
||||
const {
|
||||
clientId,
|
||||
container,
|
||||
attributes
|
||||
} = this.props;
|
||||
|
||||
const FieldEdit = getFieldType( field.type, 'block' );
|
||||
|
||||
if ( ! FieldEdit ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const id = `cf-${ clientId }__${ field.base_name }`;
|
||||
const value = get( attributes.data, field.base_name, field.default_value );
|
||||
|
||||
return (
|
||||
<Field
|
||||
key={ index }
|
||||
id={ id }
|
||||
field={ field }
|
||||
>
|
||||
<FieldEdit
|
||||
id={ id }
|
||||
containerId={ container.id }
|
||||
blockId={ clientId }
|
||||
value={ value }
|
||||
field={ field }
|
||||
name={ field.base_name }
|
||||
onChange={ this.handleFieldChange }
|
||||
/>
|
||||
</Field>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the fields in tabs.
|
||||
*
|
||||
* @param {string[]} fieldNames
|
||||
* @return {Object[]}
|
||||
*/
|
||||
renderTabbedFields( fieldNames ) {
|
||||
const { fields } = this.props;
|
||||
|
||||
return map( fieldNames, ( fieldName, index ) => {
|
||||
const field = find( fields, [ 'name', fieldName ] );
|
||||
|
||||
return this.renderField( field, index );
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the fields that aren't in tabs.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
renderNonTabbedFields() {
|
||||
return (
|
||||
<div className="cf-block__fields">
|
||||
{ this.props.fields.map( this.renderField ) }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
const { currentTab } = this.state;
|
||||
|
||||
const {
|
||||
clientId,
|
||||
container,
|
||||
supportsTabs,
|
||||
supportsPreview,
|
||||
supportsInnerBlocks
|
||||
} = this.props;
|
||||
|
||||
const innerBlocks = ( ( supportsInnerBlocks && this.isInEditMode ) && (
|
||||
<div className="cf-block__inner-blocks">
|
||||
<InnerBlocks
|
||||
template={ container.settings.inner_blocks.template }
|
||||
templateLock={ container.settings.inner_blocks.template_lock }
|
||||
allowedBlocks={ container.settings.inner_blocks.allowed_blocks }
|
||||
/>
|
||||
</div>
|
||||
) );
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{ container.settings.inner_blocks.position === 'above' && innerBlocks }
|
||||
|
||||
{ supportsPreview && (
|
||||
<BlockControls>
|
||||
<ToolbarGroup label="Options" controls={ [ {
|
||||
icon: this.isInEditMode
|
||||
? 'visibility'
|
||||
: 'hidden',
|
||||
title: this.isInEditMode
|
||||
? __( 'Show preview', 'carbon-fields-ui' )
|
||||
: __( 'Hide preview', 'carbon-fields-ui' ),
|
||||
onClick: this.handleModeChange
|
||||
} ] } />
|
||||
</BlockControls>
|
||||
) }
|
||||
|
||||
{ ( this.isInEditMode && supportsTabs ) && (
|
||||
<div className="cf-block__tabs">
|
||||
<ul className="cf-block__tabs-list">
|
||||
{ map( container.settings.tabs, ( fieldNames, tabName ) => {
|
||||
const classes = cx(
|
||||
'cf-block__tabs-item',
|
||||
{
|
||||
'cf-block__tabs-item--current': tabName === currentTab
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<li
|
||||
key={ tabName }
|
||||
className={ classes }
|
||||
onClick={ () => this.handleTabChange( tabName ) }
|
||||
>
|
||||
{ tabName }
|
||||
</li>
|
||||
);
|
||||
} ) }
|
||||
</ul>
|
||||
</div>
|
||||
) }
|
||||
|
||||
{ this.isInEditMode && (
|
||||
supportsTabs
|
||||
? (
|
||||
map( container.settings.tabs, ( fieldNames, tabName ) => {
|
||||
return (
|
||||
<div className="cf-block__fields" key={ tabName } hidden={ tabName !== currentTab }>
|
||||
{ this.renderTabbedFields( fieldNames ) }
|
||||
</div>
|
||||
);
|
||||
} )
|
||||
)
|
||||
: (
|
||||
this.renderNonTabbedFields()
|
||||
)
|
||||
) }
|
||||
|
||||
{ this.isInPreviewMode && (
|
||||
<div className="cf-block__preview">
|
||||
<ServerSideRender clientId={ clientId } />
|
||||
</div>
|
||||
) }
|
||||
|
||||
{ container.settings.inner_blocks.position === 'below' && innerBlocks }
|
||||
|
||||
{ this.isInPreviewMode && (
|
||||
<InspectorControls>
|
||||
{
|
||||
supportsTabs
|
||||
? (
|
||||
map( container.settings.tabs, ( fieldNames, tabName ) => {
|
||||
return (
|
||||
<PanelBody key={ tabName } title={ tabName }>
|
||||
<div className="cf-block__fields">
|
||||
{ this.renderTabbedFields( fieldNames ) }
|
||||
</div>
|
||||
</PanelBody>
|
||||
);
|
||||
} )
|
||||
)
|
||||
: (
|
||||
<PanelBody title={ __( 'Fields', 'carbon-fields-ui' ) }>
|
||||
{ this.renderNonTabbedFields() }
|
||||
</PanelBody>
|
||||
)
|
||||
}
|
||||
</InspectorControls>
|
||||
) }
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withSelect( ( select, { clientId, name } ) => {
|
||||
const { hasBlockSupport } = select( 'core/blocks' );
|
||||
const { getBlockRootClientId } = select( 'core/block-editor' );
|
||||
const {
|
||||
getContainerDefinitionByBlockName,
|
||||
getFieldDefinitionsByBlockName
|
||||
} = select( 'carbon-fields/blocks' );
|
||||
|
||||
const rootClientId = getBlockRootClientId( clientId );
|
||||
|
||||
return {
|
||||
container: getContainerDefinitionByBlockName( name ),
|
||||
fields: getFieldDefinitionsByBlockName( name ),
|
||||
supportsTabs: hasBlockSupport( name, 'tabs' ),
|
||||
supportsPreview: hasBlockSupport( name, 'preview' ) && ! rootClientId,
|
||||
supportsInnerBlocks: hasBlockSupport( name, 'innerBlocks' )
|
||||
};
|
||||
} )( BlockEdit );
|
||||
51
web/vendor/htmlburger/carbon-fields/packages/blocks/components/block-edit/style.scss
vendored
Normal file
51
web/vendor/htmlburger/carbon-fields/packages/blocks/components/block-edit/style.scss
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/* ==========================================================================
|
||||
Block
|
||||
========================================================================== */
|
||||
|
||||
.cf-block__tabs {
|
||||
margin-bottom: $size-base * 4;
|
||||
}
|
||||
|
||||
.cf-block__tabs-list {
|
||||
.wp-block & {
|
||||
display: flex;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none outside none;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-block__tabs-item {
|
||||
padding: $size-base * 2;
|
||||
margin: 0;
|
||||
font-family: $wp-font;
|
||||
font-size: $wp-font-size;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
|
||||
&--current {
|
||||
box-shadow: 0 3px 0 $wp-color-medium-blue;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-block__fields {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
&[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.wp-block & {
|
||||
margin: $size-base * -2;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-block__preview {
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.cf-block__inner-blocks .block-list-appender {
|
||||
margin-top: 32px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
41
web/vendor/htmlburger/carbon-fields/packages/blocks/components/block-save/index.js
vendored
Normal file
41
web/vendor/htmlburger/carbon-fields/packages/blocks/components/block-save/index.js
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { Component } from '@wordpress/element';
|
||||
import { InnerBlocks } from '@wordpress/editor';
|
||||
|
||||
class BlockSave extends Component {
|
||||
/**
|
||||
* Render the component.
|
||||
*
|
||||
* @return {null}
|
||||
*/
|
||||
render() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the content of inner blocks to the saved content.
|
||||
*
|
||||
* @param {mixed} element
|
||||
* @param {Object} blockType
|
||||
* @return {mixed}
|
||||
*/
|
||||
function addInnerBlocksContent( element, blockType ) {
|
||||
if ( ! /^carbon\-fields\/.+$/.test( blockType.name ) ) {
|
||||
return element;
|
||||
}
|
||||
|
||||
if ( ! blockType.supports.innerBlocks ) {
|
||||
return element;
|
||||
}
|
||||
|
||||
return (
|
||||
<InnerBlocks.Content />
|
||||
);
|
||||
}
|
||||
|
||||
wp.hooks.addFilter( 'blocks.getSaveElement', 'carbon-fields/blocks', addInnerBlocksContent );
|
||||
|
||||
export default BlockSave;
|
||||
11
web/vendor/htmlburger/carbon-fields/packages/blocks/components/field/index.js
vendored
Normal file
11
web/vendor/htmlburger/carbon-fields/packages/blocks/components/field/index.js
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* Carbon Fields dependencies.
|
||||
*/
|
||||
import { Field, withFilters } from '@carbon-fields/core';
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
|
||||
export default withFilters( 'carbon-fields.field-wrapper.block' )( Field );
|
||||
47
web/vendor/htmlburger/carbon-fields/packages/blocks/components/field/style.scss
vendored
Normal file
47
web/vendor/htmlburger/carbon-fields/packages/blocks/components/field/style.scss
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/* ==========================================================================
|
||||
Field
|
||||
========================================================================== */
|
||||
|
||||
.cf-field {
|
||||
.block-editor & {
|
||||
font-family: $wp-font;
|
||||
font-size: $wp-font-size;
|
||||
line-height: $wp-line-height;
|
||||
color: $gb-dark-gray-500;
|
||||
padding: $size-base * 2;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.wp-block-widget-area & {
|
||||
padding: 6.5px 20px;
|
||||
}
|
||||
|
||||
.edit-post-sidebar .cf-block__fields > & {
|
||||
padding: $size-base 0 0;
|
||||
}
|
||||
|
||||
.block-editor .cf-complex & {
|
||||
border-width: 1px 1px 0 0;
|
||||
border-style: solid;
|
||||
border-color: $wp-color-gray-light-500;
|
||||
}
|
||||
|
||||
.edit-post-sidebar .cf-complex & {
|
||||
border-color: $gb-dark-gray-150;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-field__label {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: $wp-color-dark-gray;
|
||||
|
||||
.block-editor & {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.wp-block-widget-area & {
|
||||
margin-bottom: 6.5px;
|
||||
}
|
||||
|
||||
}
|
||||
18
web/vendor/htmlburger/carbon-fields/packages/blocks/components/not-supported-field/index.js
vendored
Normal file
18
web/vendor/htmlburger/carbon-fields/packages/blocks/components/not-supported-field/index.js
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* The external dependencies.
|
||||
*/
|
||||
import { __, sprintf } from '@wordpress/i18n';
|
||||
|
||||
/**
|
||||
* Render a notice to inform the user that the field doesn't have
|
||||
* any options.
|
||||
*
|
||||
* @return {React.Element}
|
||||
*/
|
||||
const NotSupportedField = ( { type } ) => (
|
||||
<em>
|
||||
{ sprintf( __( `Field of type '%s' is not supported in Gutenberg.`, 'carbon-fields-ui' ), [ type ] ) }
|
||||
</em>
|
||||
);
|
||||
|
||||
export default NotSupportedField;
|
||||
154
web/vendor/htmlburger/carbon-fields/packages/blocks/components/server-side-render/index.js
vendored
Normal file
154
web/vendor/htmlburger/carbon-fields/packages/blocks/components/server-side-render/index.js
vendored
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import apiFetch from '@wordpress/api-fetch';
|
||||
import { Component, RawHTML } from '@wordpress/element';
|
||||
import { Placeholder, Spinner } from '@wordpress/components';
|
||||
import { withSelect } from '@wordpress/data';
|
||||
import { serialize } from '@wordpress/blocks';
|
||||
import { __, sprintf } from '@wordpress/i18n';
|
||||
import { isEqual, debounce } from 'lodash';
|
||||
|
||||
/**
|
||||
* This component is slightly modified version of the `ServerSideRender` component
|
||||
* that comes by default with Gutenberg.
|
||||
*
|
||||
* @see https://github.com/WordPress/gutenberg/tree/master/packages/components/src/server-side-render
|
||||
*/
|
||||
class ServerSideRender extends Component {
|
||||
/**
|
||||
* Local state.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
state = {
|
||||
response: null
|
||||
};
|
||||
|
||||
/**
|
||||
* Lifecycle hook.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
componentDidMount() {
|
||||
this.isStillMounted = true;
|
||||
|
||||
// Do the initial rendering.
|
||||
this.fetch( this.props );
|
||||
|
||||
// Only debounce once the initial fetch occurs to ensure that the first
|
||||
// renders show data as soon as possible.
|
||||
this.fetch = debounce( this.fetch, 500 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifecycle hook.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
this.isStillMounted = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifecycle hook.
|
||||
*
|
||||
* @param {Object} prevProps
|
||||
* @return {void}
|
||||
*/
|
||||
componentDidUpdate( prevProps ) {
|
||||
if ( ! isEqual( prevProps, this.props ) ) {
|
||||
this.fetch( this.props );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the preview of the block.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @return {void}
|
||||
*/
|
||||
fetch( props ) {
|
||||
if ( ! this.isStillMounted ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( null !== this.state.response ) {
|
||||
this.setState( { response: null } );
|
||||
}
|
||||
|
||||
const { block } = props;
|
||||
|
||||
// Store the latest fetch request so that when we process it, we can
|
||||
// check if it is the current request, to avoid race conditions on slow networks.
|
||||
const fetchRequest = this.currentFetchRequest = apiFetch( {
|
||||
method: 'post',
|
||||
path: '/carbon-fields/v1/block-renderer',
|
||||
data: {
|
||||
name: block.name,
|
||||
content: serialize( [ block ] )
|
||||
}
|
||||
} )
|
||||
.then( ( response ) => {
|
||||
if ( this.isStillMounted && fetchRequest === this.currentFetchRequest && response && response.rendered ) {
|
||||
this.setState( {
|
||||
response: response.rendered
|
||||
} );
|
||||
}
|
||||
} )
|
||||
.catch( ( error ) => {
|
||||
if ( this.isStillMounted && fetchRequest === this.currentFetchRequest ) {
|
||||
this.setState( {
|
||||
response: {
|
||||
error: true,
|
||||
errorMsg: error.message
|
||||
}
|
||||
} );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
const { response } = this.state;
|
||||
const { className } = this.props;
|
||||
|
||||
if ( ! response ) {
|
||||
return (
|
||||
<Placeholder className={ className }>
|
||||
<Spinner />
|
||||
</Placeholder>
|
||||
);
|
||||
} else if ( response.error ) {
|
||||
return (
|
||||
<Placeholder className={ className }>
|
||||
{ sprintf( __( 'Error loading block: %s', 'carbon-fields-ui' ), response.errorMsg ) }
|
||||
</Placeholder>
|
||||
);
|
||||
} else if ( ! response.length ) {
|
||||
return (
|
||||
<Placeholder className={ className }>
|
||||
{ __( 'No results found.', 'carbon-fields-ui' ) }
|
||||
</Placeholder>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<RawHTML key="html" className={ className }>
|
||||
{ response }
|
||||
</RawHTML>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withSelect( ( select, { clientId } ) => {
|
||||
const { getBlock } = select( 'core/block-editor' );
|
||||
|
||||
return {
|
||||
block: getBlock( clientId )
|
||||
};
|
||||
} )( ServerSideRender );
|
||||
55
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/association/index.js
vendored
Normal file
55
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/association/index.js
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { addFilter } from '@wordpress/hooks';
|
||||
import { select } from '@wordpress/data';
|
||||
import { get, find } from 'lodash';
|
||||
|
||||
/**
|
||||
* Carbon Fields dependencies.
|
||||
*/
|
||||
import { withProps } from '@carbon-fields/core';
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
|
||||
addFilter( 'carbon-fields.association.block', 'carbon-fields/blocks', withProps( ( props ) => {
|
||||
return {
|
||||
hierarchyResolver() {
|
||||
// Get the block that contains the field.
|
||||
const block = select( 'core/block-editor' ).getBlock( props.blockId );
|
||||
|
||||
// Get the path.
|
||||
const path = props.id.split( '__' );
|
||||
|
||||
// Remove the chunk that contains the block identifier.
|
||||
path.shift();
|
||||
|
||||
// Get the hierarchy.
|
||||
let hierarchy = path.shift();
|
||||
let accessor = `data.${ hierarchy }`;
|
||||
|
||||
// Visit every branch in the tree so we can get the full hierarchy.
|
||||
while ( path.length > 0 ) {
|
||||
const chunk = path.shift();
|
||||
const isGroup = chunk.indexOf( 'cf-' ) === 0;
|
||||
|
||||
if ( isGroup ) {
|
||||
const groups = get( block.attributes, `${ accessor }` );
|
||||
const group = find( groups, [ '_id', chunk ] );
|
||||
const groupIndex = groups.indexOf( group );
|
||||
|
||||
accessor = `${ accessor }.${ groupIndex }`;
|
||||
hierarchy = `${ hierarchy }[${ groupIndex }]:${ group._type }/`;
|
||||
} else {
|
||||
accessor = `${ accessor }.${ chunk }`;
|
||||
hierarchy = `${ hierarchy }${ chunk }`;
|
||||
}
|
||||
}
|
||||
|
||||
return hierarchy;
|
||||
}
|
||||
};
|
||||
} ) );
|
||||
72
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/association/style.scss
vendored
Normal file
72
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/association/style.scss
vendored
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/* ==========================================================================
|
||||
Association
|
||||
========================================================================== */
|
||||
|
||||
.cf-association__cols {
|
||||
.block-editor & {
|
||||
border-top-width: 1px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.edit-post-sidebar & {
|
||||
border-color: $gb-dark-gray-150;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.edit-post-sidebar &::before {
|
||||
background-color: $gb-dark-gray-150;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-association__counter {
|
||||
.edit-post-sidebar & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-association__option {
|
||||
.edit-post-sidebar & {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.edit-post-sidebar & + & {
|
||||
border-top-color: $gb-dark-gray-150;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-association__option-thumb {
|
||||
.edit-post-sidebar & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-association__option-content {
|
||||
.edit-post-sidebar & {
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-association__option-title {
|
||||
.edit-post-sidebar & {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-association__option-actions {
|
||||
.edit-post-sidebar .cf-association__col:first-child & {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.edit-post-sidebar & {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-association__option-action {
|
||||
.edit-post-sidebar &--edit {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
4
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/block-preview/index.js
vendored
Normal file
4
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/block-preview/index.js
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
15
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/block-preview/style.scss
vendored
Normal file
15
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/block-preview/style.scss
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/* ------------------------------------------------------------ *\
|
||||
Block Preview iFrame
|
||||
\* ------------------------------------------------------------ */
|
||||
|
||||
body.block-editor-iframe__body {
|
||||
.cf-block-preview {
|
||||
display: block;
|
||||
}
|
||||
|
||||
// Hide all other fields except the HTML fields with preview
|
||||
// Also check if there is preview field at all or just show all fields
|
||||
.cf-block__fields:has(.cf-block-preview) .cf-field:not(.cf-block-preview) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
325
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/complex/index.js
vendored
Normal file
325
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/complex/index.js
vendored
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import produce from 'immer';
|
||||
import { Component } from '@wordpress/element';
|
||||
import { addFilter } from '@wordpress/hooks';
|
||||
import {
|
||||
get,
|
||||
set,
|
||||
find,
|
||||
omit,
|
||||
assign,
|
||||
mapKeys,
|
||||
without,
|
||||
cloneDeep,
|
||||
findIndex
|
||||
} from 'lodash';
|
||||
|
||||
/**
|
||||
* Carbon Fields dependencies.
|
||||
*/
|
||||
import { uniqueId } from '@carbon-fields/core';
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
import Field from '../../components/field';
|
||||
|
||||
class ComplexField extends Component {
|
||||
/**
|
||||
* Local state.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
state = {
|
||||
collapsedGroups: this.props.value.reduce( ( accumulator, { _id, _type } ) => {
|
||||
const group = find( this.props.field.groups, [ 'name', _type ] );
|
||||
|
||||
if ( ! group.collapsed ) {
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
return accumulator.concat( _id );
|
||||
}, [] )
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a list of group values.
|
||||
*
|
||||
* @return {Array}
|
||||
*/
|
||||
getGroupValues() {
|
||||
return this.props.value.map( ( group ) => {
|
||||
const values = mapKeys( omit( group, [ '_id', '_type' ] ), ( value, key ) => key.replace( /\-/g, '_' ) );
|
||||
|
||||
return [ group._type, values ];
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles adding of group.
|
||||
*
|
||||
* @param {Object} group
|
||||
* @param {Function} callback
|
||||
* @return {void}
|
||||
*/
|
||||
handleAddGroup = ( group, callback ) => {
|
||||
const {
|
||||
id,
|
||||
value,
|
||||
onChange
|
||||
} = this.props;
|
||||
|
||||
const data = {};
|
||||
|
||||
data._id = uniqueId();
|
||||
data._type = group.name;
|
||||
|
||||
group.fields.reduce( ( accumulator, field ) => {
|
||||
accumulator[ field.base_name ] = field.default_value;
|
||||
|
||||
return accumulator;
|
||||
}, data );
|
||||
|
||||
onChange( id, value.concat( data ) );
|
||||
|
||||
callback( data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles cloning of group.
|
||||
*
|
||||
* @param {Object} group
|
||||
* @param {Function} callback
|
||||
* @return {void}
|
||||
*/
|
||||
handleCloneGroup = ( group, callback ) => {
|
||||
const {
|
||||
id,
|
||||
value,
|
||||
onChange
|
||||
} = this.props;
|
||||
|
||||
const index = value.indexOf( group );
|
||||
const clonedGroup = cloneDeep( group );
|
||||
|
||||
clonedGroup._id = uniqueId();
|
||||
|
||||
onChange( id, produce( value, ( draft ) => {
|
||||
draft.splice( index + 1, 0, clonedGroup );
|
||||
} ) );
|
||||
|
||||
callback( clonedGroup );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles removing of group.
|
||||
*
|
||||
* @param {Object} group
|
||||
* @return {void}
|
||||
*/
|
||||
handleRemoveGroup = ( group ) => {
|
||||
const {
|
||||
id,
|
||||
value,
|
||||
onChange
|
||||
} = this.props;
|
||||
|
||||
const groupIndex = findIndex( value, [ '_id', group._id ] );
|
||||
|
||||
onChange( id, produce( value, ( draft ) => {
|
||||
draft.splice( groupIndex, 1 );
|
||||
} ) );
|
||||
|
||||
this.setState( ( { collapsedGroups } ) => ( {
|
||||
collapsedGroups: without( collapsedGroups, group._id )
|
||||
} ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles expanding/collapsing of group.
|
||||
*
|
||||
* @param {string} groupId
|
||||
* @return {void}
|
||||
*/
|
||||
handleToggleGroup = ( groupId ) => {
|
||||
this.setState( ( { collapsedGroups } ) => {
|
||||
if ( collapsedGroups.indexOf( groupId ) > -1 ) {
|
||||
collapsedGroups = without( collapsedGroups, groupId );
|
||||
} else {
|
||||
collapsedGroups = [ ...collapsedGroups, groupId ];
|
||||
}
|
||||
|
||||
return { collapsedGroups };
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles expanding/collapsing of all groups.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
handleToggleAllGroups = () => {
|
||||
const { value } = this.props;
|
||||
|
||||
this.setState( ( { collapsedGroups } ) => {
|
||||
if ( collapsedGroups.length !== value.length ) {
|
||||
collapsedGroups = value.map( ( group ) => group._id );
|
||||
} else {
|
||||
collapsedGroups = [];
|
||||
}
|
||||
|
||||
return { collapsedGroups };
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles setuping of group.
|
||||
*
|
||||
* @param {Object} group
|
||||
* @param {Object} props
|
||||
* @return {Object}
|
||||
*/
|
||||
handleGroupSetup = ( group, props ) => {
|
||||
const fields = get( find( this.props.field.groups, [ 'name', group._type ] ), 'fields', [] );
|
||||
const values = omit( group, [ '_id', '_type' ] );
|
||||
|
||||
return assign( {}, props, {
|
||||
id: group._id,
|
||||
fields: fields,
|
||||
collapsed: this.state.collapsedGroups.indexOf( group._id ) > -1,
|
||||
context: 'block',
|
||||
values
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles setuping of group's field.
|
||||
*
|
||||
* @param {Object} field
|
||||
* @param {Object} props
|
||||
* @param {Object} groupProps
|
||||
* @return {Array}
|
||||
*/
|
||||
handleGroupFieldSetup = ( field, props, groupProps ) => {
|
||||
const { blockId } = this.props;
|
||||
const id = `${ this.props.id }__${ groupProps.id }__${ field.base_name }`;
|
||||
const value = get( groupProps, `values.${ field.base_name }` );
|
||||
|
||||
return [ Field, assign( {}, props, {
|
||||
key: id,
|
||||
id: id,
|
||||
name: field.base_name,
|
||||
containerId: this.props.containerId,
|
||||
blockId,
|
||||
field,
|
||||
value,
|
||||
onChange: this.handleGroupFieldChange
|
||||
} ) ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the change of group field.
|
||||
*
|
||||
* @param {string} fieldId
|
||||
* @param {mixed} fieldValue
|
||||
* @return {void}
|
||||
*/
|
||||
handleGroupFieldChange = ( fieldId, fieldValue ) => {
|
||||
const {
|
||||
id,
|
||||
value,
|
||||
onChange
|
||||
} = this.props;
|
||||
|
||||
onChange( id, produce( value, ( draft ) => {
|
||||
const path = fieldId.split( '__' );
|
||||
const fieldName = path.pop();
|
||||
const group = find( draft, [ '_id', path.pop() ] );
|
||||
|
||||
set( group, fieldName, fieldValue );
|
||||
} ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
handleGroupSetup,
|
||||
handleGroupFieldSetup,
|
||||
handleAddGroup,
|
||||
handleCloneGroup,
|
||||
handleRemoveGroup,
|
||||
handleToggleGroup,
|
||||
handleToggleAllGroups
|
||||
} = this;
|
||||
|
||||
const { value, children } = this.props;
|
||||
|
||||
const groupValues = this.getGroupValues();
|
||||
const allGroupsAreCollapsed = this.state.collapsedGroups.length === value.length;
|
||||
|
||||
return children( {
|
||||
groupValues,
|
||||
allGroupsAreCollapsed,
|
||||
handleGroupSetup,
|
||||
handleGroupFieldSetup,
|
||||
handleAddGroup,
|
||||
handleCloneGroup,
|
||||
handleRemoveGroup,
|
||||
handleToggleGroup,
|
||||
handleToggleAllGroups
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
addFilter( 'carbon-fields.complex.block', 'carbon-fields/blocks', ( OriginalComplexField ) => ( props ) => {
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
value,
|
||||
error,
|
||||
field
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<ComplexField { ...props }>
|
||||
{ ( {
|
||||
groupValues,
|
||||
allGroupsAreCollapsed,
|
||||
handleGroupSetup,
|
||||
handleGroupFieldSetup,
|
||||
handleAddGroup,
|
||||
handleCloneGroup,
|
||||
handleRemoveGroup,
|
||||
handleToggleGroup,
|
||||
handleToggleAllGroups
|
||||
} ) => (
|
||||
<OriginalComplexField
|
||||
groupIdKey="_id"
|
||||
groupFilterKey="_type"
|
||||
id={ id }
|
||||
name={ name }
|
||||
value={ value }
|
||||
error={ error }
|
||||
field={ field }
|
||||
groupValues={ groupValues }
|
||||
allGroupsAreCollapsed={ allGroupsAreCollapsed }
|
||||
onGroupSetup={ handleGroupSetup }
|
||||
onGroupFieldSetup={ handleGroupFieldSetup }
|
||||
onAddGroup={ handleAddGroup }
|
||||
onCloneGroup={ handleCloneGroup }
|
||||
onRemoveGroup={ handleRemoveGroup }
|
||||
onToggleGroup={ handleToggleGroup }
|
||||
onToggleAllGroups={ handleToggleAllGroups }
|
||||
onChange={ props.onChange }
|
||||
/>
|
||||
) }
|
||||
</ComplexField>
|
||||
);
|
||||
} );
|
||||
89
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/complex/style.scss
vendored
Normal file
89
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/complex/style.scss
vendored
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/* ==========================================================================
|
||||
Complex
|
||||
========================================================================== */
|
||||
|
||||
.cf-complex__placeholder-label {
|
||||
font-size: $wp-font-size;
|
||||
line-height: $wp-line-height;
|
||||
}
|
||||
|
||||
.cf-complex__inserter-menu {
|
||||
.block-editor & {
|
||||
z-index: 10;
|
||||
list-style: none outside none;
|
||||
border: 1px solid $gb-light-gray-500;
|
||||
box-shadow: 0 3px 30px rgba($gb-dark-gray-900, .1);
|
||||
background-color: $color-white;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 100%;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-width: 8px 8px 8px 0;
|
||||
border-style: solid;
|
||||
margin-top: -8px;
|
||||
content: '';
|
||||
}
|
||||
|
||||
&::before {
|
||||
border-color: transparent $gb-light-gray-500;
|
||||
margin-right: 1px;
|
||||
}
|
||||
|
||||
&::after {
|
||||
border-color: transparent $color-white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cf-complex__inserter-item {
|
||||
.block-editor & {
|
||||
color: $gb-dark-gray-600;
|
||||
|
||||
&:hover {
|
||||
color: $gb-dark-gray-900;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cf-complex__inserter-button {
|
||||
.edit-post-sidebar .cf-complex__tabs & {
|
||||
border-color: $gb-dark-gray-150;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-complex__tabs-item {
|
||||
.block-editor & {
|
||||
color: $gb-dark-gray-500;
|
||||
}
|
||||
|
||||
.block-editor &--current {
|
||||
color: $gb-dark-gray-900;
|
||||
}
|
||||
|
||||
.edit-post-sidebar & {
|
||||
border-color: $gb-dark-gray-150;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-complex__group-head {
|
||||
.edit-post-sidebar & {
|
||||
border-color: $gb-dark-gray-150;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-complex__group-body {
|
||||
.edit-post-sidebar & {
|
||||
display: block;
|
||||
border-color: $gb-dark-gray-150;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-complex__group-actions {
|
||||
.edit-post-sidebar &--tabbed {
|
||||
border-color: $gb-dark-gray-150;
|
||||
}
|
||||
}
|
||||
96
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/datetime/index.js
vendored
Normal file
96
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/datetime/index.js
vendored
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { format } from '@wordpress/date';
|
||||
import { Component } from '@wordpress/element';
|
||||
import { addFilter } from '@wordpress/hooks';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
|
||||
class DateTimeField extends Component {
|
||||
/**
|
||||
* Handles the change.
|
||||
*
|
||||
* @param {Date[]} selectedDates
|
||||
* @param {string} selectedDateStr
|
||||
* @return {void}
|
||||
*/
|
||||
handleChange = ( selectedDates, selectedDateStr ) => {
|
||||
const {
|
||||
id,
|
||||
onChange,
|
||||
value,
|
||||
field
|
||||
} = this.props;
|
||||
|
||||
const formattedDate = format( field.storage_format, selectedDateStr );
|
||||
|
||||
if ( formattedDate !== value ) {
|
||||
onChange( id, formattedDate );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
const { handleChange } = this;
|
||||
const { children } = this.props;
|
||||
|
||||
return children( {
|
||||
handleChange
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
addFilter( 'carbon-fields.date_time.block', 'carbon-fields/blocks', ( OriginalDateTimeField ) => ( props ) => {
|
||||
return (
|
||||
<DateTimeField { ...props }>
|
||||
{ ( {
|
||||
handleChange
|
||||
} ) => (
|
||||
<OriginalDateTimeField
|
||||
buttonText={ __( 'Select Date', 'carbon-fields-ui' ) }
|
||||
{ ...props }
|
||||
onChange={ handleChange }
|
||||
/>
|
||||
) }
|
||||
</DateTimeField>
|
||||
);
|
||||
} );
|
||||
|
||||
addFilter( 'carbon-fields.date.block', 'carbon-fields/blocks', ( OriginalDateField ) => ( props ) => {
|
||||
return (
|
||||
<DateTimeField { ...props }>
|
||||
{ ( {
|
||||
handleChange
|
||||
} ) => (
|
||||
<OriginalDateField
|
||||
{ ...props }
|
||||
onChange={ handleChange }
|
||||
/>
|
||||
) }
|
||||
</DateTimeField>
|
||||
);
|
||||
} );
|
||||
|
||||
addFilter( 'carbon-fields.time.block', 'carbon-fields/blocks', ( OriginalTimeField ) => ( props ) => {
|
||||
return (
|
||||
<DateTimeField { ...props }>
|
||||
{ ( {
|
||||
handleChange
|
||||
} ) => (
|
||||
<OriginalTimeField
|
||||
{ ...props }
|
||||
onChange={ handleChange }
|
||||
/>
|
||||
) }
|
||||
</DateTimeField>
|
||||
);
|
||||
} );
|
||||
44
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/datetime/style.scss
vendored
Normal file
44
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/datetime/style.scss
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/* ==========================================================================
|
||||
DateTime
|
||||
========================================================================== */
|
||||
|
||||
.cf-datetime__inner {
|
||||
.edit-post-sidebar & {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.edit-post-sidebar &::before {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 9px;
|
||||
display: inline-block;
|
||||
margin-top: -10px;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-datetime__input {
|
||||
.wp-block .cf-field & {
|
||||
min-width: 0;
|
||||
border-color: $wp-color-gray-light-500;
|
||||
border-radius: 0;
|
||||
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-post-sidebar .cf-field & {
|
||||
padding-left: 35px;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-datetime__button {
|
||||
.wp-block & {
|
||||
height: auto;
|
||||
border-color: $wp-color-gray-light-500;
|
||||
}
|
||||
|
||||
.edit-post-sidebar & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
21
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/file/index.js
vendored
Normal file
21
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/file/index.js
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { addFilter } from '@wordpress/hooks';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
|
||||
addFilter( 'carbon-fields.file.block', 'carbon-fields/blocks', ( OriginalFileField ) => ( props ) => {
|
||||
return (
|
||||
<OriginalFileField
|
||||
buttonLabel={ __( 'Select File', 'carbon-fields-ui' ) }
|
||||
mediaLibraryButtonLabel={ __( 'Use File', 'carbon-fields-ui' ) }
|
||||
mediaLibraryTitle={ __( 'Select File', 'carbon-fields-ui' ) }
|
||||
{ ...props }
|
||||
/>
|
||||
);
|
||||
} );
|
||||
21
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/file/style.scss
vendored
Normal file
21
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/file/style.scss
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/* ==========================================================================
|
||||
File
|
||||
========================================================================== */
|
||||
|
||||
.cf-file__inner {
|
||||
.edit-post-sidebar & {
|
||||
border-color: $gb-dark-gray-150;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-file__content {
|
||||
.edit-post-sidebar & {
|
||||
border-color: $gb-dark-gray-150;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-file__name {
|
||||
.edit-post-sidebar & {
|
||||
border-color: $gb-dark-gray-150;
|
||||
}
|
||||
}
|
||||
11
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/footer-scripts/index.js
vendored
Normal file
11
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/footer-scripts/index.js
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { addFilter } from '@wordpress/hooks';
|
||||
|
||||
/**
|
||||
* The internal dependencies.
|
||||
*/
|
||||
import NotSupportedField from '../../components/not-supported-field';
|
||||
|
||||
addFilter( 'carbon-fields.footer_scripts.block', 'carbon-fields/blocks', () => ( props ) => <NotSupportedField type={ props.field.type } /> );
|
||||
11
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/header-scripts/index.js
vendored
Normal file
11
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/header-scripts/index.js
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { addFilter } from '@wordpress/hooks';
|
||||
|
||||
/**
|
||||
* The internal dependencies.
|
||||
*/
|
||||
import NotSupportedField from '../../components/not-supported-field';
|
||||
|
||||
addFilter( 'carbon-fields.header_scripts.block', 'carbon-fields/blocks', () => ( props ) => <NotSupportedField type={ props.field.type } /> );
|
||||
11
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/hidden/index.js
vendored
Normal file
11
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/hidden/index.js
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { addFilter } from '@wordpress/hooks';
|
||||
|
||||
/**
|
||||
* The internal dependencies.
|
||||
*/
|
||||
import NotSupportedField from '../../components/not-supported-field';
|
||||
|
||||
addFilter( 'carbon-fields.hidden.block', 'carbon-fields/blocks', () => ( props ) => <NotSupportedField type={ props.field.type } /> );
|
||||
16
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/image/index.js
vendored
Normal file
16
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/image/index.js
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { addFilter } from '@wordpress/hooks';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
addFilter( 'carbon-fields.image.block', 'carbon-fields/blocks', ( OriginalImageField ) => ( props ) => {
|
||||
return (
|
||||
<OriginalImageField
|
||||
buttonLabel={ __( 'Select Image', 'carbon-fields-ui' ) }
|
||||
mediaLibraryButtonLabel={ __( 'Use Image', 'carbon-fields-ui' ) }
|
||||
mediaLibraryTitle={ __( 'Select Image', 'carbon-fields-ui' ) }
|
||||
{ ...props }
|
||||
/>
|
||||
);
|
||||
} );
|
||||
63
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/index.js
vendored
Normal file
63
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/index.js
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { compose } from '@wordpress/compose';
|
||||
import { addFilter } from '@wordpress/hooks';
|
||||
import { withDispatch } from '@wordpress/data';
|
||||
|
||||
/**
|
||||
* Carbon Fields dependencies.
|
||||
*/
|
||||
import { withValidation } from '@carbon-fields/core';
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import withConditionalLogic from '../hocs/with-conditional-logic';
|
||||
import isGutenberg from '../../metaboxes/utils/is-gutenberg';
|
||||
|
||||
/**
|
||||
* Connects every field to the store.
|
||||
*/
|
||||
addFilter( 'carbon-fields.field-edit.block', 'carbon-fields/blocks', compose(
|
||||
withConditionalLogic,
|
||||
withDispatch( ( dispatch ) => {
|
||||
// Widgets support - WordPress 5.8
|
||||
if ( isGutenberg() ) {
|
||||
const { lockPostSaving, unlockPostSaving } = dispatch( 'core/editor' );
|
||||
|
||||
return {
|
||||
lockSaving: lockPostSaving,
|
||||
unlockSaving: unlockPostSaving
|
||||
};
|
||||
}
|
||||
|
||||
return {};
|
||||
} ),
|
||||
withValidation
|
||||
) );
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './association';
|
||||
import './complex';
|
||||
import './datetime';
|
||||
import './file';
|
||||
import './footer-scripts';
|
||||
import './header-scripts';
|
||||
import './hidden';
|
||||
import './image';
|
||||
import './map';
|
||||
import './multiselect';
|
||||
import './media-gallery';
|
||||
import './oembed';
|
||||
import './radio';
|
||||
import './radio-image';
|
||||
import './select';
|
||||
import './set';
|
||||
import './sidebar';
|
||||
import './separator';
|
||||
import './text';
|
||||
import './textarea';
|
||||
import './block-preview';
|
||||
4
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/map/index.js
vendored
Normal file
4
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/map/index.js
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
15
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/map/style.scss
vendored
Normal file
15
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/map/style.scss
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/* ==========================================================================
|
||||
Map
|
||||
========================================================================== */
|
||||
|
||||
.cf-map__canvas {
|
||||
.edit-post-sidebar & {
|
||||
border-color: $gb-dark-gray-150;
|
||||
border-top-width: 1px;
|
||||
margin-top: $size-base;
|
||||
}
|
||||
|
||||
.block-editor .cf-map__search:focus-within ~ & {
|
||||
border-color: $wp-color-medium-blue;
|
||||
}
|
||||
}
|
||||
21
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/media-gallery/index.js
vendored
Normal file
21
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/media-gallery/index.js
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { addFilter } from '@wordpress/hooks';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
|
||||
addFilter( 'carbon-fields.media_gallery.block', 'carbon-fields/blocks', ( OriginalMediaGalleryField ) => ( props ) => {
|
||||
return (
|
||||
<OriginalMediaGalleryField
|
||||
buttonLabel={ __( 'Select Attachments', 'carbon-fields-ui' ) }
|
||||
mediaLibraryButtonLabel={ __( 'Use Attachments', 'carbon-fields-ui' ) }
|
||||
mediaLibraryTitle={ __( 'Select Attachments', 'carbon-fields-ui' ) }
|
||||
{ ...props }
|
||||
/>
|
||||
);
|
||||
} );
|
||||
69
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/media-gallery/style.scss
vendored
Normal file
69
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/media-gallery/style.scss
vendored
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/* ==========================================================================
|
||||
Media Gallery
|
||||
========================================================================== */
|
||||
|
||||
.cf-media-gallery__item {
|
||||
.block-editor & {
|
||||
@media (min-width: 1440px) {
|
||||
flex-basis: 16.6667%;
|
||||
}
|
||||
|
||||
@media (min-width: 1680px) {
|
||||
flex-basis: 16.6667%;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-post-sidebar & {
|
||||
flex-basis: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-media-gallery__inner {
|
||||
.wp-block & {
|
||||
border: 1px solid $wp-color-gray-light-500;
|
||||
}
|
||||
|
||||
.edit-post-sidebar & {
|
||||
border: 1px solid $gb-dark-gray-150;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-media-gallery__actions {
|
||||
.wp-block & {
|
||||
border-top: 1px solid $wp-color-gray-light-500;
|
||||
}
|
||||
|
||||
.edit-post-sidebar & {
|
||||
border-top: 1px solid $gb-dark-gray-150;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-media-gallery__item-inner {
|
||||
.wp-block & {
|
||||
border: 1px solid $wp-color-gray-light-500;
|
||||
}
|
||||
|
||||
.edit-post-sidebar & {
|
||||
border: 1px solid $gb-dark-gray-150;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-media-gallery__item-preview {
|
||||
.block-editor & {
|
||||
background-color: $wp-color-gray-light-200;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-media-gallery__item-name {
|
||||
.block-editor & {
|
||||
background-color: $wp-color-gray-light-200;
|
||||
}
|
||||
|
||||
.wp-block & {
|
||||
border-top: 1px solid $wp-color-gray-light-500;
|
||||
}
|
||||
|
||||
.edit-post-sidebar & {
|
||||
border-top: 1px solid $gb-dark-gray-150;
|
||||
}
|
||||
}
|
||||
4
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/multiselect/index.js
vendored
Normal file
4
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/multiselect/index.js
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
20
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/multiselect/style.scss
vendored
Normal file
20
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/multiselect/style.scss
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/* ==========================================================================
|
||||
Multiselect
|
||||
========================================================================== */
|
||||
|
||||
.cf-multiselect__control {
|
||||
.wp-block & {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.edit-post-sidebar &,
|
||||
.edit-post-sidebar &:hover {
|
||||
border-color: $gb-dark-gray-150;
|
||||
}
|
||||
|
||||
.edit-post-sidebar &--is-focused,
|
||||
.edit-post-sidebar &--is-focused:hover {
|
||||
border-color: $wp-color-medium-blue;
|
||||
box-shadow: 0 0 0 1px $wp-color-medium-blue;
|
||||
}
|
||||
}
|
||||
4
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/oembed/index.js
vendored
Normal file
4
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/oembed/index.js
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
16
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/oembed/style.scss
vendored
Normal file
16
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/oembed/style.scss
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/* ==========================================================================
|
||||
oEmbed
|
||||
========================================================================== */
|
||||
|
||||
.cf-oembed__preview {
|
||||
.edit-post-sidebar & {
|
||||
border-color: $gb-dark-gray-150;
|
||||
border-top-width: 1px;
|
||||
margin-top: $size-base;
|
||||
}
|
||||
|
||||
.block-editor .cf-oembed:focus-within & {
|
||||
border-color: $wp-color-medium-blue;
|
||||
}
|
||||
}
|
||||
|
||||
4
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/radio-image/index.js
vendored
Normal file
4
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/radio-image/index.js
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
38
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/radio-image/style.scss
vendored
Normal file
38
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/radio-image/style.scss
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/* ==========================================================================
|
||||
Radio Image
|
||||
========================================================================== */
|
||||
|
||||
.cf-radio__list-item {
|
||||
.block-editor & {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.wp-block .cf-radio-image & {
|
||||
@media (min-width: 1440px) {
|
||||
flex-basis: 25%;
|
||||
}
|
||||
|
||||
@media (min-width: 1680px) {
|
||||
flex-basis: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-post-sidebar .cf-radio-image & {
|
||||
flex-basis: 33.3333%;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-radio-image__image {
|
||||
.wp-block & {
|
||||
border: 1px solid $wp-color-gray-light-500;
|
||||
}
|
||||
|
||||
.edit-post-sidebar & {
|
||||
border: 1px solid $gb-dark-gray-150;
|
||||
}
|
||||
|
||||
.block-editor .cf-radio__input:focus ~ .cf-radio__label &,
|
||||
.block-editor .cf-radio__input:checked ~ .cf-radio__label & {
|
||||
outline: 2px solid $wp-color-medium-blue;
|
||||
}
|
||||
}
|
||||
4
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/radio/index.js
vendored
Normal file
4
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/radio/index.js
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
9
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/radio/style.scss
vendored
Normal file
9
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/radio/style.scss
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
/* ==========================================================================
|
||||
Radio
|
||||
========================================================================== */
|
||||
|
||||
.cf-radio__list {
|
||||
.wp-block & {
|
||||
list-style: none outside none;
|
||||
}
|
||||
}
|
||||
4
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/select/index.js
vendored
Normal file
4
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/select/index.js
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
14
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/select/style.scss
vendored
Normal file
14
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/select/style.scss
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
/* ==========================================================================
|
||||
Select
|
||||
========================================================================== */
|
||||
|
||||
.cf-select__input {
|
||||
.wp-block .cf-field & {
|
||||
border-color: $wp-color-gray-light-500;
|
||||
border-radius: 0;
|
||||
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
4
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/separator/index.js
vendored
Normal file
4
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/separator/index.js
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
9
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/separator/style.scss
vendored
Normal file
9
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/separator/style.scss
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
/* ==========================================================================
|
||||
Separator
|
||||
========================================================================== */
|
||||
|
||||
.cf-separator {
|
||||
.block-editor & h3 {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
4
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/set/index.js
vendored
Normal file
4
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/set/index.js
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
9
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/set/style.scss
vendored
Normal file
9
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/set/style.scss
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
/* ==========================================================================
|
||||
Set
|
||||
========================================================================== */
|
||||
|
||||
.cf-set__list {
|
||||
.wp-block & {
|
||||
list-style: none outside none;
|
||||
}
|
||||
}
|
||||
11
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/sidebar/index.js
vendored
Normal file
11
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/sidebar/index.js
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { addFilter } from '@wordpress/hooks';
|
||||
|
||||
/**
|
||||
* The internal dependencies.
|
||||
*/
|
||||
import NotSupportedField from '../../components/not-supported-field';
|
||||
|
||||
addFilter( 'carbon-fields.sidebar.block', 'carbon-fields/blocks', () => ( props ) => <NotSupportedField type={ props.field.type } /> );
|
||||
4
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/text/index.js
vendored
Normal file
4
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/text/index.js
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
14
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/text/style.scss
vendored
Normal file
14
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/text/style.scss
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
/* ==========================================================================
|
||||
Text
|
||||
========================================================================== */
|
||||
|
||||
.cf-text__input {
|
||||
.wp-block .cf-field & {
|
||||
border-color: $wp-color-gray-light-500;
|
||||
border-radius: 0;
|
||||
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
4
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/textarea/index.js
vendored
Normal file
4
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/textarea/index.js
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
16
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/textarea/style.scss
vendored
Normal file
16
web/vendor/htmlburger/carbon-fields/packages/blocks/fields/textarea/style.scss
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/* ==========================================================================
|
||||
Textarea
|
||||
========================================================================== */
|
||||
|
||||
.cf-textarea__input {
|
||||
.wp-block .cf-field & {
|
||||
border-color: $wp-color-gray-light-500;
|
||||
border-radius: 0;
|
||||
transition: border-color $transition-base;
|
||||
|
||||
&:focus {
|
||||
border-color: $wp-color-medium-blue;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
131
web/vendor/htmlburger/carbon-fields/packages/blocks/hocs/with-conditional-logic/index.js
vendored
Normal file
131
web/vendor/htmlburger/carbon-fields/packages/blocks/hocs/with-conditional-logic/index.js
vendored
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import distinctUntilChanged from 'callbag-distinct-until-changed';
|
||||
import { select } from '@wordpress/data';
|
||||
import { pipe, map } from 'callbag-basics';
|
||||
import {
|
||||
get,
|
||||
has,
|
||||
omit,
|
||||
assign,
|
||||
repeat,
|
||||
mapKeys,
|
||||
findIndex,
|
||||
startsWith
|
||||
} from 'lodash';
|
||||
|
||||
/**
|
||||
* Carbon Fields dependencies.
|
||||
*/
|
||||
import { fromSelector, withConditionalLogic } from '@carbon-fields/core';
|
||||
|
||||
/**
|
||||
* Adds the `parent.` parent prefix to field's name.
|
||||
*
|
||||
* @param {Object[]} fields
|
||||
* @param {number} depth
|
||||
* @return {Array[]}
|
||||
*/
|
||||
function mapParentPrefix( fields, depth = 0 ) {
|
||||
return mapKeys( fields, ( value, key ) => `${ repeat( 'parent.', depth ) }${ key }` );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given string is a group identifier.
|
||||
*
|
||||
* @param {string} id
|
||||
* @return {boolean}
|
||||
*/
|
||||
function isComplexGroupIdentifier( id ) {
|
||||
return startsWith( id, 'cf-' );
|
||||
}
|
||||
|
||||
/**
|
||||
* The function used to track dependencies required
|
||||
* by conditional logic.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @return {Object}
|
||||
*/
|
||||
function input( props ) {
|
||||
return pipe(
|
||||
fromSelector( select( 'core/block-editor' ).getBlock, props.blockId ),
|
||||
distinctUntilChanged(),
|
||||
map( ( blockData ) => blockData?.attributes?.data )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The function that provides the data that needs to be
|
||||
* evaluated by conditional logic.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @param {Object} fields
|
||||
* @return {Object}
|
||||
*/
|
||||
function output( props, fields ) {
|
||||
const isTopLevelField = has( fields, props.field.base_name );
|
||||
let siblingFields = {};
|
||||
|
||||
if ( isTopLevelField ) {
|
||||
siblingFields = mapParentPrefix( omit( fields, [ props.field.base_name ] ) );
|
||||
} else {
|
||||
// Get the hierarchy.
|
||||
const path = props.id.split( '__' );
|
||||
|
||||
// Remove the chunk with identifier of block since
|
||||
// we already have it.
|
||||
path.shift();
|
||||
|
||||
// Remove the chunk with name of root field.
|
||||
const rootFieldName = path.shift();
|
||||
|
||||
// Remove the chunk with name of field since
|
||||
// we already have it.
|
||||
path.pop();
|
||||
|
||||
// Keep reference to the depth
|
||||
// so we can add the `parent.` prefix.
|
||||
let depth = path.reduce( ( accumulator, chunk ) => {
|
||||
return isComplexGroupIdentifier( chunk )
|
||||
? accumulator
|
||||
: accumulator + 1;
|
||||
}, 0 );
|
||||
|
||||
// Collect fields that are siblings of root field.
|
||||
siblingFields = omit( fields, [ rootFieldName ] );
|
||||
siblingFields = mapParentPrefix( siblingFields, depth + 1 );
|
||||
|
||||
// Keep reference to the full path of the field.
|
||||
let pathPrefix = rootFieldName;
|
||||
|
||||
while ( path.length > 0 ) {
|
||||
const chunk = path.shift();
|
||||
const isGroup = isComplexGroupIdentifier( chunk );
|
||||
const isNestedComplex = ! isGroup;
|
||||
|
||||
if ( isGroup ) {
|
||||
const groupIndex = findIndex( get( fields, pathPrefix ), [ '_id', chunk ] );
|
||||
|
||||
pathPrefix = `${ pathPrefix }.${ groupIndex }`;
|
||||
|
||||
let groupFields = get( fields, pathPrefix );
|
||||
groupFields = omit( groupFields, [ '_id', '_type', props.field.base_name ] );
|
||||
groupFields = mapParentPrefix( groupFields, depth );
|
||||
|
||||
assign( siblingFields, groupFields );
|
||||
}
|
||||
|
||||
if ( isNestedComplex ) {
|
||||
pathPrefix = `${ pathPrefix }.${ chunk }`;
|
||||
|
||||
depth--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return siblingFields;
|
||||
}
|
||||
|
||||
export default withConditionalLogic( input, output );
|
||||
75
web/vendor/htmlburger/carbon-fields/packages/blocks/index.js
vendored
Normal file
75
web/vendor/htmlburger/carbon-fields/packages/blocks/index.js
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/* eslint no-console: [ 'error', { allow: [ 'error' ] } ] */
|
||||
|
||||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { dispatch } from '@wordpress/data';
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
import { setLocaleData } from '@wordpress/i18n';
|
||||
import {
|
||||
get,
|
||||
kebabCase,
|
||||
isPlainObject
|
||||
} from 'lodash';
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './fields';
|
||||
import './store';
|
||||
import BlockEdit from './components/block-edit';
|
||||
import BlockSave from './components/block-save';
|
||||
import transformFieldsToAttributes from './utils/transform-fields-to-attributes';
|
||||
|
||||
/**
|
||||
* Sets the locale data for the package type
|
||||
*/
|
||||
setLocaleData( window.cf.config.locale, 'carbon-fields-ui' );
|
||||
|
||||
/**
|
||||
* Register the blocks.
|
||||
*/
|
||||
const containerDefinitions = {};
|
||||
const fieldDefinitions = {};
|
||||
|
||||
get( window.cf, 'preloaded.blocks', [] ).forEach( ( container ) => {
|
||||
const name = kebabCase( container.id ).replace( 'carbon-fields-container-', '' );
|
||||
const fields = transformFieldsToAttributes( container.fields );
|
||||
|
||||
const getBlockSetting = ( key, def = null ) => get( container, `settings.${ key }`, def );
|
||||
|
||||
containerDefinitions[ name ] = container;
|
||||
fieldDefinitions[ name ] = container.fields.map( ( field ) => ( { ...field } ) );
|
||||
|
||||
registerBlockType( `carbon-fields/${ name }`, {
|
||||
title: container.title,
|
||||
icon: getBlockSetting( 'icon' ),
|
||||
parent: getBlockSetting( 'parent', [] ),
|
||||
category: getBlockSetting( 'category.slug' ),
|
||||
keywords: getBlockSetting( 'keywords', [] ),
|
||||
description: getBlockSetting( 'description', '' ),
|
||||
attributes: {
|
||||
data: {
|
||||
type: 'object',
|
||||
default: fields
|
||||
}
|
||||
},
|
||||
supports: {
|
||||
tabs: isPlainObject( getBlockSetting( 'tabs' ) ),
|
||||
preview: getBlockSetting( 'preview' ),
|
||||
innerBlocks: getBlockSetting( 'inner_blocks.enabled' ),
|
||||
alignWide: false,
|
||||
anchor: false,
|
||||
html: false
|
||||
},
|
||||
edit: BlockEdit,
|
||||
save: BlockSave,
|
||||
example: true,
|
||||
} );
|
||||
} );
|
||||
|
||||
/**
|
||||
* Load the definitions in store.
|
||||
*/
|
||||
dispatch( 'carbon-fields/blocks' ).setupContainerDefinitions( containerDefinitions );
|
||||
dispatch( 'carbon-fields/blocks' ).setupFieldDefinitions( fieldDefinitions );
|
||||
29
web/vendor/htmlburger/carbon-fields/packages/blocks/store/actions.js
vendored
Normal file
29
web/vendor/htmlburger/carbon-fields/packages/blocks/store/actions.js
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* Returns an action object used to setup the definitions state when first opening an editor.
|
||||
*
|
||||
* @param {Object} definitions
|
||||
* @return {Object}
|
||||
*/
|
||||
export function setupContainerDefinitions( definitions ) {
|
||||
return {
|
||||
type: 'SETUP_CONTAINER_DEFINITIONS',
|
||||
payload: {
|
||||
definitions
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an action object used to setup the definitions state when first opening an editor.
|
||||
*
|
||||
* @param {Object} definitions
|
||||
* @return {Object}
|
||||
*/
|
||||
export function setupFieldDefinitions( definitions ) {
|
||||
return {
|
||||
type: 'SETUP_FIELD_DEFINITIONS',
|
||||
payload: {
|
||||
definitions
|
||||
}
|
||||
};
|
||||
}
|
||||
20
web/vendor/htmlburger/carbon-fields/packages/blocks/store/index.js
vendored
Normal file
20
web/vendor/htmlburger/carbon-fields/packages/blocks/store/index.js
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { registerStore } from '@wordpress/data';
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import reducer from './reducer';
|
||||
import * as actions from './actions';
|
||||
import * as selectors from './selectors';
|
||||
|
||||
/**
|
||||
* Register the store.
|
||||
*/
|
||||
registerStore( 'carbon-fields/blocks', {
|
||||
reducer,
|
||||
actions,
|
||||
selectors
|
||||
} );
|
||||
43
web/vendor/htmlburger/carbon-fields/packages/blocks/store/reducer.js
vendored
Normal file
43
web/vendor/htmlburger/carbon-fields/packages/blocks/store/reducer.js
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { combineReducers } from '@wordpress/data';
|
||||
|
||||
/**
|
||||
* The reducer that keeps track of container definitions keyed by block's name.
|
||||
*
|
||||
* @param {Object} state
|
||||
* @param {Object} action
|
||||
* @return {Object}
|
||||
*/
|
||||
export function containerDefinitionsByBlockName( state = {}, action ) {
|
||||
switch ( action.type ) {
|
||||
case 'SETUP_CONTAINER_DEFINITIONS':
|
||||
return action.payload.definitions;
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The reducer that keeps track of field definitions keyed by block's name.
|
||||
*
|
||||
* @param {Object} state
|
||||
* @param {Object} action
|
||||
* @return {Object}
|
||||
*/
|
||||
export function fieldDefinitionsByBlockName( state = {}, action ) {
|
||||
switch ( action.type ) {
|
||||
case 'SETUP_FIELD_DEFINITIONS':
|
||||
return action.payload.definitions;
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
export default combineReducers( {
|
||||
containerDefinitionsByBlockName,
|
||||
fieldDefinitionsByBlockName
|
||||
} );
|
||||
25
web/vendor/htmlburger/carbon-fields/packages/blocks/store/selectors.js
vendored
Normal file
25
web/vendor/htmlburger/carbon-fields/packages/blocks/store/selectors.js
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* Get the container by a given block name.
|
||||
*
|
||||
* @param {Object} state
|
||||
* @param {string} blockName
|
||||
* @return {Object}
|
||||
*/
|
||||
export function getContainerDefinitionByBlockName( state, blockName ) {
|
||||
return state.containerDefinitionsByBlockName[
|
||||
blockName.replace( 'carbon-fields/', '' )
|
||||
] || {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields by a given block name.
|
||||
*
|
||||
* @param {Object} state
|
||||
* @param {string} blockName
|
||||
* @return {Object[]}
|
||||
*/
|
||||
export function getFieldDefinitionsByBlockName( state, blockName ) {
|
||||
return state.fieldDefinitionsByBlockName[
|
||||
blockName.replace( 'carbon-fields/', '' )
|
||||
] || [];
|
||||
}
|
||||
14
web/vendor/htmlburger/carbon-fields/packages/blocks/utils/transform-fields-to-attributes.js
vendored
Normal file
14
web/vendor/htmlburger/carbon-fields/packages/blocks/utils/transform-fields-to-attributes.js
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
/**
|
||||
* Transforms the fields to an attributes set.
|
||||
*
|
||||
* @param {Object[]} fields
|
||||
* @return {Object}
|
||||
*/
|
||||
export default function transformFieldsToAttributes( fields ) {
|
||||
return fields.reduce( ( attributes, field ) => {
|
||||
return {
|
||||
...attributes,
|
||||
[ field.base_name ]: field.default_value
|
||||
};
|
||||
}, {} );
|
||||
}
|
||||
6
web/vendor/htmlburger/carbon-fields/packages/core/components/disabled/context.js
vendored
Normal file
6
web/vendor/htmlburger/carbon-fields/packages/core/components/disabled/context.js
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { createContext } from '@wordpress/element';
|
||||
|
||||
export const { Provider, Consumer } = createContext( false );
|
||||
120
web/vendor/htmlburger/carbon-fields/packages/core/components/disabled/index.js
vendored
Normal file
120
web/vendor/htmlburger/carbon-fields/packages/core/components/disabled/index.js
vendored
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Component, createRef } from '@wordpress/element';
|
||||
import { includes, debounce } from 'lodash';
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import { Provider, Consumer } from './context';
|
||||
|
||||
/**
|
||||
* Names of control nodes which qualify for disabled behavior.
|
||||
*
|
||||
* See WHATWG HTML Standard: 4.10.18.5: "Enabling and disabling form controls: the disabled attribute".
|
||||
*
|
||||
* @link https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#enabling-and-disabling-form-controls:-the-disabled-attribute
|
||||
*
|
||||
* @type {string[]}
|
||||
*/
|
||||
const DISABLED_ELIGIBLE_NODE_NAMES = [
|
||||
'BUTTON',
|
||||
'FIELDSET',
|
||||
'INPUT',
|
||||
'OPTGROUP',
|
||||
'OPTION',
|
||||
'SELECT',
|
||||
'TEXTAREA'
|
||||
];
|
||||
|
||||
/**
|
||||
* Disables descendant tabbable elements and prevents pointer interaction.
|
||||
*
|
||||
* @borrows https://github.com/WordPress/gutenberg/blob/master/packages/components/src/disabled/index.js
|
||||
*/
|
||||
class Disabled extends Component {
|
||||
/**
|
||||
* Keeps reference to the DOM node.
|
||||
*/
|
||||
node = createRef();
|
||||
|
||||
/**
|
||||
* Lifecycle hook.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
componentDidMount() {
|
||||
this.disable();
|
||||
|
||||
this.observer = new window.MutationObserver( this.disable );
|
||||
|
||||
this.observer.observe( this.node.current, {
|
||||
childList: true,
|
||||
attributes: true,
|
||||
subtree: true
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifecycle hook.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
this.observer.disconnect();
|
||||
this.disable.cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables all elements.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
disable = debounce( () => {
|
||||
this.node.current.querySelectorAll( `
|
||||
[tabindex],
|
||||
button:not([disabled]),
|
||||
input:not([type="hidden"]):not([disabled]),
|
||||
select:not([disabled]),
|
||||
textarea:not([disabled]),
|
||||
iframe,
|
||||
object,
|
||||
embed,
|
||||
[contenteditable]:not([contenteditable=false])
|
||||
` ).forEach( ( node ) => {
|
||||
if ( includes( DISABLED_ELIGIBLE_NODE_NAMES, node.nodeName ) ) {
|
||||
node.setAttribute( 'disabled', '' );
|
||||
}
|
||||
|
||||
if ( node.hasAttribute( 'tabindex' ) ) {
|
||||
node.removeAttribute( 'tabindex' );
|
||||
}
|
||||
|
||||
if ( node.hasAttribute( 'contenteditable' ) ) {
|
||||
node.setAttribute( 'contenteditable', 'false' );
|
||||
}
|
||||
} );
|
||||
}, { leading: true } )
|
||||
|
||||
/**
|
||||
* Renders the component.
|
||||
*
|
||||
* @return {Objec}
|
||||
*/
|
||||
render() {
|
||||
const { className, children } = this.props;
|
||||
|
||||
return (
|
||||
<Provider value={ true }>
|
||||
<div ref={ this.node } className={ className }>
|
||||
{ children }
|
||||
</div>
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Disabled.Consumer = Consumer;
|
||||
|
||||
export default Disabled;
|
||||
106
web/vendor/htmlburger/carbon-fields/packages/core/components/field/index.js
vendored
Normal file
106
web/vendor/htmlburger/carbon-fields/packages/core/components/field/index.js
vendored
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import cx from 'classnames';
|
||||
import { compose } from '@wordpress/compose';
|
||||
import { withSelect } from '@wordpress/data';
|
||||
import { kebabCase } from 'lodash';
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
import Disabled from '../../components/disabled';
|
||||
import withFilters from '../../hocs/with-filters';
|
||||
|
||||
/**
|
||||
* Renders the base wrapper of the field.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @param {string} props.id
|
||||
* @param {Object} props.field
|
||||
* @param {?string} props.error
|
||||
* @param {boolean} props.hidden
|
||||
* @param {string} props.className
|
||||
* @param {mixed} props.children
|
||||
* @return {Object}
|
||||
*/
|
||||
function Field( {
|
||||
id,
|
||||
field,
|
||||
error,
|
||||
hidden,
|
||||
className,
|
||||
children
|
||||
} ) {
|
||||
const styles = !! field.width ? { flexBasis: `${ field.width }%` } : null;
|
||||
|
||||
const classes = [
|
||||
'cf-field',
|
||||
`cf-${ kebabCase( field.type ) }`,
|
||||
{
|
||||
'cf-field--has-width': !! field.width,
|
||||
'cf-field--invalid': !! error
|
||||
},
|
||||
className,
|
||||
...field.classes
|
||||
];
|
||||
|
||||
if ( field.hidden ) {
|
||||
return ( null );
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={ cx( classes ) }
|
||||
style={ styles }
|
||||
hidden={ hidden }
|
||||
>
|
||||
<div className="cf-field__head">
|
||||
{ field.label && (
|
||||
<label className="cf-field__label" htmlFor={ id }>
|
||||
{ field.label }
|
||||
|
||||
{ field.required && (
|
||||
<span className="cf-field__asterisk">*</span>
|
||||
) }
|
||||
</label>
|
||||
) }
|
||||
</div>
|
||||
|
||||
{ ! hidden && (
|
||||
<div className="cf-field__body">
|
||||
{ children }
|
||||
</div>
|
||||
) }
|
||||
|
||||
{ hidden && (
|
||||
<Disabled className="cf-field__body">
|
||||
{ children }
|
||||
</Disabled>
|
||||
) }
|
||||
|
||||
{ field.help_text && (
|
||||
<em className="cf-field__help" dangerouslySetInnerHTML={ { __html: field.help_text } }></em>
|
||||
) }
|
||||
|
||||
{ error && (
|
||||
<span className="cf-field__error">
|
||||
{ error }
|
||||
</span>
|
||||
) }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withSelect( ( select, props ) => {
|
||||
const { getValidationError, isFieldVisible } = select( 'carbon-fields/core' );
|
||||
|
||||
return {
|
||||
error: getValidationError( props.id ),
|
||||
hidden: ! isFieldVisible( props.id )
|
||||
};
|
||||
} ),
|
||||
withFilters( 'carbon-fields.field-wrapper' )
|
||||
)( Field );
|
||||
52
web/vendor/htmlburger/carbon-fields/packages/core/components/field/style.scss
vendored
Normal file
52
web/vendor/htmlburger/carbon-fields/packages/core/components/field/style.scss
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/* ==========================================================================
|
||||
Field
|
||||
========================================================================== */
|
||||
|
||||
.cf-field,
|
||||
.cf-field__head,
|
||||
.cf-field__body {
|
||||
box-sizing: border-box;
|
||||
flex: 1 1 100%;
|
||||
}
|
||||
|
||||
.cf-field {
|
||||
@media (max-width: 1024px) {
|
||||
flex-basis: 100% !important;
|
||||
}
|
||||
|
||||
// Show only on block preview iframe
|
||||
&.cf-block-preview {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-field__body {
|
||||
.cf-rich-text & {
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.cf-complex--tabbed-vertical > & {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-field__label {
|
||||
display: block;
|
||||
|
||||
.cf-html &,
|
||||
.cf-separator &,
|
||||
.cf-block-preview & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-field__asterisk {
|
||||
color: $wp-color-accent-red;
|
||||
}
|
||||
|
||||
.cf-field__error {
|
||||
display: block;
|
||||
margin-top: $size-base;
|
||||
color: $wp-color-accent-red;
|
||||
}
|
||||
112
web/vendor/htmlburger/carbon-fields/packages/core/components/media-library/index.js
vendored
Normal file
112
web/vendor/htmlburger/carbon-fields/packages/core/components/media-library/index.js
vendored
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { compose } from '@wordpress/compose';
|
||||
import { withEffects, toProps } from 'refract-callbag';
|
||||
import {
|
||||
map,
|
||||
pipe,
|
||||
merge
|
||||
} from 'callbag-basics';
|
||||
import of from 'callbag-of';
|
||||
|
||||
function MediaLibrary( { children, openMediaBrowser } ) {
|
||||
return children( { openMediaBrowser } );
|
||||
}
|
||||
|
||||
/**
|
||||
* The function that controls the stream of side-effects.
|
||||
*
|
||||
* @param {Object} component
|
||||
* @return {Object}
|
||||
*/
|
||||
function aperture( component ) {
|
||||
const mount$ = component.mount;
|
||||
const unmount$ = component.unmount;
|
||||
const [ openMediaBrowserEvent$, openMediaBrowser ] = component.useEvent( 'openMediaBrowserEvent' );
|
||||
|
||||
return merge(
|
||||
pipe(
|
||||
mount$,
|
||||
map( () => ( {
|
||||
type: 'INIT'
|
||||
} ) )
|
||||
),
|
||||
|
||||
pipe(
|
||||
unmount$,
|
||||
map( () => ( {
|
||||
type: 'DESTROY'
|
||||
} ) )
|
||||
),
|
||||
|
||||
pipe(
|
||||
of( {
|
||||
openMediaBrowser
|
||||
} ),
|
||||
map( toProps )
|
||||
),
|
||||
|
||||
pipe(
|
||||
openMediaBrowserEvent$,
|
||||
map( ( payload ) => ( {
|
||||
type: 'OPEN',
|
||||
payload
|
||||
} ) )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The function that causes the side effects.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @return {Function}
|
||||
*/
|
||||
function handler( props ) {
|
||||
let mediaBrowser = null;
|
||||
|
||||
return function( effect ) {
|
||||
switch ( effect.type ) {
|
||||
case 'INIT':
|
||||
const { onSelect, typeFilter } = props;
|
||||
|
||||
mediaBrowser = wp.media( {
|
||||
title: props.title,
|
||||
library: {
|
||||
type: typeFilter
|
||||
},
|
||||
button: {
|
||||
text: props.buttonLabel
|
||||
},
|
||||
multiple: props.multiple
|
||||
} );
|
||||
|
||||
mediaBrowser.on( 'select', () => {
|
||||
const file = mediaBrowser.state()
|
||||
.get( 'selection' )
|
||||
.toJSON();
|
||||
|
||||
onSelect( file );
|
||||
} );
|
||||
|
||||
break;
|
||||
case 'OPEN':
|
||||
if ( mediaBrowser ) {
|
||||
mediaBrowser.open();
|
||||
}
|
||||
|
||||
break;
|
||||
case 'DESTROY':
|
||||
mediaBrowser = null;
|
||||
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const applyWithEffects = withEffects( aperture, { handler } );
|
||||
|
||||
export default compose(
|
||||
applyWithEffects
|
||||
)( MediaLibrary );
|
||||
18
web/vendor/htmlburger/carbon-fields/packages/core/components/no-options/index.js
vendored
Normal file
18
web/vendor/htmlburger/carbon-fields/packages/core/components/no-options/index.js
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* The external dependencies.
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
/**
|
||||
* Render a notice to inform the user that the field doesn't have
|
||||
* any options.
|
||||
*
|
||||
* @return {React.Element}
|
||||
*/
|
||||
const NoOptions = () => (
|
||||
<em>
|
||||
{ __( 'No options.', 'carbon-fields-ui' ) }
|
||||
</em>
|
||||
);
|
||||
|
||||
export default NoOptions;
|
||||
87
web/vendor/htmlburger/carbon-fields/packages/core/components/search-input/index.js
vendored
Normal file
87
web/vendor/htmlburger/carbon-fields/packages/core/components/search-input/index.js
vendored
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import cx from 'classnames';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { Component } from '@wordpress/element';
|
||||
import { omit } from 'lodash';
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
|
||||
/**
|
||||
* The keycode used to represent the "Enter" key.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
const KEY_ENTER = 13;
|
||||
|
||||
class SearchInput extends Component {
|
||||
/**
|
||||
* Default properties.
|
||||
*
|
||||
* TODO: Use `@wordpress/i18n` for translations.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
static defaultProps = {
|
||||
placeholder: __( 'Search...', 'carbon-fields-ui' )
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles change event of input.
|
||||
*
|
||||
* @param {Object} e
|
||||
* @return {void}
|
||||
*/
|
||||
handleChange = ( e ) => {
|
||||
this.props.onChange( e.target.value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles keydown event of input.
|
||||
*
|
||||
* @param {Object} e
|
||||
* @return {void}
|
||||
*/
|
||||
handleKeyDown = ( e ) => {
|
||||
if ( e.keyCode === KEY_ENTER ) {
|
||||
e.preventDefault();
|
||||
|
||||
this.props.onChange( e.target.value );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
value,
|
||||
className,
|
||||
...props
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div className={ cx( 'cf-search-input dashicons-before dashicons-search', className ) }>
|
||||
<input
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
className="cf-search-input__inner"
|
||||
defaultValue={ value }
|
||||
onChange={ this.handleChange }
|
||||
onKeyDown={ this.handleKeyDown }
|
||||
{ ...omit( props, [
|
||||
'onChange'
|
||||
] ) }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default SearchInput;
|
||||
50
web/vendor/htmlburger/carbon-fields/packages/core/components/search-input/style.scss
vendored
Normal file
50
web/vendor/htmlburger/carbon-fields/packages/core/components/search-input/style.scss
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/* ==========================================================================
|
||||
Search Input
|
||||
========================================================================== */
|
||||
|
||||
.cf-search-input {
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 9px;
|
||||
margin-top: -10px;
|
||||
|
||||
.postbox & {
|
||||
color: $wp-color-base-gray;
|
||||
}
|
||||
|
||||
.wp-block & {
|
||||
color: $gb-dark-gray-500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cf-search-input__inner {
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
|
||||
.cf-container &,
|
||||
.block-editor .cf-field & {
|
||||
padding-left: 35px;
|
||||
}
|
||||
|
||||
.cf-container & {
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
border-color: $wp-color-gray-light-500;
|
||||
}
|
||||
|
||||
.block-editor .cf-container &,
|
||||
.wp-block .cf-field &,
|
||||
.edit-post-sidebar .cf-block__fields & {
|
||||
border-radius: 0;
|
||||
border: 0;
|
||||
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
107
web/vendor/htmlburger/carbon-fields/packages/core/components/sortable/index.js
vendored
Normal file
107
web/vendor/htmlburger/carbon-fields/packages/core/components/sortable/index.js
vendored
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import produce from 'immer';
|
||||
import { Component, Children } from '@wordpress/element';
|
||||
|
||||
class Sortable extends Component {
|
||||
/**
|
||||
* Lifecycle hook.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
componentDidMount() {
|
||||
const { options, forwardedRef } = this.props;
|
||||
|
||||
window.jQuery( forwardedRef.current ).sortable( {
|
||||
...options,
|
||||
start: this.handleStart,
|
||||
update: this.handleUpdate,
|
||||
stop: this.handleStop
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifecycle hook.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
const { forwardedRef } = this.props;
|
||||
const $element = window.jQuery( forwardedRef.current );
|
||||
const instance = $element.sortable( 'instance' );
|
||||
|
||||
if ( instance ) {
|
||||
$element.sortable( 'destroy' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the `start` event.
|
||||
*
|
||||
* @param {Object} e
|
||||
* @param {Object} ui
|
||||
* @return {void}
|
||||
*/
|
||||
handleStart = ( e, ui ) => {
|
||||
const { onStart } = this.props;
|
||||
|
||||
if ( onStart ) {
|
||||
onStart( e, ui );
|
||||
}
|
||||
|
||||
ui.item.data( 'index', ui.item.index() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the `update` event.
|
||||
*
|
||||
* @param {Object} e
|
||||
* @param {Object} ui
|
||||
* @return {void}
|
||||
*/
|
||||
handleUpdate = ( e, ui ) => {
|
||||
const {
|
||||
items,
|
||||
forwardedRef,
|
||||
onUpdate
|
||||
} = this.props;
|
||||
|
||||
const oldIndex = ui.item.data( 'index' );
|
||||
const newIndex = ui.item.index();
|
||||
|
||||
ui.item.removeData( 'index' );
|
||||
|
||||
window.jQuery( forwardedRef.current ).sortable( 'cancel' );
|
||||
|
||||
onUpdate( produce( items, ( draft ) => {
|
||||
draft.splice( newIndex, 0, ...draft.splice( oldIndex, 1 ) );
|
||||
} ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the `stop` event.
|
||||
*
|
||||
* @param {Object} e
|
||||
* @param {Object} ui
|
||||
* @return {void}
|
||||
*/
|
||||
handleStop = ( e, ui ) => {
|
||||
const { onStop } = this.props;
|
||||
|
||||
if ( onStop ) {
|
||||
onStop( e, ui );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
return Children.only( this.props.children );
|
||||
}
|
||||
}
|
||||
|
||||
export default Sortable;
|
||||
532
web/vendor/htmlburger/carbon-fields/packages/core/fields/association/index.js
vendored
Normal file
532
web/vendor/htmlburger/carbon-fields/packages/core/fields/association/index.js
vendored
Normal file
|
|
@ -0,0 +1,532 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import produce from 'immer';
|
||||
import { __, sprintf } from '@wordpress/i18n';
|
||||
import {
|
||||
Component,
|
||||
Fragment,
|
||||
createRef
|
||||
} from '@wordpress/element';
|
||||
import { compose, withState } from '@wordpress/compose';
|
||||
import { addFilter } from '@wordpress/hooks';
|
||||
import { withEffects, toProps } from 'refract-callbag';
|
||||
import cx from 'classnames';
|
||||
import {
|
||||
find,
|
||||
pick,
|
||||
without,
|
||||
isMatch,
|
||||
isEmpty,
|
||||
debounce
|
||||
} from 'lodash';
|
||||
import {
|
||||
combine,
|
||||
map,
|
||||
merge,
|
||||
pipe
|
||||
} from 'callbag-basics';
|
||||
import of from 'callbag-of';
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
import SearchInput from '../../components/search-input';
|
||||
import Sortable from '../../components/sortable';
|
||||
import apiFetch from '../../utils/api-fetch';
|
||||
|
||||
class AssociationField extends Component {
|
||||
/**
|
||||
* Keeps reference to the DOM node that contains the selected items.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
selectedList = createRef();
|
||||
|
||||
/**
|
||||
* Keeps reference to the DOM bnode that contains the options.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
sourceList = createRef();
|
||||
|
||||
/**
|
||||
* Lifecycle hook.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
componentDidMount() {
|
||||
const {
|
||||
fetchSelectedOptions,
|
||||
field,
|
||||
value,
|
||||
setState
|
||||
} = this.props;
|
||||
|
||||
setState( {
|
||||
options: field.options.options,
|
||||
totalOptionsCount: field.options.total_options
|
||||
} );
|
||||
|
||||
if ( value.length ) {
|
||||
fetchSelectedOptions();
|
||||
}
|
||||
|
||||
this.sourceList.current.addEventListener( 'scroll', this.handleSourceListScroll );
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifecycle hook.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
this.sourceList.current.removeEventListener( 'scroll', this.handleSourceListScroll );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the scroll event of the source list.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
handleSourceListScroll = () => {
|
||||
const {
|
||||
fetchOptions,
|
||||
setState,
|
||||
options,
|
||||
page,
|
||||
queryTerm
|
||||
} = this.props;
|
||||
|
||||
const sourceList = this.sourceList.current;
|
||||
|
||||
if ( sourceList.offsetHeight + sourceList.scrollTop === sourceList.scrollHeight ) {
|
||||
setState( {
|
||||
page: page + 1
|
||||
} );
|
||||
|
||||
fetchOptions( {
|
||||
type: 'append',
|
||||
options: options,
|
||||
queryTerm,
|
||||
page: page + 1
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the change of search.
|
||||
*
|
||||
* @param {string} queryTerm
|
||||
* @return {void}
|
||||
*/
|
||||
handleSearchChange = debounce( ( queryTerm ) => {
|
||||
const {
|
||||
fetchOptions,
|
||||
setState
|
||||
} = this.props;
|
||||
|
||||
setState( {
|
||||
page: 1,
|
||||
queryTerm
|
||||
} );
|
||||
|
||||
fetchOptions( {
|
||||
type: 'replace',
|
||||
page: 1,
|
||||
queryTerm
|
||||
} );
|
||||
}, 250 )
|
||||
|
||||
/**
|
||||
* Handles addition of a new item.
|
||||
*
|
||||
* @param {Array} option
|
||||
* @return {void}
|
||||
*/
|
||||
handleAddItem = ( option ) => {
|
||||
const {
|
||||
field,
|
||||
id,
|
||||
value,
|
||||
onChange,
|
||||
setState,
|
||||
selectedOptions
|
||||
} = this.props;
|
||||
|
||||
// Don't do anything if the duplicates aren't allowed and
|
||||
// the item is already selected.
|
||||
if ( ! field.duplicates_allowed && option.disabled ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't do anything, because the maximum is reached.
|
||||
if ( field.max > 0 && value.length >= field.max ) {
|
||||
// eslint-disable-next-line no-alert
|
||||
alert(
|
||||
sprintf(
|
||||
__( 'Maximum number of items reached (%s items)', 'carbon-fields-ui' ),
|
||||
Number( field.max )
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
onChange( id, [
|
||||
...value,
|
||||
pick( option, 'id', 'type', 'subtype' )
|
||||
] );
|
||||
|
||||
setState( {
|
||||
selectedOptions: [ ...selectedOptions, option ]
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles addition of a new item.
|
||||
*
|
||||
* @param {Array} option
|
||||
* @return {void}
|
||||
*/
|
||||
handleRemoveItem = ( option ) => {
|
||||
const {
|
||||
value,
|
||||
id,
|
||||
onChange,
|
||||
setState,
|
||||
selectedOptions
|
||||
} = this.props;
|
||||
|
||||
onChange( id, without( value, option ) );
|
||||
setState( {
|
||||
selectedOptions: without( selectedOptions, option )
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles sorting of selected options.
|
||||
*
|
||||
* @param {Object[]} items
|
||||
* @return {void}
|
||||
*/
|
||||
handleSort = ( items ) => {
|
||||
const { id, onChange } = this.props;
|
||||
|
||||
onChange( id, items );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
value,
|
||||
field,
|
||||
totalOptionsCount,
|
||||
selectedOptions,
|
||||
queryTerm,
|
||||
isLoading
|
||||
} = this.props;
|
||||
|
||||
let { options } = this.props;
|
||||
|
||||
if ( ! field.duplicates_allowed ) {
|
||||
options = produce( options, ( draft ) => {
|
||||
draft.map( ( option ) => {
|
||||
option.disabled = !! find( value, ( selectedOption ) => isMatch( selectedOption, {
|
||||
id: option.id,
|
||||
type: option.type,
|
||||
subtype: option.subtype
|
||||
} ) );
|
||||
|
||||
return option;
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<div className="cf-association__bar">
|
||||
<SearchInput
|
||||
id={ id }
|
||||
value={ queryTerm }
|
||||
onChange={ this.handleSearchChange }
|
||||
/>
|
||||
|
||||
{
|
||||
isLoading
|
||||
? <span className="cf-association__spinner spinner is-active"></span>
|
||||
: ''
|
||||
}
|
||||
|
||||
<span className="cf-association__counter">
|
||||
{ sprintf(
|
||||
__( 'Showing %1$d of %2$d results', 'carbon-fields-ui' ),
|
||||
Number( options.length ),
|
||||
Number( totalOptionsCount )
|
||||
) }
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="cf-association__cols">
|
||||
<div className="cf-association__col" ref={ this.sourceList }>
|
||||
{
|
||||
options.map( ( option, index ) => {
|
||||
return (
|
||||
<div className={ cx( 'cf-association__option', { 'cf-association__option--selected': option.disabled } ) } key={ index }>
|
||||
{ option.thumbnail && (
|
||||
<img className="cf-association__option-thumb" alt={ __( 'Thumbnail', 'carbon-fields-ui' ) } src={ option.thumbnail } />
|
||||
) }
|
||||
|
||||
<div className="cf-association__option-content">
|
||||
<span className="cf-association__option-title">
|
||||
<span className="cf-association__option-title-inner">
|
||||
{ option.title }
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span className="cf-association__option-type">
|
||||
{ option.label }
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="cf-association__option-actions">
|
||||
{ option.edit_link && (
|
||||
<a
|
||||
className="cf-association__option-action cf-association__option-action--edit dashicons dashicons-edit"
|
||||
href={ option.edit_link.replace( '&', '&', 'g' ) }
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label={ __( 'Edit', 'carbon-fields-ui' ) }
|
||||
></a>
|
||||
) }
|
||||
|
||||
{ (
|
||||
! option.disabled
|
||||
&& ( field.max < 0 || value.length < field.max )
|
||||
) && (
|
||||
<button type="button" className="cf-association__option-action dashicons dashicons-plus-alt" aria-label={ __( 'Add', 'carbon-fields-ui' ) } onClick={ () => this.handleAddItem( option ) }>
|
||||
</button>
|
||||
) }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} )
|
||||
}
|
||||
</div>
|
||||
|
||||
<Sortable
|
||||
forwardedRef={ this.selectedList }
|
||||
items={ value }
|
||||
options={ {
|
||||
axis: 'y',
|
||||
forceHelperSize: true,
|
||||
forcePlaceholderSize: true,
|
||||
scroll: true,
|
||||
handle: '.cf-association__option-sort'
|
||||
} }
|
||||
onUpdate={ this.handleSort }
|
||||
>
|
||||
<div className="cf-association__col" ref={ this.selectedList }>
|
||||
{
|
||||
!! selectedOptions.length && value.map( ( option, index ) => {
|
||||
const optionData = selectedOptions.find( ( selectedOption ) => {
|
||||
return selectedOption.id === option.id
|
||||
&& selectedOption.type === option.type
|
||||
&& selectedOption.subtype === option.subtype;
|
||||
} );
|
||||
|
||||
return (
|
||||
<div className="cf-association__option" key={ index }>
|
||||
<span className="cf-association__option-sort dashicons dashicons-menu"></span>
|
||||
|
||||
{ optionData.thumbnail && (
|
||||
<img className="cf-association__option-thumb" src={ optionData.thumbnail } />
|
||||
) }
|
||||
|
||||
<div className="cf-association__option-content">
|
||||
<span className="cf-association__option-title">
|
||||
<span className="cf-association__option-title-inner">
|
||||
{ optionData.title }
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span className="cf-association__option-type">
|
||||
{ optionData.type }
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="cf-association__option-actions">
|
||||
<button type="button" className="cf-association__option-action dashicons dashicons-dismiss" aria-label={ __( 'Remove', 'carbon-fields-ui' ) } onClick={ () => this.handleRemoveItem( option ) }></button>
|
||||
</div>
|
||||
|
||||
<input
|
||||
type="hidden"
|
||||
name={ `${ name }[${ index }]` }
|
||||
value={ `${ optionData.type }:${ optionData.subtype }:${ optionData.id }` }
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
} )
|
||||
}
|
||||
</div>
|
||||
</Sortable>
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The function that controls the stream of side-effects.
|
||||
*
|
||||
* @param {Object} component
|
||||
* @return {Object}
|
||||
*/
|
||||
function aperture( component ) {
|
||||
const actions = [
|
||||
{ event: 'fetchOptionsEvent', prop: 'fetchOptions', type: 'FETCH_OPTIONS' },
|
||||
{ event: 'fetchSelectedOptionsEvent', prop: 'fetchSelectedOptions', type: 'FETCH_SELECTED_OPTIONS' }
|
||||
].map( ( actionData ) => {
|
||||
const [ actionChannel$, action ] = component.useEvent( actionData.event );
|
||||
|
||||
return {
|
||||
...actionData,
|
||||
action,
|
||||
channel$: actionChannel$
|
||||
};
|
||||
} );
|
||||
|
||||
const combined$ = pipe(
|
||||
combine( ...actions.map( ( { action, prop } ) => of( {
|
||||
action,
|
||||
prop
|
||||
} ) ) ),
|
||||
map( ( combinedActions ) => toProps( combinedActions.reduce(
|
||||
( acc, curr ) => ( {
|
||||
...acc,
|
||||
[ curr.prop ]: curr.action
|
||||
} ), {}
|
||||
) ) )
|
||||
);
|
||||
|
||||
return merge(
|
||||
combined$,
|
||||
...actions.map( ( { channel$, type } ) => pipe(
|
||||
channel$,
|
||||
map( ( payload ) => ( {
|
||||
type,
|
||||
payload
|
||||
} ) )
|
||||
) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The function that causes the side effects.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @return {Function}
|
||||
*/
|
||||
function handler( props ) {
|
||||
return function( effect ) {
|
||||
const { payload, type } = effect;
|
||||
const {
|
||||
setState,
|
||||
selectedOptions,
|
||||
hierarchyResolver
|
||||
} = props;
|
||||
|
||||
switch ( type ) {
|
||||
case 'FETCH_OPTIONS':
|
||||
setState( {
|
||||
isLoading: true
|
||||
} );
|
||||
|
||||
// eslint-disable-next-line
|
||||
const request = apiFetch(
|
||||
`${ window.wpApiSettings.root }carbon-fields/v1/association/options`,
|
||||
'get',
|
||||
{
|
||||
container_id: props.containerId,
|
||||
options: props.value.map( ( option ) => `${ option.id }:${ option.type }:${ option.subtype }` ).join( ';' ),
|
||||
field_id: hierarchyResolver,
|
||||
term: payload.queryTerm,
|
||||
page: payload.page || 1
|
||||
}
|
||||
);
|
||||
|
||||
/* eslint-disable-next-line no-alert */
|
||||
const errorHandler = () => alert( __( 'An error occurred while trying to fetch association options.', 'carbon-fields-ui' ) );
|
||||
|
||||
request.then( ( response ) => {
|
||||
setState( {
|
||||
options: payload.type === 'replace' ? response.options : [ ...payload.options, ...response.options ],
|
||||
totalOptionsCount: response.total_options
|
||||
} );
|
||||
} );
|
||||
|
||||
request.catch( errorHandler );
|
||||
request.finally( () => {
|
||||
setState( {
|
||||
isLoading: false
|
||||
} );
|
||||
} );
|
||||
break;
|
||||
|
||||
case 'FETCH_SELECTED_OPTIONS':
|
||||
apiFetch(
|
||||
`${ window.wpApiSettings.root }carbon-fields/v1/association/`,
|
||||
'get',
|
||||
{
|
||||
container_id: props.containerId,
|
||||
options: props.value.map( ( option ) => `${ option.id }:${ option.type }:${ option.subtype }` ).join( ';' ),
|
||||
field_id: hierarchyResolver
|
||||
}
|
||||
)
|
||||
.then( ( response ) => {
|
||||
setState( {
|
||||
selectedOptions: [ ...selectedOptions, ...response ]
|
||||
} );
|
||||
} );
|
||||
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const applyWithState = withState( {
|
||||
options: [],
|
||||
selectedOptions: [],
|
||||
totalOptionsCount: 0,
|
||||
queryTerm: '',
|
||||
page: 1,
|
||||
isLoading: false
|
||||
} );
|
||||
|
||||
const applyWithEffects = withEffects( aperture, { handler } );
|
||||
|
||||
addFilter( 'carbon-fields.association.validate', 'carbon-fields/core', ( field, value ) => {
|
||||
const { min, required } = field;
|
||||
|
||||
if ( required && isEmpty( value ) ) {
|
||||
return __( 'This field is required.', 'carbon-fields-ui' );
|
||||
}
|
||||
|
||||
if ( min > 0 && value.length < min ) {
|
||||
return sprintf( __( 'Minimum number of items not reached (%s items)', 'carbon-fields-ui' ), [ field.min ] );
|
||||
}
|
||||
|
||||
return null;
|
||||
} );
|
||||
|
||||
export default compose(
|
||||
applyWithState,
|
||||
applyWithEffects
|
||||
)( AssociationField );
|
||||
207
web/vendor/htmlburger/carbon-fields/packages/core/fields/association/style.scss
vendored
Normal file
207
web/vendor/htmlburger/carbon-fields/packages/core/fields/association/style.scss
vendored
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
/* ==========================================================================
|
||||
Association
|
||||
========================================================================== */
|
||||
|
||||
.container-carbon_fields_container_word_settings {
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cf-container .cf-field {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.cf-association__bar {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
border-color: $wp-color-gray-light-500;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
|
||||
.cf-search-input {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.cf-search-input__inner {
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
|
||||
&:focus {
|
||||
border-color: none;
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:focus-within {
|
||||
border-color: #5b9dd9;
|
||||
box-shadow: 0 0 2px rgba( 30, 140, 190, 0.8 );
|
||||
outline: 2px solid transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-association__counter {
|
||||
font-size: 12px;
|
||||
color: $wp-color-dark-gray;
|
||||
pointer-events: none;
|
||||
margin-right: 10px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.cf-association__spinner {
|
||||
float: none;
|
||||
margin: 0;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.cf-association__cols {
|
||||
background: #fff;
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
display: flex;
|
||||
border-width: 0 1px 1px;
|
||||
border-style: solid;
|
||||
border-color: $wp-color-gray-light-500;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
width: 1px;
|
||||
height: 100%;
|
||||
background-color: $wp-color-gray-light-500;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
|
||||
.cf-association__col {
|
||||
width: 50%;
|
||||
max-height: 160px;
|
||||
overflow-y: auto;
|
||||
|
||||
&.ui-sortable .cf-association__option-title {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.edit-post-sidebar .cf-association__cols & {
|
||||
width: 100%;
|
||||
|
||||
&:first-child {
|
||||
border-bottom: 3px solid $wp-color-dark-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cf-association__option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px 8px;
|
||||
height: 32px;
|
||||
box-sizing: border-box;
|
||||
|
||||
&--selected {
|
||||
background-color: $wp-color-gray-light-100;
|
||||
}
|
||||
|
||||
& + & {
|
||||
border-top: 1px solid $wp-color-gray-light-500;
|
||||
}
|
||||
|
||||
&.ui-sortable-helper {
|
||||
border-top: 0;
|
||||
background-color: $wp-color-gray-light-100;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-association__option-thumb {
|
||||
flex: none;
|
||||
display: block;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.cf-association__option-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.cf-association__option-title {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
margin-right: $size-base;
|
||||
|
||||
.cf-association__option--selected & {
|
||||
color: $wp-color-dark-silver-gray;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-association__option-title-inner {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
font-size: $wp-font-size;
|
||||
line-height: $wp-line-height;
|
||||
color: $wp-color-base-gray;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.cf-association__option-type {
|
||||
font-size: 9px;
|
||||
line-height: 1;
|
||||
text-transform: uppercase;
|
||||
color: $wp-color-dark-silver-gray;
|
||||
|
||||
.edit-post-sidebar .cf-association__col & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-association__option-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
button {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-association__option-sort {
|
||||
margin-right: 4px;
|
||||
color: $wp-color-dark-silver-gray;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.cf-association__option-action {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
outline: none;
|
||||
color: $wp-color-dark-silver-gray;
|
||||
transition: color $transition-base;
|
||||
cursor: pointer;
|
||||
background: transparent;
|
||||
|
||||
&:focus {
|
||||
color: $wp-color-dark-silver-gray;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: $wp-color-dark-gray;
|
||||
}
|
||||
}
|
||||
21
web/vendor/htmlburger/carbon-fields/packages/core/fields/block-preview/index.js
vendored
Normal file
21
web/vendor/htmlburger/carbon-fields/packages/core/fields/block-preview/index.js
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { RawHTML } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Renders the field.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @param {Object} props.field
|
||||
* @return {Object}
|
||||
*/
|
||||
function BlockPreviewField( { field } ) {
|
||||
return (
|
||||
<RawHTML className="cf-html__content cf-html__content--block-preview">
|
||||
{ field.html }
|
||||
</RawHTML>
|
||||
);
|
||||
}
|
||||
|
||||
export default BlockPreviewField;
|
||||
58
web/vendor/htmlburger/carbon-fields/packages/core/fields/checkbox/index.js
vendored
Normal file
58
web/vendor/htmlburger/carbon-fields/packages/core/fields/checkbox/index.js
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { Component, Fragment } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
|
||||
class CheckboxField extends Component {
|
||||
/**
|
||||
* Handles the change of the input.
|
||||
*
|
||||
* @param {Object} e
|
||||
* @return {void}
|
||||
*/
|
||||
handleChange = ( e ) => {
|
||||
const { id, onChange } = this.props;
|
||||
|
||||
onChange( id, e.target.checked );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
value,
|
||||
field
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<input
|
||||
type="checkbox"
|
||||
id={ id }
|
||||
name={ name }
|
||||
checked={ value }
|
||||
value={ value ? field.option_value : '' }
|
||||
className="cf-checkbox__input"
|
||||
onChange={ this.handleChange }
|
||||
{ ...field.attributes }
|
||||
/>
|
||||
|
||||
<label className="cf-checkbox__label" htmlFor={ id }>
|
||||
{ field.option_label }
|
||||
</label>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default CheckboxField;
|
||||
13
web/vendor/htmlburger/carbon-fields/packages/core/fields/checkbox/style.scss
vendored
Normal file
13
web/vendor/htmlburger/carbon-fields/packages/core/fields/checkbox/style.scss
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
/* ==========================================================================
|
||||
Checkbox
|
||||
========================================================================== */
|
||||
|
||||
.cf-checkbox__input {
|
||||
.cf-field & {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-checkbox__label {
|
||||
font-size: 13px;
|
||||
}
|
||||
114
web/vendor/htmlburger/carbon-fields/packages/core/fields/color/index.js
vendored
Normal file
114
web/vendor/htmlburger/carbon-fields/packages/core/fields/color/index.js
vendored
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { Component } from '@wordpress/element';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { get } from 'lodash';
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
import Picker from './picker';
|
||||
import { hexToRgba, rgbaToHex } from '../../utils/hex-and-rgba';
|
||||
|
||||
class ColorField extends Component {
|
||||
/**
|
||||
* Defines the initial state.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
state = {
|
||||
showPicker: false
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the RGBA format of the currently set color
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
getBackgroundColor = () => {
|
||||
const { field, value } = this.props;
|
||||
|
||||
const colorHex = value ? value : '#FFFFFFFF';
|
||||
const [ r, g, b, a ] = hexToRgba( colorHex );
|
||||
const rgbaColor = { r, g, b, a: field.alphaEnabled ? a : 1 };
|
||||
|
||||
return `rgba(${ Object.values( rgbaColor ).join( ', ' ) })`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the change of the input.
|
||||
*
|
||||
* @param {Object} [color]
|
||||
* @return {void}
|
||||
*/
|
||||
handleChange = ( color ) => {
|
||||
const { id, onChange, field } = this.props;
|
||||
|
||||
let value = get( color, 'hex', '' ).toUpperCase();
|
||||
|
||||
if ( field.alphaEnabled ) {
|
||||
value = rgbaToHex( get( color, 'rgb', null ) );
|
||||
}
|
||||
|
||||
onChange( id, value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the visibility of the color picker component
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
togglePicker = () => this.setState( { showPicker: ! this.state.showPicker } )
|
||||
|
||||
/**
|
||||
* Render a color input field.
|
||||
*
|
||||
* @return {React.Element}
|
||||
*/
|
||||
render() {
|
||||
const { showPicker } = this.state;
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
value,
|
||||
field
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div className="cf-color__inner">
|
||||
<input
|
||||
type="hidden"
|
||||
id={ id }
|
||||
name={ name }
|
||||
value={ value }
|
||||
/>
|
||||
|
||||
<button type="button" className="button cf-color__toggle" onClick={ this.togglePicker }>
|
||||
<span className="cf-color__preview" style={ { backgroundColor: this.getBackgroundColor() } }></span>
|
||||
|
||||
<span className="cf-color__toggle-text">
|
||||
{ __( 'Select a color', 'carbon-fields-ui' ) }
|
||||
</span>
|
||||
</button>
|
||||
|
||||
{ showPicker && (
|
||||
<Picker
|
||||
color={ value }
|
||||
onChange={ this.handleChange }
|
||||
disableAlpha={ ! field.alphaEnabled }
|
||||
presetColors={ field.palette }
|
||||
onClose={ () => showPicker ? this.togglePicker() : null }
|
||||
/>
|
||||
) }
|
||||
|
||||
<button type="button" className="button-link cf-color__reset" aria-label={ __( 'Clear', 'carbon-fields-ui' ) } onClick={ () => this.handleChange() }>
|
||||
<span className="dashicons dashicons-no"></span>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ColorField;
|
||||
42
web/vendor/htmlburger/carbon-fields/packages/core/fields/color/picker.js
vendored
Normal file
42
web/vendor/htmlburger/carbon-fields/packages/core/fields/color/picker.js
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { Component } from '@wordpress/element';
|
||||
import { SketchPicker } from 'react-color';
|
||||
import onClickOutside from 'react-onclickoutside';
|
||||
|
||||
class Picker extends Component {
|
||||
/**
|
||||
* Handles the click outside the main element.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
handleClickOutside = () => this.props.onClose()
|
||||
|
||||
/**
|
||||
* Render the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
color,
|
||||
onChange,
|
||||
disableAlpha,
|
||||
presetColors
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div id="carbon-color-picker-wrapper" className="cf-color__picker">
|
||||
<SketchPicker
|
||||
color={ color }
|
||||
onChange={ onChange }
|
||||
disableAlpha={ disableAlpha }
|
||||
presetColors={ presetColors }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default onClickOutside( Picker );
|
||||
47
web/vendor/htmlburger/carbon-fields/packages/core/fields/color/style.scss
vendored
Normal file
47
web/vendor/htmlburger/carbon-fields/packages/core/fields/color/style.scss
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/* ==========================================================================
|
||||
Color
|
||||
========================================================================== */
|
||||
|
||||
.cf-color__inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.cf-color__toggle {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.cf-color__toggle-text {
|
||||
margin-left: 27px;
|
||||
}
|
||||
|
||||
.cf-color__preview {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 26px;
|
||||
height: 100%;
|
||||
border-right: 1px solid #ccc;
|
||||
|
||||
.cf-color__toggle:hover &,
|
||||
.cf-color__toggle:active & {
|
||||
border-color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-color__reset {
|
||||
.cf-color & {
|
||||
margin-left: 5px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.cf-color &:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-color__picker {
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
}
|
||||
182
web/vendor/htmlburger/carbon-fields/packages/core/fields/complex/group.js
vendored
Normal file
182
web/vendor/htmlburger/carbon-fields/packages/core/fields/complex/group.js
vendored
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import cx from 'classnames';
|
||||
import { Component } from '@wordpress/element';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import { getFieldType } from '../../registry/fields';
|
||||
|
||||
class ComplexGroup extends Component {
|
||||
/**
|
||||
* Handles the click on the "Toggle" button.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
handleToggleClick = () => {
|
||||
const {
|
||||
id,
|
||||
onToggle
|
||||
} = this.props;
|
||||
|
||||
onToggle( id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the click on the "Clone" button.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
handleCloneClick = () => {
|
||||
const {
|
||||
id,
|
||||
onClone
|
||||
} = this.props;
|
||||
|
||||
onClone( id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the click on the "Remove" button.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
handleRemoveClick = () => {
|
||||
const {
|
||||
id,
|
||||
onRemove
|
||||
} = this.props;
|
||||
|
||||
onRemove( id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
index,
|
||||
label,
|
||||
name,
|
||||
prefix,
|
||||
tabbed,
|
||||
hidden,
|
||||
dragged,
|
||||
collapsed,
|
||||
allowClone,
|
||||
fields,
|
||||
context,
|
||||
onFieldSetup
|
||||
} = this.props;
|
||||
|
||||
const groupClasses = cx(
|
||||
'cf-complex__group',
|
||||
{
|
||||
'cf-complex__group--grid': ! tabbed,
|
||||
'cf-complex__group--tabbed': tabbed,
|
||||
'cf-complex__group--collapsed': collapsed,
|
||||
'cf-complex__group--dragged': dragged
|
||||
}
|
||||
);
|
||||
|
||||
const toggleClasses = cx(
|
||||
'dashicons-before',
|
||||
'cf-complex__group-action-icon',
|
||||
{
|
||||
'dashicons-arrow-up': ! collapsed,
|
||||
'dashicons-arrow-down': collapsed
|
||||
}
|
||||
);
|
||||
|
||||
const actionsClasses = cx(
|
||||
'cf-complex__group-actions',
|
||||
{
|
||||
'cf-complex__group-actions--grid': ! tabbed,
|
||||
'cf-complex__group-actions--tabbed': tabbed
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={ groupClasses } hidden={ hidden }>
|
||||
{ name && (
|
||||
<input
|
||||
type="hidden"
|
||||
name={ `${ prefix }[value]` }
|
||||
value={ name }
|
||||
/>
|
||||
) }
|
||||
|
||||
{ ! tabbed && (
|
||||
<div className="cf-complex__group-head">
|
||||
<span className="cf-complex__group-index">
|
||||
{ index + 1 }
|
||||
</span>
|
||||
|
||||
<span className="cf-complex__group-title">
|
||||
{ label }
|
||||
</span>
|
||||
</div>
|
||||
) }
|
||||
|
||||
{ ! dragged && (
|
||||
<div className="cf-complex__group-body" hidden={ ! tabbed && collapsed }>
|
||||
{ fields.map( ( field ) => {
|
||||
const FieldEdit = getFieldType( field.type, context );
|
||||
|
||||
if ( ! FieldEdit ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const [ Field, props ] = onFieldSetup( field, {}, this.props );
|
||||
|
||||
return (
|
||||
// The `key` will be assigned via `onFieldSetup`.
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<Field { ...props }>
|
||||
<FieldEdit { ...props } />
|
||||
</Field>
|
||||
);
|
||||
} ) }
|
||||
</div>
|
||||
) }
|
||||
|
||||
<div className={ actionsClasses }>
|
||||
{ allowClone && (
|
||||
<button type="button" title={ __( 'Duplicate', 'carbon-fields-ui' ) } className="cf-complex__group-action" onClick={ this.handleCloneClick }>
|
||||
<span className="dashicons-before dashicons-admin-page cf-complex__group-action-icon"></span>
|
||||
|
||||
<span className="cf-complex__group-action-text">
|
||||
{ __( 'Duplicate', 'carbon-fields-ui' ) }
|
||||
</span>
|
||||
</button>
|
||||
) }
|
||||
|
||||
<button type="button" title={ __( 'Remove', 'carbon-fields-ui' ) } className="cf-complex__group-action" onClick={ this.handleRemoveClick }>
|
||||
<span className="dashicons-before dashicons-trash cf-complex__group-action-icon"></span>
|
||||
|
||||
<span className="cf-complex__group-action-text">
|
||||
{ __( 'Remove', 'carbon-fields-ui' ) }
|
||||
</span>
|
||||
</button>
|
||||
|
||||
{ ! tabbed && (
|
||||
<button type="button" title={ __( 'Collapse', 'carbon-fields-ui' ) } className="cf-complex__group-action" onClick={ this.handleToggleClick }>
|
||||
<span className={ toggleClasses }></span>
|
||||
|
||||
<span className="cf-complex__group-action-text">
|
||||
{ __( 'Collapse', 'carbon-fields-ui' ) }
|
||||
</span>
|
||||
</button>
|
||||
) }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ComplexGroup;
|
||||
444
web/vendor/htmlburger/carbon-fields/packages/core/fields/complex/index.js
vendored
Normal file
444
web/vendor/htmlburger/carbon-fields/packages/core/fields/complex/index.js
vendored
Normal file
|
|
@ -0,0 +1,444 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { addFilter } from '@wordpress/hooks';
|
||||
import {
|
||||
Component,
|
||||
Fragment,
|
||||
createRef
|
||||
} from '@wordpress/element';
|
||||
import { __, sprintf } from '@wordpress/i18n';
|
||||
import {
|
||||
get,
|
||||
find,
|
||||
isEmpty,
|
||||
isString,
|
||||
template
|
||||
} from 'lodash';
|
||||
|
||||
/**
|
||||
* The internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
import Sortable from '../../components/sortable';
|
||||
import ComplexTabs from './tabs';
|
||||
import ComplexInserter from './inserter';
|
||||
import ComplexGroup from './group';
|
||||
import ComplexPlaceholder from './placeholder';
|
||||
|
||||
class ComplexField extends Component {
|
||||
/**
|
||||
* Keeps reference to the DOM that contains the groups.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
groupsList = createRef();
|
||||
|
||||
/**
|
||||
* Keeps reference to the DOM that contains the tabs.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
tabsList = createRef();
|
||||
|
||||
/**
|
||||
* Local state.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
state = {
|
||||
currentDraggedGroup: null,
|
||||
currentTab: get( this.props.value, `0.${ this.props.groupIdKey }`, null )
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the field is using tabs for the layout.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
get isTabbed() {
|
||||
return this.props.field.layout.indexOf( 'tabbed' ) > -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the maximum number of entries is reached.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
get isMaximumReached() {
|
||||
const { field, value } = this.props;
|
||||
|
||||
return field.max > 0 && value.length >= field.max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text used in "Add Entry" button.
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
get inserterButtonText() {
|
||||
const { field } = this.props;
|
||||
|
||||
return sprintf( __( 'Add %s', 'carbon-fields-ui' ), field.labels.singular_name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a group.
|
||||
*
|
||||
* @param {string} groupId
|
||||
* @return {?Object}
|
||||
*/
|
||||
findGroup( groupId ) {
|
||||
const { value, groupIdKey } = this.props;
|
||||
|
||||
return find( value, [ groupIdKey, groupId ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of groups that can be added if the field
|
||||
* doesn't allow duplicating of groups.
|
||||
*
|
||||
* @param {string} key
|
||||
* @return {Object[]}
|
||||
*/
|
||||
getAvailableGroups( key ) {
|
||||
const { field, value } = this.props;
|
||||
|
||||
if ( field.duplicate_groups_allowed ) {
|
||||
return field.groups;
|
||||
}
|
||||
|
||||
const existingGroupNames = value.map( ( group ) => group[ key ] );
|
||||
|
||||
return field.groups.filter( ( { name } ) => existingGroupNames.indexOf( name ) === -1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of labels of existing groups.
|
||||
*
|
||||
* @return {string[]}
|
||||
*/
|
||||
getGroupLabels() {
|
||||
const { field, groupValues } = this.props;
|
||||
|
||||
return groupValues.map( ( [ name, values ], index ) => {
|
||||
const group = find( field.groups, [ 'name', name ] );
|
||||
|
||||
if ( ! group ) {
|
||||
return 'N/A';
|
||||
}
|
||||
|
||||
if ( ! isString( group.label_template ) ) {
|
||||
return group.label;
|
||||
}
|
||||
|
||||
try {
|
||||
const label = template( group.label_template )( {
|
||||
$_index: index,
|
||||
...values
|
||||
} );
|
||||
|
||||
return label || group.label;
|
||||
} catch ( e ) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(
|
||||
sprintf(
|
||||
__( 'Couldn\'t create the label of group - %s', 'carbon-fields-ui' ),
|
||||
e.message
|
||||
)
|
||||
);
|
||||
|
||||
return 'N/A';
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles adding of group.
|
||||
*
|
||||
* @param {Object} selection
|
||||
* @return {void}
|
||||
*/
|
||||
handleAddGroup = ( selection ) => {
|
||||
const { groupIdKey, onAddGroup } = this.props;
|
||||
|
||||
onAddGroup( selection, ( group ) => {
|
||||
if ( this.isTabbed ) {
|
||||
this.handleTabsChange( group[ groupIdKey ] );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles cloning of group.
|
||||
*
|
||||
* @param {string} groupId
|
||||
* @return {void}
|
||||
*/
|
||||
handleCloneGroup = ( groupId ) => {
|
||||
const { groupIdKey, onCloneGroup } = this.props;
|
||||
|
||||
const group = this.findGroup( groupId );
|
||||
|
||||
onCloneGroup( group, ( clonedGroup ) => {
|
||||
if ( this.isTabbed ) {
|
||||
this.handleTabsChange( clonedGroup[ groupIdKey ] );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles removing of group.
|
||||
*
|
||||
* @param {string} groupId
|
||||
* @return {void}
|
||||
*/
|
||||
handleRemoveGroup = ( groupId ) => {
|
||||
const {
|
||||
value,
|
||||
groupIdKey,
|
||||
onRemoveGroup
|
||||
} = this.props;
|
||||
|
||||
const group = this.findGroup( groupId );
|
||||
|
||||
if ( this.isTabbed ) {
|
||||
const currentIndex = value.indexOf( group );
|
||||
const nextIndex = currentIndex > 0 ? currentIndex - 1 : 1;
|
||||
|
||||
this.setState( {
|
||||
currentTab: get( value, `${ nextIndex }.${ groupIdKey }`, null )
|
||||
} );
|
||||
}
|
||||
|
||||
onRemoveGroup( group );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles click on the "Expand/Collapse All" button.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
handleToggleAllClick = () => {
|
||||
const { allGroupsAreCollapsed, onToggleAllGroups } = this.props;
|
||||
|
||||
onToggleAllGroups( ! allGroupsAreCollapsed );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the start of groups sorting.
|
||||
*
|
||||
* @param {Object} e
|
||||
* @param {Object} ui
|
||||
* @return {void}
|
||||
*/
|
||||
handleGroupsSortStart = ( e, ui ) => {
|
||||
const { value, groupIdKey } = this.props;
|
||||
const index = ui.item.index();
|
||||
const id = get( value, `${ index }.${ groupIdKey }`, null );
|
||||
|
||||
this.setState( {
|
||||
currentDraggedGroup: id
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles sorting of groups.
|
||||
*
|
||||
* @param {Object[]} groups
|
||||
* @return {void}
|
||||
*/
|
||||
handleGroupsSortUpdate = ( groups ) => {
|
||||
const { id, onChange } = this.props;
|
||||
|
||||
onChange( id, groups );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the stop of groups sorting
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
handleGroupsSortStop = () => {
|
||||
this.setState( {
|
||||
currentDraggedGroup: null
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles changing of tabs.
|
||||
*
|
||||
* @param {string} groupId
|
||||
* @return {void}
|
||||
*/
|
||||
handleTabsChange = ( groupId ) => {
|
||||
this.setState( {
|
||||
currentTab: groupId
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
const { currentDraggedGroup, currentTab } = this.state;
|
||||
|
||||
const {
|
||||
value,
|
||||
field,
|
||||
groupIdKey,
|
||||
groupFilterKey,
|
||||
allGroupsAreCollapsed,
|
||||
onGroupSetup,
|
||||
onGroupFieldSetup,
|
||||
onToggleGroup
|
||||
} = this.props;
|
||||
|
||||
const availableGroups = this.getAvailableGroups( groupFilterKey );
|
||||
const groupLabels = this.getGroupLabels();
|
||||
|
||||
// TODO: Move this to a memoized function.
|
||||
const tabs = value.map( ( group, index ) => {
|
||||
const id = group[ groupIdKey ];
|
||||
const label = groupLabels[ index ];
|
||||
|
||||
return {
|
||||
id,
|
||||
label
|
||||
};
|
||||
} );
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{ this.isTabbed && !! value.length && (
|
||||
<Sortable
|
||||
items={ value }
|
||||
forwardedRef={ this.tabsList }
|
||||
options={ {
|
||||
axis: field.layout === 'tabbed-vertical' ? 'y' : 'x',
|
||||
forcePlaceholderSize: true
|
||||
} }
|
||||
onUpdate={ this.handleGroupsSortUpdate }
|
||||
>
|
||||
<ComplexTabs
|
||||
ref={ this.tabsList }
|
||||
items={ tabs }
|
||||
current={ currentTab }
|
||||
layout={ field.layout }
|
||||
onChange={ this.handleTabsChange }
|
||||
>
|
||||
{ !! availableGroups.length && ! this.isMaximumReached && (
|
||||
<ComplexInserter
|
||||
buttonText="+"
|
||||
groups={ availableGroups }
|
||||
onSelect={ this.handleAddGroup }
|
||||
/>
|
||||
) }
|
||||
</ComplexTabs>
|
||||
</Sortable>
|
||||
) }
|
||||
|
||||
{ ! value.length && (
|
||||
<ComplexPlaceholder label={ __( 'There are no entries yet.', 'carbon-fields-ui' ) }>
|
||||
<ComplexInserter
|
||||
buttonText={ this.inserterButtonText }
|
||||
groups={ availableGroups }
|
||||
onSelect={ this.handleAddGroup }
|
||||
/>
|
||||
</ComplexPlaceholder>
|
||||
) }
|
||||
|
||||
{ !! value.length && (
|
||||
<Sortable
|
||||
items={ value }
|
||||
options={ {
|
||||
// axis: 'y',
|
||||
helper: 'clone',
|
||||
handle: '.cf-complex__group-head',
|
||||
placeholder: 'cf-complex__group-placeholder',
|
||||
forceHelperSize: true,
|
||||
forcePlaceholderSize: true
|
||||
} }
|
||||
forwardedRef={ this.groupsList }
|
||||
onStart={ this.handleGroupsSortStart }
|
||||
onUpdate={ this.handleGroupsSortUpdate }
|
||||
onStop={ this.handleGroupsSortStop }
|
||||
>
|
||||
<div className="cf-complex__groups" ref={ this.groupsList }>
|
||||
{ value.map( ( group, index ) => (
|
||||
// The `key` will be assigned via `onGroupSetup`.
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<ComplexGroup key={ `${ group[ groupFilterKey ] }-${ index }` } { ...onGroupSetup( group, {
|
||||
index,
|
||||
label: groupLabels[ index ],
|
||||
dragged: group[ groupIdKey ] === currentDraggedGroup,
|
||||
tabbed: this.isTabbed,
|
||||
hidden: this.isTabbed && group[ groupIdKey ] !== currentTab,
|
||||
allowClone: field.duplicate_groups_allowed && ! this.isMaximumReached,
|
||||
onFieldSetup: onGroupFieldSetup,
|
||||
onClone: this.handleCloneGroup,
|
||||
onRemove: this.handleRemoveGroup,
|
||||
onToggle: onToggleGroup
|
||||
} ) } />
|
||||
) ) }
|
||||
</div>
|
||||
</Sortable>
|
||||
) }
|
||||
|
||||
{ ! this.isTabbed && !! value.length && (
|
||||
<div className="cf-complex__actions">
|
||||
{ !! availableGroups.length && ! this.isMaximumReached && (
|
||||
<ComplexInserter
|
||||
buttonText={ this.inserterButtonText }
|
||||
groups={ availableGroups }
|
||||
onSelect={ this.handleAddGroup }
|
||||
/>
|
||||
) }
|
||||
|
||||
<button type="button" className="button cf-complex__toggler" onClick={ this.handleToggleAllClick }>
|
||||
{ allGroupsAreCollapsed ? __( 'Expand All', 'carbon-fields-ui' ) : __( 'Collapse All', 'carbon-fields-ui' ) }
|
||||
</button>
|
||||
</div>
|
||||
) }
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
addFilter( 'carbon-fields.field-wrapper', 'carbon-fields/core', ( OriginalField ) => ( props ) => {
|
||||
const { field } = props;
|
||||
|
||||
if ( field.type !== 'complex' ) {
|
||||
return <OriginalField { ...props } />;
|
||||
}
|
||||
|
||||
return <OriginalField className={ `cf-complex--${ field.layout }` } { ...props } />;
|
||||
} );
|
||||
|
||||
addFilter( 'carbon-fields.complex.validate', 'carbon-fields/core', ( field, value ) => {
|
||||
const {
|
||||
min,
|
||||
labels,
|
||||
required
|
||||
} = field;
|
||||
|
||||
if ( required && isEmpty( value ) ) {
|
||||
return __( 'This field is required.', 'carbon-fields-ui' );
|
||||
}
|
||||
|
||||
if ( min > 0 && value.length < min ) {
|
||||
const label = min === 1 ? labels.singular_name : labels.plural_name;
|
||||
|
||||
return sprintf(
|
||||
__( 'Minimum number of rows not reached (%1$d %2$s)', 'carbon-fields-ui' ),
|
||||
Number( min ),
|
||||
label.toLowerCase()
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
} );
|
||||
|
||||
export default ComplexField;
|
||||
91
web/vendor/htmlburger/carbon-fields/packages/core/fields/complex/inserter.js
vendored
Normal file
91
web/vendor/htmlburger/carbon-fields/packages/core/fields/complex/inserter.js
vendored
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import onClickOutside from 'react-onclickoutside';
|
||||
import { Component } from '@wordpress/element';
|
||||
|
||||
class ComplexInserter extends Component {
|
||||
/**
|
||||
* Local state.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
state = {
|
||||
menuVisible: false
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the click outside the main element.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
handleClickOutside = () => {
|
||||
this.setState( {
|
||||
menuVisible: false
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the click on the "Add" button.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
handleAddClick = () => {
|
||||
const { groups, onSelect } = this.props;
|
||||
|
||||
if ( groups.length > 1 ) {
|
||||
this.setState( ( { menuVisible } ) => ( {
|
||||
menuVisible: ! menuVisible
|
||||
} ) );
|
||||
} else {
|
||||
onSelect( groups[ 0 ] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the click on an item in the menu.
|
||||
*
|
||||
* @param {Object} group
|
||||
* @return {void}
|
||||
*/
|
||||
handleItemClick = ( group ) => {
|
||||
this.setState( {
|
||||
menuVisible: false
|
||||
} );
|
||||
|
||||
this.props.onSelect( group );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
const { buttonText, groups } = this.props;
|
||||
|
||||
return (
|
||||
<div className="cf-complex__inserter">
|
||||
<button type="button" className="button cf-complex__inserter-button" onClick={ this.handleAddClick }>
|
||||
{ buttonText }
|
||||
</button>
|
||||
|
||||
{ groups.length > 1 && (
|
||||
<ul className="cf-complex__inserter-menu" hidden={ ! this.state.menuVisible }>
|
||||
{ groups.map( ( group, index ) => (
|
||||
<li
|
||||
className="cf-complex__inserter-item"
|
||||
key={ index }
|
||||
onClick={ () => this.handleItemClick( group ) }
|
||||
>
|
||||
{ group.label }
|
||||
</li>
|
||||
) ) }
|
||||
</ul>
|
||||
) }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default onClickOutside( ComplexInserter );
|
||||
21
web/vendor/htmlburger/carbon-fields/packages/core/fields/complex/placeholder.js
vendored
Normal file
21
web/vendor/htmlburger/carbon-fields/packages/core/fields/complex/placeholder.js
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* Renders the empty state of the field.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @param {string} props.label
|
||||
* @param {Object} props.children
|
||||
* @return {Object}
|
||||
*/
|
||||
function ComplexPlaceholder( { label, children } ) {
|
||||
return (
|
||||
<div className="cf-complex__placeholder">
|
||||
<p className="cf-complex__placeholder-label">
|
||||
{ label }
|
||||
</p>
|
||||
|
||||
{ children }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ComplexPlaceholder;
|
||||
321
web/vendor/htmlburger/carbon-fields/packages/core/fields/complex/style.scss
vendored
Normal file
321
web/vendor/htmlburger/carbon-fields/packages/core/fields/complex/style.scss
vendored
Normal file
|
|
@ -0,0 +1,321 @@
|
|||
/* ==========================================================================
|
||||
Complex
|
||||
========================================================================== */
|
||||
|
||||
.cf-complex__groups {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
|
||||
.cf-complex--tabbed-vertical > & {
|
||||
flex: 0 0 80%;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-complex__group {
|
||||
box-sizing: border-box;
|
||||
|
||||
.cf-complex--grid & {
|
||||
position: relative;
|
||||
margin-bottom: 12px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cf-complex__group-placeholder {
|
||||
position: relative;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px dashed $wp-color-gray-light-500;
|
||||
box-sizing: border-box;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Head
|
||||
*/
|
||||
|
||||
.cf-complex__group-head {
|
||||
position: relative;
|
||||
display: flex;
|
||||
border: 1px solid $wp-color-gray-light-500;
|
||||
border-bottom: 0;
|
||||
background-color: $wp-color-gray-light-100;
|
||||
font-family: $wp-font;
|
||||
font-size: $wp-font-size;
|
||||
font-weight: 600;
|
||||
line-height: $wp-line-height;
|
||||
color: $wp-color-dark-gray;
|
||||
cursor: move;
|
||||
transition: border-color $transition-base;
|
||||
|
||||
&:hover {
|
||||
border-color: $wp-color-dark-silver-gray;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-complex__group-index {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border-right: 1px solid $wp-color-gray-light-500;
|
||||
}
|
||||
|
||||
.cf-complex__group-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Body
|
||||
*/
|
||||
|
||||
.cf-complex__group-body {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
border-width: 1px 0 1px 1px;
|
||||
border-style: solid;
|
||||
border-color: $wp-color-gray-light-500;
|
||||
background-color: $color-white;
|
||||
|
||||
&[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Actions
|
||||
*/
|
||||
|
||||
.cf-complex__actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.cf-complex__toggler {
|
||||
.cf-complex__actions & {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserter
|
||||
*/
|
||||
|
||||
.cf-complex__inserter {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
|
||||
.cf-complex__tabs & {
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
.cf-complex__tabs--tabbed-horizontal & {
|
||||
width: 36px;
|
||||
align-self: flex-end;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.cf-complex__tabs--tabbed-vertical & {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-complex__inserter-button {
|
||||
.cf-complex__tabs & {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid $wp-color-gray-light-500;
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
background-color: $wp-color-gray-light-100;
|
||||
box-shadow: none;
|
||||
font-size: 18px;
|
||||
line-height: 1;
|
||||
transition: background-color $transition-base;
|
||||
|
||||
&:focus,
|
||||
&:hover,
|
||||
&:active {
|
||||
border-color: $wp-color-gray-light-500;
|
||||
background-color: $color-white;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&:active {
|
||||
box-shadow: none;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cf-complex__inserter-menu {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 100%;
|
||||
min-width: 180px;
|
||||
margin: 0;
|
||||
transform: translate(10px, -50%);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.cf-complex__inserter-item {
|
||||
padding: 8px 12px;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
transition: color $transition-base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Group - Actions
|
||||
*/
|
||||
|
||||
.cf-complex__group-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&--grid {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
}
|
||||
|
||||
&--tabbed {
|
||||
justify-content: flex-end;
|
||||
padding: 8px 12px;
|
||||
border-width: 0 1px 1px;
|
||||
border-style: solid;
|
||||
border-color: $wp-color-gray-light-500;
|
||||
background-color: $wp-color-gray-light-100;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-complex__group-action {
|
||||
display: inline-flex;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
margin-left: 12px;
|
||||
outline: none;
|
||||
background-color: transparent;
|
||||
color: $wp-color-dark-silver-gray;
|
||||
cursor: pointer;
|
||||
transition: color $transition-base;
|
||||
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: $wp-color-dark-gray;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-complex__group-action-text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tabs
|
||||
*/
|
||||
|
||||
.cf-complex__tabs {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
&--tabbed-horizontal {
|
||||
display: inline-flex;
|
||||
margin-bottom: -5px;
|
||||
}
|
||||
|
||||
&--tabbed-vertical {
|
||||
flex: 0 0 20%;
|
||||
margin-right: -1px;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-complex__tabs-list {
|
||||
margin: 0;
|
||||
|
||||
.cf-complex__tabs--tabbed-horizontal & {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.cf-complex__tabs--tabbed-vertical & {
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-complex__tabs-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid $wp-color-gray-light-500;
|
||||
margin: 0;
|
||||
background-color: $wp-color-gray-light-100;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
transition: background-color $transition-base, border-color $transition-base;
|
||||
|
||||
&:hover {
|
||||
background-color: $color-white;
|
||||
}
|
||||
|
||||
&--tabbed-horizontal {
|
||||
margin: 0 4px 4px 0;
|
||||
}
|
||||
|
||||
&--tabbed-vertical ~ &--tabbed-vertical {
|
||||
border-top-width: 0;
|
||||
}
|
||||
|
||||
&--current {
|
||||
background-color: $color-white;
|
||||
}
|
||||
|
||||
&--tabbed-horizontal#{&}--current {
|
||||
border-bottom-color: $color-white !important;
|
||||
}
|
||||
|
||||
&--tabbed-vertical#{&}--current {
|
||||
border-right-color: $color-white !important;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Placeholder
|
||||
*/
|
||||
|
||||
.cf-complex__placeholder-label {
|
||||
&#{&} {
|
||||
margin: $size-base * 2 0 $size-base * 3;
|
||||
}
|
||||
|
||||
.cf-container-term-meta & {
|
||||
font-style: normal;
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
68
web/vendor/htmlburger/carbon-fields/packages/core/fields/complex/tabs.js
vendored
Normal file
68
web/vendor/htmlburger/carbon-fields/packages/core/fields/complex/tabs.js
vendored
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import cx from 'classnames';
|
||||
import { forwardRef } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Renders the tabs navigation.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @param {Object[]} props.items
|
||||
* @param {string} props.current
|
||||
* @param {string} props.layout
|
||||
* @param {mixed} props.children
|
||||
* @param {Function} props.onChange
|
||||
* @param {Object} ref
|
||||
* @return {void}
|
||||
*/
|
||||
function ComplexTabs( {
|
||||
items,
|
||||
current,
|
||||
layout,
|
||||
children,
|
||||
onChange
|
||||
}, ref ) {
|
||||
return (
|
||||
<div className={ `cf-complex__tabs cf-complex__tabs--${ layout }` }>
|
||||
<ul className="cf-complex__tabs-list" ref={ ref }>
|
||||
{ items.map( ( item, index ) => {
|
||||
const classes = cx(
|
||||
'cf-complex__tabs-item',
|
||||
`cf-complex__tabs-item--${ layout }`,
|
||||
{
|
||||
'cf-complex__tabs-item--current': item.id === current
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<li
|
||||
key={ item.id }
|
||||
className={ classes }
|
||||
onClick={ () => onChange( item.id ) }
|
||||
>
|
||||
{
|
||||
item.label
|
||||
? (
|
||||
<span
|
||||
className="cf-complex__tabs-title"
|
||||
dangerouslySetInnerHTML={ { __html: item.label } }
|
||||
></span>
|
||||
)
|
||||
: (
|
||||
<span className="cf-complex__tabs-index">
|
||||
{ index + 1 }
|
||||
</span>
|
||||
)
|
||||
}
|
||||
</li>
|
||||
);
|
||||
} ) }
|
||||
</ul>
|
||||
|
||||
{ children }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default forwardRef( ComplexTabs );
|
||||
17
web/vendor/htmlburger/carbon-fields/packages/core/fields/date/index.js
vendored
Normal file
17
web/vendor/htmlburger/carbon-fields/packages/core/fields/date/index.js
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import withProps from '../../hocs/with-props';
|
||||
import DatetimeField from '../datetime';
|
||||
|
||||
export default withProps( ( props ) => {
|
||||
return {
|
||||
...props,
|
||||
buttonText: __( 'Select Date', 'carbon-fields-ui' )
|
||||
};
|
||||
} )( DatetimeField );
|
||||
134
web/vendor/htmlburger/carbon-fields/packages/core/fields/datetime/index.js
vendored
Normal file
134
web/vendor/htmlburger/carbon-fields/packages/core/fields/datetime/index.js
vendored
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { Component } from '@wordpress/element';
|
||||
import Flatpickr from 'react-flatpickr';
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
|
||||
class DateTimeField extends Component {
|
||||
/**
|
||||
* Keeps reference to the instance of Flatpickr.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
picker = null;
|
||||
|
||||
/**
|
||||
* Lifecycle hook.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
this.picker = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the intialization of the flatpickr component.
|
||||
*
|
||||
* @param {Date[]} selectedDates
|
||||
* @param {string} selectedDateStr
|
||||
* @param {Object} instance
|
||||
* @return {void}
|
||||
*/
|
||||
handleReady = ( selectedDates, selectedDateStr, instance ) => {
|
||||
this.picker = instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the change.
|
||||
*
|
||||
* @param {Date[]} selectedDates
|
||||
* @param {string} selectedDateStr
|
||||
* @return {void}
|
||||
*/
|
||||
handleChange = ( selectedDates, selectedDateStr ) => {
|
||||
const {
|
||||
id,
|
||||
onChange,
|
||||
value
|
||||
} = this.props;
|
||||
|
||||
if ( selectedDateStr !== value ) {
|
||||
onChange( id, selectedDateStr );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles manual input of dates.
|
||||
*
|
||||
* @param {Object} e
|
||||
* @return {void}
|
||||
*/
|
||||
handleManualInput = ( e ) => {
|
||||
const {
|
||||
id,
|
||||
onChange,
|
||||
value
|
||||
} = this.props;
|
||||
|
||||
if ( e.target.value !== value ) {
|
||||
onChange( id, e.target.value );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the date added manually.
|
||||
*
|
||||
* @param {Object} e
|
||||
* @return {void}
|
||||
*/
|
||||
formatManualInput = ( e ) => {
|
||||
this.picker.setDate( e.target.value, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
value,
|
||||
field,
|
||||
icon,
|
||||
buttonText
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Flatpickr
|
||||
options={ {
|
||||
...field.picker_options,
|
||||
wrap: true
|
||||
} }
|
||||
value={ value }
|
||||
onReady={ this.handleReady }
|
||||
onChange={ this.handleChange }
|
||||
className={ `cf-datetime__inner dashicons-before dashicons-${ icon || 'calendar' }` }
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
id={ id }
|
||||
name={ name }
|
||||
value={ value }
|
||||
onChange={ this.handleManualInput }
|
||||
onBlur={ this.formatManualInput }
|
||||
className="cf-datetime__input"
|
||||
data-input
|
||||
{ ...field.attributes }
|
||||
/>
|
||||
|
||||
<button type="button" className="button cf-datetime__button" data-toggle>
|
||||
{ buttonText }
|
||||
</button>
|
||||
</Flatpickr>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DateTimeField;
|
||||
34
web/vendor/htmlburger/carbon-fields/packages/core/fields/datetime/style.scss
vendored
Normal file
34
web/vendor/htmlburger/carbon-fields/packages/core/fields/datetime/style.scss
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/* ==========================================================================
|
||||
DateTime
|
||||
========================================================================== */
|
||||
|
||||
@import '~flatpickr/dist/flatpickr.min.css';
|
||||
|
||||
.cf-datetime__inner {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
flex-wrap: wrap;
|
||||
margin-top: -5px;
|
||||
|
||||
&::before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-datetime__input {
|
||||
flex: 1;
|
||||
margin: 5px 6px 0 0;
|
||||
}
|
||||
|
||||
.wp-core-ui .button.cf-datetime__button {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.cf-datetime__button {
|
||||
flex: 0 0 auto;
|
||||
|
||||
.cf-field & {
|
||||
margin-bottom: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
186
web/vendor/htmlburger/carbon-fields/packages/core/fields/file/index.js
vendored
Normal file
186
web/vendor/htmlburger/carbon-fields/packages/core/fields/file/index.js
vendored
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { Component } from '@wordpress/element';
|
||||
import { get } from 'lodash';
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
import MediaLibrary from '../../components/media-library';
|
||||
import apiFetch from '../../utils/api-fetch';
|
||||
|
||||
class FileField extends Component {
|
||||
/**
|
||||
* Local state.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
state = {
|
||||
data: {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Lifecycle Hook.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
componentDidMount() {
|
||||
const { value, field } = this.props;
|
||||
|
||||
if ( value ) {
|
||||
let endpoint = '';
|
||||
|
||||
if ( window.wpApiSettings.root.indexOf( '?rest_route' ) !== -1 ) {
|
||||
endpoint = `${ window.wpApiSettings.root }carbon-fields/v1/attachment&type=${ field.value_type }&value=${ value }`;
|
||||
} else {
|
||||
endpoint = `${ window.wpApiSettings.root }carbon-fields/v1/attachment?type=${ field.value_type }&value=${ value }`;
|
||||
}
|
||||
|
||||
// TODO: Refactor this to use `@wordpress/api-fetch` package.
|
||||
apiFetch(
|
||||
endpoint,
|
||||
'get'
|
||||
).then( this.handleFileDataChange );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an URL to the attachment's thumbnail.
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
getThumb() {
|
||||
const { data } = this.state;
|
||||
|
||||
if ( data.sizes ) {
|
||||
const size = data.sizes.thumbnail || data.sizes.full;
|
||||
|
||||
if ( size ) {
|
||||
return size.url;
|
||||
}
|
||||
}
|
||||
|
||||
if ( data.thumb_url ) {
|
||||
return data.thumb_url;
|
||||
}
|
||||
|
||||
return data.icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filename to the attachment thumbnail.
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
getFileName() {
|
||||
const { data } = this.state;
|
||||
|
||||
return data.filename || data.file_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the file meta set.
|
||||
*
|
||||
* @param {Object} data
|
||||
* @return {void}
|
||||
*/
|
||||
handleFileDataChange = ( data ) => {
|
||||
this.setState( { data } );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the clear action of the file field.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
handleClear = () => {
|
||||
const { id, onChange } = this.props;
|
||||
|
||||
onChange( id, '' );
|
||||
|
||||
this.handleFileDataChange( {} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the file selection.
|
||||
*
|
||||
* @param {Object} files
|
||||
* @return {void}
|
||||
*/
|
||||
handleSelect = ( files ) => {
|
||||
const {
|
||||
id,
|
||||
field,
|
||||
onChange
|
||||
} = this.props;
|
||||
|
||||
const [ file ] = files;
|
||||
|
||||
onChange( id, get( file, field.value_type, file.id ) );
|
||||
|
||||
this.handleFileDataChange( file );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
const { data } = this.state;
|
||||
|
||||
const {
|
||||
value,
|
||||
name,
|
||||
field,
|
||||
buttonLabel,
|
||||
mediaLibraryButtonLabel,
|
||||
mediaLibraryTitle
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<MediaLibrary
|
||||
onSelect={ this.handleSelect }
|
||||
multiple={ false }
|
||||
title={ mediaLibraryTitle }
|
||||
buttonLabel={ mediaLibraryButtonLabel }
|
||||
typeFilter={ field.type_filter }
|
||||
>
|
||||
{
|
||||
( { openMediaBrowser } ) => {
|
||||
return <div className="cf-file__inner">
|
||||
<input
|
||||
type="hidden"
|
||||
name={ name }
|
||||
value={ value }
|
||||
readOnly
|
||||
/>
|
||||
|
||||
{ ( value && !! data.id ) && (
|
||||
<div className="cf-file__content">
|
||||
<div className="cf-file__preview">
|
||||
<img src={ this.getThumb() } className="cf-file__image" />
|
||||
|
||||
<button type="button" className="cf-file__remove dashicons-before dashicons-no-alt" onClick={ this.handleClear }></button>
|
||||
</div>
|
||||
|
||||
<span className="cf-file__name" title={ this.getFileName() }>
|
||||
{ this.getFileName() }
|
||||
</span>
|
||||
</div>
|
||||
) }
|
||||
|
||||
<button type="button" className="button cf-file__browse" onClick={ openMediaBrowser }>
|
||||
{ buttonLabel }
|
||||
</button>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
</MediaLibrary>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default FileField;
|
||||
94
web/vendor/htmlburger/carbon-fields/packages/core/fields/file/style.scss
vendored
Normal file
94
web/vendor/htmlburger/carbon-fields/packages/core/fields/file/style.scss
vendored
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/* ==========================================================================
|
||||
File
|
||||
========================================================================== */
|
||||
|
||||
.cf-file__inner {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 130px;
|
||||
height: 130px;
|
||||
border: 1px dashed $wp-color-gray-light-800;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.cf-file__content {
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
right: -1px;
|
||||
bottom: -1px;
|
||||
left: -1px;
|
||||
border: 1px solid $wp-color-gray-light-800;
|
||||
}
|
||||
|
||||
.cf-file__preview {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 28px;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
background-color: $wp-color-gray-light-500;
|
||||
box-shadow: 0 0 15px transparentize($color-black, .9) inset;
|
||||
}
|
||||
|
||||
.cf-file__image {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
height: auto;
|
||||
max-width: 100%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.cf-file__name {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 5px;
|
||||
border-top: 1px solid $wp-color-gray-light-800;
|
||||
overflow: hidden;
|
||||
background-color: $wp-color-gray-light-200;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.cf-file__browse {
|
||||
position: relative;
|
||||
|
||||
.cf-file__content ~ & {
|
||||
margin-bottom: 29px;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: visibility $transition-base, opacity $transition-base;
|
||||
}
|
||||
|
||||
.cf-file__inner:hover .cf-file__content ~ & {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-file__remove {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
outline: none;
|
||||
background-color: transparent;
|
||||
cursor: pointer;
|
||||
transition: opacity $transition-base;
|
||||
|
||||
&:hover {
|
||||
opacity: .8;
|
||||
}
|
||||
|
||||
&::before {
|
||||
border-radius: 50%;
|
||||
background-color: $wp-color-ultra-dark-gray;
|
||||
color: $color-white;
|
||||
}
|
||||
}
|
||||
31
web/vendor/htmlburger/carbon-fields/packages/core/fields/hidden/index.js
vendored
Normal file
31
web/vendor/htmlburger/carbon-fields/packages/core/fields/hidden/index.js
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { Component } from '@wordpress/element';
|
||||
|
||||
class HiddenField extends Component {
|
||||
/**
|
||||
* Renders the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
name,
|
||||
value,
|
||||
field
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<input
|
||||
type="hidden"
|
||||
name={ name }
|
||||
value={ value }
|
||||
className="hidden-text"
|
||||
{ ...field.attributes }
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default HiddenField;
|
||||
21
web/vendor/htmlburger/carbon-fields/packages/core/fields/html/index.js
vendored
Normal file
21
web/vendor/htmlburger/carbon-fields/packages/core/fields/html/index.js
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { RawHTML } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Renders the field.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @param {Object} props.field
|
||||
* @return {Object}
|
||||
*/
|
||||
function HtmlField( { field } ) {
|
||||
return (
|
||||
<RawHTML className="cf-html__content">
|
||||
{ field.html }
|
||||
</RawHTML>
|
||||
);
|
||||
}
|
||||
|
||||
export default HtmlField;
|
||||
79
web/vendor/htmlburger/carbon-fields/packages/core/fields/index.js
vendored
Normal file
79
web/vendor/htmlburger/carbon-fields/packages/core/fields/index.js
vendored
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { compose } from '@wordpress/compose';
|
||||
import { addFilter } from '@wordpress/hooks';
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import withFilters from '../hocs/with-filters';
|
||||
import { registerFieldType } from '../registry/fields';
|
||||
import AssociationField from './association';
|
||||
import CheckboxField from './checkbox';
|
||||
import ColorField from './color';
|
||||
import ComplexField from './complex';
|
||||
import DateField from './date';
|
||||
import DateTimeField from './datetime';
|
||||
import FileField from './file';
|
||||
import HiddenField from './hidden';
|
||||
import HtmlField from './html';
|
||||
import MapField from './map';
|
||||
import MediaGalleryField from './media-gallery';
|
||||
import MultiselectField from './multiselect';
|
||||
import OembedField from './oembed';
|
||||
import RadioField from './radio';
|
||||
import RadioImageField from './radio-image';
|
||||
import RichTextField from './rich-text';
|
||||
import SelectField from './select';
|
||||
import SeparatorField from './separator';
|
||||
import SetField from './set';
|
||||
import SidebarField from './sidebar';
|
||||
import TextField from './text';
|
||||
import TextareaField from './textarea';
|
||||
import TimeField from './time';
|
||||
import BlockPreviewField from './block-preview';
|
||||
|
||||
/**
|
||||
* Extends the fields with necessary hooks.
|
||||
*/
|
||||
addFilter( 'carbon-fields.register-field-type', 'carbon-fields/core', ( type, context, component ) => {
|
||||
return compose(
|
||||
withFilters( `carbon-fields.field-edit.${ context }` ),
|
||||
withFilters( `carbon-fields.${ type }.${ context }` )
|
||||
)( component );
|
||||
} );
|
||||
|
||||
/**
|
||||
* Registers the fields.
|
||||
*/
|
||||
[
|
||||
[ 'association', AssociationField ],
|
||||
[ 'checkbox', CheckboxField ],
|
||||
[ 'color', ColorField ],
|
||||
[ 'complex', ComplexField ],
|
||||
[ 'date', DateField ],
|
||||
[ 'date_time', DateTimeField ],
|
||||
[ 'file', FileField ],
|
||||
[ 'footer_scripts', TextareaField ],
|
||||
[ 'gravity_form', SelectField ],
|
||||
[ 'header_scripts', TextareaField ],
|
||||
[ 'hidden', HiddenField ],
|
||||
[ 'html', HtmlField ],
|
||||
[ 'image', FileField ],
|
||||
[ 'map', MapField ],
|
||||
[ 'multiselect', MultiselectField ],
|
||||
[ 'media_gallery', MediaGalleryField ],
|
||||
[ 'oembed', OembedField ],
|
||||
[ 'radio', RadioField ],
|
||||
[ 'radio_image', RadioImageField ],
|
||||
[ 'rich_text', RichTextField ],
|
||||
[ 'select', SelectField ],
|
||||
[ 'separator', SeparatorField ],
|
||||
[ 'set', SetField ],
|
||||
[ 'sidebar', SidebarField ],
|
||||
[ 'text', TextField ],
|
||||
[ 'textarea', TextareaField ],
|
||||
[ 'time', TimeField ],
|
||||
[ 'block_preview', BlockPreviewField ]
|
||||
].forEach( ( field ) => registerFieldType( ...field ) );
|
||||
164
web/vendor/htmlburger/carbon-fields/packages/core/fields/map/google-map.js
vendored
Normal file
164
web/vendor/htmlburger/carbon-fields/packages/core/fields/map/google-map.js
vendored
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { Component, createRef } from '@wordpress/element';
|
||||
|
||||
class GoogleMap extends Component {
|
||||
/**
|
||||
* Keeps references to the DOM node.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
node = createRef();
|
||||
|
||||
/**
|
||||
* Lifecycle hook.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
componentDidMount() {
|
||||
this.setupMap();
|
||||
this.setupMapEvents();
|
||||
this.updateMap( this.props );
|
||||
|
||||
const resizeObserver = new ResizeObserver( () => {
|
||||
this.updateMap( this.props );
|
||||
} );
|
||||
|
||||
resizeObserver.observe( this.node.current );
|
||||
|
||||
this.observer = resizeObserver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifecycle hook.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
componentDidUpdate() {
|
||||
const {
|
||||
lat,
|
||||
lng,
|
||||
zoom
|
||||
} = this.props;
|
||||
|
||||
if ( this.marker ) {
|
||||
const markerLat = this.marker.getPosition().lat();
|
||||
const markerLng = this.marker.getPosition().lng();
|
||||
const mapZoom = this.map.getZoom();
|
||||
|
||||
if ( lat !== markerLat || lng !== markerLng ) {
|
||||
const location = new window.google.maps.LatLng( lat, lng );
|
||||
|
||||
this.marker.setPosition( location );
|
||||
this.map.setCenter( location );
|
||||
}
|
||||
|
||||
if ( zoom !== mapZoom ) {
|
||||
this.map.setZoom( zoom );
|
||||
}
|
||||
}
|
||||
|
||||
this.updateMap( this.props );
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifecycle hook.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
this.observer.disconnect();
|
||||
|
||||
window.google.maps.event.clearInstanceListeners( this.map );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the map into placeholder element.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
setupMap() {
|
||||
const {
|
||||
lat,
|
||||
lng,
|
||||
zoom
|
||||
} = this.props;
|
||||
|
||||
const position = new window.google.maps.LatLng( lat, lng );
|
||||
|
||||
this.map = new window.google.maps.Map( this.node.current, {
|
||||
zoom,
|
||||
center: position,
|
||||
mapTypeId: window.google.maps.MapTypeId.ROADMAP,
|
||||
scrollwheel: false
|
||||
} );
|
||||
|
||||
this.marker = new window.google.maps.Marker( {
|
||||
position,
|
||||
map: this.map,
|
||||
draggable: true
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the listeners for the map's events.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
setupMapEvents() {
|
||||
const enableScrollZoom = () => {
|
||||
this.map.setOptions( {
|
||||
scrollwheel: true
|
||||
} );
|
||||
};
|
||||
|
||||
window.google.maps.event.addListenerOnce( this.map, 'click', enableScrollZoom );
|
||||
window.google.maps.event.addListenerOnce( this.map, 'dragend', enableScrollZoom );
|
||||
|
||||
// Update the zoom when the map is changed.
|
||||
window.google.maps.event.addListener( this.map, 'zoom_changed', () => {
|
||||
this.props.onChange( {
|
||||
zoom: this.map.getZoom()
|
||||
} );
|
||||
} );
|
||||
|
||||
// Update the position when the marker is moved.
|
||||
window.google.maps.event.addListener( this.marker, 'dragend', () => {
|
||||
this.props.onChange( {
|
||||
lat: this.marker.getPosition().lat(),
|
||||
lng: this.marker.getPosition().lng()
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-draws the map.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @return {void}
|
||||
*/
|
||||
updateMap( props ) {
|
||||
const { lat, lng } = props;
|
||||
const location = new window.google.maps.LatLng( lat, lng );
|
||||
|
||||
setTimeout( () => {
|
||||
window.google.maps.event.trigger( this.map, 'resize' );
|
||||
|
||||
this.map.setCenter( location );
|
||||
}, 10 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
return (
|
||||
<div ref={ this.node } className={ this.props.className }></div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default GoogleMap;
|
||||
196
web/vendor/htmlburger/carbon-fields/packages/core/fields/map/index.js
vendored
Normal file
196
web/vendor/htmlburger/carbon-fields/packages/core/fields/map/index.js
vendored
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import of from 'callbag-of';
|
||||
import { Component, Fragment } from '@wordpress/element';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { withEffects, toProps } from 'refract-callbag';
|
||||
import { debounce } from 'lodash';
|
||||
import {
|
||||
map,
|
||||
pipe,
|
||||
merge
|
||||
} from 'callbag-basics';
|
||||
|
||||
/**
|
||||
* The internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
import SearchInput from '../../components/search-input';
|
||||
import GoogleMap from './google-map';
|
||||
|
||||
class MapField extends Component {
|
||||
/**
|
||||
* Handles the change of search.
|
||||
*
|
||||
* @param {string} address
|
||||
* @return {void}
|
||||
*/
|
||||
handleSearchChange = debounce( ( address ) => {
|
||||
if ( address ) {
|
||||
this.props.onGeocodeAddress( { address } );
|
||||
}
|
||||
}, 250 )
|
||||
|
||||
/**
|
||||
* Handles the change of map location.
|
||||
*
|
||||
* @param {Object} location
|
||||
* @return {void}
|
||||
*/
|
||||
handleMapChange = ( location ) => {
|
||||
const {
|
||||
id,
|
||||
value,
|
||||
onChange
|
||||
} = this.props;
|
||||
|
||||
onChange( id, {
|
||||
...value,
|
||||
...location
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
value
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<SearchInput
|
||||
id={ id }
|
||||
className="cf-map__search"
|
||||
name={ `${ name }[address]` }
|
||||
value={ value.address }
|
||||
onChange={ this.handleSearchChange }
|
||||
/>
|
||||
|
||||
<GoogleMap
|
||||
className="cf-map__canvas"
|
||||
lat={ value.lat }
|
||||
lng={ value.lng }
|
||||
zoom={ value.zoom }
|
||||
onChange={ this.handleMapChange }
|
||||
/>
|
||||
|
||||
<input
|
||||
type="hidden"
|
||||
name={ `${ name }[lat]` }
|
||||
value={ value.lat }
|
||||
/>
|
||||
|
||||
<input
|
||||
type="hidden"
|
||||
name={ `${ name }[lng]` }
|
||||
value={ value.lng }
|
||||
readOnly
|
||||
/>
|
||||
|
||||
<input
|
||||
type="hidden"
|
||||
name={ `${ name }[zoom]` }
|
||||
value={ value.zoom }
|
||||
readOnly
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The function that controls the stream of side-effects.
|
||||
*
|
||||
* @param {Object} component
|
||||
* @return {Object}
|
||||
*/
|
||||
function aperture( component ) {
|
||||
const [ geocodeAddress$, geocodeAddress ] = component.useEvent( 'geocodeAddress' );
|
||||
|
||||
const geocodeAddressProps$ = pipe(
|
||||
of( {
|
||||
onGeocodeAddress: geocodeAddress
|
||||
} ),
|
||||
map( toProps )
|
||||
);
|
||||
|
||||
const geocodeAddressEffect$ = pipe(
|
||||
geocodeAddress$,
|
||||
map( ( payload ) => ( {
|
||||
type: 'GEOCODE_ADDRESS',
|
||||
payload: payload
|
||||
} ) )
|
||||
);
|
||||
|
||||
return merge( geocodeAddressProps$, geocodeAddressEffect$ );
|
||||
}
|
||||
|
||||
/**
|
||||
* The function that causes the side effects.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @return {Function}
|
||||
*/
|
||||
function handler( props ) {
|
||||
return function( effect ) {
|
||||
const { payload, type } = effect;
|
||||
const {
|
||||
id,
|
||||
value,
|
||||
onChange
|
||||
} = props;
|
||||
|
||||
switch ( type ) {
|
||||
case 'GEOCODE_ADDRESS':
|
||||
const geocode = ( address ) => {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
const geocoder = new window.google.maps.Geocoder();
|
||||
|
||||
geocoder.geocode( { address }, ( results, status ) => {
|
||||
if ( status === window.google.maps.GeocoderStatus.OK ) {
|
||||
const { location } = results[ 0 ].geometry;
|
||||
|
||||
resolve( {
|
||||
lat: location.lat(),
|
||||
lng: location.lng()
|
||||
} );
|
||||
} else if ( status === 'ZERO_RESULTS' ) {
|
||||
reject( __( 'The address could not be found.', 'carbon-fields-ui' ) );
|
||||
} else {
|
||||
reject( `${ __( 'Geocode was not successful for the following reason: ', 'carbon-fields-ui' ) } ${ status }` );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
};
|
||||
|
||||
geocode( payload.address )
|
||||
.then( ( { lat, lng } ) => {
|
||||
onChange( id, {
|
||||
...value,
|
||||
address: payload.address,
|
||||
value: `${ lat },${ lng }`,
|
||||
lat,
|
||||
lng
|
||||
} );
|
||||
} )
|
||||
.catch( ( alert ) => {
|
||||
// eslint-disable-next-line
|
||||
console.log( __( 'Error alert', 'carbon-fields-ui' ) );
|
||||
|
||||
// eslint-disable-next-line
|
||||
console.log( alert );
|
||||
} );
|
||||
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default withEffects( aperture, { handler } )( MapField );
|
||||
18
web/vendor/htmlburger/carbon-fields/packages/core/fields/map/style.scss
vendored
Normal file
18
web/vendor/htmlburger/carbon-fields/packages/core/fields/map/style.scss
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/* ==========================================================================
|
||||
Map
|
||||
========================================================================== */
|
||||
|
||||
.cf-map__search {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.cf-map__canvas {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
height: 300px;
|
||||
border-width: 0 1px 1px;
|
||||
border-style: solid;
|
||||
border-color: $wp-color-gray-light-500;
|
||||
background-color: $wp-color-gray-light-200;
|
||||
}
|
||||
258
web/vendor/htmlburger/carbon-fields/packages/core/fields/media-gallery/index.js
vendored
Normal file
258
web/vendor/htmlburger/carbon-fields/packages/core/fields/media-gallery/index.js
vendored
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import produce from 'immer';
|
||||
import { withEffects } from 'refract-callbag';
|
||||
import { map, pipe } from 'callbag-basics';
|
||||
import { Component, createRef } from '@wordpress/element';
|
||||
import { withState, compose } from '@wordpress/compose';
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
import MediaLibrary from '../../components/media-library';
|
||||
import Sortable from '../../components/sortable';
|
||||
import fetchAttachmentsData from '../../utils/fetch-attachments-data';
|
||||
|
||||
class MediaGalleryField extends Component {
|
||||
/**
|
||||
* Keeps reference to the list that contains selected attachments.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
attachmentsList = createRef();
|
||||
|
||||
/**
|
||||
* Handles the file selection.
|
||||
*
|
||||
* @param {Object} attachments
|
||||
* @return {void}
|
||||
*/
|
||||
handleSelect = ( attachments ) => {
|
||||
const {
|
||||
id,
|
||||
onChange,
|
||||
setState,
|
||||
value
|
||||
} = this.props;
|
||||
|
||||
onChange( id, [ ...value, ...attachments.map( ( attachment ) => attachment.id ) ] );
|
||||
|
||||
setState( {
|
||||
attachmentsData: [ ...this.props.attachmentsData, ...attachments ]
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the removal of an item.
|
||||
*
|
||||
* @param {number} index
|
||||
* @return {void}
|
||||
*/
|
||||
handleAttachmentRemove = ( index ) => {
|
||||
const {
|
||||
id,
|
||||
value,
|
||||
onChange
|
||||
} = this.props;
|
||||
|
||||
onChange( id, produce( value, ( draft ) => {
|
||||
draft.splice( index, 1 );
|
||||
} ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the media item selection.
|
||||
*
|
||||
* @param {number} itemId
|
||||
* @return {void}
|
||||
*/
|
||||
handleAttachmentSelect = ( itemId ) => {
|
||||
const { setState } = this.props;
|
||||
|
||||
setState( ( { selectedItem } ) => ( {
|
||||
selectedItem: selectedItem !== itemId ? itemId : null
|
||||
} ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles sorting of attachments.
|
||||
*
|
||||
* @param {Object[]} attachments
|
||||
* @return {void}
|
||||
*/
|
||||
handleSort = ( attachments ) => {
|
||||
const { id, onChange } = this.props;
|
||||
|
||||
onChange( id, attachments );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an URL to the attachment's thumbnail.
|
||||
*
|
||||
* @param {Object} attachment
|
||||
* @return {string}
|
||||
*/
|
||||
getAttachmentThumb( attachment ) {
|
||||
if ( attachment.sizes ) {
|
||||
const size = attachment.sizes.thumbnail || attachment.sizes.full;
|
||||
|
||||
if ( size ) {
|
||||
return size.url;
|
||||
}
|
||||
}
|
||||
|
||||
return attachment.url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
name,
|
||||
value,
|
||||
field,
|
||||
buttonLabel,
|
||||
mediaLibraryButtonLabel,
|
||||
mediaLibraryTitle,
|
||||
attachmentsData,
|
||||
selectedItem
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Sortable
|
||||
items={ value }
|
||||
forwardedRef={ this.attachmentsList }
|
||||
options={ {
|
||||
handle: '.cf-media-gallery__item-name',
|
||||
forcePlaceholderSize: true
|
||||
} }
|
||||
onUpdate={ this.handleSort }
|
||||
>
|
||||
<MediaLibrary
|
||||
onSelect={ this.handleSelect }
|
||||
multiple={ true }
|
||||
title={ mediaLibraryTitle }
|
||||
buttonLabel={ mediaLibraryButtonLabel }
|
||||
typeFilter={ field.type_filter }
|
||||
>
|
||||
{
|
||||
( { openMediaBrowser } ) => {
|
||||
return (
|
||||
<div className="cf-media-gallery__inner">
|
||||
<ul className="cf-media-gallery__list" ref={ this.attachmentsList }>
|
||||
{ value.map( ( id, index ) => { // eslint-disable-line no-shadow
|
||||
const attachment = attachmentsData.find( ( attachmentData ) => attachmentData.id === id );
|
||||
const className = [ 'cf-media-gallery__item' ];
|
||||
const isAttachmentLoaded = !! attachment;
|
||||
|
||||
if ( isAttachmentLoaded ) {
|
||||
className.push( `cf-media-gallery__item--${ attachment.type }` );
|
||||
}
|
||||
|
||||
if ( selectedItem === index ) {
|
||||
className.push( 'cf-media-gallery__item--selected' );
|
||||
}
|
||||
|
||||
return (
|
||||
<li className={ className.join( ' ' ) } key={ index } onClick={ () => this.handleAttachmentSelect( index ) }>
|
||||
<div className="cf-media-gallery__item-inner">
|
||||
<div className="cf-media-gallery__item-preview">
|
||||
{ isAttachmentLoaded && (
|
||||
attachment.type === 'image'
|
||||
? (
|
||||
<img
|
||||
className="cf-media-gallery__item-thumb"
|
||||
src={ this.getAttachmentThumb( attachment ) }
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<img
|
||||
className="cf-media-gallery__item-icon"
|
||||
src={ attachment.icon }
|
||||
/>
|
||||
)
|
||||
) }
|
||||
</div>
|
||||
|
||||
{ isAttachmentLoaded && (
|
||||
<span className="cf-media-gallery__item-name">
|
||||
{ attachment.filename }
|
||||
</span>
|
||||
) }
|
||||
|
||||
{ isAttachmentLoaded && (
|
||||
<button
|
||||
type="button"
|
||||
className="cf-media-gallery__item-remove dashicons-before dashicons-no-alt"
|
||||
onClick={ () => this.handleAttachmentRemove( index ) }
|
||||
></button>
|
||||
) }
|
||||
</div>
|
||||
|
||||
<input
|
||||
type="hidden"
|
||||
name={ `${ name }[${ index }]` }
|
||||
value={ id }
|
||||
readOnly
|
||||
/>
|
||||
</li>
|
||||
);
|
||||
} ) }
|
||||
</ul>
|
||||
|
||||
<div className="cf-media-gallery__actions">
|
||||
<button type="button" className="button cf-media-gallery__browse" onClick={ openMediaBrowser }>
|
||||
{ buttonLabel }
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
</MediaLibrary>
|
||||
</Sortable>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function aperture( component ) {
|
||||
const mount$ = component.mount;
|
||||
|
||||
return pipe( mount$, map( () => ( {
|
||||
type: 'COMPONENT_MOUNTED'
|
||||
} ) ) );
|
||||
}
|
||||
|
||||
function handler( props ) {
|
||||
return function( effect ) {
|
||||
switch ( effect.type ) {
|
||||
case 'COMPONENT_MOUNTED':
|
||||
const { value, setState } = props;
|
||||
|
||||
fetchAttachmentsData( value ).then( ( attachmentsData ) => {
|
||||
setState( {
|
||||
attachmentsData: [ ...props.attachmentsData, ...attachmentsData ]
|
||||
} );
|
||||
} );
|
||||
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const applyWithState = withState( {
|
||||
attachmentsData: [],
|
||||
selectedItem: null
|
||||
} );
|
||||
|
||||
const applyWithEffects = withEffects( aperture, { handler } );
|
||||
|
||||
export default compose(
|
||||
applyWithState,
|
||||
applyWithEffects
|
||||
)( MediaGalleryField );
|
||||
128
web/vendor/htmlburger/carbon-fields/packages/core/fields/media-gallery/style.scss
vendored
Normal file
128
web/vendor/htmlburger/carbon-fields/packages/core/fields/media-gallery/style.scss
vendored
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
/* ==========================================================================
|
||||
Media Gallery
|
||||
========================================================================== */
|
||||
|
||||
.cf-media-gallery__list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
max-height: 400px;
|
||||
padding: 4px;
|
||||
margin: 0;
|
||||
overflow-y: auto;
|
||||
list-style: none outside none;
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-media-gallery__actions {
|
||||
padding: 8px;
|
||||
|
||||
.cf-media-gallery__list:empty ~ & {
|
||||
border-top-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-media-gallery__item {
|
||||
flex: 0 0 100%;
|
||||
min-width: 0;
|
||||
padding: 4px;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
|
||||
@media (min-width: 320px) {
|
||||
flex-basis: 50%;
|
||||
}
|
||||
|
||||
@media (min-width: 480px) {
|
||||
flex-basis: 33.3333%;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
flex-basis: 25%;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
flex-basis: 20%;
|
||||
}
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
flex-basis: 16.66667%;
|
||||
}
|
||||
|
||||
@media (min-width: 1440px) {
|
||||
flex-basis: 12.5%;
|
||||
}
|
||||
|
||||
@media (min-width: 1680px) {
|
||||
flex-basis: 10%;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-media-gallery__item-inner {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.cf-media-gallery__item-preview {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
padding-top: 100%;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.cf-media-gallery__item-thumb {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
min-width: 100%;
|
||||
min-height: 100%;
|
||||
max-width: 150%;
|
||||
transform: translate(-50%, -50%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.cf-media-gallery__item-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
max-width: 100%;
|
||||
max-height: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.cf-media-gallery__item-name {
|
||||
display: block;
|
||||
padding: 4px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.cf-media-gallery__item-remove {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
outline: none;
|
||||
background-color: transparent;
|
||||
cursor: pointer;
|
||||
|
||||
&::before {
|
||||
border-radius: 50%;
|
||||
background-color: $wp-color-ultra-dark-gray;
|
||||
color: $color-white;
|
||||
transition: color $transition-base;
|
||||
}
|
||||
|
||||
&:hover::before {
|
||||
color: $wp-color-gray-light-800;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
74
web/vendor/htmlburger/carbon-fields/packages/core/fields/multiselect/index.js
vendored
Normal file
74
web/vendor/htmlburger/carbon-fields/packages/core/fields/multiselect/index.js
vendored
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { Component } from '@wordpress/element';
|
||||
import Select from 'react-select';
|
||||
|
||||
/**
|
||||
* The internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
import NoOptions from '../../components/no-options';
|
||||
|
||||
class MultiselectField extends Component {
|
||||
/**
|
||||
* Handles the change of the input.
|
||||
*
|
||||
* @param {Object} selected
|
||||
* @return {void}
|
||||
*/
|
||||
handleChange = ( selected ) => {
|
||||
const {
|
||||
id,
|
||||
onChange
|
||||
} = this.props;
|
||||
|
||||
onChange( id, selected?.map( ( item ) => item.value ) ?? [] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the field options which are contained as values
|
||||
*
|
||||
* @param {Array} values
|
||||
* @return {Array}
|
||||
*/
|
||||
filterValues = ( values ) => {
|
||||
const { field } = this.props;
|
||||
|
||||
return values.map( ( value ) => field.options.find( ( option ) => option.value === value ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
value,
|
||||
field
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
field.options.length > 0
|
||||
? (
|
||||
<Select
|
||||
id={ id }
|
||||
name={ name }
|
||||
value={ this.filterValues( value ) }
|
||||
options={ field.options }
|
||||
delimiter={ field.valueDelimiter }
|
||||
onChange={ this.handleChange }
|
||||
className="cf-multiselect__select"
|
||||
classNamePrefix="cf-multiselect"
|
||||
isMulti
|
||||
/>
|
||||
)
|
||||
: <NoOptions />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default MultiselectField;
|
||||
80
web/vendor/htmlburger/carbon-fields/packages/core/fields/multiselect/style.scss
vendored
Normal file
80
web/vendor/htmlburger/carbon-fields/packages/core/fields/multiselect/style.scss
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/* ==========================================================================
|
||||
Multiselect
|
||||
========================================================================== */
|
||||
|
||||
.cf-multiselect__control {
|
||||
min-height: 0;
|
||||
border-color: $wp-color-gray-light-500;
|
||||
|
||||
&:hover {
|
||||
border-color: $wp-color-gray-light-500;
|
||||
}
|
||||
|
||||
&--is-focused,
|
||||
&--is-focused:hover {
|
||||
border-color: $wp-color-medium-blue !important;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-multiselect__placeholder {
|
||||
color: $wp-color-gray-light-800;
|
||||
}
|
||||
|
||||
.cf-multiselect__value-container {
|
||||
padding-left: $size-base;
|
||||
padding-right: $size-base;
|
||||
}
|
||||
|
||||
.cf-multiselect__multi-value {
|
||||
align-items: center;
|
||||
padding: 5px 3px;
|
||||
margin: 0;
|
||||
background-color: $wp-color-gray-light-500;
|
||||
|
||||
& + & {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-multiselect__multi-value__label {
|
||||
padding-left: 3px;
|
||||
font-size: 13px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.cf-multiselect__multi-value__remove {
|
||||
padding: 0;
|
||||
margin-top: 1px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-multiselect__input {
|
||||
input[id],
|
||||
input[id]:focus {
|
||||
box-shadow: none;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.cf-multiselect__menu {
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.cf-multiselect__option {
|
||||
padding: $size-base;
|
||||
|
||||
&--is-focused {
|
||||
background-color: $wp-color-medium-blue;
|
||||
color: $color-white;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-multiselect__indicator {
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
225
web/vendor/htmlburger/carbon-fields/packages/core/fields/oembed/index.js
vendored
Normal file
225
web/vendor/htmlburger/carbon-fields/packages/core/fields/oembed/index.js
vendored
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { Component, createRef } from '@wordpress/element';
|
||||
import { compose, withState } from '@wordpress/compose';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { withEffects, toProps } from 'refract-callbag';
|
||||
import {
|
||||
map,
|
||||
pipe,
|
||||
merge
|
||||
} from 'callbag-basics';
|
||||
import of from 'callbag-of';
|
||||
import {
|
||||
isEmpty,
|
||||
debounce
|
||||
} from 'lodash';
|
||||
|
||||
/**
|
||||
* The internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
import SearchInput from '../../components/search-input';
|
||||
import OembedPreview from './preview';
|
||||
|
||||
class OembedField extends Component {
|
||||
/**
|
||||
* Keeps references to the DOM node.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
node = createRef();
|
||||
|
||||
/**
|
||||
* Lifecycle hook.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
componentDidMount() {
|
||||
const { value } = this.props;
|
||||
|
||||
const i = setInterval( () => {
|
||||
if ( this.node.current !== null && this.node.current.getBoundingClientRect().width > 0 ) {
|
||||
clearInterval( i );
|
||||
|
||||
this.handleSearch( value );
|
||||
}
|
||||
}, 100 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the load of the oembed preview.
|
||||
*
|
||||
* @param {String} value
|
||||
* @return {void}
|
||||
*/
|
||||
handleSearch = debounce( ( value ) => {
|
||||
const {
|
||||
isLoading,
|
||||
setState,
|
||||
onFetchEmbedCode
|
||||
} = this.props;
|
||||
|
||||
if ( isLoading ) {
|
||||
return;
|
||||
}
|
||||
|
||||
setState( {
|
||||
embedCode: '',
|
||||
error: ''
|
||||
} );
|
||||
|
||||
if ( isEmpty( value ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
setState( {
|
||||
isLoading: true
|
||||
} );
|
||||
|
||||
onFetchEmbedCode( value );
|
||||
}, 200 )
|
||||
|
||||
/**
|
||||
* Handles the change of the input.
|
||||
*
|
||||
* @param {string} value
|
||||
* @return {void}
|
||||
*/
|
||||
handleChange = ( value ) => {
|
||||
const { id, onChange } = this.props;
|
||||
|
||||
onChange( id, value );
|
||||
|
||||
this.handleSearch( value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
value,
|
||||
embedCode,
|
||||
embedType,
|
||||
provider
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div ref={ this.node }>
|
||||
<SearchInput
|
||||
id={ id }
|
||||
value={ value }
|
||||
onChange={ this.handleChange }
|
||||
/>
|
||||
|
||||
{
|
||||
embedCode
|
||||
? <OembedPreview
|
||||
html={ embedCode }
|
||||
type={ embedType }
|
||||
provider={ provider }
|
||||
/>
|
||||
: null
|
||||
}
|
||||
|
||||
<input
|
||||
type="hidden"
|
||||
name={ name }
|
||||
value={ value }
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The function that controls the stream of side-effects.
|
||||
*
|
||||
* @param {Object} component
|
||||
* @return {Object}
|
||||
*/
|
||||
function aperture( component ) {
|
||||
const [ fetchEmbedCode$, fetchEmbedCode ] = component.useEvent( 'fetchEmbedCode' );
|
||||
|
||||
const fetchEmbedCodeProps$ = pipe(
|
||||
of( {
|
||||
onFetchEmbedCode: fetchEmbedCode
|
||||
} ),
|
||||
map( toProps )
|
||||
);
|
||||
|
||||
const fetchEmbedCodeEffect$ = pipe(
|
||||
fetchEmbedCode$,
|
||||
map( ( payload ) => ( {
|
||||
type: 'FETCH_EMBED_CODE',
|
||||
payload: payload
|
||||
} ) )
|
||||
);
|
||||
|
||||
return merge( fetchEmbedCodeProps$, fetchEmbedCodeEffect$ );
|
||||
}
|
||||
|
||||
/**
|
||||
* The function that causes the side effects.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @return {Function}
|
||||
*/
|
||||
function handler( props ) {
|
||||
return function( effect ) {
|
||||
const { payload, type } = effect;
|
||||
|
||||
switch ( type ) {
|
||||
case 'FETCH_EMBED_CODE':
|
||||
const request = window.jQuery.get( window.wpApiSettings.root + 'oembed/1.0/proxy', {
|
||||
url: payload,
|
||||
_wpnonce: window.wpApiSettings.nonce
|
||||
} );
|
||||
|
||||
/* eslint-disable-next-line no-alert */
|
||||
const errorHandler = () => alert( __( 'An error occurred while trying to fetch oembed preview.', 'carbon-fields-ui' ) );
|
||||
|
||||
request.done( ( response ) => {
|
||||
props.setState( {
|
||||
embedCode: response.html,
|
||||
embedType: response.type,
|
||||
provider: response.provider_name,
|
||||
isLoading: false
|
||||
} );
|
||||
} );
|
||||
|
||||
request.fail( () => {
|
||||
errorHandler();
|
||||
|
||||
props.setState( {
|
||||
error: __( 'Not Found', 'carbon-fields-ui' ),
|
||||
isLoading: false
|
||||
} );
|
||||
} );
|
||||
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const applyWithState = withState( {
|
||||
embedCode: '',
|
||||
embedType: '',
|
||||
provider: '',
|
||||
error: '',
|
||||
isLoading: false
|
||||
} );
|
||||
|
||||
const applyWithEffects = withEffects( aperture, { handler } );
|
||||
|
||||
export default compose(
|
||||
applyWithState,
|
||||
applyWithEffects
|
||||
)( OembedField );
|
||||
188
web/vendor/htmlburger/carbon-fields/packages/core/fields/oembed/preview.js
vendored
Normal file
188
web/vendor/htmlburger/carbon-fields/packages/core/fields/oembed/preview.js
vendored
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { Component, renderToString } from '@wordpress/element';
|
||||
|
||||
class OembedPreview extends Component {
|
||||
constructor() {
|
||||
super( ...arguments );
|
||||
|
||||
this.state = {
|
||||
width: 0,
|
||||
height: 0
|
||||
};
|
||||
|
||||
this.renderIframe = this.renderIframe.bind( this );
|
||||
this.checkMessageForResize = this.checkMessageForResize.bind( this );
|
||||
}
|
||||
|
||||
isFrameAccessible() {
|
||||
try {
|
||||
return !! this.iframe.contentDocument.body;
|
||||
} catch ( e ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifecycle hook.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
componentDidMount() {
|
||||
window.addEventListener( 'message', this.checkMessageForResize, false );
|
||||
|
||||
this.renderIframe();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifecycle Hook.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
componentDidUpdate() {
|
||||
this.renderIframe();
|
||||
}
|
||||
|
||||
checkMessageForResize( event ) {
|
||||
const iframe = this.iframe;
|
||||
|
||||
// Attempt to parse the message data as JSON if passed as string
|
||||
let data = event.data || {};
|
||||
if ( 'string' === typeof data ) {
|
||||
try {
|
||||
data = JSON.parse( data );
|
||||
} catch ( e ) {} // eslint-disable-line no-empty
|
||||
}
|
||||
|
||||
// Verify that the mounted element is the source of the message
|
||||
if ( ! iframe || iframe.contentWindow !== event.source ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the state only if the message is formatted as we expect, i.e.
|
||||
// as an object with a 'resize' action, width, and height
|
||||
const { action, width, height } = data;
|
||||
const { width: oldWidth, height: oldHeight } = this.state;
|
||||
|
||||
if ( 'resize' === action && ( oldWidth !== width || oldHeight !== height ) ) {
|
||||
this.setState( { width, height } );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render Method.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
return <div className="cf-oembed__preview">
|
||||
<iframe
|
||||
ref={ ( node ) => this.iframe = node }
|
||||
scrolling="no"
|
||||
className="cf-oembed__frame"
|
||||
onLoad={ this.renderIframe }
|
||||
width={ Math.ceil( this.state.width ) }
|
||||
height={ Math.ceil( this.state.height ) }
|
||||
/>
|
||||
</div>;
|
||||
}
|
||||
|
||||
renderIframe() {
|
||||
if ( ! this.isFrameAccessible() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const body = this.iframe.contentDocument.body;
|
||||
if ( null !== body.getAttribute( 'data-resizable-iframe-connected' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const heightCalculation = 'video' === this.props.type ? 'clientBoundingRect.width / 16 * 9' : 'clientBoundingRect.height';
|
||||
|
||||
const observeAndResizeJS = `
|
||||
( function() {
|
||||
var observer;
|
||||
|
||||
if ( ! window.MutationObserver || ! document.body || ! window.parent ) {
|
||||
return;
|
||||
}
|
||||
|
||||
function sendResize() {
|
||||
var clientBoundingRect = document.body.getBoundingClientRect();
|
||||
|
||||
window.parent.postMessage( {
|
||||
action: 'resize',
|
||||
width: clientBoundingRect.width,
|
||||
height: ${ heightCalculation }
|
||||
}, '*' );
|
||||
}
|
||||
|
||||
observer = new MutationObserver( sendResize );
|
||||
observer.observe( document.body, {
|
||||
attributes: true,
|
||||
attributeOldValue: false,
|
||||
characterData: true,
|
||||
characterDataOldValue: false,
|
||||
childList: true,
|
||||
subtree: true
|
||||
} );
|
||||
|
||||
window.addEventListener( 'load', sendResize, true );
|
||||
|
||||
// Hack: Remove viewport unit styles, as these are relative
|
||||
// the iframe root and interfere with our mechanism for
|
||||
// determining the unconstrained page bounds.
|
||||
|
||||
function removeViewportStyles( ruleOrNode ) {
|
||||
[ 'width', 'height', 'minHeight', 'maxHeight' ].forEach( function( style ) {
|
||||
if ( /^\\d+(vmin|vmax|vh|vw)$/.test( ruleOrNode.style[ style ] ) ) {
|
||||
ruleOrNode.style[ style ] = '';
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
Array.prototype.forEach.call( document.querySelectorAll( '[style]' ), removeViewportStyles );
|
||||
Array.prototype.forEach.call( document.styleSheets, function( stylesheet ) {
|
||||
Array.prototype.forEach.call( stylesheet.cssRules || stylesheet.rules, removeViewportStyles );
|
||||
} );
|
||||
document.body.setAttribute( 'data-resizable-iframe-connected', '' );
|
||||
sendResize();
|
||||
} )();`;
|
||||
|
||||
const style = `
|
||||
body { margin: 0; }
|
||||
|
||||
body > div { max-width: 600px; }
|
||||
|
||||
body.Kickstarter > div,
|
||||
body.video > div { position: relative; height: 0; padding-bottom: 56.25%; }
|
||||
body.Kickstarter > div > iframe,
|
||||
body.video > div > iframe { position: absolute; width: 100%; height: 100%; top: 0; left: 0; }
|
||||
|
||||
body > div > * { margin: 0 !important;/* has to have !important to override inline styles */ max-width: 100%; }
|
||||
|
||||
body.Flickr > div > a { display: block; }
|
||||
body.Flickr > div > a > img { width: 100%; height: auto; }
|
||||
`;
|
||||
|
||||
const htmlDoc = (
|
||||
<html lang={ document.documentElement.lang }>
|
||||
<head>
|
||||
<style dangerouslySetInnerHTML={ { __html: style } } />
|
||||
</head>
|
||||
|
||||
<body data-resizable-iframe-connected="data-resizable-iframe-connected" className={ this.props.type + ' ' + this.props.provider }>
|
||||
<div dangerouslySetInnerHTML={ { __html: this.props.html } } />
|
||||
<script type="text/javascript" dangerouslySetInnerHTML={ { __html: observeAndResizeJS } } />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
this.iframe.contentWindow.document.open();
|
||||
this.iframe.contentWindow.document.write( '<!DOCTYPE html>' + renderToString( htmlDoc ) );
|
||||
this.iframe.contentWindow.document.close();
|
||||
}
|
||||
}
|
||||
|
||||
export default OembedPreview;
|
||||
17
web/vendor/htmlburger/carbon-fields/packages/core/fields/oembed/style.scss
vendored
Normal file
17
web/vendor/htmlburger/carbon-fields/packages/core/fields/oembed/style.scss
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
/* ==========================================================================
|
||||
oEmbed
|
||||
========================================================================== */
|
||||
|
||||
.cf-oembed__preview {
|
||||
padding: 12px;
|
||||
border-width: 0 1px 1px;
|
||||
border-style: solid;
|
||||
border-color: $wp-color-gray-light-500;
|
||||
}
|
||||
|
||||
.cf-oembed__frame {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
19
web/vendor/htmlburger/carbon-fields/packages/core/fields/radio-image/index.js
vendored
Normal file
19
web/vendor/htmlburger/carbon-fields/packages/core/fields/radio-image/index.js
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import withProps from '../../hocs/with-props';
|
||||
import RadioField from '../radio';
|
||||
import './style.scss';
|
||||
|
||||
export default withProps( ( props ) => {
|
||||
return {
|
||||
...props,
|
||||
field: {
|
||||
...props.field,
|
||||
options: props.field.options.map( ( option ) => ( {
|
||||
...option,
|
||||
label: ( <img className="cf-radio-image__image" src={ option.label } /> )
|
||||
} ) )
|
||||
}
|
||||
};
|
||||
} )( RadioField );
|
||||
30
web/vendor/htmlburger/carbon-fields/packages/core/fields/radio-image/style.scss
vendored
Normal file
30
web/vendor/htmlburger/carbon-fields/packages/core/fields/radio-image/style.scss
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/* ==========================================================================
|
||||
Radio
|
||||
========================================================================== */
|
||||
|
||||
.cf-radio__list {
|
||||
.wp-block & {
|
||||
list-style: none outside none;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-radio__list-item {
|
||||
box-sizing: border-box;
|
||||
|
||||
.cf-container-term-meta & {
|
||||
flex: 0 0 20%;
|
||||
}
|
||||
|
||||
.cf-container-theme-options & {
|
||||
flex: 0 0 10%;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-radio-image__image {
|
||||
border: 1px solid $wp-color-gray-light-500;
|
||||
|
||||
.cf-radio__input:focus ~ .cf-radio__label &,
|
||||
.cf-radio__input:checked ~ .cf-radio__label & {
|
||||
outline: 4px solid $wp-color-medium-blue;
|
||||
}
|
||||
}
|
||||
78
web/vendor/htmlburger/carbon-fields/packages/core/fields/radio/index.js
vendored
Normal file
78
web/vendor/htmlburger/carbon-fields/packages/core/fields/radio/index.js
vendored
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { Component } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* The internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
import NoOptions from '../../components/no-options';
|
||||
|
||||
class RadioField extends Component {
|
||||
/**
|
||||
* Handles the change of the input.
|
||||
*
|
||||
* @param {Object} e
|
||||
* @return {void}
|
||||
*/
|
||||
handleChange = ( e ) => {
|
||||
const { id, onChange } = this.props;
|
||||
|
||||
onChange( id, e.target.value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the radio options
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
renderOptions() {
|
||||
const {
|
||||
id,
|
||||
field,
|
||||
value,
|
||||
name
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<ul className="cf-radio__list">
|
||||
{ field.options.map( ( option, index ) => (
|
||||
<li className="cf-radio__list-item" key={ index }>
|
||||
<input
|
||||
type="checkbox"
|
||||
id={ `${ id }-${ option.value }` }
|
||||
name={ name }
|
||||
value={ option.value }
|
||||
checked={ value === option.value }
|
||||
className="cf-radio__input"
|
||||
onChange={ this.handleChange }
|
||||
{ ...field.attributes }
|
||||
/>
|
||||
|
||||
<label className="cf-radio__label" htmlFor={ `${ id }-${ option.value }` }>
|
||||
{ option.label }
|
||||
</label>
|
||||
</li>
|
||||
) ) }
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
const { field } = this.props;
|
||||
|
||||
return (
|
||||
field.options.length > 0
|
||||
? this.renderOptions()
|
||||
: <NoOptions />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default RadioField;
|
||||
73
web/vendor/htmlburger/carbon-fields/packages/core/fields/radio/style.scss
vendored
Normal file
73
web/vendor/htmlburger/carbon-fields/packages/core/fields/radio/style.scss
vendored
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/* ==========================================================================
|
||||
Radio
|
||||
========================================================================== */
|
||||
|
||||
.cf-radio__list {
|
||||
margin: 0;
|
||||
|
||||
.cf-radio-image & {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-radio__list-item {
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.cf-radio-image & {
|
||||
flex: 0 0 20%;
|
||||
position: relative;
|
||||
padding: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-radio__label {
|
||||
.cf-container-term-meta & {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.cf-radio-image & {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-radio__input {
|
||||
.cf-field & {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.cf-radio-image & {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 0;
|
||||
height: 0;
|
||||
margin: 0;
|
||||
outline: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&[type="checkbox"] {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
&[type="checkbox"]:checked:before {
|
||||
content: "";
|
||||
background-color: var(--wp-admin-theme-color, #3582c4);
|
||||
border-radius: 50%;
|
||||
width: 0.5rem;
|
||||
height: 0.5rem;
|
||||
margin: 0.1875rem;
|
||||
line-height: 1.14285714;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-radio-image__image {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
207
web/vendor/htmlburger/carbon-fields/packages/core/fields/rich-text/index.js
vendored
Normal file
207
web/vendor/htmlburger/carbon-fields/packages/core/fields/rich-text/index.js
vendored
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { createRef, Component } from '@wordpress/element';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import {
|
||||
isString,
|
||||
template,
|
||||
debounce
|
||||
} from 'lodash';
|
||||
import cx from 'classnames';
|
||||
|
||||
class RichTextField extends Component {
|
||||
/**
|
||||
* Define the project base properties
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.node = createRef();
|
||||
this.editor = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifecycle hook.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
componentDidMount() {
|
||||
if ( this.props.visible ) {
|
||||
this.timer = setTimeout( this.initEditor, 250 );
|
||||
|
||||
const resizeObserver = new ResizeObserver( debounce( () => {
|
||||
if ( this.editor ) {
|
||||
/**
|
||||
* On each call of the `wpAutoResize` method the global `wpActiveEditor` reference
|
||||
* is changed to the element that will be resized. In some cases this is causing
|
||||
* conflicts with other plugins so we need to preserve and restore the previously
|
||||
* referenced element.
|
||||
*/
|
||||
const activeEdtior = window.wpActiveEditor;
|
||||
this.editor.execCommand( 'wpAutoResize', undefined, undefined, { skip_focus: true } );
|
||||
window.wpActiveEditor = activeEdtior;
|
||||
}
|
||||
}, 100 ) );
|
||||
|
||||
resizeObserver.observe( this.node.current );
|
||||
|
||||
this.observer = resizeObserver;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifecycle hook.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
clearTimeout( this.timer );
|
||||
|
||||
if ( typeof this.observer !== 'undefined' ) {
|
||||
this.observer.disconnect();
|
||||
}
|
||||
|
||||
this.destroyEditor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the change of the input.
|
||||
*
|
||||
* @param {Object|string} eventOrValue
|
||||
* @return {void}
|
||||
*/
|
||||
handleChange = ( eventOrValue ) => {
|
||||
const { id, onChange } = this.props;
|
||||
|
||||
onChange(
|
||||
id,
|
||||
isString( eventOrValue ) ? eventOrValue : eventOrValue.target.value
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
value,
|
||||
field
|
||||
} = this.props;
|
||||
|
||||
const classes = [
|
||||
'carbon-wysiwyg',
|
||||
'wp-editor-wrap',
|
||||
{ 'tmce-active': field.rich_editing },
|
||||
{ 'html-active': ! field.rich_editing }
|
||||
];
|
||||
|
||||
const mediaButtonsHTML = field.media_buttons
|
||||
? template( field.media_buttons )( { id } )
|
||||
: null;
|
||||
|
||||
const shouldRenderTabs = field.rich_editing && window.tinyMCEPreInit.qtInit[ field.settings_reference ];
|
||||
|
||||
return (
|
||||
<div
|
||||
id={ `wp-${ id }-wrap` }
|
||||
className={ cx( classes ) }
|
||||
ref={ this.node }
|
||||
>
|
||||
{ field.media_buttons && (
|
||||
<div id={ `wp-${ id }-media-buttons` } className="hide-if-no-js wp-media-buttons">
|
||||
<span dangerouslySetInnerHTML={ { __html: mediaButtonsHTML } }></span>
|
||||
</div>
|
||||
) }
|
||||
|
||||
{ shouldRenderTabs && (
|
||||
<div className="wp-editor-tabs">
|
||||
<button type="button" id={ `${ id }-tmce` } className="wp-switch-editor switch-tmce" data-wp-editor-id={ id }>
|
||||
{ __( 'Visual', 'carbon-fields-ui' ) }
|
||||
</button>
|
||||
|
||||
<button type="button" id={ `${ id }-html` } className="wp-switch-editor switch-html" data-wp-editor-id={ id }>
|
||||
{ __( 'Text', 'carbon-fields-ui' ) }
|
||||
</button>
|
||||
</div>
|
||||
) }
|
||||
|
||||
<div id={ `wp-${ id }-editor-container` } className="wp-editor-container">
|
||||
<textarea
|
||||
style={ { width: '100%' } }
|
||||
className="regular-text"
|
||||
id={ id }
|
||||
name={ name }
|
||||
value={ value }
|
||||
onChange={ this.handleChange }
|
||||
{ ...field.attributes }
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the WYSIWYG editor.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
initEditor = () => {
|
||||
const { id, field } = this.props;
|
||||
if ( field.rich_editing ) {
|
||||
const editorSetup = ( editor ) => {
|
||||
this.editor = editor;
|
||||
|
||||
editor.on( 'blur Change', () => {
|
||||
editor.save();
|
||||
|
||||
this.handleChange( editor.getContent() );
|
||||
} );
|
||||
};
|
||||
|
||||
const editorOptions = {
|
||||
...window.tinyMCEPreInit.mceInit[ field.settings_reference ],
|
||||
selector: `#${ id }`,
|
||||
setup: editorSetup
|
||||
};
|
||||
|
||||
window.tinymce.init( editorOptions );
|
||||
}
|
||||
|
||||
const quickTagsOptions = { ...window.tinyMCEPreInit.qtInit[ field.settings_reference ] };
|
||||
|
||||
if ( quickTagsOptions ) {
|
||||
const qtagInstance = window.quicktags( {
|
||||
...quickTagsOptions,
|
||||
id
|
||||
} );
|
||||
|
||||
// Force the initialization of the quick tags.
|
||||
window.QTags._buttonsInit( qtagInstance.id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the instance of the WYSIWYG editor.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
destroyEditor() {
|
||||
if ( this.editor ) {
|
||||
this.editor.remove();
|
||||
|
||||
this.node = null;
|
||||
this.editor = null;
|
||||
}
|
||||
|
||||
delete window.QTags.instances[ this.props.id ];
|
||||
}
|
||||
}
|
||||
|
||||
export default RichTextField;
|
||||
67
web/vendor/htmlburger/carbon-fields/packages/core/fields/select/index.js
vendored
Normal file
67
web/vendor/htmlburger/carbon-fields/packages/core/fields/select/index.js
vendored
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* External dependencies.
|
||||
*/
|
||||
import { Component } from '@wordpress/element';
|
||||
import { get } from 'lodash';
|
||||
|
||||
/**
|
||||
* The internal dependencies.
|
||||
*/
|
||||
import './style.scss';
|
||||
import NoOptions from '../../components/no-options';
|
||||
|
||||
export class SelectField extends Component {
|
||||
/**
|
||||
* Handles the change of the input.
|
||||
*
|
||||
* @param {Object} e
|
||||
* @return {void}
|
||||
*/
|
||||
handleChange = ( e ) => {
|
||||
const { id, onChange } = this.props;
|
||||
|
||||
onChange( id, e.target.value );
|
||||
}
|
||||
|
||||
componentMount() {
|
||||
onChange( id, value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the component.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
field,
|
||||
onChange
|
||||
} = this.props;
|
||||
|
||||
const value = this.props.value || get( field.options, '[0].value', '' );
|
||||
|
||||
return (
|
||||
field.options.length > 0
|
||||
? (
|
||||
<select
|
||||
id={ id }
|
||||
name={ name }
|
||||
value={ value }
|
||||
className="cf-select__input"
|
||||
onChange={ this.handleChange }
|
||||
>
|
||||
{ field.options.map( ( option ) => (
|
||||
<option key={ option.value } value={ option.value }>
|
||||
{ option.label }
|
||||
</option>
|
||||
) ) }
|
||||
</select>
|
||||
)
|
||||
: <NoOptions />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default SelectField;
|
||||
9
web/vendor/htmlburger/carbon-fields/packages/core/fields/select/style.scss
vendored
Normal file
9
web/vendor/htmlburger/carbon-fields/packages/core/fields/select/style.scss
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
/* ==========================================================================
|
||||
Select
|
||||
========================================================================== */
|
||||
|
||||
.cf-select__input {
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue