From 0b78b7689acf5776cc30b1f8bf561b55e1b9094c Mon Sep 17 00:00:00 2001 From: Dylan Kilgore Date: Wed, 1 Feb 2023 16:19:38 -0800 Subject: [PATCH 1/4] feat: slider: enable basic data comparison slider implementations --- src/components/Slider/Marks/Mark.tsx | 3 +- src/components/Slider/Slider.stories.tsx | 768 ++++++++++++++++++++++- src/components/Slider/Slider.tsx | 107 +++- src/components/Slider/Slider.types.ts | 79 ++- src/components/Slider/Steps/Dot.tsx | 18 +- src/components/Slider/Steps/index.tsx | 6 +- src/components/Slider/Util.ts | 2 +- src/components/Slider/slider.module.scss | 213 ++++++- src/octuple.ts | 9 +- src/styles/themes/_default-theme.scss | 29 + 10 files changed, 1167 insertions(+), 67 deletions(-) diff --git a/src/components/Slider/Marks/Mark.tsx b/src/components/Slider/Marks/Mark.tsx index d5db0abd5..c9e98b041 100644 --- a/src/components/Slider/Marks/Mark.tsx +++ b/src/components/Slider/Marks/Mark.tsx @@ -7,7 +7,7 @@ import { mergeClasses } from '../../../shared/utilities'; import styles from '../slider.module.scss'; export default function Mark(props: MarkProps) { - const { style, children, value, onClick } = props; + const { children, classNames, onClick, style, value } = props; const { direction, included, includedEnd, includedStart, min, max } = React.useContext(SliderContext); @@ -21,6 +21,7 @@ export default function Mark(props: MarkProps) { [styles.sliderMarkTextActive]: included && includedStart <= value && value <= includedEnd, }, + classNames, ])} style={{ ...positionStyle, diff --git a/src/components/Slider/Slider.stories.tsx b/src/components/Slider/Slider.stories.tsx index 3e7e72458..ab177653a 100644 --- a/src/components/Slider/Slider.stories.tsx +++ b/src/components/Slider/Slider.stories.tsx @@ -1,9 +1,12 @@ -import React, { useState } from 'react'; +import React, { useRef, useState } from 'react'; import { ComponentMeta, ComponentStory } from '@storybook/react'; -import { Slider, SliderSize } from './'; +import { Slider, SliderSize, SliderTrackColor } from './'; import { Stack } from '../Stack'; import { Col, Row } from '../Grid'; import { PrimaryButton } from '../Button'; +import { IconName, IconSize } from '../Icon'; +import { useArgs } from '@storybook/client-api'; +import { ConfigProvider } from '../ConfigProvider'; export default { title: 'Slider', @@ -308,6 +311,687 @@ const Toggle_Thumb_Story: ComponentStory = (args) => { ); }; +// Inactive employee asessment marker +const lowerAssessmentInactiveMarker = (): JSX.Element => ( + + + + + + + +); + +// Active employee asessment marker +const lowerAssessmentActiveMarker = (): JSX.Element => ( + + + + + + + +); + +// Inactive manager asessment marker +const upperAssessmentInactiveMarker = (): JSX.Element => ( + + + + + + + +); + +// Active manager asessment marker +const upperAssessmentActiveMarker = (): JSX.Element => ( + + + + + + + +); + +// Active employee assessment marker when the manager assessment is of the same value +// Active color of the marker depends upon who is editing the marker value +// In this scenario it's the employee +const combinedUpperAssessmentActiveMarker = (): JSX.Element => ( + + + + + + + + + + + + +); + +// Inactive combined upper assessment marker (both are gray) +const combinedUpperAssessmentInactiveMarker = (): JSX.Element => ( + + + + + + + + + + + + +); + +// Active benchmark marker +const roleBenchmarkActiveMarker = (): JSX.Element => ( + + + +); + +// Inactive benchmark marker +const roleBenchmarkInactiveMarker = (): JSX.Element => ( + + + +); + +// Active employee assessment marker when the benchmark is of the same value +// Active color of the marker depends upon who is editing the marker value +// In this scenario it's the employee. +const combinedBenchmarkAssessmentActiveMarker = (): JSX.Element => ( + + + + + + + + +); + +// Inactive combined employee assessment and benchmark marker (both are gray) +const combinedBenchmarkAssessmentInactiveMarker = (): JSX.Element => ( + + + + + + + + +); + +// Inactive combined markers (all three are gray) +const lowerAssessmentAllCombinedInactiveMarker = (): JSX.Element => ( + + + + + + + + + + + + + +); + +// Active employee assessment marker when the manager assessment and benchmark are of the same value +// Active color of the marker depends upon who is editing the marker value +// In this scenario it's the employee +const lowerAssessmentAllCombinedActiveMarker = (): JSX.Element => ( + + + + + + + + + + + + + +); + +const iconSet: Object = { + IcoMoonType: 'selection', + icons: [ + { + icon: { + paths: [ + 'M567.884 732.813c111.188-57.414 187.206-173.426 187.206-307.189 0-190.819-154.685-345.504-345.504-345.504s-345.504 154.686-345.504 345.504c0 133.762 76.015 249.776 187.204 307.189l158.301 211.068 158.299-211.068z', + 'M571.383 737.685l-20.251-39.224-8.989 4.643-6.075 8.095 35.315 26.485zM247.79 737.685l35.315-26.485-6.071-8.095-8.989-4.643-20.252 39.224zM409.585 953.41l-35.315 26.485 35.315 47.085 35.315-47.085-35.315-26.485zM718.575 423.719c0 119.56-67.896 223.342-167.447 274.744l40.506 78.443c127.74-65.958 215.224-199.319 215.224-353.187h-88.281zM409.585 114.73c170.649 0 308.99 138.339 308.99 308.99h88.281c0-219.408-177.86-397.27-397.27-397.27v88.281zM100.6 423.719c0-170.649 138.339-308.99 308.99-308.99v-88.281c-219.408 0-397.27 177.862-397.27 397.27h88.281zM268.042 698.459c-99.546-51.402-167.447-155.184-167.447-274.744h-88.281c0 153.868 87.485 287.228 215.224 353.187l40.506-78.443zM212.475 764.17l161.795 215.725 70.625-52.97-161.795-215.725-70.625 52.97zM444.9 979.895l161.793-215.725-70.625-52.97-161.793 215.725 70.625 52.97z', + ], + attrs: [{ fill: 'rgb(142, 208, 250)' }, { fill: 'rgb(89, 98, 183)' }], + isMulticolor: true, + isMulticolor2: true, + grid: 0, + tags: ['employee'], + colorPermutations: { + '201091661802062251': [{ f: 1 }, { f: 0 }], + }, + }, + attrs: [{ fill: 'rgb(142, 208, 250)' }, { fill: 'rgb(89, 98, 183)' }], + properties: { + order: 3, + id: 0, + name: 'employee', + prevSize: 32, + code: 59648, + codes: [59648, 59649], + }, + setIdx: 0, + setId: 2, + iconIdx: 0, + }, + ], + height: 1024, + metadata: { name: 'icomoon' }, + preferences: { + showGlyphs: true, + showQuickUse: true, + showQuickUse2: true, + showSVGs: true, + fontPref: { + prefix: 'icon-', + metadata: { fontFamily: 'icomoon' }, + metrics: { emSize: 1024, baseline: 6.25, whitespace: 50 }, + embed: false, + autoHost: true, + }, + imagePref: { + prefix: 'icon-', + png: true, + useClassSelector: true, + color: 0, + bgColor: 16777215, + classSelector: '.icon', + }, + historySize: 50, + showCodes: true, + gridSize: 24, + quickUsageToken: { + UntitledProject: + 'NWRmNjcxZTJiOGY2NjdmMjViNzdkOTliNWFiOWJhOGUjMSMxNjUzMDI0ODA4IyMjMTFiZDJhZjI4MDkz', + }, + }, +}; + +const With_Benchmark_Story: ComponentStory = (args) => { + const [transientSlidingValue, setTransientSlidingValue] = useState< + number | number[] + >(args.value); + + const handleChange = (val: number): void => { + setTransientSlidingValue(val); + }; + + return ( + + + +
{transientSlidingValue}
+
+
+ ); +}; + +const Data_Inactive_Story: ComponentStory = (args) => { + const [transientSlidingBValues, setTransientSlidingBValues] = useState< + number[] + >([1, 3]); + + const handleChangeB = (vals: number[]): void => { + setTransientSlidingBValues(vals); + }; + + return ( + + + +
{transientSlidingBValues[0]}
+
{transientSlidingBValues[1]}
+
+
+ ); +}; + +const Data_Active_Story: ComponentStory = (args) => { + const [_, updateArgs] = useArgs(); + const sliderRef: React.MutableRefObject = + useRef(null); + const [transientSlidingValues, setTransientSlidingValues] = useState< + number[] + >([1, 3]); + const [targetSlidingValue, setTargetSlidingValue] = useState(1); + + const handleChangeRange = (vals: number[]): void => { + setTransientSlidingValues(vals); + }; + + const handleChangeTarget = (val: number): void => { + setTargetSlidingValue(val); + }; + + const updateMarks = ( + value?: number, + benchmarkValue?: number, + persistedUpperValue?: number + ): Record => { + let marks: Record = { + 2: roleBenchmarkInactiveMarker(), + 3: upperAssessmentInactiveMarker(), + }; + + if ( + value >= 0 && + value !== benchmarkValue && + value !== persistedUpperValue + ) { + marks[value] = lowerAssessmentActiveMarker(); + } else if (value === benchmarkValue) { + marks[2] = combinedBenchmarkAssessmentActiveMarker(); + } else if (value === persistedUpperValue) { + marks[3] = combinedUpperAssessmentActiveMarker(); + } else { + marks[1] = lowerAssessmentActiveMarker(); + } + + return marks; + }; + + const updateValues = (): void => { + const benchmarkValue: number = 2; + const persistedUpperValue: number = 3; + if ( + targetSlidingValue < persistedUpperValue && + targetSlidingValue !== benchmarkValue + ) { + setTransientSlidingValues([targetSlidingValue, persistedUpperValue]); + updateArgs({ + ...args, + marks: updateMarks(targetSlidingValue), + trackColor: SliderTrackColor.Red, + value: [targetSlidingValue, persistedUpperValue], + }); + } else if (targetSlidingValue === benchmarkValue) { + setTransientSlidingValues([targetSlidingValue, persistedUpperValue]); + updateArgs({ + ...args, + marks: updateMarks(targetSlidingValue, benchmarkValue), + trackColor: SliderTrackColor.Red, + value: [targetSlidingValue, persistedUpperValue], + }); + } else if (targetSlidingValue === persistedUpperValue) { + setTransientSlidingValues([targetSlidingValue, persistedUpperValue]); + updateArgs({ + ...args, + marks: updateMarks(targetSlidingValue, null, persistedUpperValue), + trackColor: SliderTrackColor.Green, + value: [targetSlidingValue, persistedUpperValue], + }); + } else { + setTransientSlidingValues([ + transientSlidingValues[0], + targetSlidingValue, + ]); + updateArgs({ + ...args, + marks: updateMarks(targetSlidingValue), + trackColor: SliderTrackColor.Green, + value: [persistedUpperValue, targetSlidingValue], + }); + } + }; + + return ( + + +
+ + +
+ +
{transientSlidingValues[0]}
+
{transientSlidingValues[1]}
+
+ + + +
+
+ ); +}; + export const Standard_Slider = Slider_Story.bind({}); export const Range_Slider = Range_Slider_Story.bind({}); export const Inline_Extemity_Labels = Inline_Extemity_Labels_Story.bind({}); @@ -317,6 +1001,9 @@ export const Custom_Markers_With_Step = Custom_Markers_With_Step_Story.bind({}); export const Custom_Markers_Null_Step = Custom_Markers_Null_Step_Story.bind({}); export const Dots = Dots_Story.bind({}); export const Toggle_Thumb = Toggle_Thumb_Story.bind({}); +export const With_Benchmark = With_Benchmark_Story.bind({}); +export const Data_Inactive = Data_Inactive_Story.bind({}); +export const Data_Active = Data_Active_Story.bind({}); const sliderArgs: Object = { allowDisabledFocus: false, @@ -329,6 +1016,8 @@ const sliderArgs: Object = { }, disabled: false, dots: false, + dotClassNames: null, + dotStyle: null, formItemInput: false, hideMax: false, hideMin: false, @@ -461,3 +1150,78 @@ Toggle_Thumb.args = { showLabels: true, value: 20, }; + +With_Benchmark.args = { + ...sliderArgs, + hideMax: true, + hideMin: true, + hideThumb: false, + included: true, + labelPosition: 'inline', + marks: { + 3: roleBenchmarkInactiveMarker(), + }, + max: 5, + maxLabel: 'Expert', + minLabel: 'Novice', + showLabels: true, + showMarkers: true, + type: 'default', + value: 2, +}; + +Data_Inactive.args = { + ...sliderArgs, + hideMax: true, + hideMin: true, + hideThumb: true, + hideValue: true, + included: false, + labelPosition: 'inline', + marks: { + 1: upperAssessmentActiveMarker(), + 2: roleBenchmarkInactiveMarker(), + 3: lowerAssessmentActiveMarker(), + }, + max: 5, + maxLabel: 'Expert', + minLabel: 'Novice', + readOnly: true, + showLabels: true, + showMarkers: true, + trackColor: SliderTrackColor.Green, + type: 'data', + value: [1, 3], +}; + +Data_Active.args = { + ...sliderArgs, + dots: true, + dotClassNames: 'slider-dot', + dotStyle: { + backgroundColor: '#FFCD78', + borderColor: '#C97E19', + opacity: 0, + }, + hideMax: true, + hideMin: true, + hideThumb: true, + hideValue: true, + included: false, + labelPosition: 'inline', + marks: { + 1: lowerAssessmentActiveMarker(), + 2: roleBenchmarkInactiveMarker(), + 3: upperAssessmentInactiveMarker(), + }, + min: 0, + max: 5, + maxLabel: 'Expert', + minLabel: 'Novice', + readOnly: true, + showLabels: true, + showMarkers: true, + trackColor: SliderTrackColor.Red, + type: 'data', + value: [1, 3], +}; diff --git a/src/components/Slider/Slider.tsx b/src/components/Slider/Slider.tsx index 3e3c6b38f..01c49fb41 100644 --- a/src/components/Slider/Slider.tsx +++ b/src/components/Slider/Slider.tsx @@ -18,17 +18,18 @@ import SliderContext, { SliderContextProps } from './Context'; import Marks from './Marks'; import Steps from './Steps'; import { - LARGE_INLINE_MARGIN_OFFSET, + LARGE_MARKER_OFFSET, LARGE_THUMB_DIAMETER, LARGE_THUMB_RADIUS, Marker, - MEDIUM_INLINE_MARGIN_OFFSET, + MEDIUM_MARKER_OFFSET, MEDIUM_THUMB_DIAMETER, MEDIUM_THUMB_RADIUS, SliderMarker, SliderProps, SliderSize, - SMALL_INLINE_MARGIN_OFFSET, + SliderTrackColor, + SMALL_MARKER_OFFSET, SMALL_THUMB_DIAMETER, SMALL_THUMB_RADIUS, THUMB_TOOLTIP_Y_OFFSET, @@ -84,11 +85,14 @@ export const Slider: FC = React.forwardRef( containerClassNames, disabled = false, dots = false, + dotClassNames, dotStyle, formItemInput = false, hideMax = false, hideMin = false, + hideRail = false, hideThumb = false, + hideTrack = false, hideValue = false, id, included = true, @@ -107,6 +111,7 @@ export const Slider: FC = React.forwardRef( step = 1, tooltipContent, tooltipProps, + trackColor, type = 'default', value, valueLabel, @@ -194,7 +199,11 @@ export const Slider: FC = React.forwardRef( }; const isMarkerSegmentActive = (markerValue: number): boolean => { - const markerPct = valueToPercent(markerValue, mergedMin, mergedMax); + const markerPct: number = valueToPercent( + markerValue, + mergedMin, + mergedMax + ); const segmentRangeOffset: number = 1; return isRange ? markerPct >= @@ -211,58 +220,58 @@ export const Slider: FC = React.forwardRef( const thumbGeometry = (): { diameter: number; radius: number; - inlineLabelOffset: number; + showMarkerOffset: number; } => { switch (mergedSize) { case SliderSize.Large: return { diameter: LARGE_THUMB_DIAMETER, radius: LARGE_THUMB_RADIUS, - inlineLabelOffset: LARGE_INLINE_MARGIN_OFFSET, + showMarkerOffset: LARGE_MARKER_OFFSET, }; case SliderSize.Medium: return { diameter: MEDIUM_THUMB_DIAMETER, radius: MEDIUM_THUMB_RADIUS, - inlineLabelOffset: MEDIUM_INLINE_MARGIN_OFFSET, + showMarkerOffset: MEDIUM_MARKER_OFFSET, }; case SliderSize.Small: return { diameter: SMALL_THUMB_DIAMETER, radius: SMALL_THUMB_RADIUS, - inlineLabelOffset: SMALL_INLINE_MARGIN_OFFSET, + showMarkerOffset: SMALL_MARKER_OFFSET, }; case SliderSize.Flex: if (largeScreenActive) { return { diameter: SMALL_THUMB_DIAMETER, radius: SMALL_THUMB_RADIUS, - inlineLabelOffset: SMALL_INLINE_MARGIN_OFFSET, + showMarkerOffset: SMALL_MARKER_OFFSET, }; } else if (mediumScreenActive) { return { diameter: MEDIUM_THUMB_DIAMETER, radius: MEDIUM_THUMB_RADIUS, - inlineLabelOffset: MEDIUM_INLINE_MARGIN_OFFSET, + showMarkerOffset: MEDIUM_MARKER_OFFSET, }; } else if (smallScreenActive) { return { diameter: MEDIUM_THUMB_DIAMETER, radius: MEDIUM_THUMB_RADIUS, - inlineLabelOffset: MEDIUM_INLINE_MARGIN_OFFSET, + showMarkerOffset: MEDIUM_MARKER_OFFSET, }; } else if (xSmallScreenActive) { return { diameter: LARGE_THUMB_DIAMETER, radius: LARGE_THUMB_RADIUS, - inlineLabelOffset: LARGE_INLINE_MARGIN_OFFSET, + showMarkerOffset: LARGE_MARKER_OFFSET, }; } default: return { diameter: MEDIUM_THUMB_DIAMETER, radius: MEDIUM_THUMB_RADIUS, - inlineLabelOffset: MEDIUM_INLINE_MARGIN_OFFSET, + showMarkerOffset: MEDIUM_MARKER_OFFSET, }; } }; @@ -342,18 +351,20 @@ export const Slider: FC = React.forwardRef( } if (!isRange) { - const lowerLabelOffset: number = lowerLabelRef.current.offsetWidth / 2; - const inlineLabelOffest: number = - labelPosition === 'inline' ? thumbGeometry().inlineLabelOffset : 0; + const lowerLabelOffset: number = + lowerLabelRef.current?.offsetWidth / 2 - + sliderRef.current?.offsetLeft; + const showMarkerOffest: number = + showMarkers === true ? thumbGeometry().showMarkerOffset : 0; if (htmlDir === 'rtl') { lowerLabelRef.current.style.right = `${ - lowerThumbOffset - lowerLabelOffset + inlineLabelOffest + lowerThumbOffset - lowerLabelOffset - showMarkerOffest }px`; lowerLabelRef.current.style.left = 'unset'; } else { lowerLabelRef.current.style.left = `${ - lowerThumbOffset - lowerLabelOffset + inlineLabelOffest + lowerThumbOffset - lowerLabelOffset - showMarkerOffest }px`; lowerLabelRef.current.style.right = 'unset'; } @@ -532,7 +543,7 @@ export const Slider: FC = React.forwardRef( }; const changeToCloseValue = (newValue: number) => { - if (!disabled) { + if (!readOnly && !disabled) { let valueIndex: number = 0; let valueDist: number = mergedMax - mergedMin; @@ -646,7 +657,7 @@ export const Slider: FC = React.forwardRef( // Update markers when shown useLayoutEffect(() => { updateLayout(); - }, [showLabels, showMarkers, value, values]); + }, [labelPosition, showLabels, showMarkers, value, values]); const context: SliderContextProps = useMemo( () => ({ @@ -716,9 +727,15 @@ export const Slider: FC = React.forwardRef( >
= React.forwardRef( className={mergeClasses([ styles.sliderTrack, { - [styles.sliderTrackOpacity]: showMarkers || !included, + [styles.green]: + !!trackColor && trackColor === SliderTrackColor.Green, + }, + { + [styles.orange]: + !!trackColor && trackColor === SliderTrackColor.Orange, + }, + { + [styles.red]: + !!trackColor && trackColor === SliderTrackColor.Red, + }, + { + [styles.sliderTrackOpacity]: + !!hideTrack || !!showMarkers || !included, }, ])} onMouseDown={ @@ -741,9 +771,23 @@ export const Slider: FC = React.forwardRef( return (
= React.forwardRef( = React.forwardRef( /> {values.map((val: number, index: number) => ( = React.forwardRef( max={mergedMax} name={getIdentifier(name, index)} type="range" + readOnly={readOnly} step={mergedStep} value={val} /> diff --git a/src/components/Slider/Slider.types.ts b/src/components/Slider/Slider.types.ts index 30d1ead9a..1c784758d 100644 --- a/src/components/Slider/Slider.types.ts +++ b/src/components/Slider/Slider.types.ts @@ -27,6 +27,10 @@ export const SMALL_THUMB_RADIUS: number = SMALL_THUMB_DIAMETER / 2; export const THUMB_TOOLTIP_Y_OFFSET: number = 8; +export const LARGE_MARKER_OFFSET: number = +styles.largeMarkerOffset; +export const MEDIUM_MARKER_OFFSET: number = +styles.mediumMarkerOffset; +export const SMALL_MARKER_OFFSET: number = +styles.smallMarkerOffset; + export type SliderLabelPosition = 'bottom' | 'inline'; export type SliderMarks = SliderProps['marks']; @@ -39,7 +43,25 @@ export enum SliderSize { Medium = 'medium', Small = 'small', } + +export enum SliderTrackColor { + Green = 'green', + Orange = 'orange', + Red = 'red', +} + +export enum MarkerType { + Benchmark = 'benchmark', + Origin = 'origin', + Delta = 'delta', + Target = 'target', +} + export interface Marker { + /** + * Custom Marker class names. + */ + classNames?: string; /** * Custom Marker label. */ @@ -48,6 +70,10 @@ export interface Marker { * Custom Marker style. */ style?: React.CSSProperties; + /** + * The marker type. + */ + type?: boolean; } export interface SliderMarker extends Marker { @@ -62,6 +88,10 @@ export interface MarkProps { * The Mark renderer. */ children?: React.ReactNode; + /** + * Custom Mark class names. + */ + classNames?: string; /** * Callback executed on Mark click. */ @@ -94,10 +124,24 @@ export interface DotProps { activeStyle?: | React.CSSProperties | ((dotValue: number) => React.CSSProperties); + /** + * Custom class names. + */ + classNames?: string; /** * Custom dot style. */ style?: React.CSSProperties | ((dotValue: number) => React.CSSProperties); + /** + * The Slider track color. + * Options: green, orange, and red. + */ + trackColor?: SliderTrackColor; + /** + * The type of Slider. + * @default 'default' + */ + type?: SliderType; /** * The step dot value. */ @@ -111,6 +155,10 @@ export interface StepsProps { activeStyle?: | React.CSSProperties | ((dotValue: number) => React.CSSProperties); + /** + * Custom class names. + */ + classNames?: string; /** * The step dots. */ @@ -123,6 +171,16 @@ export interface StepsProps { * Custom dot style. */ style?: React.CSSProperties | ((dotValue: number) => React.CSSProperties); + /** + * The Slider track color. + * Options: green, orange, and red. + */ + trackColor?: SliderTrackColor; + /** + * The type of Slider. + * @default 'default' + */ + type?: SliderType; } export interface SliderProps extends SliderInputProps { @@ -178,6 +236,10 @@ export interface SliderInputProps * @default false */ dots?: boolean; + /** + * Slider step dots custom class names. + */ + dotClassNames?: string; /** * Custom dot style. */ @@ -197,11 +259,21 @@ export interface SliderInputProps * @default false */ hideMin?: boolean; + /** + * Whether to hide the Slider rail. + * @default false + */ + hideRail?: boolean; /** * Whether to hide the Slider thumb until rail is clicked. * @default false */ hideThumb?: boolean; + /** + * Whether to hide the Slider track. + * @default false + */ + hideTrack?: boolean; /** * Hide the value of the Slider. * @default false @@ -227,7 +299,7 @@ export interface SliderInputProps * Slider custom marks, type of key must be number, * and must in closed interval [min, max], each mark may declare its own style. */ - marks?: Record; + marks?: Record; /** * The maximum value of the Slider. * @default 100 @@ -277,6 +349,11 @@ export interface SliderInputProps * Max tooltip props. */ tooltipProps?: Omit; + /** + * The Slider track color. + * Options: green, orange, and red. + */ + trackColor?: SliderTrackColor; /** * The type of Slider. * @default 'default' diff --git a/src/components/Slider/Steps/Dot.tsx b/src/components/Slider/Steps/Dot.tsx index 3debfc741..3d94c156c 100644 --- a/src/components/Slider/Steps/Dot.tsx +++ b/src/components/Slider/Steps/Dot.tsx @@ -1,13 +1,13 @@ import React from 'react'; import SliderContext from '../Context'; -import { DotProps } from '../Slider.types'; +import { DotProps, SliderTrackColor } from '../Slider.types'; import { getDirectionStyle } from '../Util'; import { mergeClasses } from '../../../shared/utilities'; import styles from '../slider.module.scss'; export default function Dot(props: DotProps) { - const { activeStyle, style, value } = props; + const { activeStyle, classNames, style, trackColor, type, value } = props; const { min, max, direction, included, includedStart, includedEnd } = React.useContext(SliderContext); @@ -30,7 +30,21 @@ export default function Dot(props: DotProps) { diff --git a/src/components/Slider/Steps/index.tsx b/src/components/Slider/Steps/index.tsx index eb8bb9c4e..84a09c2bc 100644 --- a/src/components/Slider/Steps/index.tsx +++ b/src/components/Slider/Steps/index.tsx @@ -6,7 +6,8 @@ import Dot from './Dot'; import styles from '../slider.module.scss'; export default function Steps(props: StepsProps) { - const { activeStyle, dots, marks, style } = props; + const { activeStyle, classNames, dots, marks, style, trackColor, type } = + props; const { min, max, step } = React.useContext(SliderContext); const stepDots = React.useMemo(() => { @@ -34,8 +35,11 @@ export default function Steps(props: StepsProps) { {stepDots.map((dotValue: number) => ( ))} diff --git a/src/components/Slider/Util.ts b/src/components/Slider/Util.ts index 8095fe038..12af545e4 100644 --- a/src/components/Slider/Util.ts +++ b/src/components/Slider/Util.ts @@ -11,7 +11,7 @@ export const getDirectionStyle = ( min: number, max: number ): React.CSSProperties => { - const offset = getOffset(value, min, max); + const offset: number = getOffset(value, min, max); const positionStyle: React.CSSProperties = {}; diff --git a/src/components/Slider/slider.module.scss b/src/components/Slider/slider.module.scss index 52544266b..cb36378c5 100644 --- a/src/components/Slider/slider.module.scss +++ b/src/components/Slider/slider.module.scss @@ -13,7 +13,7 @@ $large-marker-top: 0; $medium-slider-height: 22px; $medium-slider-inline-margin: $space-xs; $medium-label-height: 20px; -$medium-thumb-offset: 3px; +$medium-thumb-offset: 4px; $medium-track-height: 4px; $medium-vertical-center: calc($medium-slider-height / 2); $medium-rail-top: $medium-vertical-center - calc($medium-track-height / 2); @@ -36,18 +36,14 @@ $small-marker-top: 0; largeThumbDiameter: strip-units($large-slider-height); mediumThumbDiameter: strip-units($medium-slider-height); smallThumbDiameter: strip-units($small-slider-height); + + largeMarkerOffset: strip-units($space-xxs); + mediumMarkerOffset: strip-units($medium-thumb-offset); + smallMarkerOffset: strip-units($space-xxxs); } // Default size is medium .slider-container { - --slider-default-track-color: var(--primary-color-60); - --slider-default-rail-color: var(--primary-color-10); - --slider-default-rail-border-color: var(--primary-color-60); - --slider-default-value-text-color: var(--text-secondary-color); - --slider-min-max-labels-color: var(--grey-color-60); - --slider-default-thumb-color: var(--accent-color-20); - --slider-default-marker-background: var(--background-color); - font-family: $octuple-font-family; height: $medium-slider-height + $medium-label-height; position: relative; @@ -57,8 +53,8 @@ $small-marker-top: 0; height: $medium-slider-height; &-dot { - background-color: var(--slider-default-rail-color); - border: 1px solid var(--slider-default-rail-border-color); + background-color: var(--slider-rail-background-color); + border: 1px solid var(--slider-rail-border-color); border-radius: 50%; cursor: pointer; height: calc($medium-track-height * 2); @@ -66,9 +62,28 @@ $small-marker-top: 0; top: calc($medium-rail-top - calc($border-offset * 2)); width: calc($medium-track-height * 2); + &:not(.slider-dot-active) { + &.data { + background-color: var(--slider-data-dot-background-color); + border-color: var(--slider-data-rail-border-color); + } + } + &-active { - border-color: var(--slider-default-track-color); + border-color: var(--slider-track-border-color); border-width: 2px; + + &.green { + border-color: var(--slider-track-green-border-color); + } + + &.orange { + border-color: var(--slider-track-orange-border-color); + } + + &.red { + border-color: var(--slider-track-red-border-color); + } } } @@ -82,7 +97,7 @@ $small-marker-top: 0; } &-mark-text { - color: var(--slider-default-value-text-color); + color: var(--slider-value-text-color); cursor: pointer; display: inline-block; font-family: $octuple-font-family; @@ -93,7 +108,7 @@ $small-marker-top: 0; white-space: nowrap; &-active { - color: var(--slider-default-value-text-color); + color: var(--slider-value-text-color); } } @@ -125,8 +140,13 @@ $small-marker-top: 0; // The slider rail needs to be 2px thinner than the track to prevent layered border-radius flicker. .slider-rail { - background-color: var(--slider-default-rail-color); - border: 1px solid var(--slider-default-rail-border-color); + background-color: var(--slider-rail-background-color); + border: 1px solid var(--slider-rail-border-color); + + &.data { + background-color: var(--slider-data-rail-background-color); + border-color: var(--slider-data-rail-border-color); + } &-opacity { opacity: 0; @@ -134,8 +154,23 @@ $small-marker-top: 0; } .slider-track { - background-color: var(--slider-default-track-color); - border: 1px solid var(--slider-default-track-color); + background-color: var(--slider-track-background-color); + border: 1px solid var(--slider-track-border-color); + + &.green { + background-color: var(--slider-track-green-background-color); + border-color: var(--slider-track-green-border-color); + } + + &.orange { + background-color: var(--slider-track-orange-background-color); + border-color: var(--slider-track-orange-border-color); + } + + &.red { + background-color: var(--slider-track-red-background-color); + border-color: var(--slider-track-red-border-color); + } &-opacity { opacity: 0; @@ -156,8 +191,8 @@ $small-marker-top: 0; } .rail-marker-segment { - background-color: var(--slider-default-rail-color); - border: 1px solid var(--slider-default-rail-border-color); + background-color: var(--slider-rail-background-color); + border: 1px solid var(--slider-rail-border-color); border-radius: $border-radius-xs; height: $medium-track-height; position: absolute; @@ -167,14 +202,38 @@ $small-marker-top: 0; display: none; } + &-opacity { + opacity: 0; + } + + &.data { + background-color: var(--slider-data-rail-background-color); + border-color: var(--slider-data-rail-border-color); + } + &.active { - background-color: var(--slider-default-track-color); - border: 1px solid var(--slider-default-track-color); + background-color: var(--slider-track-background-color); + border: 1px solid var(--slider-track-border-color); + + &.green { + background-color: var(--slider-track-green-background-color); + border-color: var(--slider-track-green-border-color); + } + + &.orange { + background-color: var(--slider-track-orange-background-color); + border-color: var(--slider-track-orange-border-color); + } + + &.red { + background-color: var(--slider-track-red-background-color); + border-color: var(--slider-track-red-border-color); + } } } .slider-track { - background-color: var(--slider-default-track-color); + background-color: var(--slider-track-background-color); } .slider-labels { @@ -187,7 +246,7 @@ $small-marker-top: 0; .slider-value { bottom: 0; - color: var(--slider-default-value-text-color); + color: var(--slider-value-text-color); font-family: $octuple-font-family; font-size: $text-font-size-2; padding: 0 $space-xxxs; @@ -196,7 +255,7 @@ $small-marker-top: 0; } .extremity-label { - color: var(--slider-min-max-labels-color); + color: var(--slider-extremity-text-color); font-family: $octuple-font-family; font-size: $text-font-size-2; position: absolute; @@ -259,7 +318,7 @@ $small-marker-top: 0; .thumb { box-shadow: $shadow-object-s; - cursor: pointer; + cursor: grab; display: block; height: 0; opacity: 1; @@ -268,6 +327,10 @@ $small-marker-top: 0; top: $medium-rail-top; width: 100%; + &:active { + cursor: grabbing; + } + &-hidden { opacity: 0; } @@ -284,21 +347,25 @@ $small-marker-top: 0; // For Chrome browsers &::-webkit-slider-thumb { -webkit-appearance: none; - background-color: var(--slider-default-thumb-color); + background-color: var(--slider-thumb-color); border: none; border-radius: 50%; box-shadow: $shadow-object-s; - cursor: pointer; + cursor: grab; height: $medium-slider-height; margin-top: $space-xxs; pointer-events: all; position: relative; width: $medium-slider-height; + + &:active { + cursor: grabbing; + } } // For Firefox browsers &::-moz-range-thumb { - background-color: var(--slider-default-thumb-color); + background-color: var(--slider-thumb-color); background-image: url("data:image/svg+xml,%3Csvg width='4' height='7' viewBox='0 0 4 7' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0H1.34375V1.34375H0V0ZM2.65625 0H4V1.34375H2.65625V0ZM0 2.65625H1.34375V4H0V2.65625ZM2.65625 2.65625H4V4H2.65625V2.65625ZM0 5.34375H1.34375V6.65625H0V5.34375ZM2.65625 5.34375H4V6.65625H2.65625V5.34375Z' fill='%23343c4c'/%3E%3C/svg%3E%0A"); background-position: center; background-repeat: no-repeat; @@ -315,6 +382,16 @@ $small-marker-top: 0; } &.show-markers { + .slider { + &-dot { + margin-left: -3px; + } + + &-mark-text { + margin-left: -$space-xxxs; + } + } + .thumb { margin-left: -$medium-thumb-offset; } @@ -465,6 +542,16 @@ $small-marker-top: 0; } &.show-markers { + .slider { + &-dot { + margin-left: -$space-xxs; + } + + &-mark-text { + margin-left: -$space-xxs; + } + } + .thumb { margin-left: -$space-xxs; } @@ -600,6 +687,16 @@ $small-marker-top: 0; } &.show-markers { + .slider { + &-dot { + margin-left: -3px; + } + + &-mark-text { + margin-left: -$space-xxs; + } + } + .thumb { margin-left: -$medium-thumb-offset; } @@ -740,6 +837,16 @@ $small-marker-top: 0; } &.show-markers { + .slider { + &-dot { + margin-left: -$space-xxxs; + } + + &-mark-text { + margin-left: -$space-xxxs; + } + } + .thumb { margin-left: -$space-xxxs; } @@ -804,6 +911,18 @@ $small-marker-top: 0; } &.show-markers { + .slider { + &-dot { + margin-left: unset; + margin-right: -3px; + } + + &-mark-text { + margin-left: unset; + margin-right: -$space-xxs; + } + } + .thumb { margin-left: unset; margin-right: -$medium-thumb-offset; @@ -868,6 +987,18 @@ $small-marker-top: 0; } &.show-markers { + .slider { + &-dot { + margin-left: unset; + margin-right: -$space-xxs; + } + + &-mark-text { + margin-left: unset; + margin-right: -$space-xxs; + } + } + .thumb { margin-left: unset; margin-right: -$space-xxs; @@ -926,6 +1057,18 @@ $small-marker-top: 0; } &.show-markers { + .slider { + &-dot { + margin-left: unset; + margin-right: -3px; + } + + &-mark-text { + margin-left: unset; + margin-right: -$space-xxs; + } + } + .thumb { margin-left: unset; margin-right: -$medium-thumb-offset; @@ -984,6 +1127,18 @@ $small-marker-top: 0; } &.show-markers { + .slider { + &-dot { + margin-left: unset; + margin-right: -$space-xxxs; + } + + &-mark-text { + margin-left: unset; + margin-right: -$space-xxxs; + } + } + .thumb { margin-left: unset; margin-right: -$space-xxxs; diff --git a/src/octuple.ts b/src/octuple.ts index e1ecd9cdd..dd79f7658 100644 --- a/src/octuple.ts +++ b/src/octuple.ts @@ -109,7 +109,12 @@ import { import { Select, SelectShape, SelectSize } from './components/Select'; -import { Slider, SliderMarks } from './components/Slider'; +import { + Slider, + SliderMarks, + SliderSize, + SliderTrackColor, +} from './components/Slider'; import { SnackbarContainer, Snackbar, snack } from './components/Snackbar'; @@ -295,6 +300,8 @@ export { Slide, Slider, SliderMarks, + SliderSize, + SliderTrackColor, snack, Snackbar, SnackbarContainer, diff --git a/src/styles/themes/_default-theme.scss b/src/styles/themes/_default-theme.scss index e7129e5f5..725a56dca 100644 --- a/src/styles/themes/_default-theme.scss +++ b/src/styles/themes/_default-theme.scss @@ -694,4 +694,33 @@ // ------ Spinner theme ------ --spinner-color: var(--primary-color); // ------ Spinner theme ------ + + // ------ Slider theme ------ + --slider-data-active-mark-one-background-color: var(--grey-color-30); + --slider-data-active-mark-one-border-color: var(--grey-color-60); + --slider-data-dot-background-color: var(--grey-color-10); + --slider-data-inactive-mark-one-background-color: var(--violet-color-30); + --slider-data-inactive-mark-one-border-color: var(--violetred-color-60); + --slider-data-inactive-mark-two-background-color: var(--blue-color-30); + --slider-data-inactive-mark-two-border-color: var(--blueviolet-color-60); + --slider-data-inactive-mark-three-background-color: var(--orange-color-30); + --slider-data-inactive-mark-three-border-color: var(--orange-color-60); + --slider-data-rail-background-color: var(--grey-color-30); + --slider-data-rail-border-color: var(--grey-color-60); + --slider-extremity-text-color: var(--grey-color-60); + --slider-benchmark-background-color: var(--grey-color-30); + --slider-benchmark-border-color: var(--grey-color-60); + --slider-rail-background-color: var(--accent-color-10); + --slider-rail-border-color: var(--primary-color-60); + --slider-thumb-color: var(--accent-color-20); + --slider-track-background-color: var(--primary-color-60); + --slider-track-border-color: var(--primary-color-60); + --slider-track-green-background-color: var(--green-color-30); + --slider-track-green-border-color: var(--green-color-60); + --slider-track-orange-background-color: var(--orange-color-30); + --slider-track-orange-border-color: var(--orange-color-60); + --slider-track-red-background-color: var(--red-color-30); + --slider-track-red-border-color: var(--red-color-60); + --slider-value-text-color: var(--text-secondary-color); + // ------ Slider theme ------ } From 8cddf0fa6ba9ea03e8b10bf13b825b1d2c780398 Mon Sep 17 00:00:00 2001 From: Dylan Kilgore Date: Wed, 1 Feb 2023 16:47:31 -0800 Subject: [PATCH 2/4] chore: slider: add more unit tests --- src/components/Slider/Slider.test.tsx | 43 ++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/components/Slider/Slider.test.tsx b/src/components/Slider/Slider.test.tsx index 1c600b87b..ce67b6e47 100644 --- a/src/components/Slider/Slider.test.tsx +++ b/src/components/Slider/Slider.test.tsx @@ -4,7 +4,7 @@ import Enzyme, { mount, ReactWrapper } from 'enzyme'; import MatchMediaMock from 'jest-matchmedia-mock'; import { render, fireEvent } from '@testing-library/react'; -import { Slider } from './'; +import { Slider, SliderTrackColor } from './'; Enzyme.configure({ adapter: new Adapter() }); @@ -143,11 +143,21 @@ describe('Slider', () => { expect(vals[1]).toEqual(10); }); + test('should render normally when `hideRail=true`', () => { + const { container } = render(); + expect(() => container).not.toThrowError(); + }); + test('should render normally when `hideThumb=true`', () => { const { container } = render(); expect(() => container).not.toThrowError(); }); + test('should render normally when `hideTrack=true`', () => { + const { container } = render(); + expect(() => container).not.toThrowError(); + }); + test('should render normally when `labelPosition=inline`', () => { const { container } = render(); expect(() => container).not.toThrowError(); @@ -171,6 +181,16 @@ describe('Slider', () => { ); }); + test('should render dots with custom class', () => { + const { container: container1 } = render( + + ); + expect(container1.getElementsByClassName('slider-dot')).toHaveLength(11); + expect(container1.getElementsByClassName('dot-test-class')).toHaveLength( + 11 + ); + }); + test('should render normally when `dots=true` and `step=null`', () => { const { container } = render(); expect(() => container).not.toThrowError(); @@ -257,4 +277,25 @@ describe('Slider', () => { container.getElementsByClassName('thumb')[0].getAttribute('value') ).toBe('30'); }); + + test('should render green track color', () => { + const { container: container1 } = render( + + ); + expect(container1.getElementsByClassName('green')).toHaveLength(1); + }); + + test('should render orange track color', () => { + const { container: container1 } = render( + + ); + expect(container1.getElementsByClassName('orange')).toHaveLength(1); + }); + + test('should render red track color', () => { + const { container: container1 } = render( + + ); + expect(container1.getElementsByClassName('red')).toHaveLength(1); + }); }); From 7574e307ee025e2e46314dbb2fb1389b5f8d14fb Mon Sep 17 00:00:00 2001 From: Dylan Kilgore Date: Thu, 2 Feb 2023 08:36:32 -0800 Subject: [PATCH 3/4] chore: slider: pass class names to marks --- src/components/Slider/Marks/index.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/Slider/Marks/index.tsx b/src/components/Slider/Marks/index.tsx index 6a7e50d18..2b811c146 100644 --- a/src/components/Slider/Marks/index.tsx +++ b/src/components/Slider/Marks/index.tsx @@ -14,8 +14,14 @@ export default function Marks(props: MarksProps) { return (
- {marks.map(({ value, style, label }) => ( - + {marks.map(({ classNames, label, style, value }) => ( + {label} ))} From 0f237ca54a7fdffc8b5c0e20ef8a408d737b0c51 Mon Sep 17 00:00:00 2001 From: Dylan Kilgore Date: Tue, 7 Feb 2023 17:44:51 -0800 Subject: [PATCH 4/4] chore: slider: address pr feedback by updating track color to track status --- src/components/Slider/Slider.stories.tsx | 15 ++++---- src/components/Slider/Slider.test.tsx | 21 +++++------ src/components/Slider/Slider.tsx | 38 ++++++++++--------- src/components/Slider/Slider.types.ts | 26 ++++++------- src/components/Slider/Steps/Dot.tsx | 21 ++++++++--- src/components/Slider/Steps/index.tsx | 4 +- src/components/Slider/slider.module.scss | 48 ++++++++++++------------ src/octuple.ts | 4 +- src/styles/themes/_default-theme.scss | 12 +++--- 9 files changed, 99 insertions(+), 90 deletions(-) diff --git a/src/components/Slider/Slider.stories.tsx b/src/components/Slider/Slider.stories.tsx index ab177653a..5546489c2 100644 --- a/src/components/Slider/Slider.stories.tsx +++ b/src/components/Slider/Slider.stories.tsx @@ -1,10 +1,9 @@ import React, { useRef, useState } from 'react'; import { ComponentMeta, ComponentStory } from '@storybook/react'; -import { Slider, SliderSize, SliderTrackColor } from './'; +import { Slider, SliderSize, SliderTrackStatus } from './'; import { Stack } from '../Stack'; import { Col, Row } from '../Grid'; import { PrimaryButton } from '../Button'; -import { IconName, IconSize } from '../Icon'; import { useArgs } from '@storybook/client-api'; import { ConfigProvider } from '../ConfigProvider'; @@ -915,7 +914,7 @@ const Data_Active_Story: ComponentStory = (args) => { updateArgs({ ...args, marks: updateMarks(targetSlidingValue), - trackColor: SliderTrackColor.Red, + trackStatus: SliderTrackStatus.Error, value: [targetSlidingValue, persistedUpperValue], }); } else if (targetSlidingValue === benchmarkValue) { @@ -923,7 +922,7 @@ const Data_Active_Story: ComponentStory = (args) => { updateArgs({ ...args, marks: updateMarks(targetSlidingValue, benchmarkValue), - trackColor: SliderTrackColor.Red, + trackStatus: SliderTrackStatus.Error, value: [targetSlidingValue, persistedUpperValue], }); } else if (targetSlidingValue === persistedUpperValue) { @@ -931,7 +930,7 @@ const Data_Active_Story: ComponentStory = (args) => { updateArgs({ ...args, marks: updateMarks(targetSlidingValue, null, persistedUpperValue), - trackColor: SliderTrackColor.Green, + trackStatus: SliderTrackStatus.Success, value: [targetSlidingValue, persistedUpperValue], }); } else { @@ -942,7 +941,7 @@ const Data_Active_Story: ComponentStory = (args) => { updateArgs({ ...args, marks: updateMarks(targetSlidingValue), - trackColor: SliderTrackColor.Green, + trackStatus: SliderTrackStatus.Success, value: [persistedUpperValue, targetSlidingValue], }); } @@ -1189,7 +1188,7 @@ Data_Inactive.args = { readOnly: true, showLabels: true, showMarkers: true, - trackColor: SliderTrackColor.Green, + trackStatus: SliderTrackStatus.Success, type: 'data', value: [1, 3], }; @@ -1221,7 +1220,7 @@ Data_Active.args = { readOnly: true, showLabels: true, showMarkers: true, - trackColor: SliderTrackColor.Red, + trackStatus: SliderTrackStatus.Error, type: 'data', value: [1, 3], }; diff --git a/src/components/Slider/Slider.test.tsx b/src/components/Slider/Slider.test.tsx index ce67b6e47..39b42a126 100644 --- a/src/components/Slider/Slider.test.tsx +++ b/src/components/Slider/Slider.test.tsx @@ -2,10 +2,9 @@ import React from 'react'; import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; import Enzyme, { mount, ReactWrapper } from 'enzyme'; import MatchMediaMock from 'jest-matchmedia-mock'; +import { Slider, SliderTrackStatus } from './'; import { render, fireEvent } from '@testing-library/react'; -import { Slider, SliderTrackColor } from './'; - Enzyme.configure({ adapter: new Adapter() }); let matchMedia: any; @@ -278,24 +277,24 @@ describe('Slider', () => { ).toBe('30'); }); - test('should render green track color', () => { + test('should render success track color', () => { const { container: container1 } = render( - + ); - expect(container1.getElementsByClassName('green')).toHaveLength(1); + expect(container1.getElementsByClassName('success')).toHaveLength(1); }); - test('should render orange track color', () => { + test('should render warning track color', () => { const { container: container1 } = render( - + ); - expect(container1.getElementsByClassName('orange')).toHaveLength(1); + expect(container1.getElementsByClassName('warning')).toHaveLength(1); }); - test('should render red track color', () => { + test('should render error track color', () => { const { container: container1 } = render( - + ); - expect(container1.getElementsByClassName('red')).toHaveLength(1); + expect(container1.getElementsByClassName('error')).toHaveLength(1); }); }); diff --git a/src/components/Slider/Slider.tsx b/src/components/Slider/Slider.tsx index 01c49fb41..47f287741 100644 --- a/src/components/Slider/Slider.tsx +++ b/src/components/Slider/Slider.tsx @@ -28,7 +28,7 @@ import { SliderMarker, SliderProps, SliderSize, - SliderTrackColor, + SliderTrackStatus, SMALL_MARKER_OFFSET, SMALL_THUMB_DIAMETER, SMALL_THUMB_RADIUS, @@ -111,7 +111,7 @@ export const Slider: FC = React.forwardRef( step = 1, tooltipContent, tooltipProps, - trackColor, + trackStatus, type = 'default', value, valueLabel, @@ -745,16 +745,18 @@ export const Slider: FC = React.forwardRef( className={mergeClasses([ styles.sliderTrack, { - [styles.green]: - !!trackColor && trackColor === SliderTrackColor.Green, + [styles.success]: + !!trackStatus && + trackStatus === SliderTrackStatus.Success, }, { - [styles.orange]: - !!trackColor && trackColor === SliderTrackColor.Orange, + [styles.warning]: + !!trackStatus && + trackStatus === SliderTrackStatus.Warning, }, { - [styles.red]: - !!trackColor && trackColor === SliderTrackColor.Red, + [styles.error]: + !!trackStatus && trackStatus === SliderTrackStatus.Error, }, { [styles.sliderTrackOpacity]: @@ -773,18 +775,18 @@ export const Slider: FC = React.forwardRef( className={mergeClasses(styles.railMarkerSegment, { [styles.data]: type === 'data', [styles.active]: isMarkerSegmentActive(mark.value), - [styles.green]: + [styles.success]: isMarkerSegmentActive(mark.value) && - !!trackColor && - trackColor === SliderTrackColor.Green, - [styles.orange]: + !!trackStatus && + trackStatus === SliderTrackStatus.Success, + [styles.warning]: isMarkerSegmentActive(mark.value) && - !!trackColor && - trackColor === SliderTrackColor.Orange, - [styles.red]: + !!trackStatus && + trackStatus === SliderTrackStatus.Warning, + [styles.error]: isMarkerSegmentActive(mark.value) && - !!trackColor && - trackColor === SliderTrackColor.Red, + !!trackStatus && + trackStatus === SliderTrackStatus.Error, [styles.railMarkerSegmentHidden]: index === markers.length - 1, [styles.railMarkerSegmentOpacity]: !!hideTrack, @@ -807,7 +809,7 @@ export const Slider: FC = React.forwardRef( classNames={dotClassNames} marks={markList} style={dotStyle} - trackColor={trackColor} + trackStatus={trackStatus} type={type} /> React.CSSProperties); /** - * The Slider track color. - * Options: green, orange, and red. + * The Slider track status. + * Options: success, warning, and error. */ - trackColor?: SliderTrackColor; + trackStatus?: SliderTrackStatus; /** * The type of Slider. * @default 'default' @@ -172,10 +172,10 @@ export interface StepsProps { */ style?: React.CSSProperties | ((dotValue: number) => React.CSSProperties); /** - * The Slider track color. - * Options: green, orange, and red. + * The Slider track status. + * Options: success, warning, and error. */ - trackColor?: SliderTrackColor; + trackStatus?: SliderTrackStatus; /** * The type of Slider. * @default 'default' @@ -350,10 +350,10 @@ export interface SliderInputProps */ tooltipProps?: Omit; /** - * The Slider track color. - * Options: green, orange, and red. + * The Slider track status. + * Options: success, warning, and error. */ - trackColor?: SliderTrackColor; + trackStatus?: SliderTrackStatus; /** * The type of Slider. * @default 'default' diff --git a/src/components/Slider/Steps/Dot.tsx b/src/components/Slider/Steps/Dot.tsx index 3d94c156c..4bd827aec 100644 --- a/src/components/Slider/Steps/Dot.tsx +++ b/src/components/Slider/Steps/Dot.tsx @@ -1,13 +1,20 @@ import React from 'react'; import SliderContext from '../Context'; -import { DotProps, SliderTrackColor } from '../Slider.types'; +import { DotProps, SliderTrackStatus } from '../Slider.types'; import { getDirectionStyle } from '../Util'; import { mergeClasses } from '../../../shared/utilities'; import styles from '../slider.module.scss'; export default function Dot(props: DotProps) { - const { activeStyle, classNames, style, trackColor, type, value } = props; + const { + activeStyle, + classNames, + style, + trackStatus: trackStatus, + type, + value, + } = props; const { min, max, direction, included, includedStart, includedEnd } = React.useContext(SliderContext); @@ -34,14 +41,16 @@ export default function Dot(props: DotProps) { [styles.data]: type === 'data', }, { - [styles.green]: !!trackColor && trackColor === SliderTrackColor.Green, + [styles.success]: + !!trackStatus && trackStatus === SliderTrackStatus.Success, }, { - [styles.orange]: - !!trackColor && trackColor === SliderTrackColor.Orange, + [styles.warning]: + !!trackStatus && trackStatus === SliderTrackStatus.Warning, }, { - [styles.red]: !!trackColor && trackColor === SliderTrackColor.Red, + [styles.error]: + !!trackStatus && trackStatus === SliderTrackStatus.Error, }, { [styles.sliderDotActive]: active }, classNames, diff --git a/src/components/Slider/Steps/index.tsx b/src/components/Slider/Steps/index.tsx index 84a09c2bc..8ee4ae5d2 100644 --- a/src/components/Slider/Steps/index.tsx +++ b/src/components/Slider/Steps/index.tsx @@ -6,7 +6,7 @@ import Dot from './Dot'; import styles from '../slider.module.scss'; export default function Steps(props: StepsProps) { - const { activeStyle, classNames, dots, marks, style, trackColor, type } = + const { activeStyle, classNames, dots, marks, style, trackStatus, type } = props; const { min, max, step } = React.useContext(SliderContext); @@ -38,7 +38,7 @@ export default function Steps(props: StepsProps) { classNames={classNames} key={dotValue} style={style} - trackColor={trackColor} + trackStatus={trackStatus} type={type} value={dotValue} /> diff --git a/src/components/Slider/slider.module.scss b/src/components/Slider/slider.module.scss index cb36378c5..9a11e8600 100644 --- a/src/components/Slider/slider.module.scss +++ b/src/components/Slider/slider.module.scss @@ -73,16 +73,16 @@ $small-marker-top: 0; border-color: var(--slider-track-border-color); border-width: 2px; - &.green { - border-color: var(--slider-track-green-border-color); + &.success { + border-color: var(--slider-track-success-border-color); } - &.orange { - border-color: var(--slider-track-orange-border-color); + &.warning { + border-color: var(--slider-track-warning-border-color); } - &.red { - border-color: var(--slider-track-red-border-color); + &.error { + border-color: var(--slider-track-error-border-color); } } } @@ -157,19 +157,19 @@ $small-marker-top: 0; background-color: var(--slider-track-background-color); border: 1px solid var(--slider-track-border-color); - &.green { - background-color: var(--slider-track-green-background-color); - border-color: var(--slider-track-green-border-color); + &.success { + background-color: var(--slider-track-success-background-color); + border-color: var(--slider-track-success-border-color); } - &.orange { - background-color: var(--slider-track-orange-background-color); - border-color: var(--slider-track-orange-border-color); + &.warning { + background-color: var(--slider-track-warning-background-color); + border-color: var(--slider-track-warning-border-color); } - &.red { - background-color: var(--slider-track-red-background-color); - border-color: var(--slider-track-red-border-color); + &.error { + background-color: var(--slider-track-error-background-color); + border-color: var(--slider-track-error-border-color); } &-opacity { @@ -215,19 +215,19 @@ $small-marker-top: 0; background-color: var(--slider-track-background-color); border: 1px solid var(--slider-track-border-color); - &.green { - background-color: var(--slider-track-green-background-color); - border-color: var(--slider-track-green-border-color); + &.success { + background-color: var(--slider-track-success-background-color); + border-color: var(--slider-track-success-border-color); } - &.orange { - background-color: var(--slider-track-orange-background-color); - border-color: var(--slider-track-orange-border-color); + &.warning { + background-color: var(--slider-track-warning-background-color); + border-color: var(--slider-track-warning-border-color); } - &.red { - background-color: var(--slider-track-red-background-color); - border-color: var(--slider-track-red-border-color); + &.error { + background-color: var(--slider-track-error-background-color); + border-color: var(--slider-track-error-border-color); } } } diff --git a/src/octuple.ts b/src/octuple.ts index dd79f7658..697f13fa0 100644 --- a/src/octuple.ts +++ b/src/octuple.ts @@ -113,7 +113,7 @@ import { Slider, SliderMarks, SliderSize, - SliderTrackColor, + SliderTrackStatus, } from './components/Slider'; import { SnackbarContainer, Snackbar, snack } from './components/Snackbar'; @@ -301,7 +301,7 @@ export { Slider, SliderMarks, SliderSize, - SliderTrackColor, + SliderTrackStatus, snack, Snackbar, SnackbarContainer, diff --git a/src/styles/themes/_default-theme.scss b/src/styles/themes/_default-theme.scss index 725a56dca..d23fd364d 100644 --- a/src/styles/themes/_default-theme.scss +++ b/src/styles/themes/_default-theme.scss @@ -715,12 +715,12 @@ --slider-thumb-color: var(--accent-color-20); --slider-track-background-color: var(--primary-color-60); --slider-track-border-color: var(--primary-color-60); - --slider-track-green-background-color: var(--green-color-30); - --slider-track-green-border-color: var(--green-color-60); - --slider-track-orange-background-color: var(--orange-color-30); - --slider-track-orange-border-color: var(--orange-color-60); - --slider-track-red-background-color: var(--red-color-30); - --slider-track-red-border-color: var(--red-color-60); + --slider-track-success-background-color: var(--green-color-30); + --slider-track-success-border-color: var(--green-color-60); + --slider-track-warning-background-color: var(--orange-color-30); + --slider-track-warning-border-color: var(--orange-color-60); + --slider-track-error-background-color: var(--red-color-30); + --slider-track-error-border-color: var(--red-color-60); --slider-value-text-color: var(--text-secondary-color); // ------ Slider theme ------ }