packageDocumentation module import "./SliderEditor.scss" ; import classnames from "classnames" ; import * as React from "react" ; import { PropertyEditorParams , PropertyEditorParamTypes , PropertyValue , PropertyValueFormat , SliderEditorParams , StandardEditorNames , StandardTypeNames , } from "@itwin/appui-abstract" ; import { Icon } from "@itwin/core-react" ; import { Slider , TooltipProps } from "@itwin/itwinui-react" ; import { PropertyEditorProps , TypeEditor } from "./EditorContainer" ; import { PropertyEditorBase , PropertyEditorManager } from "./PropertyEditorManager" ; import { PopupButton , PopupContent , PopupOkCancelButtons } from "./PopupButton" ; internal interface SliderEditorState { value : number ; isDisabled ? : boolean ; min : number ; max : number ; size ? : number ; step ? : number ; showTooltip ? : boolean ; tooltipBelow ? : boolean ; formatTooltip ? : ( value : number ) => string ; thumbMode ? : "allow-crossing" | "inhibit-crossing" ; trackDisplayMode ? : "auto" | "none" | "odd-segments" | "even-segments" ; minLabel ? : React . ReactNode ; maxLabel ? : React . ReactNode ; tickLabels ? : React . ReactNode ; } public export class SliderEditor extends React . PureComponent < PropertyEditorProps , SliderEditorState > implements TypeEditor { private _isMounted = false ; private _enterKey = false ; private _divElement = React . createRef < HTMLDivElement > ( ) ; internal public override readonly state : Readonly < SliderEditorState > = { value : 0 , min : 0 , max : 100 } ; public async getPropertyValue ( ) { const record = this . props . propertyRecord ; let propertyValue ; if ( record && record . value . valueFormat === PropertyValueFormat . Primitive ) { propertyValue = { valueFormat : PropertyValueFormat . Primitive , value : this . state . value , displayValue : "" } ; } return propertyValue ; } public get htmlElement ( ) : HTMLElement | null { return this . _divElement . current ; } public get hasFocus ( ) : boolean { let containsFocus = false ; if ( this . htmlElement ) containsFocus = this . htmlElement . contains ( document . activeElement ) ; return containsFocus ; } private _handleChange = ( values ) : void => { const newValue = values [ 0 ] ; if ( this . _isMounted ) this . setState ( { value : newValue } ) ; } ; internal public override componentDidMount ( ) { this . _isMounted = true ; this . setStateFromProps ( ) ; } internal public override componentWillUnmount ( ) { this . _isMounted = false ; } internal public override componentDidUpdate ( prevProps ) { if ( this . props . propertyRecord !== prevProps . propertyRecord ) { this . setStateFromProps ( ) ; } } private internalFormatTooltip = ( value , step = 1 ) => { if ( Number . isInteger ( step ) ) return value . toFixed ( 0 ) ; const stepString = step . toString ( ) ; const decimalIndex = stepString . indexOf ( "." ) ; const numDecimals = step . toString ( ) . length - ( decimalIndex + 1 ) ; return value . toFixed ( numDecimals ) ; } ; private async setStateFromProps ( ) { const record = this . props . propertyRecord ; let initialValue = 0 ; if ( record && record . value . valueFormat === PropertyValueFormat . Primitive ) { initialValue = record . value . value as number ; } let size ; let min = 0 ; let max = 100 ; let step ; let showTooltip ; let tooltipBelow ; let formatTooltip ; let tickLabels ; let minLabel ; let maxLabel ; let trackDisplayMode ; let thumbMode ; const isDisabled = record ? record . isDisabled : undefined ; if ( record && record . property && record . property . editor && record . property . editor . params ) { const sliderParams = record . property . editor . params . find ( ( param ) => param . type === PropertyEditorParamTypes . Slider ) as SliderEditorParams ; if ( sliderParams ) { min = sliderParams . minimum ; max = sliderParams . maximum ; size = sliderParams . size ; step = sliderParams . step ; thumbMode = 1 === sliderParams . mode ? "allow-crossing" : "inhibit-crossing" ; trackDisplayMode = ! sliderParams . reversed ? "auto" : "odd-segments" ; showTooltip = sliderParams . showTooltip ; tooltipBelow = sliderParams . tooltipBelow ; formatTooltip = sliderParams . formatTooltip ; minLabel = ! sliderParams . showMinMax ? "" : sliderParams . minIconSpec ? < Icon iconSpec = { sliderParams . minIconSpec } /> : undefined; maxLabel = ! sliderParams . showMinMax ? "" : sliderParams . maxIconSpec ? < Icon iconSpec = { sliderParams . maxIconSpec } /> : undefined; if ( sliderParams . showTicks ) { const count = sliderParams . getTickCount ? sliderParams . getTickCount ( ) : 0 ; if ( count ) { tickLabels = [ ] ; const increment = ( max - min ) / count ; for ( let i = 0 ; i <= count ; i ++ ) { const value = ( i * increment ) + min ; if ( sliderParams . showTickLabels ) { const label = sliderParams . formatTick ? sliderParams . formatTick ( value ) : this . internalFormatTooltip ( value , step ) ; tickLabels . push ( label ) ; } else { tickLabels . push ( "" ) ; } } } else if ( sliderParams . getTickValues ) { tickLabels = sliderParams . getTickValues ( ) . map ( ( val ) => sliderParams . formatTick ? sliderParams . formatTick ( val ) : this . internalFormatTooltip ( val , step ) ) ; } } } } if ( this . _isMounted ) this . setState ( { value : initialValue , isDisabled , size , min , max , step , trackDisplayMode , showTooltip , tooltipBelow , formatTooltip , minLabel , maxLabel , tickLabels , thumbMode } ) ; } private _handleEnter = async ( ) : Promise < void > => { this . _enterKey = true ; await this . _handleCommit ( ) ; } ; private _handleClose = async ( ) : Promise < void > => { if ( this . _enterKey ) { this . _enterKey = false ; } else { if ( this . props . onCancel ) this . props . onCancel ( ) ; } } ; private _handleOk = async ( _event ) : Promise < void > => { await this . _handleCommit ( ) ; } ; private _handleCancel = ( _event ) : void => { if ( this . props . onCancel ) { this . props . onCancel ( ) ; } } ; private _handleCommit = async ( ) : Promise < void > => { if ( this . props . propertyRecord && this . props . onCommit ) { const propertyValue = await this . getPropertyValue ( ) ; if ( propertyValue !== undefined ) { this . props . onCommit ( { propertyRecord : this . props . propertyRecord , newValue : propertyValue } ) ; } } } ; private tooltipProps = ( _index , val ) => { const content = this . state . formatTooltip ? this . state . formatTooltip ( val ) : this . internalFormatTooltip ( val , this . state . step ) ; return { placement : this . state . tooltipBelow ? "bottom" : "top" , content , visible : this . state . showTooltip } as Partial < Omit < TooltipProps , "children" > > ; } ; internal public override render ( ) { const className = classnames ( "components-cell-editor" , "components-slider-editor" , this . props . className ) ; const minSize = this . state . size ? this . state . size : 100 ; const style = { ... this . props . style , minWidth : `${ minSize }px` } ; const popupContent = ( < Slider className = "components-slider-editor-slider" style = { style } values = { [ this . state . value ] } min = { this . state . min } max = { this . state . max } step = { this . state . step } thumbMode = { this . state . thumbMode } trackDisplayMode = { this . state . trackDisplayMode } disabled = { this . state . isDisabled } minLabel = { this . state . minLabel } maxLabel = { this . state . maxLabel } tooltipProps = { this . tooltipProps } tickLabels = { this . state . tickLabels } onChange = { this . _handleChange } / > ) ; return ( < div className = { className } ref = { this . _divElement } > < PopupButton label = { this . state . value } onClose = { this . _handleClose } onEnter = { this . _handleEnter } setFocus = { this . props . setFocus } focusTarget = ".core-slider-handle" > < PopupContent > { popupContent } < PopupOkCancelButtons onOk = { this . _handleOk } onCancel = { this . _handleCancel } / > < /PopupContent> < /PopupButton> < /div>); } } public export class SliderPropertyEditor extends PropertyEditorBase { public get reactNode ( ) : React . ReactNode { return < SliderEditor />; } } PropertyEditorManager . registerEditor ( StandardTypeNames . Number , SliderPropertyEditor , StandardEditorNames . Slider ) ; PropertyEditorManager . registerEditor ( StandardTypeNames . Int , SliderPropertyEditor , StandardEditorNames . Slider ) ; PropertyEditorManager . registerEditor ( StandardTypeNames . Float , SliderPropertyEditor , StandardEditorNames . Slider ) ; PropertyEditorManager . registerEditor ( StandardTypeNames . Double , SliderPropertyEditor , StandardEditorNames . Slider ) ;