diff --git a/CHANGELOG.md b/CHANGELOG.md
index f6de20655..7f36a688a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,11 @@
* include documents in npm package for ai agents ([#960](https://github.com/WeBankFinTech/fes-design/issues/960)) ([3cc476c](https://github.com/WeBankFinTech/fes-design/commit/3cc476c81fb652c7fc3887884d99b46a02de0b74))
+### Refactor
+
+* refactor(space): 改用 grid gap 实现 ([#885](https://github.com/WeBankFinTech/fes-design/issues/885))
+
+
## [0.8.84](https://github.com/WeBankFinTech/fes-design/compare/v0.8.83...v0.8.84) (2025-11-04)
diff --git a/components/space/__tests__/space-885.spec.ts b/components/space/__tests__/space-885.spec.ts
new file mode 100644
index 000000000..0715210f0
--- /dev/null
+++ b/components/space/__tests__/space-885.spec.ts
@@ -0,0 +1,50 @@
+import { describe, it, expect } from 'vitest';
+import { mount } from '@vue/test-utils';
+import FSpace from '../index';
+import '../space';
+
+describe('Space Grid Layout #885', () => {
+ it('space.tsx uses grid display (not flex)', async () => {
+ const fsSpace = mount(FSpace, {
+ slots: {
+ default: [
+ { template: '1' },
+ { template: '2' },
+ { template: '3' },
+ ],
+ },
+ });
+ const el = fsSpace.element as HTMLElement;
+ expect(el.style.display).toBe('grid');
+ });
+
+ it('space.tsx sets gridTemplateColumns with repeat(auto-fit or auto-fill)', async () => {
+ const fsSpace = mount(FSpace, {
+ slots: {
+ default: [
+ { template: '1' },
+ { template: '2' },
+ { template: '3' },
+ ],
+ },
+ });
+ const el = fsSpace.element as HTMLElement;
+ expect(el.style.gridTemplateColumns).toMatch(/repeat\((auto-fit|auto-fill)/);
+ });
+
+ it('FSpace with 3 children renders with display grid', async () => {
+ const wrapper = mount(FSpace, {
+ props: { size: 8 },
+ slots: {
+ default: [
+ { template: '' },
+ { template: '' },
+ { template: '' },
+ ],
+ },
+ });
+ const el = wrapper.element as HTMLElement;
+ expect(el.style.display).toBe('grid');
+ expect(wrapper.findAll('.fes-space > *')).toHaveLength(3);
+ });
+});
\ No newline at end of file
diff --git a/components/space/space.tsx b/components/space/space.tsx
index 3377c4210..8f38829d4 100644
--- a/components/space/space.tsx
+++ b/components/space/space.tsx
@@ -7,35 +7,25 @@ import type { TThemeVars } from '../_theme/base';
import { COMPONENT_NAME, prefixCls } from './const';
import { type SpaceInnerProps, spaceProps } from './props';
-const useMargin = (props: SpaceInnerProps, themeVarsRef: Ref) => {
- const margin = computed(() => {
+const useGap = (props: SpaceInnerProps, themeVarsRef: Ref) => {
+ const gap = computed(() => {
const { size } = props;
- let horizontal = 0;
- let vertical = 0;
if (Array.isArray(size)) {
- horizontal = size[0];
- vertical = size[1];
+ return { row: size[0], col: size[1] };
} else if (typeof size === 'number') {
- horizontal = size;
- vertical = size;
- } else {
- const currentSize = depx(
- themeVarsRef.value[createKey('padding', size)]
- || themeVarsRef.value[createKey('padding', 'small')],
- );
- horizontal = currentSize;
- vertical = currentSize;
+ return { row: size, col: size };
}
- return {
- horizontal: `${horizontal}px`,
- vertical: `${vertical}px`,
- };
+ const currentSize = depx(
+ themeVarsRef.value[createKey('padding', size)]
+ || themeVarsRef.value[createKey('padding', 'small')],
+ );
+ return { row: currentSize, col: currentSize };
});
return {
- margin,
+ gap,
};
};
@@ -45,11 +35,11 @@ export default defineComponent({
setup(props) {
const { themeVars } = useTheme();
- const { margin } = useMargin(props, themeVars);
+ const { gap } = useGap(props, themeVars);
return {
prefixCls,
- margin,
+ gap,
};
},
render() {
@@ -62,7 +52,7 @@ export default defineComponent({
itemStyle,
wrap,
prefixCls,
- margin,
+ gap,
} = this;
const children = flatten(getSlot(this.$slots) || []).filter((node) =>
@@ -74,14 +64,14 @@ export default defineComponent({
role="none"
class={`${prefixCls}`}
style={{
- display: inline ? 'inline-flex' : 'flex',
- flexDirection: vertical ? 'column' : 'row',
- justifyContent: ['start', 'end'].includes(justify)
+ display: inline ? 'inline-grid' : 'grid',
+ gridTemplateColumns: vertical ? 'unset' : 'repeat(auto-fit, minmax(0, 1fr))',
+ gridTemplateRows: vertical ? 'repeat(auto-fit, minmax(0, 1fr))' : 'unset',
+ justifyItems: justify === 'start' || justify === 'end'
? `flex-${justify}`
- : justify,
+ : justify === 'center' ? 'center' : justify,
alignItems: align,
- flexWrap: !wrap || vertical ? 'nowrap' : 'wrap',
- gap: `${margin.vertical} ${margin.horizontal}`,
+ gap: `${gap.row}px ${gap.col}px`,
}}
>
{ wrapItem