@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
124 lines (123 loc) • 5.75 kB
JavaScript
"use client";
import _extends from "@babel/runtime-corejs3/helpers/esm/extends";
import React, { useCallback, useContext, useRef, useState } from 'react';
import classnames from 'classnames';
import ScrollView from "../../fragments/scroll-view/ScrollView.js";
import { useIsomorphicLayoutEffect as useLayoutEffect } from "../../shared/helpers/useIsomorphicLayoutEffect.js";
import { ListContext } from "./ListContext.js";
const defaultListItemOutlineCompensation = '0.125rem';
function ListScrollView(props) {
var _parentContext$varian, _parentContext$separa;
const parentContext = useContext(ListContext);
const {
className,
children,
maxVisibleListItems,
skeleton,
disabled,
style,
innerRef,
...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;
}
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 (!innerRef) {
return;
}
if (typeof innerRef === 'function') {
innerRef(localRef.current);
return;
}
innerRef.current = localRef.current;
}, [innerRef]);
useLayoutEffect(() => {
measureMaxHeight();
}, [children, measureMaxHeight]);
useLayoutEffect(() => {
if (!hasValidMaxVisibleListItems || style !== null && style !== void 0 && style.maxHeight) {
return;
}
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 = React.createElement(ScrollView, _extends({
className: classnames("dnb-list__card__scroll-view dnb-list--inset-outline", className),
interactive: "auto",
ref: localRef,
style: scrollViewStyle
}, rest), 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 React.createElement(ListContext.Provider, {
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
}
}, 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