UNPKG

@sap-ux/ui-components

Version:
882 lines 34.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.UISections = exports.ANIMATION_TIME = void 0; const react_1 = __importDefault(require("react")); const react_2 = require("@fluentui/react"); const UISection_1 = require("./UISection"); const UISplitter_1 = require("./UISplitter"); require("./UISections.scss"); exports.ANIMATION_TIME = 300; const SECTIONS_ANIMATION_CLASS = 'sections--animated'; /** * UISections component. * * @exports * @class {UISections} * @extends {React.Component<UISectionsProps, UISectionsState>} */ class UISections extends react_1.default.Component { /** * Initializes component properties. * * @param {UISectionsProps} props */ constructor(props) { super(props); this.resizeSections = []; this.isFullScreen = false; this.rootSize = 0; this.ignoreAnimation = false; this.state = { sizes: undefined }; this.onWindowResize = this.onWindowResize.bind(this); this.rootRef = react_1.default.createRef(); this.sizeProperty = props.vertical ? 'height' : 'width'; this.domSizeProperty = props.vertical ? 'clientHeight' : 'clientWidth'; this.startPositionProperty = props.vertical ? 'top' : 'left'; this.endPositionProperty = props.vertical ? 'bottom' : 'right'; this.sizeProperty = props.vertical ? 'height' : 'width'; window.addEventListener('resize', this.onWindowResize); } /** * Updates state sizes. * * @param newSize Latest size of root * @param sizes Sizes of sections * @param oldSize Old size of root before resize of window * @returns Calculated sizes and position for all sections */ updateStateSizes(newSize, sizes, oldSize = newSize) { let uiSizes = sizes; const dynamicSectionIndex = this.getDynamicSectionIndex(); // Calculate size for dynamic section let availableSize = 0; sizes.forEach((section, index) => { if (typeof section === 'object' && section.size === undefined) { section.size = this.getSize(section, oldSize); } if (index !== dynamicSectionIndex) { availableSize += (typeof section === 'object' ? section.size : section) ?? 0; } }); availableSize = newSize - availableSize; // Check if number array is passed as sizes. Convert array of number to array of UISectionSize if (typeof sizes[0] !== 'object') { uiSizes = []; let start = 0; sizes.forEach((size, index) => { size = dynamicSectionIndex !== index ? size : availableSize; uiSizes.push({ percentage: false, size, start }); start += size || 0; }); } // Apply size for dynamic section const dynamicSection = uiSizes[dynamicSectionIndex]; if (dynamicSection) { dynamicSection.size = availableSize; } // Recalculate start and end positions this.recalculatePositions(uiSizes); // Validate min sizes this.validateStateMinSizes(uiSizes); return uiSizes; } componentDidMount() { const { sizesAsPercents, sizes } = this.props; this.rootSize = this.getRootSize(); if (!sizesAsPercents && sizes) { // Calculate state this.setState({ sizes: this.updateStateSizes(this.rootSize, sizes) }); } } /** * React lifecycle method that is invoked immediately after updating occurs. * This method is used to determine if the section sizes need to be recalculated * when the external prop sizes have changed. * * @param prevProps The previous props of the component before the update. * @param prevState The previous state of the component before the update. */ componentDidUpdate(prevProps, prevState) { this.ignoreAnimation = false; const externalSizes = this.props.sizes ?? []; const sizes = this.state.sizes ?? []; const prevSizes = prevProps.sizes ?? []; const prevVisibleSections = prevState.visibleSections ?? []; const visibleSections = this.state.visibleSections ?? []; let newSizes; // Recalculate sizes when external sizes changed const isExternalSizesChanged = externalSizes !== prevSizes && (externalSizes.length !== prevSizes.length || externalSizes.some((size, index) => size !== prevSizes[index])); // Recalculate sizes when visibility of sections are changed const isSectionsVisibilityToggled = prevVisibleSections.length !== visibleSections.length || prevVisibleSections.some((index) => !visibleSections.includes(index)); if (isExternalSizesChanged || isSectionsVisibilityToggled) { newSizes = this.updateStateSizes(this.rootSize, isExternalSizesChanged ? externalSizes : sizes); } if (newSizes) { // State sizes are updated this.setState({ sizes: newSizes }); // Update cached section's sizes for (let i = 0; i < newSizes.length; i++) { if (this.resizeSections[i]) { this.resizeSections[i].section = newSizes[i]; } } } } /** * Gets derived state from properties. * * @param {UISectionProps} nextProps * @param {UISectionsState} prevState * @returns {UISectionsState | null} */ static getDerivedStateFromProps(nextProps, prevState) { // Handle property "animation" as array let animate = prevState.animate; const visibleSections = UISections.getVisibleSections(nextProps.children); let dynamicSection = 0; if (Array.isArray(nextProps.animation)) { // Check if there is transition for section with enabled animation let transitionAnimation; for (let i = 0; i < nextProps.animation.length; i++) { if (visibleSections?.includes(i) !== prevState.visibleSections?.includes(i)) { transitionAnimation = transitionAnimation || nextProps.animation[i]; } } if (transitionAnimation !== undefined) { // Visibility of sections changed - apply animation for transition section animate = transitionAnimation; } } else { animate = nextProps.animation; } // Find dynamic section index nextProps.sizes?.forEach((size, index) => { if (size === undefined) { dynamicSection = index; } }); return { animate, visibleSections, dynamicSection }; } /** * Validates state min sizes. * * @param {UISectionSize[]} sizes */ validateStateMinSizes(sizes) { // Prerequisite. Get size infos let minSizesSum = 0; let recalculateSizes = false; const sizesInfo = []; for (let i = 0; i < this.props.children.length; i++) { const size = sizes[i]?.size ?? 0; const minSize = this.getMinSectionSize(i); if (minSize > size) { recalculateSizes = true; } minSizesSum += minSize; // Sizes data sizesInfo.push({ size, minSize, spareSize: size - minSize }); } // First Part. Check if full screen required const layoutSize = this.getRootSize(); // Second Part. Calculate sections which less than min size. if (recalculateSizes && layoutSize >= minSizesSum) { const recalculatedSizes = this.calculateSectionSizes(sizesInfo); for (let i = 0; i < sizes.length; i++) { sizes[i] = recalculatedSizes[i]; } } // Check full screen toggle const isFullScreen = layoutSize < minSizesSum; if (isFullScreen !== this.isFullScreen) { this.isFullScreen = isFullScreen; this.props.onToggleFullscreen?.(isFullScreen); } } onWindowResize() { let { sizes } = this.state; // Dynamic section index const oldSize = this.rootSize; this.rootSize = this.getRootSize(); if (sizes) { // Update sizes after resize sizes = this.updateStateSizes(this.rootSize, sizes, oldSize); // Update cached section's sizes for (let i = 0; i < sizes.length; i++) { if (this.resizeSections[i]) { this.resizeSections[i].section = sizes[i]; } } // Apply state this.ignoreAnimation = true; this.setState({ sizes: sizes }); } } /** * Method returns indices of visible sections. * * @param {React.ReactNodeArray} sections Section elements. * @returns {number[]} Indices of visible sections. */ static getVisibleSections(sections) { const visibleSections = []; sections.forEach((child, i) => { if (!UISections.isSectionVisible(child)) { visibleSections.push(i); } }); return visibleSections; } /** * Method checks is passed child section visible or not. * * @param {React.ReactElement | undefined} node React child node. * @returns {boolean} True if section visible. */ static isSectionVisible(node) { if (node && node.type === UISection_1.UISection) { return !node.props.hidden; } return false; } /** * Method called when resizing of section started. */ onSplitterResizeStart() { const rootDom = this.rootRef.current; const resizeSections = []; if (rootDom?.childNodes) { rootDom.classList.remove(SECTIONS_ANIMATION_CLASS); for (let i = 0; i < rootDom.childNodes.length; i++) { const minSectionSize = this.getMinSectionSize(i); const siblingMinSectionSize = this.getMinSectionSize(i === 0 ? 1 : 0); const sectionDom = rootDom.children[i]; const maxSize = Math.max(minSectionSize, rootDom[this.domSizeProperty] - siblingMinSectionSize); resizeSections.push({ size: sectionDom[this.domSizeProperty], dom: sectionDom, maxSize, section: this.resizeSections[i] ? this.resizeSections[i].section : { percentage: false } }); } } this.resizeSections = resizeSections; } /** * Method called when resizing of section is happening. * * @param {number} index Index of splitter. * @param {number} position Delta position in pixels. * @returns {boolean} If resizing was happened - it can return false when splitter meets resizing limitation. */ onSplitterResize(index, position) { const resizeSections = position !== 0 ? this.resizeSections : []; const totalSize = this.rootSize; let left = this.getSiblingsSize(resizeSections, 0, index, true); this.refreshResizeSections(0, index, this.state.sizes); let minSizeTriggered = false; for (let i = index; i < resizeSections.length; i++) { const sectionSize = { percentage: false }; const resizeSection = resizeSections[i]; const minSectionSize = this.getMinSectionSize(i); const maxSectioSize = this.getMaxSectionSize(i, minSectionSize, index); if (minSectionSize === maxSectioSize) { // Ignore resize - section is not resizable left += minSectionSize; continue; } let newSize = resizeSection.size; if (i === index) { newSize = resizeSection.size + position; } else if (i === index + 1 || minSizeTriggered) { newSize = resizeSection.size - position; } // Do not allow size exceed min and max boundaries minSizeTriggered = false; if (newSize < minSectionSize) { position = this.correctBoundaryPosition(position, minSectionSize, newSize, i === index); newSize = minSectionSize; minSizeTriggered = true; } else if (newSize > maxSectioSize) { position = this.correctBoundaryPosition(position, maxSectioSize, newSize, i === index); newSize = maxSectioSize; } let right = 0; if (resizeSections[i + 1]) { right = totalSize - left - newSize; } this.updateSectionSize(sectionSize, i, { size: newSize, start: left, end: right, percentage: false }); resizeSection.dom.style[this.startPositionProperty] = sectionSize.start + 'px'; resizeSection.dom.style[this.endPositionProperty] = sectionSize.end + 'px'; resizeSection.dom.style[this.sizeProperty] = ''; resizeSection.section = sectionSize; left += newSize; } return false; } /** * Method returns corrected position based on boundary and size. * * @param {number} position Delta position in pixels. * @param {number} boundary Boundary position. * @param {number} size Section size. * @param {boolean} positive Direction. * @returns {number} Position after correction based on boundary. */ correctBoundaryPosition(position, boundary, size, positive) { const diff = boundary - size; return position + (positive ? diff : -diff); } /** * Method called when resizing session ended. */ onSplitterResizeEnd() { const rootDom = this.rootRef.current; if (rootDom && this.isAnimationEnabled()) { rootDom.classList.add(SECTIONS_ANIMATION_CLASS); } const sizes = this.resizeSections.map((resizeSection) => resizeSection.section); if (sizes.some((size) => size.end !== undefined || size.start !== undefined || size.size !== undefined)) { this.setState({ sizes }); } this.props.onResize?.(sizes); } /** * Method called when splitter with type 'Toggle' was toggled. */ onSplitterToggle() { if (this.props.onClose) { this.props.onClose(); } } /** * Method returns visible children sections count. * * @returns {number} Count of visible children sections. */ getVisibleChildrenCount() { return this.props.children.filter((child) => child && UISections.isSectionVisible(child)) .length; } /** * Method returns size of section in percents. * * @param {number} index Target section index. * @param {number} childrenCount Count of children. * @param {boolean} [reverse] Reverse calculation(width vs right). * @returns {number} Size of section in percents. For example 50% => 0.5. */ getSizePercents(index, childrenCount, reverse = false) { const { sizes = [], sizesAsPercents } = this.props; let propSize = sizes[index]; if (propSize === undefined && index === this.state.dynamicSection) { // Find available size let newSize = 100; sizes.every((size) => { if (size) { newSize -= size; } }); propSize = newSize; } if (propSize && sizesAsPercents) { return reverse ? 100 - propSize : propSize; } return childrenCount > 0 ? 100 / childrenCount : 0; } /** * Method gets section size when section size is not percent based and 'sizes' prop is passed from outside. * * @param {number} index Section index to look up. * @param {number} childrenCount Count of visible children. * @returns {React.CSSProperties | undefined} CSS Style object or undefined if no style from 'sizes' prop. */ getSectionSize(index, childrenCount) { const { sizes } = this.state; if (!sizes || this.props.sizesAsPercents || !this.props.sizes || childrenCount < 2) { return undefined; } const result = {}; if (sizes[index].start !== undefined) { result[this.startPositionProperty] = sizes[index].start; } if (sizes[index].end !== undefined) { result[this.endPositionProperty] = sizes[index].end; } return result; } /** * Gets position style value. * * @param {number} childrenCount * @param {string} value * @returns {string} */ getPositionStyleValue(childrenCount, value) { return childrenCount === 1 ? '0%' : value; } /** * Method returns style object for passed visible section. * Method calculates size of section depending on several points. * 1. Section - resized or not. * 2. Animation - off or on. * * @param {number} index Index of section. * @returns {SectionStyleCalculation} Object which contains visibility state and styles to apply. */ getVisibleSectionStyle(index) { const sectionStyle = { visible: true, style: {} }; // Use values from state or calculate initial percents const childrenCount = this.getVisibleChildrenCount(); const stateSize = this.state.sizes?.[index]; if (childrenCount === this.props.children.length && stateSize) { sectionStyle.style = { ...(stateSize.start !== undefined && { [this.startPositionProperty]: stateSize.start + 'px' }), ...(stateSize.end !== undefined && { [this.endPositionProperty]: stateSize.end + 'px' }) }; if (stateSize.size !== undefined && (stateSize.start === undefined || stateSize.end === undefined)) { // No need to provide size if start and end defined sectionStyle.style[this.sizeProperty] = stateSize.size + 'px'; } } else { let usePercents = true; if (stateSize) { const toggleSectionSize = this.getSectionSize(index, childrenCount); if (toggleSectionSize) { sectionStyle.style = { ...sectionStyle.style, ...toggleSectionSize }; usePercents = false; } } if (usePercents) { const size = this.getSizePercents(index, childrenCount, true); sectionStyle.style = { [this.startPositionProperty]: this.getPositionStyleValue(childrenCount, `${index * size}%`), [this.endPositionProperty]: this.getPositionStyleValue(childrenCount, `${(childrenCount - (index + 1)) * size}%`) }; } } return sectionStyle; } /** * Method returns style object for passed hidden section. * Method calculates size of section depending on several points. * 1. Section - resized or not. * 2. Animation - off or on. * * @param {number} index Index of section. * @returns {SectionStyleCalculation} Object which contains visibility state and styles to apply. */ getHiddenSectionStyle(index) { const sectionStyle = { visible: false }; // Hidden section when animation is ON let stateSize = this.state.sizes?.[index]; if (!stateSize && this.props.splitterType === UISplitter_1.UISplitterType.Toggle && this.props.sizes?.[index]) { stateSize = { size: this.props.sizes[index], percentage: false }; } let unit; let size = 0; if (stateSize) { unit = 'px'; if (stateSize.size) { size = stateSize.size; } else if (stateSize?.start !== undefined && stateSize?.end !== undefined) { size = this.getRootSize() - stateSize.end - stateSize.start; } } else { const childrenCount = this.props.children.length; size = this.getSizePercents(index, childrenCount); unit = '%'; } const hiddenPosition = -size + unit; sectionStyle.style = { [this.endPositionProperty]: index === 0 ? '100%' : hiddenPosition, [this.startPositionProperty]: index === 0 ? hiddenPosition : '100%' }; return sectionStyle; } /** * Method returns minimal size for passed section. * * @param {number} index Index of section. * @returns {number} Minimal size of section. */ getMinSectionSize(index) { const minSectionSize = this.props.minSectionSize; let minSize = 0; if (minSectionSize) { minSize = Array.isArray(minSectionSize) ? minSectionSize[index] : minSectionSize; } return minSize; } /** * Method returns class names string depending on props and component state. * * @param {boolean} fullSizeMode Is full size mode - only ine sction visible. * @returns {number} Minimal size of section. */ getClassNames(fullSizeMode) { let classNames = ` ${this.props.vertical ? 'sections--vertical' : 'sections--horizontal'}`; // Animation const sectionsAnimationClass = ` ${SECTIONS_ANIMATION_CLASS}`; classNames += `${this.isAnimationEnabled() ? sectionsAnimationClass : ''}`; // Full 'screen' mode - only one section visible classNames += `${fullSizeMode ? ' sections--full' : ''}`; return classNames; } /** * Method returns section's react element based on passed section index. * * @param {number} index Section index. * @param {boolean} isSectionHidden Is section hidden. * @returns {React.ReactElement | undefined} Section's react element. */ getSection(index, isSectionHidden) { const childNode = this.props.children[index]; const sectionStyle = UISections.isSectionVisible(childNode) ? this.getVisibleSectionStyle(index) : this.getHiddenSectionStyle(index); if (!sectionStyle) { return undefined; } const { splitter, vertical, splitterTitle, splitterType = UISplitter_1.UISplitterType.Resize, splitterTabIndex, splitterLayoutType = UISplitter_1.UISplitterLayoutType.Standard } = this.props; let isSplitterVisible = splitter && index > 0; const isSingleSection = this.getVisibleChildrenCount() === 1; if (isSingleSection && !this.isAnimationEnabled()) { isSplitterVisible = false; } return (react_1.default.createElement("div", { key: index, className: `sections__item${isSplitterVisible ? ' sections__item--' + splitterType : ''}${!sectionStyle.visible ? ' sections__item--hidden' : ''}`, style: sectionStyle.style }, isSplitterVisible && childNode && (react_1.default.createElement(UISplitter_1.UISplitter, { vertical: vertical, onResize: this.onSplitterResize.bind(this, index - 1), onResizeStart: this.onSplitterResizeStart.bind(this), onResizeEnd: this.onSplitterResizeEnd.bind(this), onToggle: this.onSplitterToggle.bind(this), hidden: isSectionHidden || isSingleSection || !this.isSectionVisible(index - 1), type: splitterType, splitterTabIndex: splitterTabIndex, title: splitterTitle, splitterLayoutType: splitterLayoutType })), childNode)); } /** * Method checks if animation enabled with current state. * * @returns {boolean} True if animation is enabled. */ isAnimationEnabled() { return !this.ignoreAnimation && (this.props.animation === true || this.state.animate); } /** * Method returns index of dynamicly sized section. * * @returns {number} Index of dynamicly sized section. */ getDynamicSectionIndex() { return this.state.dynamicSection !== undefined ? this.state.dynamicSection : 0; } /** * Method calculates spare size for passed section. * * @param {SizeCalculationInfo} origin Section size. * @param {SizeCalculationInfo[]} sizes All section sizes. * @returns {number} Spare size. */ getSpareSize(origin, sizes) { let increaseSize = 0; let target = origin.minSize - origin.size; for (const info of sizes) { if (info === origin) { continue; } if (info.spareSize > 0) { const useSize = Math.min(info.spareSize, target); // Update targets increaseSize += useSize; info.spareSize -= useSize; info.size -= useSize; target -= useSize; } if (target <= 0) { // Desireable target meet requirement break; } } return increaseSize; } /** * Method converts SizeCalculationInfo into UISectionSize before applying sizes to state. * * @param {SizeCalculationInfo[]} sizes Section sizes. * @returns {UISectionSize[]} Section sizes applyable for state. */ calculateSectionSizes(sizes) { // Calculate sizes for (const section of sizes) { if (section.size < section.minSize) { const diff = this.getSpareSize(section, sizes); if (diff) { section.size += diff; } } } // Apply sizes to state const stateSizes = []; for (let i = 0; i < sizes.length; i++) { const sectionSize = { percentage: false }; const current = sizes[i]; const right = this.getSiblingsSize(sizes, i + 1, sizes.length); if (i > 0) { sectionSize.size = current.size; sectionSize.start = undefined; } else { sectionSize.start = 0; } sectionSize.end = right; stateSizes.push(sectionSize); } return stateSizes; } /** * Method recalculates "start" and "end" position based on size property. * * @param {UISectionSize[]} sizes Section sizes. */ recalculatePositions(sizes) { sizes.forEach((section, index) => { if (this.isSectionVisible(index)) { section.start = this.getSectionPosition(index, sizes, true); section.end = this.getSectionPosition(index, sizes, false); } // else { // section.start = 0; // section.end = 0; // } }); } /** * Method returns size of sections container. * * @returns {UISectionSize[]} Size of sections container. */ getRootSize() { const rootDom = this.rootRef.current; return rootDom?.getBoundingClientRect()[this.sizeProperty] ?? 0; } /** * @returns {React.ReactElement} */ render() { const divProps = (0, react_2.getNativeProps)(this.props, react_2.divProperties, [ 'className', 'children' ]); const sections = []; let visibleSections = 0; for (let i = 0; i < this.props.children.length; i++) { const isSectionHidden = !this.isSectionVisible(i); if (!isSectionHidden) { visibleSections++; } const section = this.getSection(i, isSectionHidden); if (section) { sections.push(section); } } return (react_1.default.createElement("div", { ...divProps, ref: this.rootRef, className: `sections ${this.getClassNames(visibleSections === 1)}`, style: { ...(this.props.height && { height: this.props.height }) } }, sections)); } /** * Calculates the total size of sibling elements within a specified range. * * @param sizes An array of objects, each containing 'size` property. * @param start The starting index (inclusive) of the range. * @param end The ending index (exclusive) of the range. * @param onlyVisible Calculate only visible sections. * @returns The sum of the sibling sizes for the specified range. */ getSiblingsSize(sizes, start, end, onlyVisible = false) { let size = 0; for (let j = start; j < end; j++) { const next = sizes[j]; if (next?.size && (!onlyVisible || this.isSectionVisible(j))) { size += next.size; } } return size; } /** * Refreshes the resize sections by updating their sizes from a provided range. * * @param start The starting index (inclusive) of the sections to refresh. * @param end The ending index (exclusive) of the sections to refresh. * @param sizes An array of section sizes to apply. */ refreshResizeSections(start, end, sizes = []) { for (let i = start; i < end; i++) { if (sizes[i]) { this.resizeSections[i].section = sizes[i]; } } } /** * Calculates the maximum allowable size for a section at the specified index. * * @param index The index of the section to calculate the maximum size for. * @param minSectionSize The minimum size of the section. * @param splitterIndex Optional index of the splitter; if specified, the section at this index is not considered resizable. * @returns The maximum size the section can expand to, constrained by available space and other sections. */ getMaxSectionSize(index, minSectionSize, splitterIndex) { const resizeSection = this.resizeSections[index]; if (resizeSection && index !== splitterIndex) { return Math.max(minSectionSize, resizeSection.maxSize); } // Calculate max size based on current DOM const rootDom = this.rootRef.current; const mainSize = rootDom?.[this.domSizeProperty] ?? 0; const resizeSections = this.resizeSections; let reservedSize = 0; for (let i = 0; i < index; i++) { if (this.isSectionVisible(i)) { reservedSize += resizeSections[i].size; } } for (let i = index + 1; i < resizeSections.length; i++) { if (this.isSectionVisible(i)) { reservedSize += this.getMinSectionSize(i); } } return Math.max(minSectionSize, mainSize - reservedSize); } /** * Updates the size and position of section. * * @param sectionSize The section object to be updated. * @param index The index of the section. * @param newSize The new size and position values for the section. */ updateSectionSize(sectionSize, index, newSize) { if (index > 0) { sectionSize.size = newSize.size; sectionSize.start = newSize.start; } else { sectionSize.start = 0; } sectionSize.end = newSize.end; if (this.isSectionVisible(index) && sectionSize.end !== undefined && sectionSize.start !== undefined) { sectionSize.size = Math.abs(this.rootSize - sectionSize.end - sectionSize.start); } } /** * Determines whether a specific section is visible. * * @param {number} index - The index of the child node to check. * @returns {boolean} - Returns `true` if the section is visible, otherwise `false`. */ isSectionVisible(index) { const childNode = this.props.children[index]; return childNode ? UISections.isSectionVisible(childNode) : false; } /** * Calculates the position of a section, either from the start or the end. * * @param index The index of the section. * @param sizes An array of section size objects. * @param start Determines whether to calculate from the start (true) or the end (false). * @returns The calculated position of the section. */ getSectionPosition(index, sizes, start) { let visibleSize = 0; let hiddenSize = 0; let totalHiddenSize = 0; const iterate = (i) => { const size = this.getSize(sizes[i]); if (this.isSectionVisible(i)) { visibleSize += size; totalHiddenSize += hiddenSize; hiddenSize = 0; } else { hiddenSize += size; } }; if (start) { for (let i = 0; i < index; i++) { iterate(i); } } else { for (let i = sizes.length - 1; i > index; i--) { iterate(i); } } return visibleSize + totalHiddenSize; } /** * Returns the size of a section based on its properties(size, start, end). * * @param sizes The section size object containing size, start, and end properties. * @param rootSize Size of root container. * @returns The computed size of the section. Returns 0 if no valid size is found. */ getSize(sizes, rootSize = this.rootSize) { if (sizes.size !== undefined) { return sizes.size; } if (sizes.end !== undefined && sizes.start !== undefined) { return Math.abs(rootSize - sizes.end - sizes.start); } return 0; } } exports.UISections = UISections; UISections.Section = UISection_1.UISection; //# sourceMappingURL=UISections.js.map