Socket
Socket
Sign inDemoInstall

@hig/tabs

Package Overview
Dependencies
Maintainers
4
Versions
125
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@hig/tabs - npm Package Compare versions

Comparing version 0.2.0-alpha.fbb1eed0 to 1.0.0

CHANGELOG.md

759

build/index.es.js

@@ -1,7 +0,758 @@

import { Tabs, Tab } from 'hig-react';
import memoize from 'lodash.memoize';
import React, { Component, Children } from 'react';
import { css } from 'emotion';
import PropTypes from 'prop-types';
import ThemeContext from '@hig/theme-context';
import Typography from '@hig/typography';
import { ControlBehavior } from '@hig/behaviors';
import Fragment from 'render-fragment';
import { polyfill } from 'react-lifecycles-compat';
Tabs.displayName = "Tabs";
function _toConsumableArray(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) {
arr2[i] = arr[i];
}return arr2;
} else {
return Array.from(arr);
}
}
Tab.displayName = "Tab";
/**
* @typedef {Object} ButtonEventHandlers
* @property {function(MouseEvent, ...any): void} handleClick
* @property {function(KeyboardEvent, ...any): void} handleKeyDown
*/
export { Tabs, Tab };
/**
* @typedef {Object} Options
* @property {boolean} [preventDefault]
*/
var KEYBOARD_INTERACTIONS = [" ", "Enter"];
/**
* Create event handlers for native button behavior for non-button elements
* @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/button_role
*
* @param {function(MouseEvent|KeyboardEvent, ...any): void} [handler] the event handler function
* @param {Options} [options]
* @returns {ButtonEventHandlers}
*/
function createButtonEventHandlers(handler) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (!handler) return {};
var _options$preventDefau = options.preventDefault,
preventDefault = _options$preventDefau === undefined ? true : _options$preventDefau;
return {
handleClick: handler,
handleKeyDown: function handleKeyDown(event) {
var key = event.key;
if (!KEYBOARD_INTERACTIONS.includes(key)) return;
// Prevent space key default scrolling behavior
if (preventDefault) event.preventDefault();
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
handler.apply(undefined, [event].concat(_toConsumableArray(args)));
}
};
}
var alignments = Object.freeze({
LEFT: "left",
CENTER: "center",
RIGHT: "right"
});
var AVAILABLE_ALIGNMENTS = Object.freeze(Object.values(alignments));
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function stylesheet(_ref, themeData) {
var _justifyContent;
var align = _ref.align;
var justifyContent = (_justifyContent = {}, _defineProperty(_justifyContent, alignments.LEFT, "flex-start"), _defineProperty(_justifyContent, alignments.CENTER, "center"), _defineProperty(_justifyContent, alignments.RIGHT, "flex-end"), _justifyContent);
return {
tabs: {
boxSizing: "border-box",
flexGrow: 1,
display: "flex",
padding: themeData["density.spacings.extraExtraSmall"] + " 0 " + themeData["density.spacings.extraSmall"] + " 0",
margin: 0,
justifyContent: justifyContent[align]
}
};
}
function TabsPresenter(_ref) {
var align = _ref.align,
children = _ref.children;
return React.createElement(
ThemeContext.Consumer,
null,
function (_ref2) {
var resolvedRoles = _ref2.resolvedRoles;
var styles = stylesheet({ align: align }, resolvedRoles);
return React.createElement(
"ul",
{ className: css(styles.tabs) },
children
);
}
);
}
TabsPresenter.propTypes = {
align: PropTypes.oneOf(AVAILABLE_ALIGNMENTS),
children: PropTypes.node
};
TabsPresenter.defaultProps = {
align: alignments.CENTER
};
TabsPresenter.__docgenInfo = {
"description": "",
"displayName": "TabsPresenter",
"props": {
"align": {
"type": {
"name": "enum",
"computed": true,
"value": "AVAILABLE_ALIGNMENTS"
},
"required": false,
"description": "",
"defaultValue": {
"value": "alignments.CENTER",
"computed": true
}
},
"children": {
"type": {
"name": "node"
},
"required": false,
"description": ""
}
}
};
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
function stylesheet$1(_ref, themeData) {
var active = _ref.active,
hasFocus = _ref.hasFocus,
hasHover = _ref.hasHover,
label = _ref.label;
return {
tab: {
position: "relative",
display: "flex",
alignContent: "center",
justifyContent: "center",
padding: "0 " + themeData["density.spacings.small"],
margin: 0,
cursor: "pointer",
userSelect: "none",
textAlign: "center",
borderBottom: themeData["tabs.general.borderBottomWidth"] + " solid " + themeData["tabs.general.borderBottomColor"],
"&:first-of-type": {
paddingLeft: 0
},
"&:last-of-type": {
paddingRight: 0
},
"&:before": _extends({
position: "absolute",
content: "''",
bottom: "-" + themeData["tabs.general.borderBottomWidth"],
left: themeData["density.spacings.small"],
width: "calc(100% - (2 * " + themeData["density.spacings.small"] + "))",
borderBottomColor: "transparent",
borderBottomStyle: "solid",
borderBottomWidth: 0
}, hasHover && {
borderBottomColor: themeData["tabs.general.tab.hover.borderBottomColor"],
borderBottomWidth: themeData["tabs.general.tab.hover.borderBottomWidth"]
}, active && {
borderBottomColor: themeData["tabs.general.tab.selected.borderBottomColor"],
borderBottomWidth: themeData["tabs.general.tab.selected.borderBottomWidth"]
}),
"&:first-of-type:before": {
left: 0,
width: "calc(100% - " + themeData["density.spacings.small"] + ")"
},
"&:last-of-type:before": {
width: "calc(100% - " + themeData["density.spacings.small"] + ")"
},
"&:after": _extends({
position: "absolute",
content: "''",
bottom: "-" + themeData["tabs.general.tab.focus.halo.width"],
left: themeData["density.spacings.small"],
width: "calc(100% - (2 * " + themeData["density.spacings.small"] + "))"
}, hasFocus && {
borderBottom: themeData["tabs.general.tab.focus.halo.width"] + " solid " + themeData["tabs.general.tab.focus.halo.color"]
}),
"&:first-of-type:after": {
left: 0,
width: "calc(100% - " + themeData["density.spacings.small"] + ")"
},
"&:last-of-type:after": {
width: "calc(100% - " + themeData["density.spacings.small"] + ")"
}
},
tabLabel: _extends({
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
padding: themeData["tabs.general.gutter"] + " 0",
"&:focus": {
outline: "none"
}
}, label && {
"&:before": {
display: "block",
content: "\"" + label + "\"",
fontFamily: themeData["tabs.general.tab.fontFamily"],
fontSize: themeData["tabs.general.tab.fontSize"],
fontWeight: themeData["tabs.general.tab.selected.fontWeight"],
height: "0",
color: "transparent",
overflow: "hidden",
visibility: "hidden"
}
}),
tabLabelText: _extends({
fontSize: themeData["tabs.general.tab.fontSize"]
}, active && {
fontWeight: themeData["tabs.general.tab.selected.fontWeight"]
})
};
}
/**
* @typedef {Object} TabPresenterProps
* @property {boolean} [active]
* @property {string} label
* @property {Function} [onClick]
* @property {Function} [onKeyDown]
*/
/**
* @param {TabPresenterProps} props
* @returns {JSX.Element}
*/
function TabPresenter(_ref) {
var active = _ref.active,
hasFocus = _ref.hasFocus,
hasHover = _ref.hasHover,
label = _ref.label,
onBlur = _ref.onBlur,
onFocus = _ref.onFocus,
onClick = _ref.onClick,
onKeyDown = _ref.onKeyDown,
onMouseEnter = _ref.onMouseEnter,
onMouseLeave = _ref.onMouseLeave;
return React.createElement(
ThemeContext.Consumer,
null,
function (_ref2) {
var resolvedRoles = _ref2.resolvedRoles;
var styles = stylesheet$1({ active: active, hasFocus: hasFocus, hasHover: hasHover, label: label }, resolvedRoles);
return React.createElement(
"li",
{ className: css(styles.tab) },
React.createElement(
"div",
{
onBlur: onBlur,
onFocus: onFocus,
onClick: onClick,
onKeyDown: onKeyDown,
onMouseEnter: onMouseEnter,
onMouseLeave: onMouseLeave,
role: "button",
tabIndex: "0",
className: css(styles.tabLabel)
},
React.createElement(
Typography,
{ style: styles.tabLabelText },
label
)
)
);
}
);
}
TabPresenter.propTypes = {
active: PropTypes.bool,
label: PropTypes.string,
hasFocus: PropTypes.bool,
hasHover: PropTypes.bool,
onBlur: PropTypes.func,
onFocus: PropTypes.func,
onClick: PropTypes.func,
onKeyDown: PropTypes.func,
onMouseEnter: PropTypes.func,
onMouseLeave: PropTypes.func
};
TabPresenter.__docgenInfo = {
"description": "@param {TabPresenterProps} props\n@returns {JSX.Element}",
"displayName": "TabPresenter",
"props": {
"active": {
"type": {
"name": "bool"
},
"required": false,
"description": ""
},
"label": {
"type": {
"name": "string"
},
"required": false,
"description": ""
},
"hasFocus": {
"type": {
"name": "bool"
},
"required": false,
"description": ""
},
"hasHover": {
"type": {
"name": "bool"
},
"required": false,
"description": ""
},
"onBlur": {
"type": {
"name": "func"
},
"required": false,
"description": ""
},
"onFocus": {
"type": {
"name": "func"
},
"required": false,
"description": ""
},
"onClick": {
"type": {
"name": "func"
},
"required": false,
"description": ""
},
"onKeyDown": {
"type": {
"name": "func"
},
"required": false,
"description": ""
},
"onMouseEnter": {
"type": {
"name": "func"
},
"required": false,
"description": ""
},
"onMouseLeave": {
"type": {
"name": "func"
},
"required": false,
"description": ""
}
}
};
var _extends$1 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
/**
* @typedef {Object} RenderTabPayload
* @property {string} key
* @property {boolean} [active]
* @property {string} [label]
* @property {Function} [handleClick]
* @property {Function} [handleKeyDown]
*/
/**
* @typedef {Object} TabProps
* @property {boolean} [active]
* @property {string} [children]
* @property {string} [label]
* @property {Function} [onClick]
* @property {string} render A render prop allowing for custom tab components to be rendered
*/
/**
* This component is a facade for interfacing with the `Tabs` component.
* The logic within the `Tabs` component is strictly separated from the `TabPresenter`.
*
* @param {TabProps} props
* @returns {null}
*/
function Tab() {
return null;
}
Tab.defaultProps = {
/**
* @param {RenderTabPayload} props
* @returns {JSX.Element}
*/
render: function render(_ref) {
var handleClick = _ref.handleClick,
handleKeyDown = _ref.handleKeyDown,
label = _ref.label,
otherProps = _objectWithoutProperties(_ref, ["handleClick", "handleKeyDown", "label"]);
return React.createElement(
ControlBehavior,
{ key: label },
function (_ref2) {
var hasFocus = _ref2.hasFocus,
hasHover = _ref2.hasHover,
onBlur = _ref2.onBlur,
onFocus = _ref2.onFocus,
onMouseEnter = _ref2.onMouseEnter,
onMouseLeave = _ref2.onMouseLeave;
return React.createElement(TabPresenter, _extends$1({
hasFocus: hasFocus,
hasHover: hasHover,
label: label,
onBlur: onBlur,
onFocus: onFocus,
onMouseEnter: onMouseEnter,
onMouseLeave: onMouseLeave,
onClick: handleClick,
onKeyDown: handleKeyDown
}, otherProps));
}
);
}
};
Tab.propTypes = {
active: PropTypes.bool,
children: PropTypes.node,
label: PropTypes.string,
onBlur: PropTypes.func,
onFocus: PropTypes.func,
onClick: PropTypes.func,
render: PropTypes.func.isRequired
};
var _extends$2 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var FIRST_TAB_INDEX = 0;
/**
* @typedef {import("./Tab").RenderTabPayload} RenderTabPayload
*/
/**
* @typedef {Object} TabMeta
* @property {string} key
* @property {import("./tab").TabProps} props
*/
/**
* @typedef {Object} TabsProps
* @property {string} [align]
* @property {ReactNode} [children]
*/
/**
* @typedef {Object} TabsState
* @property {number} activeTabIndex
*/
/**
* @param {ReactNode} children
* @returns {TabMeta[]}
*/
function createTabs(children) {
return Children.toArray(children).reduce(function (result, child) {
var type = child.type,
key = child.key,
_child$props = child.props,
props = _child$props === undefined ? {} : _child$props;
if (type === Tab) {
result.push({ key: key, props: props });
}
return result;
}, []);
}
var Tabs = function (_Component) {
_inherits(Tabs, _Component);
function Tabs() {
var _ref;
var _temp, _this, _ret;
_classCallCheck(this, Tabs);
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Tabs.__proto__ || Object.getPrototypeOf(Tabs)).call.apply(_ref, [this].concat(args))), _this), _this.state = {
activeTabIndex: FIRST_TAB_INDEX
}, _this.createTabEventHandlers = memoize(function (index) {
return createButtonEventHandlers(function () {
return _this.setActiveTab(index);
});
}), _this.renderTab = function (_ref2, index) {
var key = _ref2.key,
props = _ref2.props;
var render = props.render,
label = props.label;
var activeTabIndex = _this.state.activeTabIndex;
/** @type {RenderTabPayload} */
var payload = _extends$2({
key: key,
label: label,
active: activeTabIndex === index
}, _this.createTabEventHandlers(index));
return render(payload);
}, _temp), _possibleConstructorReturn(_this, _ret);
}
/** @type {TabsState} */
_createClass(Tabs, [{
key: "getTabs",
/** @returns {TabMeta[]} */
value: function getTabs() {
return createTabs(this.props.children);
}
/** @returns {TabMeta|undefined} */
}, {
key: "getActiveTab",
value: function getActiveTab() {
var activeTabIndex = this.state.activeTabIndex;
return this.getTabs()[activeTabIndex];
}
/**
* @param {number} nextActiveTabIndex
*/
}, {
key: "setActiveTab",
value: function setActiveTab(nextActiveTabIndex) {
var prevActiveTabIndex = this.state.activeTabIndex;
var onTabChange = this.props.onTabChange;
if (prevActiveTabIndex === nextActiveTabIndex) return;
onTabChange(nextActiveTabIndex);
this.setState({ activeTabIndex: nextActiveTabIndex });
}
/**
* @param {TabMeta} tab
* @param {number} index
* @returns {JSX.Element}
*/
}, {
key: "renderTabs",
/**
* @returns {JSX.Element}
*/
value: function renderTabs() {
return React.createElement(
TabsPresenter,
{ align: this.props.align },
this.getTabs().map(this.renderTab)
);
}
/** @returns {ReactNode} */
}, {
key: "renderContent",
value: function renderContent() {
var activeTab = this.getActiveTab();
return activeTab ? activeTab.props.children : null;
}
}, {
key: "render",
value: function render() {
return React.createElement(
Fragment,
null,
this.renderTabs(),
this.renderContent()
);
}
}], [{
key: "getDerivedStateFromProps",
/**
* @param {TabsProps} nextProps
* @param {TabsState} prevState
* @returns {TabsState | null}
*/
value: function getDerivedStateFromProps(nextProps, prevState) {
var children = nextProps.children;
var nextTabs = createTabs(children);
var nextActiveTabIndex = nextTabs.findIndex(function (_ref3) {
var props = _ref3.props;
return props.active;
});
var prevActiveTabIndex = prevState.activeTabIndex;
if (
// If no active tab was declared
nextActiveTabIndex < 0 ||
// If the declared active tab is the same as the current active tab
nextActiveTabIndex === prevActiveTabIndex) {
return null;
}
return {
activeTabIndex: nextActiveTabIndex
};
}
}]);
return Tabs;
}(Component);
Tabs.propTypes = {
/**
* Specify how to justify the tabs within their container
*/
align: PropTypes.oneOf(AVAILABLE_ALIGNMENTS),
/**
* Accepts Tab components
*/
children: PropTypes.node,
/**
* Called when user activates a tab
*/
onTabChange: PropTypes.func
};
Tabs.defaultProps = {
align: alignments.CENTER,
onTabChange: function onTabChange() {}
};
var Tabs$1 = polyfill(Tabs);
Tabs.__docgenInfo = {
"description": "",
"displayName": "Tabs",
"props": {
"align": {
"type": {
"name": "enum",
"computed": true,
"value": "AVAILABLE_ALIGNMENTS"
},
"required": false,
"description": "Specify how to justify the tabs within their container",
"defaultValue": {
"value": "alignments.CENTER",
"computed": true
}
},
"children": {
"type": {
"name": "node"
},
"required": false,
"description": "Accepts Tab components"
},
"onTabChange": {
"type": {
"name": "func"
},
"required": false,
"description": "Called when user activates a tab",
"defaultValue": {
"value": "() => {}",
"computed": false
}
}
}
};
export default Tabs$1;
export { Tab, alignments, AVAILABLE_ALIGNMENTS };

