mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-27 12:39:49 +08:00
feat:🔥New Component: Splitter (#50038)
* feat: SplitPanel init
* feat: SplitPanel update
* feat: SplitPanel update
* feat: splitPanel update useResize
* feat: SplitPanel update
* feat: splitPanel update useResize
* feat: SplitPanel update
* feat: splitPanel demo
* feat: splitPanel update
* feat: splitPanel support complicated combination
* feat: SplitPanel rename to Splitter
* feat: Splitter support onRize
* feat: support collapsible
* feat: support token and collapsible
* feat: update docs
* feat: size defaultSize support string
* feat: min max support string
* feat: update
* feat: support DOM structure
* feat: Optimize UI
* feat: Optimize Code
* fix: Add a default size during initialization to prevent failure to obtain container size
* feat: optimized code
* feat: optimized code
* feat: Optimize Code
* Update components/splitter/demo/layout.tsx
Co-authored-by: lijianan <574980606@qq.com>
Signed-off-by: Wanpan <wanpan96@163.com>
* Update components/splitter/demo/multiple.tsx
Co-authored-by: lijianan <574980606@qq.com>
Signed-off-by: Wanpan <wanpan96@163.com>
* docs: update
* feat: Modify the style and optimize the interface
* feat: use PropsWithChildren
* feat: support rtl
* feat: collapsible supports object types
* fix: when collapsible is boolean not work
* feat: Splitter add test
* feat: update
* test: update snapshots
* docs: update
* test: update snapshots
* test: update
* test: update
* test: update
* test: update
* fix: Removed invalid min and max restrictions when collapsible exists
* test: update
* test: update
* test: update
* test: test coverage
* Revert "test: test coverage"
This reverts commit d247193722
.
* test: test coverage
* feat: rename
* feat: optimized code
* ci: lint
* feat: optimized code
* feat: add useag tips
* feat: optimized code
* feat: Modify splitbar layout
* feat: optimized code
* feat: numerical precision
* feat: optimized code
* feat: Optimized trigger region
* feat: Support configuration animation
* fix: Fix Collapsible exception when using multiple panels
* fix: Fixed the issue of drag area overlapping when multiple panels are folded
* feat: optimized code
* feat: annotation
* feAt: optimized code
* fix: bgcolor
* fix: Modify the initial value calculation method
* test: update
* feat: add cover image
* chore: adjust logic
* chore: use items size
* chore: rtl
* chore: limit
* chore: controlled
* docs: update demo
* docs: adjust style
* chore: add split style
* chore: hor collapisble style
* chore: collapse icon
* chore: update warning
* chore: clean up
* chore: collapse logic
* chore: adjust demo
* chore: clean up
* test: adjust logic
* docs: update demo
* docs: rm useless demo
* docs: demo
* test: add demo test
* test: test of them
* test: 100% coverage
* chore: fix lint
* docs: update demo
* refactor: unique resize config
* docs: add demo
* fix: support virtual resiable
* chore: add cursor mask
* test: update snapshot
* test: add test case
* test: update snapshot
* chore: use px base
* chore: rm useless code
---------
Signed-off-by: Wanpan <wanpan96@163.com>
Co-authored-by: lijianan <574980606@qq.com>
Co-authored-by: 二货机器人 <smith3816@gmail.com>
Co-authored-by: ice <49827327+coding-ice@users.noreply.github.com>
This commit is contained in:
parent
33533ff22c
commit
742ce37887
@ -54,6 +54,7 @@ exports[`antd exports modules correctly 1`] = `
|
||||
"Slider",
|
||||
"Space",
|
||||
"Spin",
|
||||
"Splitter",
|
||||
"Statistic",
|
||||
"Steps",
|
||||
"Switch",
|
||||
|
@ -170,3 +170,5 @@ export type { UploadFile, UploadProps } from './upload';
|
||||
export { default as version } from './version';
|
||||
export { default as Watermark } from './watermark';
|
||||
export type { WatermarkProps } from './watermark';
|
||||
export { default as Splitter } from './splitter';
|
||||
export type { SplitterProps } from './splitter';
|
||||
|
32
components/splitter/Panel.tsx
Normal file
32
components/splitter/Panel.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
import React, { forwardRef } from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import type { InternalPanelProps, PanelProps } from './interface';
|
||||
|
||||
export const InternalPanel = forwardRef<
|
||||
HTMLDivElement,
|
||||
React.PropsWithChildren<InternalPanelProps>
|
||||
>((props, ref) => {
|
||||
const { prefixCls, className, children, size, style = {} } = props;
|
||||
const panelClassName = classNames(
|
||||
`${prefixCls}-panel`,
|
||||
{
|
||||
[`${prefixCls}-panel-hidden`]: !size,
|
||||
},
|
||||
className,
|
||||
);
|
||||
|
||||
return (
|
||||
<div ref={ref} className={panelClassName} style={{ ...style, flexBasis: size }}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
InternalPanel.displayName = 'Panel';
|
||||
}
|
||||
|
||||
const Panel: React.FC<React.PropsWithChildren<PanelProps>> = () => null;
|
||||
|
||||
export default Panel;
|
139
components/splitter/SplitBar.tsx
Normal file
139
components/splitter/SplitBar.tsx
Normal file
@ -0,0 +1,139 @@
|
||||
import React, { useState } from 'react';
|
||||
import DownOutlined from '@ant-design/icons/DownOutlined';
|
||||
import LeftOutlined from '@ant-design/icons/LeftOutlined';
|
||||
import RightOutlined from '@ant-design/icons/RightOutlined';
|
||||
import UpOutlined from '@ant-design/icons/UpOutlined';
|
||||
import classNames from 'classnames';
|
||||
|
||||
export interface SplitBarProps {
|
||||
index: number;
|
||||
active: boolean;
|
||||
prefixCls: string;
|
||||
resizable: boolean;
|
||||
startCollapsible: boolean;
|
||||
endCollapsible: boolean;
|
||||
onOffsetStart: (index: number) => void;
|
||||
onOffsetUpdate: (index: number, offsetX: number, offsetY: number) => void;
|
||||
onOffsetEnd: VoidFunction;
|
||||
onCollapse: (index: number, type: 'start' | 'end') => void;
|
||||
vertical: boolean;
|
||||
ariaNow: number;
|
||||
ariaMin: number;
|
||||
ariaMax: number;
|
||||
}
|
||||
|
||||
const SplitBar: React.FC<SplitBarProps> = (props) => {
|
||||
const {
|
||||
prefixCls,
|
||||
vertical,
|
||||
index,
|
||||
active,
|
||||
ariaNow,
|
||||
ariaMin,
|
||||
ariaMax,
|
||||
resizable,
|
||||
startCollapsible,
|
||||
endCollapsible,
|
||||
onOffsetStart,
|
||||
onOffsetUpdate,
|
||||
onOffsetEnd,
|
||||
onCollapse,
|
||||
} = props;
|
||||
|
||||
const splitBarPrefixCls = `${prefixCls}-bar`;
|
||||
|
||||
// ======================== Resize ========================
|
||||
const [startPos, setStartPos] = useState<[x: number, y: number] | null>(null);
|
||||
|
||||
const onMouseDown: React.MouseEventHandler<HTMLDivElement> = (e) => {
|
||||
if (resizable && e.currentTarget) {
|
||||
setStartPos([e.pageX, e.pageY]);
|
||||
onOffsetStart(index);
|
||||
}
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
if (startPos) {
|
||||
const onMouseMove = (e: MouseEvent) => {
|
||||
const { pageX, pageY } = e;
|
||||
const offsetX = pageX - startPos[0];
|
||||
const offsetY = pageY - startPos[1];
|
||||
|
||||
onOffsetUpdate(index, offsetX, offsetY);
|
||||
};
|
||||
|
||||
const onMouseUp = () => {
|
||||
setStartPos(null);
|
||||
onOffsetEnd();
|
||||
};
|
||||
|
||||
window.addEventListener('mousemove', onMouseMove);
|
||||
window.addEventListener('mouseup', onMouseUp);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('mousemove', onMouseMove);
|
||||
window.removeEventListener('mouseup', onMouseUp);
|
||||
};
|
||||
}
|
||||
}, [startPos]);
|
||||
|
||||
// ======================== Render ========================
|
||||
const StartIcon = vertical ? UpOutlined : LeftOutlined;
|
||||
const EndIcon = vertical ? DownOutlined : RightOutlined;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={splitBarPrefixCls}
|
||||
role="separator"
|
||||
aria-valuenow={Math.round(ariaNow)}
|
||||
aria-valuemin={Math.round(ariaMin)}
|
||||
aria-valuemax={Math.round(ariaMax)}
|
||||
>
|
||||
<div
|
||||
className={classNames(`${splitBarPrefixCls}-dragger`, {
|
||||
[`${splitBarPrefixCls}-dragger-disabled`]: !resizable,
|
||||
[`${splitBarPrefixCls}-dragger-active`]: active,
|
||||
})}
|
||||
onMouseDown={onMouseDown}
|
||||
/>
|
||||
|
||||
{/* Start Collapsible */}
|
||||
{startCollapsible && (
|
||||
<div
|
||||
className={classNames(
|
||||
`${splitBarPrefixCls}-collapse-bar`,
|
||||
`${splitBarPrefixCls}-collapse-bar-start`,
|
||||
)}
|
||||
>
|
||||
<StartIcon
|
||||
className={classNames(
|
||||
`${splitBarPrefixCls}-collapse-icon`,
|
||||
`${splitBarPrefixCls}-collapse-start`,
|
||||
)}
|
||||
onClick={() => onCollapse(index, 'start')}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* End Collapsible */}
|
||||
{endCollapsible && (
|
||||
<div
|
||||
className={classNames(
|
||||
`${splitBarPrefixCls}-collapse-bar`,
|
||||
`${splitBarPrefixCls}-collapse-bar-end`,
|
||||
)}
|
||||
>
|
||||
<EndIcon
|
||||
className={classNames(
|
||||
`${splitBarPrefixCls}-collapse-icon`,
|
||||
`${splitBarPrefixCls}-collapse-end`,
|
||||
)}
|
||||
onClick={() => onCollapse(index, 'end')}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SplitBar;
|
219
components/splitter/Splitter.tsx
Normal file
219
components/splitter/Splitter.tsx
Normal file
@ -0,0 +1,219 @@
|
||||
/* eslint-disable react/no-array-index-key */
|
||||
import React, { useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import ResizeObserver from 'rc-resize-observer';
|
||||
import { useEvent } from 'rc-util';
|
||||
|
||||
import type { GetProp } from '../_util/type';
|
||||
import { devUseWarning } from '../_util/warning';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
|
||||
import useItems from './hooks/useItems';
|
||||
import useResizable from './hooks/useResizable';
|
||||
import useResize from './hooks/useResize';
|
||||
import useSizes from './hooks/useSizes';
|
||||
import type { SplitterProps } from './interface';
|
||||
import { InternalPanel } from './Panel';
|
||||
import SplitBar from './SplitBar';
|
||||
import useStyle from './style';
|
||||
|
||||
const Splitter: React.FC<React.PropsWithChildren<SplitterProps>> = (props) => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
className,
|
||||
style,
|
||||
layout,
|
||||
children,
|
||||
rootClassName,
|
||||
onResizeStart,
|
||||
onResize,
|
||||
onResizeEnd,
|
||||
} = props;
|
||||
|
||||
const { getPrefixCls, direction } = React.useContext(ConfigContext);
|
||||
const prefixCls = getPrefixCls('splitter', customizePrefixCls);
|
||||
const rootCls = useCSSVarCls(prefixCls);
|
||||
const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls, rootCls);
|
||||
|
||||
// ======================== Direct ========================
|
||||
const isVertical = layout === 'vertical';
|
||||
const isRTL = direction === 'rtl';
|
||||
const reverse = !isVertical && isRTL;
|
||||
|
||||
// ====================== Items Data ======================
|
||||
const items = useItems(children);
|
||||
|
||||
// >>> Warning for uncontrolled
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const warning = devUseWarning('Splitter');
|
||||
|
||||
let existSize = false;
|
||||
let existUndefinedSize = false;
|
||||
|
||||
items.forEach((item) => {
|
||||
if (item.size !== undefined) {
|
||||
existSize = true;
|
||||
} else {
|
||||
existUndefinedSize = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (existSize && existUndefinedSize && !onResize) {
|
||||
warning(
|
||||
false,
|
||||
'usage',
|
||||
'When part of `Splitter.Panel` has `size`, `onResize` is required or change `size` to `defaultSize`.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ====================== Container =======================
|
||||
const [containerSize, setContainerSize] = useState<number>(100);
|
||||
|
||||
const onContainerResize: GetProp<typeof ResizeObserver, 'onResize'> = (size) => {
|
||||
setContainerSize(isVertical ? size.offsetHeight : size.offsetWidth);
|
||||
};
|
||||
|
||||
// ========================= Size =========================
|
||||
const [itemPxSizes, itemPtgSizes, itemPtgMinSizes, itemPtgMaxSizes, updateSizes] = useSizes(
|
||||
items,
|
||||
containerSize,
|
||||
);
|
||||
|
||||
// ====================== Resizable =======================
|
||||
const resizableInfos = useResizable(items, itemPxSizes);
|
||||
|
||||
const [onOffsetStart, onOffsetUpdate, onOffsetEnd, onCollapse, movingIndex] = useResize(
|
||||
items,
|
||||
resizableInfos,
|
||||
itemPtgSizes,
|
||||
containerSize,
|
||||
updateSizes,
|
||||
);
|
||||
|
||||
// ======================== Events ========================
|
||||
const onInternalResizeStart = useEvent((index: number) => {
|
||||
onOffsetStart(index);
|
||||
onResizeStart?.(itemPxSizes);
|
||||
});
|
||||
|
||||
const onInternalResizeUpdate = useEvent((index: number, offset: number) => {
|
||||
const nextSizes = onOffsetUpdate(index, offset);
|
||||
onResize?.(nextSizes);
|
||||
});
|
||||
|
||||
const onInternalResizeEnd = useEvent(() => {
|
||||
onOffsetEnd();
|
||||
onResizeEnd?.(itemPxSizes);
|
||||
});
|
||||
|
||||
const onInternalCollapse = useEvent((index: number, type: 'start' | 'end') => {
|
||||
const nextSizes = onCollapse(index, type);
|
||||
onResize?.(nextSizes);
|
||||
onResizeEnd?.(nextSizes);
|
||||
});
|
||||
|
||||
// ======================== Styles ========================
|
||||
const containerClassName = classNames(
|
||||
prefixCls,
|
||||
className,
|
||||
{
|
||||
[`${prefixCls}-horizontal`]: !isVertical,
|
||||
[`${prefixCls}-vertical`]: isVertical,
|
||||
[`${prefixCls}-rtl`]: isRTL,
|
||||
},
|
||||
rootClassName,
|
||||
cssVarCls,
|
||||
rootCls,
|
||||
hashId,
|
||||
);
|
||||
|
||||
// ======================== Render ========================
|
||||
const maskCls = `${prefixCls}-mask`;
|
||||
|
||||
const stackSizes = React.useMemo(() => {
|
||||
const mergedSizes = [];
|
||||
|
||||
let stack = 0;
|
||||
for (let i = 0; i < items.length; i += 1) {
|
||||
stack += itemPtgSizes[i];
|
||||
mergedSizes.push(stack);
|
||||
}
|
||||
|
||||
return mergedSizes;
|
||||
}, [itemPtgSizes]);
|
||||
|
||||
return wrapCSSVar(
|
||||
<>
|
||||
<ResizeObserver onResize={onContainerResize}>
|
||||
<div style={style} className={containerClassName}>
|
||||
{items.map((item, idx) => {
|
||||
// Panel
|
||||
const panel = <InternalPanel {...item} prefixCls={prefixCls} size={itemPxSizes[idx]} />;
|
||||
|
||||
// Split Bar
|
||||
let splitBar: React.ReactElement | null = null;
|
||||
|
||||
const resizableInfo = resizableInfos[idx];
|
||||
if (resizableInfo) {
|
||||
const ariaMinStart = (stackSizes[idx - 1] || 0) + itemPtgMinSizes[idx];
|
||||
const ariaMinEnd = (stackSizes[idx + 1] || 100) - itemPtgMaxSizes[idx + 1];
|
||||
|
||||
const ariaMaxStart = (stackSizes[idx - 1] || 0) + itemPtgMaxSizes[idx];
|
||||
const ariaMaxEnd = (stackSizes[idx + 1] || 100) - itemPtgMinSizes[idx + 1];
|
||||
|
||||
splitBar = (
|
||||
<SplitBar
|
||||
index={idx}
|
||||
active={movingIndex === idx}
|
||||
prefixCls={prefixCls}
|
||||
vertical={isVertical}
|
||||
resizable={resizableInfo.resizable}
|
||||
ariaNow={stackSizes[idx] * 100}
|
||||
ariaMin={Math.max(ariaMinStart, ariaMinEnd) * 100}
|
||||
ariaMax={Math.min(ariaMaxStart, ariaMaxEnd) * 100}
|
||||
startCollapsible={resizableInfo.startCollapsible}
|
||||
endCollapsible={resizableInfo.endCollapsible}
|
||||
onOffsetStart={onInternalResizeStart}
|
||||
onOffsetUpdate={(index, offsetX, offsetY) => {
|
||||
let offset = isVertical ? offsetY : offsetX;
|
||||
if (reverse) {
|
||||
offset = -offset;
|
||||
}
|
||||
onInternalResizeUpdate(index, offset);
|
||||
}}
|
||||
onOffsetEnd={onInternalResizeEnd}
|
||||
onCollapse={onInternalCollapse}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment key={`split-panel-${idx}`}>
|
||||
{panel}
|
||||
{splitBar}
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</ResizeObserver>
|
||||
|
||||
{/* Fake mask for cursor */}
|
||||
{typeof movingIndex === 'number' && (
|
||||
<div
|
||||
aria-hidden
|
||||
className={classNames(maskCls, {
|
||||
[`${maskCls}-horizontal`]: !isVertical,
|
||||
[`${maskCls}-vertical`]: isVertical,
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</>,
|
||||
);
|
||||
};
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
Splitter.displayName = 'Splitter';
|
||||
}
|
||||
|
||||
export default Splitter;
|
@ -0,0 +1,913 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders components/splitter/demo/collapsible.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-flex ant-flex-align-stretch ant-flex-gap-middle ant-flex-vertical"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter ant-splitter-horizontal"
|
||||
style="box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); height: 200px;"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 50px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
first
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="20"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
<div
|
||||
class="ant-splitter-bar-collapse-bar ant-splitter-bar-collapse-bar-start"
|
||||
>
|
||||
<span
|
||||
aria-label="left"
|
||||
class="anticon anticon-left ant-splitter-bar-collapse-icon ant-splitter-bar-collapse-start"
|
||||
role="img"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="left"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 000 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-bar-collapse-bar ant-splitter-bar-collapse-bar-end"
|
||||
>
|
||||
<span
|
||||
aria-label="right"
|
||||
class="anticon anticon-right ant-splitter-bar-collapse-icon ant-splitter-bar-collapse-end"
|
||||
role="img"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="right"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 50px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
second
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter ant-splitter-vertical"
|
||||
style="box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); height: 300px;"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 50px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
first
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="20"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
<div
|
||||
class="ant-splitter-bar-collapse-bar ant-splitter-bar-collapse-bar-start"
|
||||
>
|
||||
<span
|
||||
aria-label="up"
|
||||
class="anticon anticon-up ant-splitter-bar-collapse-icon ant-splitter-bar-collapse-start"
|
||||
role="img"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="up"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M890.5 755.3L537.9 269.2c-12.8-17.6-39-17.6-51.7 0L133.5 755.3A8 8 0 00140 768h75c5.1 0 9.9-2.5 12.9-6.6L512 369.8l284.1 391.6c3 4.1 7.8 6.6 12.9 6.6h75c6.5 0 10.3-7.4 6.5-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-bar-collapse-bar ant-splitter-bar-collapse-bar-end"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-splitter-bar-collapse-icon ant-splitter-bar-collapse-end"
|
||||
role="img"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 50px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
second
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/splitter/demo/collapsible.tsx extend context correctly 2`] = `[]`;
|
||||
|
||||
exports[`renders components/splitter/demo/control.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-flex ant-flex-align-stretch ant-flex-gap-middle ant-flex-vertical"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter ant-splitter-horizontal"
|
||||
style="height: 200px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 50px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
First
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 50px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
Second
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-flex ant-flex-justify-space-between ant-flex-gap-middle"
|
||||
>
|
||||
<button
|
||||
aria-checked="true"
|
||||
class="ant-switch ant-switch-checked"
|
||||
role="switch"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="ant-switch-handle"
|
||||
/>
|
||||
<span
|
||||
class="ant-switch-inner"
|
||||
>
|
||||
<span
|
||||
class="ant-switch-inner-checked"
|
||||
>
|
||||
Enabled
|
||||
</span>
|
||||
<span
|
||||
class="ant-switch-inner-unchecked"
|
||||
>
|
||||
Disabled
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-outlined"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Reset
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/splitter/demo/control.tsx extend context correctly 2`] = `[]`;
|
||||
|
||||
exports[`renders components/splitter/demo/debug.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-flex ant-flex-align-stretch ant-flex-gap-middle ant-flex-vertical"
|
||||
>
|
||||
<h3
|
||||
class="ant-typography"
|
||||
>
|
||||
[true, 0, false]
|
||||
</h3>
|
||||
<div
|
||||
class="ant-splitter ant-splitter-horizontal"
|
||||
style="height: 200px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 50px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
Panel 1
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="50"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel ant-splitter-panel-hidden"
|
||||
style="flex-basis: 0px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
Panel 2
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="50"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger ant-splitter-bar-dragger-disabled"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 50px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
Panel 3
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h3
|
||||
class="ant-typography"
|
||||
>
|
||||
[false, 0, true]
|
||||
</h3>
|
||||
<div
|
||||
class="ant-splitter ant-splitter-horizontal"
|
||||
style="height: 200px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 50px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
Panel 1
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="50"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger ant-splitter-bar-dragger-disabled"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel ant-splitter-panel-hidden"
|
||||
style="flex-basis: 0px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
Panel 2
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="50"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 50px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
Panel 3
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h3
|
||||
class="ant-typography"
|
||||
>
|
||||
Start have min & max
|
||||
</h3>
|
||||
<div
|
||||
class="ant-splitter ant-splitter-horizontal"
|
||||
style="height: 200px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 50px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
Panel 1
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="50"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 50px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
Panel 2
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h3
|
||||
class="ant-typography"
|
||||
>
|
||||
End have min & max
|
||||
</h3>
|
||||
<div
|
||||
class="ant-splitter ant-splitter-horizontal"
|
||||
style="height: 200px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 50px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
Panel 1
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="80"
|
||||
aria-valuemin="30"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 50px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
Panel 2
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/splitter/demo/debug.tsx extend context correctly 2`] = `[]`;
|
||||
|
||||
exports[`renders components/splitter/demo/group.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-splitter ant-splitter-horizontal"
|
||||
style="height: 300px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 50px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
Left
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
<div
|
||||
class="ant-splitter-bar-collapse-bar ant-splitter-bar-collapse-bar-start"
|
||||
>
|
||||
<span
|
||||
aria-label="left"
|
||||
class="anticon anticon-left ant-splitter-bar-collapse-icon ant-splitter-bar-collapse-start"
|
||||
role="img"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="left"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 000 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 50px;"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter ant-splitter-vertical"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 50px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
Top
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 50px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
Bottom
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/splitter/demo/group.tsx extend context correctly 2`] = `[]`;
|
||||
|
||||
exports[`renders components/splitter/demo/multiple.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-splitter ant-splitter-horizontal"
|
||||
style="height: 200px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 33.33333333333333px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
Panel 1
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="67"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow="33"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
<div
|
||||
class="ant-splitter-bar-collapse-bar ant-splitter-bar-collapse-bar-start"
|
||||
>
|
||||
<span
|
||||
aria-label="left"
|
||||
class="anticon anticon-left ant-splitter-bar-collapse-icon ant-splitter-bar-collapse-start"
|
||||
role="img"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="left"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 000 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-bar-collapse-bar ant-splitter-bar-collapse-bar-end"
|
||||
>
|
||||
<span
|
||||
aria-label="right"
|
||||
class="anticon anticon-right ant-splitter-bar-collapse-icon ant-splitter-bar-collapse-end"
|
||||
role="img"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="right"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 33.33333333333333px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
Panel 2
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="33"
|
||||
aria-valuenow="67"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 33.33333333333333px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
Panel 3
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/splitter/demo/multiple.tsx extend context correctly 2`] = `[]`;
|
||||
|
||||
exports[`renders components/splitter/demo/size.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-splitter ant-splitter-horizontal"
|
||||
style="height: 200px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 40px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
>
|
||||
First
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="70"
|
||||
aria-valuemin="20"
|
||||
aria-valuenow="40"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 60px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
>
|
||||
Second
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/splitter/demo/size.tsx extend context correctly 2`] = `[]`;
|
||||
|
||||
exports[`renders components/splitter/demo/vertical.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-splitter ant-splitter-vertical"
|
||||
style="height: 300px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 50px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
>
|
||||
First
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis: 50px;"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
>
|
||||
Second
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/splitter/demo/vertical.tsx extend context correctly 2`] = `[]`;
|
925
components/splitter/__tests__/__snapshots__/demo.test.ts.snap
Normal file
925
components/splitter/__tests__/__snapshots__/demo.test.ts.snap
Normal file
@ -0,0 +1,925 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders components/splitter/demo/collapsible.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-flex ant-flex-align-stretch ant-flex-gap-middle ant-flex-vertical"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter ant-splitter-horizontal"
|
||||
style="box-shadow:0 0 10px rgba(0, 0, 0, 0.1);height:200px"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:50px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space:nowrap"
|
||||
>
|
||||
first
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="20"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
<div
|
||||
class="ant-splitter-bar-collapse-bar ant-splitter-bar-collapse-bar-start"
|
||||
>
|
||||
<span
|
||||
aria-label="left"
|
||||
class="anticon anticon-left ant-splitter-bar-collapse-icon ant-splitter-bar-collapse-start"
|
||||
role="img"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="left"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 000 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-bar-collapse-bar ant-splitter-bar-collapse-bar-end"
|
||||
>
|
||||
<span
|
||||
aria-label="right"
|
||||
class="anticon anticon-right ant-splitter-bar-collapse-icon ant-splitter-bar-collapse-end"
|
||||
role="img"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="right"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:50px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space:nowrap"
|
||||
>
|
||||
second
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter ant-splitter-vertical"
|
||||
style="box-shadow:0 0 10px rgba(0, 0, 0, 0.1);height:300px"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:50px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space:nowrap"
|
||||
>
|
||||
first
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="20"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
<div
|
||||
class="ant-splitter-bar-collapse-bar ant-splitter-bar-collapse-bar-start"
|
||||
>
|
||||
<span
|
||||
aria-label="up"
|
||||
class="anticon anticon-up ant-splitter-bar-collapse-icon ant-splitter-bar-collapse-start"
|
||||
role="img"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="up"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M890.5 755.3L537.9 269.2c-12.8-17.6-39-17.6-51.7 0L133.5 755.3A8 8 0 00140 768h75c5.1 0 9.9-2.5 12.9-6.6L512 369.8l284.1 391.6c3 4.1 7.8 6.6 12.9 6.6h75c6.5 0 10.3-7.4 6.5-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-bar-collapse-bar ant-splitter-bar-collapse-bar-end"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-splitter-bar-collapse-icon ant-splitter-bar-collapse-end"
|
||||
role="img"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:50px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space:nowrap"
|
||||
>
|
||||
second
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/splitter/demo/control.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-flex ant-flex-align-stretch ant-flex-gap-middle ant-flex-vertical"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter ant-splitter-horizontal"
|
||||
style="height:200px;box-shadow:0 0 10px rgba(0, 0, 0, 0.1)"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:50px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space:nowrap"
|
||||
>
|
||||
First
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:50px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space:nowrap"
|
||||
>
|
||||
Second
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-flex ant-flex-justify-space-between ant-flex-gap-middle"
|
||||
>
|
||||
<button
|
||||
aria-checked="true"
|
||||
class="ant-switch ant-switch-checked"
|
||||
role="switch"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="ant-switch-handle"
|
||||
/>
|
||||
<span
|
||||
class="ant-switch-inner"
|
||||
>
|
||||
<span
|
||||
class="ant-switch-inner-checked"
|
||||
>
|
||||
Enabled
|
||||
</span>
|
||||
<span
|
||||
class="ant-switch-inner-unchecked"
|
||||
>
|
||||
Disabled
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-default ant-btn-outlined"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Reset
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/splitter/demo/debug.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-flex ant-flex-align-stretch ant-flex-gap-middle ant-flex-vertical"
|
||||
>
|
||||
<h3
|
||||
class="ant-typography"
|
||||
>
|
||||
[true, 0, false]
|
||||
</h3>
|
||||
<div
|
||||
class="ant-splitter ant-splitter-horizontal"
|
||||
style="height:200px;box-shadow:0 0 10px rgba(0, 0, 0, 0.1)"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:50px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space:nowrap"
|
||||
>
|
||||
Panel
|
||||
<!-- -->
|
||||
1
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="50"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel ant-splitter-panel-hidden"
|
||||
style="flex-basis:0"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space:nowrap"
|
||||
>
|
||||
Panel
|
||||
<!-- -->
|
||||
2
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="50"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger ant-splitter-bar-dragger-disabled"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:50px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space:nowrap"
|
||||
>
|
||||
Panel
|
||||
<!-- -->
|
||||
3
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h3
|
||||
class="ant-typography"
|
||||
>
|
||||
[false, 0, true]
|
||||
</h3>
|
||||
<div
|
||||
class="ant-splitter ant-splitter-horizontal"
|
||||
style="height:200px;box-shadow:0 0 10px rgba(0, 0, 0, 0.1)"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:50px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space:nowrap"
|
||||
>
|
||||
Panel
|
||||
<!-- -->
|
||||
1
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="50"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger ant-splitter-bar-dragger-disabled"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel ant-splitter-panel-hidden"
|
||||
style="flex-basis:0"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space:nowrap"
|
||||
>
|
||||
Panel
|
||||
<!-- -->
|
||||
2
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="50"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:50px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space:nowrap"
|
||||
>
|
||||
Panel
|
||||
<!-- -->
|
||||
3
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h3
|
||||
class="ant-typography"
|
||||
>
|
||||
Start have min & max
|
||||
</h3>
|
||||
<div
|
||||
class="ant-splitter ant-splitter-horizontal"
|
||||
style="height:200px;box-shadow:0 0 10px rgba(0, 0, 0, 0.1)"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:50px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space:nowrap"
|
||||
>
|
||||
Panel
|
||||
<!-- -->
|
||||
1
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="50"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:50px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space:nowrap"
|
||||
>
|
||||
Panel
|
||||
<!-- -->
|
||||
2
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h3
|
||||
class="ant-typography"
|
||||
>
|
||||
End have min & max
|
||||
</h3>
|
||||
<div
|
||||
class="ant-splitter ant-splitter-horizontal"
|
||||
style="height:200px;box-shadow:0 0 10px rgba(0, 0, 0, 0.1)"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:50px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space:nowrap"
|
||||
>
|
||||
Panel
|
||||
<!-- -->
|
||||
1
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="80"
|
||||
aria-valuemin="30"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:50px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space:nowrap"
|
||||
>
|
||||
Panel
|
||||
<!-- -->
|
||||
2
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/splitter/demo/group.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-splitter ant-splitter-horizontal"
|
||||
style="height:300px;box-shadow:0 0 10px rgba(0, 0, 0, 0.1)"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:50px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space:nowrap"
|
||||
>
|
||||
Left
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
<div
|
||||
class="ant-splitter-bar-collapse-bar ant-splitter-bar-collapse-bar-start"
|
||||
>
|
||||
<span
|
||||
aria-label="left"
|
||||
class="anticon anticon-left ant-splitter-bar-collapse-icon ant-splitter-bar-collapse-start"
|
||||
role="img"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="left"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 000 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:50px"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter ant-splitter-vertical"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:50px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space:nowrap"
|
||||
>
|
||||
Top
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:50px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space:nowrap"
|
||||
>
|
||||
Bottom
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/splitter/demo/multiple.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-splitter ant-splitter-horizontal"
|
||||
style="height:200px;box-shadow:0 0 10px rgba(0, 0, 0, 0.1)"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:33.33333333333333px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space:nowrap"
|
||||
>
|
||||
Panel
|
||||
<!-- -->
|
||||
1
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="67"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow="33"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
<div
|
||||
class="ant-splitter-bar-collapse-bar ant-splitter-bar-collapse-bar-start"
|
||||
>
|
||||
<span
|
||||
aria-label="left"
|
||||
class="anticon anticon-left ant-splitter-bar-collapse-icon ant-splitter-bar-collapse-start"
|
||||
role="img"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="left"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 000 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-bar-collapse-bar ant-splitter-bar-collapse-bar-end"
|
||||
>
|
||||
<span
|
||||
aria-label="right"
|
||||
class="anticon anticon-right ant-splitter-bar-collapse-icon ant-splitter-bar-collapse-end"
|
||||
role="img"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="right"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:33.33333333333333px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space:nowrap"
|
||||
>
|
||||
Panel
|
||||
<!-- -->
|
||||
2
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="33"
|
||||
aria-valuenow="67"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:33.33333333333333px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
style="white-space:nowrap"
|
||||
>
|
||||
Panel
|
||||
<!-- -->
|
||||
3
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/splitter/demo/size.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-splitter ant-splitter-horizontal"
|
||||
style="height:200px;box-shadow:0 0 10px rgba(0, 0, 0, 0.1)"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:40px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
>
|
||||
First
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="70"
|
||||
aria-valuemin="20"
|
||||
aria-valuenow="40"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:60px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
>
|
||||
Second
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/splitter/demo/vertical.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-splitter ant-splitter-vertical"
|
||||
style="height:300px;box-shadow:0 0 10px rgba(0, 0, 0, 0.1)"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:50px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
>
|
||||
First
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow="50"
|
||||
class="ant-splitter-bar"
|
||||
role="separator"
|
||||
>
|
||||
<div
|
||||
class="ant-splitter-bar-dragger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-splitter-panel"
|
||||
style="flex-basis:50px"
|
||||
>
|
||||
<div
|
||||
class="ant-flex ant-flex-align-center ant-flex-justify-center"
|
||||
style="height:100%"
|
||||
>
|
||||
<h5
|
||||
class="ant-typography ant-typography-secondary"
|
||||
>
|
||||
Second
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
3
components/splitter/__tests__/demo-extend.test.ts
Normal file
3
components/splitter/__tests__/demo-extend.test.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { extendTest } from '../../../tests/shared/demoTest';
|
||||
|
||||
extendTest('splitter');
|
3
components/splitter/__tests__/demo.test.ts
Normal file
3
components/splitter/__tests__/demo.test.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import demoTest from '../../../tests/shared/demoTest';
|
||||
|
||||
demoTest('splitter');
|
5
components/splitter/__tests__/image.test.ts
Normal file
5
components/splitter/__tests__/image.test.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { imageDemoTest } from '../../../tests/shared/imageTest';
|
||||
|
||||
describe('Splitter image', () => {
|
||||
imageDemoTest('splitter');
|
||||
});
|
452
components/splitter/__tests__/index.test.tsx
Normal file
452
components/splitter/__tests__/index.test.tsx
Normal file
@ -0,0 +1,452 @@
|
||||
import React from 'react';
|
||||
import type { GetProps, SplitterProps } from 'antd';
|
||||
import { ConfigProvider, Splitter } from 'antd';
|
||||
import { spyElementPrototypes } from 'rc-util/lib/test/domHook';
|
||||
|
||||
import { resetWarned } from '../../_util/warning';
|
||||
import {
|
||||
act,
|
||||
createEvent,
|
||||
fireEvent,
|
||||
render,
|
||||
triggerResize,
|
||||
waitFakeTimer,
|
||||
} from '../../../tests/utils';
|
||||
|
||||
type PanelProps = GetProps<typeof Splitter.Panel>;
|
||||
|
||||
const SplitterDemo = ({ items = [{}, {}], ...props }: { items?: PanelProps[] } & SplitterProps) => (
|
||||
<Splitter {...props}>
|
||||
{items?.map((item, idx) => {
|
||||
const key = `panel-${idx}`;
|
||||
return <Splitter.Panel key={key} {...item} />;
|
||||
})}
|
||||
</Splitter>
|
||||
);
|
||||
|
||||
describe('Splitter', () => {
|
||||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
let containerSize = 100;
|
||||
|
||||
beforeAll(() => {
|
||||
spyElementPrototypes(HTMLElement, {
|
||||
offsetWidth: {
|
||||
get: () => containerSize,
|
||||
},
|
||||
offsetHeight: {
|
||||
get: () => containerSize,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
containerSize = 100;
|
||||
errSpy.mockReset();
|
||||
resetWarned();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllTimers();
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('should correct render', () => {
|
||||
const { container } = render(<SplitterDemo />);
|
||||
expect(container.querySelector('.ant-splitter')).toBeTruthy();
|
||||
expect(container.querySelectorAll('.ant-splitter-panel')).toHaveLength(2);
|
||||
expect(container.querySelector('.ant-splitter-bar')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should correct render panel size', async () => {
|
||||
const { container } = render(<SplitterDemo items={[{ size: 20 }, { size: '45%' }, {}]} />);
|
||||
|
||||
const panels = container.querySelectorAll('.ant-splitter-panel');
|
||||
|
||||
expect(panels?.[0]).toHaveStyle('flex-basis: 20px');
|
||||
expect(panels?.[1]).toHaveStyle('flex-basis: 45px');
|
||||
expect(panels?.[2]).toHaveStyle('flex-basis: 35px');
|
||||
});
|
||||
|
||||
it('The layout should work fine', () => {
|
||||
const { container, rerender } = render(<SplitterDemo />);
|
||||
expect(container.querySelector('.ant-splitter-horizontal')).toBeTruthy();
|
||||
|
||||
rerender(<SplitterDemo items={[{}, {}, {}]} layout="vertical" />);
|
||||
expect(container.querySelector('.ant-splitter-vertical')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('The resizable should work fine', () => {
|
||||
const { container, rerender } = render(
|
||||
<SplitterDemo items={[{ size: 20 }, { resizable: false }, {}]} />,
|
||||
);
|
||||
expect(container.querySelectorAll('.ant-splitter-bar-dragger')).toHaveLength(2);
|
||||
expect(container.querySelectorAll('.ant-splitter-bar-dragger-disabled')).toHaveLength(2);
|
||||
|
||||
rerender(<SplitterDemo items={[{ size: 20 }, {}, { resizable: false }]} />);
|
||||
expect(container.querySelectorAll('.ant-splitter-bar-dragger')).toHaveLength(2);
|
||||
expect(container.querySelectorAll('.ant-splitter-bar-dragger-disabled')).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('Splitter.Panel is syntactic sugar', () => {
|
||||
const { container } = render(<Splitter.Panel />);
|
||||
expect(container.innerHTML).toEqual('');
|
||||
});
|
||||
|
||||
// ============================== Resizable ==============================
|
||||
describe('drag', () => {
|
||||
function mockDrag(draggerEle: HTMLElement, offset: number) {
|
||||
// Down
|
||||
const downEvent = createEvent.mouseDown(draggerEle);
|
||||
(downEvent as any).pageX = 0;
|
||||
(downEvent as any).pageY = 0;
|
||||
|
||||
fireEvent(draggerEle, downEvent);
|
||||
|
||||
// Move
|
||||
const moveEvent = createEvent.mouseMove(draggerEle);
|
||||
(moveEvent as any).pageX = offset;
|
||||
(moveEvent as any).pageY = offset;
|
||||
fireEvent(draggerEle, moveEvent);
|
||||
|
||||
// Up
|
||||
fireEvent.mouseUp(draggerEle);
|
||||
}
|
||||
|
||||
it('The mousemove should work fine', async () => {
|
||||
const onResize = jest.fn();
|
||||
const onResizeEnd = jest.fn();
|
||||
|
||||
const { container } = render(
|
||||
<SplitterDemo items={[{}, {}]} onResize={onResize} onResizeEnd={onResizeEnd} />,
|
||||
);
|
||||
|
||||
// Right
|
||||
mockDrag(container.querySelector('.ant-splitter-bar-dragger')!, 40);
|
||||
expect(onResize).toHaveBeenCalledWith([90, 10]);
|
||||
expect(onResizeEnd).toHaveBeenCalledWith([90, 10]);
|
||||
|
||||
// Left
|
||||
mockDrag(container.querySelector('.ant-splitter-bar-dragger')!, -200);
|
||||
expect(onResize).toHaveBeenCalledWith([0, 100]);
|
||||
expect(onResizeEnd).toHaveBeenCalledWith([0, 100]);
|
||||
});
|
||||
|
||||
it('with min', () => {
|
||||
const onResize = jest.fn();
|
||||
const onResizeEnd = jest.fn();
|
||||
|
||||
const { container } = render(
|
||||
<SplitterDemo items={[{ min: 10 }, {}]} onResize={onResize} onResizeEnd={onResizeEnd} />,
|
||||
);
|
||||
|
||||
mockDrag(container.querySelector('.ant-splitter-bar-dragger')!, -100);
|
||||
expect(onResize).toHaveBeenCalledWith([10, 90]);
|
||||
expect(onResizeEnd).toHaveBeenCalledWith([10, 90]);
|
||||
});
|
||||
|
||||
it('with max', () => {
|
||||
const onResize = jest.fn();
|
||||
const onResizeEnd = jest.fn();
|
||||
|
||||
const { container } = render(
|
||||
<SplitterDemo items={[{ max: 90 }, {}]} onResize={onResize} onResizeEnd={onResizeEnd} />,
|
||||
);
|
||||
|
||||
mockDrag(container.querySelector('.ant-splitter-bar-dragger')!, 100);
|
||||
expect(onResize).toHaveBeenCalledWith([90, 10]);
|
||||
expect(onResizeEnd).toHaveBeenCalledWith([90, 10]);
|
||||
});
|
||||
|
||||
it('both panel has min and max', () => {
|
||||
const onResize = jest.fn();
|
||||
const onResizeEnd = jest.fn();
|
||||
|
||||
const { container } = render(
|
||||
<SplitterDemo
|
||||
items={[
|
||||
{ min: 10, max: 80 },
|
||||
{ min: 10, max: 80 },
|
||||
]}
|
||||
onResize={onResize}
|
||||
onResizeEnd={onResizeEnd}
|
||||
/>,
|
||||
);
|
||||
|
||||
mockDrag(container.querySelector('.ant-splitter-bar-dragger')!, -100);
|
||||
expect(onResize).toHaveBeenCalledWith([20, 80]);
|
||||
expect(onResizeEnd).toHaveBeenCalledWith([20, 80]);
|
||||
|
||||
mockDrag(container.querySelector('.ant-splitter-bar-dragger')!, 100);
|
||||
expect(onResize).toHaveBeenCalledWith([80, 20]);
|
||||
expect(onResizeEnd).toHaveBeenCalledWith([80, 20]);
|
||||
});
|
||||
|
||||
it('rtl', () => {
|
||||
const onResize = jest.fn();
|
||||
const onResizeEnd = jest.fn();
|
||||
|
||||
const { container } = render(
|
||||
<ConfigProvider direction="rtl">
|
||||
<SplitterDemo items={[{}, {}]} onResize={onResize} onResizeEnd={onResizeEnd} />
|
||||
</ConfigProvider>,
|
||||
);
|
||||
|
||||
mockDrag(container.querySelector('.ant-splitter-bar-dragger')!, -40);
|
||||
expect(onResize).toHaveBeenCalledWith([90, 10]);
|
||||
expect(onResizeEnd).toHaveBeenCalledWith([90, 10]);
|
||||
});
|
||||
|
||||
it('[true, 0, true] can be move left', () => {
|
||||
const onResize = jest.fn();
|
||||
const onResizeEnd = jest.fn();
|
||||
|
||||
const { container } = render(
|
||||
<SplitterDemo
|
||||
items={[{}, { defaultSize: 0 }, {}]}
|
||||
onResize={onResize}
|
||||
onResizeEnd={onResizeEnd}
|
||||
/>,
|
||||
);
|
||||
|
||||
mockDrag(container.querySelectorAll<HTMLDivElement>('.ant-splitter-bar-dragger')[1], -100);
|
||||
expect(onResize).toHaveBeenCalledWith([0, 50, 50]);
|
||||
expect(onResizeEnd).toHaveBeenCalledWith([0, 50, 50]);
|
||||
});
|
||||
|
||||
it('[false, 0, true] can not be move left', () => {
|
||||
const onResize = jest.fn();
|
||||
const onResizeEnd = jest.fn();
|
||||
|
||||
const { container } = render(
|
||||
<SplitterDemo
|
||||
items={[{ resizable: false }, { defaultSize: 0 }, {}]}
|
||||
onResize={onResize}
|
||||
onResizeEnd={onResizeEnd}
|
||||
/>,
|
||||
);
|
||||
|
||||
mockDrag(container.querySelectorAll<HTMLDivElement>('.ant-splitter-bar-dragger')[1], -100);
|
||||
expect(onResize).toHaveBeenCalledWith([50, 0, 50]);
|
||||
expect(onResizeEnd).toHaveBeenCalledWith([50, 0, 50]);
|
||||
});
|
||||
});
|
||||
|
||||
// ============================= Collapsible =============================
|
||||
describe('collapsible', () => {
|
||||
it('Basic', () => {
|
||||
const { container, rerender } = render(
|
||||
<SplitterDemo items={[{ size: 20, collapsible: true }, { collapsible: true }]} />,
|
||||
);
|
||||
|
||||
expect(container.querySelectorAll('.ant-splitter-bar-collapse-icon')).toHaveLength(2);
|
||||
expect(container.querySelector('.ant-splitter-bar-collapse-start')).toBeTruthy();
|
||||
expect(container.querySelector('.ant-splitter-bar-collapse-end')).toBeTruthy();
|
||||
|
||||
// support collapsible is object
|
||||
rerender(
|
||||
<SplitterDemo
|
||||
items={[
|
||||
{
|
||||
size: 20,
|
||||
collapsible: true,
|
||||
},
|
||||
{
|
||||
collapsible: true,
|
||||
},
|
||||
{},
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(container.querySelectorAll('.ant-splitter-bar-collapse-start')).toHaveLength(2);
|
||||
expect(container.querySelectorAll('.ant-splitter-bar-collapse-end')).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('collapsible - true', () => {
|
||||
const onResize = jest.fn();
|
||||
const onResizeEnd = jest.fn();
|
||||
|
||||
const { container } = render(
|
||||
<SplitterDemo
|
||||
items={[
|
||||
{
|
||||
size: 20,
|
||||
collapsible: true,
|
||||
},
|
||||
{},
|
||||
]}
|
||||
onResize={onResize}
|
||||
onResizeEnd={onResizeEnd}
|
||||
/>,
|
||||
);
|
||||
|
||||
fireEvent.click(container.querySelector('.ant-splitter-bar-collapse-start')!);
|
||||
expect(onResize).toHaveBeenCalledWith([0, 100]);
|
||||
expect(onResizeEnd).toHaveBeenCalledWith([0, 100]);
|
||||
});
|
||||
|
||||
it('collapsible - start:true', () => {
|
||||
const onResize = jest.fn();
|
||||
const onResizeEnd = jest.fn();
|
||||
|
||||
const { container } = render(
|
||||
<SplitterDemo
|
||||
items={[
|
||||
{},
|
||||
{
|
||||
size: 20,
|
||||
collapsible: {
|
||||
start: true,
|
||||
},
|
||||
},
|
||||
{},
|
||||
]}
|
||||
onResize={onResize}
|
||||
onResizeEnd={onResizeEnd}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(container.querySelector('.ant-splitter-bar-collapse-start')).toBeFalsy();
|
||||
expect(container.querySelector('.ant-splitter-bar-collapse-end')).toBeTruthy();
|
||||
|
||||
fireEvent.click(container.querySelector('.ant-splitter-bar-collapse-end')!);
|
||||
expect(onResize).toHaveBeenCalledWith([60, 0, 40]);
|
||||
expect(onResizeEnd).toHaveBeenCalledWith([60, 0, 40]);
|
||||
});
|
||||
|
||||
it('collapsible - end:true', () => {
|
||||
const onResize = jest.fn();
|
||||
const onResizeEnd = jest.fn();
|
||||
|
||||
const { container } = render(
|
||||
<SplitterDemo
|
||||
items={[
|
||||
{},
|
||||
{
|
||||
size: 20,
|
||||
collapsible: {
|
||||
end: true,
|
||||
},
|
||||
},
|
||||
{},
|
||||
]}
|
||||
onResize={onResize}
|
||||
onResizeEnd={onResizeEnd}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(container.querySelector('.ant-splitter-bar-collapse-start')).toBeTruthy();
|
||||
expect(container.querySelector('.ant-splitter-bar-collapse-end')).toBeFalsy();
|
||||
|
||||
fireEvent.click(container.querySelector('.ant-splitter-bar-collapse-start')!);
|
||||
expect(onResize).toHaveBeenCalledWith([40, 0, 60]);
|
||||
expect(onResizeEnd).toHaveBeenCalledWith([40, 0, 60]);
|
||||
});
|
||||
|
||||
it('both collapsible', () => {
|
||||
const onResize = jest.fn();
|
||||
const onResizeEnd = jest.fn();
|
||||
|
||||
const { container } = render(
|
||||
<SplitterDemo
|
||||
items={[
|
||||
{
|
||||
collapsible: true,
|
||||
},
|
||||
{
|
||||
collapsible: true,
|
||||
},
|
||||
]}
|
||||
onResize={onResize}
|
||||
onResizeEnd={onResizeEnd}
|
||||
/>,
|
||||
);
|
||||
|
||||
function expectClick(element: HTMLElement, size: number[]) {
|
||||
onResize.mockReset();
|
||||
onResizeEnd.mockReset();
|
||||
|
||||
fireEvent.click(element);
|
||||
expect(onResize).toHaveBeenCalledWith(size);
|
||||
expect(onResizeEnd).toHaveBeenCalledWith(size);
|
||||
}
|
||||
|
||||
expectClick(container.querySelector('.ant-splitter-bar-collapse-start')!, [0, 100]);
|
||||
expectClick(container.querySelector('.ant-splitter-bar-collapse-end')!, [50, 50]);
|
||||
expectClick(container.querySelector('.ant-splitter-bar-collapse-end')!, [100, 0]);
|
||||
expectClick(container.querySelector('.ant-splitter-bar-collapse-start')!, [50, 50]);
|
||||
});
|
||||
|
||||
it('collapsible with min', () => {
|
||||
const onResize = jest.fn();
|
||||
const onResizeEnd = jest.fn();
|
||||
|
||||
const { container } = render(
|
||||
<SplitterDemo
|
||||
items={[
|
||||
{
|
||||
defaultSize: 20,
|
||||
collapsible: true,
|
||||
min: 10,
|
||||
},
|
||||
{
|
||||
collapsible: true,
|
||||
min: '80%',
|
||||
},
|
||||
]}
|
||||
onResize={onResize}
|
||||
onResizeEnd={onResizeEnd}
|
||||
/>,
|
||||
);
|
||||
|
||||
// Collapse left
|
||||
fireEvent.click(container.querySelector('.ant-splitter-bar-collapse-start')!);
|
||||
expect(onResize).toHaveBeenCalledWith([0, 100]);
|
||||
expect(onResizeEnd).toHaveBeenCalledWith([0, 100]);
|
||||
expect(container.querySelector('.ant-splitter-bar-dragger-disabled')).toBeTruthy();
|
||||
|
||||
// Collapse back
|
||||
onResize.mockReset();
|
||||
onResizeEnd.mockReset();
|
||||
fireEvent.click(container.querySelector('.ant-splitter-bar-collapse-end')!);
|
||||
expect(onResize).toHaveBeenCalledWith([5, 95]);
|
||||
expect(onResizeEnd).toHaveBeenCalledWith([5, 95]);
|
||||
expect(container.querySelector('.ant-splitter-bar-dragger-disabled')).toBeFalsy();
|
||||
|
||||
// Collapse right
|
||||
onResize.mockReset();
|
||||
onResizeEnd.mockReset();
|
||||
fireEvent.click(container.querySelector('.ant-splitter-bar-collapse-end')!);
|
||||
expect(onResize).toHaveBeenCalledWith([100, 0]);
|
||||
expect(onResizeEnd).toHaveBeenCalledWith([100, 0]);
|
||||
expect(container.querySelector('.ant-splitter-bar-dragger-disabled')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
it('auto resize', async () => {
|
||||
containerSize = 200;
|
||||
|
||||
const onResize = jest.fn();
|
||||
const { container } = render(
|
||||
<SplitterDemo
|
||||
items={[
|
||||
{
|
||||
collapsible: true,
|
||||
},
|
||||
{},
|
||||
]}
|
||||
onResize={onResize}
|
||||
/>,
|
||||
);
|
||||
|
||||
triggerResize(container.querySelector('.ant-splitter')!);
|
||||
|
||||
await act(async () => {
|
||||
await waitFakeTimer();
|
||||
});
|
||||
|
||||
fireEvent.click(container.querySelector('.ant-splitter-bar-collapse-start')!);
|
||||
expect(onResize).toHaveBeenCalledWith([0, 200]);
|
||||
});
|
||||
});
|
7
components/splitter/demo/collapsible.md
Normal file
7
components/splitter/demo/collapsible.md
Normal file
@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
配置 `collapsible` 提供快捷收缩能力。可以通过 `min` 限制收缩后不能通过拖拽展开。
|
||||
|
||||
## en-US
|
||||
|
||||
Set `collapsible` to enable collapse. Can through `min` to limit dragging to expand when collapsed.
|
47
components/splitter/demo/collapsible.tsx
Normal file
47
components/splitter/demo/collapsible.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import React from 'react';
|
||||
import { Flex, Splitter, Typography } from 'antd';
|
||||
import type { SplitterProps } from 'antd';
|
||||
|
||||
const renderDesc = (text: string) => (
|
||||
<Flex justify="center" align="center" style={{ height: '100%' }}>
|
||||
<Typography.Title
|
||||
type="secondary"
|
||||
level={5}
|
||||
style={{
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
{text}
|
||||
</Typography.Title>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
const renderSplitter = ({ style, ...restProps }: SplitterProps) => (
|
||||
<Splitter
|
||||
style={{
|
||||
boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)',
|
||||
...style,
|
||||
}}
|
||||
{...restProps}
|
||||
>
|
||||
<Splitter.Panel collapsible min="20%">
|
||||
{renderDesc('first')}
|
||||
</Splitter.Panel>
|
||||
|
||||
<Splitter.Panel collapsible>{renderDesc('second')}</Splitter.Panel>
|
||||
</Splitter>
|
||||
);
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Flex gap="middle" vertical>
|
||||
{renderSplitter({
|
||||
style: { height: 200 },
|
||||
})}
|
||||
{renderSplitter({
|
||||
style: { height: 300 },
|
||||
layout: 'vertical',
|
||||
})}
|
||||
</Flex>
|
||||
);
|
||||
|
||||
export default App;
|
7
components/splitter/demo/control.md
Normal file
7
components/splitter/demo/control.md
Normal file
@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
受控调整尺寸。当 Panel 之间任意一方禁用 `resizable`,则其拖拽将被禁用。
|
||||
|
||||
## en-US
|
||||
|
||||
Control the size of the splitter. When one of the panels disables `resizable`, dragging will be disabled.
|
62
components/splitter/demo/control.tsx
Normal file
62
components/splitter/demo/control.tsx
Normal file
@ -0,0 +1,62 @@
|
||||
import React from 'react';
|
||||
import { Button, Flex, Splitter, Switch, Typography } from 'antd';
|
||||
|
||||
const renderDesc = (text: string) => (
|
||||
<Flex justify="center" align="center" style={{ height: '100%' }}>
|
||||
<Typography.Title
|
||||
type="secondary"
|
||||
level={5}
|
||||
style={{
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
{text}
|
||||
</Typography.Title>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
const App: React.FC = () => {
|
||||
const [sizes, setSizes] = React.useState<(number | string)[]>(['50%', '50%']);
|
||||
const [enabled, setEnabled] = React.useState(true);
|
||||
|
||||
return (
|
||||
<Flex vertical gap="middle">
|
||||
<Splitter
|
||||
style={{
|
||||
height: 200,
|
||||
boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)',
|
||||
}}
|
||||
onResize={(nextSizes) => {
|
||||
setSizes(nextSizes);
|
||||
}}
|
||||
>
|
||||
<Splitter.Panel size={sizes[0]} resizable={enabled}>
|
||||
{renderDesc('First')}
|
||||
</Splitter.Panel>
|
||||
|
||||
<Splitter.Panel size={sizes[1]}>{renderDesc('Second')}</Splitter.Panel>
|
||||
</Splitter>
|
||||
|
||||
<Flex gap="middle" justify="space-between">
|
||||
<Switch
|
||||
value={enabled}
|
||||
onChange={() => {
|
||||
setEnabled(!enabled);
|
||||
}}
|
||||
checkedChildren="Enabled"
|
||||
unCheckedChildren="Disabled"
|
||||
/>
|
||||
|
||||
<Button
|
||||
onClick={() => {
|
||||
setSizes(['50%', '50%']);
|
||||
}}
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
7
components/splitter/demo/debug.md
Normal file
7
components/splitter/demo/debug.md
Normal file
@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
面板 2 宽度为 0,面板 3 禁止调整大小。
|
||||
|
||||
## en-US
|
||||
|
||||
Panel 2 width is 0, panel 3 is not resizable.
|
78
components/splitter/demo/debug.tsx
Normal file
78
components/splitter/demo/debug.tsx
Normal file
@ -0,0 +1,78 @@
|
||||
import React from 'react';
|
||||
import { Flex, Splitter, Typography } from 'antd';
|
||||
|
||||
const renderDesc = (id: number) => (
|
||||
<Flex justify="center" align="center" style={{ height: '100%' }}>
|
||||
<Typography.Title
|
||||
type="secondary"
|
||||
level={5}
|
||||
style={{
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
Panel {id}
|
||||
</Typography.Title>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Flex vertical gap="middle">
|
||||
<Typography.Title level={3}>[true, 0, false]</Typography.Title>
|
||||
<Splitter
|
||||
style={{
|
||||
height: 200,
|
||||
boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)',
|
||||
}}
|
||||
>
|
||||
<Splitter.Panel>{renderDesc(1)}</Splitter.Panel>
|
||||
|
||||
<Splitter.Panel defaultSize={0}>{renderDesc(2)}</Splitter.Panel>
|
||||
|
||||
<Splitter.Panel resizable={false}>{renderDesc(3)}</Splitter.Panel>
|
||||
</Splitter>
|
||||
|
||||
<Typography.Title level={3}>[false, 0, true]</Typography.Title>
|
||||
<Splitter
|
||||
style={{
|
||||
height: 200,
|
||||
boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)',
|
||||
}}
|
||||
>
|
||||
<Splitter.Panel resizable={false}>{renderDesc(1)}</Splitter.Panel>
|
||||
|
||||
<Splitter.Panel defaultSize={0}>{renderDesc(2)}</Splitter.Panel>
|
||||
|
||||
<Splitter.Panel>{renderDesc(3)}</Splitter.Panel>
|
||||
</Splitter>
|
||||
|
||||
<Typography.Title level={3}>Start have min & max</Typography.Title>
|
||||
<Splitter
|
||||
style={{
|
||||
height: 200,
|
||||
boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)',
|
||||
}}
|
||||
>
|
||||
<Splitter.Panel min={50} max={100}>
|
||||
{renderDesc(1)}
|
||||
</Splitter.Panel>
|
||||
|
||||
<Splitter.Panel>{renderDesc(2)}</Splitter.Panel>
|
||||
</Splitter>
|
||||
|
||||
<Typography.Title level={3}>End have min & max</Typography.Title>
|
||||
<Splitter
|
||||
style={{
|
||||
height: 200,
|
||||
boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)',
|
||||
}}
|
||||
>
|
||||
<Splitter.Panel>{renderDesc(1)}</Splitter.Panel>
|
||||
|
||||
<Splitter.Panel min="20%" max="70%">
|
||||
{renderDesc(2)}
|
||||
</Splitter.Panel>
|
||||
</Splitter>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
export default App;
|
7
components/splitter/demo/group.md
Normal file
7
components/splitter/demo/group.md
Normal file
@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
复杂组合面板,快捷折叠,禁止改变大小
|
||||
|
||||
## en-US
|
||||
|
||||
Complex combination panel, quick folding, prohibited from changing size
|
35
components/splitter/demo/group.tsx
Normal file
35
components/splitter/demo/group.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
import React from 'react';
|
||||
import { Flex, Splitter, Typography } from 'antd';
|
||||
|
||||
const renderDesc = (text: string) => (
|
||||
<Flex justify="center" align="center" style={{ height: '100%' }}>
|
||||
<Typography.Title
|
||||
type="secondary"
|
||||
level={5}
|
||||
style={{
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
{text}
|
||||
</Typography.Title>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Splitter
|
||||
style={{
|
||||
height: 300,
|
||||
boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)',
|
||||
}}
|
||||
>
|
||||
<Splitter.Panel collapsible>{renderDesc('Left')}</Splitter.Panel>
|
||||
<Splitter.Panel>
|
||||
<Splitter layout="vertical">
|
||||
<Splitter.Panel>{renderDesc('Top')}</Splitter.Panel>
|
||||
<Splitter.Panel>{renderDesc('Bottom')}</Splitter.Panel>
|
||||
</Splitter>
|
||||
</Splitter.Panel>
|
||||
</Splitter>
|
||||
);
|
||||
|
||||
export default App;
|
7
components/splitter/demo/multiple.md
Normal file
7
components/splitter/demo/multiple.md
Normal file
@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
多面板
|
||||
|
||||
## en-US
|
||||
|
||||
Multiple panels.
|
39
components/splitter/demo/multiple.tsx
Normal file
39
components/splitter/demo/multiple.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
import React from 'react';
|
||||
import { Flex, Splitter, Typography } from 'antd';
|
||||
|
||||
const renderDesc = (id: number) => (
|
||||
<Flex justify="center" align="center" style={{ height: '100%' }}>
|
||||
<Typography.Title
|
||||
type="secondary"
|
||||
level={5}
|
||||
style={{
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
Panel {id}
|
||||
</Typography.Title>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Splitter
|
||||
style={{
|
||||
height: 200,
|
||||
boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)',
|
||||
}}
|
||||
>
|
||||
<Splitter.Panel collapsible>{renderDesc(1)}</Splitter.Panel>
|
||||
|
||||
<Splitter.Panel
|
||||
collapsible={{
|
||||
start: true,
|
||||
}}
|
||||
>
|
||||
{renderDesc(2)}
|
||||
</Splitter.Panel>
|
||||
|
||||
<Splitter.Panel>{renderDesc(3)}</Splitter.Panel>
|
||||
</Splitter>
|
||||
);
|
||||
|
||||
export default App;
|
7
components/splitter/demo/size.md
Normal file
7
components/splitter/demo/size.md
Normal file
@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
初始化面板大小,面板大小限制。
|
||||
|
||||
## en-US
|
||||
|
||||
Initialize panel size, panel size limit.
|
27
components/splitter/demo/size.tsx
Normal file
27
components/splitter/demo/size.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import React from 'react';
|
||||
import { Flex, Splitter, Typography } from 'antd';
|
||||
|
||||
const renderDesc = (text: string) => (
|
||||
<Flex justify="center" align="center" style={{ height: '100%' }}>
|
||||
<Typography.Title type="secondary" level={5}>
|
||||
{text}
|
||||
</Typography.Title>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Splitter
|
||||
style={{
|
||||
height: 200,
|
||||
boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)',
|
||||
}}
|
||||
>
|
||||
<Splitter.Panel defaultSize="40%" min="20%" max="70%">
|
||||
{renderDesc('First')}
|
||||
</Splitter.Panel>
|
||||
|
||||
<Splitter.Panel>{renderDesc('Second')}</Splitter.Panel>
|
||||
</Splitter>
|
||||
);
|
||||
|
||||
export default App;
|
7
components/splitter/demo/vertical.md
Normal file
7
components/splitter/demo/vertical.md
Normal file
@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
使用垂直布局。
|
||||
|
||||
## en-US
|
||||
|
||||
Use vertical layout.
|
26
components/splitter/demo/vertical.tsx
Normal file
26
components/splitter/demo/vertical.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import { Flex, Splitter, Typography } from 'antd';
|
||||
|
||||
const renderDesc = (text: string) => (
|
||||
<Flex justify="center" align="center" style={{ height: '100%' }}>
|
||||
<Typography.Title type="secondary" level={5}>
|
||||
{text}
|
||||
</Typography.Title>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Splitter
|
||||
layout="vertical"
|
||||
style={{
|
||||
height: 300,
|
||||
boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)',
|
||||
}}
|
||||
>
|
||||
<Splitter.Panel>{renderDesc('First')}</Splitter.Panel>
|
||||
|
||||
<Splitter.Panel>{renderDesc('Second')}</Splitter.Panel>
|
||||
</Splitter>
|
||||
);
|
||||
|
||||
export default App;
|
45
components/splitter/hooks/useItems.ts
Normal file
45
components/splitter/hooks/useItems.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import * as React from 'react';
|
||||
import toArray from 'rc-util/lib/Children/toArray';
|
||||
|
||||
import type { PanelProps } from '../interface';
|
||||
|
||||
function getCollapsible(collapsible?: PanelProps['collapsible']) {
|
||||
if (collapsible && typeof collapsible === 'object') {
|
||||
return collapsible;
|
||||
}
|
||||
|
||||
const mergedCollapsible = !!collapsible;
|
||||
return {
|
||||
start: mergedCollapsible,
|
||||
end: mergedCollapsible,
|
||||
};
|
||||
}
|
||||
|
||||
export type ItemType = Omit<PanelProps, 'collapsible'> & {
|
||||
collapsible: {
|
||||
start?: boolean;
|
||||
end?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert `children` into `items`.
|
||||
*/
|
||||
export default function useItems(children: React.ReactNode): ItemType[] {
|
||||
const items = React.useMemo(
|
||||
() =>
|
||||
toArray(children)
|
||||
.filter(React.isValidElement)
|
||||
.map((node) => {
|
||||
const { props } = node as React.ReactElement<PanelProps>;
|
||||
const { collapsible, ...restProps } = props;
|
||||
|
||||
return {
|
||||
...restProps,
|
||||
collapsible: getCollapsible(collapsible),
|
||||
};
|
||||
}),
|
||||
[children],
|
||||
);
|
||||
return items;
|
||||
}
|
62
components/splitter/hooks/useResizable.ts
Normal file
62
components/splitter/hooks/useResizable.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import type { ItemType } from './useItems';
|
||||
|
||||
export type ResizableInfo = {
|
||||
resizable: boolean;
|
||||
startCollapsible: boolean;
|
||||
endCollapsible: boolean;
|
||||
};
|
||||
|
||||
export default function useResizable(items: ItemType[], pxSizes: number[]) {
|
||||
return React.useMemo(() => {
|
||||
const resizeInfos: ResizableInfo[] = [];
|
||||
|
||||
for (let i = 0; i < items.length - 1; i += 1) {
|
||||
const prevItem = items[i];
|
||||
const nextItem = items[i + 1];
|
||||
const prevSize = pxSizes[i];
|
||||
const nextSize = pxSizes[i + 1];
|
||||
|
||||
const {
|
||||
resizable: prevResizable = true,
|
||||
min: prevMin,
|
||||
collapsible: prevCollapsible,
|
||||
} = prevItem;
|
||||
const {
|
||||
resizable: nextResizable = true,
|
||||
min: nextMin,
|
||||
collapsible: nextCollapsible,
|
||||
} = nextItem;
|
||||
|
||||
const mergedResizable =
|
||||
// Both need to be resizable
|
||||
prevResizable &&
|
||||
nextResizable &&
|
||||
// Prev is not collapsed and limit min size
|
||||
(prevSize !== 0 || !prevMin) &&
|
||||
// Next is not collapsed and limit min size
|
||||
(nextSize !== 0 || !nextMin);
|
||||
|
||||
const startCollapsible =
|
||||
// Self is collapsible
|
||||
(prevCollapsible.end && prevSize > 0) ||
|
||||
// Collapsed and can be collapsed
|
||||
(nextCollapsible.start && nextSize === 0 && prevSize > 0);
|
||||
|
||||
const endCollapsible =
|
||||
// Self is collapsible
|
||||
(nextCollapsible.start && nextSize > 0) ||
|
||||
// Collapsed and can be collapsed
|
||||
(prevCollapsible.end && prevSize === 0 && nextSize > 0);
|
||||
|
||||
resizeInfos[i] = {
|
||||
resizable: mergedResizable,
|
||||
startCollapsible: !!startCollapsible,
|
||||
endCollapsible: !!endCollapsible,
|
||||
};
|
||||
}
|
||||
|
||||
return resizeInfos;
|
||||
}, [pxSizes, items]);
|
||||
}
|
150
components/splitter/hooks/useResize.ts
Normal file
150
components/splitter/hooks/useResize.ts
Normal file
@ -0,0 +1,150 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import type { ItemType } from './useItems';
|
||||
import type { ResizableInfo } from './useResizable';
|
||||
import { getPtg } from './useSizes';
|
||||
|
||||
export default function useResize(
|
||||
items: ItemType[],
|
||||
resizableInfos: ResizableInfo[],
|
||||
percentSizes: number[],
|
||||
containerSize: number,
|
||||
updateSizes: (sizes: number[]) => void,
|
||||
) {
|
||||
const limitSizes = items.map((item) => [item.min, item.max]);
|
||||
|
||||
const ptg2px = (ptg: number) => ptg * containerSize;
|
||||
|
||||
// ======================== Resize ========================
|
||||
function getLimitSize(str: string | number | undefined, defaultLimit: number) {
|
||||
if (typeof str === 'string') {
|
||||
return ptg2px(getPtg(str));
|
||||
}
|
||||
return str ?? defaultLimit;
|
||||
}
|
||||
|
||||
// Real px sizes
|
||||
const [cacheSizes, setCacheSizes] = React.useState<number[]>([]);
|
||||
|
||||
/**
|
||||
* When start drag, check the direct is `start` or `end`.
|
||||
* This will handle when 2 splitter bar are in the same position.
|
||||
*/
|
||||
const [movingIndex, setMovingIndex] = React.useState<{
|
||||
index: number;
|
||||
confirmed: boolean;
|
||||
} | null>(null);
|
||||
|
||||
const getPxSizes = () => percentSizes.map(ptg2px);
|
||||
|
||||
const onOffsetStart = (index: number) => {
|
||||
setCacheSizes(getPxSizes());
|
||||
setMovingIndex({
|
||||
index,
|
||||
confirmed: false,
|
||||
});
|
||||
};
|
||||
|
||||
const onOffsetUpdate = (index: number, offset: number) => {
|
||||
// First time trigger move index update is not sync in the state
|
||||
let confirmedIndex: number | null = null;
|
||||
|
||||
// We need to know what the real index is.
|
||||
if ((!movingIndex || !movingIndex.confirmed) && offset !== 0) {
|
||||
// Search for the real index
|
||||
if (offset > 0) {
|
||||
confirmedIndex = index;
|
||||
setMovingIndex({
|
||||
index,
|
||||
confirmed: true,
|
||||
});
|
||||
} else {
|
||||
for (let i = index; i >= 0; i -= 1) {
|
||||
if (cacheSizes[i] > 0 && resizableInfos[i].resizable) {
|
||||
confirmedIndex = i;
|
||||
setMovingIndex({
|
||||
index: i,
|
||||
confirmed: true,
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const mergedIndex = confirmedIndex ?? movingIndex?.index ?? index;
|
||||
|
||||
const numSizes = [...cacheSizes];
|
||||
const nextIndex = mergedIndex + 1;
|
||||
|
||||
// Get boundary
|
||||
const startMinSize = getLimitSize(limitSizes[mergedIndex][0], 0);
|
||||
const endMinSize = getLimitSize(limitSizes[nextIndex][0], 0);
|
||||
const startMaxSize = getLimitSize(limitSizes[mergedIndex][1], containerSize);
|
||||
const endMaxSize = getLimitSize(limitSizes[nextIndex][1], containerSize);
|
||||
|
||||
let mergedOffset = offset;
|
||||
|
||||
// Align with the boundary
|
||||
if (numSizes[mergedIndex] + mergedOffset < startMinSize) {
|
||||
mergedOffset = startMinSize - numSizes[mergedIndex];
|
||||
}
|
||||
if (numSizes[nextIndex] - mergedOffset < endMinSize) {
|
||||
mergedOffset = numSizes[nextIndex] - endMinSize;
|
||||
}
|
||||
if (numSizes[mergedIndex] + mergedOffset > startMaxSize) {
|
||||
mergedOffset = startMaxSize - numSizes[mergedIndex];
|
||||
}
|
||||
if (numSizes[nextIndex] - mergedOffset > endMaxSize) {
|
||||
mergedOffset = numSizes[nextIndex] - endMaxSize;
|
||||
}
|
||||
|
||||
// Do offset
|
||||
numSizes[mergedIndex] += mergedOffset;
|
||||
numSizes[nextIndex] -= mergedOffset;
|
||||
|
||||
updateSizes(numSizes);
|
||||
|
||||
return numSizes;
|
||||
};
|
||||
|
||||
const onOffsetEnd = () => {
|
||||
setMovingIndex(null);
|
||||
};
|
||||
|
||||
// ======================= Collapse =======================
|
||||
const onCollapse = (index: number, type: 'start' | 'end') => {
|
||||
const currentSizes = getPxSizes();
|
||||
|
||||
const currentIndex = type === 'start' ? index : index + 1;
|
||||
const targetIndex = type === 'start' ? index + 1 : index;
|
||||
|
||||
const currentSize = currentSizes[currentIndex];
|
||||
const targetSize = currentSizes[targetIndex];
|
||||
|
||||
if (currentSize !== 0 && targetSize !== 0) {
|
||||
// Collapse directly
|
||||
currentSizes[currentIndex] = 0;
|
||||
currentSizes[targetIndex] += currentSize;
|
||||
} else {
|
||||
const totalSize = currentSize + targetSize;
|
||||
|
||||
const currentSizeMin = getLimitSize(limitSizes[currentIndex][0], 0);
|
||||
const currentSizeMax = getLimitSize(limitSizes[currentIndex][1], containerSize);
|
||||
const targetSizeMin = getLimitSize(limitSizes[targetIndex][0], 0);
|
||||
const targetSizeMax = getLimitSize(limitSizes[targetIndex][1], containerSize);
|
||||
|
||||
const limitStart = Math.max(currentSizeMin, totalSize - targetSizeMax);
|
||||
const limitEnd = Math.min(currentSizeMax, totalSize - targetSizeMin);
|
||||
const halfOffset = (limitEnd - limitStart) / 2;
|
||||
|
||||
currentSizes[currentIndex] -= halfOffset;
|
||||
currentSizes[targetIndex] += halfOffset;
|
||||
}
|
||||
|
||||
updateSizes(currentSizes);
|
||||
|
||||
return currentSizes;
|
||||
};
|
||||
|
||||
return [onOffsetStart, onOffsetUpdate, onOffsetEnd, onCollapse, movingIndex?.index] as const;
|
||||
}
|
113
components/splitter/hooks/useSizes.ts
Normal file
113
components/splitter/hooks/useSizes.ts
Normal file
@ -0,0 +1,113 @@
|
||||
import React from 'react';
|
||||
|
||||
import type { PanelProps } from '../interface';
|
||||
|
||||
export function getPtg(str: string) {
|
||||
return Number(str.slice(0, -1)) / 100;
|
||||
}
|
||||
|
||||
function isPtg(itemSize: string | number | undefined): itemSize is string {
|
||||
return typeof itemSize === 'string' && itemSize.endsWith('%');
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the size state.
|
||||
* Align the size into flex percentage base.
|
||||
*/
|
||||
export default function useSizes(items: PanelProps[], containerSize: number) {
|
||||
const propSizes = items.map((item) => item.size);
|
||||
|
||||
const itemsCount = items.length;
|
||||
|
||||
const ptg2px = (ptg: number) => ptg * containerSize;
|
||||
|
||||
// We do not need care the size state match the `items` length in `useState`.
|
||||
// It will calculate later.
|
||||
const [innerSizes, setInnerSizes] = React.useState<(string | number | undefined)[]>(() =>
|
||||
items.map((item) => item.defaultSize),
|
||||
);
|
||||
const sizes = React.useMemo(() => {
|
||||
const mergedSizes = [];
|
||||
|
||||
for (let i = 0; i < itemsCount; i += 1) {
|
||||
mergedSizes[i] = propSizes[i] ?? innerSizes[i];
|
||||
}
|
||||
|
||||
return mergedSizes;
|
||||
}, [itemsCount, innerSizes, propSizes]);
|
||||
|
||||
// Post handle the size. Will do:
|
||||
// 1. Convert all the px into percentage if not empty.
|
||||
// 2. Get rest percentage for exist percentage.
|
||||
// 3. Fill the rest percentage into empty item.
|
||||
const postPercentSizes = React.useMemo(() => {
|
||||
let ptgList: (number | undefined)[] = [];
|
||||
let emptyCount = 0;
|
||||
|
||||
// Fill default percentage
|
||||
for (let i = 0; i < itemsCount; i += 1) {
|
||||
const itemSize = sizes[i];
|
||||
|
||||
if (isPtg(itemSize)) {
|
||||
ptgList[i] = getPtg(itemSize);
|
||||
} else if (itemSize || itemSize === 0) {
|
||||
const num = Number(itemSize);
|
||||
if (!Number.isNaN(num)) {
|
||||
ptgList[i] = num / containerSize;
|
||||
}
|
||||
} else {
|
||||
emptyCount += 1;
|
||||
ptgList[i] = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const totalPtg = ptgList.reduce((acc: number, ptg) => acc + (ptg || 0), 0);
|
||||
|
||||
if (totalPtg > 1 || !emptyCount) {
|
||||
// If total percentage is larger than 1, we will scale it down.
|
||||
const scale = 1 / totalPtg;
|
||||
ptgList = ptgList.map((ptg) => (ptg === undefined ? 0 : ptg * scale));
|
||||
} else {
|
||||
// If total percentage is smaller than 1, we will fill the rest.
|
||||
const avgRest = (1 - totalPtg) / emptyCount;
|
||||
ptgList = ptgList.map((ptg) => (ptg === undefined ? avgRest : ptg));
|
||||
}
|
||||
|
||||
return ptgList as number[];
|
||||
}, [sizes, containerSize]);
|
||||
|
||||
const postPxSizes = React.useMemo(
|
||||
() => postPercentSizes.map(ptg2px),
|
||||
[postPercentSizes, containerSize],
|
||||
);
|
||||
|
||||
const postPercentMinSizes = React.useMemo(
|
||||
() =>
|
||||
items.map((item) => {
|
||||
if (isPtg(item.min)) {
|
||||
return getPtg(item.min);
|
||||
}
|
||||
return (item.min || 0) / containerSize;
|
||||
}),
|
||||
[items, containerSize],
|
||||
);
|
||||
|
||||
const postPercentMaxSizes = React.useMemo(
|
||||
() =>
|
||||
items.map((item) => {
|
||||
if (isPtg(item.max)) {
|
||||
return getPtg(item.max);
|
||||
}
|
||||
return (item.max || containerSize) / containerSize;
|
||||
}),
|
||||
[items, containerSize],
|
||||
);
|
||||
|
||||
return [
|
||||
postPxSizes,
|
||||
postPercentSizes,
|
||||
postPercentMinSizes,
|
||||
postPercentMaxSizes,
|
||||
setInnerSizes,
|
||||
] as const;
|
||||
}
|
55
components/splitter/index.en-US.md
Normal file
55
components/splitter/index.en-US.md
Normal file
@ -0,0 +1,55 @@
|
||||
---
|
||||
category: Components
|
||||
group: Layout
|
||||
title: Splitter
|
||||
description: Split panels are used to isolate areas and display multiple contents.
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*mQmMTYq6OjYAAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*7v4GTo2Ely8AAAAAAAAAAAAADrJ8AQ/original
|
||||
demo:
|
||||
cols: 1
|
||||
tag: 5.21.0
|
||||
---
|
||||
|
||||
## When To Use
|
||||
|
||||
You need to display multiple contents, and you want users to be able to adjust the size of each content freely.
|
||||
|
||||
- The Splitter component needs to calculate the panel size through its child elements, so its child elements only support `Splitter.Panel`。
|
||||
|
||||
## Examples
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/size.tsx">Basic</code>
|
||||
<code src="./demo/control.tsx">Control mode</code>
|
||||
<code src="./demo/vertical.tsx">Vertical</code>
|
||||
<code src="./demo/collapsible.tsx">Collapsible</code>
|
||||
<code src="./demo/multiple.tsx">Multiple panels</code>
|
||||
<code src="./demo/group.tsx">Complex combination</code>
|
||||
<code src="./demo/debug.tsx" debug>Debug</code>
|
||||
|
||||
## API
|
||||
|
||||
Common props ref:[Common props](/docs/react/common-props)
|
||||
|
||||
### Splitter
|
||||
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| layout | Layout direction | `horizontal` \| `vertical` | `horizontal` | - |
|
||||
| onResizeStart | Callback before dragging starts | `(sizes: number[]) => void` | - | - |
|
||||
| onResize | Panel size change callback | `(sizes: number[]) => void` | - | - |
|
||||
| onResizeEnd | Drag end callback | `(sizes: number[]) => void` | - | - |
|
||||
|
||||
### Panel
|
||||
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| min | Minimum threshold support number for px or 'percent%' usage | `number \| string` | - | - |
|
||||
| max | Maximum threshold support number for px or 'percent%' usage | `number \| string` | - | - |
|
||||
| size | Controlled panel size support number for px or 'percent%' usage | `number \| string` | - | - |
|
||||
| collapsible | Quick folding | `boolean \| { start?: boolean; end?: boolean }` | `false` | - |
|
||||
| resizable | Whether to enable drag and drop | `boolean` | `true` | - |
|
||||
|
||||
## Design Token
|
||||
|
||||
<ComponentTokenTable component='Splitter'></ComponentTokenTable>
|
13
components/splitter/index.tsx
Normal file
13
components/splitter/index.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import Panel from './Panel';
|
||||
import SplitterComp from './Splitter';
|
||||
|
||||
export type { SplitterProps } from './interface';
|
||||
|
||||
type CompoundedComponent = typeof SplitterComp & {
|
||||
Panel: typeof Panel;
|
||||
};
|
||||
|
||||
const Splitter = SplitterComp as CompoundedComponent;
|
||||
Splitter.Panel = Panel;
|
||||
|
||||
export default Splitter;
|
56
components/splitter/index.zh-CN.md
Normal file
56
components/splitter/index.zh-CN.md
Normal file
@ -0,0 +1,56 @@
|
||||
---
|
||||
category: Components
|
||||
group: 布局
|
||||
title: Splitter
|
||||
subtitle: 分隔面板
|
||||
description: 分割面板用于隔离区域,展示多个内容。
|
||||
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*mQmMTYq6OjYAAAAAAAAAAAAADrJ8AQ/original
|
||||
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*7v4GTo2Ely8AAAAAAAAAAAAADrJ8AQ/original
|
||||
demo:
|
||||
cols: 1
|
||||
tag: 5.21.0
|
||||
---
|
||||
|
||||
## 何时使用
|
||||
|
||||
需要展示多个内容,并且希望用户可以自由调整每个内容的大小。
|
||||
|
||||
- Splitter 组件需要通过子元素计算面板大小,因而其子元素仅支持 `Splitter.Panel`。
|
||||
|
||||
## 代码演示
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
<code src="./demo/size.tsx">基本用法</code>
|
||||
<code src="./demo/control.tsx">受控模式</code>
|
||||
<code src="./demo/vertical.tsx">垂直方向</code>
|
||||
<code src="./demo/collapsible.tsx">可折叠</code>
|
||||
<code src="./demo/multiple.tsx">多面板</code>
|
||||
<code src="./demo/group.tsx">复杂组合</code>
|
||||
<code src="./demo/debug.tsx" debug>调试</code>
|
||||
|
||||
## API
|
||||
|
||||
通用属性参考:[通用属性](/docs/react/common-props)
|
||||
|
||||
### Splitter
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| ------------- | ---------------- | --------------------------- | ------------ | ---- |
|
||||
| layout | 布局方向 | `horizontal` \| `vertical` | `horizontal` | - |
|
||||
| onResizeStart | 开始拖拽之前回调 | `(sizes: number[]) => void` | - | - |
|
||||
| onResize | 面板大小变化回调 | `(sizes: number[]) => void` | - | - |
|
||||
| onResizeEnd | 拖拽结束回调 | `(sizes: number[]) => void` | - | - |
|
||||
|
||||
### Panel
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| min | 最小阈值,支持数字 px 或者文字 '百分比%' 类型 | `number \| string` | - | - |
|
||||
| max | 最大阈值,支持数字 px 或者文字 '百分比%' 类型 | `number \| string` | - | - |
|
||||
| size | 受控面板大小,支持数字 px 或者文字 '百分比%' 类型 | `number \| string` | - | - |
|
||||
| collapsible | 快速折叠 | `boolean \| { start?: boolean; end?: boolean }` | `false` | - |
|
||||
| resizable | 是否开启拖拽伸缩 | `boolean` | `true` | - |
|
||||
|
||||
## 主题变量(Design Token)
|
||||
|
||||
<ComponentTokenTable component='Splitter'></ComponentTokenTable>
|
72
components/splitter/interface.ts
Normal file
72
components/splitter/interface.ts
Normal file
@ -0,0 +1,72 @@
|
||||
// ================ outside ================
|
||||
export interface SplitterProps {
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
rootClassName?: string;
|
||||
layout?: 'horizontal' | 'vertical';
|
||||
onResizeStart?: (sizes: number[]) => void;
|
||||
onResize?: (sizes: number[]) => void;
|
||||
onResizeEnd?: (sizes: number[]) => void;
|
||||
}
|
||||
|
||||
export interface PanelProps {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
min?: number | string;
|
||||
max?: number | string;
|
||||
size?: number | string;
|
||||
collapsible?:
|
||||
| boolean
|
||||
| {
|
||||
start?: boolean;
|
||||
end?: boolean;
|
||||
};
|
||||
resizable?: boolean;
|
||||
defaultSize?: number | string;
|
||||
}
|
||||
|
||||
// ================ inside ================
|
||||
|
||||
export interface InternalPanelProps extends PanelProps {
|
||||
className?: string;
|
||||
prefixCls?: string;
|
||||
}
|
||||
|
||||
export interface UseResizeProps extends Pick<SplitterProps, 'onResize'> {
|
||||
basicsState: number[];
|
||||
items: PanelProps[];
|
||||
panelsRef: React.RefObject<(HTMLDivElement | null)[]>;
|
||||
reverse: boolean;
|
||||
setBasicsState: React.Dispatch<React.SetStateAction<number[]>>;
|
||||
}
|
||||
export interface UseResize {
|
||||
setSize: (data: { size: number; index: number }[]) => void;
|
||||
setOffset: (offset: number, containerSize: number, index: number) => void;
|
||||
}
|
||||
|
||||
export interface UseHandleProps
|
||||
extends Pick<SplitterProps, 'layout' | 'onResizeStart' | 'onResizeEnd'> {
|
||||
basicsState: number[];
|
||||
containerRef?: React.RefObject<HTMLDivElement | null>;
|
||||
setOffset: UseResize['setOffset'];
|
||||
setResizing: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
}
|
||||
export interface UseHandle {
|
||||
onStart: (x: number, y: number, index: number) => void;
|
||||
}
|
||||
|
||||
export interface UseCollapsibleProps {
|
||||
basicsState: number[];
|
||||
collapsible?: PanelProps['collapsible'];
|
||||
index: number;
|
||||
reverse: boolean;
|
||||
setSize?: UseResize['setSize'];
|
||||
}
|
||||
export interface UseCollapsible {
|
||||
nextIcon: boolean;
|
||||
overlap: boolean;
|
||||
previousIcon: boolean;
|
||||
onFold: (type: 'previous' | 'next') => void;
|
||||
setOldBasics: () => void;
|
||||
}
|
338
components/splitter/style/index.ts
Normal file
338
components/splitter/style/index.ts
Normal file
@ -0,0 +1,338 @@
|
||||
import type { CSSObject } from '@ant-design/cssinjs';
|
||||
|
||||
import { resetComponent } from '../../style';
|
||||
import type { FullToken, GenerateStyle, GetDefaultToken } from '../../theme/internal';
|
||||
import { genStyleHooks } from '../../theme/internal';
|
||||
|
||||
export interface ComponentToken {
|
||||
/**
|
||||
* @desc 可改变大小标识 元素大小
|
||||
* @descEN Height of content area
|
||||
*/
|
||||
resizeSpinnerSize: number;
|
||||
/**
|
||||
* @desc 拖拽标识元素大小
|
||||
* @descEN Drag the element size
|
||||
*/
|
||||
splitBarSize: number;
|
||||
/**
|
||||
* @desc 拖拽触发区域大小
|
||||
* @descEN Drag and drop trigger area size
|
||||
*/
|
||||
splitTriggerSize: number;
|
||||
}
|
||||
|
||||
interface SplitterToken extends FullToken<'Splitter'> {}
|
||||
|
||||
const genRtlStyle = (token: SplitterToken): CSSObject => {
|
||||
const { componentCls } = token;
|
||||
return {
|
||||
[`&-rtl${componentCls}-horizontal`]: {
|
||||
[`> ${componentCls}-bar`]: {
|
||||
[`${componentCls}-bar-collapse-previous`]: {
|
||||
insetInlineEnd: 0,
|
||||
insetInlineStart: 'unset',
|
||||
},
|
||||
|
||||
[`${componentCls}-bar-collapse-next`]: {
|
||||
insetInlineEnd: 'unset',
|
||||
insetInlineStart: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
[`&-rtl${componentCls}-vertical`]: {
|
||||
[`> ${componentCls}-bar`]: {
|
||||
[`${componentCls}-bar-collapse-previous`]: {
|
||||
insetInlineEnd: '50%',
|
||||
insetInlineStart: 'unset',
|
||||
},
|
||||
|
||||
[`${componentCls}-bar-collapse-next`]: {
|
||||
insetInlineEnd: '50%',
|
||||
insetInlineStart: 'unset',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const centerStyle: CSSObject = {
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
left: {
|
||||
_skip_check_: true,
|
||||
value: '50%',
|
||||
},
|
||||
transform: 'translate(-50%, -50%)',
|
||||
};
|
||||
|
||||
const genSplitterStyle: GenerateStyle<SplitterToken> = (token: SplitterToken): CSSObject => {
|
||||
const {
|
||||
componentCls,
|
||||
colorFill,
|
||||
resizeSpinnerSize,
|
||||
splitBarSize,
|
||||
splitTriggerSize,
|
||||
controlItemBgHover,
|
||||
controlItemBgActive,
|
||||
controlItemBgActiveHover,
|
||||
} = token;
|
||||
|
||||
const splitBarCls = `${componentCls}-bar`;
|
||||
|
||||
const halfTriggerSize = token.calc(splitTriggerSize).div(2).equal();
|
||||
|
||||
return {
|
||||
[componentCls]: {
|
||||
...resetComponent(token),
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
alignItems: 'stretch',
|
||||
|
||||
// ======================== SplitBar ========================
|
||||
// Use `>` to avoid conflict with mix layout
|
||||
[`> ${splitBarCls}`]: {
|
||||
flex: 'none',
|
||||
position: 'relative',
|
||||
userSelect: 'none',
|
||||
|
||||
// ======================= Dragger =======================
|
||||
[`${splitBarCls}-dragger`]: {
|
||||
...centerStyle,
|
||||
zIndex: 1,
|
||||
|
||||
// Hover background
|
||||
'&:before': {
|
||||
content: '""',
|
||||
background: controlItemBgHover,
|
||||
...centerStyle,
|
||||
},
|
||||
|
||||
// Spinner
|
||||
'&:after': {
|
||||
content: '""',
|
||||
background: colorFill,
|
||||
...centerStyle,
|
||||
},
|
||||
|
||||
// Hover
|
||||
[`&:hover:not(${splitBarCls}-dragger-active)`]: {
|
||||
'&:before': {
|
||||
background: controlItemBgActive,
|
||||
},
|
||||
},
|
||||
|
||||
// Active
|
||||
'&-active': {
|
||||
zIndex: 2,
|
||||
|
||||
'&:before': {
|
||||
background: controlItemBgActiveHover,
|
||||
},
|
||||
},
|
||||
|
||||
// Disabled, not use `pointer-events: none` since still need trigger collapse
|
||||
[`&-disabled${splitBarCls}-dragger`]: {
|
||||
zIndex: 0,
|
||||
|
||||
'&, &:hover, &-active': {
|
||||
cursor: 'default',
|
||||
'&:before': {
|
||||
background: controlItemBgHover,
|
||||
},
|
||||
},
|
||||
|
||||
'&:after': {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// ======================= Collapse =======================
|
||||
[`${splitBarCls}-collapse-bar`]: {
|
||||
...centerStyle,
|
||||
zIndex: 1,
|
||||
background: controlItemBgHover,
|
||||
fontSize: token.fontSizeSM,
|
||||
borderRadius: token.borderRadiusXS,
|
||||
color: token.colorText,
|
||||
cursor: 'pointer',
|
||||
opacity: 0,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
|
||||
// Hover
|
||||
'&:hover': {
|
||||
background: controlItemBgActive,
|
||||
},
|
||||
|
||||
// Active
|
||||
'&:active': {
|
||||
background: controlItemBgActiveHover,
|
||||
},
|
||||
},
|
||||
|
||||
// ======================== Status ========================
|
||||
// Hover
|
||||
'&:hover, &:active': {
|
||||
[`${splitBarCls}-collapse-bar`]: {
|
||||
opacity: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// =========================== Mask =========================
|
||||
// Util dom for handle cursor
|
||||
'&-mask': {
|
||||
position: 'fixed',
|
||||
zIndex: token.zIndexPopupBase,
|
||||
inset: 0,
|
||||
|
||||
'&-horizontal': {
|
||||
cursor: 'col-resize',
|
||||
},
|
||||
|
||||
'&-vertical': {
|
||||
cursor: 'row-resize',
|
||||
},
|
||||
},
|
||||
|
||||
// ==========================================================
|
||||
// == Layout ==
|
||||
// ==========================================================
|
||||
'&-horizontal': {
|
||||
flexDirection: 'row',
|
||||
|
||||
[`> ${splitBarCls}`]: {
|
||||
width: 0,
|
||||
|
||||
// ======================= Dragger =======================
|
||||
[`${splitBarCls}-dragger`]: {
|
||||
cursor: 'col-resize',
|
||||
height: '100%',
|
||||
width: splitTriggerSize,
|
||||
|
||||
'&:before': {
|
||||
height: '100%',
|
||||
width: splitBarSize,
|
||||
},
|
||||
|
||||
'&:after': {
|
||||
height: resizeSpinnerSize,
|
||||
width: splitBarSize,
|
||||
},
|
||||
},
|
||||
|
||||
// ======================= Collapse =======================
|
||||
[`${splitBarCls}-collapse-bar`]: {
|
||||
width: token.fontSizeSM,
|
||||
height: token.controlHeightSM,
|
||||
|
||||
'&-start': {
|
||||
left: {
|
||||
_skip_check_: true,
|
||||
value: 'auto',
|
||||
},
|
||||
right: {
|
||||
_skip_check_: true,
|
||||
value: halfTriggerSize,
|
||||
},
|
||||
transform: 'translateY(-50%)',
|
||||
},
|
||||
|
||||
'&-end': {
|
||||
left: {
|
||||
_skip_check_: true,
|
||||
value: halfTriggerSize,
|
||||
},
|
||||
right: {
|
||||
_skip_check_: true,
|
||||
value: 'auto',
|
||||
},
|
||||
transform: 'translateY(-50%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
'&-vertical': {
|
||||
flexDirection: 'column',
|
||||
|
||||
[`> ${splitBarCls}`]: {
|
||||
height: 0,
|
||||
|
||||
// ======================= Dragger =======================
|
||||
[`${splitBarCls}-dragger`]: {
|
||||
cursor: 'row-resize',
|
||||
width: '100%',
|
||||
height: splitTriggerSize,
|
||||
|
||||
'&:before': {
|
||||
width: '100%',
|
||||
height: splitBarSize,
|
||||
},
|
||||
|
||||
'&:after': {
|
||||
width: resizeSpinnerSize,
|
||||
height: splitBarSize,
|
||||
},
|
||||
},
|
||||
|
||||
// ======================= Collapse =======================
|
||||
[`${splitBarCls}-collapse-bar`]: {
|
||||
height: token.fontSizeSM,
|
||||
width: token.controlHeightSM,
|
||||
|
||||
'&-start': {
|
||||
top: 'auto',
|
||||
bottom: halfTriggerSize,
|
||||
transform: 'translateX(-50%)',
|
||||
},
|
||||
|
||||
'&-end': {
|
||||
top: halfTriggerSize,
|
||||
bottom: 'auto',
|
||||
transform: 'translateX(-50%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// ========================= Panels =========================
|
||||
'&-panel': {
|
||||
overflow: 'auto',
|
||||
padding: '0 1px',
|
||||
scrollbarWidth: 'thin',
|
||||
boxSizing: 'border-box',
|
||||
},
|
||||
'&-panel-hidden': {
|
||||
padding: 0,
|
||||
},
|
||||
|
||||
...genRtlStyle(token),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const prepareComponentToken: GetDefaultToken<'Splitter'> = (token) => {
|
||||
const splitBarSize = token.splitBarSize || 2;
|
||||
const splitTriggerSize = token.splitTriggerSize || 6;
|
||||
|
||||
const resizeSpinnerSize = token.resizeSpinnerSize || 20;
|
||||
|
||||
return {
|
||||
splitBarSize,
|
||||
splitTriggerSize,
|
||||
resizeSpinnerSize,
|
||||
};
|
||||
};
|
||||
|
||||
// ============================== Export ==============================
|
||||
export default genStyleHooks(
|
||||
'Splitter',
|
||||
(token) => [genSplitterStyle(token)],
|
||||
prepareComponentToken,
|
||||
);
|
@ -63,6 +63,7 @@ import type { ComponentToken as TreeSelectComponentToken } from '../../tree-sele
|
||||
import type { ComponentToken as TreeComponentToken } from '../../tree/style';
|
||||
import type { ComponentToken as TypographyComponentToken } from '../../typography/style';
|
||||
import type { ComponentToken as UploadComponentToken } from '../../upload/style';
|
||||
import type { ComponentToken as SplitterComponentToken } from '../../splitter/style';
|
||||
|
||||
export interface ComponentTokenMap {
|
||||
Affix?: AffixComponentToken;
|
||||
@ -109,6 +110,7 @@ export interface ComponentTokenMap {
|
||||
Spin?: SpinComponentToken;
|
||||
Statistic?: StatisticComponentToken;
|
||||
Switch?: SwitchComponentToken;
|
||||
Splitter?: SplitterComponentToken;
|
||||
Tag?: TagComponentToken;
|
||||
Tree?: TreeComponentToken;
|
||||
TreeSelect?: TreeSelectComponentToken;
|
||||
|
@ -349,5 +349,8 @@
|
||||
"title": "Ant Design",
|
||||
"tnpm": {
|
||||
"mode": "npm"
|
||||
},
|
||||
"overrides": {
|
||||
"@umijs/mako": "0.8.8-rc.1"
|
||||
}
|
||||
}
|
||||
|
@ -208,6 +208,10 @@ exports[`site test Component components/spin en Page 1`] = `1`;
|
||||
|
||||
exports[`site test Component components/spin zh Page 1`] = `1`;
|
||||
|
||||
exports[`site test Component components/splitter en Page 1`] = `2`;
|
||||
|
||||
exports[`site test Component components/splitter zh Page 1`] = `2`;
|
||||
|
||||
exports[`site test Component components/statistic en Page 1`] = `2`;
|
||||
|
||||
exports[`site test Component components/statistic zh Page 1`] = `2`;
|
||||
|
@ -54,6 +54,7 @@ exports[`antd dist files exports modules correctly 1`] = `
|
||||
"Slider",
|
||||
"Space",
|
||||
"Spin",
|
||||
"Splitter",
|
||||
"Statistic",
|
||||
"Steps",
|
||||
"Switch",
|
||||
|
Loading…
Reference in New Issue
Block a user