-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Editor: Expose custom class name hook for mobile (#8072)
* Editor: Expose custom class name hook for mobile * Use overrides in subfolders rathern in the entry point file * Element: Reorganize code to make it fit better React Native needs * Editor: Expose another custom class name hook needed for mobile that were not exposed in the previous commit * Fix lint
- Loading branch information
Showing
14 changed files
with
350 additions
and
287 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { assign, difference, compact } from 'lodash'; | ||
import classnames from 'classnames'; | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { addFilter } from '@wordpress/hooks'; | ||
import { | ||
hasBlockSupport, | ||
getSaveContent, | ||
parseWithAttributeSchema, | ||
} from '@wordpress/blocks'; | ||
|
||
/** | ||
* Filters registered block settings, extending attributes with anchor using ID | ||
* of the first node. | ||
* | ||
* @param {Object} settings Original block settings. | ||
* | ||
* @return {Object} Filtered block settings. | ||
*/ | ||
export function addAttribute( settings ) { | ||
if ( hasBlockSupport( settings, 'customClassName', true ) ) { | ||
// Use Lodash's assign to gracefully handle if attributes are undefined | ||
settings.attributes = assign( settings.attributes, { | ||
className: { | ||
type: 'string', | ||
}, | ||
} ); | ||
} | ||
|
||
return settings; | ||
} | ||
|
||
/** | ||
* Override props assigned to save component to inject anchor ID, if block | ||
* supports anchor. This is only applied if the block's save result is an | ||
* element and not a markup string. | ||
* | ||
* @param {Object} extraProps Additional props applied to save element. | ||
* @param {Object} blockType Block type. | ||
* @param {Object} attributes Current block attributes. | ||
* | ||
* @return {Object} Filtered props applied to save element. | ||
*/ | ||
export function addSaveProps( extraProps, blockType, attributes ) { | ||
if ( hasBlockSupport( blockType, 'customClassName', true ) && attributes.className ) { | ||
extraProps.className = classnames( extraProps.className, attributes.className ); | ||
} | ||
|
||
return extraProps; | ||
} | ||
|
||
/** | ||
* Given an HTML string, returns an array of class names assigned to the root | ||
* element in the markup. | ||
* | ||
* @param {string} innerHTML Markup string from which to extract classes. | ||
* | ||
* @return {string[]} Array of class names assigned to the root element. | ||
*/ | ||
export function getHTMLRootElementClasses( innerHTML ) { | ||
innerHTML = `<div data-custom-class-name>${ innerHTML }</div>`; | ||
|
||
const parsed = parseWithAttributeSchema( innerHTML, { | ||
type: 'string', | ||
source: 'attribute', | ||
selector: '[data-custom-class-name] > *', | ||
attribute: 'class', | ||
} ); | ||
|
||
return parsed ? parsed.trim().split( /\s+/ ) : []; | ||
} | ||
|
||
/** | ||
* Given a parsed set of block attributes, if the block supports custom class | ||
* names and an unknown class (per the block's serialization behavior) is | ||
* found, the unknown classes are treated as custom classes. This prevents the | ||
* block from being considered as invalid. | ||
* | ||
* @param {Object} blockAttributes Original block attributes. | ||
* @param {Object} blockType Block type settings. | ||
* @param {string} innerHTML Original block markup. | ||
* | ||
* @return {Object} Filtered block attributes. | ||
*/ | ||
export function addParsedDifference( blockAttributes, blockType, innerHTML ) { | ||
if ( hasBlockSupport( blockType, 'customClassName', true ) ) { | ||
// To determine difference, serialize block given the known set of | ||
// attributes. If there are classes which are mismatched with the | ||
// incoming HTML of the block, add to filtered result. | ||
const serialized = getSaveContent( blockType, blockAttributes ); | ||
const classes = getHTMLRootElementClasses( serialized ); | ||
const parsedClasses = getHTMLRootElementClasses( innerHTML ); | ||
const customClasses = difference( parsedClasses, classes ); | ||
|
||
const filteredClassName = compact( [ | ||
blockAttributes.className, | ||
...customClasses, | ||
] ).join( ' ' ); | ||
|
||
if ( filteredClassName ) { | ||
blockAttributes.className = filteredClassName; | ||
} else { | ||
delete blockAttributes.className; | ||
} | ||
} | ||
|
||
return blockAttributes; | ||
} | ||
|
||
addFilter( 'blocks.registerBlockType', 'core/custom-class-name/attribute', addAttribute ); | ||
addFilter( 'blocks.getSaveContent.extraProps', 'core/custom-class-name/save-props', addSaveProps ); | ||
addFilter( 'blocks.getBlockAttributes', 'core/custom-class-name/addParsedDifference', addParsedDifference ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
/** | ||
* Internal dependencies | ||
*/ | ||
import './custom-class-name'; | ||
import './generated-class-name'; |
This file was deleted.
Oops, something went wrong.
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,197 +1,7 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { | ||
createElement, | ||
createContext, | ||
createRef, | ||
forwardRef, | ||
Component, | ||
cloneElement, | ||
Children, | ||
Fragment, | ||
isValidElement, | ||
StrictMode, | ||
} from 'react'; | ||
import { render, findDOMNode, createPortal, unmountComponentAtNode } from 'react-dom'; | ||
import { isString } from 'lodash'; | ||
export * from './react'; | ||
export * from './react-platform'; | ||
export { default as renderToString } from './serialize'; | ||
export { default as RawHTML } from './raw-html'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import serialize from './serialize'; | ||
import { RawHTML } from './index-common'; | ||
// deprecated | ||
export * from './deprecated'; | ||
|
||
/** | ||
* Returns a new element of given type. Type can be either a string tag name or | ||
* another function which itself returns an element. | ||
* | ||
* @param {?(string|Function)} type Tag name or element creator | ||
* @param {Object} props Element properties, either attribute | ||
* set to apply to DOM node or values to | ||
* pass through to element creator | ||
* @param {...WPElement} children Descendant elements | ||
* | ||
* @return {WPElement} Element. | ||
*/ | ||
export { createElement }; | ||
|
||
/** | ||
* Returns an object tracking a reference to a rendered element via its | ||
* `current` property as either a DOMElement or Element, dependent upon the | ||
* type of element rendered with the ref attribute. | ||
* | ||
* @return {Object} Ref object. | ||
*/ | ||
export { createRef }; | ||
|
||
/** | ||
* Component enhancer used to enable passing a ref to its wrapped component. | ||
* Pass a function argument which receives `props` and `ref` as its arguments, | ||
* returning an element using the forwarded ref. The return value is a new | ||
* component which forwards its ref. | ||
* | ||
* @param {Function} forwarder Function passed `props` and `ref`, expected to | ||
* return an element. | ||
* | ||
* @return {WPComponent} Enhanced component. | ||
*/ | ||
export { forwardRef }; | ||
|
||
/** | ||
* Renders a given element into the target DOM node. | ||
* | ||
* @param {WPElement} element Element to render | ||
* @param {Element} target DOM node into which element should be rendered | ||
*/ | ||
export { render }; | ||
|
||
/** | ||
* Removes any mounted element from the target DOM node. | ||
* | ||
* @param {Element} target DOM node in which element is to be removed | ||
*/ | ||
export { unmountComponentAtNode }; | ||
|
||
/** | ||
* A base class to create WordPress Components (Refs, state and lifecycle hooks) | ||
*/ | ||
export { Component }; | ||
|
||
/** | ||
* Creates a copy of an element with extended props. | ||
* | ||
* @param {WPElement} element Element | ||
* @param {?Object} props Props to apply to cloned element | ||
* | ||
* @return {WPElement} Cloned element. | ||
*/ | ||
export { cloneElement }; | ||
|
||
/** | ||
* Finds the dom node of a React component | ||
* | ||
* @param {Component} component component's instance | ||
* @param {Element} target DOM node into which element should be rendered | ||
*/ | ||
export { findDOMNode }; | ||
|
||
export { Children }; | ||
|
||
export { StrictMode }; | ||
|
||
/** | ||
* A component which renders its children without any wrapping element. | ||
*/ | ||
export { Fragment }; | ||
|
||
/** | ||
* Creates a context object containing two components: a provider and consumer. | ||
* | ||
* @param {Object} defaultValue A default data stored in the context. | ||
* | ||
* @return {Object} Context object. | ||
*/ | ||
export { createContext }; | ||
|
||
/** | ||
* Checks if an object is a valid WPElement | ||
* | ||
* @param {Object} objectToCheck The object to be checked. | ||
* | ||
* @return {boolean} true if objectToTest is a valid WPElement and false otherwise. | ||
*/ | ||
export { isValidElement }; | ||
|
||
/** | ||
* Creates a portal into which a component can be rendered. | ||
* | ||
* @see https://github.com/facebook/react/issues/10309#issuecomment-318433235 | ||
* | ||
* @param {Component} component Component | ||
* @param {Element} target DOM node into which element should be rendered | ||
*/ | ||
export { createPortal }; | ||
|
||
/** | ||
* Renders a given element into a string. | ||
* | ||
* @param {WPElement} element Element to render | ||
* | ||
* @return {string} HTML. | ||
*/ | ||
export { serialize as renderToString }; | ||
|
||
/** | ||
* Concatenate two or more React children objects. | ||
* | ||
* @param {...?Object} childrenArguments Array of children arguments (array of arrays/strings/objects) to concatenate. | ||
* | ||
* @return {Array} The concatenated value. | ||
*/ | ||
export function concatChildren( ...childrenArguments ) { | ||
return childrenArguments.reduce( ( memo, children, i ) => { | ||
Children.forEach( children, ( child, j ) => { | ||
if ( child && 'string' !== typeof child ) { | ||
child = cloneElement( child, { | ||
key: [ i, j ].join(), | ||
} ); | ||
} | ||
|
||
memo.push( child ); | ||
} ); | ||
|
||
return memo; | ||
}, [] ); | ||
} | ||
|
||
/** | ||
* Switches the nodeName of all the elements in the children object. | ||
* | ||
* @param {?Object} children Children object. | ||
* @param {string} nodeName Node name. | ||
* | ||
* @return {?Object} The updated children object. | ||
*/ | ||
export function switchChildrenNodeName( children, nodeName ) { | ||
return children && Children.map( children, ( elt, index ) => { | ||
if ( isString( elt ) ) { | ||
return createElement( nodeName, { key: index }, elt ); | ||
} | ||
const { children: childrenProp, ...props } = elt.props; | ||
return createElement( nodeName, { key: index, ...props }, childrenProp ); | ||
} ); | ||
} | ||
|
||
/** | ||
* Component used as equivalent of Fragment with unescaped HTML, in cases where | ||
* it is desirable to render dangerous HTML without needing a wrapper element. | ||
* To preserve additional props, a `div` wrapper _will_ be created if any props | ||
* aside from `children` are passed. | ||
* | ||
* @param {string} props.children HTML to render. | ||
* | ||
* @return {WPElement} Dangerously-rendering element. | ||
*/ | ||
export { RawHTML }; |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.