import { html , TemplateResult } from '@spectrum-web-components/base' ; import '../sp-slider.js' ; import '../sp-slider-handle.js' ; import { Slider , SliderHandle , variants } from '../' ; import { spreadProps } from '../../../test/lit-helpers.js' ; export default { component : 'sp-slider' , title : 'Slider' , argTypes : { onInput : { action : 'input' } , onChange : { action : 'change' } , variant : { name : 'Variant' , description : 'Determines the style of slider.' , table : { type : { summary : 'string' } , defaultValue : { summary : undefined } , } , control : { type : 'inline-radio' , options : [ undefined , ... variants ] , } , } , tickStep : { name : 'Tick Step' , description : 'Tick spacing on slider.' , table : { type : { summary : 'number' } , defaultValue : { summary : 0.1 } , } , control : { type : 'number' , } , } , labelVisibility : { name : 'Label Visibility' , description : 'The labels visibily available in the UI' , table : { type : { summary : '"text" | "value" | "none" | undefined' } , defaultValue : { summary : undefined } , } , control : { type : 'text' , } , } , } , args : { variant : undefined , tickStep : 0.1 , labelVisibility : undefined , } , } ; export interface StoryArgs { variant ? : string ; tickStep ? : number ; labelVisibility ? : string ; onInput ? : ( val : string ) => void ; onChange ? : ( val : string ) => void ; [ prop ] : unknown ; } const handleEvent = ( { onInput , onChange } ) => ( event ) : void => { const { value } = event . target as Slider ; if ( onInput && event . type === 'input' ) { onInput ( value . toString ( ) ) ; } else if ( onChange && event . type === 'change' ) { onChange ( value . toString ( ) ) ; } } ; const handleHandleEvent = ( { onInput , onChange } ) => ( event ) : void => { const target = event . target as SliderHandle ; if ( target . value != null ) { if ( typeof target . value === 'object' ) { const value = JSON . stringify ( target . value , null , 2 ) ; if ( onInput && event . type === 'input' ) { onInput ( value ) ; } else if ( onChange && event . type === 'change' ) { onChange ( value ) ; } } else { const value = `${ target . name }: ${ target . value }` ; if ( onInput && event . type === 'input' ) { onInput ( value ) ; } else if ( onChange && event . type === 'change' ) { onChange ( value ) ; } } } } ; export const Default = ( args = { } ) : TemplateResult => { return html `
        <div style="width: 500px; margin: 12px 20px;">
            <sp-slider
                max="1"
                min="0"
                value=".5"
                step="0.01"
                @input=${ handleEvent ( args ) }
                @change=${ handleEvent ( args ) }
                .formatOptions=${ { style : 'percent' } }
                ...=${ spreadProps ( args ) }
            >
                Opacity
            </sp-slider>
        </div>
    ` ; } ; export const noVisibleTextLabel = ( args = { } ) : TemplateResult => { return html `
        <div style="width: 500px; margin: 12px 20px;">
            <sp-slider
                max="1"
                min="0"
                value=".5"
                step="0.01"
                @input=${ handleEvent ( args ) }
                @change=${ handleEvent ( args ) }
                .formatOptions=${ { style : 'percent' } }
                ...=${ spreadProps ( args ) }
            >
                Opacity
            </sp-slider>
        </div>
    ` ; } ; noVisibleTextLabel . args = { labelVisibility : 'value' , } ; export const noVisibleValueLabel = ( args = { } ) : TemplateResult => { return html `
        <div style="width: 500px; margin: 12px 20px;">
            <sp-slider
                max="1"
                min="0"
                value=".5"
                step="0.01"
                @input=${ handleEvent ( args ) }
                @change=${ handleEvent ( args ) }
                .formatOptions=${ { style : 'percent' } }
                ...=${ spreadProps ( args ) }
            >
                Opacity
            </sp-slider>
        </div>
    ` ; } ; noVisibleValueLabel . args = { labelVisibility : 'text' , } ; export const noVisibleLabels = ( args = { } ) : TemplateResult => { return html `
        <div style="width: 500px; margin: 12px 20px;">
            <sp-slider
                max="1"
                min="0"
                value=".5"
                step="0.01"
                @input=${ handleEvent ( args ) }
                @change=${ handleEvent ( args ) }
                .formatOptions=${ { style : 'percent' } }
                ...=${ spreadProps ( args ) }
            >
                Opacity
            </sp-slider>
        </div>
    ` ; } ; noVisibleLabels . args = { labelVisibility : 'none' , } ; export const px = ( args = { } ) : TemplateResult => { return html `
        <div style="width: 500px; margin: 12px 20px;">
            <sp-slider
                max="360"
                min="0"
                value="90"
                step="1"
                @input=${ handleEvent ( args ) }
                @change=${ handleEvent ( args ) }
                .formatOptions=${ { style : 'unit' , unit : 'px' , } }
                ...=${ spreadProps ( args ) }
            >
                Angle
            </sp-slider>
        </div>
    ` ; } ; class NumberFieldDefined extends HTMLElement { constructor ( ) { super ( ) ; this . numberFieldLoaderPromise = new Promise ( ( res ) => { customElements . whenDefined ( 'sp-number-field' ) . then ( ( ) => { res ( true ) ; } ) ; } ) ; } private numberFieldLoaderPromise : Promise < boolean > = Promise . resolve ( false ) ; get updateComplete ( ) : Promise < boolean > { return this . numberFieldLoaderPromise ; } } customElements . define ( 'number-field-defined' , NumberFieldDefined ) ; const editableDecorator = ( story ) : TemplateResult => { return html `
        ${ story ( ) }
        <number-field-defined></number-field-defined>
    ` ; } ; export const editable = ( args = { } ) : TemplateResult => { return html `
        <div style="width: 500px; margin: 12px 20px;">
            <sp-slider
                editable
                max="360"
                min="0"
                value="90"
                step="1"
                @input=${ handleEvent ( args ) }
                @change=${ handleEvent ( args ) }
                .formatOptions=${ { style : 'unit' , unit : 'degree' , unitDisplay : 'narrow' , } }
                ...=${ spreadProps ( args ) }
            >
                Angle
            </sp-slider>
        </div>
    ` ; } ; editable . decorators = [ editableDecorator ] ; export const editableDisabled = ( args = { } ) : TemplateResult => { return html `
        <div style="width: 500px; margin: 12px 20px;">
            <sp-slider
                editable
                disabled
                max="360"
                min="0"
                value="90"
                step="1"
                @input=${ handleEvent ( args ) }
                @change=${ handleEvent ( args ) }
                .formatOptions=${ { style : 'unit' , unit : 'degree' , unitDisplay : 'narrow' , } }
                ...=${ spreadProps ( args ) }
            >
                Angle
            </sp-slider>
        </div>
    ` ; } ; editable . decorators = [ editableDecorator ] ; export const editableCustom = ( args = { } ) : TemplateResult => { return html `
        <div
            style="width: 500px; margin: 12px 20px; --spectrum-slider-editable-number-field-width: 150px;"
        >
            <sp-slider
                editable
                max="24"
                min="0"
                value="12.75"
                step="0.25"
                @input=${ handleEvent ( args ) }
                @change=${ handleEvent ( args ) }
                .formatOptions=${ { style : 'unit' , unit : 'hour' } }
                ...=${ spreadProps ( args ) }
            >
                Hours
            </sp-slider>
        </div>
    ` ; } ; editableCustom . decorators = [ editableDecorator ] ; export const hideStepper = ( args = { } ) : TemplateResult => { return html `
        <div style="width: 500px; margin: 12px 20px;">
            <sp-slider
                editable
                hide-stepper
                max="1"
                min="0"
                value=".5"
                step="0.01"
                @input=${ handleEvent ( args ) }
                @change=${ handleEvent ( args ) }
                .formatOptions=${ { style : 'percent' } }
                ...=${ spreadProps ( args ) }
            >
                Opacity
            </sp-slider>
        </div>
    ` ; } ; hideStepper . decorators = [ editableDecorator ] ; export const Gradient = ( args = { } ) : TemplateResult => { return html `
        <div
            style="
                width: 500px;
                margin: 12px 20px;
                --spectrum-slider-track-color:linear-gradient(to right, red, green 100%);
                --spectrum-slider-track-color-rtl:linear-gradient(to left, red, green 100%);
            "
        >
            <sp-slider
                label="Opacity"
                max="100"
                min="0"
                value="50"
                id="opacity-slider"
                @input=${ handleEvent ( args ) }
                @change=${ handleEvent ( args ) }
                ...=${ spreadProps ( args ) }
            ></sp-slider>
        </div>
    ` ; } ; Gradient . args = { variant : undefined , } ; export const tick = ( args = { } ) : TemplateResult => { return html `
        <sp-slider
            label="Slider Label"
            variant="tick"
            min="0"
            max="92"
            ...=${ spreadProps ( args ) }
        ></sp-slider>
    ` ; } ; tick . args = { variant : 'tick' , tickStep : 5 , } ; export const Disabled = ( args = { } ) : TemplateResult => { return html `
        <div style="width: 500px; margin: 12px 20px;">
            <sp-slider
                disabled
                value="5"
                step="0.5"
                min="0"
                max="20"
                label="Intensity"
                ...=${ spreadProps ( args ) }
            ></sp-slider>
        </div>
    ` ; } ; export const ExplicitHandle = ( args = { } ) : TemplateResult => { return html `
        <div style="width: 500px; margin: 12px 20px;">
            <sp-slider
                step="0.5"
                min="0"
                max="20"
                @input=${ handleHandleEvent ( args ) }
                @change=${ handleHandleEvent ( args ) }
                ...=${ spreadProps ( args ) }
            >
                Intensity
                <sp-slider-handle slot="handle" value="5"></sp-slider-handle>
            </sp-slider>
        </div>
    ` ; } ; export const TwoHandles = ( args = { } ) : TemplateResult => { return html `
        <div style="width: 500px; margin: 12px 20px;">
            <sp-slider
                value="5"
                step="1"
                min="0"
                max="255"
                @input=${ handleHandleEvent ( args ) }
                @change=${ handleHandleEvent ( args ) }
                ...=${ spreadProps ( args ) }
            >
                Output Levels
                <sp-slider-handle
                    slot="handle"
                    name="min"
                    value="5"
                ></sp-slider-handle>
                <sp-slider-handle
                    slot="handle"
                    name="max"
                    value="250"
                ></sp-slider-handle>
            </sp-slider>
        </div>
    ` ; } ; TwoHandles . args = { variant : 'range' , tickStep : 10 , } ; export const TwoHandlesPt = ( args = { } ) : TemplateResult => { return html `
        <div style="width: 500px; margin: 12px 20px;">
            <sp-slider
                value="5"
                step="1"
                min="0"
                max="255"
                @input=${ handleHandleEvent ( args ) }
                @change=${ handleHandleEvent ( args ) }
                .formatOptions=${ { style : 'unit' , unit : 'pt' , } }
                ...=${ spreadProps ( args ) }
            >
                Output Levels
                <sp-slider-handle
                    slot="handle"
                    name="min"
                    value="5"
                ></sp-slider-handle>
                <sp-slider-handle
                    slot="handle"
                    name="max"
                    value="250"
                ></sp-slider-handle>
            </sp-slider>
        </div>
    ` ; } ; TwoHandlesPt . args = { variant : 'range' , tickStep : 10 , } ; export const ThreeHandlesPc = ( args = { } ) : TemplateResult => { return html `
        <div style="width: 500px; margin: 12px 20px;">
            <sp-slider
                value="5"
                step="1"
                min="0"
                max="255"
                @input=${ handleHandleEvent ( args ) }
                @change=${ handleHandleEvent ( args ) }
                .formatOptions=${ { style : 'unit' , unit : 'pc' , } }
                ...=${ spreadProps ( args ) }
            >
                Output Levels
                <sp-slider-handle slot="handle" value="5"></sp-slider-handle>
                <sp-slider-handle slot="handle" value="133"></sp-slider-handle>
                <sp-slider-handle slot="handle" value="250"></sp-slider-handle>
            </sp-slider>
        </div>
    ` ; } ; export const ThreeHandlesOrdered = ( args = { } ) : TemplateResult => { return html `
        <div style="width: 500px; margin: 12px 20px;">
            <sp-slider
                step="1"
                min="0"
                max="255"
                @input=${ handleHandleEvent ( args ) }
                @change=${ handleHandleEvent ( args ) }
                ...=${ spreadProps ( args ) }
            >
                Output Levels
                <sp-slider-handle
                    slot="handle"
                    name="low"
                    value="5"
                    max="next"
                ></sp-slider-handle>
                <sp-slider-handle
                    slot="handle"
                    name="mid"
                    value="100"
                    min="previous"
                    max="next"
                ></sp-slider-handle>
                <sp-slider-handle
                    slot="handle"
                    name="high"
                    value="250"
                    min="previous"
                ></sp-slider-handle>
            </sp-slider>
        </div>
    ` ; } ; ThreeHandlesOrdered . args = { tickStep : 10 , } ; export const ThreeHandlesComplex = ( args = { } ) : TemplateResult => { const values = { black : 50 , gray : 4.98 , white : 225 , } ; const handleEvent = ( { onInput , onChange } ) => ( event ) : void => { const target = event . target as SliderHandle ; if ( target . value != null ) { if ( typeof target . value === 'object' ) { const value = JSON . stringify ( target . value , null , 2 ) ; if ( onInput && event . type === 'input' ) { onInput ( value ) ; } else if ( onChange && event . type === 'change' ) { onChange ( value ) ; } } else { const value = `${ target . name }: ${ target . value }` ; if ( onInput && event . type === 'input' ) { onInput ( value ) ; } else if ( onChange && event . type === 'change' ) { onChange ( value ) ; } } values [ target . name ] = target . value ; } } ; const grayNormalization = { toNormalized ( value ) { const normalizedBlack = values . black / 255 ; const normalizedWhite = values . white / 255 ; const clamped = Math . max ( Math . min ( value , 1 ) , 0 ) ; return ( clamped * ( normalizedWhite - normalizedBlack ) + normalizedBlack ) ; } , fromNormalized ( value ) { const normalizedBlack = values . black / 255 ; const normalizedWhite = values . white / 255 ; const clamped = Math . max ( Math . min ( value , normalizedWhite ) , normalizedBlack ) ; return ( ( clamped - normalizedBlack ) / ( normalizedWhite - normalizedBlack ) ) ; } , } ; const blackNormalization = { toNormalized ( value ) { const clamped = Math . min ( value , values . white ) ; return clamped / 255 ; } , fromNormalized ( value ) { const denormalized = value * 255 ; return Math . min ( denormalized , values . white ) ; } , } ; const whiteNormalization = { toNormalized ( value ) { const clamped = Math . max ( value , values . black ) ; return clamped / 255 ; } , fromNormalized ( value ) { const denormalized = value * 255 ; return Math . max ( denormalized , values . black ) ; } , } ; const computeGray = ( value ) : string => { let result = 1.0 ; if ( value > 0.5 ) { result = Math . max ( 2 * ( 1 - value ) , 0.01 ) ; } else if ( value < 0.5 ) { result = ( ( 1 - 2 * value ) * ( Math . sqrt ( 9.99 ) - 1 ) + 1 ) ** 2 ; } const formatOptions = { maximumFractionDigits : 2 , minimumFractionDigits : 2 , } ; return new Intl . NumberFormat ( navigator . language , formatOptions ) . format ( result ) ; } ; return html `
        <div style="width: 500px; margin: 12px 20px;">
            <sp-slider
                step="1"
                min="0"
                max="255"
                @input=${ handleEvent }
                @change=${ handleEvent }
                ...=${ spreadProps ( args ) }
            >
                Output Levels
                <sp-slider-handle
                    slot="handle"
                    name="black"
                    value=${ values . black }
                    .normalization=${ blackNormalization }
                ></sp-slider-handle>
                <sp-slider-handle
                    slot="handle"
                    name="gray"
                    value="0.215"
                    min="0"
                    max="1"
                    step="0.005"
                    .normalization=${ grayNormalization }
                    .getAriaHandleText=${ computeGray }
                ></sp-slider-handle>
                <sp-slider-handle
                    slot="handle"
                    name="white"
                    value=${ values . white }
                    .normalization=${ whiteNormalization }
                ></sp-slider-handle>
            </sp-slider>
        </div>
    ` ; } ; ThreeHandlesOrdered . args = { tickStep : 10 , } ; export const focusTabDemo = ( args = { } ) : TemplateResult => { const value = 50 ; const min = 0 ; const max = 100 ; const step = 1 ; return html `
        <div style="width: 500px; margin: 12px 20px 20px;">
            <sp-slider
                value="${ value }"
                step="${ step }"
                min="${ min }"
                max="${ max }"
                label="Opacity"
                id="opacity-slider-opacity"
                ...=${ spreadProps ( args ) }
            ></sp-slider>
        </div>
        <div style="width: 500px; margin: 20px;">
            <sp-slider
                value="${ value }"
                step="${ step }"
                min="${ min }"
                max="${ max }"
                label="Lightness"
                id="opacity-slider-lightness"
                ...=${ spreadProps ( args ) }
            ></sp-slider>
        </div>
        <div style="width: 500px; margin: 20px 20px 12px;">
            <sp-slider
                value="${ value }"
                step="${ step }"
                min="${ min }"
                max="${ max }"
                label="Saturation"
                id="opacity-slider-saturation"
                ...=${ spreadProps ( args ) }
            ></sp-slider>
        </div>
    ` ; } ;