UNPKG

wix-style-react

Version:
168 lines (165 loc) 5.92 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.withFocusable = withFocusable; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _react = _interopRequireDefault(require("react")); var _hoistNonReactMethods = _interopRequireDefault(require("hoist-non-react-methods")); var _FocusableSt = require("./Focusable.st.css"); var _hocUtils = require("../hocUtils"); var _jsxFileName = "/home/builduser/work/a9c1ac8876d5057c/packages/wix-style-react/dist/cjs/common/Focusable/Focusable.tsx"; /** * Assigned the given propTypes to the given class. * * This is a hack because since Yoshi3, with babel-preset-yoshi, * the babel-plugin-transform-react-remove-prop-types is enabled and removes propTypes. * * So if we simply do Focusable.propTypes = Component.propTypes, it is being stripped away. * * This later becomes a problem if another component defines: * <code> * Comp.propTypes = { * prop1: SomeFocusableComp.propTypes.prop1 * } * </code> */ var assignPropTypesHack = (target, propTypes) => { target.propTypes = propTypes; }; /** * Singleton for managing current input method (keyboard or mouse). */ var inputMethod = new class { constructor() { // Default is keyboard in case an element is focused programmatically. this.method = 'keyboard'; this.subscribers = new Map(); this.subscribe = (target, callback) => this.subscribers.set(target, callback); this.unsubscribe = target => this.subscribers.delete(target); /** * Is the current input method `keyboard`. if `false` is means it is `mouse` */ this.isKeyboard = () => this.method === 'keyboard'; if (typeof window !== 'undefined') { window.addEventListener('mousedown', () => this.setMethod('mouse')); window.addEventListener('keydown', () => this.setMethod('keyboard')); // We need to listen on keyUp, in case a TAB is made from the browser's address-bar, // so the keyDown is not fired, only the keyUp. window.addEventListener('keyup', () => this.setMethod('keyboard')); } } setMethod(method) { if (method !== this.method) { this.method = method; this.subscribers.forEach(f => f()); } } }(); /* * TODO: Consider adding 'disabled' state to this HOC, since: * - When component is focused and then it becomes disabled, then the focus needs to be blured. * * TODO: Consider using [Recompose](https://github.com/acdlite/recompose/tree/master/src/packages/recompose) to do: * - the static hoisting * - set displayName */ function withFocusable(Component) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; class Focusable extends _react.default.Component { constructor() { super(...arguments); this.wrappedComponentRef = null; this.state = { focus: false, focusVisible: false }; this.focus = () => { var _this$wrappedComponen; if ((_this$wrappedComponen = this.wrappedComponentRef) != null && _this$wrappedComponen.focus) { this.wrappedComponentRef.focus(); } }; this.markAsFocused = () => { this.setState({ focus: true, focusVisible: options.isFocusWithMouse || inputMethod.isKeyboard() }); inputMethod.subscribe(this, () => { if (options.isFocusWithMouse || inputMethod.isKeyboard()) { this.setState({ focusVisible: true }); } }); }; this.markAsBlurred = () => { inputMethod.unsubscribe(this); this.setState({ focus: false, focusVisible: false }); }; this.onFocus = event => { var { onFocus } = this.props; onFocus ? onFocus(event, { blur: this.markAsBlurred, focus: this.markAsFocused }) : this.markAsFocused(); }; this.onBlur = event => { var { onBlur } = this.props; onBlur ? onBlur(event, { blur: this.markAsBlurred, focus: this.markAsFocused }) : this.markAsBlurred(); }; } componentWillUnmount() { inputMethod.unsubscribe(this); } componentDidUpdate(prevProps) { /* in case when button was focused and then become disabled, we need to trigger blur logic and remove all listers, as disabled button do not trigger onFocus and onBlur events */ var isFocused = this.state.focus || this.state.focusVisible; var isBecomeDisabled = !prevProps.disabled && this.props.disabled; if (isFocused && isBecomeDisabled) { this.onBlur({}); } } render() { var reference = (0, _hocUtils.isStatelessComponent)(Component) ? undefined : ref => { this.wrappedComponentRef = ref; }; return /*#__PURE__*/_react.default.createElement(Component, (0, _extends2.default)({}, this.props, { ref: reference, focusableOnFocus: this.onFocus, focusableOnBlur: this.onBlur, className: (0, _FocusableSt.st)(_FocusableSt.classes.root, { focus: this.state.focus, 'focus-visible': this.state.focusVisible }, this.props.className), __self: this, __source: { fileName: _jsxFileName, lineNumber: 181, columnNumber: 9 } })); } } Focusable.displayName = (0, _hocUtils.getDisplayName)(Component); Focusable.defaultProps = Component.defaultProps; assignPropTypesHack(Focusable, Component.propTypes); return (0, _hocUtils.isStatelessComponent)(Component) ? Focusable : (0, _hoistNonReactMethods.default)(Focusable, Component, { delegateTo: c => c.wrappedComponentRef, hoistStatics: true }); } //# sourceMappingURL=Focusable.js.map