ant-design/components/space/index.tsx
Yuki Zhang c3e51506cc
feat: add Space.Compact (#37652)
* feat: add Space.Compact

* feat: update input style

* feat: add CompactItem for context memoize

* feat: add demo

* feat: update button style

* feat: update input style

* feat: 提取 getCompactClassNames 公用方法

* feat: update button style

* feat: update picker

* feat: add block prop for Space.Compact

* feat: use Space.Compact for Input#addonBefore/After

* feat: update addon

* refactor: compact

* feat: update

* feat: update

* feat: migrate styles to compact for new Input/Input.Search

* feat: organize input demo

* feat: add more button compact demo

* feat: resolve select border collapse

* feat: fix input addon select style

* feat: add input addon demo in Space

* feat: add  useCompactItemContext hook

* feat: update compact-item style

* feat: rollback input#addon implements

* feat: rollback input#addon and input.search style

* feat: select border collapse

* feat: add Space.Compact demo

* feat: Space.Compact vertical for Button

* refactor: useCompactItemContext

* feat: update Button vertical demo

* feat: rtl for compact mixin

* feat: rtl for compact button

* feat: input rtl

* feat: add docs for Space.Compact

* test: add some tests for Space.Compact

* test: add tests

* feat: select style

* feat: handle select focus style

* feat: add useCompactItemContext for Picker and Cascader

* style: add compact-item style for cascader

* feat: support nested Space.Compact

* style: Input.Search in Space.Compact

* chore: clean

* feat: add useCompactItemContext for TreeSelect

* fix: lint issues

* fix: style lint

* docs: update demos for Space.Compact

* docs: update demo

* fix: add deps-lint-skip for space

* fix: add deps-lint-skip for space

* fix: handle edge case for useCompactItemContext

* test: add search test case

* chore: + bundlesize

* style: merge button compact style into one file

* style: improve style for nested compact

* fix: stylelint

* docs: update Space.Compact docs

* test: update demo snapshot

* test: update input debug test snapshot

* docs: update doccs for Space.Compact

* test: improve test cases for Compact

* docs: clean demos for Compact

* refactor: improve Space.Compact

* fix: add useCompactItemContext for Input.Search

* style: improve compact border-radius implementation

* refactor: use context to make nested compact works

* fix: input-number focused style

* refactor: remove useless style

* refactor: improve style for vertical compact

* test: update snapshot

* test: update snapshot for input

* refactor: improve compact-item-border-radius

* fix: search group in RTL

* style: improve style for button compact

* style: use after

* fix: stylelint

* chore: update snapshot

* style: improve button compact

* refactor: improve btn-icon-only style in compact
2022-10-18 16:23:10 +08:00

157 lines
3.8 KiB
TypeScript

import classNames from 'classnames';
import toArray from 'rc-util/lib/Children/toArray';
import * as React from 'react';
import { ConfigContext } from '../config-provider';
import type { SizeType } from '../config-provider/SizeContext';
import useFlexGapSupport from '../_util/hooks/useFlexGapSupport';
import Item from './Item';
import Compact from './Compact';
export const SpaceContext = React.createContext({
latestIndex: 0,
horizontalSize: 0,
verticalSize: 0,
supportFlexGap: false,
});
export type SpaceSize = SizeType | number;
export interface SpaceProps extends React.HTMLAttributes<HTMLDivElement> {
prefixCls?: string;
className?: string;
style?: React.CSSProperties;
size?: SpaceSize | [SpaceSize, SpaceSize];
direction?: 'horizontal' | 'vertical';
// No `stretch` since many components do not support that.
align?: 'start' | 'end' | 'center' | 'baseline';
split?: React.ReactNode;
wrap?: boolean;
}
const spaceSize = {
small: 8,
middle: 16,
large: 24,
};
function getNumberSize(size: SpaceSize) {
return typeof size === 'string' ? spaceSize[size] : size || 0;
}
const Space: React.FC<SpaceProps> = props => {
const { getPrefixCls, space, direction: directionConfig } = React.useContext(ConfigContext);
const {
size = space?.size || 'small',
align,
className,
children,
direction = 'horizontal',
prefixCls: customizePrefixCls,
split,
style,
wrap = false,
...otherProps
} = props;
const supportFlexGap = useFlexGapSupport();
const [horizontalSize, verticalSize] = React.useMemo(
() =>
((Array.isArray(size) ? size : [size, size]) as [SpaceSize, SpaceSize]).map(item =>
getNumberSize(item),
),
[size],
);
const childNodes = toArray(children, { keepEmpty: true });
const mergedAlign = align === undefined && direction === 'horizontal' ? 'center' : align;
const prefixCls = getPrefixCls('space', customizePrefixCls);
const cn = classNames(
prefixCls,
`${prefixCls}-${direction}`,
{
[`${prefixCls}-rtl`]: directionConfig === 'rtl',
[`${prefixCls}-align-${mergedAlign}`]: mergedAlign,
},
className,
);
const itemClassName = `${prefixCls}-item`;
const marginDirection = directionConfig === 'rtl' ? 'marginLeft' : 'marginRight';
// Calculate latest one
let latestIndex = 0;
const nodes = childNodes.map((child, i) => {
if (child !== null && child !== undefined) {
latestIndex = i;
}
const key = (child && child.key) || `${itemClassName}-${i}`;
return (
<Item
className={itemClassName}
key={key}
direction={direction}
index={i}
marginDirection={marginDirection}
split={split}
wrap={wrap}
>
{child}
</Item>
);
});
const spaceContext = React.useMemo(
() => ({ horizontalSize, verticalSize, latestIndex, supportFlexGap }),
[horizontalSize, verticalSize, latestIndex, supportFlexGap],
);
// =========================== Render ===========================
if (childNodes.length === 0) {
return null;
}
const gapStyle: React.CSSProperties = {};
if (wrap) {
gapStyle.flexWrap = 'wrap';
// Patch for gap not support
if (!supportFlexGap) {
gapStyle.marginBottom = -verticalSize;
}
}
if (supportFlexGap) {
gapStyle.columnGap = horizontalSize;
gapStyle.rowGap = verticalSize;
}
return (
<div
className={cn}
style={{
...gapStyle,
...style,
}}
{...otherProps}
>
<SpaceContext.Provider value={spaceContext}>{nodes}</SpaceContext.Provider>
</div>
);
};
interface CompoundedComponent extends React.FC<SpaceProps> {
Compact: typeof Compact;
}
const CompoundedSpace = Space as CompoundedComponent;
CompoundedSpace.Compact = Compact;
export default CompoundedSpace;