-
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.
Create SliderControl relocating Slider as internal only component
Update snapshots Remove comments
- Loading branch information
1 parent
d8af9c2
commit 3f5f8b4
Showing
25 changed files
with
2,611 additions
and
1,019 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,2 @@ | ||
export { default as SliderControl } from './slider-control/component'; | ||
export { useSliderControl } from './slider-control/hook'; |
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,48 @@ | ||
/** | ||
* Internal dependencies | ||
*/ | ||
import { contextConnect, WordPressComponentProps } from '../../ui/context'; | ||
import { useMark } from './hook'; | ||
import { View } from '../../view'; | ||
|
||
import type { MarkProps } from '../types'; | ||
|
||
const UnconnectedMark = ( | ||
props: WordPressComponentProps< MarkProps, 'span' >, | ||
forwardedRef: React.ForwardedRef< any > | ||
) => { | ||
const { | ||
className, | ||
isFilled = false, | ||
label, | ||
labelClassName, | ||
style = {}, | ||
...otherProps | ||
} = useMark( props ); | ||
|
||
return ( | ||
<> | ||
<View | ||
as="span" | ||
{ ...otherProps } | ||
aria-hidden="true" | ||
className={ className } | ||
style={ style } | ||
ref={ forwardedRef } | ||
/> | ||
{ label && ( | ||
<View | ||
as="span" | ||
aria-hidden="true" | ||
className={ labelClassName } | ||
style={ style } | ||
> | ||
{ label } | ||
</View> | ||
) } | ||
</> | ||
); | ||
}; | ||
|
||
export const Mark = contextConnect( UnconnectedMark, 'Mark' ); | ||
export default Mark; |
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,38 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { useMemo } from '@wordpress/element'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import * as styles from '../styles'; | ||
import { useContextSystem, WordPressComponentProps } from '../../ui/context'; | ||
import { useCx } from '../../utils/hooks'; | ||
|
||
import type { MarkProps } from '../types'; | ||
|
||
export function useMark( props: WordPressComponentProps< MarkProps, 'span' > ) { | ||
const { className, disabled, isFilled, ...otherProps } = useContextSystem( | ||
props, | ||
'Mark' | ||
); | ||
|
||
// Generate dynamic class names. | ||
const cx = useCx(); | ||
const classes = useMemo( () => { | ||
return cx( styles.mark( { isFilled, disabled } ), className ); | ||
}, [ className, cx, disabled, isFilled ] ); | ||
|
||
const labelClassName = useMemo( () => { | ||
return cx( styles.markLabel( { isFilled } ) ); | ||
}, [ className, cx, isFilled ] ); | ||
|
||
return { | ||
...otherProps, | ||
className: classes, | ||
disabled, | ||
isFilled, | ||
labelClassName, | ||
}; | ||
} |
36 changes: 36 additions & 0 deletions
36
packages/components/src/slider-control/marks/component.tsx
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,36 @@ | ||
/** | ||
* Internal dependencies | ||
*/ | ||
import { contextConnect, WordPressComponentProps } from '../../ui/context'; | ||
import { useMarks } from './hook'; | ||
import { View } from '../../view'; | ||
import { Mark } from '../mark/component'; | ||
|
||
import type { MarksProps } from '../types'; | ||
|
||
const UnconnectedMarks = ( | ||
props: WordPressComponentProps< MarksProps, 'input', false >, | ||
forwardedRef: React.ForwardedRef< any > | ||
) => { | ||
const { className, disabled = false, marksData } = useMarks( props ); | ||
return ( | ||
<View | ||
as="span" | ||
aria-hidden="true" | ||
className={ className } | ||
ref={ forwardedRef } | ||
> | ||
{ marksData.map( ( mark ) => ( | ||
<Mark | ||
{ ...mark } | ||
key={ mark.key } | ||
aria-hidden="true" | ||
disabled={ disabled } | ||
/> | ||
) ) } | ||
</View> | ||
); | ||
}; | ||
|
||
export const Marks = contextConnect( UnconnectedMarks, 'Marks' ); | ||
export default Marks; |
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,43 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { useMemo } from '@wordpress/element'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import * as styles from '../styles'; | ||
import { useContextSystem, WordPressComponentProps } from '../../ui/context'; | ||
import { useCx } from '../../utils/hooks'; | ||
import useMarksData from './use-marks-data'; | ||
|
||
import type { MarksProps } from '../types'; | ||
|
||
export function useMarks( | ||
props: WordPressComponentProps< MarksProps, 'input', false > | ||
) { | ||
const { | ||
className, | ||
marks = false, | ||
min = 0, | ||
max = 100, | ||
step: stepProp = 1, | ||
value = 0, | ||
...otherProps | ||
} = useContextSystem( props, 'Marks' ); | ||
|
||
const step = stepProp === 'any' ? 1 : stepProp; | ||
const marksData = useMarksData( { marks, min, max, step, value } ); | ||
|
||
// Generate dynamic class names. | ||
const cx = useCx(); | ||
const classes = useMemo( () => { | ||
return cx( styles.marks, className ); | ||
}, [ className, cx ] ); | ||
|
||
return { | ||
...otherProps, | ||
className: classes, | ||
marksData, | ||
}; | ||
} |
53 changes: 53 additions & 0 deletions
53
packages/components/src/slider-control/marks/use-marks-data.ts
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,53 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { isRTL } from '@wordpress/i18n'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import type { MarkProps, useMarksDataArgs } from '../types'; | ||
|
||
const useMarksData = ( { | ||
marks, | ||
min = 0, | ||
max = 100, | ||
step = 1, | ||
value = 0, | ||
}: useMarksDataArgs ) => { | ||
if ( ! marks || step === 0 ) { | ||
return []; | ||
} | ||
|
||
const range = max - min; | ||
if ( ! Array.isArray( marks ) ) { | ||
marks = []; | ||
const count = 1 + Math.round( range / step ); | ||
while ( count > marks.push( { value: step * marks.length + min } ) ); | ||
} | ||
|
||
const placedMarks: MarkProps[] = []; | ||
marks.forEach( ( mark, index ) => { | ||
if ( mark.value < min || mark.value > max ) { | ||
return; | ||
} | ||
const key = `mark-${ index }`; | ||
const isFilled = mark.value <= value; | ||
const offset = `${ ( ( mark.value - min ) / range ) * 100 }%`; | ||
|
||
const offsetStyle = { | ||
[ isRTL() ? 'right' : 'left' ]: offset, | ||
}; | ||
|
||
placedMarks.push( { | ||
...mark, | ||
isFilled, | ||
key, | ||
style: offsetStyle, | ||
} ); | ||
} ); | ||
|
||
return placedMarks; | ||
}; | ||
|
||
export default useMarksData; |
130 changes: 130 additions & 0 deletions
130
packages/components/src/slider-control/slider-control/component.tsx
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,130 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { useInstanceId, useMergeRefs } from '@wordpress/compose'; | ||
import { __ } from '@wordpress/i18n'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import BaseControl from '../../base-control'; | ||
import Marks from '../marks/component'; | ||
import Slider from '../slider/component'; | ||
import Tooltip from '../tooltip/component'; | ||
import { contextConnect, WordPressComponentProps } from '../../ui/context'; | ||
import { useSliderControl } from './hook'; | ||
import { VStack } from '../../v-stack'; | ||
import { clamp } from '../../utils/math'; | ||
|
||
import type { SliderControlProps } from '../types'; | ||
|
||
const noop = () => {}; | ||
|
||
const UnconnectedSliderControl = ( | ||
props: WordPressComponentProps< SliderControlProps, 'input', false >, | ||
forwardedRef: React.ForwardedRef< any > | ||
) => { | ||
const { | ||
className, | ||
disabled, | ||
enableTooltip, | ||
help, | ||
hideLabelFromVision = false, | ||
inputRef, | ||
label, | ||
marks = false, | ||
max = 100, | ||
min = 0, | ||
onBlur = noop, | ||
onChange = noop, | ||
onFocus = noop, | ||
onMouseLeave = noop, | ||
onMouseMove = noop, | ||
renderTooltipContent = ( v ) => v, | ||
showTooltip, | ||
step = 1, | ||
value: valueProp, | ||
wrapperClassName, | ||
...otherProps | ||
} = useSliderControl( props ); | ||
|
||
const id = useInstanceId( UnconnectedSliderControl, 'slider-control' ); | ||
const describedBy = !! help ? `${ id }__help` : undefined; | ||
|
||
const value = valueProp; | ||
const isValueReset = value === null; | ||
const rangeFillValue = isValueReset ? ( max - min ) / 2 + min : value; | ||
const fillValue = isValueReset | ||
? 50 | ||
: ( ( value - min ) / ( max - min ) ) * 100; | ||
const fillPercentage = clamp( fillValue, 0, 100 ); | ||
|
||
return ( | ||
<BaseControl | ||
className={ className } | ||
label={ label } | ||
hideLabelFromVision={ hideLabelFromVision } | ||
id={ `${ id }` } | ||
help={ help } | ||
> | ||
<VStack className={ wrapperClassName }> | ||
<Slider | ||
aria-describedby={ describedBy } | ||
className="components-range-control__slider" | ||
disabled={ disabled } | ||
id={ `${ id }` } | ||
label={ label } | ||
max={ max } | ||
min={ min } | ||
onBlur={ onBlur } | ||
onChange={ onChange } | ||
onFocus={ onFocus } | ||
onMouseLeave={ onMouseLeave } | ||
onMouseMove={ onMouseMove } | ||
ref={ useMergeRefs( [ inputRef, forwardedRef ] ) } | ||
step={ step } | ||
value={ isValueReset ? undefined : value } | ||
{ ...otherProps } | ||
/> | ||
<Marks | ||
disabled={ disabled } | ||
marks={ marks } | ||
max={ max } | ||
min={ min } | ||
step={ step } | ||
value={ rangeFillValue } | ||
/> | ||
{ enableTooltip && ( | ||
<Tooltip | ||
inputRef={ inputRef } | ||
renderTooltipContent={ renderTooltipContent } | ||
show={ showTooltip } | ||
fillPercentage={ fillPercentage } | ||
value={ value } | ||
/> | ||
) } | ||
</VStack> | ||
</BaseControl> | ||
); | ||
}; | ||
|
||
/** | ||
* `SliderControl` is a form component that lets users choose a value within a | ||
* range. | ||
* | ||
* @example | ||
* ```jsx | ||
* import { SliderControl } from `@wordpress/components` | ||
* | ||
* function Example() { | ||
* return ( | ||
* <SliderControl /> | ||
* ); | ||
* } | ||
* ``` | ||
*/ | ||
export const SliderControl = contextConnect( | ||
UnconnectedSliderControl, | ||
'SliderControl' | ||
); | ||
export default SliderControl; |
Oops, something went wrong.