UNPKG

@razorpay/blade

Version:

The Design System that powers Razorpay

193 lines (189 loc) 8.86 kB
import _defineProperty from '@babel/runtime/helpers/defineProperty'; import _slicedToArray from '@babel/runtime/helpers/slicedToArray'; import React__default from 'react'; import styled from 'styled-components'; import '../../../utils/index.js'; import '../../../tokens/global/index.js'; import '../../../utils/metaAttribute/index.js'; import '../../BladeProvider/index.js'; import { useResize } from '../../../utils/useResize.js'; import { useIsomorphicLayoutEffect } from '../../../utils/useIsomorphicLayoutEffect.js'; import '../../Box/BaseBox/index.js'; import { jsxs, jsx } from 'react/jsx-runtime'; import { BaseBox } from '../../Box/BaseBox/BaseBox.web.js'; import { makeSpace } from '../../../utils/makeSpace/makeSpace.js'; import { makeBorderSize } from '../../../utils/makeBorderSize/makeBorderSize.js'; import { size } from '../../../tokens/global/size.js'; import useTheme from '../../BladeProvider/useTheme.js'; import { makeMotionTime } from '../../../utils/makeMotionTime/makeMotionTime.web.js'; import { castWebType } from '../../../utils/platform/castUtils.js'; import { metaAttribute } from '../../../utils/metaAttribute/metaAttribute.web.js'; import { MetaConstants } from '../../../utils/metaAttribute/metaConstants.js'; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } var StyledIndicatorWrapper = /*#__PURE__*/styled.div.withConfig({ displayName: "TabNavIndicatorweb__StyledIndicatorWrapper", componentId: "lqpaj2-0" })({ pointerEvents: 'none', position: 'absolute', bottom: 0, left: 0, willChange: 'transform, width, opacity' }); var StyledTabNavIndicatorLine = /*#__PURE__*/styled(BaseBox).withConfig({ displayName: "TabNavIndicatorweb__StyledTabNavIndicatorLine", componentId: "lqpaj2-1" })(function (_ref) { var theme = _ref.theme; return { position: 'relative', width: '100%', height: makeSpace(theme.border.width.thinner), borderTopLeftRadius: makeBorderSize(theme.border.radius.medium), borderTopRightRadius: makeBorderSize(theme.border.radius.medium) }; }); var GLOW_OVERFLOW = 32; var GLOW_HEIGHT = size[56]; var buildGlowMask = function buildGlowMask(width) { var height = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : GLOW_HEIGHT; var cx = width / 2; var rx = width * 0.37; return "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='".concat(width, "' height='").concat(height, "'%3E%3Cdefs%3E%3Cfilter id='b' filterUnits='userSpaceOnUse' x='0' y='0' width='").concat(width, "' height='").concat(height, "'%3E%3CfeGaussianBlur stdDeviation='40'/%3E%3C/filter%3E%3C/defs%3E%3Cellipse cx='").concat(cx, "' cy='").concat(height, "' rx='").concat(rx, "' ry='60' fill='black' filter='url(%23b)'/%3E%3C/svg%3E\")"); }; var StyledIndicatorGlow = /*#__PURE__*/styled.div.withConfig({ displayName: "TabNavIndicatorweb__StyledIndicatorGlow", componentId: "lqpaj2-2" })(function (_ref2) { var glowColor = _ref2.glowColor, glowWidth = _ref2.glowWidth, glowMask = _ref2.glowMask; var totalWidth = glowWidth + GLOW_OVERFLOW * 2; return { position: 'absolute', bottom: 0, left: "".concat(-GLOW_OVERFLOW, "px"), width: "".concat(totalWidth, "px"), height: "".concat(GLOW_HEIGHT, "px"), // Tuned visually to blend the glow into the dark TopNav background without overpowering the indicator line opacity: 0.8, background: "radial-gradient(50% 100% at 50% 100%, ".concat(glowColor, " 0%, transparent 100%)"), WebkitMaskImage: glowMask, WebkitMaskRepeat: 'no-repeat', WebkitMaskPosition: 'center bottom', WebkitMaskSize: '100% 100%', maskImage: glowMask, maskRepeat: 'no-repeat', maskPosition: 'center bottom', maskSize: '100% 100%' }; }); var ACTIVE_ITEM_SELECTOR = '[data-blade-component="tab-nav-item"][data-active="true"]'; var TabNavIndicator = function TabNavIndicator(_ref3) { var containerRef = _ref3.containerRef; var _useTheme = useTheme(), theme = _useTheme.theme; var wrapperRef = React__default.useRef(null); var shouldAnimateRef = React__default.useRef(false); var _React$useState = React__default.useState(0), _React$useState2 = _slicedToArray(_React$useState, 2), activeWidth = _React$useState2[0], setActiveWidth = _React$useState2[1]; var _React$useState3 = React__default.useState(theme.colors.surface.background.primary.intense), _React$useState4 = _slicedToArray(_React$useState3, 2), glowColor = _React$useState4[0], setGlowColor = _React$useState4[1]; var glowMask = React__default.useMemo(function () { return buildGlowMask(activeWidth + GLOW_OVERFLOW * 2); }, [activeWidth]); var updatePosition = React__default.useCallback(function () { var _activeItem$dataset$g; var container = containerRef.current; var wrapper = wrapperRef.current; if (!container || !wrapper) return; var activeItem = container.querySelector(ACTIVE_ITEM_SELECTOR); if (!activeItem || activeItem.offsetWidth === 0) { wrapper.style.opacity = '0'; return; } var containerRect = container.getBoundingClientRect(); var activeRect = activeItem.getBoundingClientRect(); var x = activeRect.left - containerRect.left; var duration = shouldAnimateRef.current ? makeMotionTime(theme.motion.duration.gentle) : '0ms'; wrapper.style.transitionDuration = castWebType(duration); wrapper.style.width = "".concat(activeRect.width, "px"); wrapper.style.transform = "translateX(".concat(x, "px)"); wrapper.style.opacity = '1'; setActiveWidth(activeRect.width); setGlowColor((_activeItem$dataset$g = activeItem.dataset.glowColor) !== null && _activeItem$dataset$g !== void 0 ? _activeItem$dataset$g : theme.colors.surface.background.primary.intense); if (!shouldAnimateRef.current) { requestAnimationFrame(function () { shouldAnimateRef.current = true; }); } }, [containerRef, theme.motion.duration.gentle, theme.colors.surface.background.primary.intense]); useIsomorphicLayoutEffect(function () { void updatePosition(); }, [updatePosition]); // Watch for data-active attribute changes AND child additions/removals so the // indicator moves when: (a) active tab changes via router, (b) an item moves // into/out of the "More" overflow (the More button is added to the DOM with // data-active already set, so a pure attribute observer would miss it). React__default.useEffect(function () { var container = containerRef.current; if (!container) return; var rafId; var observer = new MutationObserver(function () { cancelAnimationFrame(rafId); rafId = requestAnimationFrame(function () { void updatePosition(); }); }); observer.observe(container, { attributes: true, attributeFilter: ['data-active'], childList: true, subtree: true }); return function () { cancelAnimationFrame(rafId); observer.disconnect(); }; }, [containerRef, updatePosition]); React__default.useEffect(function () { if ('fonts' in document) { try { void document.fonts.ready.then(function () { updatePosition(); }); } catch (_unused) { /* empty */ } } }, [updatePosition]); useResize(containerRef, updatePosition); return /*#__PURE__*/jsxs(StyledIndicatorWrapper, _objectSpread(_objectSpread({ ref: wrapperRef, style: { transitionProperty: 'transform, width, opacity', transitionTimingFunction: castWebType(theme.motion.easing.standard), transitionDuration: '0ms', opacity: 0 } }, metaAttribute({ name: MetaConstants.TabNavIndicator })), {}, { children: [activeWidth > 0 && /*#__PURE__*/jsx(StyledIndicatorGlow, { glowColor: glowColor, glowWidth: activeWidth, glowMask: glowMask }), /*#__PURE__*/jsx(StyledTabNavIndicatorLine, { style: { background: "linear-gradient(90deg, transparent 0%, ".concat(theme.colors.surface.icon.staticWhite.normal, " 20%, ").concat(theme.colors.surface.icon.staticWhite.normal, " 80.29%, transparent 100%)") } })] })); }; export { TabNavIndicator }; //# sourceMappingURL=TabNavIndicator.web.js.map