UNPKG

@carbon/ibm-products

Version:
190 lines (188 loc) 9.99 kB
/** * Copyright IBM Corp. 2020, 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_index = require("../../../node_modules/classnames/index.js"); const require_useIsomorphicEffect = require("../../../global/js/hooks/useIsomorphicEffect.js"); const require_useMatchMedia = require("../../../global/js/hooks/useMatchMedia.js"); const require_useCarbonFeatureFlagsObject = require("../../../global/js/hooks/useCarbonFeatureFlagsObject.js"); const require_useMergedRefs = require("../../../global/js/hooks/useMergedRefs.js"); const require_useId = require("../../../global/js/utils/useId.js"); const require_usePresence = require("../usePresence.js"); const require_context = require("./context.js"); const require_TearsheetHeader = require("./TearsheetHeader.js"); const require_TearsheetHeaderContent = require("./TearsheetHeaderContent.js"); const require_TearsheetBody = require("./TearsheetBody.js"); const require_TearsheetHeaderActions = require("./TearsheetHeaderActions.js"); const require_TearsheetFooter = require("./TearsheetFooter.js"); const require_StackContext = require("./StackContext.js"); let react = require("react"); react = require_runtime.__toESM(react); let _carbon_react = require("@carbon/react"); let react_dom = require("react-dom"); let _carbon_layout = require("@carbon/layout"); //#region src/components/Tearsheet/next/Tearsheet.tsx /** * Copyright IBM Corp. 2025, 2025 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ var import_classnames = /* @__PURE__ */ require_runtime.__toESM(require_index.default); /** * Internal component that handles the actual tearsheet rendering. * This component is always "present" when mounted - the wrapper handles presence logic. */ const TearsheetInternal = (0, react.forwardRef)(({ children, variant = "wide", selectorsFloatingMenus = [], className, influencerWidth, summaryContentWidth, ariaLabel, onClose, selectorPrimaryFocus, open = false, portalTarget, disablePortal = false, verticalGap, containerClassName, keepMounted = false, isExiting = false, presenceRef, decorator, launcherButtonRef, ...rest }, ref) => { const carbonPrefix = (0, _carbon_react.usePrefix)(); const localRef = (0, react.useRef)(null); const bodyRef = (0, react.useRef)(null); const mergedRefs = require_useMergedRefs.useMergedRefs([ ref, localRef, presenceRef ]); const isSm = require_useMatchMedia.useMatchMedia(`(max-width: ${_carbon_layout.breakpoints.md.width})`) || variant === "narrow"; const parentFlagsObject = require_useCarbonFeatureFlagsObject.useCarbonFeatureFlagsObject(); const [fullyCollapsed, setFullyCollapsed] = (0, react.useState)(false); const [disableHeaderCollapse, setDisableHeaderCollapse] = (0, react.useState)(false); const arr = react.default.Children.toArray(children); const header = arr.find((child) => child.type === require_TearsheetHeader.default); const influencer = arr.find((child) => child.type === require_TearsheetBody.Influencer); const body = arr.find((child) => child.type === require_TearsheetBody.default); const footer = arr.find((child) => child.type === require_TearsheetFooter.default); const uniqueId = (0, react.useRef)(require_useId.useId()); const titleId = (0, react.useRef)(`${require_context.blockClass}__title-${uniqueId.current}`); const { notifyStack, stack, getDepth, getScaleFactor, getBlockSizeChange } = require_StackContext.useStackContext(); const [depth, setDepth] = (0, react.useState)(0); const [mountNode, setMountNode] = (0, react.useState)(null); require_useIsomorphicEffect.useIsomorphicEffect(() => { if (!disablePortal) setMountNode(portalTarget || document.body); }, [portalTarget, disablePortal]); require_useIsomorphicEffect.useIsomorphicEffect(() => { const headerActionMarginRight = (localRef.current?.querySelector(`.${carbonPrefix}--ai-label`)?.clientWidth ?? 0) + 24 + (isSm ? 8 : 0); document.documentElement.style.setProperty("--tearsheet-header-action-offset", `${headerActionMarginRight}px`); if (influencerWidth) document.documentElement.style.setProperty("--tearsheet-influencer-width", `${influencerWidth}`); if (summaryContentWidth) document.documentElement.style.setProperty("--tearsheet-summary-content-width", `${summaryContentWidth}`); if (verticalGap) document.documentElement.style.setProperty("--tearsheet-vertical-gap", `${verticalGap}`); }, [ isSm, decorator, influencerWidth, summaryContentWidth, verticalGap ]); require_useIsomorphicEffect.useIsomorphicEffect(() => { const id = uniqueId.current; if (localRef.current && open) notifyStack?.(id, true, localRef.current); return () => { notifyStack?.(id, false, null); }; }, [localRef.current, open]); (0, react.useEffect)(() => { if (stack?.length > 0 && localRef.current) { const stackDepth = getDepth?.(uniqueId.current), blockSizeChange = getBlockSizeChange?.(uniqueId.current), scaleFactor = getScaleFactor?.(uniqueId.current); setDepth(stackDepth); localRef.current.style.setProperty("--stack-depth", stackDepth + ""); localRef.current.style.setProperty("--block-size-change", blockSizeChange); localRef.current.style.setProperty("--scale-factor", scaleFactor + ""); } }, [stack]); (0, react.useEffect)(() => { if (!open && launcherButtonRef?.current) { const timeoutId = setTimeout(() => { const refCurrent = launcherButtonRef.current; if (refCurrent instanceof HTMLElement) { const headerActionItem = refCurrent.closest(`.${require_context.blockClass}__header-action-item`); if (headerActionItem) { const menuButton = headerActionItem.closest(`.${require_context.blockClass}__content__header-actions`)?.querySelector(`.${require_context.blockClass}__header-actions-menuButton:not(.${require_context.blockClass}__header-actions-menuButton--hidden) button`); if (menuButton instanceof HTMLElement) menuButton.focus(); else refCurrent.focus(); } else refCurrent.focus(); } }, 100); return () => clearTimeout(timeoutId); } }, [open, launcherButtonRef]); const content = /* @__PURE__ */ react.default.createElement(require_context.TearsheetContext.Provider, { value: { fullyCollapsed, setFullyCollapsed, onClose, disableHeaderCollapse, setDisableHeaderCollapse, variant, isSm, decorator, titleId: titleId.current } }, /* @__PURE__ */ react.default.createElement(_carbon_react.unstable_FeatureFlags, { flags: { ...parentFlagsObject, "enable-experimental-focus-wrap-without-sentinels": true } }, /* @__PURE__ */ react.default.createElement(_carbon_react.ComposedModal, { ...rest, "aria-label": ariaLabel, "aria-labelledby": !ariaLabel ? titleId.current : void 0, className: (0, import_classnames.default)(require_context.blockClass, className, { [`${require_context.blockClass}--wide`]: variant === "wide", [`${require_context.blockClass}--narrow`]: variant === "narrow", [`${require_context.blockClass}--stacked`]: depth > 0, [`${require_context.blockClass}--stack-activated`]: stack.length > 1, [`${require_context.blockClass}--has-ai-label`]: !!decorator && decorator["type"]?.displayName === "AILabel", [`${require_context.blockClass}--has-decorator`]: !!decorator && decorator["type"]?.displayName !== "AILabel", ["is-visible"]: keepMounted ? open : true, [`${require_context.blockClass}--keep-mounted`]: keepMounted }), containerClassName: (0, import_classnames.default)(`${require_context.blockClass}__container`, containerClassName), onClose, open: keepMounted ? open : true, selectorPrimaryFocus, ref: mergedRefs, selectorsFloatingMenus: [ `.${carbonPrefix}--overflow-menu-options`, `.${carbonPrefix}--tooltip`, ".flatpickr-calendar", `.${require_context.blockClass}__container`, `.${carbonPrefix}--menu`, ...selectorsFloatingMenus ], isFullWidth: true, size: variant === "narrow" ? "sm" : "", "data-tearsheet-exiting": isExiting ? true : void 0 }, header, /* @__PURE__ */ react.default.createElement(_carbon_react.ModalBody, { className: (0, import_classnames.default)(`${require_context.blockClass}__body-layout`, { [`${require_context.blockClass}__body-layout--has-influencer`]: influencer && !isSm }), ref: bodyRef }, influencer, body, footer)))); if (disablePortal) return content; return mountNode ? (0, react_dom.createPortal)(content, mountNode) : content; }); /** * Wrapper component that handles presence logic and conditionally renders TearsheetInternal. * This ensures that all component state and effects are only initialized when the tearsheet is present. */ const Tearsheet = (0, react.forwardRef)((props, ref) => { const { open = false, keepMounted = false } = props; const presenceRef = (0, react.useRef)(null); const { isPresent, isExiting } = require_usePresence.usePresence(presenceRef, keepMounted ? true : open); if (!keepMounted && !isPresent) return null; return /* @__PURE__ */ react.default.createElement(TearsheetInternal, { ...props, ref, presenceRef, isExiting }); }); Tearsheet.Header = require_TearsheetHeader.default; Tearsheet.HeaderContent = require_TearsheetHeaderContent.default; Tearsheet.Body = require_TearsheetBody.default; Tearsheet.Influencer = require_TearsheetBody.Influencer; Tearsheet.MainContent = require_TearsheetBody.MainContent; Tearsheet.SummaryContent = require_TearsheetBody.SummaryContent; Tearsheet.Footer = require_TearsheetFooter.default; Tearsheet.NavigationBar = require_TearsheetHeader.TearsheetNavigationBar; Tearsheet.ScrollButton = require_TearsheetHeader.TearsheetScrollButton; Tearsheet.HeaderActions = require_TearsheetHeaderActions.TearsheetHeaderActions; Tearsheet.HeaderActionItem = require_TearsheetHeaderActions.TearsheetHeaderActionItem; //#endregion exports.Tearsheet = Tearsheet;