@zendeskgarden/react-tabs
Version:
Components and render prop containers relating to the Garden Design System.
298 lines (283 loc) • 11.2 kB
JavaScript
/**
* Copyright Zendesk, Inc.
*
* Use of this source code is governed under the Apache License, Version 2.0
* found at http://www.apache.org/licenses/LICENSE-2.0.
*/
'use strict';
var React = require('react');
var PropTypes = require('prop-types');
var reactMergeRefs = require('react-merge-refs');
var styled = require('styled-components');
var reactTheming = require('@zendeskgarden/react-theming');
var polished = require('polished');
var containerTabs = require('@zendeskgarden/container-tabs');
var containerUtilities = require('@zendeskgarden/container-utilities');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
var React__default = /*#__PURE__*/_interopDefault(React);
var PropTypes__default = /*#__PURE__*/_interopDefault(PropTypes);
var styled__default = /*#__PURE__*/_interopDefault(styled);
const COMPONENT_ID$3 = 'tabs.tab';
const colorStyles$1 = _ref => {
let {
theme,
$isSelected
} = _ref;
const borderColor = $isSelected ? reactTheming.getColor({
theme,
variable: 'border.primaryEmphasis'
}) : 'transparent';
const selectedColor = reactTheming.getColor({
theme,
variable: 'foreground.primary'
});
const foregroundColor = $isSelected ? selectedColor : 'inherit';
const disabledColor = reactTheming.getColor({
theme,
variable: 'foreground.disabled'
});
return styled.css(["border-color:", ";color:", ";&:hover{color:", ";}", " &:active{border-color:currentcolor;color:", ";}&[aria-disabled='true']{border-color:transparent;color:", ";}"], borderColor, foregroundColor, selectedColor, reactTheming.focusStyles({
theme,
inset: true,
spacerWidth: null,
shadowWidth: 'sm',
selector: '&:focus-visible::before',
styles: {
color: selectedColor
}
}), selectedColor, disabledColor);
};
const sizeStyles$2 = _ref2 => {
let {
theme,
$isVertical
} = _ref2;
const borderWidth = theme.borderWidths.md;
const focusHeight = `calc(100% - ${theme.space.base * ($isVertical ? 2 : 4)}px);`;
let marginBottom;
let padding;
if ($isVertical) {
marginBottom = `${theme.space.base * 5}px`;
padding = `${theme.space.base}px ${theme.space.base * 2}px`;
} else {
const paddingTop = theme.space.base * 2.5;
const paddingHorizontal = theme.space.base * 7;
const paddingBottom = paddingTop - polished.stripUnit(theme.borderWidths.md) - polished.stripUnit(theme.borderWidths.sm);
padding = `${paddingTop}px ${paddingHorizontal}px ${paddingBottom}px`;
}
return styled.css(["margin-bottom:", ";border-width:", ";padding:", ";&:focus-visible::before,&[data-garden-focus-visible]::before{height:", ";}&:last-of-type{margin-bottom:0;}"], marginBottom, borderWidth, padding, focusHeight);
};
const StyledTab = styled__default.default.div.attrs({
'data-garden-id': COMPONENT_ID$3,
'data-garden-version': '9.11.3'
}).withConfig({
displayName: "StyledTab",
componentId: "sc-x2pbow-0"
})(["display:", ";position:relative;transition:color 0.25s ease-in-out;border-bottom:", ";border-", ":", ";cursor:pointer;overflow:hidden;vertical-align:top;user-select:none;text-align:", ";text-decoration:none;text-overflow:ellipsis;", ";", ";&:focus{text-decoration:none;}&::before{transition:box-shadow 0.1s ease-in-out;content:'';}&:focus-visible::before{position:absolute;top:", "px;right:", "px;left:", "px;border-radius:", ";pointer-events:none;}&:active::before{box-shadow:none;}&[aria-disabled='true']{cursor:default;}", ";"], props => props.$isVertical ? 'block' : 'inline-block', props => props.$isVertical ? undefined : props.theme.borderStyles.solid, props => props.theme.rtl ? 'right' : 'left', props => props.$isVertical ? props.theme.borderStyles.solid : undefined, props => {
if (props.$isVertical) {
return props.theme.rtl ? 'right' : 'left';
}
return 'center';
}, sizeStyles$2, colorStyles$1, props => props.theme.space.base * (props.$isVertical ? 1 : 2.5), props => props.theme.space.base * (props.$isVertical ? 1 : 6), props => props.theme.space.base * (props.$isVertical ? 1 : 6), props => props.theme.borderRadii.md, reactTheming.componentStyles);
const COMPONENT_ID$2 = 'tabs.tablist';
const colorStyles = _ref => {
let {
theme
} = _ref;
const borderColor = reactTheming.getColor({
theme,
variable: 'border.default'
});
const foregroundColor = reactTheming.getColor({
theme,
variable: 'foreground.default'
});
return styled.css(["transition:border-color 0.25s ease-in-out;color-scheme:only ", ";border-bottom-color:", ";color:", ";"], p => p.theme.colors.base, borderColor, foregroundColor);
};
const sizeStyles$1 = _ref2 => {
let {
theme,
$isVertical
} = _ref2;
const marginBottom = $isVertical ? 0 : `${theme.space.base * 5}px`;
const borderBottom = $isVertical ? undefined : theme.borderWidths.sm;
const fontSize = theme.fontSizes.md;
const lineHeight = reactTheming.getLineHeight(theme.space.base * 5, fontSize);
return styled.css(["margin-top:0;margin-bottom:", ";border-bottom-width:", ";padding:0;line-height:", ";font-size:", ";"], marginBottom, borderBottom, lineHeight, fontSize);
};
const StyledTabList = styled__default.default.div.attrs({
'data-garden-id': COMPONENT_ID$2,
'data-garden-version': '9.11.3'
}).withConfig({
displayName: "StyledTabList",
componentId: "sc-wa5aaj-0"
})(["display:", ";border-bottom:", ";vertical-align:", ";white-space:nowrap;", ";", ";", ";"], props => props.$isVertical ? 'table-cell' : 'block', props => props.$isVertical ? 'none' : props.theme.borderStyles.solid, props => props.$isVertical ? 'top' : undefined, sizeStyles$1, colorStyles, reactTheming.componentStyles);
const COMPONENT_ID$1 = 'tabs.tabpanel';
const sizeStyles = _ref => {
let {
theme,
$isVertical
} = _ref;
const margin = $isVertical ? `${theme.space.base * 8}px` : undefined;
return styled.css(["margin-", ":", ";"], theme.rtl ? 'right' : 'left', margin);
};
const StyledTabPanel = styled__default.default.div.attrs({
'data-garden-id': COMPONENT_ID$1,
'data-garden-version': '9.11.3'
}).withConfig({
displayName: "StyledTabPanel",
componentId: "sc-7lhrmp-0"
})(["display:block;vertical-align:", ";color-scheme:only ", ";", ";&[aria-hidden='true']{display:none;}", ";"], props => props.$isVertical && 'top', p => p.theme.colors.base, sizeStyles, reactTheming.componentStyles);
const COMPONENT_ID = 'tabs.tabs';
const StyledTabs = styled__default.default.div.attrs({
'data-garden-id': COMPONENT_ID,
'data-garden-version': '9.11.3'
}).withConfig({
displayName: "StyledTabs",
componentId: "sc-1qaor65-0"
})(["display:", ";overflow:hidden;direction:", ";", ";"], props => props.$isVertical ? 'table' : 'block', props => props.theme.rtl && 'rtl', reactTheming.componentStyles);
const TabsContext = React.createContext(undefined);
const useTabsContext = () => {
return React.useContext(TabsContext);
};
const Tab = React__default.default.forwardRef((_ref, ref) => {
let {
disabled,
item,
...otherProps
} = _ref;
const tabsPropGetters = useTabsContext();
if (disabled || !tabsPropGetters) {
return React__default.default.createElement(StyledTab, Object.assign({
role: "tab",
"aria-disabled": disabled,
ref: ref,
$isVertical: tabsPropGetters?.isVertical
}, otherProps));
}
const {
ref: tabRef,
...tabProps
} = tabsPropGetters.getTabProps({
value: item
});
return React__default.default.createElement(StyledTab, Object.assign({
$isSelected: item === tabsPropGetters.selectedValue,
$isVertical: tabsPropGetters.isVertical
}, tabProps, otherProps, {
ref: reactMergeRefs.mergeRefs([tabRef, ref])
}));
});
Tab.displayName = 'Tabs.Tab';
Tab.propTypes = {
disabled: PropTypes__default.default.bool,
item: PropTypes__default.default.any
};
const TabList = React__default.default.forwardRef((props, ref) => {
const tabsPropGetters = useTabsContext();
if (!tabsPropGetters) {
return React__default.default.createElement(StyledTabList, Object.assign({
ref: ref
}, props));
}
const tabListProps = tabsPropGetters.getTabListProps();
return React__default.default.createElement(StyledTabList, Object.assign({
$isVertical: tabsPropGetters.isVertical
}, tabListProps, props, {
ref: ref
}));
});
TabList.displayName = 'Tabs.TabList';
const TabPanel = React__default.default.forwardRef((_ref, ref) => {
let {
item,
...otherProps
} = _ref;
const tabsPropGetters = useTabsContext();
if (!tabsPropGetters) {
return React__default.default.createElement(StyledTabPanel, Object.assign({
ref: ref
}, otherProps));
}
const tabPanelProps = tabsPropGetters.getTabPanelProps({
value: item
});
return React__default.default.createElement(StyledTabPanel, Object.assign({
"aria-hidden": tabsPropGetters.selectedValue !== item,
$isVertical: tabsPropGetters.isVertical
}, tabPanelProps, otherProps, {
ref: ref
}));
});
TabPanel.displayName = 'Tabs.TabPanel';
TabPanel.propTypes = {
item: PropTypes__default.default.any
};
const toTabs = children => React.Children.toArray(children).reduce((_items, child) => {
const retVal = _items;
if (React.isValidElement(child)) {
if ('item' in child.props) {
const props = child.props;
retVal.push({
value: props.item,
disabled: props.disabled
});
} else {
const childItems = toTabs(child.props.children);
retVal.push(...childItems);
}
}
return retVal;
}, []);
const TabsComponent = React.forwardRef((_ref, ref) => {
let {
isVertical = false,
children,
onChange,
selectedItem: controlledSelectedItem,
...otherProps
} = _ref;
const theme = React.useContext(styled.ThemeContext) || reactTheming.DEFAULT_THEME;
const [internalSelectedItem, setInternalSelectedItem] = React.useState();
const selectedItem = containerUtilities.getControlledValue(controlledSelectedItem, internalSelectedItem);
const tabs = React.useMemo(() => toTabs(children), [children]);
const tabsContextValue = containerTabs.useTabs({
tabs,
rtl: theme.rtl,
orientation: isVertical ? 'vertical' : 'horizontal',
selectedValue: selectedItem,
defaultSelectedValue: tabs.find(tab => !tab.disabled)?.value,
onSelect: item => {
if (onChange) {
onChange(item);
} else {
setInternalSelectedItem(item);
}
}
});
const contextValue = React.useMemo(() => ({
isVertical,
...tabsContextValue
}), [isVertical, tabsContextValue]);
return React__default.default.createElement(TabsContext.Provider, {
value: contextValue
}, React__default.default.createElement(StyledTabs, Object.assign({
$isVertical: isVertical
}, otherProps, {
ref: ref
}), children));
});
TabsComponent.propTypes = {
isVertical: PropTypes__default.default.bool,
selectedItem: PropTypes__default.default.any,
onChange: PropTypes__default.default.func
};
TabsComponent.displayName = 'Tabs';
const Tabs = TabsComponent;
Tabs.Tab = Tab;
Tabs.TabList = TabList;
Tabs.TabPanel = TabPanel;
exports.Tab = Tab;
exports.TabList = TabList;
exports.TabPanel = TabPanel;
exports.Tabs = Tabs;