diff --git a/packages/react/src/components/Slider/Slider-test.js b/packages/react/src/components/Slider/Slider-test.js index 0f58440a59fb..63409195b559 100644 --- a/packages/react/src/components/Slider/Slider-test.js +++ b/packages/react/src/components/Slider/Slider-test.js @@ -149,8 +149,12 @@ describe('Slider', () => { }); it('should accurately position slider on mount', () => { - renderSlider({ value: 50, max: 100, min: 0 }); - expect(screen.getByRole('slider')).toHaveStyle({ + const { container } = renderSlider({ value: 50, max: 100, min: 0 }); + // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access + const sliderWrapper = container.querySelector( + `.${prefix}--slider__thumb-wrapper` + ); + expect(sliderWrapper).toHaveStyle({ insetInlineStart: '50%', }); }); @@ -681,40 +685,51 @@ describe('Slider', () => { // Keyboard interactions on the upper thumb, lets mix it up and do the up // and down arrow keys this time. + // Note: Somewhat unintuitively, a click on the upperThumb in the moves it + // as close to the lowerThumb as possible. This is because the elements + // in Jest don't exist in a specific position, layer and size. + // @see https://testing-library.com/docs/user-event/pointer await click(upperThumb); expect(upperThumb).toHaveFocus(); await keyboard('{ArrowUp}'); - expect(onChange).toHaveBeenLastCalledWith({ value: 10, valueUpper: 91 }); - expect(upperThumb).toHaveAttribute('aria-valuenow', '91'); - expect(lowerThumb).toHaveAttribute('aria-valuemax', '91'); - expect(upperInput).toHaveValue(91); + expect(onChange).toHaveBeenLastCalledWith({ value: 10, valueUpper: 11 }); + expect(upperThumb).toHaveAttribute('aria-valuenow', '11'); + expect(lowerThumb).toHaveAttribute('aria-valuemax', '11'); + expect(upperInput).toHaveValue(11); await keyboard('{ArrowDown}'); - expect(onChange).toHaveBeenLastCalledWith({ value: 10, valueUpper: 90 }); - expect(upperThumb).toHaveAttribute('aria-valuenow', '90'); - expect(lowerThumb).toHaveAttribute('aria-valuemax', '90'); - expect(upperInput).toHaveValue(90); + expect(onChange).toHaveBeenLastCalledWith({ value: 10, valueUpper: 10 }); + expect(upperThumb).toHaveAttribute('aria-valuenow', '10'); + expect(lowerThumb).toHaveAttribute('aria-valuemax', '10'); + expect(upperInput).toHaveValue(10); await keyboard('{Shift>}{ArrowUp}{/Shift}'); - expect(onChange).toHaveBeenLastCalledWith({ value: 10, valueUpper: 94 }); - expect(upperThumb).toHaveAttribute('aria-valuenow', '94'); - expect(lowerThumb).toHaveAttribute('aria-valuemax', '94'); - expect(upperInput).toHaveValue(94); + expect(onChange).toHaveBeenLastCalledWith({ value: 10, valueUpper: 14 }); + expect(upperThumb).toHaveAttribute('aria-valuenow', '14'); + expect(lowerThumb).toHaveAttribute('aria-valuemax', '14'); + expect(upperInput).toHaveValue(14); await keyboard('{Shift>}{ArrowDown}{/Shift}'); - expect(onChange).toHaveBeenLastCalledWith({ value: 10, valueUpper: 90 }); - expect(upperThumb).toHaveAttribute('aria-valuenow', '90'); - expect(lowerThumb).toHaveAttribute('aria-valuemax', '90'); - expect(upperInput).toHaveValue(90); + expect(onChange).toHaveBeenLastCalledWith({ value: 10, valueUpper: 10 }); + expect(upperThumb).toHaveAttribute('aria-valuenow', '10'); + expect(lowerThumb).toHaveAttribute('aria-valuemax', '10'); + expect(upperInput).toHaveValue(10); }); it('should accurately position handles on mount', () => { - renderTwoHandleSlider({ + const { container } = renderTwoHandleSlider({ value: 50, unstable_valueUpper: 50, min: 0, max: 100, }); - const [lowerThumb, upperThumb] = screen.getAllByRole('slider'); - expect(lowerThumb).toHaveStyle({ insetInlineStart: '50%' }); - expect(upperThumb).toHaveStyle({ insetInlineStart: '50%' }); + // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access + const sliderWrapperLower = container.querySelector( + `.${prefix}--slider__thumb-wrapper--lower` + ); + // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access + const sliderWrapperUpper = container.querySelector( + `.${prefix}--slider__thumb-wrapper--upper` + ); + expect(sliderWrapperLower).toHaveStyle({ insetInlineStart: '50%' }); + expect(sliderWrapperUpper).toHaveStyle({ insetInlineStart: '50%' }); }); it('marks input field as hidden if hidden via props', () => { diff --git a/packages/react/src/components/Slider/Slider.Skeleton.tsx b/packages/react/src/components/Slider/Slider.Skeleton.tsx index d3fad4cc19a7..27bcf53962dc 100644 --- a/packages/react/src/components/Slider/Slider.Skeleton.tsx +++ b/packages/react/src/components/Slider/Slider.Skeleton.tsx @@ -10,6 +10,7 @@ import React, { HTMLAttributes } from 'react'; import cx from 'classnames'; import { usePrefix } from '../../internal/usePrefix'; import classNames from 'classnames'; +import { LowerHandle, UpperHandle } from './SliderHandles'; export interface SliderSkeletonProps extends HTMLAttributes { /** @@ -35,11 +36,13 @@ const SliderSkeleton = ({ ...rest }: SliderSkeletonProps) => { const prefix = usePrefix(); + const isRtl = document?.dir === 'rtl'; const containerClasses = classNames( `${prefix}--slider-container`, `${prefix}--skeleton`, { [`${prefix}--slider-container--two-handles`]: twoHandles, + [`${prefix}--slider-container--rtl`]: isRtl, } ); const lowerThumbClasses = classNames(`${prefix}--slider__thumb`, { @@ -48,6 +51,18 @@ const SliderSkeleton = ({ const upperThumbClasses = classNames(`${prefix}--slider__thumb`, { [`${prefix}--slider__thumb--upper`]: twoHandles, }); + const lowerThumbWrapperClasses = classNames( + `${prefix}--slider__thumb-wrapper`, + { + [`${prefix}--slider__thumb-wrapper--lower`]: twoHandles, + } + ); + const upperThumbWrapperClasses = classNames( + `${prefix}--slider__thumb-wrapper`, + { + [`${prefix}--slider__thumb-wrapper--upper`]: twoHandles, + } + ); return (
{!hideLabel && ( @@ -58,8 +73,26 @@ const SliderSkeleton = ({
-
- {twoHandles ?
: undefined} +
+
+ {twoHandles && !isRtl ? ( + + ) : twoHandles && isRtl ? ( + + ) : undefined} +
+
+ {twoHandles ? ( +
+
+ {twoHandles && !isRtl ? ( + + ) : twoHandles && isRtl ? ( + + ) : undefined} +
+
+ ) : undefined}
diff --git a/packages/react/src/components/Slider/Slider.stories.js b/packages/react/src/components/Slider/Slider.stories.js index c1ec2c749f39..019a5077b236 100644 --- a/packages/react/src/components/Slider/Slider.stories.js +++ b/packages/react/src/components/Slider/Slider.stories.js @@ -39,6 +39,20 @@ export const Default = () => ( /> ); +export const SliderWithHiddenInputs = () => ( + +); + export const ControlledSlider = () => { const [val, setVal] = useState(87); return ( @@ -110,6 +124,22 @@ export const TwoHandleSlider = () => ( /> ); +export const TwoHandleSliderWithHiddenInputs = () => ( + +); + export const Skeleton = () => ; export const TwoHandleSkeleton = () => ; diff --git a/packages/react/src/components/Slider/Slider.tsx b/packages/react/src/components/Slider/Slider.tsx index b803cd80833a..56ec24d2ca85 100644 --- a/packages/react/src/components/Slider/Slider.tsx +++ b/packages/react/src/components/Slider/Slider.tsx @@ -18,68 +18,59 @@ import deprecate from '../../prop-types/deprecate'; import { FeatureFlagContext } from '../FeatureFlags'; import { WarningFilled, WarningAltFilled } from '@carbon/icons-react'; import { Text } from '../Text'; +import { Tooltip } from '../Tooltip'; +import { + LowerHandle, + LowerHandleFocus, + UpperHandle, + UpperHandleFocus, +} from './SliderHandles'; + +const ThumbWrapper = ({ + hasTooltip = false, + className, + style, + children, + ...rest +}) => { + if (hasTooltip) { + return ( + // eslint-disable-next-line react/forbid-component-props + + {children} + + ); + } else { + return ( + // eslint-disable-next-line react/forbid-dom-props +
+ {children} +
+ ); + } +}; -const LowerHandle = () => ( - - {(prefix) => ( - - - - - )} - -); - -const LowerHandleFocus = () => ( - - {(prefix) => ( - - - - - - - - )} - -); - -const UpperHandle = () => ( - - {(prefix) => ( - - - - - )} - -); - -const UpperHandleFocus = () => ( - - {(prefix) => ( - - - - - - - - )} - -); +ThumbWrapper.propTypes = { + /** + * The thumb node itself. + */ + children: PropTypes.node, + + /** + * CSS wrapper class names. + */ + className: PropTypes.string, + + /** + * Should the thumb show a tooltip with the current value? + */ + hasTooltip: PropTypes.bool.isRequired, + + /** + * Percentage offset for the select thumb value. + */ + style: PropTypes.object, +}; const translationIds = { autoCorrectAnnouncement: 'carbon.slider.auto-correct-announcement', @@ -564,15 +555,6 @@ class Slider extends PureComponent { // Fire onChange event handler if present, if there's a usable value, and // if the value is different from the last one if (this.hasTwoHandles()) { - if (this.thumbRef.current) { - this.thumbRef.current.style.insetInlineStart = `${this.state.left}%`; - if (this.state.isRtl) { - this.thumbRef.current.style.transform = `translate(100%, -50%)`; - } - } - if (this.thumbRefUpper.current) { - this.thumbRefUpper.current.style.insetInlineStart = `${this.state.leftUpper}%`; - } if (this.filledTrackRef.current) { this.filledTrackRef.current.style.transform = this.state.isRtl ? `translate(${100 - this.state.leftUpper}%, -50%) scaleX(${ @@ -583,11 +565,6 @@ class Slider extends PureComponent { })`; } } else { - if (this.thumbRef.current) { - this.thumbRef.current.style.insetInlineStart = this.state.isRtl - ? `calc(${this.state.left}% - 14px)` - : `${this.state.left}%`; - } if (this.filledTrackRef.current) { this.filledTrackRef.current.style.transform = this.state.isRtl ? `translate(100%, -50%) scaleX(-${this.state.left / 100})` @@ -691,6 +668,12 @@ class Slider extends PureComponent { return; } + // We're going to force focus on one of the handles later on here, b/c we're + // firing on a mousedown event, we need to call event.preventDefault() to + // keep the focus from leaving the HTMLElement. + // @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus#notes + evt.preventDefault(); + // Register drag stop handlers DRAG_STOP_EVENT_TYPES.forEach((element) => { this.element?.ownerDocument.addEventListener(element, this.onDragStop); @@ -705,20 +688,43 @@ class Slider extends PureComponent { let activeHandle; if (this.hasTwoHandles()) { - const distanceToLower = this.calcDistanceToHandle( - HandlePosition.LOWER, - clientX - ); - const distanceToUpper = this.calcDistanceToHandle( - HandlePosition.UPPER, - clientX - ); - if (distanceToLower <= distanceToUpper) { + if (evt.target == this.thumbRef.current) { activeHandle = HandlePosition.LOWER; - } else { + } else if (evt.target == this.thumbRefUpper.current) { activeHandle = HandlePosition.UPPER; + } else { + const distanceToLower = this.calcDistanceToHandle( + HandlePosition.LOWER, + clientX + ); + const distanceToUpper = this.calcDistanceToHandle( + HandlePosition.UPPER, + clientX + ); + if (distanceToLower <= distanceToUpper) { + activeHandle = HandlePosition.LOWER; + } else { + activeHandle = HandlePosition.UPPER; + } } } + + // Force focus to the appropriate handle. + const focusOptions = { + preventScroll: true, + }; + if (this.hasTwoHandles()) { + if (this.thumbRef.current && activeHandle === HandlePosition.LOWER) { + this.thumbRef.current.focus(focusOptions); + } else if ( + this.thumbRefUpper.current && + activeHandle === HandlePosition.UPPER + ) { + this.thumbRefUpper.current.focus(focusOptions); + } + } else if (this.thumbRef.current) { + this.thumbRef.current.focus(focusOptions); + } this.setState({ activeHandle }); // Perform first recalculation since we probably didn't click exactly in the @@ -1358,6 +1364,7 @@ class Slider extends PureComponent { [`${prefix}--slider-container--two-handles`]: twoHandles, [`${prefix}--slider-container--disabled`]: disabled, [`${prefix}--slider-container--readonly`]: readOnly, + [`${prefix}--slider-container--rtl`]: isRtl, }); const sliderClasses = classNames(`${prefix}--slider`, { [`${prefix}--slider--disabled`]: disabled, @@ -1370,7 +1377,6 @@ class Slider extends PureComponent { ]; const conditionalInputClasses = { [`${prefix}--text-input--light`]: light, - [`${prefix}--slider-text-input--hidden`]: hideTextInput, }; const lowerInputClasses = classNames([ ...fixedInputClasses, @@ -1397,6 +1403,7 @@ class Slider extends PureComponent { `${prefix}--slider-text-input-wrapper--lower`, { [`${prefix}--text-input-wrapper--readonly`]: readOnly, + [`${prefix}--slider-text-input-wrapper--hidden`]: hideTextInput, }, ]); const upperInputWrapperClasses = classNames([ @@ -1405,6 +1412,7 @@ class Slider extends PureComponent { `${prefix}--slider-text-input-wrapper--upper`, { [`${prefix}--text-input-wrapper--readonly`]: readOnly, + [`${prefix}--slider-text-input-wrapper--hidden`]: hideTextInput, }, ]); const lowerThumbClasses = classNames(`${prefix}--slider__thumb`, { @@ -1413,6 +1421,28 @@ class Slider extends PureComponent { const upperThumbClasses = classNames(`${prefix}--slider__thumb`, { [`${prefix}--slider__thumb--upper`]: twoHandles, }); + const lowerThumbWrapperClasses = classNames([ + `${prefix}--icon-tooltip`, + `${prefix}--slider__thumb-wrapper`, + { + [`${prefix}--slider__thumb-wrapper--lower`]: twoHandles, + }, + ]); + const upperThumbWrapperClasses = classNames([ + `${prefix}--icon-tooltip`, + `${prefix}--slider__thumb-wrapper`, + { + [`${prefix}--slider__thumb-wrapper--upper`]: twoHandles, + }, + ]); + const lowerThumbWrapperProps = { + style: { + insetInlineStart: `${this.state.left}%`, + }, + }; + const upperThumbWrapperProps = { + style: { insetInlineStart: `${this.state.leftUpper}%` }, + }; return (
@@ -1481,43 +1511,71 @@ class Slider extends PureComponent { : null } {...other}> -
- this.setState({ activeHandle: HandlePosition.LOWER }) - }> - {twoHandles && !isRtl && } - {twoHandles && !isRtl && } - {twoHandles && isRtl && } - {twoHandles && isRtl && } -
- {twoHandles ? ( +
- this.setState({ activeHandle: HandlePosition.UPPER }) + this.setState({ activeHandle: HandlePosition.LOWER }) }> - {twoHandles && !isRtl && } - {twoHandles && !isRtl && } - {twoHandles && isRtl && } - {twoHandles && isRtl && } + {twoHandles && !isRtl ? ( + <> + + + + ) : twoHandles && isRtl ? ( + <> + + + + ) : undefined}
+
+ {twoHandles ? ( + +
+ this.setState({ activeHandle: HandlePosition.UPPER }) + }> + {twoHandles && !isRtl ? ( + <> + + + + ) : twoHandles && isRtl ? ( + <> + + + + ) : undefined} +
+
) : null}
( + + {(prefix) => ( + + + + + )} + +); + +export const LowerHandleFocus = () => ( + + {(prefix) => ( + + + + + + + + )} + +); + +export const UpperHandle = () => ( + + {(prefix) => ( + + + + + )} + +); + +export const UpperHandleFocus = () => ( + + {(prefix) => ( + + + + + + + + )} + +); diff --git a/packages/react/src/components/Tabs/Tabs-test.js b/packages/react/src/components/Tabs/Tabs-test.js index ce3ec130364c..a384ea368ac3 100644 --- a/packages/react/src/components/Tabs/Tabs-test.js +++ b/packages/react/src/components/Tabs/Tabs-test.js @@ -492,7 +492,7 @@ describe('TabPanel', () => { ); - expect(screen.getByText('Tab Panel 1')).toHaveAttribute('tabIndex', '0'); + expect(screen.getByText('Tab Panel 1')).toHaveAttribute('tabIndex', '-1'); }); it('should not recieve focus if there is interactive content', () => { diff --git a/packages/react/src/components/Tooltip/Tooltip.tsx b/packages/react/src/components/Tooltip/Tooltip.tsx index 9dddaba643e5..b90a225bc924 100644 --- a/packages/react/src/components/Tooltip/Tooltip.tsx +++ b/packages/react/src/components/Tooltip/Tooltip.tsx @@ -7,7 +7,7 @@ import cx from 'classnames'; import PropTypes from 'prop-types'; -import React, { useRef, useEffect } from 'react'; +import React, { useRef, useEffect, useState, useCallback } from 'react'; import { Popover, PopoverAlignment, PopoverContent } from '../Popover'; import { keys, match } from '../../internal/keyboard'; import { useDelayedState } from '../../internal/useDelayedState'; @@ -19,6 +19,11 @@ import { import { usePrefix } from '../../internal/usePrefix'; import { type PolymorphicProps } from '../../types/common'; +/** + * Event types that trigger a "drag" to stop. + */ +const DRAG_STOP_EVENT_TYPES = new Set(['mouseup', 'touchend', 'touchcancel']); + interface TooltipBaseProps { /** * Specify how the trigger should align with the tooltip @@ -99,6 +104,8 @@ function Tooltip({ const containerRef = useRef(null); const tooltipRef = useRef(null); const [open, setOpen] = useDelayedState(defaultOpen); + const [isDragging, setIsDragging] = useState(false); + const [isPointerIntersecting, setIsPointerIntersecting] = useState(false); const id = useId('tooltip'); const prefix = usePrefix(); const child = React.Children.only(children); @@ -109,6 +116,10 @@ function Tooltip({ onClick: () => closeOnActivation && setOpen(false), // This should be placed on the trigger in case the element is disabled onMouseEnter, + onMouseLeave, + onMouseDown: onDragStart, + onMouseMove: onMouseMove, + onTouchStart: onDragStart, }; function getChildEventHandlers(childProps: any) { @@ -151,13 +162,39 @@ function Tooltip({ } function onMouseEnter() { + setIsPointerIntersecting(true); setOpen(true, enterDelayMs); } function onMouseLeave() { + setIsPointerIntersecting(false); + if (isDragging) { + return; + } setOpen(false, leaveDelayMs); } + function onMouseMove(evt) { + if (evt.buttons === 1) { + setIsDragging(true); + } else { + setIsDragging(false); + } + } + + function onDragStart() { + setIsDragging(true); + } + + const onDragStop = useCallback(() => { + setIsDragging(false); + // Close the tooltip, unless the mouse pointer is within the bounds of the + // trigger. + if (!isPointerIntersecting) { + setOpen(false, leaveDelayMs); + } + }, [isPointerIntersecting, leaveDelayMs, setOpen]); + useNoInteractiveChildren( tooltipRef, 'The Tooltip component must have no interactive content rendered by the' + @@ -175,6 +212,20 @@ function Tooltip({ } }); + useEffect(() => { + if (isDragging) { + // Register drag stop handlers. + DRAG_STOP_EVENT_TYPES.forEach((eventType) => { + document.addEventListener(eventType, onDragStop); + }); + } + return () => { + DRAG_STOP_EVENT_TYPES.forEach((eventType) => { + document.removeEventListener(eventType, onDragStop); + }); + }; + }, [isDragging, onDragStop]); + return ( .#{$prefix}--popover > .#{$prefix}--popover-content { + transform: translate( + 50%, + calc(-100% - custom-property.get-var('popover-offset', 0rem)) + ); + } + + > .#{$prefix}--popover > .#{$prefix}--popover-caret { + inset-inline-end: 0; + inset-inline-start: revert; + transform: translate( + 50%, + calc(-1 * custom-property.get-var('popover-offset', 0rem)) + ); + } + } + + .#{$prefix}--slider-container--rtl .#{$prefix}--slider__thumb-wrapper--lower { + transform: translate(100%, -50%); + + > .#{$prefix}--popover > .#{$prefix}--popover-content { + transform: translate( + 0, + calc(-100% - custom-property.get-var('popover-offset', 0rem)) + ); + } + + > .#{$prefix}--popover > .#{$prefix}--popover-caret { + transform: translate( + -50%, + calc(-1 * custom-property.get-var('popover-offset', 0rem)) + ); + } + } + + .#{$prefix}--slider__thumb-wrapper--upper { + transform: translate(0, -50%); + + > .#{$prefix}--popover > .#{$prefix}--popover-content { + transform: translate( + -50%, + calc(-100% - custom-property.get-var('popover-offset', 0rem)) + ); + } + + > .#{$prefix}--popover > .#{$prefix}--popover-caret { + inset-inline-start: 0; + transform: translate( + -50%, + calc(-1 * custom-property.get-var('popover-offset', 0rem)) + ); + } + } + + .#{$prefix}--slider-container--rtl .#{$prefix}--slider__thumb-wrapper--upper { + transform: translate(0, -50%); + + > .#{$prefix}--popover > .#{$prefix}--popover-content { + transform: translate( + 0, + calc(-100% - custom-property.get-var('popover-offset', 0rem)) + ); + } + + > .#{$prefix}--popover > .#{$prefix}--popover-caret { + transform: translate( + 50%, + calc(-1 * custom-property.get-var('popover-offset', 0rem)) + ); + } + } + + .#{$prefix}--slider__thumb { + position: absolute; border-radius: 50%; background: $layer-selected-inverse; - block-size: convert.to-rem(14px); box-shadow: inset 0 0 0 1px transparent, inset 0 0 0 2px transparent; - inline-size: convert.to-rem(14px); + inset: 0; outline: none; - transform: translate(-50%, -50%); transition: transform $duration-fast-02 motion(standard, productive), background $duration-fast-02 motion(standard, productive), box-shadow $duration-fast-02 motion(standard, productive); &:hover { // 20px / 14px = 1.4286 - transform: translate(-50%, -50%) scale(1.4286); + transform: scale(1.4286); } &:focus { background-color: $interactive; box-shadow: inset 0 0 0 2px $interactive, inset 0 0 0 3px $layer; // 20px / 14px = 1.4286 - transform: translate(-50%, -50%) scale(1.4286); + transform: scale(1.4286); } &:active { box-shadow: inset 0 0 0 2px $interactive; - transform: translate(-50%, -50%) scale(1.4286); + transform: scale(1.4286); } } @@ -128,14 +225,12 @@ .#{$prefix}--slider__thumb--lower, .#{$prefix}--slider__thumb--upper { - display: block; + position: absolute; /* stylelint-disable-next-line declaration-property-value-disallowed-list */ border-radius: unset; background-color: transparent; - block-size: 24px; box-shadow: none; - inline-size: 16px; - transform: translate(-100%, -50%); + inset: 0; transition: none; &::before { @@ -151,7 +246,7 @@ } &:hover { - transform: translate(-100%, -50%); + transform: none; .#{$prefix}--slider__thumb-icon { fill: $text-secondary; @@ -160,13 +255,13 @@ &:active { box-shadow: none; - transform: translate(-100%, -50%); + transform: none; } &:focus { background-color: transparent; box-shadow: none; - transform: translate(-100%, -50%); + transform: none; .#{$prefix}--slider__thumb-icon { display: none; @@ -185,23 +280,17 @@ } .#{$prefix}--slider__thumb--upper { - transform: translate(0, -50%); + transform: none; &::before { inset-inline-end: auto; inset-inline-start: 0; } - &:hover { - transform: translate(0, -50%); - } - - &:active { - transform: translate(0, -50%); - } - + &:hover, + &:active, &:focus { - transform: translate(0, -50%); + transform: none; } } @@ -213,6 +302,10 @@ position: relative; } + .#{$prefix}--slider-text-input-wrapper--hidden { + display: none; + } + .#{$prefix}--slider-text-input, .#{$prefix}-slider-text-input { -moz-appearance: textfield; @@ -226,11 +319,9 @@ } } - .#{$prefix}--slider-text-input--hidden { - display: none; - } - - .#{$prefix}--slider__thumb:focus ~ .#{$prefix}--slider__filled-track { + .#{$prefix}--slider__thumb:focus ~ .#{$prefix}--slider__filled-track, + .#{$prefix}--slider__thumb-wrapper:focus-within + ~ .#{$prefix}--slider__filled-track { background-color: $border-interactive; } @@ -368,17 +459,20 @@ } .#{$prefix}--slider-container.#{$prefix}--skeleton { + .#{$prefix}--slider__thumb-wrapper { + inset-inline-start: 50%; + } + .#{$prefix}--slider__thumb { cursor: default; - inset-inline-start: 50%; pointer-events: none; } - .#{$prefix}--slider__thumb--lower { + .#{$prefix}--slider__thumb-wrapper--lower { inset-inline-start: 0; } - .#{$prefix}--slider__thumb--upper { + .#{$prefix}--slider__thumb-wrapper--upper { inset-inline-start: 100%; } }