zrmc
Version:
ZRMC is an ES7 React wrapper for Material Components Web.
361 lines (297 loc) • 11 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof2 = require("babel-runtime/helpers/typeof");
var _typeof3 = _interopRequireDefault(_typeof2);
var _extends2 = require("babel-runtime/helpers/extends");
var _extends3 = _interopRequireDefault(_extends2);
var _objectWithoutProperties2 = require("babel-runtime/helpers/objectWithoutProperties");
var _objectWithoutProperties3 = _interopRequireDefault(_objectWithoutProperties2);
var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = require("babel-runtime/helpers/possibleConstructorReturn");
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require("babel-runtime/helpers/inherits");
var _inherits3 = _interopRequireDefault(_inherits2);
var _react = require("react");
var _react2 = _interopRequireDefault(_react);
var _propTypes = require("prop-types");
var _propTypes2 = _interopRequireDefault(_propTypes);
var _ = require("../");
var _2 = _interopRequireDefault(_);
var _menu = require("../menu/menu");
var _menu2 = _interopRequireDefault(_menu);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* mdc-select
*
* See:
* https://material.io/develop/web/components/input-controls/select-menus/
*
*
*/
/**
* Copyright (c) 2015-present, CWB SAS
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
var MDC_SELECT = "mdc-select";
var Select = function (_Component) {
(0, _inherits3.default)(Select, _Component);
function Select(props) {
(0, _classCallCheck3.default)(this, Select);
var _this = (0, _possibleConstructorReturn3.default)(this, (Select.__proto__ || Object.getPrototypeOf(Select)).call(this, props));
_this.onBlur = function () {
_this.setState({ focused: false });
};
_this.onFocus = function () {
_this.setState({ focused: true });
};
_this.onSelect = function (selectedItem, selectedIndex) {
_this.setState({
selectedIndex: selectedIndex,
selectedDisplayValue: selectedItem.props.children
});
if (_this.props.onSelected) {
// We pass the value of the selected item to the parent.
var selectedValue = selectedItem.props.value || selectedItem.props.children;
_this.props.onSelected(selectedValue, selectedIndex);
}
};
_this.onClickOutsideHandler = function (e) {
var open = _this.state.open;
if (open && (!_this.anchorRef || !_this.anchorRef.contains(e.target)) && (!_this.menuRef || !_this.menuRef.innerRef || !_this.menuRef.innerRef.contains(e.target))) {
e.preventDefault();
_this.onClose();
}
};
_this.onClickHandler = function (e) {
e.preventDefault();
if (_this.state.open) {
_this.onClose();
} else {
_this.setState({ open: true });
_2.default.lockScroll();
}
};
_this.onClose = function () {
_this.setState({ open: false }, function () {
_2.default.unlockScroll();
if (_this.focusRef) {
_this.focusRef.focus();
}
});
};
_this.setRef = function (c) {
_this.anchorRef = c;
};
var selectedChild = _react.Children.toArray(props.children).find(function (child, index) {
return index === props.selectedIndex;
});
_this.state = {
open: false,
focused: false,
selectedDisplayValue: selectedChild ? selectedChild.props.children : null,
selectedIndex: props.selectedIndex
};
_this.ctx = null;
return _this;
}
(0, _createClass3.default)(Select, [{
key: "componentDidMount",
value: function componentDidMount() {
_2.default.enableClickOutside(this.onClickOutsideHandler);
this.updateContent();
}
}, {
key: "componentDidUpdate",
value: function componentDidUpdate() {
this.updateContent();
}
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
_2.default.disableClickOutside(this.onClickOutsideHandler);
this.ctx = null;
}
}, {
key: "calculateWidth",
value: function calculateWidth() {
var _this2 = this;
if (!this.ctx) {
this.ctx = document.createElement("canvas").getContext("2d");
}
this.ctx.font = _2.default.getFontStyle(this.anchorRef);
var letterSpacing = parseFloat(_2.default.getComputedStyleValue(this.anchorRef, "letter-spacing"));
var surfacePaddingRight = parseInt(_2.default.getComputedStyleValue(this.anchorRef, "padding-right"), 10);
var surfacePaddingLeft = parseInt(_2.default.getComputedStyleValue(this.anchorRef, "padding-left"), 10);
var selectBoxAddedPadding = surfacePaddingRight + surfacePaddingLeft;
var maxTextLength = 0;
_react.Children.forEach(this.props.children, function (child) {
if (child.props.children) {
var txt = child.props.children.trim();
var _ctx$measureText = _this2.ctx.measureText(txt),
width = _ctx$measureText.width;
var addedSpace = letterSpacing * txt.length;
maxTextLength = Math.max(maxTextLength, Math.ceil(width + addedSpace + selectBoxAddedPadding));
}
});
return maxTextLength;
}
}, {
key: "updateContent",
value: function updateContent() {
if (this.anchorRef && this.menuRef) {
var w = this.calculateWidth();
var style = void 0;
if (!(this.props.style && this.props.style.width)) {
style = "width: " + w + "px;";
this.anchorRef.style = style;
}
if (this.state.open) {
var _window = window,
innerHeight = _window.innerHeight;
var _anchorRef$getBoundin = this.anchorRef.getBoundingClientRect(),
top = _anchorRef$getBoundin.top;
var menuHeight = this.menuRef.innerRef.offsetHeight;
var itemOffsetTop = 0;
if (this.state.selectedIndex > -1 && this.menuRef.selectedRef && this.menuRef.selectedRef.innerRef) {
itemOffsetTop = this.menuRef.selectedRef.innerRef.offsetTop;
}
var adjustedLeft = 0;
var adjustedTop = 0 - itemOffsetTop;
if (top < itemOffsetTop) {
adjustedTop = -top;
} else if (top + menuHeight > innerHeight) {
adjustedTop = Math.max(0, innerHeight - menuHeight) - top;
}
style = "left: " + adjustedLeft + "px; top: " + adjustedTop + "px; transform-origin: center " + itemOffsetTop + "px;";
this.menuRef.innerRef.style = style;
}
}
}
}, {
key: "render",
value: function render() {
var _this3 = this;
var _props = this.props,
children = _props.children,
disabled = _props.disabled,
label = _props.label,
props = (0, _objectWithoutProperties3.default)(_props, ["children", "disabled", "label"]);
var _state = this.state,
open = _state.open,
focused = _state.focused,
selectedIndex = _state.selectedIndex,
selectedDisplayValue = _state.selectedDisplayValue;
var classes = MDC_SELECT;
var p = {};
var tabIndex = "0";
if (disabled) {
p["aria-disabled"] = true;
tabIndex = "-1";
}
var lc = "mdc-floating-label";
if (selectedDisplayValue) {
lc += " mdc-floating-label--float-above";
} else {
lc += " zrmc-floating-label";
}
var bc = "mdc-line-ripple";
if (focused) {
bc += " mdc-line-ripple--active";
}
/* eslint-disable jsx-a11y/no-noninteractive-tabindex */
var element = _react2.default.createElement(
"div",
(0, _extends3.default)({
className: classes,
"aria-hidden": true,
role: "listbox",
onKeyUp: function onKeyUp() {},
onClick: this.onClickHandler,
ref: this.setRef
}, p),
_react2.default.createElement(
"div",
{
className: "mdc-select__native-control",
tabIndex: tabIndex,
ref: function ref(c) {
_this3.focusRef = c;
}
},
_react2.default.createElement(
"div",
{ className: lc },
label
),
_react2.default.createElement(
"div",
{ className: "mdc-select__selected-text" },
selectedDisplayValue
),
_react2.default.createElement("div", { className: bc })
),
_react2.default.createElement(
_menu2.default,
{
open: open,
focusedIndex: selectedIndex,
className: "mdc-select__menu",
ref: function ref(c) {
_this3.menuRef = c;
},
onSelected: this.onSelect,
onClose: this.onClose
},
_react.Children.map(children, function (child) {
return _react2.default.cloneElement(child, (0, _extends3.default)({}, child.props, {
role: "option"
}));
})
)
);
/* eslint-enable jsx-a11y/no-noninteractive-tabindex */
return _2.default.render(element, props);
}
}]);
return Select;
}(_react.Component);
Select.defaultProps = {
mdcElement: MDC_SELECT,
disabled: false,
label: null,
onSelected: null,
selectedIndex: -1,
style: {}
};
var propTypeForSelectChildren = function propTypeForSelectChildren(componentName, child) {
var displayName = void 0;
if (child.type) {
displayName = child.type.displayName || child.type.name || child.type;
}
displayName = displayName || (typeof child === "undefined" ? "undefined" : (0, _typeof3.default)(child));
if (!/MenuItem/.test(displayName)) {
return new Error("Invalid child '" + displayName + "' supplied to " + componentName + ".");
}
return null;
};
Select.propTypes = {
children: _propTypes2.default.oneOfType([function (props, propName, componentName) {
return propTypeForSelectChildren(componentName, props[propName]);
}, _propTypes2.default.arrayOf(function (propValue, key, componentName) {
return propTypeForSelectChildren(componentName, propValue[key]);
})]).isRequired,
mdcElement: _propTypes2.default.string,
disabled: _propTypes2.default.bool,
label: _propTypes2.default.string,
style: _propTypes2.default.shape({ width: _propTypes2.default.string }),
onSelected: _propTypes2.default.func,
selectedIndex: _propTypes2.default.number
};
exports.default = Select;