diff --git a/e2e/components/Slider/Slider-test.avt.e2e.js b/e2e/components/Slider/Slider-test.avt.e2e.js index 8ae03d13663c..a8f6d59ff0ed 100644 --- a/e2e/components/Slider/Slider-test.avt.e2e.js +++ b/e2e/components/Slider/Slider-test.avt.e2e.js @@ -92,6 +92,53 @@ test.describe('@avt Slider', () => { await expect(page).toHaveNoACViolations('Slider-with-layer'); }); + test('@avt-advanced-states slider with custom format', async ({ page }) => { + await visitStory(page, { + component: 'Slider', + id: 'components-slider--slider-with-custom-value-label', + globals: { + theme: 'white', + }, + }); + + await expect(page).toHaveNoACViolations('Slider-with-custom-value-label'); + }); + + test.slow('@avt-keyboard-nav slider with custom format', async ({ page }) => { + await visitStory(page, { + component: 'Slider', + id: 'components-slider--slider-with-custom-value-label', + globals: { + theme: 'white', + }, + }); + + // Test for label changes + // Initial value + await page.keyboard.press('Tab'); + await expect(page.getByRole('slider')).toBeVisible(); + await page.keyboard.press('Tab'); + + await expect(page.getByRole('slider')).toHaveAttribute( + 'aria-valuetext', + 'Medium' + ); + // Move to high + await page.keyboard.press('Shift+ArrowRight'); + await expect(page.getByRole('slider')).toHaveAttribute( + 'aria-valuetext', + 'High' + ); + + // Move to Low + await page.keyboard.press('Shift+ArrowLeft'); + await page.keyboard.press('Shift+ArrowLeft'); + await expect(page.getByRole('slider')).toHaveAttribute( + 'aria-valuetext', + 'Low' + ); + }); + // Prevent timeout test.slow('@avt-keyboard-nav', async ({ page }) => { await visitStory(page, { diff --git a/e2e/components/Slider/Slider-test.e2e.js b/e2e/components/Slider/Slider-test.e2e.js index 49e8d4086eca..af64b6b973b8 100644 --- a/e2e/components/Slider/Slider-test.e2e.js +++ b/e2e/components/Slider/Slider-test.e2e.js @@ -37,6 +37,14 @@ test.describe('Slider', () => { theme, }); }); + + test('slider with formatLabel @vrt', async ({ page }) => { + await snapshotStory(page, { + component: 'Slider', + id: 'components-slider--slider-with-custom-value-label', + theme, + }); + }); }); }); }); diff --git a/packages/react/src/components/Slider/Slider-test.js b/packages/react/src/components/Slider/Slider-test.js index 63409195b559..9f694b8d4ca6 100644 --- a/packages/react/src/components/Slider/Slider-test.js +++ b/packages/react/src/components/Slider/Slider-test.js @@ -466,6 +466,28 @@ describe('Slider', () => { expect(rangeLabels[0]).toHaveTextContent('0-min'); expect(rangeLabels[1]).toHaveTextContent('100-max'); }); + + it('supports custom formatting on the tooltip when input is hidden', () => { + const { container } = renderSlider({ + min: 0, + max: 100, + value: 50, + formatLabel: (value) => `${value}%`, + hideTextInput: true, + }); + + const rangeLabels = container.querySelectorAll( + `.${prefix}--slider__range-label` + ); + + const valueLabel = container.querySelector( + `.${prefix}--popover-content.${prefix}--tooltip-content` + ); + + expect(rangeLabels[0]).toHaveTextContent('0%'); + expect(rangeLabels[1]).toHaveTextContent('100%'); + expect(valueLabel).toHaveTextContent('50%'); + }); }); describe('Key/mouse event processing', () => { @@ -744,6 +766,30 @@ describe('Slider', () => { expect(upperInput).toHaveAttribute('type', 'hidden'); }); + it('supports custom formatting on the tooltip when input is hidden', () => { + const { container } = renderTwoHandleSlider({ + min: 0, + max: 100, + value: 50, + unstable_valueUpper: 70, + formatLabel: (value) => `${value}%`, + hideTextInput: true, + }); + + const rangeLabels = container.querySelectorAll( + `.${prefix}--slider__range-label` + ); + + const valueLabels = container.querySelectorAll( + `.${prefix}--popover-content.${prefix}--tooltip-content` + ); + + expect(rangeLabels[0]).toHaveTextContent('0%'); + expect(rangeLabels[1]).toHaveTextContent('100%'); + expect(valueLabels[0]).toHaveTextContent('50%'); + expect(valueLabels[1]).toHaveTextContent('70%'); + }); + it('allows user to set invalid value when typing in input field', async () => { const { type } = userEvent; renderTwoHandleSlider({ diff --git a/packages/react/src/components/Slider/Slider.stories.js b/packages/react/src/components/Slider/Slider.stories.js index 019a5077b236..d84b88d39f0b 100644 --- a/packages/react/src/components/Slider/Slider.stories.js +++ b/packages/react/src/components/Slider/Slider.stories.js @@ -53,6 +53,27 @@ export const SliderWithHiddenInputs = () => ( /> ); +export const SliderWithCustomValueLabel = () => ( + { + if (val < 25) { + return 'Low'; + } else if (val > 75) { + return 'High'; + } + return 'Medium'; + }} + /> +); + export const ControlledSlider = () => { const [val, setVal] = useState(87); return ( diff --git a/packages/react/src/components/Slider/Slider.tsx b/packages/react/src/components/Slider/Slider.tsx index 591cc14e1f70..ddb8277f5927 100644 --- a/packages/react/src/components/Slider/Slider.tsx +++ b/packages/react/src/components/Slider/Slider.tsx @@ -153,7 +153,7 @@ export interface SliderProps disabled?: boolean; /** - * The callback to format the label associated with the minimum/maximum value. + * The callback to format the label associated with the minimum/maximum value and the value tooltip when hideTextInput is true. */ formatLabel?: (value: number, label: string | undefined) => string; @@ -1521,7 +1521,7 @@ class Slider extends PureComponent {
{ role="slider" id={twoHandles ? undefined : id} tabIndex={!readOnly ? 0 : -1} + aria-valuetext={`${formatLabel(value, '')}`} aria-valuemax={twoHandles ? valueUpper : max} aria-valuemin={min} aria-valuenow={value} @@ -1555,7 +1556,7 @@ class Slider extends PureComponent {