diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/slider/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/components/slider/Examples.tsx index e5f8fb4040f..c5b01e9c07d 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/components/slider/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/slider/Examples.tsx @@ -5,6 +5,7 @@ import React from 'react' import ComponentBox from 'dnb-design-system-portal/src/shared/tags/ComponentBox' +import { format } from '@dnb/eufemia/src/components/number-format/NumberUtils' export const SliderExampleDefault = () => ( @@ -16,6 +17,7 @@ export const SliderExampleDefault = () => ( value={70} label="Default Slider:" numberFormat={{ currency: 'EUR' }} + tooltip={true} onChange={({ value }) => console.log('onChange:', value)} /> ` @@ -24,7 +26,7 @@ export const SliderExampleDefault = () => ( ) export const SliderExampleMultiButtons = () => ( - + { /* jsx */ ` @@ -34,16 +36,18 @@ export const SliderExampleMultiButtons = () => ( value={[30, 70]} step={5} label="Range with steps:" - numberFormat={{ currency: 'EUR' }} + numberFormat={{ currency: 'USD' }} + tooltip onChange={({ value }) => console.log('onChange:', value)} bottom - /> - + format(value, { percent: true })} onChange={({ value, number }) => console.log('onChange:', value, number)} /> @@ -62,6 +66,7 @@ export const SliderExampleMultiButtonsThumbBehavior = () => ( value={[30, 70]} label="Omit behavior:" numberFormat={{ currency: 'EUR' }} + tooltip={true} onChange={({ value }) => console.log('onChange:', value)} bottom /> @@ -71,6 +76,7 @@ export const SliderExampleMultiButtonsThumbBehavior = () => ( step={1} label="Push behavior:" numberFormat={{ currency: true }} + tooltip={true} onChange={({ value, number }) => console.log('onChange:', value, number)} /> @@ -80,7 +86,7 @@ export const SliderExampleMultiButtonsThumbBehavior = () => ( ) export const SliderExampleHorizontalSync = () => ( - + { /* jsx */ ` const Component = () => { @@ -92,6 +98,7 @@ const Component = () => { hideButtons label="Slider A:" numberFormat={{ currency: 'EUR' }} + tooltip={true} onChange={({ value }) => setValue(value)} /> @@ -103,6 +110,7 @@ const Component = () => { label="Slider B:" labelDirection="vertical" numberFormat={{ currency: 'NOK' }} + tooltip={(value) => format(value, { currency: true })} onChange={({ value }) => setValue(value)} /> ( ) -export const SliderExampleRange = () => ( - - { - /* jsx */ ` - - - Native Range Slider - - console.log(event.currentTarget.value)} - /> - - ` - } - -) - export const SliderVerticalWithSteps = () => ( { diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/slider/info.md b/packages/dnb-design-system-portal/src/docs/uilib/components/slider/info.md index f51baa76119..029fa08e741 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/components/slider/info.md +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/slider/info.md @@ -9,7 +9,3 @@ The Slider component provides a visual indication of adjustable value. A value c ### Define a `min` and `max` value Keep in mind, you should most probably define your `min` and `max` value, because they are tied closely to your given value property. - -### Tooltip - -When a `numberFormat` is given, a Tooltip will be shown above the thumb button. diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/slider/properties.md b/packages/dnb-design-system-portal/src/docs/uilib/components/slider/properties.md index 70a7bdcae9e..2a196a655a7 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/components/slider/properties.md +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/slider/properties.md @@ -18,7 +18,8 @@ showTabs: true | `thumbTitle` | _(optional)_ give the slider thumb button a title for accessibility reasons. Defaults to `null`. | | `subtractTitle` | _(optional)_ give the subtract button a title for accessibility reasons. Defaults to `−`. | | `addTitle` | _(optional)_ give the add button a title for accessibility reasons. Defaults to `+`. | -| `numberFormat` | _(optional)_ Will extend the return object with a `number` property (from `onChange` event). You can use all the options from the [NumberFormat](/uilib/components/number-format/properties) component. It also will use that formatted number in the increase/decrease buttons. If it has to represent a currency, then use e.g. `numberFormat={{ currency: true, decimals: 0 }}` | +| `numberFormat` | _(optional)_ will extend the return object with a `number` property (from `onChange` event). You can use all the options from the [NumberFormat](/uilib/components/number-format/properties) component. It also will use that formatted number in the increase/decrease buttons. If it has to represent a currency, then use e.g. `numberFormat={{ currency: true, decimals: 0 }}` | +| `tooltip` | _(optional)_ use `true` to show a tooltip on `mouseOver`, `touchStart` and `focus`, showing the current number (if `numberFormat` is given) or the raw value. You can also provide a function callback. Defaults to `null`. | | `label` | _(optional)_ prepends the Form Label component. If no ID is provided, a random ID is created. | | `labelDirection` | _(optional)_ use `labelDirection="vertical"` to change the label layout direction. Defaults to `horizontal`. | | `labelSrOnly` | _(optional)_ use `true` to make the label only readable by screen readers. | diff --git a/packages/dnb-eufemia/src/components/slider/SliderProvider.tsx b/packages/dnb-eufemia/src/components/slider/SliderProvider.tsx index 3e40f6646d3..56d73db9239 100644 --- a/packages/dnb-eufemia/src/components/slider/SliderProvider.tsx +++ b/packages/dnb-eufemia/src/components/slider/SliderProvider.tsx @@ -83,6 +83,7 @@ export function SliderProvider(localProps: SliderProps) { hideButtons, // eslint-disable-line multiThumbBehavior, numberFormat, + tooltip, // eslint-disable-line skeleton, max, // eslint-disable-line min, // eslint-disable-line diff --git a/packages/dnb-eufemia/src/components/slider/SliderThumb.tsx b/packages/dnb-eufemia/src/components/slider/SliderThumb.tsx index 2ca7411411b..e826b8fa745 100644 --- a/packages/dnb-eufemia/src/components/slider/SliderThumb.tsx +++ b/packages/dnb-eufemia/src/components/slider/SliderThumb.tsx @@ -47,6 +47,7 @@ function Thumb({ value, currentIndex }: ThumbProps) { disabled, suffix, numberFormat, + tooltip, } = allProps const index = thumbIndex.current @@ -148,9 +149,11 @@ function Thumb({ value, currentIndex }: ThumbProps) { {...thumbParams} /> - {numberFormat && ( + {tooltip && ( - {number || value} + {typeof tooltip === 'function' + ? tooltip(value) + : number || value} )} diff --git a/packages/dnb-eufemia/src/components/slider/__tests__/Slider.test.tsx b/packages/dnb-eufemia/src/components/slider/__tests__/Slider.test.tsx index eac96b92a26..464e49db471 100644 --- a/packages/dnb-eufemia/src/components/slider/__tests__/Slider.test.tsx +++ b/packages/dnb-eufemia/src/components/slider/__tests__/Slider.test.tsx @@ -9,6 +9,7 @@ import { fireEvent, render } from '@testing-library/react' import Slider from '../Slider' import type { SliderProps, onChangeEventProps } from '../Slider' +import { format } from '../../number-format/NumberUtils' const props: SliderProps = { id: 'slider', @@ -153,33 +154,72 @@ describe('Slider component', () => { ) }) - it('shows Tooltip on hover when numberFormat is given', () => { - render() + describe('Tooltip', () => { + it('shows Tooltip on hover with numberFormat', () => { + render( + + ) - const mainElem = document.querySelector('.dnb-slider') - const thumbElem = mainElem.querySelector('.dnb-slider__thumb') - const tooltipElem = thumbElem.querySelector('.dnb-tooltip') + const mainElem = document.querySelector('.dnb-slider') + const thumbElem = mainElem.querySelector('.dnb-slider__thumb') + const tooltipElem = thumbElem.querySelector('.dnb-tooltip') - expect(tooltipElem.textContent).toBe('70,00 €') - expect(Array.from(tooltipElem.classList)).toEqual( - expect.arrayContaining(['dnb-tooltip']) - ) + expect(tooltipElem.textContent).toBe('70,00 €') + expect(Array.from(tooltipElem.classList)).toEqual( + expect.arrayContaining(['dnb-tooltip']) + ) - fireEvent.mouseOver(thumbElem) + fireEvent.mouseOver(thumbElem) - simulateMouseMove({ pageX: 80, width: 100, height: 10 }) + simulateMouseMove({ pageX: 80, width: 100, height: 10 }) - expect(Array.from(tooltipElem.classList)).toEqual( - expect.arrayContaining(['dnb-tooltip', 'dnb-tooltip--active']) - ) + expect(Array.from(tooltipElem.classList)).toEqual( + expect.arrayContaining(['dnb-tooltip', 'dnb-tooltip--active']) + ) - expect(tooltipElem.textContent).toBe('80,00 €') + expect(tooltipElem.textContent).toBe('80,00 €') - fireEvent.mouseOut(thumbElem) + fireEvent.mouseOut(thumbElem) - expect(Array.from(tooltipElem.classList)).toEqual( - expect.arrayContaining(['dnb-tooltip', 'dnb-tooltip--hide']) - ) + expect(Array.from(tooltipElem.classList)).toEqual( + expect.arrayContaining(['dnb-tooltip', 'dnb-tooltip--hide']) + ) + }) + + it('shows Tooltip on hover with custom formatting', () => { + render( + format(value, { percent: true })} + step={null} + /> + ) + + const mainElem = document.querySelector('.dnb-slider') + const thumbElem = mainElem.querySelector('.dnb-slider__thumb') + const tooltipElem = thumbElem.querySelector('.dnb-tooltip') + + expect(tooltipElem.textContent).toBe('70 %') + expect(Array.from(tooltipElem.classList)).toEqual( + expect.arrayContaining(['dnb-tooltip']) + ) + + fireEvent.mouseOver(thumbElem) + + simulateMouseMove({ pageX: 80.5, width: 100, height: 10 }) + + expect(Array.from(tooltipElem.classList)).toEqual( + expect.arrayContaining(['dnb-tooltip', 'dnb-tooltip--active']) + ) + + expect(tooltipElem.textContent).toBe('80,5 %') + + fireEvent.mouseOut(thumbElem) + + expect(Array.from(tooltipElem.classList)).toEqual( + expect.arrayContaining(['dnb-tooltip', 'dnb-tooltip--hide']) + ) + }) }) it('has events that return a correct value', () => { diff --git a/packages/dnb-eufemia/src/components/slider/stories/Slider.stories.tsx b/packages/dnb-eufemia/src/components/slider/stories/Slider.stories.tsx index 0c0ecaea3ce..91561f67f2b 100644 --- a/packages/dnb-eufemia/src/components/slider/stories/Slider.stories.tsx +++ b/packages/dnb-eufemia/src/components/slider/stories/Slider.stories.tsx @@ -8,6 +8,7 @@ import { Wrapper, Box } from 'storybook-utils/helpers' import styled from '@emotion/styled' import { Slider, ToggleButton, Input, FormRow, FormLabel } from '../../' +import { format } from '../../number-format/NumberUtils' export default { title: 'Eufemia/Components/Slider', @@ -55,7 +56,8 @@ export function MultiButtons() { max={1000} step={10} stretch - numberFormat={{ decimals: 2, currency: true }} + numberFormat={{ currency: true }} + tooltip={(value) => format(value, { currency: 'USD' })} onChange={({ value, number }) => { console.log('onChange:', value, number) setValue(value as Array) @@ -109,7 +111,7 @@ const SliderStory = () => { max={100} value={value} step={0.05} - numberFormat={{ decimals: 2, currency: true }} + numberFormat={{ currency: true }} // reverse onChange={({ value, number, rawValue }) => { console.log('onChange:', { value, number, rawValue }) diff --git a/packages/dnb-eufemia/src/components/slider/types.ts b/packages/dnb-eufemia/src/components/slider/types.ts index d76ce1bc690..b01de427163 100644 --- a/packages/dnb-eufemia/src/components/slider/types.ts +++ b/packages/dnb-eufemia/src/components/slider/types.ts @@ -74,9 +74,12 @@ export type SliderProps = IncludeSnakeCase<{ /** if set to `true`, then the slider will be 100% in `width`. */ stretch?: boolean - /** Will extend the return object with a `number` property (from `onChange` event). You can use all the options from the [NumberFormat](/uilib/components/number-format/properties) component. It also will use that formatted number in the increase/decrease buttons. If it has to represent a currency, then use e.g. `numberFormat={{ currency: true, decimals: 0 }}` */ + /** will extend the return object with a `number` property (from `onChange` event). You can use all the options from the [NumberFormat](/uilib/components/number-format/properties) component. It also will use that formatted number in the increase/decrease buttons. If it has to represent a currency, then use e.g. `numberFormat={{ currency: true, decimals: 0 }}` */ numberFormat?: formatOptionParams + /** use `true` to show a tooltip on `mouseOver`, `touchStart` and `focus`, showing the current number (if `numberFormat` is given) or the raw value. You can also provide a function callback. Defaults to `null`. */ + tooltip: boolean | ((value: number) => unknown) + /** removes the helper buttons. Defaults to `false`. */ hideButtons?: boolean