diff --git a/src/components/views/elements/AccessibleButton.js b/src/components/views/elements/AccessibleButton.tsx similarity index 71% rename from src/components/views/elements/AccessibleButton.js rename to src/components/views/elements/AccessibleButton.tsx index d708a44ab2..f35cd52734 100644 --- a/src/components/views/elements/AccessibleButton.js +++ b/src/components/views/elements/AccessibleButton.tsx @@ -15,7 +15,6 @@ */ import React from 'react'; -import PropTypes from 'prop-types'; import {Key} from '../../../Keyboard'; @@ -27,11 +26,20 @@ import {Key} from '../../../Keyboard'; * @param {Object} props react element properties * @returns {Object} rendered react */ -export default function AccessibleButton(props) { - const {element, onClick, children, kind, disabled, ...restProps} = props; +export default function AccessibleButton({ + element, + onClick, + children, + kind, + disabled, + inputRef, + className, + ...restProps +}: IProps) { + const newProps: IAccessibleButtonProps = restProps; if (!disabled) { - restProps.onClick = onClick; + newProps.onClick = onClick, // We need to consume enter onKeyDown and space onKeyUp // otherwise we are risking also activating other keyboard focusable elements // that might receive focus as a result of the AccessibleButtonClick action @@ -39,7 +47,7 @@ export default function AccessibleButton(props) { // And divs which we report as role button to assistive technologies. // Browsers handle space and enter keypresses differently and we are only adjusting to the // inconsistencies here - restProps.onKeyDown = function(e) { + newProps.onKeyDown = (e) => { if (e.key === Key.ENTER) { e.stopPropagation(); e.preventDefault(); @@ -49,8 +57,8 @@ export default function AccessibleButton(props) { e.stopPropagation(); e.preventDefault(); } - }; - restProps.onKeyUp = function(e) { + }, + newProps.onKeyUp = (e) => { if (e.key === Key.SPACE) { e.stopPropagation(); e.preventDefault(); @@ -60,26 +68,26 @@ export default function AccessibleButton(props) { e.stopPropagation(); e.preventDefault(); } - }; + } } // Pass through the ref - used for keyboard shortcut access to some buttons - restProps.ref = restProps.inputRef; - delete restProps.inputRef; + newProps.ref = inputRef; - restProps.className = (restProps.className ? restProps.className + " " : "") + "mx_AccessibleButton"; + newProps.className = (className ? className + " " : "") + "mx_AccessibleButton"; if (kind) { // We apply a hasKind class to maintain backwards compatibility with // buttons which might not know about kind and break - restProps.className += " mx_AccessibleButton_hasKind mx_AccessibleButton_kind_" + kind; + newProps.className += " mx_AccessibleButton_hasKind mx_AccessibleButton_kind_" + kind; } if (disabled) { - restProps.className += " mx_AccessibleButton_disabled"; - restProps["aria-disabled"] = true; + newProps.className += " mx_AccessibleButton_disabled"; + newProps["aria-disabled"] = true; } + // React.createElement expects InputHTMLAttributes return React.createElement(element, restProps, children); } @@ -89,28 +97,25 @@ export default function AccessibleButton(props) { * onClick: (required) Event handler for button activation. Should be * implemented exactly like a normal onClick handler. */ -AccessibleButton.propTypes = { - children: PropTypes.node, - inputRef: PropTypes.oneOfType([ - // Either a function - PropTypes.func, - // Or the instance of a DOM native element - PropTypes.shape({ current: PropTypes.instanceOf(Element) }), - ]), - element: PropTypes.string, - onClick: PropTypes.func.isRequired, - +interface IProps extends React.InputHTMLAttributes { + inputRef?: React.Ref, + element?: string; // The kind of button, similar to how Bootstrap works. // See available classes for AccessibleButton for options. - kind: PropTypes.string, + kind?: string, // The ARIA role - role: PropTypes.string, + role?: string, // The tabIndex - tabIndex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), - - disabled: PropTypes.bool, + tabIndex?: number, + disabled?: boolean, + className?: string, + onClick(e?: React.MouseEvent | React.KeyboardEvent): void; }; +interface IAccessibleButtonProps extends React.InputHTMLAttributes { + ref?: React.Ref, +} + AccessibleButton.defaultProps = { element: 'div', role: 'button', diff --git a/src/components/views/elements/SettingsFlag.js b/src/components/views/elements/SettingsFlag.tsx similarity index 54% rename from src/components/views/elements/SettingsFlag.js rename to src/components/views/elements/SettingsFlag.tsx index 15f17805a8..2ae9bc3d87 100644 --- a/src/components/views/elements/SettingsFlag.js +++ b/src/components/views/elements/SettingsFlag.tsx @@ -21,58 +21,76 @@ import createReactClass from 'create-react-class'; import SettingsStore from "../../../settings/SettingsStore"; import { _t } from '../../../languageHandler'; import ToggleSwitch from "./ToggleSwitch"; +import StyledCheckbox from "./StyledCheckbox"; -export default createReactClass({ - displayName: 'SettingsFlag', - propTypes: { - name: PropTypes.string.isRequired, - level: PropTypes.string.isRequired, - roomId: PropTypes.string, // for per-room settings - label: PropTypes.string, // untranslated - onChange: PropTypes.func, - isExplicit: PropTypes.bool, - }, +interface IProps { + name: string, + level: string, + roomId?: string, // for per-room settings + label?: string, // untranslated + isExplicit: boolean, + // XXX: once design replaces all toggles make this the default + useCheckbox?: boolean, + onChange(checked: boolean): void, +} - getInitialState: function() { - return { +interface IState { + // XXX: make this generic when the settings store is typed + value: any; +} + +export default class SettingsFlag extends React.Component { + + constructor(props: IProps) { + super(props); + + this.state = { value: SettingsStore.getValueAt( this.props.level, this.props.name, this.props.roomId, this.props.isExplicit, ), - }; - }, - - onChange: function(checked) { - if (this.props.group && !checked) return; + } + } + private onChange = (checked: boolean): void => { this.save(checked); this.setState({ value: checked }); if (this.props.onChange) this.props.onChange(checked); - }, + } - save: function(val = undefined) { + private checkBoxOnChange = (e: React.ChangeEvent) => { + this.onChange(e.target.checked); + } + + private save = (val?: any): void => { return SettingsStore.setValue( this.props.name, this.props.roomId, this.props.level, val !== undefined ? val : this.state.value, ); - }, + } - render: function() { + public render() { const canChange = SettingsStore.canSetValue(this.props.name, this.props.roomId, this.props.level); let label = this.props.label; if (!label) label = SettingsStore.getDisplayName(this.props.name, this.props.level); else label = _t(label); - return ( -
- {label} - -
- ); - }, -}); + if (this.props.useCheckbox) { + return + {label} + ; + } else { + return ( +
+ {label} + +
+ ); + } + } +} diff --git a/src/components/views/elements/ToggleSwitch.js b/src/components/views/elements/ToggleSwitch.tsx similarity index 82% rename from src/components/views/elements/ToggleSwitch.js rename to src/components/views/elements/ToggleSwitch.tsx index bea1a85555..4cb2fa1ef1 100644 --- a/src/components/views/elements/ToggleSwitch.js +++ b/src/components/views/elements/ToggleSwitch.tsx @@ -15,14 +15,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from "react"; -import PropTypes from "prop-types"; +import React, { EventHandler } from "react"; import classNames from "classnames"; import * as sdk from "../../../index"; // Controlled Toggle Switch element, written with Accessibility in mind -const ToggleSwitch = ({checked, disabled=false, onChange, ...props}) => { - const _onClick = (e) => { +export default ({checked, disabled=false, onChange, ...props}: IProps) => { + const _onClick = () => { if (disabled) return; onChange(!checked); }; @@ -47,15 +46,13 @@ const ToggleSwitch = ({checked, disabled=false, onChange, ...props}) => { ); }; -ToggleSwitch.propTypes = { +interface IProps { // Whether or not this toggle is in the 'on' position. - checked: PropTypes.bool.isRequired, + checked: boolean, // Whether or not the user can interact with the switch - disabled: PropTypes.bool, + disabled: boolean, // Called when the checked state changes. First argument will be the new state. - onChange: PropTypes.func.isRequired, + onChange(checked: boolean): void, }; - -export default ToggleSwitch;