UNPKG

@navinc/base-react-components

Version:
151 lines (146 loc) 6.97 kB
var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { styled } from 'styled-components'; import { forwardRef, useCallback, useRef, useState } from 'react'; import { useDebouncedCallback } from 'use-debounce'; import { clamp } from '@navinc/utils'; import { useMediaQuery } from '../../use-media-query.js'; import useResizeObserver from 'use-resize-observer'; import { IconButton } from '../icon-button/icon-button.js'; import { elevation1 } from '../../themes/elevation.js'; import { mediaQueryFragments } from '../../themes/media.js'; const MoveButton = styled(IconButton).attrs((props) => (Object.assign({ density: 'loose' }, props))).withConfig({ displayName: "brc-sc-MoveButton", componentId: "brc-sc-7uy9dr" }) ` ${elevation1} border-radius: 100%; background: ${({ theme }) => theme.surfaceContainerHighest}; width: 40px; height: 40px; &:focus:not(:disabled), &:hover:not(:disabled) { background: linear-gradient(180deg, rgb(255 255 255 / 0%) 0%, rgb(27 27 31 / 4%) 100%), ${({ theme }) => theme.surfaceContainerHighest}; } &:active:not(:disabled) { background: linear-gradient(180deg, rgb(27 27 31 / 8%) 0%, rgb(27 27 31 / 8%) 100%), ${({ theme }) => theme.surfaceContainerHighest}; box-shadow: 0 0 0 1px rgb(0 0 0 / 30%), 0 4px 1px -2px rgb(0 0 0 / 8%); } `; const ContainerEl = styled.div.withConfig({ displayName: "brc-sc-ContainerEl", componentId: "brc-sc-gfsuqg" }) ` position: relative; `; const ControlsEl = styled.div.withConfig({ displayName: "brc-sc-ControlsEl", componentId: "brc-sc-16gr4do" }) ` position: absolute; inset: 0; display: flex; flex-direction: row; align-items: stretch; justify-content: space-between; pointer-events: none; `; const ContentEl = styled.div.withConfig({ displayName: "brc-sc-ContentEl", componentId: "brc-sc-ft7ann" }) ` overflow: scroll; -webkit-scrollbar-width: none; /* stylelint-disable-next-line plugin/no-unsupported-browser-features -- No support on iOS Safari, also using ::-webkit-scrollbar selector below */ scrollbar-width: none; /* Firefox */ -ms-overflow-style: none; /* Internet Explorer 10+ */ &::-webkit-scrollbar { /* WebKit */ width: 0; height: 0; } `; const FadeBase = styled.div.withConfig({ displayName: "brc-sc-FadeBase", componentId: "brc-sc-1qgazle" }) ` display: flex; align-items: center; pointer-events: none; width: 75px; height: 100%; transition: opacity 0.3s; opacity: 0; ${MoveButton} { pointer-events: none; } ${({ show }) => show && ` opacity: 1; ${MoveButton} { pointer-events: all; } `} `; const FadeLeft = styled(FadeBase).withConfig({ displayName: "brc-sc-FadeLeft", componentId: "brc-sc-1slbk2n" }) ` justify-content: flex-start; background: linear-gradient(to right, ${({ theme }) => theme.background} 0%, transparent 100%); `; const FadeRight = styled(FadeBase).withConfig({ displayName: "brc-sc-FadeRight", componentId: "brc-sc-1fusqq1" }) ` justify-content: flex-end; background: linear-gradient(to left, ${({ theme }) => theme.background} 0%, transparent 100%); `; const MaxContent = styled.div.withConfig({ displayName: "brc-sc-MaxContent", componentId: "brc-sc-w8lngf" }) ` width: max-content; `; const Content = (_a) => { var { childRef, children, onResize } = _a, props = __rest(_a, ["childRef", "children", "onResize"]); useResizeObserver({ ref: childRef, onResize }); return (_jsx(ContentEl, Object.assign({ ref: childRef }, props, { children: _jsx(MaxContent, { children: children }) }))); }; const Controls = ({ showLeft, showRight, onLeftClick, onRightClick, }) => { return (_jsxs(ControlsEl, { children: [_jsx(FadeLeft, { show: showLeft, children: _jsx(MoveButton, { tabIndex: showLeft ? undefined : -1, name: "chevron_left", onClick: onLeftClick, children: "Left" }) }), _jsx(FadeRight, { show: showRight, children: _jsx(MoveButton, { tabIndex: showRight ? undefined : -1, name: "chevron_right", onClick: onRightClick, children: "Right" }) })] })); }; export const HorizontalScrollWidget = styled(forwardRef((_a, forwardedRef) => { var { children } = _a, props = __rest(_a, ["children"]); const [state, setState] = useState({ showLeft: false, showRight: false, scrollPosition: 0, }); const ref = useRef(null); const scrollingTo = useRef(null); const recalculate = useDebouncedCallback(useCallback(() => { if (ref.current) { const shouldShowLeft = ref.current.scrollLeft > 0; const shouldShowRight = ref.current.scrollLeft < ref.current.scrollWidth - ref.current.clientWidth; if (state.showLeft !== shouldShowLeft) { setState((state) => (Object.assign(Object.assign({}, state), { showLeft: shouldShowLeft }))); } if (state.showRight !== shouldShowRight) { setState((state) => (Object.assign(Object.assign({}, state), { showRight: shouldShowRight }))); } } }, [state, ref]), 50, { maxWait: 100 }); const clearScrollingTo = useDebouncedCallback(() => { scrollingTo.current = null; }, 50); const isLargerThanPhone = useMediaQuery(mediaQueryFragments.largerThanPhone); const scroll = (direction) => { var _a; if (ref.current) { let scrollLeft = (_a = scrollingTo.current) !== null && _a !== void 0 ? _a : ref.current.scrollLeft; const pageWidth = ref.current.clientWidth * 0.75; scrollLeft += direction === 'left' ? -pageWidth : pageWidth; scrollLeft = clamp(0, ref.current.scrollWidth - ref.current.clientWidth)(scrollLeft); ref.current.scrollTo({ left: scrollLeft, behavior: 'smooth' }); scrollingTo.current = scrollLeft; } }; return (_jsxs(ContainerEl, Object.assign({ ref: forwardedRef }, props, { children: [_jsx(Content, { childRef: ref, onResize: recalculate, onScroll: () => { clearScrollingTo(); recalculate(); }, "data-testid": "horizontal-scroll-widget:content", children: children }), isLargerThanPhone && (_jsx(Controls, { showLeft: state.showLeft, showRight: state.showRight, onLeftClick: () => scroll('left'), onRightClick: () => scroll('right') }))] }))); })).withConfig({ displayName: "brc-sc-HorizontalScrollWidget", componentId: "brc-sc-1o8u15f" }) ``; //# sourceMappingURL=horizontal-scroll-widget.js.map