src/button-group/stateful-container.ts (64 lines of code) (raw):

/* Copyright (c) Uber Technologies, Inc. This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. */ import * as React from 'react'; import { MODE, STATE_CHANGE_TYPE } from './constants'; import type { StatefulContainerProps, State } from './types'; import type { SyntheticEvent } from 'react'; // handles the case where selected = 0 // @ts-ignore function isSelectedDefined(selected) { return Array.isArray(selected) || typeof selected === 'number'; } function defaultStateReducer( type: (typeof STATE_CHANGE_TYPE)[keyof typeof STATE_CHANGE_TYPE], nextState: State, // eslint-disable-next-line @typescript-eslint/no-unused-vars currentState: State ) { return nextState; } export default class StatefulContainer extends React.Component<StatefulContainerProps, State> { static defaultProps = { // @ts-ignore initialState: { selected: [] }, stateReducer: defaultStateReducer, }; constructor(props: StatefulContainerProps) { super(props); const { initialState = {} as State } = props; const { selected = [] } = initialState; this.state = { // @ts-ignore selected: isSelectedDefined(selected) ? [].concat(selected) : [], }; } changeState = (nextState: State) => { if (this.props.stateReducer) { this.setState(this.props.stateReducer(STATE_CHANGE_TYPE.change, nextState, this.state)); } else { this.setState(nextState); } }; onClick = (event: SyntheticEvent<HTMLButtonElement>, index: number) => { if (this.props.mode === MODE.radio) { if (this.state.selected.length === 0 || this.state.selected[0] !== index) { this.changeState({ selected: [index] }); } else { this.changeState({ selected: [] }); } } if (this.props.mode === MODE.checkbox) { if (!this.state.selected.includes(index)) { this.changeState({ selected: [...this.state.selected, index] }); } else { this.changeState({ selected: this.state.selected.filter((value) => value !== index), }); } } if (this.props.onClick) { this.props.onClick(event, index); } }; render() { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { initialState, stateReducer, ...props } = this.props; return this.props.children({ ...props, onClick: this.onClick, selected: this.state.selected, }); } }