From 3c1cbd51dc67f9bab7a8339d32f4a6dbaf0d42b6 Mon Sep 17 00:00:00 2001
From: hyperlife1119 <hyperlife1119@qq.com>
Date: Mon, 16 Sep 2024 22:25:16 +0800
Subject: [PATCH] feat(module:space): add space compact component

---
 components/button/button-group.component.ts   |   3 +
 components/button/button.component.ts         |   7 +-
 components/button/demo/button-group.md        |   4 +
 components/cascader/cascader.component.ts     |   3 +
 components/core/types/size.ts                 |   1 +
 .../date-picker/date-picker.component.ts      |   3 +
 .../input-number/input-number.component.ts    |   5 +-
 components/input/input.directive.ts           |   5 +-
 components/select/select.component.ts         |   5 +-
 .../space/demo/compact-button-vertical.md     |  14 ++
 .../space/demo/compact-button-vertical.ts     |  25 +++
 components/space/demo/compact-buttons.md      |  14 ++
 components/space/demo/compact-buttons.ts      |  86 +++++++
 components/space/demo/compact.md              |  14 ++
 components/space/demo/compact.ts              | 210 ++++++++++++++++++
 components/space/demo/module                  |  26 ++-
 components/space/doc/index.en-US.md           |  20 +-
 components/space/doc/index.zh-CN.md           |  20 +-
 components/space/public-api.ts                |   7 +-
 .../space/space-compact-item.directive.ts     |  61 +++++
 components/space/space-compact-token.ts       |  11 +
 components/space/space-compact.component.ts   |  32 +++
 components/space/space-item.directive.ts      |   6 +-
 components/space/space.component.ts           |   2 +-
 components/space/space.module.ts              |   5 +-
 .../time-picker/time-picker.component.ts      |   7 +-
 .../tree-select/tree-select.component.ts      |   3 +
 27 files changed, 580 insertions(+), 19 deletions(-)
 create mode 100644 components/space/demo/compact-button-vertical.md
 create mode 100644 components/space/demo/compact-button-vertical.ts
 create mode 100644 components/space/demo/compact-buttons.md
 create mode 100644 components/space/demo/compact-buttons.ts
 create mode 100644 components/space/demo/compact.md
 create mode 100644 components/space/demo/compact.ts
 create mode 100644 components/space/space-compact-item.directive.ts
 create mode 100644 components/space/space-compact-token.ts
 create mode 100644 components/space/space-compact.component.ts

diff --git a/components/button/button-group.component.ts b/components/button/button-group.component.ts
index e570abe2fea..a17a86a51db 100644
--- a/components/button/button-group.component.ts
+++ b/components/button/button-group.component.ts
@@ -10,6 +10,9 @@ import { takeUntil } from 'rxjs/operators';
 
 export type NzButtonGroupSize = 'large' | 'default' | 'small';
 
+/**
+ * @deprecated Will be removed in v20. Use `NzSpaceCompactComponent` instead.
+ */
 @Component({
   selector: 'nz-button-group',
   exportAs: 'nzButtonGroup',
diff --git a/components/button/button.component.ts b/components/button/button.component.ts
index 5f00a05d685..34464ad42b8 100644
--- a/components/button/button.component.ts
+++ b/components/button/button.component.ts
@@ -27,6 +27,7 @@ import { filter, startWith, takeUntil } from 'rxjs/operators';
 
 import { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/config';
 import { NzIconDirective, NzIconModule } from 'ng-zorro-antd/icon';
+import { NZ_SPACE_COMPACT_ITEM_TYPE, NzSpaceCompactItemDirective } from 'ng-zorro-antd/space';
 
 export type NzButtonType = 'primary' | 'default' | 'dashed' | 'link' | 'text' | null;
 export type NzButtonShape = 'circle' | 'round' | null;
@@ -37,6 +38,8 @@ const NZ_CONFIG_MODULE_NAME: NzConfigKey = 'button';
 @Component({
   selector: 'button[nz-button], a[nz-button]',
   exportAs: 'nzButton',
+  standalone: true,
+  imports: [NzIconModule],
   preserveWhitespaces: false,
   changeDetection: ChangeDetectionStrategy.OnPush,
   encapsulation: ViewEncapsulation.None,
@@ -67,8 +70,8 @@ const NZ_CONFIG_MODULE_NAME: NzConfigKey = 'button';
     '[attr.tabindex]': 'disabled ? -1 : (tabIndex === null ? null : tabIndex)',
     '[attr.disabled]': 'disabled || null'
   },
-  imports: [NzIconModule],
-  standalone: true
+  hostDirectives: [NzSpaceCompactItemDirective],
+  providers: [{ provide: NZ_SPACE_COMPACT_ITEM_TYPE, useValue: 'btn' }]
 })
 export class NzButtonComponent implements OnDestroy, OnChanges, AfterViewInit, AfterContentInit, OnInit {
   readonly _nzModuleName: NzConfigKey = NZ_CONFIG_MODULE_NAME;
diff --git a/components/button/demo/button-group.md b/components/button/demo/button-group.md
index 2f1368b5a95..fdd00a31be2 100755
--- a/components/button/demo/button-group.md
+++ b/components/button/demo/button-group.md
@@ -11,8 +11,12 @@ title:
 
 通过设置 `nzSize` 为 `large` `small` 分别把按钮组合设为大、小尺寸。若不设置 `nzSize`,则尺寸为中。
 
+警告:在 v19.0.0 中被弃用,请使用 `<nz-space-compact>` 组件替代。
+
 ## en-US
 
 Buttons can be grouped by placing multiple `nz-button` components into a `nz-button-group`.
 
 The `nzSize` can be set to `large`, `small` or left unset resulting in a default size.
+
+Warning: Deprecated in v19.0.0, use `<nz-space-compact>` instead.
diff --git a/components/cascader/cascader.component.ts b/components/cascader/cascader.component.ts
index f2ae6654bd4..cc5557ada40 100644
--- a/components/cascader/cascader.component.ts
+++ b/components/cascader/cascader.component.ts
@@ -55,6 +55,7 @@ import { getStatusClassNames, toArray } from 'ng-zorro-antd/core/util';
 import { NzEmptyModule } from 'ng-zorro-antd/empty';
 import { NzCascaderI18nInterface, NzI18nService } from 'ng-zorro-antd/i18n';
 import { NzIconModule } from 'ng-zorro-antd/icon';
+import { NZ_SPACE_COMPACT_ITEM_TYPE, NzSpaceCompactItemDirective } from 'ng-zorro-antd/space';
 
 import { NzCascaderOptionComponent } from './cascader-li.component';
 import { NzCascaderService } from './cascader.service';
@@ -217,6 +218,7 @@ const defaultDisplayRender = (labels: string[]): string => labels.join(' / ');
       useExisting: forwardRef(() => NzCascaderComponent),
       multi: true
     },
+    { provide: NZ_SPACE_COMPACT_ITEM_TYPE, useValue: 'select' },
     NzCascaderService,
     NzDestroyService
   ],
@@ -234,6 +236,7 @@ const defaultDisplayRender = (labels: string[]): string => labels.join(' / ');
     '[class.ant-select-single]': 'true',
     '[class.ant-select-rtl]': `dir === 'rtl'`
   },