@@ -5,9 +5,764 @@ 'use strict';

var higReact = require('hig-react');
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
higReact.Tabs.displayName = "Tabs";
var memoize = _interopDefault(require('lodash.memoize'));
var React = require('react');
var React__default = _interopDefault(React);
var emotion = require('emotion');
var PropTypes = _interopDefault(require('prop-types'));
var ThemeContext = _interopDefault(require('@hig/theme-context'));
var Typography = _interopDefault(require('@hig/typography'));
var behaviors = require('@hig/behaviors');
var Fragment = _interopDefault(require('render-fragment'));
var reactLifecyclesCompat = require('react-lifecycles-compat');
higReact.Tab.displayName = "Tab";
function _toConsumableArray(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) {
arr2[i] = arr[i];
}return arr2;
} else {
return Array.from(arr);
}
}
exports.Tabs = higReact.Tabs;
exports.Tab = higReact.Tab;
/**
* @typedef {Object} ButtonEventHandlers
* @property {function(MouseEvent, ...any): void} handleClick
* @property {function(KeyboardEvent, ...any): void} handleKeyDown
*/
/**
* @typedef {Object} Options
* @property {boolean} [preventDefault]
*/
var KEYBOARD_INTERACTIONS = [" ", "Enter"];
/**
* Create event handlers for native button behavior for non-button elements
* @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/button_role
*
* @param {function(MouseEvent|KeyboardEvent, ...any): void} [handler] the event handler function
* @param {Options} [options]
* @returns {ButtonEventHandlers}
*/
function createButtonEventHandlers(handler) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (!handler) return {};
var _options$preventDefau = options.preventDefault,
preventDefault = _options$preventDefau === undefined ? true : _options$preventDefau;
return {
handleClick: handler,
handleKeyDown: function handleKeyDown(event) {
var key = event.key;
if (!KEYBOARD_INTERACTIONS.includes(key)) return;
// Prevent space key default scrolling behavior
if (preventDefault) event.preventDefault();
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
handler.apply(undefined, [event].concat(_toConsumableArray(args)));
}
};
}
var alignments = Object.freeze({
LEFT: "left",
CENTER: "center",
RIGHT: "right"
});
var AVAILABLE_ALIGNMENTS = Object.freeze(Object.values(alignments));
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function stylesheet(_ref, themeData) {
var _justifyContent;
var align = _ref.align;
var justifyContent = (_justifyContent = {}, _defineProperty(_justifyContent, alignments.LEFT, "flex-start"), _defineProperty(_justifyContent, alignments.CENTER, "center"), _defineProperty(_justifyContent, alignments.RIGHT, "flex-end"), _justifyContent);
return {
tabs: {
boxSizing: "border-box",
flexGrow: 1,
display: "flex",
padding: themeData["density.spacings.extraExtraSmall"] + " 0 " + themeData["density.spacings.extraSmall"] + " 0",
margin: 0,
justifyContent: justifyContent[align]
}
};
}
function TabsPresenter(_ref) {
var align = _ref.align,
children = _ref.children;
return React__default.createElement(
ThemeContext.Consumer,
null,
function (_ref2) {
var resolvedRoles = _ref2.resolvedRoles;
var styles = stylesheet({ align: align }, resolvedRoles);
return React__default.createElement(
"ul",
{ className: emotion.css(styles.tabs) },
children
);
}
);
}
TabsPresenter.propTypes = {
align: PropTypes.oneOf(AVAILABLE_ALIGNMENTS),
children: PropTypes.node
};
TabsPresenter.defaultProps = {
align: alignments.CENTER
};
TabsPresenter.__docgenInfo = {
"description": "",
"displayName": "TabsPresenter",
"props": {
"align": {
"type": {
"name": "enum",
"computed": true,
"value": "AVAILABLE_ALIGNMENTS"
},
"required": false,
"description": "",
"defaultValue": {
"value": "alignments.CENTER",
"computed": true
}
},
"children": {
"type": {
"name": "node"
},
"required": false,
"description": ""
}
}
};
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
function stylesheet$1(_ref, themeData) {
var active = _ref.active,
hasFocus = _ref.hasFocus,
hasHover = _ref.hasHover,
label = _ref.label;
return {
tab: {
position: "relative",
display: "flex",
alignContent: "center",
justifyContent: "center",
padding: "0 " + themeData["density.spacings.small"],
margin: 0,
cursor: "pointer",
userSelect: "none",
textAlign: "center",
borderBottom: themeData["tabs.general.borderBottomWidth"] + " solid " + themeData["tabs.general.borderBottomColor"],
"&:first-of-type": {
paddingLeft: 0
},
"&:last-of-type": {
paddingRight: 0
},
"&:before": _extends({
position: "absolute",
content: "''",
bottom: "-" + themeData["tabs.general.borderBottomWidth"],
left: themeData["density.spacings.small"],
width: "calc(100% - (2 * " + themeData["density.spacings.small"] + "))",
borderBottomColor: "transparent",
borderBottomStyle: "solid",
borderBottomWidth: 0
}, hasHover && {
borderBottomColor: themeData["tabs.general.tab.hover.borderBottomColor"],
borderBottomWidth: themeData["tabs.general.tab.hover.borderBottomWidth"]
}, active && {
borderBottomColor: themeData["tabs.general.tab.selected.borderBottomColor"],
borderBottomWidth: themeData["tabs.general.tab.selected.borderBottomWidth"]
}),
"&:first-of-type:before": {
left: 0,
width: "calc(100% - " + themeData["density.spacings.small"] + ")"
},
"&:last-of-type:before": {
width: "calc(100% - " + themeData["density.spacings.small"] + ")"
},
"&:after": _extends({
position: "absolute",
content: "''",
bottom: "-" + themeData["tabs.general.tab.focus.halo.width"],
left: themeData["density.spacings.small"],
width: "calc(100% - (2 * " + themeData["density.spacings.small"] + "))"
}, hasFocus && {
borderBottom: themeData["tabs.general.tab.focus.halo.width"] + " solid " + themeData["tabs.general.tab.focus.halo.color"]
}),
"&:first-of-type:after": {
left: 0,
width: "calc(100% - " + themeData["density.spacings.small"] + ")"
},
"&:last-of-type:after": {
width: "calc(100% - " + themeData["density.spacings.small"] + ")"
}
},
tabLabel: _extends({
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
padding: themeData["tabs.general.gutter"] + " 0",
"&:focus": {
outline: "none"
}
}, label && {
"&:before": {
display: "block",
content: "\"" + label + "\"",
fontFamily: themeData["tabs.general.tab.fontFamily"],
fontSize: themeData["tabs.general.tab.fontSize"],
fontWeight: themeData["tabs.general.tab.selected.fontWeight"],
height: "0",
color: "transparent",
overflow: "hidden",
visibility: "hidden"
}
}),
tabLabelText: _extends({
fontSize: themeData["tabs.general.tab.fontSize"]
}, active && {
fontWeight: themeData["tabs.general.tab.selected.fontWeight"]
})
};
}
/**
* @typedef {Object} TabPresenterProps
* @property {boolean} [active]
* @property {string} label
* @property {Function} [onClick]
* @property {Function} [onKeyDown]
*/
/**
* @param {TabPresenterProps} props
* @returns {JSX.Element}
*/
function TabPresenter(_ref) {
var active = _ref.active,
hasFocus = _ref.hasFocus,
hasHover = _ref.hasHover,
label = _ref.label,
onBlur = _ref.onBlur,
onFocus = _ref.onFocus,
onClick = _ref.onClick,
onKeyDown = _ref.onKeyDown,
onMouseEnter = _ref.onMouseEnter,
onMouseLeave = _ref.onMouseLeave;
return React__default.createElement(
ThemeContext.Consumer,
null,
function (_ref2) {
var resolvedRoles = _ref2.resolvedRoles;
var styles = stylesheet$1({ active: active, hasFocus: hasFocus, hasHover: hasHover, label: label }, resolvedRoles);
return React__default.createElement(
"li",
{ className: emotion.css(styles.tab) },
React__default.createElement(
"div",
{
onBlur: onBlur,
onFocus: onFocus,
onClick: onClick,
onKeyDown: onKeyDown,
onMouseEnter: onMouseEnter,
onMouseLeave: onMouseLeave,
role: "button",
tabIndex: "0",
className: emotion.css(styles.tabLabel)
},
React__default.createElement(
Typography,
{ style: styles.tabLabelText },
label
)
)
);
}
);
}
TabPresenter.propTypes = {
active: PropTypes.bool,
label: PropTypes.string,
hasFocus: PropTypes.bool,
hasHover: PropTypes.bool,
onBlur: PropTypes.func,
onFocus: PropTypes.func,
onClick: PropTypes.func,
onKeyDown: PropTypes.func,
onMouseEnter: PropTypes.func,
onMouseLeave: PropTypes.func
};
TabPresenter.__docgenInfo = {
"description": "@param {TabPresenterProps} props\n@returns {JSX.Element}",
"displayName": "TabPresenter",
"props": {
"active": {
"type": {
"name": "bool"
},
"required": false,
"description": ""
},
"label": {
"type": {
"name": "string"
},
"required": false,
"description": ""
},
"hasFocus": {
"type": {
"name": "bool"
},
"required": false,
"description": ""
},
"hasHover": {
"type": {
"name": "bool"
},
"required": false,
"description": ""
},
"onBlur": {
"type": {
"name": "func"
},
"required": false,
"description": ""
},
"onFocus": {
"type": {
"name": "func"
},
"required": false,
"description": ""
},
"onClick": {
"type": {
"name": "func"
},
"required": false,
"description": ""
},
"onKeyDown": {
"type": {
"name": "func"
},
"required": false,
"description": ""
},
"onMouseEnter": {
"type": {
"name": "func"
},
"required": false,
"description": ""
},
"onMouseLeave": {
"type": {
"name": "func"
},
"required": false,
"description": ""
}
}
};
var _extends$1 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
/**
* @typedef {Object} RenderTabPayload
* @property {string} key
* @property {boolean} [active]
* @property {string} [label]
* @property {Function} [handleClick]
* @property {Function} [handleKeyDown]
*/
/**
* @typedef {Object} TabProps
* @property {boolean} [active]
* @property {string} [children]
* @property {string} [label]
* @property {Function} [onClick]
* @property {string} render A render prop allowing for custom tab components to be rendered
*/
/**
* This component is a facade for interfacing with the `Tabs` component.
* The logic within the `Tabs` component is strictly separated from the `TabPresenter`.
*
* @param {TabProps} props
* @returns {null}
*/
function Tab() {
return null;
}
Tab.defaultProps = {
/**
* @param {RenderTabPayload} props
* @returns {JSX.Element}
*/
render: function render(_ref) {
var handleClick = _ref.handleClick,
handleKeyDown = _ref.handleKeyDown,
label = _ref.label,
otherProps = _objectWithoutProperties(_ref, ["handleClick", "handleKeyDown", "label"]);
return React__default.createElement(
behaviors.ControlBehavior,
{ key: label },
function (_ref2) {
var hasFocus = _ref2.hasFocus,
hasHover = _ref2.hasHover,
onBlur = _ref2.onBlur,
onFocus = _ref2.onFocus,
onMouseEnter = _ref2.onMouseEnter,
onMouseLeave = _ref2.onMouseLeave;
return React__default.createElement(TabPresenter, _extends$1({
hasFocus: hasFocus,
hasHover: hasHover,
label: label,
onBlur: onBlur,
onFocus: onFocus,
onMouseEnter: onMouseEnter,
onMouseLeave: onMouseLeave,
onClick: handleClick,
onKeyDown: handleKeyDown
}, otherProps));
}
);
}
};
Tab.propTypes = {
active: PropTypes.bool,
children: PropTypes.node,
label: PropTypes.string,
onBlur: PropTypes.func,
onFocus: PropTypes.func,
onClick: PropTypes.func,
render: PropTypes.func.isRequired
};
var _extends$2 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var FIRST_TAB_INDEX = 0;
/**
* @typedef {import("./Tab").RenderTabPayload} RenderTabPayload
*/
/**
* @typedef {Object} TabMeta
* @property {string} key
* @property {import("./tab").TabProps} props
*/
/**
* @typedef {Object} TabsProps
* @property {string} [align]
* @property {ReactNode} [children]
*/
/**
* @typedef {Object} TabsState
* @property {number} activeTabIndex
*/
/**
* @param {ReactNode} children
* @returns {TabMeta[]}
*/
function createTabs(children) {
return React.Children.toArray(children).reduce(function (result, child) {
var type = child.type,
key = child.key,
_child$props = child.props,
props = _child$props === undefined ? {} : _child$props;
if (type === Tab) {
result.push({ key: key, props: props });
}
return result;
}, []);
}
var Tabs = function (_Component) {
_inherits(Tabs, _Component);
function Tabs() {
var _ref;
var _temp, _this, _ret;
_classCallCheck(this, Tabs);
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Tabs.__proto__ || Object.getPrototypeOf(Tabs)).call.apply(_ref, [this].concat(args))), _this), _this.state = {
activeTabIndex: FIRST_TAB_INDEX
}, _this.createTabEventHandlers = memoize(function (index) {
return createButtonEventHandlers(function () {
return _this.setActiveTab(index);
});
}), _this.renderTab = function (_ref2, index) {
var key = _ref2.key,
props = _ref2.props;
var render = props.render,
label = props.label;
var activeTabIndex = _this.state.activeTabIndex;
/** @type {RenderTabPayload} */
var payload = _extends$2({
key: key,
label: label,
active: activeTabIndex === index
}, _this.createTabEventHandlers(index));
return render(payload);
}, _temp), _possibleConstructorReturn(_this, _ret);
}
/** @type {TabsState} */
_createClass(Tabs, [{
key: "getTabs",
/** @returns {TabMeta[]} */
value: function getTabs() {
return createTabs(this.props.children);
}
/** @returns {TabMeta|undefined} */
}, {
key: "getActiveTab",
value: function getActiveTab() {
var activeTabIndex = this.state.activeTabIndex;
return this.getTabs()[activeTabIndex];
}
/**
* @param {number} nextActiveTabIndex
*/
}, {
key: "setActiveTab",
value: function setActiveTab(nextActiveTabIndex) {
var prevActiveTabIndex = this.state.activeTabIndex;
var onTabChange = this.props.onTabChange;
if (prevActiveTabIndex === nextActiveTabIndex) return;
onTabChange(nextActiveTabIndex);
this.setState({ activeTabIndex: nextActiveTabIndex });
}
/**
* @param {TabMeta} tab
* @param {number} index
* @returns {JSX.Element}
*/
}, {
key: "renderTabs",
/**
* @returns {JSX.Element}
*/
value: function renderTabs() {
return React__default.createElement(
TabsPresenter,
{ align: this.props.align },
this.getTabs().map(this.renderTab)
);
}
/** @returns {ReactNode} */
}, {
key: "renderContent",
value: function renderContent() {
var activeTab = this.getActiveTab();
return activeTab ? activeTab.props.children : null;
}
}, {
key: "render",
value: function render() {
return React__default.createElement(
Fragment,
null,
this.renderTabs(),
this.renderContent()
);
}
}], [{
key: "getDerivedStateFromProps",
/**
* @param {TabsProps} nextProps
* @param {TabsState} prevState
* @returns {TabsState | null}
*/
value: function getDerivedStateFromProps(nextProps, prevState) {
var children = nextProps.children;
var nextTabs = createTabs(children);
var nextActiveTabIndex = nextTabs.findIndex(function (_ref3) {
var props = _ref3.props;
return props.active;
});
var prevActiveTabIndex = prevState.activeTabIndex;
if (
// If no active tab was declared
nextActiveTabIndex < 0 ||
// If the declared active tab is the same as the current active tab
nextActiveTabIndex === prevActiveTabIndex) {
return null;
}
return {
activeTabIndex: nextActiveTabIndex
};
}
}]);
return Tabs;
}(React.Component);
Tabs.propTypes = {
/**
* Specify how to justify the tabs within their container
*/
align: PropTypes.oneOf(AVAILABLE_ALIGNMENTS),
/**
* Accepts Tab components
*/
children: PropTypes.node,
/**
* Called when user activates a tab
*/
onTabChange: PropTypes.func
};
Tabs.defaultProps = {
align: alignments.CENTER,
onTabChange: function onTabChange() {}
};
var Tabs$1 = reactLifecyclesCompat.polyfill(Tabs);
Tabs.__docgenInfo = {
"description": "",
"displayName": "Tabs",
"props": {
"align": {
"type": {
"name": "enum",
"computed": true,
"value": "AVAILABLE_ALIGNMENTS"
},
"required": false,
"description": "Specify how to justify the tabs within their container",
"defaultValue": {
"value": "alignments.CENTER",
"computed": true
}
},
"children": {
"type": {
"name": "node"
},
"required": false,
"description": "Accepts Tab components"
},
"onTabChange": {
"type": {
"name": "func"
},
"required": false,
"description": "Called when user activates a tab",
"defaultValue": {
"value": "() => {}",
"computed": false
}
}
}
};
exports.default = Tabs$1;
exports.Tab = Tab;
exports.alignments = alignments;
exports.AVAILABLE_ALIGNMENTS = AVAILABLE_ALIGNMENTS;

