UNPKG

@primer/react

Version:

An implementation of GitHub's Primer Design System using React

255 lines (247 loc) • 10.2 kB
'use strict'; var React = require('react'); var styled = require('styled-components'); var useId = require('../hooks/useId.js'); var useSlots = require('../hooks/useSlots.js'); var sx = require('../sx.js'); var ThemeProvider = require('../ThemeProvider.js'); var defaultSxProp = require('../utils/defaultSxProp.js'); var ActionListContainerContext = require('./ActionListContainerContext.js'); var Description = require('./Description.js'); var Group = require('./Group.js'); var List = require('./List.js'); var Selection = require('./Selection.js'); var shared = require('./shared.js'); var Visuals = require('./Visuals.js'); var Box = require('../Box/Box.js'); var merge = require('deepmerge'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } var React__default = /*#__PURE__*/_interopDefault(React); var styled__default = /*#__PURE__*/_interopDefault(styled); var merge__default = /*#__PURE__*/_interopDefault(merge); function _extends() { _extends = Object.assign ? Object.assign.bind() : 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; }; return _extends.apply(this, arguments); } const LiBox = styled__default.default.li.withConfig({ displayName: "Item__LiBox", componentId: "sc-yeql7o-0" })(sx.default); const Item = /*#__PURE__*/React__default.default.forwardRef(({ variant = 'default', disabled = false, selected = undefined, active = false, onSelect, sx: sxProp = defaultSxProp.defaultSxProp, id, role, _PrivateItemWrapper, ...props }, forwardedRef) => { var _slots$description, _slots$description2, _slots$description3; const [slots, childrenWithoutSlots] = useSlots.useSlots(props.children, { leadingVisual: Visuals.LeadingVisual, trailingVisual: Visuals.TrailingVisual, description: Description.Description }); const { variant: listVariant, showDividers, selectionVariant: listSelectionVariant } = React__default.default.useContext(List.ListContext); const { selectionVariant: groupSelectionVariant } = React__default.default.useContext(Group.GroupContext); const { container, afterSelect, selectionAttribute } = React__default.default.useContext(ActionListContainerContext.ActionListContainerContext); let selectionVariant; if (typeof groupSelectionVariant !== 'undefined') selectionVariant = groupSelectionVariant;else selectionVariant = listSelectionVariant; /** Infer item role based on the container */ let itemRole; if (container === 'ActionMenu' || container === 'DropdownMenu') { if (selectionVariant === 'single') itemRole = 'menuitemradio';else if (selectionVariant === 'multiple') itemRole = 'menuitemcheckbox';else itemRole = 'menuitem'; } const { theme } = ThemeProvider.useTheme(); const activeStyles = { fontWeight: 'bold', bg: 'actionListItem.default.selectedBg', '&::after': { position: 'absolute', top: 'calc(50% - 12px)', left: -2, width: '4px', height: '24px', content: '""', bg: 'accent.fg', borderRadius: 2 } }; const styles = { position: 'relative', display: 'flex', paddingX: 2, fontSize: 1, paddingY: '6px', // custom value off the scale lineHeight: shared.TEXT_ROW_HEIGHT, minHeight: 5, marginX: listVariant === 'inset' ? 2 : 0, borderRadius: listVariant === 'inset' ? 2 : 0, transition: 'background 33.333ms linear', color: shared.getVariantStyles(variant, disabled).color, cursor: 'pointer', '&[aria-disabled]': { cursor: 'not-allowed' }, // Button reset styles (to support as="button") appearance: 'none', background: 'unset', border: 'unset', width: 'calc(100% - 16px)', fontFamily: 'unset', textAlign: 'unset', marginY: 'unset', '@media (hover: hover) and (pointer: fine)': { ':hover:not([aria-disabled])': { backgroundColor: `actionListItem.${variant}.hoverBg`, color: shared.getVariantStyles(variant, disabled).hoverColor }, '&:focus-visible, > a:focus-visible': { outline: 'none', border: `2 solid`, boxShadow: `0 0 0 2px ${theme === null || theme === void 0 ? void 0 : theme.colors.accent.emphasis}` }, ':active:not([aria-disabled])': { backgroundColor: `actionListItem.${variant}.activeBg`, color: shared.getVariantStyles(variant, disabled).hoverColor } }, '@media (forced-colors: active)': { ':focus': { // Support for Windows high contrast https://sarahmhigley.com/writing/whcm-quick-tips outline: 'solid 1px transparent !important' } }, /** Divider styles */ '[data-component="ActionList.Item--DividerContainer"]': { position: 'relative' }, '[data-component="ActionList.Item--DividerContainer"]::before': { content: '" "', display: 'block', position: 'absolute', width: '100%', top: '-7px', border: '0 solid', borderTopWidth: showDividers ? `1px` : '0', borderColor: 'var(--divider-color, transparent)' }, // show between 2 items ':not(:first-of-type)': { '--divider-color': theme === null || theme === void 0 ? void 0 : theme.colors.actionListItem.inlineDivider }, // hide divider after dividers & group header, with higher importance! '[data-component="ActionList.Divider"] + &': { '--divider-color': 'transparent !important' }, // hide border on current and previous item '&:hover:not([aria-disabled]), &:focus:not([aria-disabled]), &[data-focus-visible-added]:not([aria-disabled])': { '--divider-color': 'transparent' }, '&:hover:not([aria-disabled]) + &, &:focus:not([aria-disabled]) + &, &[data-focus-visible-added] + li': { '--divider-color': 'transparent' }, ...(active ? activeStyles : {}) }; const clickHandler = React__default.default.useCallback(event => { if (disabled) return; if (!event.defaultPrevented) { if (typeof onSelect === 'function') onSelect(event); // if this Item is inside a Menu, close the Menu if (typeof afterSelect === 'function') afterSelect(); } }, [onSelect, disabled, afterSelect]); const keyPressHandler = React__default.default.useCallback(event => { if (disabled) return; if (!event.defaultPrevented && [' ', 'Enter'].includes(event.key)) { if (typeof onSelect === 'function') onSelect(event); // if this Item is inside a Menu, close the Menu if (typeof afterSelect === 'function') afterSelect(); } }, [onSelect, disabled, afterSelect]); // use props.id if provided, otherwise generate one. const labelId = useId.useId(id); const inlineDescriptionId = useId.useId(id && `${id}--inline-description`); const blockDescriptionId = useId.useId(id && `${id}--block-description`); const ItemWrapper = _PrivateItemWrapper || React__default.default.Fragment; const menuItemProps = { onClick: clickHandler, onKeyPress: keyPressHandler, 'aria-disabled': disabled ? true : undefined, tabIndex: disabled ? undefined : 0, 'aria-labelledby': `${labelId} ${slots.description && slots.description.props.variant !== 'block' ? inlineDescriptionId : ''}`, 'aria-describedby': ((_slots$description = slots.description) === null || _slots$description === void 0 ? void 0 : _slots$description.props.variant) === 'block' ? blockDescriptionId : undefined, ...(selectionAttribute && { [selectionAttribute]: selected }), role: role || itemRole }; const containerProps = _PrivateItemWrapper ? { role: role || itemRole ? 'none' : undefined } : menuItemProps; const wrapperProps = _PrivateItemWrapper ? menuItemProps : {}; return /*#__PURE__*/React__default.default.createElement(shared.ItemContext.Provider, { value: { variant, disabled, inlineDescriptionId, blockDescriptionId } }, /*#__PURE__*/React__default.default.createElement(LiBox, _extends({ ref: forwardedRef, sx: merge__default.default(styles, sxProp) }, containerProps, props), /*#__PURE__*/React__default.default.createElement(ItemWrapper, wrapperProps, /*#__PURE__*/React__default.default.createElement(Selection.Selection, { selected: selected }), slots.leadingVisual, /*#__PURE__*/React__default.default.createElement(Box, { "data-component": "ActionList.Item--DividerContainer", sx: { display: 'flex', flexDirection: 'column', flexGrow: 1, minWidth: 0 } }, /*#__PURE__*/React__default.default.createElement(ConditionalBox, { if: Boolean(slots.trailingVisual), sx: { display: 'flex', flexGrow: 1 } }, /*#__PURE__*/React__default.default.createElement(ConditionalBox, { if: !!slots.description && slots.description.props.variant !== 'block', sx: { display: 'flex', flexGrow: 1, alignItems: 'baseline', minWidth: 0 } }, /*#__PURE__*/React__default.default.createElement(Box, { as: "span", id: labelId, sx: { flexGrow: slots.description && slots.description.props.variant !== 'block' ? 0 : 1, fontWeight: slots.description && slots.description.props.variant !== 'block' ? 'bold' : 'normal' } }, childrenWithoutSlots), ((_slots$description2 = slots.description) === null || _slots$description2 === void 0 ? void 0 : _slots$description2.props.variant) !== 'block' ? slots.description : null), slots.trailingVisual), ((_slots$description3 = slots.description) === null || _slots$description3 === void 0 ? void 0 : _slots$description3.props.variant) === 'block' ? slots.description : null)))); }); Item.displayName = 'ActionList.Item'; const ConditionalBox = props => { const { if: condition, ...rest } = props; if (condition) return /*#__PURE__*/React__default.default.createElement(Box, rest, props.children);else return /*#__PURE__*/React__default.default.createElement(React__default.default.Fragment, null, props.children); }; exports.Item = Item;