+  hostDirectives: [NzSpaceCompactItemDirective],
   imports: [
     OverlayModule,
     FormsModule,
diff --git a/components/core/types/size.ts b/components/core/types/size.ts
index a816a7f03be..42a7bd022d1 100644
--- a/components/core/types/size.ts
+++ b/components/core/types/size.ts
@@ -5,5 +5,6 @@
 
 // TODO: replace other size with this type.
 export type NzSizeLDSType = 'large' | 'default' | 'small';
+export type NzSizeLMSType = 'large' | 'middle' | 'small';
 export type NzSizeMDSType = 'middle' | 'default' | 'small';
 export type NzSizeDSType = 'default' | 'small';
diff --git a/components/date-picker/date-picker.component.ts b/components/date-picker/date-picker.component.ts
index 5d2a28479dc..2d15d361056 100644
--- a/components/date-picker/date-picker.component.ts
+++ b/components/date-picker/date-picker.component.ts
@@ -69,6 +69,7 @@ import {
   NzI18nService
 } from 'ng-zorro-antd/i18n';
 import { NzIconModule } from 'ng-zorro-antd/icon';
+import { NZ_SPACE_COMPACT_ITEM_TYPE, NzSpaceCompactItemDirective } from 'ng-zorro-antd/space';
 
 import { DatePickerService } from './date-picker.service';
 import { DateRangePopupComponent } from './date-range-popup.component';
@@ -249,9 +250,11 @@ export type NzPlacement = 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topRight';
     '[class.ant-picker-inline]': `nzInline`,
     '(click)': 'onClickInputBox($event)'
   },
+  hostDirectives: [NzSpaceCompactItemDirective],
   providers: [
     NzDestroyService,
     DatePickerService,
+    { provide: NZ_SPACE_COMPACT_ITEM_TYPE, useValue: 'picker' },
     {
       provide: NG_VALUE_ACCESSOR,
       multi: true,
diff --git a/components/input-number/input-number.component.ts b/components/input-number/input-number.component.ts
index 3bcf56cb5e5..a322ee757e7 100644
--- a/components/input-number/input-number.component.ts
+++ b/components/input-number/input-number.component.ts
@@ -44,6 +44,7 @@ import {
 } from 'ng-zorro-antd/core/types';
 import { getStatusClassNames, isNotNil } from 'ng-zorro-antd/core/util';
 import { NzIconModule } from 'ng-zorro-antd/icon';
+import { NZ_SPACE_COMPACT_ITEM_TYPE, NzSpaceCompactItemDirective } from 'ng-zorro-antd/space';
 
 @Component({
   selector: 'nz-input-number',
@@ -97,6 +98,7 @@ import { NzIconModule } from 'ng-zorro-antd/icon';
       useExisting: forwardRef(() => NzInputNumberComponent),
       multi: true
     },
+    { provide: NZ_SPACE_COMPACT_ITEM_TYPE, useValue: 'input-number' },
     NzDestroyService
   ],
   changeDetection: ChangeDetectionStrategy.OnPush,
@@ -113,7 +115,8 @@ import { NzIconModule } from 'ng-zorro-antd/icon';
     '[class.ant-input-number-borderless]': `nzBorderless`
   },
   imports: [NzIconModule, FormsModule, NzFormPatchModule],
-  standalone: true
+  standalone: true,
+  hostDirectives: [NzSpaceCompactItemDirective]
 })
 export class NzInputNumberComponent implements ControlValueAccessor, AfterViewInit, OnChanges, OnInit, OnDestroy {
   private autoStepTimer?: ReturnType<typeof setTimeout>;
diff --git a/components/input/input.directive.ts b/components/input/input.directive.ts
index 44c4868fda1..7a9cefccc10 100644
--- a/components/input/input.directive.ts
+++ b/components/input/input.directive.ts
@@ -25,6 +25,7 @@ import { distinctUntilChanged, filter, takeUntil } from 'rxjs/operators';
 import { NzFormItemFeedbackIconComponent, NzFormNoStatusService, NzFormStatusService } from 'ng-zorro-antd/core/form';
 import { NgClassInterface, NzSizeLDSType, NzStatus, NzValidateStatus } from 'ng-zorro-antd/core/types';
 import { getStatusClassNames } from 'ng-zorro-antd/core/util';
+import { NZ_SPACE_COMPACT_ITEM_TYPE, NzSpaceCompactItemDirective } from 'ng-zorro-antd/space';
 
 @Directive({
   selector: 'input[nz-input],textarea[nz-input]',
@@ -39,7 +40,9 @@ import { getStatusClassNames } from 'ng-zorro-antd/core/util';
     '[class.ant-input-rtl]': `dir=== 'rtl'`,
     '[class.ant-input-stepperless]': `nzStepperless`
   },
-  standalone: true
+  standalone: true,
+  hostDirectives: [NzSpaceCompactItemDirective],
+  providers: [{ provide: NZ_SPACE_COMPACT_ITEM_TYPE, useValue: 'input' }]
 })
 export class NzInputDirective implements OnChanges, OnInit, OnDestroy {
   @Input({ transform: booleanAttribute }) nzBorderless = false;
diff --git a/components/select/select.component.ts b/components/select/select.component.ts
index ff5523ca6e0..14564411d60 100644
--- a/components/select/select.component.ts
+++ b/components/select/select.component.ts
@@ -58,6 +58,7 @@ import {
   OnTouchedType
 } from 'ng-zorro-antd/core/types';
 import { getStatusClassNames, isNotNil } from 'ng-zorro-antd/core/util';
+import { NZ_SPACE_COMPACT_ITEM_TYPE, NzSpaceCompactItemDirective } from 'ng-zorro-antd/space';
 
 import { NzOptionContainerComponent } from './option-container.component';
 import { NzOptionGroupComponent } from './option-group.component';
@@ -95,7 +96,8 @@ export type NzSelectSizeType = 'large' | 'default' | 'small';
       provide: NG_VALUE_ACCESSOR,
       useExisting: forwardRef(() => NzSelectComponent),
       multi: true
-    }
+    },
+    { provide: NZ_SPACE_COMPACT_ITEM_TYPE, useValue: 'select' }
   ],
   changeDetection: ChangeDetectionStrategy.OnPush,
   encapsulation: ViewEncapsulation.None,
