diff --git a/packages/react-component-library/cypress/selectors/RangeSliderE.ts b/packages/react-component-library/cypress/selectors/RangeSlider.ts similarity index 100% rename from packages/react-component-library/cypress/selectors/RangeSliderE.ts rename to packages/react-component-library/cypress/selectors/RangeSlider.ts diff --git a/packages/react-component-library/cypress/selectors/index.ts b/packages/react-component-library/cypress/selectors/index.ts index dfbef61cf8..45df782158 100644 --- a/packages/react-component-library/cypress/selectors/index.ts +++ b/packages/react-component-library/cypress/selectors/index.ts @@ -6,7 +6,7 @@ import datePicker from './DatePicker' import dismissibleBanner from './DismissibleBanner' import form from './form' import NumberInput from './NumberInput' -import rangeSliderE from './RangeSliderE' +import RangeSlider from './RangeSlider' import selectE from './SelectE' import timeline from './timeline' @@ -19,7 +19,7 @@ export default { dismissibleBanner, form, NumberInput, - rangeSliderE, + RangeSlider, selectE, timeline, } diff --git a/packages/react-component-library/cypress/specs/RangeSliderE/index.spec.ts b/packages/react-component-library/cypress/specs/RangeSlider/index.spec.ts similarity index 70% rename from packages/react-component-library/cypress/specs/RangeSliderE/index.spec.ts rename to packages/react-component-library/cypress/specs/RangeSlider/index.spec.ts index 6423450658..5687136ec2 100644 --- a/packages/react-component-library/cypress/specs/RangeSliderE/index.spec.ts +++ b/packages/react-component-library/cypress/specs/RangeSlider/index.spec.ts @@ -4,33 +4,31 @@ import { ColorNeutral200, ColorAction500 } from '@defencedigital/design-tokens' import selectors from '../../selectors' import { hexToRgb } from '../../helpers' -describe('RangeSliderE', () => { +describe('RangeSlider', () => { describe('the user clicks on the rail (beyond selected range)', () => { before(() => { - cy.visit( - '/iframe.html?id=range-slider-experimental--default&viewMode=story' - ) + cy.visit('/iframe.html?id=range-slider--default&viewMode=story') - cy.get(selectors.rangeSliderE.rail).click(800, 0) + cy.get(selectors.RangeSlider.rail).click(800, 0) }) it('should apply focus to the handle', () => { - cy.get(selectors.rangeSliderE.handle.handle).should('have.focus') + cy.get(selectors.RangeSlider.handle.handle).should('have.focus') }) it('should move the handle to that position', () => { - cy.get(selectors.rangeSliderE.handle.value) + cy.get(selectors.RangeSlider.handle.value) .contains('33') .should('be.visible') }) describe('the user clicks on the rail (within selected range)', () => { before(() => { - cy.get(selectors.rangeSliderE.rail).click(200, 0) + cy.get(selectors.RangeSlider.rail).click(200, 0) }) it('should move the handle to that position', () => { - cy.get(selectors.rangeSliderE.handle.value) + cy.get(selectors.RangeSlider.handle.value) .contains('8') .should('be.visible') }) @@ -39,30 +37,28 @@ describe('RangeSliderE', () => { describe('thresholds', () => { before(() => { - cy.visit( - '/iframe.html?id=range-slider-experimental--double-threshold&viewMode=story' - ) + cy.visit('/iframe.html?id=range-slider--double-threshold&viewMode=story') }) it('renders both thresholds', () => { - cy.get(selectors.rangeSliderE.thresholds.betweenThresholds).should( + cy.get(selectors.RangeSlider.thresholds.betweenThresholds).should( 'be.visible' ) - cy.get(selectors.rangeSliderE.thresholds.aboveThresholds).should( + cy.get(selectors.RangeSlider.thresholds.aboveThresholds).should( 'be.visible' ) }) describe.skip('the user clicks on the rail (below both thresholds)', () => { beforeEach(() => { - cy.get(selectors.rangeSliderE.rail).click(0, 0) + cy.get(selectors.RangeSlider.rail).click(0, 0) }) it('should no longer render either threshold', () => { - cy.get(selectors.rangeSliderE.thresholds.betweenThresholds).should( + cy.get(selectors.RangeSlider.thresholds.betweenThresholds).should( 'not.be.visible' ) - cy.get(selectors.rangeSliderE.thresholds.aboveThresholds).should( + cy.get(selectors.RangeSlider.thresholds.aboveThresholds).should( 'not.be.visible' ) }) @@ -71,14 +67,12 @@ describe('RangeSliderE', () => { describe('multiple handles', () => { before(() => { - cy.visit( - '/iframe.html?id=range-slider-experimental--multiple-handles&viewMode=story' - ) + cy.visit('/iframe.html?id=range-slider--multiple-handles&viewMode=story') }) it('correctly sets each marker active state', () => { // [- - * * * * * - -] - cy.get(selectors.rangeSliderE.markers).should(($marker) => { + cy.get(selectors.RangeSlider.markers).should(($marker) => { expect($marker.eq(0), 'marker 1').to.have.css( 'background-color', hexToRgb(ColorNeutral200) diff --git a/packages/react-component-library/src/components/RangeSlider/Handle.tsx b/packages/react-component-library/src/components/RangeSlider/Handle.tsx index f1e703aac8..b032a1ec17 100644 --- a/packages/react-component-library/src/components/RangeSlider/Handle.tsx +++ b/packages/react-component-library/src/components/RangeSlider/Handle.tsx @@ -1,58 +1,64 @@ -import React from 'react' +import React, { useState } from 'react' import { GetHandleProps, SliderItem } from 'react-compound-slider' -import { useThresholdColor } from './useThresholdColor' import { RangeSliderPositionBag, RangeSliderValueFormatter } from '.' +import { StyledHandleWrapper } from './partials/StyledHandleWrapper' import { StyledHandle } from './partials/StyledHandle' -import { StyledPercentage } from './partials/StyledPercentage' import { StyledValue } from './partials/StyledValue' export interface HandleProps { - activeHandleID: string domain: ReadonlyArray handle: SliderItem getHandleProps: GetHandleProps formatValue: RangeSliderValueFormatter - thresholds?: number[] } -export const Handle: React.FC = ({ - activeHandleID, - domain: [min, max], - handle: { id, value, percent }, - getHandleProps, - thresholds, - formatValue, -}) => { - const isActive: boolean = activeHandleID === id +export const Handle = React.forwardRef( + ( + { + domain: [min, max], + handle: { id, value, percent }, + getHandleProps, + formatValue, + }, + ref + ) => { + const [hasFocus, setHasFocus] = useState(false) - const positionBag: RangeSliderPositionBag = { - value, - percentage: percent, - } + const positionBag: RangeSliderPositionBag = { + value, + percentage: percent, + } - return ( - - - {`${Math.floor(percent)}%`} - - - {formatValue(positionBag)} - - - ) -} + return ( + + setHasFocus(true)} + onBlur={(_) => setHasFocus(false)} + /> + + (ref as React.RefObject).current?.focus() + } + > + {formatValue(positionBag)} + + + ) + } +) Handle.displayName = 'Handle' diff --git a/packages/react-component-library/src/components/RangeSlider/RangeSlider.stories.tsx b/packages/react-component-library/src/components/RangeSlider/RangeSlider.stories.tsx index ed51ca2c4b..7610ac0db2 100644 --- a/packages/react-component-library/src/components/RangeSlider/RangeSlider.stories.tsx +++ b/packages/react-component-library/src/components/RangeSlider/RangeSlider.stories.tsx @@ -1,4 +1,5 @@ import React from 'react' +import styled from 'styled-components' import { ComponentStory, ComponentMeta } from '@storybook/react' import { @@ -28,205 +29,143 @@ const disableColorContrastRule = { }, } -export const Default: ComponentStory = (props) => ( -
+const StyledWrapper = styled.div` + display: flex; + height: 5rem; + padding: 0 1.5rem; +` + +const Template: ComponentStory = (props) => ( + -
+ ) +export const Default = Template.bind({}) Default.args = { domain: [0, 40], mode: 1, values: [20], tracksLeft: true, } - Default.parameters = disableColorContrastRule -export const MultipleHandles: ComponentStory = (props) => ( -
- -
-) - +export const MultipleHandles = Template.bind({}) +MultipleHandles.args = { + domain: [0, 40], + mode: 2, + values: [10, 30], + step: 1, + tickCount: 10, + hasMarkers: true, + displayUnit: 'pt', +} MultipleHandles.storyName = 'Multiple handles' - MultipleHandles.parameters = disableColorContrastRule -export const SingleThreshold: ComponentStory = (props) => ( -
- -
-) - +export const SingleThreshold = Template.bind({}) +SingleThreshold.args = { + domain: [0, 40], + mode: 1, + values: [30], + tracksLeft: true, + hasMarkers: true, + thresholds: [40], +} SingleThreshold.storyName = 'Single threshold' - SingleThreshold.parameters = disableColorContrastRule -export const DoubleThreshold: ComponentStory = (props) => ( -
- -
-) - +export const DoubleThreshold = Template.bind({}) +DoubleThreshold.args = { + domain: [0, 40], + mode: 1, + values: [30], + tracksLeft: true, + hasMarkers: true, + thresholds: [40, 60], +} DoubleThreshold.storyName = 'Double threshold' - DoubleThreshold.parameters = disableColorContrastRule -export const CustomValueFormatter: ComponentStory = ( - props -) => ( -
- `£${value.toFixed(2)}`} - /> -
-) - +export const CustomValueFormatter = Template.bind({}) +CustomValueFormatter.args = { + domain: [0, 40], + mode: 1, + values: [20], + tickCount: 4, + tracksLeft: true, + hasMarkers: true, + formatValue: ({ value }) => `£${value.toFixed(2)}`, +} CustomValueFormatter.storyName = 'Custom value formatter' - CustomValueFormatter.parameters = disableColorContrastRule -export const Stepped: ComponentStory = (props) => ( -
- -
-) - +export const Stepped = Template.bind({}) +Stepped.args = { + domain: [0, 40], + step: 10, + mode: 1, + values: [20], + tickCount: 4, + tracksLeft: true, + hasMarkers: true, +} Stepped.storyName = 'Stepped' - Stepped.parameters = disableColorContrastRule -export const WithPercentage: ComponentStory = (props) => ( -
- -
-) - -WithPercentage.storyName = 'With percentage' - -WithPercentage.parameters = disableColorContrastRule - -export const WithIcons: ComponentStory = (props) => ( -
- -
-) - +export const WithIcons = Template.bind({}) +WithIcons.args = { + domain: [0, 40], + step: 10, + mode: 1, + values: [20], + tickCount: 4, + tracksLeft: true, + hasMarkers: true, + IconLeft: IconBrightnessLow, + IconRight: IconBrightnessHigh, +} WithIcons.storyName = 'With icons' - WithIcons.parameters = disableColorContrastRule -export const WithLabels: ComponentStory = (props) => ( -
- -
-) - +export const WithLabels = Template.bind({}) +WithLabels.args = { + domain: [0, 40], + step: 2, + mode: 1, + values: [20], + tracksLeft: true, + hasLabels: true, + hasMarkers: true, + tickCount: 20, +} WithLabels.storyName = 'With labels' - WithLabels.parameters = disableColorContrastRule -export const ReversedScale: ComponentStory = (props) => ( -
- -
-) - +export const ReversedScale = Template.bind({}) +ReversedScale.args = { + domain: [0, 40], + step: 2, + mode: 1, + values: [20], + tracksRight: true, + hasLabels: true, + hasMarkers: true, + tickCount: 20, + isReversed: true, +} ReversedScale.storyName = 'Reversed scale' - ReversedScale.parameters = disableColorContrastRule -export const Disabled: ComponentStory = (props) => ( -
- -
-) - +export const Disabled = Template.bind({}) +Disabled.args = { + domain: [0, 40], + step: 10, + mode: 1, + values: [20], + tracksLeft: true, + hasMarkers: true, + isDisabled: true, +} Disabled.storyName = 'Disabled' - Disabled.parameters = disableColorContrastRule diff --git a/packages/react-component-library/src/components/RangeSlider/RangeSlider.test.tsx b/packages/react-component-library/src/components/RangeSlider/RangeSlider.test.tsx index e1dfbae4b9..eebd60586d 100644 --- a/packages/react-component-library/src/components/RangeSlider/RangeSlider.test.tsx +++ b/packages/react-component-library/src/components/RangeSlider/RangeSlider.test.tsx @@ -23,8 +23,8 @@ describe('RangeSlider', () => { values: ReadonlyArray, data: { activeHandleID: string } ) => void - let domain: number[] // lower and upper bounds - let values: number[] // initial handle values + let domain: readonly [number, number] // lower and upper bounds + let values: readonly [number] | readonly [number, number] // initial handle values let step: number let tickCount: number @@ -53,10 +53,6 @@ describe('RangeSlider', () => { ) }) - it('should not display the percentage value next to the handle', () => { - expect(wrapper.getByTestId('rangeslider-percentage')).not.toBeVisible() - }) - it('should set the correct `tabindex`', () => { expect(wrapper.getByTestId('rangeslider-handle')).toHaveAttribute( 'tabindex', @@ -94,6 +90,10 @@ describe('RangeSlider', () => { expect(wrapper.queryAllByTestId('rangeslider-label')).toHaveLength(0) }) + it('should not render any markers', () => { + expect(wrapper.queryAllByTestId('rangeslider-marker')).toHaveLength(2) + }) + describe('and the end user moves the handle to the right using keyboard', () => { beforeEach(() => { userEvent.click(wrapper.getByTestId('rangeslider-handle')) @@ -140,7 +140,7 @@ describe('RangeSlider', () => { it('renders the correct track chunks', () => { expect( - wrapper.queryByTestId('rangeslider-chunk-below-first-threshold') + wrapper.queryByTestId('rangeslider-track-below-first-threshold') ).toBeInTheDocument() }) }) @@ -160,10 +160,10 @@ describe('RangeSlider', () => { it('renders the correct track chunks', () => { expect( - wrapper.queryByTestId('rangeslider-chunk-below-first-threshold') + wrapper.queryByTestId('rangeslider-track-below-first-threshold') ).toBeInTheDocument() expect( - wrapper.queryByTestId('rangeslider-chunk-between-thresholds') + wrapper.queryByTestId('rangeslider-track-between-thresholds') ).toBeInTheDocument() }) }) @@ -246,7 +246,7 @@ describe('RangeSlider', () => { describe('multiple handles', () => { beforeEach(() => { - values = [10, 20, 30] + values = [10, 20] wrapper = render( { }) it('should render two handles', () => { - expect(wrapper.queryAllByTestId('rangeslider-handle')).toHaveLength(3) + expect(wrapper.queryAllByTestId('rangeslider-handle')).toHaveLength(2) }) }) - describe('when the `hasPercentage` prop is provided', () => { + describe('when the `displayUnit` prop is provided', () => { beforeEach(() => { wrapper = render( { tracksLeft tickCount={4} thresholds={[40, 60]} - hasPercentage + displayUnit="pt" /> ) }) - it('should display the percentage value next to the handle', () => { - expect(wrapper.getByTestId('rangeslider-percentage')).toBeVisible() + it('should append the display unit to the handle label', () => { + expect(wrapper.getByTestId('rangeslider-value')).toHaveTextContent('20pt') }) }) - describe('when the `displayUnit` prop is provided', () => { + describe('when the `formatValue` prop is provided', () => { beforeEach(() => { wrapper = render( { tracksLeft tickCount={4} thresholds={[40, 60]} - displayUnit="pt" + formatValue={({ value }) => `£${value}`} /> ) }) - it('should append the display unit to the handle label', () => { - expect(wrapper.getByTestId('rangeslider-value')).toHaveTextContent('20pt') + it('formats the handle label using the provided formatter', () => { + expect(wrapper.getByTestId('rangeslider-value')).toHaveTextContent('£20') }) }) - describe('when the `formatValue` prop is provided', () => { + describe('when markers and labels are enabled', () => { beforeEach(() => { wrapper = render( { tracksLeft tickCount={4} thresholds={[40, 60]} - formatValue={({ value }) => `£${value}`} + hasMarkers + hasLabels /> ) }) - it('formats the handle label using the provided formatter', () => { - expect(wrapper.getByTestId('rangeslider-value')).toHaveTextContent('£20') + it('should render the correct number of labels', () => { + expect(wrapper.queryAllByTestId('rangeslider-label')).toHaveLength(5) + }) + + it('should render the correct number of markers', () => { + expect(wrapper.queryAllByTestId('rangeslider-marker')).toHaveLength(5) }) }) diff --git a/packages/react-component-library/src/components/RangeSlider/Slider.tsx b/packages/react-component-library/src/components/RangeSlider/Slider.tsx index 0f870cdfce..c87a6b64ef 100644 --- a/packages/react-component-library/src/components/RangeSlider/Slider.tsx +++ b/packages/react-component-library/src/components/RangeSlider/Slider.tsx @@ -1,4 +1,5 @@ -import React, { useCallback, useState } from 'react' +import React, { useCallback, useState, createRef } from 'react' +import intersection from 'lodash/intersection' import { SliderProps, CustomMode, @@ -13,6 +14,7 @@ import { RangeSliderValueFormatter, Track, ThresholdTrack, + ThresholdRail, Tick, } from '.' import { StyledSlider } from './partials/StyledSlider' @@ -40,13 +42,13 @@ export interface RangeSliderProps extends Omit { * Two element array of numbers providing the min and max values for the slider [min, max] e.g. [0, 100]. * It does not matter if the slider is reversed on the screen, domain is always [min, max] with min < max. */ - domain?: ReadonlyArray + domain: readonly [number, number] /** - * An array of numbers. You can supply one for a value slider, two for a range slider or more to create n-handled sliders. + * An array of numbers. You can supply one for a value slider, two for a range slider. * The values should correspond to valid step values in the domain. * The numbers will be forced into the domain if they are two small or large. */ - values: ReadonlyArray + values: readonly [number] | readonly [number, number] /** * The step value for the slider. */ @@ -62,6 +64,10 @@ export interface RangeSliderProps extends Omit { * Toggles whether or not to display labels below the slider. */ hasLabels?: boolean + /** + * Toggles whether or not to display value markers along the slider. + */ + hasMarkers?: boolean /** * Toggles whether to display colored tracks to the left of the handle. */ @@ -71,7 +77,7 @@ export interface RangeSliderProps extends Omit { */ tracksRight?: boolean /** - * The number of tickets to display along the slider track. + * The number of Tickts to display along the slider track. */ tickCount?: number /** @@ -94,10 +100,6 @@ export interface RangeSliderProps extends Omit { * Optional numeric array of thresholds to display on the slider bar (up to 2). */ thresholds?: number[] - /** - * Toggles whether to display percentage values alongside the draggable handles. - */ - hasPercentage?: boolean /** * Toggles whether to display unit values alongside the draggable handles. */ @@ -112,6 +114,7 @@ export const RangeSlider: React.FC = ({ domain, step, hasLabels, + hasMarkers, tracksLeft = false, tracksRight = false, tickCount = 10, @@ -123,7 +126,6 @@ export const RangeSlider: React.FC = ({ onChange, onUpdate, thresholds, - hasPercentage, displayUnit = '', formatValue, mode, @@ -131,17 +133,38 @@ export const RangeSlider: React.FC = ({ onSlideEnd, ...rest }) => { - const [sliderValues, setSliderValues] = useState(values) + const [sliderValues, setSliderValues] = + useState>(values) + const handleRefs = values.map(() => createRef()) + + const focusHandle = useCallback( + (newValues: ReadonlyArray): void => { + const staticValues = intersection(sliderValues, newValues) + + // Single handle + if (sliderValues.length === 1) { + handleRefs[0].current?.focus() + } + + // Multiple handles + if (sliderValues.length === 2 && staticValues.length === 1) { + const refId = sliderValues.indexOf(staticValues[0]) === 1 ? 0 : 1 + handleRefs[refId].current?.focus() + } + }, + [sliderValues, handleRefs] + ) const onUpdateHandler = useCallback( (newValues: ReadonlyArray): void => { + focusHandle(newValues) setSliderValues(newValues) if (onUpdate) { onUpdate(newValues) } }, - [onUpdate, setSliderValues] + [onUpdate, setSliderValues, focusHandle] ) const formatValueDefault: RangeSliderValueFormatter = useCallback( @@ -153,13 +176,12 @@ export const RangeSlider: React.FC = ({ {IconLeft && ( - + )} = ({ > {({ getRailProps }) => ( - - + + + {thresholds && } + )} - {({ activeHandleID, handles, getHandleProps }) => ( + {({ handles, getHandleProps }) => (
- {handles.map((handle) => ( + {handles.map((handle, index) => ( ))}
@@ -238,11 +261,14 @@ export const RangeSlider: React.FC = ({ key={tick.id} tick={tick} count={ticks.length} + hasMarkers={hasMarkers} hasLabels={hasLabels} values={sliderValues} domain={domain} isReversed={isReversed} thresholds={thresholds} + tracksLeft={tracksLeft} + tracksRight={tracksRight} /> ))} @@ -252,7 +278,7 @@ export const RangeSlider: React.FC = ({
{IconRight && ( - + )}
diff --git a/packages/react-component-library/src/components/RangeSliderE/ThresholdRailE.tsx b/packages/react-component-library/src/components/RangeSlider/ThresholdRail.tsx similarity index 84% rename from packages/react-component-library/src/components/RangeSliderE/ThresholdRailE.tsx rename to packages/react-component-library/src/components/RangeSlider/ThresholdRail.tsx index c324deeede..8a9e983288 100644 --- a/packages/react-component-library/src/components/RangeSliderE/ThresholdRailE.tsx +++ b/packages/react-component-library/src/components/RangeSlider/ThresholdRail.tsx @@ -9,11 +9,11 @@ import { } from './constants' import { StyledRailChunk } from './partials/StyledRailChunk' -export interface ThresholdRailEProps { +export interface ThresholdRailProps { thresholds: number[] } -export interface RailChunkEProps { +export interface RailChunkProps { $left: number $width: number $maxWidth: number @@ -21,7 +21,7 @@ export interface RailChunkEProps { $thresholdColor?: ThresholdColor } -const RailChunkE: React.FC = ({ +const RailChunk: React.FC = ({ $left, $width, $maxWidth, @@ -42,16 +42,14 @@ const RailChunkE: React.FC = ({ ) } -export const ThresholdRailE: React.FC = ({ - thresholds, -}) => { +export const ThresholdRail: React.FC = ({ thresholds }) => { const singleThreshold = thresholds?.length === 1 const doubleThreshold = thresholds?.length === 2 return ( <> {(singleThreshold || doubleThreshold) && ( - = ({ )} {doubleThreshold && ( - = ({ testId="between-thresholds" > - + )} - = ({ testId="above-thresholds" > - + ) } -ThresholdRailE.displayName = 'ThresholdRailE' +ThresholdRail.displayName = 'ThresholdRail' diff --git a/packages/react-component-library/src/components/RangeSlider/ThresholdTrack.tsx b/packages/react-component-library/src/components/RangeSlider/ThresholdTrack.tsx index 06152363e4..994627eeba 100644 --- a/packages/react-component-library/src/components/RangeSlider/ThresholdTrack.tsx +++ b/packages/react-component-library/src/components/RangeSlider/ThresholdTrack.tsx @@ -7,14 +7,14 @@ import { RANGE_SLIDER_TRACK_BETWEEN_THRESHOLDS, RANGE_SLIDER_TRACK_ABOVE_THRESHOLDS, } from './constants' -import { StyledChunk } from './partials/StyledChunk' +import { StyledTrackChunk } from './partials/StyledTrackChunk' export interface ThresholdTrackProps extends TrackItem { getTrackProps: GetTrackProps - thresholds?: number[] + thresholds: number[] } -export interface ChunkProps { +export interface TrackChunkProps { getTrackProps: GetTrackProps $left: number $width: number @@ -23,7 +23,7 @@ export interface ChunkProps { $thresholdColor?: ThresholdColor } -const Chunk: React.FC = ({ +const TrackChunk: React.FC = ({ getTrackProps, $left, $width, @@ -32,13 +32,13 @@ const Chunk: React.FC = ({ $thresholdColor, }) => { return ( - ) } @@ -54,7 +54,7 @@ export const ThresholdTrack: React.FC = ({ return ( <> {(singleThreshold || doubleThreshold) && ( - = ({ )} {doubleThreshold && ( - )} - diff --git a/packages/react-component-library/src/components/RangeSlider/Tick.tsx b/packages/react-component-library/src/components/RangeSlider/Tick.tsx index c566e8f6d0..5962c862e1 100644 --- a/packages/react-component-library/src/components/RangeSlider/Tick.tsx +++ b/packages/react-component-library/src/components/RangeSlider/Tick.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { useMemo } from 'react' import { SliderItem } from 'react-compound-slider' import { useThresholdColor } from './useThresholdColor' @@ -9,35 +9,68 @@ export interface TickProps { tick: SliderItem count: number hasLabels?: boolean + hasMarkers?: boolean values: ReadonlyArray domain: ReadonlyArray isReversed?: boolean thresholds?: number[] + tracksLeft?: boolean + tracksRight?: boolean } -function isActive(values: ReadonlyArray, tickValue: number): boolean { - return values.some((item) => item >= tickValue) +function isActive( + values: ReadonlyArray, + tickValue: number, + tracksLeft: boolean, + tracksRight: boolean +): boolean { + if (!tracksLeft && !tracksRight) { + return tickValue >= values[0] && tickValue <= values[1] + } + + if (tracksLeft && tracksRight) { + return true + } + + return values.some((item) => tickValue <= item) } export const Tick: React.FC = ({ tick, count, hasLabels, + hasMarkers, values, domain, isReversed, thresholds, + tracksLeft = false, + tracksRight = false, }) => { - const percent: number = isReversed ? 100 - tick.percent : tick.percent // invert if reversed - const tickValue: number = (domain[1] / 100) * percent + const percent: number = useMemo( + () => (isReversed ? 100 - tick.percent : tick.percent), + [tick.percent, isReversed] + ) // invert if reversed + + const tickValue: number = useMemo( + () => (domain[1] / 100) * percent, + [domain, percent] + ) + + const thresholdColor = useThresholdColor(percent, thresholds) + + const showMarker = percent === 0 || percent === 100 || hasMarkers return (
- + {showMarker && ( + + )} {hasLabels && ( ( - ({ $left, $width, $maxWidth }) => ({ - style: { - left: $left, - width: $width, - maxWidth: $maxWidth, - }, - }) -)` - position: absolute; - transform: translate(0%, -50%); - height: 2px; - z-index: 1; - background-color: ${RANGE_SLIDER_TRACK_COLOR}; - cursor: pointer; - - ${({ $thresholdColor }) => css` - background-color: ${$thresholdColor}; - - &::after { - color: ${$thresholdColor}; - background-color: ${transparentize(0.75, $thresholdColor)}; - } - `} -` diff --git a/packages/react-component-library/src/components/RangeSlider/partials/StyledHandle.tsx b/packages/react-component-library/src/components/RangeSlider/partials/StyledHandle.tsx index f298f83acb..7a4428ccd5 100644 --- a/packages/react-component-library/src/components/RangeSlider/partials/StyledHandle.tsx +++ b/packages/react-component-library/src/components/RangeSlider/partials/StyledHandle.tsx @@ -1,80 +1,28 @@ -import styled, { css } from 'styled-components' +import styled from 'styled-components' import { selectors } from '@defencedigital/design-tokens' import { transparentize } from 'polished' import { RANGE_SLIDER_HANDLE_COLOR } from '../constants' -import { ThresholdColor } from '../useThresholdColor' -import { StyledValue } from './StyledValue' -import { StyledPercentage } from './StyledPercentage' - -interface StyledHandleProps { - $isActive?: boolean - $thresholdColor?: ThresholdColor - $left: string -} const { color } = selectors -export const StyledHandle = styled.div.attrs(({ $left }) => ({ - style: { - left: $left, - }, -}))` +export const StyledHandle = styled.div` position: absolute; - transform: translate(-50%, -50%); - z-index: 2; - width: 14px; - height: 14px; + transform: translate(-10px, -50%); + width: 18px; + height: 18px; margin-left: 1px; border: none; border-radius: 9999px; background-color: ${RANGE_SLIDER_HANDLE_COLOR}; text-align: center; - box-shadow: 0px 0px 0px 0px ${transparentize(0.5, color('neutral', '200'))}; transition: box-shadow 0.15s ease-in-out; cursor: pointer; - - &:nth-of-type(2n) { - ${StyledValue} { - transform: translate(-50%, 125%); - } - - ${StyledPercentage} { - transform: translate(-50%, 355%); - } - } - - ${({ $isActive }) => - $isActive && - css` - box-shadow: 0px 0px 0px 7px - ${transparentize(0.5, color('neutral', '200'))}; - outline: none; - - ${StyledValue}, - ${StyledPercentage} { - opacity: 1; - } - `} + box-shadow: 1px 1px 2px 0px rgba(000, 000, 000, 0.25); &:focus { - box-shadow: 0px 0px 0px 7px ${transparentize(0.5, color('neutral', '200'))}; + box-shadow: 1px 1px 2px 0px rgba(000, 000, 000, 0.25), + 0px 0px 0px 5px ${transparentize(0.5, color('action', '200'))}; outline: none; - - ${StyledValue}, - ${StyledPercentage} { - opacity: 1; - } } - - ${({ $thresholdColor }) => - $thresholdColor && - css` - background-color: ${$thresholdColor}; - - ${StyledValue} { - color: ${$thresholdColor}; - background-color: ${transparentize(0.75, $thresholdColor)}; - } - `} ` diff --git a/packages/react-component-library/src/components/RangeSliderE/partials/StyledHandleWrapper.tsx b/packages/react-component-library/src/components/RangeSlider/partials/StyledHandleWrapper.tsx similarity index 100% rename from packages/react-component-library/src/components/RangeSliderE/partials/StyledHandleWrapper.tsx rename to packages/react-component-library/src/components/RangeSlider/partials/StyledHandleWrapper.tsx diff --git a/packages/react-component-library/src/components/RangeSlider/partials/StyledIconLeft.tsx b/packages/react-component-library/src/components/RangeSlider/partials/StyledIconLeft.tsx index fa18549e25..7d2cd0d399 100644 --- a/packages/react-component-library/src/components/RangeSlider/partials/StyledIconLeft.tsx +++ b/packages/react-component-library/src/components/RangeSlider/partials/StyledIconLeft.tsx @@ -4,9 +4,13 @@ import { selectors } from '@defencedigital/design-tokens' const { color, spacing } = selectors export const StyledIconLeft = styled.div` + display: inline-flex; + justify-content: center; + align-items: center; + svg { color: ${color('neutral', '400')}; overflow: visible; - margin-right: ${spacing('2')}; + margin-right: ${spacing('6')}; } ` diff --git a/packages/react-component-library/src/components/RangeSlider/partials/StyledIconRight.tsx b/packages/react-component-library/src/components/RangeSlider/partials/StyledIconRight.tsx index 4995b082e7..04a4815963 100644 --- a/packages/react-component-library/src/components/RangeSlider/partials/StyledIconRight.tsx +++ b/packages/react-component-library/src/components/RangeSlider/partials/StyledIconRight.tsx @@ -4,9 +4,13 @@ import { selectors } from '@defencedigital/design-tokens' const { color, spacing } = selectors export const StyledIconRight = styled.div` + display: inline-flex; + justify-content: center; + align-items: center; + svg { color: ${color('neutral', '400')}; overflow: visible; - margin-left: ${spacing('2')}; + margin-left: ${spacing('6')}; } ` diff --git a/packages/react-component-library/src/components/RangeSlider/partials/StyledLabel.tsx b/packages/react-component-library/src/components/RangeSlider/partials/StyledLabel.tsx index 6747560c70..65c98b39e3 100644 --- a/packages/react-component-library/src/components/RangeSlider/partials/StyledLabel.tsx +++ b/packages/react-component-library/src/components/RangeSlider/partials/StyledLabel.tsx @@ -11,8 +11,8 @@ const { fontSize, color } = selectors export const StyledLabel = styled.span` position: absolute; - margin-top: 22px; - font-size: ${fontSize('xs')}; + margin-top: 14px; + font-size: ${fontSize('s')}; color: ${color('neutral', '400')}; text-align: center; margin-left: ${({ $marginLeft }) => $marginLeft}; diff --git a/packages/react-component-library/src/components/RangeSlider/partials/StyledMarker.tsx b/packages/react-component-library/src/components/RangeSlider/partials/StyledMarker.tsx index edacc1af35..df19601be1 100644 --- a/packages/react-component-library/src/components/RangeSlider/partials/StyledMarker.tsx +++ b/packages/react-component-library/src/components/RangeSlider/partials/StyledMarker.tsx @@ -1,10 +1,10 @@ import styled, { css } from 'styled-components' -import { transparentize } from 'polished' +import { setLightness } from 'polished' import { ThresholdColor } from '../useThresholdColor' import { + RANGE_SLIDER_TRACK_BELOW_FIRST_THRESHOLD, RANGE_SLIDER_BG_COLOR, - RANGE_SLIDER_TRACK_ABOVE_THRESHOLDS, } from '../constants' interface StyledMarkerProps { @@ -15,26 +15,30 @@ interface StyledMarkerProps { export const StyledMarker = styled.div` position: absolute; - width: 2px; - height: 12px; - transform: translateY(-50%); - background-color: ${RANGE_SLIDER_TRACK_ABOVE_THRESHOLDS}; + width: 6px; + height: 6px; + border-radius: 999px; + transform: translate(-50%, -50%); + pointer-events: none; + background-color: ${RANGE_SLIDER_BG_COLOR}; left: ${({ $left }) => $left}; + ${({ $isActive }) => + $isActive && + css` + background-color: ${RANGE_SLIDER_TRACK_BELOW_FIRST_THRESHOLD}; + `}; + ${({ $thresholdColor }) => $thresholdColor && css` - background-color: ${$thresholdColor}; - - &::after { - color: ${$thresholdColor}; - background-color: ${transparentize(0.75, $thresholdColor)}; - } + background-color: ${setLightness(0.85, $thresholdColor)}; `} - ${({ $isActive }) => - !$isActive && + ${({ $isActive, $thresholdColor }) => + $isActive && + $thresholdColor && css` - background-color: ${RANGE_SLIDER_BG_COLOR}; + background-color: ${$thresholdColor}; `}; ` diff --git a/packages/react-component-library/src/components/RangeSlider/partials/StyledPercentage.tsx b/packages/react-component-library/src/components/RangeSlider/partials/StyledPercentage.tsx deleted file mode 100644 index ef5edbb9d7..0000000000 --- a/packages/react-component-library/src/components/RangeSlider/partials/StyledPercentage.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import styled from 'styled-components' -import { selectors } from '@defencedigital/design-tokens' - -const { fontSize, color } = selectors - -export const StyledPercentage = styled.span` - position: absolute; - transform: translate(-50%, -355%); - font-size: ${fontSize('s')}; - color: ${color('neutral', '300')}; - opacity: 1; - transition: opacity 0.15s ease-in-out; - font-weight: 700; -` diff --git a/packages/react-component-library/src/components/RangeSlider/partials/StyledRail.tsx b/packages/react-component-library/src/components/RangeSlider/partials/StyledRail.tsx index 35ee38bf02..6ab7581018 100644 --- a/packages/react-component-library/src/components/RangeSlider/partials/StyledRail.tsx +++ b/packages/react-component-library/src/components/RangeSlider/partials/StyledRail.tsx @@ -8,4 +8,5 @@ export const StyledRail = styled.div` width: 100%; height: 40px; transform: translateY(-100%); + cursor: pointer; ` diff --git a/packages/react-component-library/src/components/RangeSliderE/partials/StyledRailChunk.tsx b/packages/react-component-library/src/components/RangeSlider/partials/StyledRailChunk.tsx similarity index 100% rename from packages/react-component-library/src/components/RangeSliderE/partials/StyledRailChunk.tsx rename to packages/react-component-library/src/components/RangeSlider/partials/StyledRailChunk.tsx diff --git a/packages/react-component-library/src/components/RangeSlider/partials/StyledRangeSlider.tsx b/packages/react-component-library/src/components/RangeSlider/partials/StyledRangeSlider.tsx index 6dc6efd628..94f63f0c08 100644 --- a/packages/react-component-library/src/components/RangeSlider/partials/StyledRangeSlider.tsx +++ b/packages/react-component-library/src/components/RangeSlider/partials/StyledRangeSlider.tsx @@ -1,11 +1,8 @@ import styled, { css } from 'styled-components' -import { StyledPercentage } from './StyledPercentage' - interface StyledRangeSliderProps { $isReversed?: boolean $isDisabled?: boolean - $hasPercentage?: boolean } export const StyledRangeSlider = styled.div` @@ -19,16 +16,8 @@ export const StyledRangeSlider = styled.div` opacity: 0.5; cursor: not-allowed; - * { + &&& * { cursor: not-allowed; } `} - - ${({ $hasPercentage }) => - !$hasPercentage && - ` - ${StyledPercentage} { - display: none; - } - `} ` diff --git a/packages/react-component-library/src/components/RangeSlider/partials/StyledTicks.tsx b/packages/react-component-library/src/components/RangeSlider/partials/StyledTicks.tsx index d89f3ea23d..3c80568751 100644 --- a/packages/react-component-library/src/components/RangeSlider/partials/StyledTicks.tsx +++ b/packages/react-component-library/src/components/RangeSlider/partials/StyledTicks.tsx @@ -4,7 +4,8 @@ export const StyledTicks = styled.div` div:first-of-type, div:last-of-type { div { - height: 16px; + height: 20px; + width: 2px; } } ` diff --git a/packages/react-component-library/src/components/RangeSlider/partials/StyledTrack.tsx b/packages/react-component-library/src/components/RangeSlider/partials/StyledTrack.tsx index 68d9550ae1..5f73d8711d 100644 --- a/packages/react-component-library/src/components/RangeSlider/partials/StyledTrack.tsx +++ b/packages/react-component-library/src/components/RangeSlider/partials/StyledTrack.tsx @@ -10,8 +10,7 @@ interface StyledTrackProps { export const StyledTrack = styled.div` position: absolute; transform: translate(0%, -50%); - height: 2px; - z-index: 1; + height: 6px; background-color: ${RANGE_SLIDER_TRACK_COLOR}; cursor: pointer; width: ${({ $width }) => $width}; diff --git a/packages/react-component-library/src/components/RangeSliderE/partials/StyledTrackChunk.tsx b/packages/react-component-library/src/components/RangeSlider/partials/StyledTrackChunk.tsx similarity index 100% rename from packages/react-component-library/src/components/RangeSliderE/partials/StyledTrackChunk.tsx rename to packages/react-component-library/src/components/RangeSlider/partials/StyledTrackChunk.tsx diff --git a/packages/react-component-library/src/components/RangeSlider/partials/StyledValue.tsx b/packages/react-component-library/src/components/RangeSlider/partials/StyledValue.tsx index 967c05bf9f..f19136b129 100644 --- a/packages/react-component-library/src/components/RangeSlider/partials/StyledValue.tsx +++ b/packages/react-component-library/src/components/RangeSlider/partials/StyledValue.tsx @@ -3,14 +3,16 @@ import { selectors } from '@defencedigital/design-tokens' const { fontSize, spacing, color } = selectors -export const StyledValue = styled.span` +export const StyledValue = styled.div` position: absolute; - transform: translate(-50%, -155%); - font-size: ${fontSize('xs')}; - color: ${color('neutral', '600')}; - opacity: 1; - transition: opacity 0.15s ease-in-out; - padding: ${spacing('2')} ${spacing('3')}; - border-radius: 12px; + display: inline-block; + transform: translate(-50%, -160%); + font-size: ${fontSize('m')}; + color: ${color('neutral', '500')}; + padding: ${spacing('3')} ${spacing('4')}; + border-radius: 8px; + border: 1px solid ${color('neutral', '200')}; font-weight: 600; + background-color: ${color('neutral', 'white')}; + cursor: pointer; ` diff --git a/packages/react-component-library/src/components/RangeSlider/useThresholdColor.ts b/packages/react-component-library/src/components/RangeSlider/useThresholdColor.ts index d68940192f..6378b1beb1 100644 --- a/packages/react-component-library/src/components/RangeSlider/useThresholdColor.ts +++ b/packages/react-component-library/src/components/RangeSlider/useThresholdColor.ts @@ -11,7 +11,7 @@ export type ThresholdColor = export function useThresholdColor( percent: number, - thresholds: number[] + thresholds: number[] | undefined ): ThresholdColor | undefined { const singleThreshold = thresholds?.length === 1 const doubleThreshold = thresholds?.length === 2 diff --git a/packages/react-component-library/src/components/RangeSliderE/HandleE.tsx b/packages/react-component-library/src/components/RangeSliderE/HandleE.tsx deleted file mode 100644 index 477533011b..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/HandleE.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import React, { useState } from 'react' -import { GetHandleProps, SliderItem } from 'react-compound-slider' - -import { RangeSliderEPositionBag, RangeSliderEValueFormatter } from '.' -import { StyledHandleWrapper } from './partials/StyledHandleWrapper' -import { StyledHandle } from './partials/StyledHandle' -import { StyledValue } from './partials/StyledValue' - -export interface HandleEProps { - domain: ReadonlyArray - handle: SliderItem - getHandleProps: GetHandleProps - formatValue: RangeSliderEValueFormatter -} - -export const HandleE = React.forwardRef( - ( - { - domain: [min, max], - handle: { id, value, percent }, - getHandleProps, - formatValue, - }, - ref - ) => { - const [hasFocus, setHasFocus] = useState(false) - - const positionBag: RangeSliderEPositionBag = { - value, - percentage: percent, - } - - return ( - - setHasFocus(true)} - onBlur={(_) => setHasFocus(false)} - /> - - (ref as React.RefObject).current?.focus() - } - > - {formatValue(positionBag)} - - - ) - } -) - -HandleE.displayName = 'HandleE' diff --git a/packages/react-component-library/src/components/RangeSliderE/RangeSliderE.stories.tsx b/packages/react-component-library/src/components/RangeSliderE/RangeSliderE.stories.tsx deleted file mode 100644 index 8c12e15fae..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/RangeSliderE.stories.tsx +++ /dev/null @@ -1,171 +0,0 @@ -import React from 'react' -import styled from 'styled-components' -import { ComponentStory, ComponentMeta } from '@storybook/react' - -import { - IconBrightnessLow, - IconBrightnessHigh, -} from '@defencedigital/icon-library' -import { RangeSliderE } from './index' - -export default { - component: RangeSliderE, - title: 'Range Slider (Experimental)', - parameters: { - actions: { argTypesRegex: '^on.*' }, - }, -} as ComponentMeta - -const disableColorContrastRule = { - a11y: { - config: { - rules: [ - { - id: 'color-contrast', - enabled: false, - }, - ], - }, - }, -} - -const StyledWrapper = styled.div` - display: flex; - height: 5rem; - padding: 0 1.5rem; -` - -const Template: ComponentStory = (props) => ( - - - -) - -export const Default = Template.bind({}) -Default.args = { - domain: [0, 40], - mode: 1, - values: [20], - tracksLeft: true, -} -Default.parameters = disableColorContrastRule - -export const MultipleHandles = Template.bind({}) -MultipleHandles.args = { - domain: [0, 40], - mode: 2, - values: [10, 30], - step: 1, - tickCount: 10, - hasMarkers: true, - displayUnit: 'pt', -} -MultipleHandles.storyName = 'Multiple handles' -MultipleHandles.parameters = disableColorContrastRule - -export const SingleThreshold = Template.bind({}) -SingleThreshold.args = { - domain: [0, 40], - mode: 1, - values: [30], - tracksLeft: true, - hasMarkers: true, - thresholds: [40], -} -SingleThreshold.storyName = 'Single threshold' -SingleThreshold.parameters = disableColorContrastRule - -export const DoubleThreshold = Template.bind({}) -DoubleThreshold.args = { - domain: [0, 40], - mode: 1, - values: [30], - tracksLeft: true, - hasMarkers: true, - thresholds: [40, 60], -} -DoubleThreshold.storyName = 'Double threshold' -DoubleThreshold.parameters = disableColorContrastRule - -export const CustomValueFormatter = Template.bind({}) -CustomValueFormatter.args = { - domain: [0, 40], - mode: 1, - values: [20], - tickCount: 4, - tracksLeft: true, - hasMarkers: true, - formatValue: ({ value }) => `£${value.toFixed(2)}`, -} -CustomValueFormatter.storyName = 'Custom value formatter' -CustomValueFormatter.parameters = disableColorContrastRule - -export const Stepped = Template.bind({}) -Stepped.args = { - domain: [0, 40], - step: 10, - mode: 1, - values: [20], - tickCount: 4, - tracksLeft: true, - hasMarkers: true, -} -Stepped.storyName = 'Stepped' -Stepped.parameters = disableColorContrastRule - -export const WithIcons = Template.bind({}) -WithIcons.args = { - domain: [0, 40], - step: 10, - mode: 1, - values: [20], - tickCount: 4, - tracksLeft: true, - hasMarkers: true, - IconLeft: IconBrightnessLow, - IconRight: IconBrightnessHigh, -} -WithIcons.storyName = 'With icons' -WithIcons.parameters = disableColorContrastRule - -export const WithLabels = Template.bind({}) -WithLabels.args = { - domain: [0, 40], - step: 2, - mode: 1, - values: [20], - tracksLeft: true, - hasLabels: true, - hasMarkers: true, - tickCount: 20, -} -WithLabels.storyName = 'With labels' -WithLabels.parameters = disableColorContrastRule - -export const ReversedScale = Template.bind({}) -ReversedScale.args = { - domain: [0, 40], - step: 2, - mode: 1, - values: [20], - tracksRight: true, - hasLabels: true, - hasMarkers: true, - tickCount: 20, - isReversed: true, -} -ReversedScale.storyName = 'Reversed scale' -ReversedScale.parameters = disableColorContrastRule - -export const Disabled = Template.bind({}) -Disabled.args = { - domain: [0, 40], - step: 10, - mode: 1, - values: [20], - tracksLeft: true, - hasMarkers: true, - isDisabled: true, -} -Disabled.storyName = 'Disabled' -Disabled.parameters = disableColorContrastRule diff --git a/packages/react-component-library/src/components/RangeSliderE/RangeSliderE.test.tsx b/packages/react-component-library/src/components/RangeSliderE/RangeSliderE.test.tsx deleted file mode 100644 index d69d3bc378..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/RangeSliderE.test.tsx +++ /dev/null @@ -1,381 +0,0 @@ -import React from 'react' -import '@testing-library/jest-dom/extend-expect' -import { render, RenderResult, fireEvent } from '@testing-library/react' -import 'jest-styled-components' -import userEvent from '@testing-library/user-event' -import { CustomMode } from 'react-compound-slider' - -import { - IconBrightnessLow, - IconBrightnessHigh, -} from '@defencedigital/icon-library' -import { RangeSliderE } from '.' - -describe('RangeSliderE', () => { - let wrapper: RenderResult - let mode: 1 | 2 | 3 | CustomMode - let onUpdateSpy: (values: readonly number[]) => void - let onSlideStartSpy: ( - values: ReadonlyArray, - data: { activeHandleID: string } - ) => void - let onSlideEndSpy: ( - values: ReadonlyArray, - data: { activeHandleID: string } - ) => void - let domain: readonly [number, number] // lower and upper bounds - let values: readonly [number] | readonly [number, number] // initial handle values - let step: number - let tickCount: number - - describe('single handle, unstepped, with callbacks', () => { - beforeEach(() => { - mode = 1 - onUpdateSpy = jest.fn() - onSlideStartSpy = jest.fn() - onSlideEndSpy = jest.fn() - domain = [0, 40] - values = [20] - step = 10 - tickCount = 4 - - wrapper = render( - - ) - }) - - it('should set the correct `tabindex`', () => { - expect(wrapper.getByTestId('rangeslider-handle')).toHaveAttribute( - 'tabindex', - '0' - ) - }) - - it('should render the ticks', () => { - expect(wrapper.getAllByTestId('rangeslider-tick')).toHaveLength(5) - }) - - it('should render a single handle', () => { - expect(wrapper.queryAllByTestId('rangeslider-handle')).toHaveLength(1) - }) - - it('should set the ARIA attributes on the handle', () => { - const handle = wrapper.getByTestId('rangeslider-handle') - - expect(handle).toHaveAttribute('role', 'slider') - expect(handle).toHaveAttribute('aria-label', 'Select range') - expect(handle).toHaveAttribute('aria-valuemin', '0') - expect(handle).toHaveAttribute('aria-valuemax', '40') - expect(handle).toHaveAttribute('aria-valuenow', '20') - }) - - it('should render correct number of ticks', () => { - expect(wrapper.queryAllByTestId('rangeslider-tick')).toHaveLength(5) - }) - - it('should not render any tracks', () => { - expect(wrapper.queryAllByTestId('rangeslider-track')).toHaveLength(0) - }) - - it('should not render any labels', () => { - expect(wrapper.queryAllByTestId('rangeslider-label')).toHaveLength(0) - }) - - it('should not render any markers', () => { - expect(wrapper.queryAllByTestId('rangeslider-marker')).toHaveLength(2) - }) - - describe('and the end user moves the handle to the right using keyboard', () => { - beforeEach(() => { - userEvent.click(wrapper.getByTestId('rangeslider-handle')) - - fireEvent.keyDown(wrapper.getByTestId('rangeslider-handle'), { - key: 'ArrowRight', - code: 39, - }) - }) - - it('should update the `aria-valuenow` attribute on the handle', () => { - expect(wrapper.getByTestId('rangeslider-handle')).toHaveAttribute( - 'aria-valuenow', - '30' - ) - }) - - it('invokes the onSlideStartSpy callback', () => { - expect(onSlideStartSpy).toHaveBeenCalledTimes(1) - }) - - it('invokes the onSlideEndSpy callback', () => { - expect(onSlideEndSpy).toHaveBeenCalledTimes(1) - }) - - it('invokes the onUpdateSpy callback', () => { - expect(onUpdateSpy).toHaveBeenCalled() - }) - }) - }) - - describe('single threshold', () => { - beforeEach(() => { - wrapper = render( - - ) - }) - - it('renders the correct track chunks', () => { - expect( - wrapper.queryByTestId('rangeslider-track-below-first-threshold') - ).toBeInTheDocument() - }) - }) - - describe('double threshold', () => { - beforeEach(() => { - wrapper = render( - - ) - }) - - it('renders the correct track chunks', () => { - expect( - wrapper.queryByTestId('rangeslider-track-below-first-threshold') - ).toBeInTheDocument() - expect( - wrapper.queryByTestId('rangeslider-track-between-thresholds') - ).toBeInTheDocument() - }) - }) - - describe('disabled', () => { - beforeEach(() => { - wrapper = render( - - ) - }) - - it('should apply the cursor `not-allowed` CSS property', () => { - expect(wrapper.queryByTestId('rangeslider')).toHaveStyleRule( - 'cursor', - 'not-allowed' - ) - }) - - describe('and the user attempts to move the slider', () => { - beforeEach(() => { - userEvent.click(wrapper.getByTestId('rangeslider-handle')) - - fireEvent.keyDown(wrapper.getByTestId('rangeslider-handle'), { - key: 'ArrowRight', - code: 39, - }) - }) - - it('does not move', () => { - expect(wrapper.getByTestId('rangeslider-handle')).toHaveAttribute( - 'aria-valuenow', - '20' - ) - }) - }) - }) - - describe('includes user defined left and right icons', () => { - beforeEach(() => { - wrapper = render( - - ) - }) - - it('should render the Icon component left of the slider', () => { - expect(wrapper.queryByTestId('rangeslider-icon-left')).not.toBeNull() - }) - - it('should set the `aria-hidden` attribute to `true` for the left icon', () => { - expect(wrapper.queryByTestId('rangeslider-icon-left')).toHaveAttribute( - 'aria-hidden', - 'true' - ) - }) - - it('should render the Icon component right of the slider', () => { - expect(wrapper.queryByTestId('rangeslider-icon-right')).not.toBeNull() - }) - - it('should set the `aria-hidden` attribute to `true` for the right icon', () => { - expect(wrapper.queryByTestId('rangeslider-icon-right')).toHaveAttribute( - 'aria-hidden', - 'true' - ) - }) - }) - - describe('multiple handles', () => { - beforeEach(() => { - values = [10, 20] - - wrapper = render( - - ) - }) - - it('should render two handles', () => { - expect(wrapper.queryAllByTestId('rangeslider-handle')).toHaveLength(2) - }) - }) - - describe('when the `displayUnit` prop is provided', () => { - beforeEach(() => { - wrapper = render( - - ) - }) - - it('should append the display unit to the handle label', () => { - expect(wrapper.getByTestId('rangeslider-value')).toHaveTextContent('20pt') - }) - }) - - describe('when the `formatValue` prop is provided', () => { - beforeEach(() => { - wrapper = render( - `£${value}`} - /> - ) - }) - - it('formats the handle label using the provided formatter', () => { - expect(wrapper.getByTestId('rangeslider-value')).toHaveTextContent('£20') - }) - }) - - describe('when markers and labels are enabled', () => { - beforeEach(() => { - wrapper = render( - - ) - }) - - it('should render the correct number of labels', () => { - expect(wrapper.queryAllByTestId('rangeslider-label')).toHaveLength(5) - }) - - it('should render the correct number of markers', () => { - expect(wrapper.queryAllByTestId('rangeslider-marker')).toHaveLength(5) - }) - }) - - describe('when arbitrary props are provided', () => { - beforeEach(() => { - wrapper = render( - - ) - }) - - it('should spread arbitrary props', () => { - expect(wrapper.getByTestId('rangeslider')).toHaveAttribute( - 'data-arbitrary', - 'arbitrary' - ) - }) - }) - - describe('without the `onUpdate` callback', () => { - beforeEach(() => { - wrapper = render( - - ) - }) - - describe('and the end user moves the handle to the right using keyboard', () => { - it('does not throw an error', () => { - expect(() => { - fireEvent( - wrapper.getByTestId('rangeslider-handle'), - new MouseEvent('click', { - bubbles: true, - cancelable: true, - }) - ) - - fireEvent.keyDown(wrapper.getByTestId('rangeslider-handle'), { - key: 'ArrowRight', - code: 39, - }) - }).not.toThrow(TypeError) - }) - }) - }) -}) diff --git a/packages/react-component-library/src/components/RangeSliderE/SliderE.tsx b/packages/react-component-library/src/components/RangeSliderE/SliderE.tsx deleted file mode 100644 index 1dd2fcca66..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/SliderE.tsx +++ /dev/null @@ -1,288 +0,0 @@ -import React, { useCallback, useState, createRef } from 'react' -import intersection from 'lodash/intersection' -import { - SliderProps, - CustomMode, - Rail, - Handles, - Tracks, - Ticks, -} from 'react-compound-slider' - -import { - HandleE, - RangeSliderEValueFormatter, - TrackE, - ThresholdTrackE, - ThresholdRailE, - TickE, -} from '.' -import { StyledSlider } from './partials/StyledSlider' -import { StyledIconLeft } from './partials/StyledIconLeft' -import { StyledIconRight } from './partials/StyledIconRight' -import { StyledRangeSlider } from './partials/StyledRangeSlider' -import { StyledRail } from './partials/StyledRail' -import { StyledRailInner } from './partials/StyledRailInner' -import { StyledTicks } from './partials/StyledTicks' - -type SliderOmitType = - | 'children' - | 'disabled' - | 'reversed' - | 'vertical' - | 'domain' - | 'values' - | 'mode' - | 'step' - -type SliderModeType = 1 | 2 | 3 | CustomMode - -export interface RangeSliderEProps extends Omit { - /** - * Two element array of numbers providing the min and max values for the slider [min, max] e.g. [0, 100]. - * It does not matter if the slider is reversed on the screen, domain is always [min, max] with min < max. - */ - domain: readonly [number, number] - /** - * An array of numbers. You can supply one for a value slider, two for a range slider. - * The values should correspond to valid step values in the domain. - * The numbers will be forced into the domain if they are two small or large. - */ - values: readonly [number] | readonly [number, number] - /** - * The step value for the slider. - */ - step?: number - /** - * The interaction mode. Value of 1 will allow handles to cross each other. - * Value of 2 will keep the sliders from crossing and separated by a step. - * Value of 3 will make the handles pushable and keep them a step apart. - * You can also supply a function that will be passed the current values and the incoming update. Your function should return what the state should be set as. - */ - mode?: SliderModeType - /** - * Toggles whether or not to display labels below the slider. - */ - hasLabels?: boolean - /** - * Toggles whether or not to display value markers along the slider. - */ - hasMarkers?: boolean - /** - * Toggles whether to display colored tracks to the left of the handle. - */ - tracksLeft?: boolean - /** - * Toggles whether to display colored tracks to the right of the handle. - */ - tracksRight?: boolean - /** - * The number of tickets to display along the slider track. - */ - tickCount?: number - /** - * Optional JSX icon element to display to the left of the component. - */ - IconLeft?: React.ElementType - /** - * Optional JSX icon element to display to the right of the component. - */ - IconRight?: React.ElementType - /** - * Toggles whether the component is disabled or not (preventing user interaction). - */ - isDisabled?: boolean - /** - * Toggles whether to reverse the scale of the slider. - */ - isReversed?: boolean - /** - * Optional numeric array of thresholds to display on the slider bar (up to 2). - */ - thresholds?: number[] - /** - * Toggles whether to display unit values alongside the draggable handles. - */ - displayUnit?: string - /** - * Optional custom value formatter function. - */ - formatValue?: RangeSliderEValueFormatter -} - -export const RangeSliderE: React.FC = ({ - domain, - step, - hasLabels, - hasMarkers, - tracksLeft = false, - tracksRight = false, - tickCount = 10, - IconLeft, - IconRight, - isReversed, - isDisabled, - values, - onChange, - onUpdate, - thresholds, - displayUnit = '', - formatValue, - mode, - onSlideStart, - onSlideEnd, - ...rest -}) => { - const [sliderValues, setSliderValues] = - useState>(values) - const handleRefs = values.map(() => createRef()) - - const focusHandle = useCallback( - (newValues: ReadonlyArray): void => { - const staticValues = intersection(sliderValues, newValues) - - // Single handle - if (sliderValues.length === 1) { - handleRefs[0].current?.focus() - } - - // Multiple handles - if (sliderValues.length === 2 && staticValues.length === 1) { - const refId = sliderValues.indexOf(staticValues[0]) === 1 ? 0 : 1 - handleRefs[refId].current?.focus() - } - }, - [sliderValues, handleRefs] - ) - - const onUpdateHandler = useCallback( - (newValues: ReadonlyArray): void => { - focusHandle(newValues) - setSliderValues(newValues) - - if (onUpdate) { - onUpdate(newValues) - } - }, - [onUpdate, setSliderValues, focusHandle] - ) - - const formatValueDefault: RangeSliderEValueFormatter = useCallback( - ({ value }) => `${Math.floor(value)}${displayUnit}`, - [displayUnit] - ) - - return ( - - {IconLeft && ( - - - - )} - - - {({ getRailProps }) => ( - - - {thresholds && } - - - )} - - - {({ handles, getHandleProps }) => ( -
- {handles.map((handle, index) => ( - - ))} -
- )} -
- - {({ tracks, getTrackProps }) => ( -
- {tracks.map(({ id, source, target }) => { - if (thresholds) { - return ( - - ) - } - - return ( - - ) - })} -
- )} -
- {tickCount && ( - - {({ ticks }) => ( - - {ticks.map((tick) => ( - - ))} - - )} - - )} -
- {IconRight && ( - - - - )} -
- ) -} - -RangeSliderE.displayName = 'RangeSliderE' diff --git a/packages/react-component-library/src/components/RangeSliderE/ThresholdTrackE.tsx b/packages/react-component-library/src/components/RangeSliderE/ThresholdTrackE.tsx deleted file mode 100644 index 69c5b112ce..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/ThresholdTrackE.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import React from 'react' -import { TrackItem, GetTrackProps } from 'react-compound-slider' - -import { ThresholdColor } from './useThresholdColor' -import { - RANGE_SLIDER_TRACK_BELOW_FIRST_THRESHOLD, - RANGE_SLIDER_TRACK_BETWEEN_THRESHOLDS, - RANGE_SLIDER_TRACK_ABOVE_THRESHOLDS, -} from './constants' -import { StyledTrackChunk } from './partials/StyledTrackChunk' - -export interface ThresholdTrackEProps extends TrackItem { - getTrackProps: GetTrackProps - thresholds: number[] -} - -export interface TrackChunkEProps { - getTrackProps: GetTrackProps - $left: number - $width: number - $maxWidth: number - testId: string - $thresholdColor?: ThresholdColor -} - -const TrackChunkE: React.FC = ({ - getTrackProps, - $left, - $width, - $maxWidth, - testId, - $thresholdColor, -}) => { - return ( - - ) -} - -export const ThresholdTrackE: React.FC = ({ - target, - getTrackProps, - thresholds, -}) => { - const singleThreshold = thresholds?.length === 1 - const doubleThreshold = thresholds?.length === 2 - - return ( - <> - {(singleThreshold || doubleThreshold) && ( - - )} - - {doubleThreshold && ( - - )} - - - - ) -} - -ThresholdTrackE.displayName = 'ThresholdTrackE' diff --git a/packages/react-component-library/src/components/RangeSliderE/TickE.tsx b/packages/react-component-library/src/components/RangeSliderE/TickE.tsx deleted file mode 100644 index 29f256867b..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/TickE.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import React, { useMemo } from 'react' -import { SliderItem } from 'react-compound-slider' - -import { useThresholdColor } from './useThresholdColor' -import { StyledLabel } from './partials/StyledLabel' -import { StyledMarker } from './partials/StyledMarker' - -export interface TickEProps { - tick: SliderItem - count: number - hasLabels?: boolean - hasMarkers?: boolean - values: ReadonlyArray - domain: ReadonlyArray - isReversed?: boolean - thresholds?: number[] - tracksLeft?: boolean - tracksRight?: boolean -} - -function isActive( - values: ReadonlyArray, - tickValue: number, - tracksLeft: boolean, - tracksRight: boolean -): boolean { - if (!tracksLeft && !tracksRight) { - return tickValue >= values[0] && tickValue <= values[1] - } - - if (tracksLeft && tracksRight) { - return true - } - - return values.some((item) => tickValue <= item) -} - -export const TickE: React.FC = ({ - tick, - count, - hasLabels, - hasMarkers, - values, - domain, - isReversed, - thresholds, - tracksLeft = false, - tracksRight = false, -}) => { - const percent: number = useMemo( - () => (isReversed ? 100 - tick.percent : tick.percent), - [tick.percent, isReversed] - ) // invert if reversed - - const tickValue: number = useMemo( - () => (domain[1] / 100) * percent, - [domain, percent] - ) - - const thresholdColor = useThresholdColor(percent, thresholds) - - const showMarker = percent === 0 || percent === 100 || hasMarkers - - return ( -
- {showMarker && ( - - )} - {hasLabels && ( - - {tick.value} - - )} -
- ) -} - -TickE.displayName = 'TickE' diff --git a/packages/react-component-library/src/components/RangeSliderE/TrackE.tsx b/packages/react-component-library/src/components/RangeSliderE/TrackE.tsx deleted file mode 100644 index 3e705defa4..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/TrackE.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react' -import { TrackItem, GetTrackProps } from 'react-compound-slider' - -import { StyledTrack } from './partials/StyledTrack' - -interface TrackEProps extends TrackItem { - getTrackProps: GetTrackProps -} - -export const TrackE: React.FC = ({ - source, - target, - getTrackProps, -}) => { - return ( - - ) -} - -TrackE.displayName = 'TrackE' diff --git a/packages/react-component-library/src/components/RangeSliderE/constants.ts b/packages/react-component-library/src/components/RangeSliderE/constants.ts deleted file mode 100644 index 7298fab41f..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/constants.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { selectors } from '@defencedigital/design-tokens' - -const { color } = selectors - -export const RANGE_SLIDER_BG_COLOR = color('neutral', '200') -export const RANGE_SLIDER_HANDLE_COLOR = color('action', '500') -export const RANGE_SLIDER_TRACK_COLOR = color('action', '200') - -export const RANGE_SLIDER_TRACK_BELOW_FIRST_THRESHOLD = color('action', '500') -export const RANGE_SLIDER_TRACK_BETWEEN_THRESHOLDS = color('warning', '500') -export const RANGE_SLIDER_TRACK_ABOVE_THRESHOLDS = color('danger', '500') diff --git a/packages/react-component-library/src/components/RangeSliderE/index.ts b/packages/react-component-library/src/components/RangeSliderE/index.ts deleted file mode 100644 index 397962677a..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * from './SliderE' -export * from './HandleE' -export * from './TrackE' -export * from './ThresholdTrackE' -export * from './ThresholdRailE' -export * from './TickE' -export * from './types' diff --git a/packages/react-component-library/src/components/RangeSliderE/partials/StyledHandle.tsx b/packages/react-component-library/src/components/RangeSliderE/partials/StyledHandle.tsx deleted file mode 100644 index 7a4428ccd5..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/partials/StyledHandle.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import styled from 'styled-components' -import { selectors } from '@defencedigital/design-tokens' -import { transparentize } from 'polished' - -import { RANGE_SLIDER_HANDLE_COLOR } from '../constants' - -const { color } = selectors - -export const StyledHandle = styled.div` - position: absolute; - transform: translate(-10px, -50%); - width: 18px; - height: 18px; - margin-left: 1px; - border: none; - border-radius: 9999px; - background-color: ${RANGE_SLIDER_HANDLE_COLOR}; - text-align: center; - transition: box-shadow 0.15s ease-in-out; - cursor: pointer; - box-shadow: 1px 1px 2px 0px rgba(000, 000, 000, 0.25); - - &:focus { - box-shadow: 1px 1px 2px 0px rgba(000, 000, 000, 0.25), - 0px 0px 0px 5px ${transparentize(0.5, color('action', '200'))}; - outline: none; - } -` diff --git a/packages/react-component-library/src/components/RangeSliderE/partials/StyledIconLeft.tsx b/packages/react-component-library/src/components/RangeSliderE/partials/StyledIconLeft.tsx deleted file mode 100644 index 7d2cd0d399..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/partials/StyledIconLeft.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import styled from 'styled-components' -import { selectors } from '@defencedigital/design-tokens' - -const { color, spacing } = selectors - -export const StyledIconLeft = styled.div` - display: inline-flex; - justify-content: center; - align-items: center; - - svg { - color: ${color('neutral', '400')}; - overflow: visible; - margin-right: ${spacing('6')}; - } -` diff --git a/packages/react-component-library/src/components/RangeSliderE/partials/StyledIconRight.tsx b/packages/react-component-library/src/components/RangeSliderE/partials/StyledIconRight.tsx deleted file mode 100644 index 04a4815963..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/partials/StyledIconRight.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import styled from 'styled-components' -import { selectors } from '@defencedigital/design-tokens' - -const { color, spacing } = selectors - -export const StyledIconRight = styled.div` - display: inline-flex; - justify-content: center; - align-items: center; - - svg { - color: ${color('neutral', '400')}; - overflow: visible; - margin-left: ${spacing('6')}; - } -` diff --git a/packages/react-component-library/src/components/RangeSliderE/partials/StyledLabel.tsx b/packages/react-component-library/src/components/RangeSliderE/partials/StyledLabel.tsx deleted file mode 100644 index 65c98b39e3..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/partials/StyledLabel.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import styled from 'styled-components' -import { selectors } from '@defencedigital/design-tokens' - -interface StyledLabelProps { - $marginLeft: string - $width: string - $left: string -} - -const { fontSize, color } = selectors - -export const StyledLabel = styled.span` - position: absolute; - margin-top: 14px; - font-size: ${fontSize('s')}; - color: ${color('neutral', '400')}; - text-align: center; - margin-left: ${({ $marginLeft }) => $marginLeft}; - width: ${({ $width }) => $width}; - left: ${({ $left }) => $left}; -` diff --git a/packages/react-component-library/src/components/RangeSliderE/partials/StyledMarker.tsx b/packages/react-component-library/src/components/RangeSliderE/partials/StyledMarker.tsx deleted file mode 100644 index df19601be1..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/partials/StyledMarker.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import styled, { css } from 'styled-components' -import { setLightness } from 'polished' - -import { ThresholdColor } from '../useThresholdColor' -import { - RANGE_SLIDER_TRACK_BELOW_FIRST_THRESHOLD, - RANGE_SLIDER_BG_COLOR, -} from '../constants' - -interface StyledMarkerProps { - $isActive?: boolean - $thresholdColor?: ThresholdColor - $left: string -} - -export const StyledMarker = styled.div` - position: absolute; - width: 6px; - height: 6px; - border-radius: 999px; - transform: translate(-50%, -50%); - pointer-events: none; - background-color: ${RANGE_SLIDER_BG_COLOR}; - left: ${({ $left }) => $left}; - - ${({ $isActive }) => - $isActive && - css` - background-color: ${RANGE_SLIDER_TRACK_BELOW_FIRST_THRESHOLD}; - `}; - - ${({ $thresholdColor }) => - $thresholdColor && - css` - background-color: ${setLightness(0.85, $thresholdColor)}; - `} - - ${({ $isActive, $thresholdColor }) => - $isActive && - $thresholdColor && - css` - background-color: ${$thresholdColor}; - `}; -` diff --git a/packages/react-component-library/src/components/RangeSliderE/partials/StyledRail.tsx b/packages/react-component-library/src/components/RangeSliderE/partials/StyledRail.tsx deleted file mode 100644 index 6ab7581018..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/partials/StyledRail.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import styled from 'styled-components' - -export const StyledRail = styled.div` - position: absolute; - top: calc(50% + 20px); - left: 0; - display: inline-block; - width: 100%; - height: 40px; - transform: translateY(-100%); - cursor: pointer; -` diff --git a/packages/react-component-library/src/components/RangeSliderE/partials/StyledRailInner.tsx b/packages/react-component-library/src/components/RangeSliderE/partials/StyledRailInner.tsx deleted file mode 100644 index 45ca599f4e..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/partials/StyledRailInner.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import styled from 'styled-components' - -import { RANGE_SLIDER_BG_COLOR } from '../constants' - -export const StyledRailInner = styled.div` - position: absolute; - top: 50%; - width: 100%; - height: 2px; - transform: translateY(-50%); - background-color: ${RANGE_SLIDER_BG_COLOR}; - pointer-events: none; -` diff --git a/packages/react-component-library/src/components/RangeSliderE/partials/StyledRangeSlider.tsx b/packages/react-component-library/src/components/RangeSliderE/partials/StyledRangeSlider.tsx deleted file mode 100644 index 94f63f0c08..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/partials/StyledRangeSlider.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import styled, { css } from 'styled-components' - -interface StyledRangeSliderProps { - $isReversed?: boolean - $isDisabled?: boolean -} - -export const StyledRangeSlider = styled.div` - display: inline-flex; - align-items: center; - width: 100%; - - ${({ $isDisabled }) => - $isDisabled && - css` - opacity: 0.5; - cursor: not-allowed; - - &&& * { - cursor: not-allowed; - } - `} -` diff --git a/packages/react-component-library/src/components/RangeSliderE/partials/StyledSlider.tsx b/packages/react-component-library/src/components/RangeSliderE/partials/StyledSlider.tsx deleted file mode 100644 index 8167e3cf45..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/partials/StyledSlider.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import styled from 'styled-components' -import { Slider, SliderProps } from 'react-compound-slider' - -export const StyledSlider = styled>(Slider)` - position: relative; - width: 100%; - height: 40px; - padding-top: 20px; -` diff --git a/packages/react-component-library/src/components/RangeSliderE/partials/StyledTicks.tsx b/packages/react-component-library/src/components/RangeSliderE/partials/StyledTicks.tsx deleted file mode 100644 index 3c80568751..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/partials/StyledTicks.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import styled from 'styled-components' - -export const StyledTicks = styled.div` - div:first-of-type, - div:last-of-type { - div { - height: 20px; - width: 2px; - } - } -` diff --git a/packages/react-component-library/src/components/RangeSliderE/partials/StyledTrack.tsx b/packages/react-component-library/src/components/RangeSliderE/partials/StyledTrack.tsx deleted file mode 100644 index 5f73d8711d..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/partials/StyledTrack.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import styled from 'styled-components' - -import { RANGE_SLIDER_TRACK_COLOR } from '../constants' - -interface StyledTrackProps { - $left: string - $width: string -} - -export const StyledTrack = styled.div` - position: absolute; - transform: translate(0%, -50%); - height: 6px; - background-color: ${RANGE_SLIDER_TRACK_COLOR}; - cursor: pointer; - width: ${({ $width }) => $width}; - left: ${({ $left }) => $left}; -` diff --git a/packages/react-component-library/src/components/RangeSliderE/partials/StyledValue.tsx b/packages/react-component-library/src/components/RangeSliderE/partials/StyledValue.tsx deleted file mode 100644 index f19136b129..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/partials/StyledValue.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import styled from 'styled-components' -import { selectors } from '@defencedigital/design-tokens' - -const { fontSize, spacing, color } = selectors - -export const StyledValue = styled.div` - position: absolute; - display: inline-block; - transform: translate(-50%, -160%); - font-size: ${fontSize('m')}; - color: ${color('neutral', '500')}; - padding: ${spacing('3')} ${spacing('4')}; - border-radius: 8px; - border: 1px solid ${color('neutral', '200')}; - font-weight: 600; - background-color: ${color('neutral', 'white')}; - cursor: pointer; -` diff --git a/packages/react-component-library/src/components/RangeSliderE/types.ts b/packages/react-component-library/src/components/RangeSliderE/types.ts deleted file mode 100644 index 25554fce75..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -export type RangeSliderEPositionBag = { - value: number - percentage: number -} - -export type RangeSliderEValueFormatter = ( - positionBag: RangeSliderEPositionBag -) => string diff --git a/packages/react-component-library/src/components/RangeSliderE/useThresholdColor.ts b/packages/react-component-library/src/components/RangeSliderE/useThresholdColor.ts deleted file mode 100644 index 6378b1beb1..0000000000 --- a/packages/react-component-library/src/components/RangeSliderE/useThresholdColor.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { - RANGE_SLIDER_TRACK_BELOW_FIRST_THRESHOLD, - RANGE_SLIDER_TRACK_BETWEEN_THRESHOLDS, - RANGE_SLIDER_TRACK_ABOVE_THRESHOLDS, -} from './constants' - -export type ThresholdColor = - | typeof RANGE_SLIDER_TRACK_BELOW_FIRST_THRESHOLD - | typeof RANGE_SLIDER_TRACK_BETWEEN_THRESHOLDS - | typeof RANGE_SLIDER_TRACK_ABOVE_THRESHOLDS - -export function useThresholdColor( - percent: number, - thresholds: number[] | undefined -): ThresholdColor | undefined { - const singleThreshold = thresholds?.length === 1 - const doubleThreshold = thresholds?.length === 2 - - if ((singleThreshold || doubleThreshold) && percent <= thresholds[0]) { - return RANGE_SLIDER_TRACK_BELOW_FIRST_THRESHOLD - } - - if (doubleThreshold && percent < thresholds[1] && percent >= thresholds[0]) { - return RANGE_SLIDER_TRACK_BETWEEN_THRESHOLDS - } - - if ( - (singleThreshold || doubleThreshold) && - percent >= thresholds[thresholds.length - 1] - ) { - return RANGE_SLIDER_TRACK_ABOVE_THRESHOLDS - } - - return undefined -} diff --git a/packages/react-component-library/src/forms/formik/formik.stories.tsx b/packages/react-component-library/src/forms/formik/formik.stories.tsx index 66df83312b..aa424caa34 100644 --- a/packages/react-component-library/src/forms/formik/formik.stories.tsx +++ b/packages/react-component-library/src/forms/formik/formik.stories.tsx @@ -13,7 +13,7 @@ import { NumberInput } from '../../components/NumberInput' import { DatePicker, DatePickerOnChangeData } from '../../components/DatePicker' import { SelectE, SelectEOption } from '../../components/SelectE' import { SwitchE, SwitchEOption } from '../../components/SwitchE' -import { RangeSliderE } from '../../components/RangeSliderE' +import { RangeSlider } from '../../components/RangeSlider' import { sleep } from '../../helpers' import { Field } from '../../components/Field' import { Fieldset } from '../../components/Fieldset' @@ -306,7 +306,7 @@ export const Example: React.FC = () => { hintText="Example hint text." errors={[{ error: meta.touched && meta.error }]} > - = () => { - ) => { handleChange({ currentTarget: { diff --git a/packages/react-component-library/src/forms/react-hook-form/react-hook-form.stories.tsx b/packages/react-component-library/src/forms/react-hook-form/react-hook-form.stories.tsx index 2dfa555955..f0402cc246 100644 --- a/packages/react-component-library/src/forms/react-hook-form/react-hook-form.stories.tsx +++ b/packages/react-component-library/src/forms/react-hook-form/react-hook-form.stories.tsx @@ -14,7 +14,7 @@ import { DatePicker } from '../../components/DatePicker' import { NumberInput } from '../../components/NumberInput' import { SelectE, SelectEOption } from '../../components/SelectE' import { SwitchE, SwitchEOption } from '../../components/SwitchE' -import { RangeSliderE } from '../../components/RangeSliderE' +import { RangeSlider } from '../../components/RangeSlider' import { Button } from '../../components/Button' import { Fieldset } from '../../components/Fieldset' import { sleep } from '../../helpers' @@ -37,7 +37,7 @@ export interface FormValues { const MINIMUM_DATE = parseISO('2022-01-01') -const StyledRangeSliderE = styled(RangeSliderE)` +const StyledRangeSlider = styled(RangeSlider)` margin-top: 3rem; ` @@ -254,7 +254,7 @@ export const Example: React.FC = () => { name="exampleRangeSlider" render={({ onChange, value }) => { return ( -