29

package.json
{
"name": "@hig/tabs",
"version": "0.2.0-alpha.fbb1eed0",
"version": "1.0.0",
"description": "HIG Tabs",

@@ -21,6 +21,11 @@ "author": "Autodesk Inc.",

"dependencies": {
"classnames": "^2.2.5",
"hig-react": "0.30.0-alpha.fbb1eed0",
"prop-types": "^15.6.1",
"react-lifecycles-compat": "^3.0.2"
"@hig/behaviors": "^1.1.1",
"@hig/fonts": "^1.0.1",
"@hig/theme-context": "^2.1.0",
"@hig/typography": "^1.0.2",
"emotion": "^10.0.0",
"lodash.memoize": "^4.1.2",
"prop-types": "^15.7.1",
"react-lifecycles-compat": "^3.0.4",
"render-fragment": "^0.1.1"
},

@@ -31,7 +36,7 @@ "peerDependencies": {

"devDependencies": {
"@hig/babel-preset": "0.2.0-alpha.fbb1eed0",
"@hig/eslint-config": "0.2.0-alpha.fbb1eed0",
"@hig/scripts": "0.2.0-alpha.fbb1eed0",
"@hig/semantic-release-config": "0.2.0-alpha.fbb1eed0",
"@hig/styles": "^0.1.1"
"@hig/babel-preset": "^0.1.1",
"@hig/eslint-config": "^0.1.0",
"@hig/jest-preset": "^0.1.0",
"@hig/scripts": "^0.1.2",
"@hig/semantic-release-config": "^0.1.0"
},

@@ -41,2 +46,3 @@ "scripts": {

"lint": "hig-scripts-lint",
"test": "hig-scripts-test",
"release": "hig-scripts-release"

@@ -47,2 +53,5 @@ },

},
"jest": {
"preset": "@hig/jest-preset"
},
"release": {

@@ -49,0 +58,0 @@ "extends": "@hig/semantic-release-config"

@@ -18,4 +18,4 @@ # Tabs

```js
import { Tabs, Tab } from '@hig/tabs';
import '@hig/tabs/build/index.css';
import Tabs, { Tab } from "@hig/tabs";
import "@hig/tabs/build/index.css";
```

@@ -22,0 +22,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc