Skip to content

Commit 53ec598

Browse files
committed
feat: add markmode in four range control
1 parent f40b72b commit 53ec598

File tree

1 file changed

+226
-20
lines changed
  • src/components/four-range-control

1 file changed

+226
-20
lines changed

src/components/four-range-control/index.js

Lines changed: 226 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import { __ } from '@wordpress/i18n'
2727
import {
2828
Fragment, useState, memo,
2929
} from '@wordpress/element'
30+
import { settings } from '@wordpress/icons'
31+
import { dispatch } from '@wordpress/data'
3032

3133
/**
3234
* External dependencies
@@ -40,6 +42,7 @@ import {
4042
useBlockAttributesContext,
4143
useDeviceType,
4244
useBlockHoverState,
45+
useBlockSetAttributesContext,
4346
} from '~stackable/hooks'
4447

4548
const isEqualInitial = ( props, value, firstValue ) => {
@@ -51,6 +54,17 @@ const isEqualInitial = ( props, value, firstValue ) => {
5154
return isEqual
5255
}
5356

57+
// The value can be in the format '10px' or '10.0em' or '10rem'.
58+
// Return an array with the number and the unit.
59+
const extractNumberAndUnit = value => {
60+
// Match the last characters that are not numbers.
61+
const matches = value.match( /([\d.]+)(\D*)$/ )
62+
if ( ! matches ) {
63+
return [ value, '' ]
64+
}
65+
return [ matches[ 1 ], matches[ 2 ] ]
66+
}
67+
5468
const FourRangeControl = memo( props => {
5569
const [ _value, _onChange ] = useControlHandlers( props.attribute, props.responsive, props.hover, props.valueCallback, props.changeCallback )
5670
const [ propsToPass, controlProps ] = extractControlProps( props )
@@ -98,6 +112,7 @@ const FourRangeControl = memo( props => {
98112
label={ isLocked ? __( 'Individual sides', i18n ) : __( 'All sides', i18n ) }
99113
/>
100114

115+
const setAttributes = useBlockSetAttributesContext()
101116
const hasUnits = !! props.units?.length
102117
const unitAttrName = useAttributeName( `${ props.attribute }Unit`, props.responsive, props.hover )
103118

@@ -180,6 +195,25 @@ const FourRangeControl = memo( props => {
180195
: props.enableBottom ? { desktop: _valueDesktop?.bottom, tablet: _valueTablet?.bottom }
181196
: { desktop: _valueDesktop?.left, tablet: _valueTablet?.left }
182197

198+
// Is value at first render the same as a step value? If so, do mark mode
199+
// at the start, or show custom
200+
const isMarkValue = {
201+
first: !! props.marks,
202+
top: !! props.marks,
203+
right: !! props.marks,
204+
bottom: !! props.marks,
205+
left: !! props.marks,
206+
}
207+
if ( props.marks && value ) {
208+
// Check if the current value exsits in the marks
209+
isMarkValue.first = isMarkValue.first && props.marks.some( mark => mark.value === firstValue + unit )
210+
isMarkValue.top = isMarkValue.top && props.marks.some( mark => mark.value === value.top + unit )
211+
isMarkValue.right = isMarkValue.right && props.marks.some( mark => mark.value === value.right + unit )
212+
isMarkValue.bottom = isMarkValue.bottom && props.marks.some( mark => mark.value === value.bottom + unit )
213+
isMarkValue.left = isMarkValue.left && props.marks.some( mark => mark.value === value.left + unit )
214+
}
215+
const [ isFourMarkMode, setIsFourMarkMode ] = useState( isMarkValue )
216+
183217
const onChangeAll = newValue => {
184218
onChange( {
185219
top: props.enableTop ? newValue : value.top,
@@ -242,15 +276,114 @@ const FourRangeControl = memo( props => {
242276
left: newValue,
243277
} )
244278
}
279+
// Support for steps. Modify the props to make the range control show steps.
280+
const stepSupport = ( isMarkMode, initialValue, initialOnChange ) => {
281+
const newProps = { ...propsToPass }
282+
283+
if ( props.marks && isMarkMode ) {
284+
// Steps only have 1 increment values
285+
newProps.min = 0
286+
newProps.max = props.marks.length - 1
287+
newProps.sliderMin = 0
288+
newProps.sliderMax = props.marks.length - 1
289+
newProps.step = 1
290+
291+
// Show the marks and labels
292+
newProps.marks = props.marks.reduce( ( acc, mark, index ) => {
293+
return [
294+
{
295+
value: index,
296+
label: undefined,
297+
},
298+
...acc,
299+
]
300+
}, [] )
301+
newProps.renderTooltipContent = value => {
302+
return props.marks[ value ]?.label || ''
303+
}
304+
305+
// Other necessary props for steps.
306+
newProps.withInputField = false
307+
controlProps.units = false
308+
} else {
309+
newProps.marks = undefined
310+
}
311+
312+
if ( props.marks ) {
313+
controlProps.className = controlProps.className || ''
314+
controlProps.className += 'stk-range-control--with-marks'
315+
controlProps.className += isMarkMode ? ' stk-range-control--mark-mode' : ''
316+
}
317+
318+
// We need to change the way we handle the value and onChange if we're doing marks
319+
let rangeValue = initialValue
320+
let rangeOnChange = initialOnChange
321+
if ( props.marks && isMarkMode ) {
322+
rangeValue = props.marks.findIndex( mark => {
323+
const [ _value, _unit ] = extractNumberAndUnit( mark.value )
324+
return _value === value
325+
} )
326+
rangeOnChange = value => {
327+
if ( value === '' ) {
328+
return initialOnChange( value )
329+
}
330+
331+
// Extract the unit and value.
332+
const markValue = props.marks[ value ]?.value || '0'
333+
const [ _newValue, unit ] = extractNumberAndUnit( markValue )
334+
const newValue = _newValue
335+
336+
// Update the unit.
337+
dispatch( 'core/block-editor' ).__unstableMarkNextChangeAsNotPersistent()
338+
setAttributes( { [ unitAttrName ]: unit } )
339+
340+
initialOnChange( newValue )
341+
}
342+
}
343+
344+
return [
345+
newProps, rangeValue, rangeOnChange,
346+
]
347+
}
348+
349+
const [ propsToPassFirst, rangeValueFirst, rangeOnChangeFirst ] = stepSupport(
350+
isFourMarkMode.first,
351+
firstValue,
352+
onChangeAll,
353+
)
354+
355+
const [ propsToPassTop, rangeValueTop, rangeOnChangeTop ] = stepSupport(
356+
isFourMarkMode.top,
357+
value.top,
358+
onChangeTop,
359+
)
360+
361+
const [ propsToPassRight, rangeValueRight, rangeOnChangeRight ] = stepSupport(
362+
isFourMarkMode.right,
363+
value.right,
364+
onChangeRight,
365+
)
366+
367+
const [ propsToPassBottom, rangeValueBottom, rangeOnChangeBottom ] = stepSupport(
368+
isFourMarkMode.bottom,
369+
value.bottom,
370+
onChangeBottom,
371+
)
372+
373+
const [ propsToPassLeft, rangeValueLeft, rangeOnChangeLeft ] = stepSupport(
374+
isFourMarkMode.left,
375+
value.left,
376+
onChangeLeft,
377+
)
245378

246379
return (
247380
<AdvancedControl { ...controlProps }>
248381
{ isLocked && ! props.vhMode && (
249382
<Fragment>
250383
<RangeControl
251-
{ ...propsToPass }
252-
value={ firstValue }
253-
onChange={ onChangeAll }
384+
{ ...propsToPassFirst }
385+
value={ rangeValueFirst }
386+
onChange={ rangeOnChangeFirst }
254387
allowReset={ false }
255388
initialPosition={ ( () => {
256389
if ( currentHoverState !== 'normal' ) {
@@ -278,7 +411,21 @@ const FourRangeControl = memo( props => {
278411

279412
return propsToPass.placeholder
280413
} )() }
281-
/>
414+
__nextHasNoMarginBottom
415+
>
416+
{ props.allowCustom && props.marks && (
417+
<Button
418+
className="stk-range-control__custom-button"
419+
size="small"
420+
variant="tertiary"
421+
onClick={ () => setIsFourMarkMode( prev => {
422+
return { ...prev, first: ! prev.first }
423+
} ) }
424+
icon={ settings }
425+
>
426+
</Button>
427+
) }
428+
</RangeControl>
282429
<ResetButton
283430
allowReset={ props.allowReset }
284431
value={ firstValue }
@@ -384,9 +531,9 @@ const FourRangeControl = memo( props => {
384531
<span className="ugb-four-range-control__icon">{ props.isCorner ? <SVGUpperLeftImage /> : <SVGTopImage /> }</span>
385532
</Tooltip>
386533
<RangeControl
387-
{ ...propsToPass }
388-
value={ value.top }
389-
onChange={ onChangeTop }
534+
{ ...propsToPassTop }
535+
value={ rangeValueTop }
536+
onChange={ rangeOnChangeTop }
390537
allowReset={ false }
391538
initialPosition={ ( () => {
392539
if ( currentHoverState !== 'normal' ) {
@@ -414,7 +561,21 @@ const FourRangeControl = memo( props => {
414561

415562
return typeof props.placeholderTop === 'undefined' ? propsToPass.placeholder : props.placeholderTop
416563
} )() }
417-
/>
564+
__nextHasNoMarginBottom
565+
>
566+
{ props.allowCustom && props.marks && (
567+
<Button
568+
className="stk-range-control__custom-button"
569+
size="small"
570+
variant="tertiary"
571+
onClick={ () => setIsFourMarkMode( prev => {
572+
return { ...prev, top: ! prev.top }
573+
} ) }
574+
icon={ settings }
575+
>
576+
</Button>
577+
) }
578+
</RangeControl>
418579
<ResetButton
419580
allowReset={ props.allowReset }
420581
value={ value.top }
@@ -429,9 +590,9 @@ const FourRangeControl = memo( props => {
429590
<span className="ugb-four-range-control__icon">{ props.isCorner ? <SVGUpperRightImage /> : <SVGRightImage /> }</span>
430591
</Tooltip>
431592
<RangeControl
432-
{ ...propsToPass }
433-
value={ value.right }
434-
onChange={ onChangeRight }
593+
{ ...propsToPassRight }
594+
value={ rangeValueRight }
595+
onChange={ rangeOnChangeRight }
435596
allowReset={ false }
436597
initialPosition={ ( () => {
437598
if ( currentHoverState !== 'normal' ) {
@@ -459,7 +620,21 @@ const FourRangeControl = memo( props => {
459620

460621
return typeof props.placeholderRight === 'undefined' ? propsToPass.placeholder : props.placeholderRight
461622
} )() }
462-
/>
623+
__nextHasNoMarginBottom
624+
>
625+
{ props.allowCustom && props.marks && (
626+
<Button
627+
className="stk-range-control__custom-button"
628+
size="small"
629+
variant="tertiary"
630+
onClick={ () => setIsFourMarkMode( prev => {
631+
return { ...prev, right: ! prev.right }
632+
} ) }
633+
icon={ settings }
634+
>
635+
</Button>
636+
) }
637+
</RangeControl>
463638
<ResetButton
464639
allowReset={ props.allowReset }
465640
value={ value.right }
@@ -474,9 +649,9 @@ const FourRangeControl = memo( props => {
474649
<span className="ugb-four-range-control__icon">{ props.isCorner ? <SVGLowerLeftImage /> : <SVGBottomImage /> }</span>
475650
</Tooltip>
476651
<RangeControl
477-
{ ...propsToPass }
478-
value={ value.bottom }
479-
onChange={ onChangeBottom }
652+
{ ...propsToPassBottom }
653+
value={ rangeValueBottom }
654+
onChange={ rangeOnChangeBottom }
480655
allowReset={ false }
481656
initialPosition={ ( () => {
482657
if ( currentHoverState !== 'normal' ) {
@@ -504,7 +679,21 @@ const FourRangeControl = memo( props => {
504679

505680
return typeof props.placeholderBottom === 'undefined' ? propsToPass.placeholder : props.placeholderBottom
506681
} )() }
507-
/>
682+
__nextHasNoMarginBottom
683+
>
684+
{ props.allowCustom && props.marks && (
685+
<Button
686+
className="stk-range-control__custom-button"
687+
size="small"
688+
variant="tertiary"
689+
onClick={ () => setIsFourMarkMode( prev => {
690+
return { ...prev, bottom: ! prev.bottom }
691+
} ) }
692+
icon={ settings }
693+
>
694+
</Button>
695+
) }
696+
</RangeControl>
508697
<ResetButton
509698
allowReset={ props.allowReset }
510699
value={ value.bottom }
@@ -519,9 +708,9 @@ const FourRangeControl = memo( props => {
519708
<span className="ugb-four-range-control__icon">{ props.isCorner ? <SVGLowerRightImage /> : <SVGLeftImage /> }</span>
520709
</Tooltip>
521710
<RangeControl
522-
{ ...propsToPass }
523-
value={ value.left }
524-
onChange={ onChangeLeft }
711+
{ ...propsToPassLeft }
712+
value={ rangeValueLeft }
713+
onChange={ rangeOnChangeLeft }
525714
allowReset={ false }
526715
initialPosition={ ( () => {
527716
if ( currentHoverState !== 'normal' ) {
@@ -549,7 +738,21 @@ const FourRangeControl = memo( props => {
549738

550739
return typeof props.placeholderLeft === 'undefined' ? propsToPass.placeholder : props.placeholderLeft
551740
} )() }
552-
/>
741+
__nextHasNoMarginBottom
742+
>
743+
{ props.allowCustom && props.marks && (
744+
<Button
745+
className="stk-range-control__custom-button"
746+
size="small"
747+
variant="tertiary"
748+
onClick={ () => setIsFourMarkMode( prev => {
749+
return { ...prev, left: ! prev.left }
750+
} ) }
751+
icon={ settings }
752+
>
753+
</Button>
754+
) }
755+
</RangeControl>
553756
<ResetButton
554757
allowReset={ props.allowReset }
555758
value={ value.left }
@@ -598,6 +801,9 @@ FourRangeControl.defaultProps = {
598801
onChange: undefined,
599802

600803
isCorner: false,
804+
805+
marks: undefined,
806+
allowCustom: true,
601807
}
602808

603809
export default memo( FourRangeControl )

0 commit comments

Comments
 (0)