@carbon/react
Version:
React components for the Carbon Design System
209 lines (207 loc) • 7.22 kB
JavaScript
/**
* Copyright IBM Corp. 2016, 2026
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
const require_runtime = require("../../_virtual/_rolldown/runtime.js");
const require_usePrefix = require("../../internal/usePrefix.js");
const require_keys = require("../../internal/keyboard/keys.js");
const require_match = require("../../internal/keyboard/match.js");
const require_useId = require("../../internal/useId.js");
const require_useEvent = require("../../internal/useEvent.js");
const require_index = require("../Popover/index.js");
let classnames = require("classnames");
classnames = require_runtime.__toESM(classnames);
let react = require("react");
react = require_runtime.__toESM(react);
let prop_types = require("prop-types");
prop_types = require_runtime.__toESM(prop_types);
let react_jsx_runtime = require("react/jsx-runtime");
//#region src/components/Toggletip/index.tsx
/**
* Copyright IBM Corp. 2016, 2026
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* Used to render the label for a Toggletip
*/
function ToggletipLabel({ as: BaseComponent = "span", children, className: customClassName, ...rest }) {
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BaseComponent, {
className: (0, classnames.default)(`${require_usePrefix.usePrefix()}--toggletip-label`, customClassName),
...rest,
children
});
}
ToggletipLabel.propTypes = {
as: prop_types.default.elementType,
children: prop_types.default.node,
className: prop_types.default.string
};
const ToggletipContext = react.default.createContext(void 0);
function useToggletip() {
return (0, 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 = (0, react.useRef)(null);
const [open, setOpen] = (0, react.useState)(defaultOpen);
const prefix = require_usePrefix.usePrefix();
const id = require_useId.useId();
const className = (0, classnames.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 : void 0,
onClick: actions.toggle
},
contentProps: { id },
onClick: { onClick: actions.toggle }
};
const onKeyDown = (event) => {
if (open && require_match.match(event, require_keys.Escape)) {
event.stopPropagation();
actions.close();
const button = ref.current?.children[0];
if (button instanceof HTMLButtonElement) button.focus();
}
};
const handleBlur = (event) => {
if (open && event.relatedTarget === null) return;
if (!event.currentTarget.contains(event.relatedTarget)) actions.close();
};
require_useEvent.useWindowEvent("blur", () => {
if (open) actions.close();
});
(0, react.useEffect)(() => {
if (!open || !ref.current) return;
const targetDocument = ref.current.ownerDocument || document;
const eventType = "PointerEvent" in window ? "pointerdown" : "mousedown";
const handleOutsideClick = (event) => {
const { current } = ref;
if (!current) return;
const isInsideCurrent = (target) => target instanceof Node && current.contains(target);
if (!(isInsideCurrent(event.target) || typeof event.composedPath === "function" && event.composedPath().some(isInsideCurrent))) setOpen(false);
};
const options = { capture: true };
targetDocument.addEventListener(eventType, handleOutsideClick, options);
return () => {
targetDocument.removeEventListener(eventType, handleOutsideClick, options);
};
}, [open]);
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggletipContext.Provider, {
value,
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_index.Popover, {
align,
as,
caret: true,
className,
dropShadow: false,
highContrast: true,
open,
onKeyDown,
onBlur: handleBlur,
ref,
autoAlign,
...rest,
children
})
});
}
const { open, ...popoverNonOpenPropTypes } = require_index.Popover.propTypes ?? {};
Toggletip.propTypes = {
...popoverNonOpenPropTypes,
defaultOpen: prop_types.default.bool
};
/**
* `ToggletipButton` controls the visibility of the Toggletip through mouse
* clicks and keyboard interactions.
*/
const ToggletipButton = (0, react.forwardRef)(function ToggletipButton({ children, className: customClassName, label = "Show information", as: BaseComponent, ...rest }, ref) {
const toggletip = useToggletip();
const className = (0, classnames.default)(`${require_usePrefix.usePrefix()}--toggletip-button`, customClassName);
const ComponentToggle = BaseComponent ?? "button";
if (ComponentToggle !== "button") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ComponentToggle, {
...toggletip?.onClick,
className,
...rest,
children
});
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
...toggletip?.buttonProps,
"aria-label": label,
type: "button",
className,
ref,
...rest,
children
});
});
ToggletipButton.propTypes = {
children: prop_types.default.node,
className: prop_types.default.string,
label: prop_types.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 = (0, react.forwardRef)((props, ref) => {
const { children, className: customClassName } = props;
const toggletip = useToggletip();
const prefix = require_usePrefix.usePrefix();
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_index.PopoverContent, {
className: customClassName,
...toggletip?.contentProps,
ref,
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
className: `${prefix}--toggletip-content`,
children
})
});
});
ToggletipContent.propTypes = {
children: prop_types.default.node,
className: prop_types.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 }) {
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
className: (0, classnames.default)(`${require_usePrefix.usePrefix()}--toggletip-actions`, customClassName),
children
});
}
ToggletipActions.propTypes = {
children: prop_types.default.node,
className: prop_types.default.string
};
//#endregion
exports.ToggletipActions = ToggletipActions;
exports.ToggletipButton = ToggletipButton;
exports.ToggletipContent = ToggletipContent;
exports.ToggletipLabel = ToggletipLabel;
exports.default = Toggletip;