-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #194 from vendidero/block-support
Block support
- Loading branch information
Showing
153 changed files
with
40,886 additions
and
28,759 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
81 changes: 81 additions & 0 deletions
81
assets/js/base/components/formatted-monetary-amount/index.js
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,81 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import NumberFormat from 'react-number-format'; | ||
import classNames from 'classnames'; | ||
|
||
/** | ||
* Formats currency data into the expected format for NumberFormat. | ||
*/ | ||
const currencyToNumberFormat = ( currency ) => { | ||
return { | ||
thousandSeparator: currency?.thousandSeparator, | ||
decimalSeparator: currency?.decimalSeparator, | ||
fixedDecimalScale: true, | ||
prefix: currency?.prefix, | ||
suffix: currency?.suffix, | ||
isNumericString: true, | ||
}; | ||
}; | ||
|
||
/** | ||
* FormattedMonetaryAmount component. | ||
* | ||
* Takes a price and returns a formatted price using the NumberFormat component. | ||
*/ | ||
const FormattedMonetaryAmount = ( { | ||
className, | ||
value: rawValue, | ||
currency, | ||
onValueChange, | ||
displayType = 'text', | ||
...props | ||
}) => { | ||
const value = | ||
typeof rawValue === 'string' ? parseInt( rawValue, 10 ) : rawValue; | ||
|
||
if ( ! Number.isFinite( value ) ) { | ||
return null; | ||
} | ||
|
||
const priceValue = value / 10 ** currency.minorUnit; | ||
|
||
if ( ! Number.isFinite( priceValue ) ) { | ||
return null; | ||
} | ||
|
||
const classes = classNames( | ||
'wc-block-formatted-money-amount', | ||
'wc-block-components-formatted-money-amount', | ||
className | ||
); | ||
const decimalScale = props.decimalScale ?? currency?.minorUnit; | ||
const numberFormatProps = { | ||
...props, | ||
...currencyToNumberFormat( currency ), | ||
decimalScale, | ||
value: undefined, | ||
currency: undefined, | ||
onValueChange: undefined, | ||
}; | ||
|
||
// Wrapper for NumberFormat onValueChange which handles subunit conversion. | ||
const onValueChangeWrapper = onValueChange | ||
? ( values ) => { | ||
const minorUnitValue = +values.value * 10 ** currency.minorUnit; | ||
onValueChange( minorUnitValue ); | ||
} | ||
: () => void 0; | ||
|
||
return ( | ||
<NumberFormat | ||
className={ classes } | ||
displayType={ displayType } | ||
{ ...numberFormatProps } | ||
value={ priceValue } | ||
onValueChange={ onValueChangeWrapper } | ||
/> | ||
); | ||
}; | ||
|
||
export default FormattedMonetaryAmount; |
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,4 @@ | ||
export * from './noninteractive'; | ||
export * from './radio-control'; | ||
export * from './radio-control-accordion'; | ||
export * from './formatted-monetary-amount'; |
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,93 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { useRef, useLayoutEffect } from '@wordpress/element'; | ||
import { focus } from '@wordpress/dom'; | ||
import { useDebouncedCallback } from 'use-debounce'; | ||
|
||
/** | ||
* Names of control nodes which need to be disabled. | ||
*/ | ||
const FOCUSABLE_NODE_NAMES = [ | ||
'BUTTON', | ||
'FIELDSET', | ||
'INPUT', | ||
'OPTGROUP', | ||
'OPTION', | ||
'SELECT', | ||
'TEXTAREA', | ||
'A', | ||
]; | ||
|
||
/** | ||
* Noninteractive component | ||
* | ||
* Makes children elements Noninteractive, preventing both mouse and keyboard events without affecting how the elements | ||
* appear visually. Used for previews. | ||
* | ||
* Based on the <Disabled> component in WordPress. | ||
* | ||
* @see https://github.com/WordPress/gutenberg/blob/trunk/packages/components/src/disabled/index.js | ||
*/ | ||
const Noninteractive = ( { | ||
children, | ||
style = {}, | ||
...props | ||
}) => { | ||
const node = useRef(); | ||
|
||
const disableFocus = () => { | ||
if ( node.current ) { | ||
focus.focusable.find( node.current ).forEach( ( focusable ) => { | ||
if ( FOCUSABLE_NODE_NAMES.includes( focusable.nodeName ) ) { | ||
focusable.setAttribute( 'tabindex', '-1' ); | ||
} | ||
if ( focusable.hasAttribute( 'contenteditable' ) ) { | ||
focusable.setAttribute( 'contenteditable', 'false' ); | ||
} | ||
} ); | ||
} | ||
}; | ||
|
||
// Debounce re-disable since disabling process itself will incur additional mutations which should be ignored. | ||
const debounced = useDebouncedCallback( disableFocus, 0, { | ||
leading: true, | ||
} ); | ||
|
||
useLayoutEffect( () => { | ||
let observer; | ||
disableFocus(); | ||
if ( node.current ) { | ||
observer = new window.MutationObserver( debounced ); | ||
observer.observe( node.current, { | ||
childList: true, | ||
attributes: true, | ||
subtree: true, | ||
} ); | ||
} | ||
return () => { | ||
if ( observer ) { | ||
observer.disconnect(); | ||
} | ||
debounced.cancel(); | ||
}; | ||
}, [ debounced ] ); | ||
|
||
return ( | ||
<div | ||
ref={ node } | ||
aria-disabled="true" | ||
style={ { | ||
userSelect: 'none', | ||
pointerEvents: 'none', | ||
cursor: 'normal', | ||
...style, | ||
} } | ||
{ ...props } | ||
> | ||
{ children } | ||
</div> | ||
); | ||
}; | ||
|
||
export default Noninteractive; |
73 changes: 73 additions & 0 deletions
73
assets/js/base/components/radio-control-accordion/index.js
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,73 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import classnames from 'classnames'; | ||
import { withInstanceId } from '@wordpress/compose'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import RadioControlOption from '../radio-control/option'; | ||
|
||
const RadioControlAccordion = ( { | ||
className, | ||
instanceId, | ||
id, | ||
selected, | ||
onChange, | ||
options, | ||
} ) => { | ||
const radioControlId = id || instanceId; | ||
|
||
if ( ! options.length ) { | ||
return null; | ||
} | ||
return ( | ||
<div | ||
className={ classnames( | ||
'wc-block-components-radio-control', | ||
className | ||
) } | ||
> | ||
{ options.map( ( option ) => { | ||
const hasOptionContent = | ||
typeof option === 'object' && 'content' in option; | ||
const checked = option.value === selected; | ||
return ( | ||
<div | ||
className="wc-block-components-radio-control-accordion-option" | ||
key={ option.value } | ||
> | ||
<RadioControlOption | ||
name={ `radio-control-${ radioControlId }` } | ||
checked={ checked } | ||
option={ option } | ||
onChange={ ( value ) => { | ||
onChange( value ); | ||
if ( typeof option.onChange === 'function' ) { | ||
option.onChange( value ); | ||
} | ||
} } | ||
/> | ||
{ hasOptionContent && checked && ( | ||
<div | ||
className={ classnames( | ||
'wc-block-components-radio-control-accordion-content', | ||
{ | ||
'wc-block-components-radio-control-accordion-content-hide': | ||
! checked, | ||
} | ||
) } | ||
> | ||
{ option.content } | ||
</div> | ||
) } | ||
</div> | ||
); | ||
} ) } | ||
</div> | ||
); | ||
}; | ||
|
||
export default withInstanceId( RadioControlAccordion ); | ||
export { RadioControlAccordion }; |
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,55 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import classnames from 'classnames'; | ||
import { useInstanceId } from '@wordpress/compose'; | ||
/** | ||
* Internal dependencies | ||
*/ | ||
import RadioControlOption from './option'; | ||
import './style.scss'; | ||
|
||
const RadioControl = ( { | ||
className, | ||
id, | ||
selected, | ||
onChange, | ||
options, | ||
disabled, | ||
} ) => { | ||
const instanceId = useInstanceId( RadioControl ); | ||
const radioControlId = id || instanceId; | ||
|
||
if ( ! options.length ) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<div | ||
className={ classnames( | ||
'wc-block-components-radio-control', | ||
className | ||
) } | ||
> | ||
{ options.map( ( option ) => ( | ||
<RadioControlOption | ||
key={ `${ radioControlId }-${ option.value }` } | ||
name={ `radio-control-${ radioControlId }` } | ||
checked={ option.value === selected } | ||
option={ option } | ||
onChange={ ( value ) => { | ||
onChange( value ); | ||
if ( typeof option.onChange === 'function' ) { | ||
option.onChange( value ); | ||
} | ||
} } | ||
disabled={ disabled } | ||
/> | ||
) ) } | ||
</div> | ||
); | ||
}; | ||
|
||
export default RadioControl; | ||
export { default as RadioControlOption } from './option'; | ||
export { default as RadioControlOptionLayout } from './option-layout'; |
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,52 @@ | ||
const OptionLayout = ( { | ||
label, | ||
secondaryLabel, | ||
description, | ||
secondaryDescription, | ||
id, | ||
} ) => { | ||
return ( | ||
<div className="wc-block-components-radio-control__option-layout"> | ||
<div className="wc-block-components-radio-control__label-group"> | ||
{ label && ( | ||
<span | ||
id={ id && `${ id }__label` } | ||
className="wc-block-components-radio-control__label" | ||
> | ||
{ label } | ||
</span> | ||
) } | ||
{ secondaryLabel && ( | ||
<span | ||
id={ id && `${ id }__secondary-label` } | ||
className="wc-block-components-radio-control__secondary-label" | ||
> | ||
{ secondaryLabel } | ||
</span> | ||
) } | ||
</div> | ||
{ ( description || secondaryDescription ) && ( | ||
<div className="wc-block-components-radio-control__description-group"> | ||
{ description && ( | ||
<span | ||
id={ id && `${ id }__description` } | ||
className="wc-block-components-radio-control__description" | ||
> | ||
{ description } | ||
</span> | ||
) } | ||
{ secondaryDescription && ( | ||
<span | ||
id={ id && `${ id }__secondary-description` } | ||
className="wc-block-components-radio-control__secondary-description" | ||
> | ||
{ secondaryDescription } | ||
</span> | ||
) } | ||
</div> | ||
) } | ||
</div> | ||
); | ||
}; | ||
|
||
export default OptionLayout; |
Oops, something went wrong.