@@ -204,6 +206,7 @@ export type NzSelectSizeType = 'large' | 'default' | 'small';
     '[class.ant-select-multiple]': `nzMode !== 'default'`,
     '[class.ant-select-rtl]': `dir === 'rtl'`
   },
+  hostDirectives: [NzSpaceCompactItemDirective],
   imports: [
     NzSelectTopControlComponent,
     CdkOverlayOrigin,
diff --git a/components/space/demo/compact-button-vertical.md b/components/space/demo/compact-button-vertical.md
new file mode 100644
index 00000000000..c6109d8d757
--- /dev/null
+++ b/components/space/demo/compact-button-vertical.md
@@ -0,0 +1,14 @@
+---
+order: 8
+title:
+  zh-CN: 垂直方向紧凑布局
+  en-US: Vertical Compact Mode
+---
+
+## zh-CN
+
+垂直方向的紧凑布局,目前仅支持 Button 组合。
+
+## en-US
+
+Vertical Mode for Space.Compact, support Button only.
diff --git a/components/space/demo/compact-button-vertical.ts b/components/space/demo/compact-button-vertical.ts
new file mode 100644
index 00000000000..c0d5e39c2cf
--- /dev/null
+++ b/components/space/demo/compact-button-vertical.ts
@@ -0,0 +1,25 @@
+import { Component } from '@angular/core';
+
+@Component({
+  selector: 'nz-demo-space-compact-button-vertical',
+  template: `
+    <nz-space>
+      <nz-space-compact *nzSpaceItem nzDirection="vertical">
+        <button nz-button>Button 1</button>
+        <button nz-button>Button 2</button>
+        <button nz-button>Button 3</button>
+      </nz-space-compact>
+      <nz-space-compact *nzSpaceItem nzDirection="vertical">
+        <button nz-button nzType="dashed">Button 1</button>
+        <button nz-button nzType="dashed">Button 2</button>
+        <button nz-button nzType="dashed">Button 3</button>
+      </nz-space-compact>
+      <nz-space-compact *nzSpaceItem nzDirection="vertical">
+        <button nz-button nzType="primary">Button 1</button>
+        <button nz-button nzType="primary">Button 2</button>
+        <button nz-button nzType="primary">Button 3</button>
+      </nz-space-compact>
+    </nz-space>
+  `
+})
+export class NzDemoSpaceCompactButtonVerticalComponent {}
diff --git a/components/space/demo/compact-buttons.md b/components/space/demo/compact-buttons.md
new file mode 100644
index 00000000000..b89cef2f2e3
--- /dev/null
+++ b/components/space/demo/compact-buttons.md
@@ -0,0 +1,14 @@
+---
+order: 7
+title:
+  zh-CN: Button 紧凑布局
+  en-US: Button Compact Mode
+---
+
+## zh-CN
+
+Button 组件紧凑排列的示例。
+
+## en-US
+
+Button component compact example.
diff --git a/components/space/demo/compact-buttons.ts b/components/space/demo/compact-buttons.ts
new file mode 100644
index 00000000000..df6ba19a83f
--- /dev/null
+++ b/components/space/demo/compact-buttons.ts
@@ -0,0 +1,86 @@
+import { Component } from '@angular/core';
+
+@Component({
+  selector: 'nz-demo-space-compact-buttons',
+  template: `
+    <nz-space-compact nzBlock>
+      <button nz-button nz-tooltip nzTooltipTitle="Like">
+        <span nz-icon nzType="like"></span>
+      </button>
+      <button nz-button nz-tooltip nzTooltipTitle="Comment">
+        <span nz-icon nzType="comment"></span>
+      </button>
+      <button nz-button nz-tooltip nzTooltipTitle="Star">
+        <span nz-icon nzType="star"></span>
+      </button>
+      <button nz-button nz-tooltip nzTooltipTitle="Heart">
+        <span nz-icon nzType="heart"></span>
+      </button>
+      <button nz-button nz-tooltip nzTooltipTitle="Share">
+        <span nz-icon nzType="share-alt"></span>
+      </button>
+      <button nz-button nz-tooltip nzTooltipTitle="Download">
+        <span nz-icon nzType="download"></span>
+      </button>
+      <nz-dropdown-menu #menu>
+        <ul nz-menu>
+          <li nz-menu-item>
+            <a>1st item</a>
+          </li>
+          <li nz-menu-item>
+            <a>2nd item</a>
+          </li>
+          <li nz-menu-item>
+            <a>3rd item</a>
+          </li>
+        </ul>
+      </nz-dropdown-menu>
+      <button nz-button nz-dropdown [nzDropdownMenu]="menu">
+        <span nz-icon nzType="ellipsis"></span>
+      </button>
+    </nz-space-compact>
+    <br />
+    <nz-space-compact nzBlock>
+      <button nz-button nzType="primary">Button 1</button>
+      <button nz-button nzType="primary">Button 2</button>
+      <button nz-button nzType="primary">Button 3</button>
+      <button nz-button nzType="primary">Button 4</button>
+      <button nz-button nzType="primary" disabled nz-tooltip nzTooltipTitle="Tooltip">
+        <span nz-icon nzType="download"></span>
+      </button>
+      <button nz-button nzType="primary" nz-tooltip nzTooltipTitle="Tooltip">
+        <span nz-icon nzType="download"></span>
+      </button>
+    </nz-space-compact>
+    <br />
+    <nz-space-compact nzBlock>
+      <button nz-button>Button 1</button>
+      <button nz-button>Button 2</button>
+      <button nz-button>Button 3</button>
+      <button nz-button disabled nz-tooltip nzTooltipTitle="Tooltip">
+        <span nz-icon nzType="download"></span>
+      </button>
+      <button nz-button nz-tooltip nzTooltipTitle="Tooltip">
+        <span nz-icon nzType="download"></span>
+      </button>
+      <button nz-button nzType="primary">Button 4</button>
+      <nz-dropdown-menu #menu>
+        <ul nz-menu>
+          <li nz-menu-item>
+            <a>1st item</a>
+          </li>
+          <li nz-menu-item>
+            <a>2nd item</a>
+          </li>
+          <li nz-menu-item>
+            <a>3rd item</a>
+          </li>
+        </ul>
+      </nz-dropdown-menu>
+      <button nz-button nzType="primary" nz-dropdown [nzDropdownMenu]="menu">
+        <span nz-icon nzType="ellipsis"></span>
+      </button>
+    </nz-space-compact>
+  `
+})
+export class NzDemoSpaceCompactButtonsComponent {}
diff --git a/components/space/demo/compact.md b/components/space/demo/compact.md
new file mode 100644
index 00000000000..b187aebad51
--- /dev/null
+++ b/components/space/demo/compact.md
@@ -0,0 +1,14 @@
+---
+order: 6
+title:
+  zh-CN: 紧凑布局组合
+  en-US: Compact Mode
+---
+
+## zh-CN
+
+使用 `<nz-space-compact>` 让表单组件之间紧凑连接且合并边框。
+
+## en-US
+
+Compact Mode for form component.
diff --git a/components/space/demo/compact.ts b/components/space/demo/compact.ts
new file mode 100644
index 00000000000..65f6da9e14a
--- /dev/null
+++ b/components/space/demo/compact.ts
@@ -0,0 +1,210 @@
+import { Component } from '@angular/core';
+
+@Component({
+  selector: 'nz-demo-space-compact',
+  template: `
+    <nz-space-compact nzBlock>
+      <input nz-input value="0571" [style.width.%]="20" />
+      <input nz-input value="26888888" [style.width.%]="30" />
+    </nz-space-compact>
+    <br />
+    <nz-space-compact nzBlock nzSize="small">
+      <input nz-input value="https://ng.ant.design" [style.width]="'calc(100% - 200px)'" />
+      <button nz-button nzType="primary">Submit</button>
+    </nz-space-compact>
+    <br />
+    <nz-space-compact nzBlock>
+      <input nz-input value="https://ng.ant.design" [style.width]="'calc(100% - 200px)'" />
+      <button nz-button nzType="primary">Submit</button>
+    </nz-space-compact>
+    <br />
+    <nz-space-compact nzBlock>
+      <input nz-input value="git@github.com:NG-ZORRO/ng-zorro-antd.git" [style.width]="'calc(100% - 200px)'" />
+      <button nz-button nz-tooltip nzTooltipTitle="copy git url">
+        <span nz-icon nzType="copy"></span>
+      </button>
+    </nz-space-compact>
+    <br />
+    <nz-space-compact nzBlock>
+      <nz-select ngModel="Zhejianggggg">
+        <nz-option nzLabel="Zhejianggggg" nzValue="Zhejianggggg"></nz-option>
+        <nz-option nzLabel="Jiangsu" nzValue="Jiangsu"></nz-option>
+      </nz-select>
+      <input nz-input value="Xihu District, Hangzhou" [style.width.%]="50" />
+    </nz-space-compact>
+    <br />
+    <nz-space-compact nzBlock>
+      <nz-select nzMode="multiple" [ngModel]="['Zhejianggggg']" [style.width.%]="50">
+        <nz-option nzLabel="Zhejianggggg" nzValue="Zhejianggggg"></nz-option>
+        <nz-option nzLabel="Jiangsu" nzValue="Jiangsu"></nz-option>
+      </nz-select>
+      <input nz-input value="Xihu District, Hangzhou" [style.width.%]="50" />
+    </nz-space-compact>
+    <br />
+    <nz-space-compact nzBlock>
+      <nz-select ngModel="Option1">
+        <nz-option nzLabel="Option1" nzValue="Option1"></nz-option>
+        <nz-option nzLabel="Option2" nzValue="Option2"></nz-option>
+      </nz-select>
+      <input nz-input value="input content" [style.width.%]="50" />
+      <nz-input-number [ngModel]="12" />
+    </nz-space-compact>
+    <br />
+    <nz-space-compact nzBlock>
+      <input nz-input value="input content" [style.width.%]="50" />
+      <nz-date-picker [style.width.%]="50" />
+    </nz-space-compact>
+    <br />
+    <nz-space-compact nzBlock>
+      <nz-range-picker [style.width.%]="70" />
+      <input nz-input value="input content" [style.width.%]="30" />
+      <button nz-button nzType="primary">查询</button>
+    </nz-space-compact>
+    <br />
+    <nz-space-compact nzBlock>
+      <input nz-input value="input content" [style.width.%]="30" />
+      <nz-range-picker [style.width.%]="70" />
+    </nz-space-compact>
+    <br />
+    <nz-space-compact nzBlock>
+      <nz-select ngModel="Option1-1">
+        <nz-option nzLabel="Option1-1" nzValue="Option1-1"></nz-option>
+        <nz-option nzLabel="Option2-1" nzValue="Option2-1"></nz-option>
+      </nz-select>
+      <nz-select ngModel="Option1-2">
+        <nz-option nzLabel="Option1-2" nzValue="Option1-2"></nz-option>
+        <nz-option nzLabel="Option2-2" nzValue="Option2-2"></nz-option>
+      </nz-select>
+    </nz-space-compact>
+    <br />
+    <nz-space-compact nzBlock>
+      <nz-select ngModel="1">
+        <nz-option nzLabel="Between" nzValue="1"></nz-option>
+        <nz-option nzLabel="Except" nzValue="2"></nz-option>
+      </nz-select>
+      <input nz-input placeholder="Minimum" style="width: 100px; text-align: center" />
+      <input
+        nz-input
+        class="site-input-split"
+        style="
+          width: 30px;
+          border-left: 0;
+          border-right: 0;
+          pointer-events: none
+        "
+        placeholder="~"
+        disabled
+      />
+      <input nz-input class="site-input-right" style="width: 100px; text-align: center" placeholder="Maximum" />
+    </nz-space-compact>
+    <br />
+    <nz-space-compact nzBlock>
+      <nz-select ngModel="Sign Up" [style.width.%]="30">
+        <nz-option nzLabel="Sign Up" nzValue="Sign Up"></nz-option>
+        <nz-option nzLabel="Sign In" nzValue="Sign In"></nz-option>
+      </nz-select>
+      <nz-autocomplete #auto [nzDataSource]="['text 1', 'text 2']" />
+      <input nz-input placeholder="Email" [nzAutocomplete]="auto" [style.width.%]="70" />
+    </nz-space-compact>
+    <br />
+    <nz-space-compact nzBlock>
+      <nz-time-picker [style.width.%]="70" />
+      <nz-cascader [nzOptions]="cascaderOptions" nzPlaceholder="Select Address" [style.width.%]="70" />
+    </nz-space-compact>
+    <br />
+    <nz-space-compact nzBlock>
+      <nz-tree-select
+        [nzNodes]="nodes"
+        nzShowSearch
+        nzPlaceHolder="Please select"
+        ngModel="10010"
+        nzDefaultExpandAll
+        [style.width.%]="60"
+      ></nz-tree-select>
+      <button nz-button nzType="primary">Submit</button>
+    </nz-space-compact>
+  `,
+  styles: [
+    `
+      .site-input-split {
+        background-color: #fff;
+      }
+
+      .site-input-right:not(.ant-input-rtl) {
+        border-left-width: 0;
+      }
+
+      .site-input-right:not(.ant-input-rtl):hover,
+      .site-input-right:not(.ant-input-rtl):focus {
+        border-left-width: 1px;
+      }
+
+      .site-input-right.ant-input-rtl {
+        border-right-width: 0;
+      }
+
+      .site-input-right.ant-input-rtl:hover,
+      .site-input-right.ant-input-rtl:focus {
+        border-right-width: 1px;
+      }
+    `
+  ]
+})
+export class NzDemoSpaceCompactComponent {
+  cascaderOptions = [
+    {
+      value: 'zhejiang',
+      label: 'Zhejiang',
+      children: [
+        {
+          value: 'hangzhou',
+          label: 'Hangzhou',
+          children: [
+            {
+              value: 'xihu',
+              label: 'West Lake'
+            }
+          ]
+        }
+      ]
+    },
+    {
+      value: 'jiangsu',
+      label: 'Jiangsu',
+      children: [
+        {
+          value: 'nanjing',
+          label: 'Nanjing',
+          children: [
+            {
+              value: 'zhonghuamen',
+              label: 'Zhong Hua Men'
+            }
+          ]
+        }
+      ]
+    }
+  ];
+
+  nodes = [
+    {
+      title: 'parent 1',
+      key: '100',
+      children: [
+        {
+          title: 'parent 1-0',
+          key: '1001',
+          children: [
+            { title: 'leaf 1-0-0', key: '10010', isLeaf: true },
+            { title: 'leaf 1-0-1', key: '10011', isLeaf: true }
+          ]
+        },
+        {
+          title: 'parent 1-1',
+          key: '1002',
+          children: [{ title: 'leaf 1-1-0', key: '10020', isLeaf: true }]
+        }
+      ]
+    }
+  ];
+}
diff --git a/components/space/demo/module b/components/space/demo/module
index 0ea9aa08ab1..7eaf223b61f 100644
--- a/components/space/demo/module
+++ b/components/space/demo/module
@@ -1,23 +1,45 @@
+import { FormsModule } from '@angular/forms';
+import { NzAutocompleteModule } from 'ng-zorro-antd/auto-complete';
 import { NzButtonModule } from 'ng-zorro-antd/button';
 import { NzCardModule } from 'ng-zorro-antd/card';
+import { NzCascaderModule } from 'ng-zorro-antd/cascader';
+import { NzDatePickerModule } from 'ng-zorro-antd/date-picker';
 import { NzDividerModule } from 'ng-zorro-antd/divider';
+import { NzDropDownModule } from 'ng-zorro-antd/dropdown';
 import { NzIconModule } from 'ng-zorro-antd/icon';
+import { NzInputModule } from 'ng-zorro-antd/input';
+import { NzInputNumberModule } from 'ng-zorro-antd/input-number';
 import { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm';
 import { NzRadioModule } from 'ng-zorro-antd/radio';
+import { NzSelectModule } from 'ng-zorro-antd/select';
 import { NzSliderModule } from 'ng-zorro-antd/slider';
 import { NzSpaceModule } from 'ng-zorro-antd/space';
+import { NzTimePickerModule } from 'ng-zorro-antd/time-picker';
+import { NzToolTipModule } from 'ng-zorro-antd/tooltip';
+import { NzTreeSelectModule } from 'ng-zorro-antd/tree-select';
 import { NzTypographyModule } from 'ng-zorro-antd/typography';
 import { NzUploadModule } from 'ng-zorro-antd/upload';
 
 export const moduleList = [
   NzRadioModule,
   NzSliderModule,
-  NzUploadModule,
   NzButtonModule,
+  NzInputModule,
+  NzInputNumberModule,
+  NzSelectModule,
+  NzCascaderModule,
+  NzDatePickerModule,
+  NzTimePickerModule,
+  NzTreeSelectModule,
+  NzUploadModule,
   NzSpaceModule,
   NzIconModule,
   NzPopconfirmModule,
   NzCardModule,
   NzDividerModule,
-  NzTypographyModule
+  NzTypographyModule,
+  NzToolTipModule,
+  NzAutocompleteModule,
+  NzDropDownModule,
+  FormsModule
 ];
diff --git a/components/space/doc/index.en-US.md b/components/space/doc/index.en-US.md
index e9f86205fc2..1b05f020fbb 100644
--- a/components/space/doc/index.en-US.md
+++ b/components/space/doc/index.en-US.md
@@ -22,8 +22,26 @@ import { NzSpaceModule } from 'ng-zorro-antd/space';
 
 | Property        | Description                                 | Type                                         | Default      | Global Config |
 | --------------- | ------------------------------------------- | -------------------------------------------- | ------------ | ------------- |
-| `[nzSize]`      | The space size                              | `'small' \| 'middle' \| 'large' \| number`   | `small`      | ✅            |
+| `[nzSize]`      | The space size                              | `'small' \| 'middle' \| 'large' \| number`   | `small`      | ✅             |
 | `[nzDirection]` | The space direction                         | `'vertical' \| 'horizontal'`                 | `horizontal` |               |
 | `[nzAlign]`     | Align items                                 | `'start' \| 'end' \| 'baseline' \| 'center'` | -            |               |
 | `[nzWrap]`      | Auto wrap line, when `horizontal` effective | `boolean`                                    | `false`      |               |
 | `[nzSplit]`     | Set split                                   | `TemplateRef`                                | -            |               |
+
+### nz-space-compact:standalone
+
+Use `<nz-space-compact>` when child form components are compactly connected and the border is collapsed. The supported components are:
+
+- Button
+- Cascader
+- DatePicker
+- Input
+- Select
+- TimePicker
+- TreeSelect
+-
+| 参数            | 说明                                       | 类型                             | 默认值       | 支持全局配置 |
+| --------------- | ------------------------------------------ | -------------------------------- | ------------ | ------------ |
+| `[nzBlock]`     | Option to fit width to its parent\'s width | `boolean`                        | `false`      |              |
+| `[nzDirection]` | Set direction of layout                    | `'vertical' \| 'horizontal'`     | `horizontal` |              |
+| `[nzSize]`      | Set child component size                   | `'large' \| 'middle' \| 'small'` | `'middle'`   |              |
diff --git a/components/space/doc/index.zh-CN.md b/components/space/doc/index.zh-CN.md
index 39992fd2781..2b216ccd47d 100644
--- a/components/space/doc/index.zh-CN.md
+++ b/components/space/doc/index.zh-CN.md
@@ -26,8 +26,26 @@ import { NzSpaceModule } from 'ng-zorro-antd/space';
 
 | 参数            | 说明                                   | 类型                                         | 默认值       | 支持全局配置 |
 | --------------- | -------------------------------------- | -------------------------------------------- | ------------ | ------------ |
-| `[nzSize]`      | 间距大小                               | `'small' \| 'middle' \| 'large' \| number`   | `'small'`    | ✅           |
+| `[nzSize]`      | 间距大小                               | `'small' \| 'middle' \| 'large' \| number`   | `'small'`    | ✅            |
 | `[nzDirection]` | 间距方向                               | `'vertical' \| 'horizontal'`                 | `horizontal` |              |
 | `[nzAlign]`     | 对齐方式                               | `'start' \| 'end' \| 'baseline' \| 'center'` | -            |              |
 | `[nzWrap]`      | 是否自动换行,仅在 `horizontal` 时有效 | `boolean`                                    | `false`      |              |
 | `[nzSplit]`     | 设置分隔符                             | `TemplateRef`                                | -            |              |
+
+### nz-space-compact:standalone
+
+需要表单组件之间紧凑连接且合并边框时,使用 `<nz-space-compact>`。支持的组件有:
+
+- Button
+- Cascader
+- DatePicker
+- Input
+- Select
+- TimePicker
+- TreeSelect
+-
+| 参数            | 说明                         | 类型                             | 默认值       | 支持全局配置 |
+| --------------- | ---------------------------- | -------------------------------- | ------------ | ------------ |
+| `[nzBlock]`     | 将宽度调整为父元素宽度的选项 | `boolean`                        | `false`      |              |
+| `[nzDirection]` | 指定排列方向                 | `'vertical' \| 'horizontal'`     | `horizontal` |              |
+| `[nzSize]`      | 子组件大小                   | `'large' \| 'middle' \| 'small'` | `'middle'`   |              |
diff --git a/components/space/public-api.ts b/components/space/public-api.ts
index f29ed924b75..1cd8b53f927 100644
--- a/components/space/public-api.ts
+++ b/components/space/public-api.ts
@@ -3,7 +3,10 @@
  * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
  */
 
-export * from './space.module';
-export * from './space.component';
+export * from './space-compact-item.directive';
+export * from './space-compact-token';
+export * from './space-compact.component';
 export * from './space-item.directive';
+export * from './space.component';
+export * from './space.module';
 export * from './types';
diff --git a/components/space/space-compact-item.directive.ts b/components/space/space-compact-item.directive.ts
new file mode 100644
index 00000000000..70912a95476
--- /dev/null
+++ b/components/space/space-compact-item.directive.ts
@@ -0,0 +1,61 @@
+/**
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
+ */
+
+import { computed, Directive, forwardRef, inject } from '@angular/core';
+
+import { NZ_SPACE_COMPACT_ITEM, NZ_SPACE_COMPACT_ITEM_TYPE } from './space-compact-token';
+import { NzSpaceCompactComponent } from './space-compact.component';
+
+@Directive({
+  exportAs: 'nzSpaceCompactItem',
+  standalone: true,
+  providers: [{ provide: NZ_SPACE_COMPACT_ITEM, useExisting: forwardRef(() => NzSpaceCompactItemDirective) }],
+  host: {
+    '[class]': 'class()'
+  }
+})
+export class NzSpaceCompactItemDirective {
+  private spaceCompactCmp = inject(NzSpaceCompactComponent, { host: true, skipSelf: true, optional: true });
+  private type = inject(NZ_SPACE_COMPACT_ITEM_TYPE);
+
+  protected class = computed(() => {
+    // Only handle when the parent is space compact component
+    if (!this.spaceCompactCmp) return null;
+
+    const items = this.spaceCompactCmp.items();
+    const direction = this.spaceCompactCmp.nzDirection();
+    const index = items.indexOf(this);
+    const classes = [compactItemClassOf(this.type, direction)];
+
+    if (index === 0) {
+      classes.push(compactFirstItemClassOf(this.type, direction));
+    } else if (index === items.length - 1) {
+      classes.push(compactLastItemClassOf(this.type, direction));
+    }
+
+    return classes;
+  });
+}
+
+function generateCompactClass(
+  type: string,
+  direction: 'vertical' | 'horizontal',
+  position: 'item' | 'first-item' | 'last-item'
+): string {
+  const directionPrefix = direction === 'vertical' ? 'vertical-' : '';
+  return `ant-${type}-compact-${directionPrefix}${position}`;
+}
+
+function compactItemClassOf(type: string, direction: 'vertical' | 'horizontal'): string {
+  return generateCompactClass(type, direction, 'item');
+}
+
+function compactFirstItemClassOf(type: string, direction: 'vertical' | 'horizontal'): string {
+  return generateCompactClass(type, direction, 'first-item');
+}
+
+function compactLastItemClassOf(type: string, direction: 'vertical' | 'horizontal'): string {
+  return generateCompactClass(type, direction, 'last-item');
+}
diff --git a/components/space/space-compact-token.ts b/components/space/space-compact-token.ts
new file mode 100644
index 00000000000..b4ffa23220f
--- /dev/null
+++ b/components/space/space-compact-token.ts
@@ -0,0 +1,11 @@
+/**
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
+ */
+
+import { InjectionToken } from '@angular/core';
+
+import type { NzSpaceCompactItemDirective } from './space-compact-item.directive';
+
+export const NZ_SPACE_COMPACT_ITEM = new InjectionToken<NzSpaceCompactItemDirective>('');
+export const NZ_SPACE_COMPACT_ITEM_TYPE = new InjectionToken<string>('');
diff --git a/components/space/space-compact.component.ts b/components/space/space-compact.component.ts
new file mode 100644
index 00000000000..951e145a0a7
--- /dev/null
+++ b/components/space/space-compact.component.ts
@@ -0,0 +1,32 @@
+/**
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
+ */
+
+import { NgTemplateOutlet } from '@angular/common';
+import { booleanAttribute, ChangeDetectionStrategy, Component, contentChildren, input } from '@angular/core';
+
+import { NzSizeLMSType } from 'ng-zorro-antd/core/types';
+
+import { NZ_SPACE_COMPACT_ITEM } from './space-compact-token';
+
+@Component({
+  selector: 'nz-space-compact, [nz-space-compact]',
+  exportAs: 'nzSpaceCompact',
+  standalone: true,
+  imports: [NgTemplateOutlet],
+  template: `<ng-content></ng-content>`,
+  host: {
+    class: 'ant-space-compact',
+    '[class.ant-space-compact-block]': `nzBlock()`,
+    '[class.ant-space-compact-vertical]': `nzDirection() === 'vertical'`
+  },
+  changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class NzSpaceCompactComponent {
+  nzBlock = input(false, { transform: booleanAttribute });
+  nzDirection = input<'vertical' | 'horizontal'>('horizontal');
+  nzSize = input<NzSizeLMSType>('middle');
+
+  items = contentChildren(NZ_SPACE_COMPACT_ITEM);
+}
diff --git a/components/space/space-item.directive.ts b/components/space/space-item.directive.ts
index 4b884c9d59d..31f20c26d17 100644
--- a/components/space/space-item.directive.ts
+++ b/components/space/space-item.directive.ts
@@ -6,9 +6,7 @@
 import { Directive } from '@angular/core';
 
 @Directive({
-  selector: '[nzSpaceItem]',
+  selector: '[nzSpaceItem],[nz-space-item]',
   standalone: true
 })
-export class NzSpaceItemDirective {
-  constructor() {}
-}
+export class NzSpaceItemDirective {}
diff --git a/components/space/space.component.ts b/components/space/space.component.ts
index c905ff838c8..2a706620e1c 100644
--- a/components/space/space.component.ts
+++ b/components/space/space.component.ts
@@ -37,7 +37,7 @@ const SPACE_SIZE: {
 
 @Component({
   selector: 'nz-space, [nz-space]',
-  exportAs: 'NzSpace',
+  exportAs: 'nzSpace',
   changeDetection: ChangeDetectionStrategy.OnPush,
   template: `
     <ng-content></ng-content>
diff --git a/components/space/space.module.ts b/components/space/space.module.ts
index fe40a9ed883..de7a95c1058 100644
--- a/components/space/space.module.ts
+++ b/components/space/space.module.ts
@@ -5,11 +5,12 @@
 
 import { NgModule } from '@angular/core';
 
+import { NzSpaceCompactComponent } from './space-compact.component';
 import { NzSpaceItemDirective } from './space-item.directive';
 import { NzSpaceComponent } from './space.component';
 
 @NgModule({
-  imports: [NzSpaceComponent, NzSpaceItemDirective],
-  exports: [NzSpaceComponent, NzSpaceItemDirective]
+  imports: [NzSpaceComponent, NzSpaceItemDirective, NzSpaceCompactComponent],
+  exports: [NzSpaceComponent, NzSpaceItemDirective, NzSpaceCompactComponent]
 })
 export class NzSpaceModule {}
diff --git a/components/time-picker/time-picker.component.ts b/components/time-picker/time-picker.component.ts
index 58f5124f28b..17798ada04e 100644
--- a/components/time-picker/time-picker.component.ts
+++ b/components/time-picker/time-picker.component.ts
@@ -43,6 +43,7 @@ import { NgClassInterface, NzSafeAny, NzStatus, NzValidateStatus } from 'ng-zorr
 import { getStatusClassNames, isNil } from 'ng-zorro-antd/core/util';
 import { DateHelperService, NzI18nInterface, NzI18nService } from 'ng-zorro-antd/i18n';
 import { NzIconModule } from 'ng-zorro-antd/icon';
+import { NZ_SPACE_COMPACT_ITEM_TYPE, NzSpaceCompactItemDirective } from 'ng-zorro-antd/space';
 
 import { NzTimePickerPanelComponent } from './time-picker-panel.component';
 
@@ -143,8 +144,12 @@ const NZ_CONFIG_MODULE_NAME: NzConfigKey = 'timePicker';
     '[class.ant-picker-borderless]': `nzBorderless`,
     '(click)': 'open()'
   },
+  hostDirectives: [NzSpaceCompactItemDirective],
   animations: [slideMotion],
-  providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: NzTimePickerComponent, multi: true }],
+  providers: [
+    { provide: NG_VALUE_ACCESSOR, useExisting: NzTimePickerComponent, multi: true },
+    { provide: NZ_SPACE_COMPACT_ITEM_TYPE, useValue: 'picker' }
+  ],
   imports: [
     AsyncPipe,
     FormsModule,
diff --git a/components/tree-select/tree-select.component.ts b/components/tree-select/tree-select.component.ts
index 5f4274c6dd3..4eec5c1b0c2 100644
--- a/components/tree-select/tree-select.component.ts
+++ b/components/tree-select/tree-select.component.ts
@@ -63,6 +63,7 @@ import {
 import { getStatusClassNames, isNotNil } from 'ng-zorro-antd/core/util';
 import { NzEmptyModule } from 'ng-zorro-antd/empty';
 import { NzSelectModule, NzSelectSearchComponent } from 'ng-zorro-antd/select';
+import { NZ_SPACE_COMPACT_ITEM_TYPE, NzSpaceCompactItemDirective } from 'ng-zorro-antd/space';
 import { NzTreeComponent, NzTreeModule } from 'ng-zorro-antd/tree';
 
 import { NzTreeSelectService } from './tree-select.service';
@@ -215,6 +216,7 @@ const listOfPositions = [
   `,
   providers: [
     NzTreeSelectService,
+    { provide: NZ_SPACE_COMPACT_ITEM_TYPE, useValue: 'select' },
     {
       provide: NzTreeHigherOrderServiceToken,
       useExisting: NzTreeSelectService
@@ -242,6 +244,7 @@ const listOfPositions = [
     '(click)': 'trigger()',
     '(keydown)': 'onKeydown($event)'
   },
+  hostDirectives: [NzSpaceCompactItemDirective],
   imports: [
     NzOverlayModule,
     CdkConnectedOverlay,