@gfazioli/mantine-split-pane
Version:
A Mantine 9 React component for resizable split pane layouts with 7 resizer variants, context-based prop inheritance, responsive orientation, and dynamic pane generation.
198 lines (195 loc) • 5.47 kB
JavaScript
'use client';
import { createVarsResolver, factory, useProps, useStyles, Box } from '@mantine/core';
import { useResizeObserver, useMergedRef } from '@mantine/hooks';
import React, { useState, useMemo, isValidElement, cloneElement } from 'react';
import { SplitDynamic } from './Dynamic/SplitDynamic.mjs';
import { useResponsiveValue } from './hooks/use-responsive-value.mjs';
import { useSplitResizerOrientation } from './hooks/use-split-resizer-orientation.mjs';
import { SplitPane } from './Pane/SplitPane.mjs';
import { defaultProps as defaultProps$1, SplitResizer } from './Resizer/SplitResizer.mjs';
import { SplitContextProvider } from './Split.context.mjs';
import classes from './Split.module.css.mjs';
const defaultProps = {
inline: false,
autoResizers: false,
...defaultProps$1
};
const varsResolver = createVarsResolver((_, { inline }) => ({
root: {
"--split-inline": inline ? "inline-flex" : "flex"
}
}));
const Split = factory((_props) => {
const { ref, ...restProps } = _props;
const props = useProps("Split", defaultProps, restProps);
const {
inline,
autoResizers,
orientation: propOrientation,
opacity,
size,
radius,
withKnob,
knobAlwaysOn,
knobSize,
knobOpacity,
knobRadius,
knobColor,
knobHoverColor,
spacing,
step,
shiftStep,
snapPoints,
snapTolerance,
snapFrom,
cursorVertical,
cursorHorizontal,
color,
hoverColor,
variant,
gradient,
hoverGradient,
classNames,
style,
styles,
unstyled,
vars,
mod,
children,
className,
...others
} = props;
const orientation = useSplitResizerOrientation(propOrientation ?? "vertical");
const resolvedSize = useResponsiveValue(size) ?? defaultProps$1.size;
const resolvedSpacing = useResponsiveValue(spacing) ?? defaultProps$1.spacing;
const resolvedKnobSize = useResponsiveValue(knobSize) ?? defaultProps$1.knobSize;
const [resizeObserverRef, containerRect] = useResizeObserver();
const [containerSize, setContainerSize] = useState({
width: 0,
height: 0
});
React.useEffect(() => {
if (containerRect.width > 0 || containerRect.height > 0) {
setContainerSize({ width: containerRect.width, height: containerRect.height });
}
}, [containerRect.width, containerRect.height]);
const mergedRef = useMergedRef(ref, resizeObserverRef);
const getStyles = useStyles({
name: "Split",
props,
classes,
className,
style,
classNames,
styles,
unstyled,
vars,
varsResolver
});
const childrenCount = React.Children.count(children);
const childRefs = useMemo(
() => Array.from(
{ length: childrenCount },
() => React.createRef()
),
[childrenCount]
);
let clonedChildren;
if (autoResizers) {
const elementsWithResizers = [];
let resizerIndex = 0;
let paneIndex = 0;
const paneRefs = [];
React.Children.forEach(children, (child, index) => {
if (isValidElement(child) && child.type === SplitPane) {
const ref2 = childRefs[index];
paneRefs.push(ref2);
elementsWithResizers.push(
cloneElement(child, {
key: child.key ?? `pane-${paneIndex}`,
ref: ref2
})
);
paneIndex++;
}
});
const finalElements = [];
elementsWithResizers.forEach((pane, index) => {
finalElements.push(pane);
if (index < elementsWithResizers.length - 1) {
const beforeRef = paneRefs[index];
const afterRef = paneRefs[index + 1];
finalElements.push(
/* @__PURE__ */ React.createElement(
SplitResizer,
{
key: `auto-resizer-${resizerIndex++}`,
__beforeRef: beforeRef,
__afterRef: afterRef
}
)
);
}
});
clonedChildren = finalElements;
} else {
clonedChildren = React.Children.map(children, (child, index) => {
if (isValidElement(child)) {
if (child.type === SplitResizer) {
const beforeRef = childRefs[index - 1];
const afterRef = childRefs[index + 1];
return cloneElement(child, {
__beforeRef: beforeRef,
__afterRef: afterRef
});
} else if (child.type === SplitPane) {
return cloneElement(child, {
ref: childRefs[index]
});
}
return child;
}
return child;
}) ?? [];
}
return /* @__PURE__ */ React.createElement(
SplitContextProvider,
{
value: {
orientation,
size: resolvedSize,
opacity,
radius,
color,
hoverColor,
knobSize: resolvedKnobSize,
knobOpacity,
knobRadius,
knobColor,
knobHoverColor,
variant,
withKnob,
knobAlwaysOn,
spacing: resolvedSpacing,
step,
shiftStep,
snapPoints,
snapTolerance,
snapFrom,
cursorVertical,
cursorHorizontal,
gradient,
hoverGradient,
containerSize
}
},
/* @__PURE__ */ React.createElement(Box, { ref: mergedRef, mod: { orientation }, ...getStyles("root"), ...others }, clonedChildren)
);
});
Split.classes = classes;
Split.displayName = "Split";
Split.Pane = SplitPane;
Split.Resizer = SplitResizer;
Split.Dynamic = SplitDynamic;
export { Split };
//# sourceMappingURL=Split.mjs.map