wix-style-react
Version:
wix-style-react
168 lines (165 loc) • 5.92 kB
JavaScript
"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