UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

127 lines (126 loc) 5.71 kB
"use client"; import React, { useCallback, useContext, useRef, useState } from 'react'; import clsx from 'clsx'; import ScrollView from "../../fragments/scroll-view/ScrollView.js"; import { useIsomorphicLayoutEffect as useLayoutEffect } from "../../shared/helpers/useIsomorphicLayoutEffect.js"; import { ListContext } from "./ListContext.js"; import { jsx as _jsx } from "react/jsx-runtime"; const defaultListItemOutlineCompensation = '0.125rem'; function ListScrollView(props) { var _parentContext$varian, _parentContext$separa; const parentContext = useContext(ListContext); const { className, children, maxVisibleListItems, skeleton, disabled, style, ref, ...rest } = props; const localRef = useRef(null); const [measuredMaxHeight, setMeasuredMaxHeight] = useState(undefined); const [outlineCompensation, setOutlineCompensation] = useState(defaultListItemOutlineCompensation); const hasValidMaxVisibleListItems = typeof maxVisibleListItems === 'number' && Number.isFinite(maxVisibleListItems) && maxVisibleListItems > 0; const fallbackMaxHeight = hasValidMaxVisibleListItems ? `calc(var(--item-height, 4rem) * ${maxVisibleListItems})` : undefined; const measureMaxHeight = useCallback(() => { if (!hasValidMaxVisibleListItems || style !== null && style !== void 0 && style.maxHeight) { setMeasuredMaxHeight(undefined); return undefined; } setOutlineCompensation(getListItemOutlineCompensation(localRef.current)); const measuredHeight = getVisibleListItemsHeight(localRef.current, maxVisibleListItems); setMeasuredMaxHeight(measuredHeight ? `${measuredHeight}px` : undefined); }, [hasValidMaxVisibleListItems, maxVisibleListItems, style === null || style === void 0 ? void 0 : style.maxHeight]); useLayoutEffect(() => { if (!ref) { return undefined; } if (typeof ref === 'function') { ref(localRef.current); return undefined; } ref.current = localRef.current; }, [ref]); useLayoutEffect(() => { measureMaxHeight(); }, [children, measureMaxHeight]); useLayoutEffect(() => { if (!hasValidMaxVisibleListItems || style !== null && style !== void 0 && style.maxHeight) { return undefined; } window.addEventListener('resize', measureMaxHeight); return () => { window.removeEventListener('resize', measureMaxHeight); }; }, [hasValidMaxVisibleListItems, measureMaxHeight, style === null || style === void 0 ? void 0 : style.maxHeight]); const resolvedMaxHeight = style !== null && style !== void 0 && style.maxHeight ? undefined : measuredMaxHeight || fallbackMaxHeight; const scrollViewStyle = { ...(resolvedMaxHeight ? { maxHeight: `calc(${resolvedMaxHeight} + ${outlineCompensation})`, marginBottom: `-${outlineCompensation}` } : null), ...style }; const scrollViewContent = _jsx(ScrollView, { className: clsx("dnb-list__card__scroll-view dnb-list--inset-outline", className), interactive: "auto", ref: localRef, style: scrollViewStyle, ...rest, children: children }); const appliedSkeleton = skeleton !== null && skeleton !== void 0 ? skeleton : parentContext === null || parentContext === void 0 ? void 0 : parentContext.skeleton; const appliedDisabled = disabled !== null && disabled !== void 0 ? disabled : parentContext === null || parentContext === void 0 ? void 0 : parentContext.disabled; return _jsx(ListContext, { value: { variant: (_parentContext$varian = parentContext === null || parentContext === void 0 ? void 0 : parentContext.variant) !== null && _parentContext$varian !== void 0 ? _parentContext$varian : 'basic', separated: (_parentContext$separa = parentContext === null || parentContext === void 0 ? void 0 : parentContext.separated) !== null && _parentContext$separa !== void 0 ? _parentContext$separa : false, skeleton: appliedSkeleton, disabled: appliedDisabled }, children: scrollViewContent }); } function getVisibleListItemsHeight(scrollViewElement, maxVisibleListItems) { if (!scrollViewElement) { return null; } const listElement = scrollViewElement.querySelector('.dnb-list__container'); if (!(listElement instanceof HTMLElement)) { return null; } const items = Array.from(listElement.children).filter(element => element instanceof HTMLElement); const firstVisibleItem = items[0]; const lastVisibleItem = items[maxVisibleListItems - 1]; if (!firstVisibleItem || !lastVisibleItem) { return null; } return Math.ceil(lastVisibleItem.offsetTop + lastVisibleItem.offsetHeight - firstVisibleItem.offsetTop); } function getListItemOutlineCompensation(scrollViewElement) { if (!scrollViewElement || typeof getComputedStyle === 'undefined') { return defaultListItemOutlineCompensation; } const cardElement = scrollViewElement.closest('.dnb-card'); const targetElement = (cardElement === null || cardElement === void 0 ? void 0 : cardElement.querySelector('.dnb-list__container')) || scrollViewElement.querySelector('.dnb-list__container'); if (!(targetElement instanceof HTMLElement)) { return defaultListItemOutlineCompensation; } const outlineWidth = getComputedStyle(targetElement).getPropertyValue('--item-outline-width').trim(); return doubleCssLength(outlineWidth) || defaultListItemOutlineCompensation; } function doubleCssLength(value) { if (!value) { return null; } const match = value.match(/^(-?\d*\.?\d+)([a-z%]+)$/i); if (match) { return `${parseFloat(match[1]) * 2}${match[2]}`; } return `calc(${value} * 2)`; } ListScrollView._supportsSpacingProps = true; export default ListScrollView; //# sourceMappingURL=ListScrollView.js.map