@carbon/react
Version:
React components for the Carbon Design System
321 lines (306 loc) • 10.3 kB
JavaScript
/**
* Copyright IBM Corp. 2016, 2023
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var _rollupPluginBabelHelpers = require('../../_virtual/_rollupPluginBabelHelpers.js');
var cx = require('classnames');
var PropTypes = require('prop-types');
var React = require('react');
var index = require('../Popover/index.js');
var keys = require('../../internal/keyboard/keys.js');
var match = require('../../internal/keyboard/match.js');
var useEvent = require('../../internal/useEvent.js');
var useId = require('../../internal/useId.js');
var usePrefix = require('../../internal/usePrefix.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var cx__default = /*#__PURE__*/_interopDefaultLegacy(cx);
var PropTypes__default = /*#__PURE__*/_interopDefaultLegacy(PropTypes);
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
/**
* Used to render the label for a Toggletip
*/
function ToggletipLabel({
as: BaseComponent = 'span',
children,
className: customClassName,
...rest
}) {
const prefix = usePrefix.usePrefix();
const className = cx__default["default"](`${prefix}--toggletip-label`, customClassName);
const BaseComponentAsAny = BaseComponent;
return /*#__PURE__*/React__default["default"].createElement(BaseComponentAsAny, _rollupPluginBabelHelpers["extends"]({
className: className
}, rest), children);
}
ToggletipLabel.propTypes = {
/**
* Provide a custom element or component to render the top-level node for the
* component.
*/
as: PropTypes__default["default"].elementType,
/**
* Custom children to be rendered as the content of the label
*/
children: PropTypes__default["default"].node,
/**
* Provide a custom class name to be added to the outermost node in the
* component
*/
className: PropTypes__default["default"].string
};
// Used to coordinate accessibility props between button and content along with
// the actions to open and close the toggletip
const ToggletipContext = /*#__PURE__*/React__default["default"].createContext(undefined);
function useToggletip() {
return React.useContext(ToggletipContext);
}
/**
* Used as a container for the button and content of a toggletip. This component
* is responsible for coordinating between interactions with the button and the
* visibility of the content
*/
function Toggletip({
align,
as,
autoAlign,
className: customClassName,
children,
defaultOpen = false,
...rest
}) {
const ref = React.useRef(null);
const [open, setOpen] = React.useState(defaultOpen);
const prefix = usePrefix.usePrefix();
const id = useId.useId();
const className = cx__default["default"](`${prefix}--toggletip`, customClassName, {
[`${prefix}--toggletip--open`]: open,
[`${prefix}--autoalign`]: autoAlign
});
const actions = {
toggle: () => {
setOpen(!open);
},
close: () => {
setOpen(false);
}
};
const value = {
buttonProps: {
'aria-expanded': open,
'aria-controls': id,
'aria-describedby': open ? id : undefined,
onClick: actions.toggle
},
contentProps: {
id
},
onClick: {
onClick: actions.toggle
}
};
const onKeyDown = event => {
if (open && match.match(event, keys.Escape)) {
actions.close();
// If the menu is closed while focus is still inside the menu, it should return to the trigger button (#12922)
const button = ref.current?.children[0];
if (button instanceof HTMLButtonElement) {
button.focus();
}
}
};
const handleBlur = event => {
// Do not close if the menu itself is clicked, should only close on focus out
if (open && event.relatedTarget === null) {
return;
}
if (!event.currentTarget.contains(event.relatedTarget)) {
// The menu should be closed when focus leaves the `Toggletip` (#12922)
actions.close();
}
};
// If the `Toggletip` is the last focusable item in the tab order, it should also close when the browser window loses focus (#12922)
useEvent.useWindowEvent('blur', () => {
if (open) {
actions.close();
}
});
useEvent.useWindowEvent('click', ({
target
}) => {
if (open && target instanceof Node && !ref.current?.contains(target)) {
actions.close();
}
});
return /*#__PURE__*/React__default["default"].createElement(ToggletipContext.Provider, {
value: value
}, /*#__PURE__*/React__default["default"].createElement(index.Popover, _rollupPluginBabelHelpers["extends"]({
align: align,
as: as,
caret: true,
className: className,
dropShadow: false,
highContrast: true,
open: open,
onKeyDown: onKeyDown,
onBlur: handleBlur,
ref: ref,
autoAlign: autoAlign
}, rest), children));
}
Toggletip.propTypes = {
/**
* Specify how the toggletip should align with the button
*/
align: PropTypes__default["default"].oneOf(['top', 'top-left',
// deprecated use top-start instead
'top-right',
// deprecated use top-end instead
'bottom', 'bottom-left',
// deprecated use bottom-start instead
'bottom-right',
// deprecated use bottom-end instead
'left', 'left-bottom',
// deprecated use left-end instead
'left-top',
// deprecated use left-start instead
'right', 'right-bottom',
// deprecated use right-end instead
'right-top',
// deprecated use right-start instead
// new values to match floating-ui
'top-start', 'top-end', 'bottom-start', 'bottom-end', 'left-end', 'left-start', 'right-end', 'right-start']),
/**
* Provide an offset value for alignment axis.
*/
alignmentAxisOffset: PropTypes__default["default"].number,
/**
* Provide a custom element or component to render the top-level node for the
* component.
*/
as: PropTypes__default["default"].elementType,
/**
* Will auto-align the popover on first render if it is not visible. This prop is currently experimental and is subject to future changes.
*/
autoAlign: PropTypes__default["default"].bool,
/**
* Custom children to be rendered as the content of the label
*/
children: PropTypes__default["default"].node,
/**
* Provide a custom class name to be added to the outermost node in the
* component
*/
className: PropTypes__default["default"].string,
/**
* Specify if the toggletip should be open by default
*/
defaultOpen: PropTypes__default["default"].bool
};
/**
* `ToggletipButton` controls the visibility of the Toggletip through mouse
* clicks and keyboard interactions.
*/
const ToggletipButton = /*#__PURE__*/React__default["default"].forwardRef(function ToggletipButton({
children,
className: customClassName,
label = 'Show information',
as: BaseComponent,
...rest
}, ref) {
const toggletip = useToggletip();
const prefix = usePrefix.usePrefix();
const className = cx__default["default"](`${prefix}--toggletip-button`, customClassName);
const ComponentToggle = BaseComponent ?? 'button';
if (ComponentToggle !== 'button') {
return /*#__PURE__*/React__default["default"].createElement(ComponentToggle, _rollupPluginBabelHelpers["extends"]({}, toggletip?.onClick, {
className: className
}, rest), children);
}
return /*#__PURE__*/React__default["default"].createElement("button", _rollupPluginBabelHelpers["extends"]({}, toggletip?.buttonProps, {
"aria-label": label,
type: "button",
className: className,
ref: ref
}, rest), children);
});
ToggletipButton.propTypes = {
/**
* Custom children to be rendered as the content of the label
*/
children: PropTypes__default["default"].node,
/**
* Provide a custom class name to be added to the outermost node in the
* component
*/
className: PropTypes__default["default"].string,
/**
* Provide an accessible label for this button
*/
label: PropTypes__default["default"].string
};
ToggletipButton.displayName = 'ToggletipButton';
/**
* `ToggletipContent` is a wrapper around `PopoverContent`. It places the
* `children` passed in as a prop inside of `PopoverContent` so that they will
* be rendered inside of the popover for this component.
*/
const ToggletipContent = /*#__PURE__*/React__default["default"].forwardRef(function ToggletipContent({
children,
className: customClassName
}, ref) {
const toggletip = useToggletip();
const prefix = usePrefix.usePrefix();
return /*#__PURE__*/React__default["default"].createElement(index.PopoverContent, _rollupPluginBabelHelpers["extends"]({
className: customClassName
}, toggletip?.contentProps, {
ref: ref
}), /*#__PURE__*/React__default["default"].createElement("div", {
className: `${prefix}--toggletip-content`
}, children));
});
ToggletipContent.propTypes = {
/**
* Custom children to be rendered as the content of the label
*/
children: PropTypes__default["default"].node,
/**
* Provide a custom class name to be added to the outermost node in the
* component
*/
className: PropTypes__default["default"].string
};
ToggletipContent.displayName = 'ToggletipContent';
/**
* `ToggletipActions` is a container for one or two actions present at the base
* of a toggletip. It is used for layout of these items.
*/
function ToggletipActions({
children,
className: customClassName
}) {
const prefix = usePrefix.usePrefix();
const className = cx__default["default"](`${prefix}--toggletip-actions`, customClassName);
return /*#__PURE__*/React__default["default"].createElement("div", {
className: className
}, children);
}
ToggletipActions.propTypes = {
/**
* Custom children to be rendered as the content of the label
*/
children: PropTypes__default["default"].node,
/**
* Provide a custom class name to be added to the outermost node in the
* component
*/
className: PropTypes__default["default"].string
};
exports.Toggletip = Toggletip;
exports.ToggletipActions = ToggletipActions;
exports.ToggletipButton = ToggletipButton;
exports.ToggletipContent = ToggletipContent;
exports.ToggletipLabel = ToggletipLabel;